From 7628f8cebc284a96cabadb67c49c691f87089f09 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 22 Oct 2026 02:48:47 +0000 Subject: [PATCH 1/5] fix(macos): use web's light panel backdrop and center the welcome panel Web OverlayPanel dims with bg-background/85 over a small blur, so the calendar shows faintly behind settings and welcome. PanelBackdropView used the dark HUD material and the 40% overlay-backdrop dim meant for menus, which read as solid gray. Tint with the 85% background over a window-background blur instead. Web also centers the welcome panel vertically; macOS pinned it to the top. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GKHjv2HDx1DFAnG4cfSxcr --- .../CompassUI/Onboarding/WelcomeModalView.swift | 15 +++++++++------ .../Sources/CompassUI/PanelBackdropView.swift | 8 +++++--- docs/features/desktop-web-parity-checklist.md | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/apps/calendar-macos/CompassUI/Sources/CompassUI/Onboarding/WelcomeModalView.swift b/apps/calendar-macos/CompassUI/Sources/CompassUI/Onboarding/WelcomeModalView.swift index c8321b888d..faed83495b 100644 --- a/apps/calendar-macos/CompassUI/Sources/CompassUI/Onboarding/WelcomeModalView.swift +++ b/apps/calendar-macos/CompassUI/Sources/CompassUI/Onboarding/WelcomeModalView.swift @@ -16,13 +16,16 @@ struct WelcomeModalView: View { ZStack { PanelBackdropView() .ignoresSafeArea() - ScrollView { - panel - .frame(maxWidth: .infinity, alignment: .top) - .padding(.top, 32) - .padding(.bottom, 32) + // Web `OverlayPanel` centers the panel and scrolls (`py-8`) only + // when it is taller than the window. + GeometryReader { geometry in + ScrollView { + panel + .frame(maxWidth: .infinity) + .padding(.vertical, 32) + .frame(minHeight: geometry.size.height) + } } - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top) } .onAppear { model.onboardingStore.setWelcomeFirstVisitOpen(true) diff --git a/apps/calendar-macos/CompassUI/Sources/CompassUI/PanelBackdropView.swift b/apps/calendar-macos/CompassUI/Sources/CompassUI/PanelBackdropView.swift index 6e6ebcac12..f61821d730 100644 --- a/apps/calendar-macos/CompassUI/Sources/CompassUI/PanelBackdropView.swift +++ b/apps/calendar-macos/CompassUI/Sources/CompassUI/PanelBackdropView.swift @@ -1,7 +1,9 @@ import AppKit import SwiftUI -/// Web `OverlayPanel` backdrop: dimmed background with light blur (`backdrop-blur-sm`). +/// Web `OverlayPanel` backdrop: `bg-background/85` over a light blur +/// (`backdrop-blur-sm`), so the calendar shows faintly through. The dark +/// `overlayBackdrop` dim belongs to menus and confirm dialogs, not panels. struct PanelBackdropView: NSViewRepresentable { @Environment(\.nativeWebTheme) private var theme @@ -10,7 +12,7 @@ struct PanelBackdropView: NSViewRepresentable { container.wantsLayer = true let blur = NSVisualEffectView() - blur.material = .hudWindow + blur.material = .windowBackground blur.blendingMode = .withinWindow blur.state = .active blur.translatesAutoresizingMaskIntoConstraints = false @@ -37,7 +39,7 @@ struct PanelBackdropView: NSViewRepresentable { } func updateNSView(_ container: NSView, context: Context) { - context.coordinator.tintView?.layer?.backgroundColor = NSColor(theme.overlayBackdropColor).cgColor + context.coordinator.tintView?.layer?.backgroundColor = NSColor(theme.panelBackdropColor).cgColor } func makeCoordinator() -> Coordinator { Coordinator() } diff --git a/docs/features/desktop-web-parity-checklist.md b/docs/features/desktop-web-parity-checklist.md index c5a70fb3b7..bc0c40251a 100644 --- a/docs/features/desktop-web-parity-checklist.md +++ b/docs/features/desktop-web-parity-checklist.md @@ -28,7 +28,7 @@ This checklist compares **apps/calendar-web** (reference UI) with **apps/calenda | --- | --- | --- | --- | --- | | Light Beach / Dark Abyss palettes | `[data-theme]` in `index.css` | `ThemeTokens.lightBeach` / `darkAbyss` | ✅ | Generated from same CSS | | SwiftUI accessor coverage | Tailwind `color-*` for all 22 roles | `NativeWebTheme` exposes subset on `ThemeTokenColor+SwiftUI.swift` | 🟡 | Missing convenience colors: `surfaceRaised`, `textSubtle`, `borderStrong`, `accentHover`, `accentStrong`, `accentSecondaryHover`, `onAccent`, `info`, `shadowDefault` | -| Panel modal backdrop | `OverlayPanel` / `bg-background/85` | `panelBackdropColor` = `background` @ 85% opacity | 🟡 | Web uses `--overlay-backdrop` for dimming; panel tint is separate | +| Panel modal backdrop | `OverlayPanel` / `bg-background/85` + `backdrop-blur-sm` | `PanelBackdropView`: `panelBackdropColor` (`background` @ 85%) over a within-window blur | ✅ | Settings and welcome used the dark `overlayBackdrop` dim and read as solid gray; that dim stays for menus and confirm dialogs. Welcome centers vertically like web | | Event default fill hex | `theme.util.ts` / deck | `EventCardView.swift` literals `#454442`, `#82A0B2` | 🟡 | Values align; not read from tokens | | Event focus ring color | `--event-focus-color` + outline | `EventCardView` CALayer border from fill-aware helper | 🟡 | Same intent, different paint model | | Holiday / gradient accents | CSS gradients on chips | Mostly solid fills | 🟡 | Audit per calendar color id | From 48bcc718cbda71d885255a2fe993b8d0713f07ee Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 22 Oct 2026 03:08:48 +0000 Subject: [PATCH 2/5] fix(macos): name welcome buttons by their title, not title plus keycap The welcome modal's buttons pair a title with a keycap chip and had no explicit label, so accessibility read "Get started for free, Enter". The onboarding parity capture added in #4707 clicks buttons["Get started for free"] and fails on every run since. Label each welcome button with its title; the keycap is a visual hint. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GKHjv2HDx1DFAnG4cfSxcr (cherry picked from commit 5d42363f902f34d41b36dc5b6fd00f17efcba748) --- .../Sources/CompassUI/Onboarding/WelcomeModalView.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/calendar-macos/CompassUI/Sources/CompassUI/Onboarding/WelcomeModalView.swift b/apps/calendar-macos/CompassUI/Sources/CompassUI/Onboarding/WelcomeModalView.swift index faed83495b..224ab1e987 100644 --- a/apps/calendar-macos/CompassUI/Sources/CompassUI/Onboarding/WelcomeModalView.swift +++ b/apps/calendar-macos/CompassUI/Sources/CompassUI/Onboarding/WelcomeModalView.swift @@ -182,6 +182,8 @@ struct WelcomeModalView: View { .shadow(color: .black.opacity(0.15), radius: 6, y: 3) } .buttonStyle(.plain) + // The keycap is a visual hint; the title alone names the button. + .accessibilityLabel(title) } private func secondaryButton(title: String, hint: String, action: @escaping () -> Void) -> some View { @@ -198,6 +200,8 @@ struct WelcomeModalView: View { .overlay(Capsule().stroke(theme.borderColor, lineWidth: 1)) } .buttonStyle(.plain) + // The keycap is a visual hint; the title alone names the button. + .accessibilityLabel(title) } private func quietTextButton(title: String, hint: String, action: @escaping () -> Void) -> some View { @@ -211,6 +215,8 @@ struct WelcomeModalView: View { .frame(maxWidth: .infinity, minHeight: 32) } .buttonStyle(.plain) + // The keycap is a visual hint; the title alone names the button. + .accessibilityLabel(title) } private func pillButton(title: String, hint: String, action: @escaping () -> Void) -> some View { @@ -228,5 +234,7 @@ struct WelcomeModalView: View { .overlay(Capsule().stroke(theme.borderColor, lineWidth: 1)) } .buttonStyle(.plain) + // The keycap is a visual hint; the title alone names the button. + .accessibilityLabel(title) } } From efd0ee37b7d4f5c23863f0e3dbc23b9f0ea8aa65 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 22 Oct 2026 03:18:26 +0000 Subject: [PATCH 3/5] test(macos): scope the welcome capture's button clicks to the welcome panel With the welcome buttons named by title, buttons["Next"] also matched the grid's week "Next" button behind the modal, so the click failed with multiple matches. Query the buttons inside compass-native-welcome-modal. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GKHjv2HDx1DFAnG4cfSxcr (cherry picked from commit 77e87f4e309cfb77c501973831d1afc29f33c405) --- .../CompassUITests/NativeParityCaptureTests.swift | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/calendar-macos/CompassUITests/NativeParityCaptureTests.swift b/apps/calendar-macos/CompassUITests/NativeParityCaptureTests.swift index f7b9668808..0abc77cb00 100644 --- a/apps/calendar-macos/CompassUITests/NativeParityCaptureTests.swift +++ b/apps/calendar-macos/CompassUITests/NativeParityCaptureTests.swift @@ -260,14 +260,16 @@ final class NativeParityCaptureTests: XCTestCase { app.launch() let window = app.windows["Compass"] XCTAssertTrue(window.waitForExistence(timeout: 15)) - XCTAssertTrue( - window.descendants(matching: .any)["compass-native-welcome-modal"].waitForExistence(timeout: 15)) + let welcome = window.descendants(matching: .any)["compass-native-welcome-modal"] + XCTAssertTrue(welcome.waitForExistence(timeout: 15)) sleep(1) NativeImageSnapshotSupport.captureWindow(window, named: "onboarding-welcome") - window.buttons["Get started for free"].click() - window.buttons["Next"].click() + // Scope to the panel: the grid's own "Next" (week) button is still in + // the window's accessibility tree behind the modal. + welcome.buttons["Get started for free"].click() + welcome.buttons["Next"].click() XCTAssertTrue( - window.buttons["Start free trial with Google"].waitForExistence(timeout: 8)) + welcome.buttons["Start free trial with Google"].waitForExistence(timeout: 8)) sleep(1) NativeImageSnapshotSupport.captureWindow(window, named: "onboarding-welcome-account-choice") } From d01361a8f793a97ec212ed336a6a2845642855dc Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 22 Oct 2026 03:54:23 +0000 Subject: [PATCH 4/5] test(macos): wait for the local-only choice on the welcome account step Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GKHjv2HDx1DFAnG4cfSxcr (cherry picked from commit b031ea7615b6c8a37b21f6900fd31c7c1c164767) --- .../CompassUITests/NativeParityCaptureTests.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/calendar-macos/CompassUITests/NativeParityCaptureTests.swift b/apps/calendar-macos/CompassUITests/NativeParityCaptureTests.swift index 0abc77cb00..0a04d41297 100644 --- a/apps/calendar-macos/CompassUITests/NativeParityCaptureTests.swift +++ b/apps/calendar-macos/CompassUITests/NativeParityCaptureTests.swift @@ -268,8 +268,9 @@ final class NativeParityCaptureTests: XCTestCase { // the window's accessibility tree behind the modal. welcome.buttons["Get started for free"].click() welcome.buttons["Next"].click() - XCTAssertTrue( - welcome.buttons["Start free trial with Google"].waitForExistence(timeout: 8)) + // The provider buttons depend on the backend config; the local-only + // choice is always on the account step. + XCTAssertTrue(welcome.buttons["On this device only"].waitForExistence(timeout: 8)) sleep(1) NativeImageSnapshotSupport.captureWindow(window, named: "onboarding-welcome-account-choice") } From 9ee84757a9340030c141e0c531fa1ab626987ace Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 22 Oct 2026 04:41:53 +0000 Subject: [PATCH 5/5] fix(macos): register the welcome account-choice parity surface The onboarding capture exports onboarding-welcome-account-choice, but the name was not a ParityCaptureSurface, so the debug URL never parsed and the export timed out. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GKHjv2HDx1DFAnG4cfSxcr (cherry picked from commit 07b3cce29ab32d86c7672b047c28eb04b6bec98e) --- .../Sources/CompassKit/Layout/ParityCaptureSurface.swift | 1 + .../CompassKitTests/DesktopDebugCommandTests.swift | 4 ++++ docs/features/desktop-web-parity-checklist.md | 1 + 3 files changed, 6 insertions(+) diff --git a/apps/calendar-macos/CompassKit/Sources/CompassKit/Layout/ParityCaptureSurface.swift b/apps/calendar-macos/CompassKit/Sources/CompassKit/Layout/ParityCaptureSurface.swift index e4ea81e82b..b656dedb05 100644 --- a/apps/calendar-macos/CompassKit/Sources/CompassKit/Layout/ParityCaptureSurface.swift +++ b/apps/calendar-macos/CompassKit/Sources/CompassKit/Layout/ParityCaptureSurface.swift @@ -15,6 +15,7 @@ public enum ParityCaptureSurface: String, CaseIterable, Sendable { case commandPalette = "command-palette" case settings = "settings" case onboardingWelcome = "onboarding-welcome" + case onboardingWelcomeAccountChoice = "onboarding-welcome-account-choice" public static func isValid(_ name: String) -> Bool { ParityCaptureSurface(rawValue: name) != nil diff --git a/apps/calendar-macos/CompassKitTests/DesktopDebugCommandTests.swift b/apps/calendar-macos/CompassKitTests/DesktopDebugCommandTests.swift index 0825b9d98d..ed6367d82f 100644 --- a/apps/calendar-macos/CompassKitTests/DesktopDebugCommandTests.swift +++ b/apps/calendar-macos/CompassKitTests/DesktopDebugCommandTests.swift @@ -59,6 +59,10 @@ final class DesktopDebugCommandTests: XCTestCase { XCTAssertEqual( DesktopDebugCommand.parse("compass://debug/parity-export-title-bar-reference"), .parityExportTitleBarReference) + // Every name NativeParityCaptureTests exports must parse, or the export times out. + XCTAssertEqual( + DesktopDebugCommand.parse("compass://debug/parity-export?name=onboarding-welcome-account-choice"), + .parityExport(surface: "onboarding-welcome-account-choice")) XCTAssertNil(DesktopDebugCommand.parse("compass://debug/parity-export?name=not-a-surface")) XCTAssertNil(DesktopDebugCommand.parse("compass://debug/unknown")) diff --git a/docs/features/desktop-web-parity-checklist.md b/docs/features/desktop-web-parity-checklist.md index bc0c40251a..89170ccc46 100644 --- a/docs/features/desktop-web-parity-checklist.md +++ b/docs/features/desktop-web-parity-checklist.md @@ -341,6 +341,7 @@ Each PR should link a child issue, include before/after screenshots (web Chromiu | 2026-10-21 | Hold-Mod sidebar chips: month picker and Up next chips render, calendar list chip moved onto the list (compare run 39634795849) | | 2026-10-21 | Per-account page-jump targets (web `calendar-account:` ids) | | 2026-10-21 | Event jump chips use web day-prefix labels (W1, SU2) and digits after a day pick | +| 2026-10-22 | macOS capture: register `onboarding-welcome-account-choice` so the welcome account step exports instead of timing out | ---