[C] Task 1: Notch Bar — adaptive shape, synthetic notch, hover affordance#1
Open
sheepxux wants to merge 17 commits into
Open
[C] Task 1: Notch Bar — adaptive shape, synthetic notch, hover affordance#1sheepxux wants to merge 17 commits into
sheepxux wants to merge 17 commits into
Conversation
- Theme tokens: Palette, Motion, Typo, NotchMetrics - NotchBarShape: dual-rect path framing the hardware notch - StatusDot: static color per BarState (animations come in Task 3) - NotchBarView: bar composition with status dot + task count - NotchBarWindow: borderless .statusBar level, multi-Space + full-screen aux - AppDelegate: spawns the bar after launch, repositions on screen change Build gating: #Preview blocks wrapped in #if PREVIEWS so swift build still passes on Command Line Tools-only machines. Xcode auto-defines PREVIEWS via Package.swift detection of /Applications/Xcode.app. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…Previews Xcode 26 requires ENABLE_DEBUG_DYLIB=YES for previewing in executable targets, but SwiftPM does not expose that build setting. The recommended workaround (per the Preview error message) is to move preview-able code into a library target. - IslandApp executable target now contains only the @main entry + AppDelegate - All Theme/Views/Windows code moves to new IslandAppLib library target - NotchBarWindow + init + reposition() promoted to public so the exec can reach them from AppDelegate - Files relocated with git mv to preserve history Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
User feedback: status-bar/notch height varies per Mac, and the bar should have a rounded "tab" silhouette instead of sharp rectangles. - NotchMetrics.Layout: per-screen snapshot driving Window framing + Shape drawing. Reads NSScreen.safeAreaInsets.top on notched displays and NSStatusBar.system.thickness on plain displays. - NotchBarShape: rounded outer-bottom corners on each side extension (cornerRadius 14pt). Inner edges stay sharp; the S-curve transition will arrive with the panel in Task 2. - NotchBarView: dual-mode rendering — NotchBarShape on notched screens, Capsule on no-notch (Mac mini, external displays); status dot + count laid out appropriately for each. - NotchBarWindow: re-measures on every reposition() so screen-parameter changes (display swap, scale change) flip notched ⇄ capsule + adjust height without a relaunch. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace hand-drawn quarter-circle arcs with UnevenRoundedRectangle in .continuous style (Apple's squircle math, same as macOS app icons). The curvature transition is no longer abrupt at the corner endpoints. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
User feedback: side vertical edges should read taller, with shorter curve transitions (Dynamic Island feel). - Bar now protrudes bottomOverhang (7pt) below the hardware notch on notched displays, giving the side a visible straight stretch before the curve starts. - NotchBarShape rewritten as one connected outline with a top-center cutout at notchHeight × notchWidth. The bottom corners use the same continuous-curvature squircle. - cornerRadius dropped 14 → 11 so the curve occupies less of the bottom. - NotchMetrics.Layout adds notchHeight separate from barHeight to drive the cutout sizing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Hover the bar / capsule → it grows wider + slightly taller with a spring animation, and the cursor switches to pointingHand. Signals "clickable" without firing the panel expansion (that's still Task 2). - NotchMetrics adds hover-boost constants (notched: +30w +4h, capsule: +50w +6h) and Layout.hovered() returning the expanded snapshot. - NotchBarWindow sizes itself to the hover-expanded dimensions so the bar can animate inside the window without any NSWindow frame churn. - NotchBarRootView holds @State isHovering, animates between idle and hover layouts via withAnimation(.spring(response: 0.3, damping: 0.75)). - Hover hit-testing uses contentShape(barHitShape) so the cursor only reacts over the actual bar pixels, not transparent window padding. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
User feedback: hover-expanded capsule overflowed the menu-bar zone. - Idle capsule height = thickness - capsuleVerticalInset (6pt). Sits inside the OS status bar with a small visible gap top + bottom. - Hover capsule height = thickness (full status bar). No overflow. - Capsule alignment in window switched to .center so growth is symmetric (top + bottom expand toward the status-bar edges). Notched bar still anchors .top so it grows downward into the menu-bar zone (Dynamic Island feel preserved). - Removed fallbackTopMargin constant; topMargin is now always 0 because the OS status bar zone is centered around the capsule via SwiftUI alignment instead of pixel offsets. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
User feedback: capsule sat too high in the menu bar zone, and felt small. Root cause: NSStatusBar.system.thickness (~22pt) under-reports the actual visible menu-bar height on macOS 26 (~28pt). Sizing the window to thickness made the window land at the top of the screen but cover only the upper slice of the menu bar — the centered capsule then drifted upward. - NotchMetrics.Layout gains menuBarHeight, measured from the screen as `frame.maxY - visibleFrame.maxY` (authoritative regardless of OS changes). Falls back to thickness when visibleFrame is unavailable. - Window container height (no-notch) = menuBarHeight, so the window covers the status-bar zone exactly and the centered capsule sits at its true vertical center. - Hover capsule height = menuBarHeight (still fills the bar exactly). - Idle capsule width 140 → 168, height inset trimmed 6 → 4 — both cooperate to give the pill more presence. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
User feedback: prefer a MacBook-style notch silhouette over a centered capsule, with the bar flush against the screen edge (no top gap). - No-notch backdrop switched from Capsule (#0A0A0A, all-rounded) to UnevenRoundedRectangle in .continuous style (#000000, flat top + rounded bottom corners) — visually a "fake notch" that hangs from the screen edge identical to a real one. - Window container anchors the bar to TOP for both modes; the no-notch container height equals the OS menu-bar height so the bar hangs from the screen edge and grows downward into the menu bar zone on hover. - Hover hit-test shape mirrors the new fake-notch silhouette. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
User feedback: synthetic notch should fill the status bar height at idle; hover should only widen it, not change height. - Removed capsuleVerticalInset; barHeight now == menuBarHeight at idle. - Layout.hovered() already sets barHeight = menuBarHeight on no-notch, so the width-only growth pattern falls out for free. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
User feedback (no-notch displays only): - Idle should show a clean fake-notch silhouette without status dot or count. - Hover should drop slightly past the menu bar bottom (Dynamic Island feel). - NotchBarView gains showsContent flag; opacity-fades the dot + count. Notched mode keeps showsContent always true (the bar is always visible around the hardware notch); synthetic-notch mode toggles on hover. - NotchMetrics adds hoverHeightBoostCapsule (8pt). Layout.hovered() for no-notch now returns barHeight = menuBarHeight + boost. - Window container sized to hover dimensions so the bar can expand into the extra height without changing the NSWindow frame. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Soft black shadow appears under the bar on hover, animating in with the size growth and fading out on exit. Window container gains shadowPadding (28pt sides + bottom) so the shadow renders without NSWindow clipping. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Previous shadow (opacity 0.45, radius 16, y 8) produced a visible hard edge between the bar bottom and its shadow. Replaced with two stacked soft shadows — a close tight one (0.18 / radius 6) for definition and a wide ambient one (0.12 / radius 22) for diffusion. Lower offsets so the shadow sits around the bar instead of below. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the two-layer shadow with one very soft ambient one (opacity 0.10, radius 20, y=0). Add .compositingGroup() before the shadow so the bar's flat edges don't produce a hard shadow band. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The .shadow primitive in SwiftUI was producing a faint horizontal seam where the bar's flat bottom met its shadow, even with .compositingGroup and zero offset. The seam was a compositor artifact tied to the way shadow gets sampled along sharp shape edges. Switch to a manual halo: render the bar's silhouette behind the bar, filled black, scaled 1.06×1.20 and blurred radius 18. The halo's center is fully covered by the actual bar; only the soft blurred edges peek out as a glow. Because it's a real blurred shape (not a shadow filter), the falloff is smooth gaussian, no artifacts. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Drop the manual halo and SwiftUI .shadow attempts entirely. NSWindow with hasShadow=true and isOpaque=false renders the system's standard window shadow against the bar's alpha silhouette — same model used by Finder, Dock, and Notification Center. Subtle, clean, no compositor seams. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Wire SwiftUI hover state back to NSWindow.hasShadow via an onHoverChange closure. Idle state: hasShadow=false (no shadow, clean silhouette). Hover: hasShadow=true + invalidateShadow() so the system recomputes against the bar's alpha mask. Same Apple-native shadow as Finder, only revealed on hover. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
1 issue found across 10 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="Package.swift">
<violation number="1" location="Package.swift:9">
P2: Hard-coding `/Applications/Xcode.app` for Xcode detection is brittle and can incorrectly disable `PREVIEWS` on valid Xcode setups.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| // Xcode app. When only Command Line Tools are present, gate previews behind | ||
| // the PREVIEWS flag so `swift build` still succeeds. Xcode builds get them | ||
| // automatically. | ||
| let hasXcode = FileManager.default.fileExists(atPath: "/Applications/Xcode.app") |
There was a problem hiding this comment.
P2: Hard-coding /Applications/Xcode.app for Xcode detection is brittle and can incorrectly disable PREVIEWS on valid Xcode setups.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Package.swift, line 9:
<comment>Hard-coding `/Applications/Xcode.app` for Xcode detection is brittle and can incorrectly disable `PREVIEWS` on valid Xcode setups.</comment>
<file context>
@@ -1,22 +1,42 @@
+// Xcode app. When only Command Line Tools are present, gate previews behind
+// the PREVIEWS flag so `swift build` still succeeds. Xcode builds get them
+// automatically.
+let hasXcode = FileManager.default.fileExists(atPath: "/Applications/Xcode.app")
+let appSettings: [SwiftSetting] = hasXcode ? [.define("PREVIEWS")] : []
+
</file context>
Suggested change
| let hasXcode = FileManager.default.fileExists(atPath: "/Applications/Xcode.app") | |
| let hasXcode = ProcessInfo.processInfo.environment["XCODE_VERSION_ACTUAL"] != nil |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Task 1 complete: collapsed Notch Bar with full design polish.
Visual
frame.maxY - visibleFrame.maxYfor accurate measurement).Hover affordance
.pointingHand.Adaptivity
didChangeScreenParametersNotification— display swap, "Larger Text", scale changes are all auto-handled.Architecture
IslandApp(exec, @main + AppDelegate) +IslandAppLib(library, all view code) so SwiftUI Previews work under Xcode 26'sENABLE_DEBUG_DYLIBrequirement.TaskStorefromIslandCoreper the contract.Test plan
NotchBarView.swift→ Canvas Resume