Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/scripts/compose-desktop-parity-shots.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,18 @@
)
# Web keeps calendar header inside the 1280×820 viewport; macOS uses a unified title bar.
WEB_CALENDAR_HEADER_HEIGHT = 48
# Web week view keeps CalendarHeader inside the 1280×820 viewport; macOS uses a
# unified title bar above the content track. Grid-region crops skip the web header
# so both sides start at the demo banner / day-label band.
WEB_GRID_REGION_TOP = WEB_CALENDAR_HEADER_HEIGHT + 48
MAC_MAIN_CONTENT_TOP = 52
GRID_CROP = (0, 0, CONTENT_LEADING_INSET + CONTENT_TRACK_WIDTH, VIEWPORT_HEIGHT)
SIDEBAR_CROP = (CONTENT_LEADING_INSET + CONTENT_TRACK_WIDTH, 0, VIEWPORT_WIDTH, VIEWPORT_HEIGHT)


def grid_region_crop(*, macos: bool) -> tuple[int, int, int, int]:
left, _, right, bottom = GRID_CROP
top = MAC_MAIN_CONTENT_TOP if macos else WEB_CALENDAR_HEADER_HEIGHT
top = MAC_MAIN_CONTENT_TOP if macos else WEB_GRID_REGION_TOP
return (left, top, right, bottom)

SURFACES = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@ public final class TimeGridView: NSView {
palette: (background: NSColor, surface: NSColor, surfaceRaised: NSColor, border: NSColor, text: NSColor, textMuted: NSColor),
currentHour: Int
) {
// Web `CalendarTimeColumn`: `top: calc(100% / TIMED_VISIBLE_HOURS - 5px)`.
let labelColumnTop = max(0, hourHeight - 5)
for hour in 0 ..< Int(ceil(state.civilDayHours)) {
let text = hour == 0 ? "" : (labels.indices.contains(hour - 1) ? labels[hour - 1] : "")
let label = NSTextField(labelWithString: text)
Expand All @@ -399,7 +401,7 @@ public final class TimeGridView: NSView {
label.alignment = .center
label.frame = NSRect(
x: xOffset + 4,
y: Double(hour) * hourHeight + 4,
y: labelColumnTop + Double(hour) * hourHeight + 4,
width: width - 8,
height: 14)
hourGutterView.addSubview(label)
Expand Down Expand Up @@ -575,8 +577,20 @@ public final class TimeGridView: NSView {
timedContentView.layer?.backgroundColor = palette.background.cgColor
let todayKey = CompassDateParsing.formatCalendarDay(state.referenceNow)

let timedTopRule = NSView(
frame: NSRect(
x: snapshot.metrics.marginLeft,
y: 0,
width: timedContentView.frame.width - snapshot.metrics.marginLeft,
height: 1
)
)
timedTopRule.wantsLayer = true
timedTopRule.layer?.backgroundColor = palette.border.cgColor
addGridBackground(timedTopRule, to: timedContentView)

for column in snapshot.columns {
// Web `TimedGrid`: only past days receive the surface tone.
// Web `TimedGrid` `data-[past=true]:bg-surface` on past day columns.
if state.layoutMode == .week, column.key < todayKey {
let tint = NSView(frame: NSRect(x: column.left, y: 0, width: column.width, height: gridHeight))
tint.wantsLayer = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,9 @@ final class NativeParityCaptureTests: XCTestCase {
waitForGridColumnCount(window, atLeast: 5, timeout: 20),
"Expected five day columns in parity week grid")
window.typeKey("t", modifierFlags: [])
RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.6))
// Re-run today/scroll after the timed viewport height settles (viewport-based hourHeight).
window.typeKey("t", modifierFlags: [])
let sundayColumn = window.descendants(matching: .any)["compass-grid-column-2026-06-07"]
XCTAssertTrue(
sundayColumn.waitForExistence(timeout: 20),
Expand All @@ -313,6 +316,9 @@ final class NativeParityCaptureTests: XCTestCase {
XCTAssertTrue(
window.buttons["Morning standup"].waitForExistence(timeout: 20),
"Expected demo-seed timed event on the week grid")
XCTAssertTrue(
window.buttons["Exercise"].waitForExistence(timeout: 20),
"Expected Wednesday Exercise demo event after scroll-to-now parity setup")
let dismissScrollHint = window.buttons["Dismiss"]
if dismissScrollHint.waitForExistence(timeout: 2) {
dismissScrollHint.tap()
Expand Down
15 changes: 13 additions & 2 deletions e2e/parity/seed-demo-fixture.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,19 @@ export async function prepareParityDemoWeek(
}
await page.locator("#mainGrid").focus();
await page.keyboard.press("t");
// Web scroll-to-now uses smooth scrolling; wait for parity PNG alignment with macOS.
await page.waitForTimeout(800);
// Match macOS instant scroll-to-now during parity capture (no mid-animation PNGs).
await page.evaluate(() => {
const timedGrid = document.getElementById("timedColumns");
if (!(timedGrid instanceof HTMLElement)) return;
const timedVisibleHours = 13;
const scrollToNowBufferPx = 150;
const minuteHeight = timedGrid.clientHeight / timedVisibleHours / 60;
const now = new Date();
const minutes = now.getUTCHours() * 60 + now.getUTCMinutes();
const targetTop = Math.max(0, minutes * minuteHeight - scrollToNowBufferPx);
timedGrid.scrollTo({ top: targetTop, behavior: "instant" });
});
await page.waitForTimeout(400);
await page
.getByRole("button", { name: /Exercise|Morning standup/i })
.first()
Expand Down
Loading