From fb1a2059e4699201bf8c87698746118b60b1195e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=8B=E1=85=AD=E1=86=BC=E1=84=90?= =?UTF-8?q?=E1=85=A2?= Date: Mon, 31 Aug 2026 23:44:02 +0900 Subject: [PATCH 1/8] =?UTF-8?q?=EC=BA=98=EB=A6=B0=EB=8D=94=20=EC=BD=98?= =?UTF-8?q?=ED=85=90=EC=B8=A0=EC=99=80=20=ED=94=8C=EB=A1=9C=ED=8C=85=20?= =?UTF-8?q?=EC=BB=A8=ED=8A=B8=EB=A1=A4=20=EB=A0=88=EC=9D=B4=EC=96=B4=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calendar-demo/CalendarDemoRoute.tsx | 276 +++++++++--------- .../calendar-demo/calendar-demo-styles.ts | 18 +- 2 files changed, 149 insertions(+), 145 deletions(-) diff --git a/site/src/routes/calendar-demo/CalendarDemoRoute.tsx b/site/src/routes/calendar-demo/CalendarDemoRoute.tsx index a8408b46..d38952c0 100644 --- a/site/src/routes/calendar-demo/CalendarDemoRoute.tsx +++ b/site/src/routes/calendar-demo/CalendarDemoRoute.tsx @@ -45,7 +45,6 @@ import { ToolbarGroup, ToolbarLayout, ToolbarRegion, - ToolbarSeparator, Toggle, } from "@interactive-os/json-document-ui-primitives-react"; import { useDemoEmbed } from "../../shared/demo-workbench/DemoPage"; @@ -312,27 +311,20 @@ export function CalendarDemoRoute(props: { + - {visiblePeriodLabel(view, visibleDate, { - monthNames: months, - weekSeparator: " – ", - })} setVisibleDate(shiftVisibleDate(visibleDate, view, -1))}> + setLocation(view === "year" ? "month" : view, today)}>Today setVisibleDate(shiftVisibleDate(visibleDate, view, 1))}> - - - setLocation(view === "year" ? "month" : view, today)}>Today - - + + + {(context) => ( + <> + + {context.visible.includes("sources") ? ( + + ) : null} + + )} + + )} >
-
- +
-
-
diff --git a/site/src/routes/calendar-demo/calendar-demo-styles.ts b/site/src/routes/calendar-demo/calendar-demo-styles.ts index 09934eee..89867354 100644 --- a/site/src/routes/calendar-demo/calendar-demo-styles.ts +++ b/site/src/routes/calendar-demo/calendar-demo-styles.ts @@ -5,7 +5,9 @@ const chipFill = "bg-background-subtle text-foreground-strong data-[calendar-col export const calendarDemoRecipe = tv({ slots: { - shell: "relative isolate overflow-hidden bg-background-canvas", + shell: "relative isolate overflow-hidden bg-background-canvas [&>[data-ui-toolbar=product]]:absolute [&>[data-ui-toolbar=product]]:right-4 [&>[data-ui-toolbar=product]]:top-3 [&>[data-ui-toolbar=product]]:z-50 [&>[data-ui-toolbar=product]]:w-auto [&>[data-ui-toolbar=product]]:max-w-[calc(100%-1.5rem)] sm:[&>[data-ui-toolbar=product]]:max-w-[calc(100%-8rem)] [&>[data-ui-toolbar=product]]:rounded-surface [&>[data-ui-toolbar=product]]:border [&>[data-ui-toolbar=product]]:border-line-subtle/50 [&>[data-ui-toolbar=product]]:bg-background-canvas [&>[data-ui-toolbar=product]]:px-1 [&>[data-ui-toolbar=product]]:py-1 [&>[data-ui-toolbar=product]]:shadow-surface [&>[data-ui-toolbar=product]]:transition-[border-color,box-shadow] [&>[data-ui-toolbar=product]]:hover:border-line-subtle [&>[data-ui-toolbar=product]]:focus-within:border-line-subtle [&>[data-ui-toolbar=product]_[data-placement=end]]:overflow-visible [&>[data-ui-toolbar=product]_[data-ui-segment=true]]:border-transparent [&>[data-ui-toolbar=product]_[data-ui-segment=true]]:bg-transparent [&>[data-ui-toolbar=product]_[data-ui-segment=true]]:shadow-none [&>[data-ui-toolbar=product]_[data-ui-segment=true]]:hover:bg-background-subtle/60 [&>[data-ui-toolbar=product]_[data-ui-segment=true][aria-checked=true]]:bg-background-subtle [&>[data-ui-toolbar=product]_[data-ui-segment=true][aria-checked=true]]:text-foreground-strong", + controlLayer: "pointer-events-none absolute inset-0 z-40 [&>*]:pointer-events-auto", + contentLayer: "relative z-0 h-full min-h-0 min-w-0 pb-24", allDayEvent: `h-full w-full rounded-control border-0 px-2 py-0.5 text-left text-xs leading-4 ${chipFill} ${chipRail}`, hourRule: "absolute inset-x-0 border-t border-line-subtle/70", timedEvent: `group flex h-full w-full flex-col items-stretch gap-0 overflow-hidden rounded-control border-0 px-2 py-0.5 pl-2.5 text-left text-xs leading-4 ${chipFill} ${chipRail}`, @@ -18,17 +20,17 @@ export const calendarDemoRecipe = tv({ quietAction: "border-0 bg-transparent p-0 shadow-none hover:border-0 hover:bg-transparent", monthOverflow: "absolute left-0 top-0 z-30 flex w-max min-w-full max-w-56 flex-col gap-0.5 p-1.5", monthHead: "px-2 py-1.5 text-center text-xs text-foreground-muted", - weekSticky: "z-30 shrink-0 border-b border-line-subtle/60 bg-background-canvas", + weekSticky: "z-30 shrink-0 border-b border-line-subtle/60 bg-background-canvas pt-14", weekHours: "min-h-0 flex-1 overflow-auto", weekHead: "flex flex-col items-center gap-0.5 px-1 py-2 text-center", weekCell: "relative border-l border-line-subtle/60", selectedSlot: "pointer-events-none absolute inset-x-0 z-10 rounded-control bg-background-subtle/60 ring-1 ring-inset ring-line-subtle/40", resizeEdge: "absolute inset-x-0 bottom-0 h-2", resizeEdgeVertical: "absolute right-0 top-0 h-full w-2", - period: "px-1 text-sm font-medium text-foreground-strong", + periodHeading: "pointer-events-none absolute left-14 top-4 z-40 m-0 hidden whitespace-nowrap text-sm font-medium text-foreground-strong sm:block", todayAction: "border-0 bg-transparent px-2 shadow-none hover:border-0 hover:bg-background-subtle", - contextualSidebar: "relative z-30 w-20 shrink-0 rounded-control px-1 py-2 outline-none transition-[width] focus-within:w-44 hover:w-44 focus-visible:ring-2 focus-visible:ring-line-accent/25", - sidebarHint: "block text-center text-overline text-foreground-muted [writing-mode:vertical-rl]", + toolbarSources: "relative grid size-8 place-items-center rounded-control outline-none focus-visible:ring-2 focus-visible:ring-line-accent/25", + sidebarHint: "grid h-5 place-items-center text-foreground-muted", yearMonth: "flex min-h-0 w-full flex-col gap-1 px-1 py-1 text-left", yearDay: "flex aspect-square w-full items-center justify-center border-0 bg-transparent p-0 text-overline shadow-none hover:border-0 hover:bg-transparent", @@ -37,8 +39,8 @@ export const calendarDemoRecipe = tv({ today: "font-semibold text-foreground-accent", todayMark: "font-semibold text-foreground-strong", dayNumber: "inline-flex size-7 items-center justify-center text-sm font-medium", - sidebar: "flex w-44 shrink-0 flex-col gap-3 overflow-auto pr-1", - inspector: "group/details z-40 flex w-80 min-w-0 flex-col gap-3 overflow-auto border border-line-subtle/60 p-3.5 shadow-overlay", + sidebar: "absolute right-0 top-[calc(100%+0.75rem)] flex max-h-[calc(100vh-8rem)] w-44 shrink-0 flex-col gap-3 overflow-auto rounded-surface border border-line-subtle/60 bg-background-canvas p-3 shadow-overlay", + inspector: "group/details z-50 flex w-80 min-w-0 flex-col gap-3 overflow-auto border border-line-subtle/60 bg-background-canvas p-3.5 shadow-surface", field: "grid gap-1", inspectorHeader: "flex min-w-0 items-center gap-2", inspectorTitle: "m-0 min-w-0 flex-1 truncate px-0 text-base font-semibold tracking-tight text-foreground-strong", @@ -50,7 +52,7 @@ export const calendarDemoRecipe = tv({ eventTime: "truncate text-overline font-normal text-foreground-muted", creationTimeHint: "pointer-events-none absolute left-1 z-20 -translate-y-1/2 whitespace-nowrap text-overline tabular-nums leading-none text-foreground-muted/55", hourLabel: "absolute right-1 whitespace-nowrap text-right text-overline tabular-nums leading-none text-foreground-muted", - composerDock: "bottom-4 left-1/2 z-30 flex w-[min(42rem,calc(100%-2rem))] -translate-x-1/2 items-center gap-2 rounded-surface border border-line-subtle/70 bg-background-canvas/95 p-2 pl-3 shadow-overlay backdrop-blur", + composerDock: "bottom-4 left-1/2 z-30 flex w-[min(36rem,calc(100%-2rem))] -translate-x-1/2 items-center gap-2 rounded-surface border border-line-subtle/50 bg-background-canvas p-2 pl-3 shadow-surface", composerDockFixed: "fixed", composerDockEmbedded: "absolute", composerSpark: "shrink-0 text-foreground-accent", From 56f511cc03212f16495f8dba8bede049c5677304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=8B=E1=85=AD=E1=86=BC=E1=84=90?= =?UTF-8?q?=E1=85=A2?= Date: Tue, 1 Sep 2026 00:25:56 +0900 Subject: [PATCH 2/8] =?UTF-8?q?=EC=BA=98=EB=A6=B0=EB=8D=94=20=ED=94=8C?= =?UTF-8?q?=EB=A1=9C=ED=8C=85=20=ED=91=9C=EB=A9=B4=20=EA=B3=A1=EB=A5=A0=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- site/src/routes/calendar-demo/calendar-demo-styles.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/site/src/routes/calendar-demo/calendar-demo-styles.ts b/site/src/routes/calendar-demo/calendar-demo-styles.ts index 89867354..cd263501 100644 --- a/site/src/routes/calendar-demo/calendar-demo-styles.ts +++ b/site/src/routes/calendar-demo/calendar-demo-styles.ts @@ -5,7 +5,7 @@ const chipFill = "bg-background-subtle text-foreground-strong data-[calendar-col export const calendarDemoRecipe = tv({ slots: { - shell: "relative isolate overflow-hidden bg-background-canvas [&>[data-ui-toolbar=product]]:absolute [&>[data-ui-toolbar=product]]:right-4 [&>[data-ui-toolbar=product]]:top-3 [&>[data-ui-toolbar=product]]:z-50 [&>[data-ui-toolbar=product]]:w-auto [&>[data-ui-toolbar=product]]:max-w-[calc(100%-1.5rem)] sm:[&>[data-ui-toolbar=product]]:max-w-[calc(100%-8rem)] [&>[data-ui-toolbar=product]]:rounded-surface [&>[data-ui-toolbar=product]]:border [&>[data-ui-toolbar=product]]:border-line-subtle/50 [&>[data-ui-toolbar=product]]:bg-background-canvas [&>[data-ui-toolbar=product]]:px-1 [&>[data-ui-toolbar=product]]:py-1 [&>[data-ui-toolbar=product]]:shadow-surface [&>[data-ui-toolbar=product]]:transition-[border-color,box-shadow] [&>[data-ui-toolbar=product]]:hover:border-line-subtle [&>[data-ui-toolbar=product]]:focus-within:border-line-subtle [&>[data-ui-toolbar=product]_[data-placement=end]]:overflow-visible [&>[data-ui-toolbar=product]_[data-ui-segment=true]]:border-transparent [&>[data-ui-toolbar=product]_[data-ui-segment=true]]:bg-transparent [&>[data-ui-toolbar=product]_[data-ui-segment=true]]:shadow-none [&>[data-ui-toolbar=product]_[data-ui-segment=true]]:hover:bg-background-subtle/60 [&>[data-ui-toolbar=product]_[data-ui-segment=true][aria-checked=true]]:bg-background-subtle [&>[data-ui-toolbar=product]_[data-ui-segment=true][aria-checked=true]]:text-foreground-strong", + shell: "relative isolate overflow-hidden bg-background-canvas [&>[data-ui-toolbar=product]]:absolute [&>[data-ui-toolbar=product]]:right-4 [&>[data-ui-toolbar=product]]:top-3 [&>[data-ui-toolbar=product]]:z-50 [&>[data-ui-toolbar=product]]:w-auto [&>[data-ui-toolbar=product]]:max-w-[calc(100%-1.5rem)] sm:[&>[data-ui-toolbar=product]]:max-w-[calc(100%-8rem)] [&>[data-ui-toolbar=product]]:rounded-full [&>[data-ui-toolbar=product]]:border [&>[data-ui-toolbar=product]]:border-line-subtle/35 [&>[data-ui-toolbar=product]]:bg-background-canvas [&>[data-ui-toolbar=product]]:px-1 [&>[data-ui-toolbar=product]]:py-1 [&>[data-ui-toolbar=product]]:shadow-none [&>[data-ui-toolbar=product]]:transition-[border-color,box-shadow] [&>[data-ui-toolbar=product]]:hover:border-line-subtle/60 [&>[data-ui-toolbar=product]]:focus-within:border-line-subtle/60 [&>[data-ui-toolbar=product]_[data-placement=end]]:overflow-visible [&>[data-ui-toolbar=product]_[data-ui-segment=true]]:rounded-full [&>[data-ui-toolbar=product]_[data-ui-segment=true]]:border-transparent [&>[data-ui-toolbar=product]_[data-ui-segment=true]]:bg-transparent [&>[data-ui-toolbar=product]_[data-ui-segment=true]]:shadow-none [&>[data-ui-toolbar=product]_[data-ui-segment=true]]:hover:bg-background-subtle/60 [&>[data-ui-toolbar=product]_[data-ui-segment=true][aria-checked=true]]:bg-background-subtle [&>[data-ui-toolbar=product]_[data-ui-segment=true][aria-checked=true]]:text-foreground-strong", controlLayer: "pointer-events-none absolute inset-0 z-40 [&>*]:pointer-events-auto", contentLayer: "relative z-0 h-full min-h-0 min-w-0 pb-24", allDayEvent: `h-full w-full rounded-control border-0 px-2 py-0.5 text-left text-xs leading-4 ${chipFill} ${chipRail}`, @@ -29,7 +29,7 @@ export const calendarDemoRecipe = tv({ resizeEdgeVertical: "absolute right-0 top-0 h-full w-2", periodHeading: "pointer-events-none absolute left-14 top-4 z-40 m-0 hidden whitespace-nowrap text-sm font-medium text-foreground-strong sm:block", todayAction: "border-0 bg-transparent px-2 shadow-none hover:border-0 hover:bg-background-subtle", - toolbarSources: "relative grid size-8 place-items-center rounded-control outline-none focus-visible:ring-2 focus-visible:ring-line-accent/25", + toolbarSources: "relative grid size-8 place-items-center rounded-full outline-none focus-visible:ring-2 focus-visible:ring-line-accent/25", sidebarHint: "grid h-5 place-items-center text-foreground-muted", yearMonth: "flex min-h-0 w-full flex-col gap-1 px-1 py-1 text-left", @@ -39,8 +39,8 @@ export const calendarDemoRecipe = tv({ today: "font-semibold text-foreground-accent", todayMark: "font-semibold text-foreground-strong", dayNumber: "inline-flex size-7 items-center justify-center text-sm font-medium", - sidebar: "absolute right-0 top-[calc(100%+0.75rem)] flex max-h-[calc(100vh-8rem)] w-44 shrink-0 flex-col gap-3 overflow-auto rounded-surface border border-line-subtle/60 bg-background-canvas p-3 shadow-overlay", - inspector: "group/details z-50 flex w-80 min-w-0 flex-col gap-3 overflow-auto border border-line-subtle/60 bg-background-canvas p-3.5 shadow-surface", + sidebar: "absolute right-0 top-[calc(100%+0.75rem)] flex max-h-[calc(100vh-8rem)] w-44 shrink-0 flex-col gap-3 overflow-auto rounded-surface border border-line-subtle/45 bg-background-canvas p-3 shadow-overlay", + inspector: "group/details z-50 flex w-80 min-w-0 flex-col gap-3 overflow-auto rounded-surface border border-line-subtle/45 bg-background-canvas p-3.5 shadow-surface", field: "grid gap-1", inspectorHeader: "flex min-w-0 items-center gap-2", inspectorTitle: "m-0 min-w-0 flex-1 truncate px-0 text-base font-semibold tracking-tight text-foreground-strong", @@ -52,7 +52,7 @@ export const calendarDemoRecipe = tv({ eventTime: "truncate text-overline font-normal text-foreground-muted", creationTimeHint: "pointer-events-none absolute left-1 z-20 -translate-y-1/2 whitespace-nowrap text-overline tabular-nums leading-none text-foreground-muted/55", hourLabel: "absolute right-1 whitespace-nowrap text-right text-overline tabular-nums leading-none text-foreground-muted", - composerDock: "bottom-4 left-1/2 z-30 flex w-[min(36rem,calc(100%-2rem))] -translate-x-1/2 items-center gap-2 rounded-surface border border-line-subtle/50 bg-background-canvas p-2 pl-3 shadow-surface", + composerDock: "bottom-4 left-1/2 z-30 flex w-[min(36rem,calc(100%-2rem))] -translate-x-1/2 items-center gap-2 rounded-full border border-line-subtle/55 bg-background-canvas p-2 pl-3 shadow-none", composerDockFixed: "fixed", composerDockEmbedded: "absolute", composerSpark: "shrink-0 text-foreground-accent", From 22c7ddda5d1c48d6234630630578e641032eb966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=8B=E1=85=AD=E1=86=BC=E1=84=90?= =?UTF-8?q?=E1=85=A2?= Date: Tue, 1 Sep 2026 00:34:41 +0900 Subject: [PATCH 3/8] =?UTF-8?q?=EC=BA=98=EB=A6=B0=EB=8D=94=20=EC=BD=98?= =?UTF-8?q?=ED=85=90=EC=B8=A0=20=EC=8B=9C=EA=B0=84=20=EC=9C=84=EA=B3=84=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/routes/calendar-demo/CalendarDemoRoute.tsx | 4 ++-- .../routes/calendar-demo/calendar-demo-styles.ts | 14 +++++++------- site/tests/unit/calendar-product-design.test.ts | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/site/src/routes/calendar-demo/CalendarDemoRoute.tsx b/site/src/routes/calendar-demo/CalendarDemoRoute.tsx index d38952c0..59102513 100644 --- a/site/src/routes/calendar-demo/CalendarDemoRoute.tsx +++ b/site/src/routes/calendar-demo/CalendarDemoRoute.tsx @@ -268,8 +268,8 @@ export function CalendarDemoRoute(props: { weekday: ui.text.meta, dayNumber: styles.dayNumber(), today: styles.todayMark(), - allDayLabel: classes("px-1 py-2 text-right", ui.text.meta), - allDayCell: classes("min-h-10", styles.weekCell()), + allDayLabel: classes("whitespace-nowrap px-1 py-1.5 text-right text-foreground-muted/70", ui.text.meta), + allDayCell: classes("min-h-8", styles.weekCell()), allDayEventContainer: "group/event relative z-10 mx-0.5 my-1", allDayEvent: styles.allDayEvent(), resizeAllDayEnd: styles.resizeEdgeVertical(), diff --git a/site/src/routes/calendar-demo/calendar-demo-styles.ts b/site/src/routes/calendar-demo/calendar-demo-styles.ts index cd263501..010a63b4 100644 --- a/site/src/routes/calendar-demo/calendar-demo-styles.ts +++ b/site/src/routes/calendar-demo/calendar-demo-styles.ts @@ -9,7 +9,7 @@ export const calendarDemoRecipe = tv({ controlLayer: "pointer-events-none absolute inset-0 z-40 [&>*]:pointer-events-auto", contentLayer: "relative z-0 h-full min-h-0 min-w-0 pb-24", allDayEvent: `h-full w-full rounded-control border-0 px-2 py-0.5 text-left text-xs leading-4 ${chipFill} ${chipRail}`, - hourRule: "absolute inset-x-0 border-t border-line-subtle/70", + hourRule: "absolute inset-x-0 border-t border-line-subtle/45", timedEvent: `group flex h-full w-full flex-col items-stretch gap-0 overflow-hidden rounded-control border-0 px-2 py-0.5 pl-2.5 text-left text-xs leading-4 ${chipFill} ${chipRail}`, monthWeek: "relative grid min-w-[36rem] grid-cols-7 border-t border-line-subtle/60", monthDay: "relative z-0 flex min-h-32 w-full flex-col items-stretch px-1.5 pb-1 text-left text-xs", @@ -20,11 +20,11 @@ export const calendarDemoRecipe = tv({ quietAction: "border-0 bg-transparent p-0 shadow-none hover:border-0 hover:bg-transparent", monthOverflow: "absolute left-0 top-0 z-30 flex w-max min-w-full max-w-56 flex-col gap-0.5 p-1.5", monthHead: "px-2 py-1.5 text-center text-xs text-foreground-muted", - weekSticky: "z-30 shrink-0 border-b border-line-subtle/60 bg-background-canvas pt-14", + weekSticky: "z-30 shrink-0 border-b border-line-subtle/40 bg-background-canvas pt-14", weekHours: "min-h-0 flex-1 overflow-auto", weekHead: "flex flex-col items-center gap-0.5 px-1 py-2 text-center", - weekCell: "relative border-l border-line-subtle/60", - selectedSlot: "pointer-events-none absolute inset-x-0 z-10 rounded-control bg-background-subtle/60 ring-1 ring-inset ring-line-subtle/40", + weekCell: "relative border-l border-line-subtle/30 outline-none focus-visible:ring-0 focus-visible:ring-offset-0", + selectedSlot: "pointer-events-none absolute inset-x-1 z-10 rounded-control bg-background-accent-subtle/70 before:absolute before:inset-y-1 before:left-1 before:w-0.5 before:rounded-full before:bg-background-accent", resizeEdge: "absolute inset-x-0 bottom-0 h-2", resizeEdgeVertical: "absolute right-0 top-0 h-full w-2", periodHeading: "pointer-events-none absolute left-14 top-4 z-40 m-0 hidden whitespace-nowrap text-sm font-medium text-foreground-strong sm:block", @@ -38,7 +38,7 @@ export const calendarDemoRecipe = tv({ nowLine: "pointer-events-none absolute inset-x-0 z-20 border-t border-line-accent", today: "font-semibold text-foreground-accent", todayMark: "font-semibold text-foreground-strong", - dayNumber: "inline-flex size-7 items-center justify-center text-sm font-medium", + dayNumber: "inline-flex size-7 items-center justify-center text-sm font-medium text-foreground-strong", sidebar: "absolute right-0 top-[calc(100%+0.75rem)] flex max-h-[calc(100vh-8rem)] w-44 shrink-0 flex-col gap-3 overflow-auto rounded-surface border border-line-subtle/45 bg-background-canvas p-3 shadow-overlay", inspector: "group/details z-50 flex w-80 min-w-0 flex-col gap-3 overflow-auto rounded-surface border border-line-subtle/45 bg-background-canvas p-3.5 shadow-surface", field: "grid gap-1", @@ -47,11 +47,11 @@ export const calendarDemoRecipe = tv({ inspectorActions: "flex shrink-0 items-center gap-0.5 [&_[data-ui-control=command]]:size-7 [&_[data-ui-control=command]]:border-0 [&_[data-ui-control=command]]:bg-transparent [&_[data-ui-control=command]]:p-0 [&_[data-ui-control=command]]:shadow-none", eventSummary: "grid gap-2 border-t border-line-subtle/40 pt-3 text-xs text-foreground-muted [&_p]:m-0 [&_p]:flex [&_p]:items-center [&_p]:gap-2 [&_svg]:shrink-0 [&_svg]:text-foreground-muted", detailsEditor: "grid gap-3 border-t border-line-subtle/40 pt-3", - calendarToggle: "group flex w-full items-center justify-start gap-2 border-0 bg-transparent px-1 text-left shadow-none hover:border-0 hover:bg-transparent aria-pressed:border-0 aria-pressed:bg-transparent aria-pressed:text-foreground-strong aria-[pressed=false]:text-foreground-muted", + calendarToggle: "group flex w-full items-center justify-start gap-2 rounded-control border-0 bg-transparent px-2 py-1.5 text-left shadow-none outline-none hover:border-0 hover:bg-background-subtle focus-visible:ring-2 focus-visible:ring-foreground-muted/25 aria-pressed:border-0 aria-pressed:bg-transparent aria-pressed:text-foreground-strong aria-[pressed=false]:text-foreground-muted", calendarSwatch: "size-2.5 shrink-0 rounded-full bg-foreground-muted opacity-40 data-[calendar-color=accent]:bg-background-accent group-aria-pressed:opacity-100", eventTime: "truncate text-overline font-normal text-foreground-muted", creationTimeHint: "pointer-events-none absolute left-1 z-20 -translate-y-1/2 whitespace-nowrap text-overline tabular-nums leading-none text-foreground-muted/55", - hourLabel: "absolute right-1 whitespace-nowrap text-right text-overline tabular-nums leading-none text-foreground-muted", + hourLabel: "absolute right-2 whitespace-nowrap text-right text-overline tabular-nums leading-none text-foreground-muted/70", composerDock: "bottom-4 left-1/2 z-30 flex w-[min(36rem,calc(100%-2rem))] -translate-x-1/2 items-center gap-2 rounded-full border border-line-subtle/55 bg-background-canvas p-2 pl-3 shadow-none", composerDockFixed: "fixed", composerDockEmbedded: "absolute", diff --git a/site/tests/unit/calendar-product-design.test.ts b/site/tests/unit/calendar-product-design.test.ts index d9b4651d..59f38cd1 100644 --- a/site/tests/unit/calendar-product-design.test.ts +++ b/site/tests/unit/calendar-product-design.test.ts @@ -52,9 +52,9 @@ describe("calendar product design", () => { test("time grid keeps calendar structure visible without a full-column hover wash", () => { const css = readFileSync(path.join(siteRoot, "src/app/index.css"), "utf8"); - expect(styles.hourRule()).toContain("border-line-subtle/70"); - expect(styles.weekCell()).toContain("border-line-subtle/60"); - expect(styles.weekSticky()).toContain("border-line-subtle/60"); + expect(styles.hourRule()).toContain("border-line-subtle/45"); + expect(styles.weekCell()).toContain("border-line-subtle/30"); + expect(styles.weekSticky()).toContain("border-line-subtle/40"); expect(styles.monthWeek()).toContain("border-line-subtle/60"); expect(styles.creationTimeHint()).toContain("text-foreground-muted/55"); expect(styles.hourLabel()).toContain("text-foreground-muted"); From 57f580e96411664a17f1e7bc5c32f76f25b56301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=8B=E1=85=AD=E1=86=BC=E1=84=90?= =?UTF-8?q?=E1=85=A2?= Date: Tue, 1 Sep 2026 00:57:15 +0900 Subject: [PATCH 4/8] =?UTF-8?q?=EC=BA=98=EB=A6=B0=EB=8D=94=20=EC=BD=98?= =?UTF-8?q?=ED=85=90=EC=B8=A0=20=EA=B8=80=EC=9E=90=EB=A5=BC=20Markdown=20?= =?UTF-8?q?=EA=B3=84=EC=B8=B5=EC=9C=BC=EB=A1=9C=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../routes/calendar-demo/CalendarDemoRoute.tsx | 16 ++++++++-------- .../routes/calendar-demo/calendar-demo-styles.ts | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/site/src/routes/calendar-demo/CalendarDemoRoute.tsx b/site/src/routes/calendar-demo/CalendarDemoRoute.tsx index 59102513..3c695140 100644 --- a/site/src/routes/calendar-demo/CalendarDemoRoute.tsx +++ b/site/src/routes/calendar-demo/CalendarDemoRoute.tsx @@ -266,7 +266,7 @@ export function CalendarDemoRoute(props: { stickyHeader: classes("grid", styles.weekSticky()), columnHeader: styles.weekHead(), weekday: ui.text.meta, - dayNumber: styles.dayNumber(), + dayNumber: classes(styles.dayNumber(), ui.text.body), today: styles.todayMark(), allDayLabel: classes("whitespace-nowrap px-1 py-1.5 text-right text-foreground-muted/70", ui.text.meta), allDayCell: classes("min-h-8", styles.weekCell()), @@ -277,16 +277,16 @@ export function CalendarDemoRoute(props: { timeViewportFill: styles.weekHours(), hourGutter: "relative overflow-hidden", viewportAnchor: "pointer-events-none absolute left-0 top-0", - hourLabel: styles.hourLabel(), + hourLabel: classes(styles.hourLabel(), ui.text.meta), timeCell: classes("overflow-hidden", styles.weekCell()), selectedSlot: styles.selectedSlot(), hourRule: styles.hourRule(), nowLine: styles.nowLine(), - creationTimeHint: styles.creationTimeHint(), + creationTimeHint: classes(styles.creationTimeHint(), ui.text.meta), timedEventContainer: "group/event absolute z-10", timedEvent: styles.timedEvent(), - eventTitle: "min-w-0 truncate", - eventTime: styles.eventTime(), + eventTitle: classes("min-w-0 truncate", ui.text.meta), + eventTime: classes(styles.eventTime(), ui.text.meta), resizeTimedEnd: styles.resizeEdge(), }} labels={{ @@ -511,7 +511,7 @@ export function CalendarDemoRoute(props: { dayInPeriod: ui.text.body, dayOutsidePeriod: ui.text.meta, dayOverflow: "z-20", - dayNumber: styles.dayNumber(), + dayNumber: classes(styles.dayNumber(), ui.text.body), today: styles.todayMark(), laneSpacer: "shrink-0", moreDisclosure: classes(styles.monthMore(), ui.text.meta), @@ -520,8 +520,8 @@ export function CalendarDemoRoute(props: { eventContainer: "group/event relative z-10 min-w-0 w-full", allDayEvent: styles.monthAllDay(), timedEvent: styles.monthTimed(), - eventTitle: "min-w-0 truncate", - eventTime: styles.eventTime(), + eventTitle: classes("min-w-0 truncate", ui.text.meta), + eventTime: classes(styles.eventTime(), ui.text.meta), resizeEnd: styles.resizeEdgeVertical(), }} labels={{ diff --git a/site/src/routes/calendar-demo/calendar-demo-styles.ts b/site/src/routes/calendar-demo/calendar-demo-styles.ts index 010a63b4..5c9ae08b 100644 --- a/site/src/routes/calendar-demo/calendar-demo-styles.ts +++ b/site/src/routes/calendar-demo/calendar-demo-styles.ts @@ -38,7 +38,7 @@ export const calendarDemoRecipe = tv({ nowLine: "pointer-events-none absolute inset-x-0 z-20 border-t border-line-accent", today: "font-semibold text-foreground-accent", todayMark: "font-semibold text-foreground-strong", - dayNumber: "inline-flex size-7 items-center justify-center text-sm font-medium text-foreground-strong", + dayNumber: "inline-flex size-7 items-center justify-center font-medium text-foreground-strong", sidebar: "absolute right-0 top-[calc(100%+0.75rem)] flex max-h-[calc(100vh-8rem)] w-44 shrink-0 flex-col gap-3 overflow-auto rounded-surface border border-line-subtle/45 bg-background-canvas p-3 shadow-overlay", inspector: "group/details z-50 flex w-80 min-w-0 flex-col gap-3 overflow-auto rounded-surface border border-line-subtle/45 bg-background-canvas p-3.5 shadow-surface", field: "grid gap-1", @@ -49,9 +49,9 @@ export const calendarDemoRecipe = tv({ detailsEditor: "grid gap-3 border-t border-line-subtle/40 pt-3", calendarToggle: "group flex w-full items-center justify-start gap-2 rounded-control border-0 bg-transparent px-2 py-1.5 text-left shadow-none outline-none hover:border-0 hover:bg-background-subtle focus-visible:ring-2 focus-visible:ring-foreground-muted/25 aria-pressed:border-0 aria-pressed:bg-transparent aria-pressed:text-foreground-strong aria-[pressed=false]:text-foreground-muted", calendarSwatch: "size-2.5 shrink-0 rounded-full bg-foreground-muted opacity-40 data-[calendar-color=accent]:bg-background-accent group-aria-pressed:opacity-100", - eventTime: "truncate text-overline font-normal text-foreground-muted", - creationTimeHint: "pointer-events-none absolute left-1 z-20 -translate-y-1/2 whitespace-nowrap text-overline tabular-nums leading-none text-foreground-muted/55", - hourLabel: "absolute right-2 whitespace-nowrap text-right text-overline tabular-nums leading-none text-foreground-muted/70", + eventTime: "truncate font-normal text-foreground-muted", + creationTimeHint: "pointer-events-none absolute left-1 z-20 -translate-y-1/2 whitespace-nowrap tabular-nums text-foreground-muted/55", + hourLabel: "absolute right-2 whitespace-nowrap text-right tabular-nums text-foreground-muted/70", composerDock: "bottom-4 left-1/2 z-30 flex w-[min(36rem,calc(100%-2rem))] -translate-x-1/2 items-center gap-2 rounded-full border border-line-subtle/55 bg-background-canvas p-2 pl-3 shadow-none", composerDockFixed: "fixed", composerDockEmbedded: "absolute", From b69343197664dac7506a865b32dff3659b9c9788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=8B=E1=85=AD=E1=86=BC=E1=84=90?= =?UTF-8?q?=E1=85=A2?= Date: Tue, 1 Sep 2026 01:09:58 +0900 Subject: [PATCH 5/8] =?UTF-8?q?=EC=A3=BC=EA=B0=84=20=EC=BA=98=EB=A6=B0?= =?UTF-8?q?=EB=8D=94=20=ED=91=9C=EC=A4=80=20=EC=8B=9C=EA=B0=84=20=EB=B0=B0?= =?UTF-8?q?=EC=B9=98=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../json-document-calendar/src/calendar-time-grid.tsx | 6 +++--- .../tests/calendar-time-grid.test.tsx | 6 +++++- site/src/routes/calendar-demo/CalendarDemoRoute.tsx | 11 +++++++++-- site/src/routes/calendar-demo/calendar-demo-styles.ts | 5 +++-- .../date-controls-demo/date-controls-demo-styles.ts | 2 +- 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/packages/json-document-calendar/src/calendar-time-grid.tsx b/packages/json-document-calendar/src/calendar-time-grid.tsx index aea1d644..01dc8434 100644 --- a/packages/json-document-calendar/src/calendar-time-grid.tsx +++ b/packages/json-document-calendar/src/calendar-time-grid.tsx @@ -112,7 +112,7 @@ export function CalendarTimeGrid(props: CalendarTimeGridProps): ReactNode { if (start !== null && end !== null) hand.createInterval(start, end); } - const gridColumns = `3.25rem repeat(${days.length}, minmax(4.5rem, 1fr))`; + const gridColumns = `4rem repeat(${days.length}, minmax(4.5rem, 1fr))`; const gridHeight = (props.hourEnd - props.hourStart) * props.pixelsPerHour; return (
- {Array.from({ length: props.hourEnd - props.hourStart }, (_, index) => props.hourStart + index).map((hour) => ( -
+ {Array.from({ length: props.hourEnd - props.hourStart }, (_, index) => index === 0 ? null : props.hourStart + index).map((hour) => hour === null ? null : ( +
{props.labels.hour(hour)}
))} diff --git a/packages/json-document-calendar/tests/calendar-time-grid.test.tsx b/packages/json-document-calendar/tests/calendar-time-grid.test.tsx index 5709b4c0..b39ad427 100644 --- a/packages/json-document-calendar/tests/calendar-time-grid.test.tsx +++ b/packages/json-document-calendar/tests/calendar-time-grid.test.tsx @@ -66,7 +66,11 @@ describe("CalendarTimeGrid", () => { } render(); - expect(screen.getByRole("grid", { name: "Week" })).toBeTruthy(); + const grid = screen.getByRole("grid", { name: "Week" }); + expect(grid).toBeTruthy(); + expect((grid.firstElementChild as HTMLElement).style.gridTemplateColumns).toBe("4rem repeat(7, minmax(4.5rem, 1fr))"); + expect(grid.querySelector('[data-calendar-hour="00"]')).toBeNull(); + expect((grid.querySelector('[data-calendar-hour="01"]') as HTMLElement).style.top).toBe("72px"); expect(screen.getAllByRole("columnheader")).toHaveLength(7); expect(screen.getByText("all-day")).toBeTruthy(); expect(screen.getByRole("presentation", { name: "Now" })).toBeTruthy(); diff --git a/site/src/routes/calendar-demo/CalendarDemoRoute.tsx b/site/src/routes/calendar-demo/CalendarDemoRoute.tsx index 3c695140..cffbc90e 100644 --- a/site/src/routes/calendar-demo/CalendarDemoRoute.tsx +++ b/site/src/routes/calendar-demo/CalendarDemoRoute.tsx @@ -159,6 +159,7 @@ export function CalendarDemoRoute(props: { active: !embedded && (view === "day" || view === "week"), resetKey: `${view}:${visibleDate}`, targetHour: workHourStart, + viewportOffset: 16, }); function setLocation(nextView: CalendarView, nextDate: string): void { @@ -267,7 +268,7 @@ export function CalendarDemoRoute(props: { columnHeader: styles.weekHead(), weekday: ui.text.meta, dayNumber: classes(styles.dayNumber(), ui.text.body), - today: styles.todayMark(), + today: styles.weekToday(), allDayLabel: classes("whitespace-nowrap px-1 py-1.5 text-right text-foreground-muted/70", ui.text.meta), allDayCell: classes("min-h-8", styles.weekCell()), allDayEventContainer: "group/event relative z-10 mx-0.5 my-1", @@ -294,7 +295,7 @@ export function CalendarDemoRoute(props: { allDay: "all-day", now: "Now", resizeEnd: (event) => `Resize ${event.title} end`, - hour: (hour) => String(hour).padStart(2, "0"), + hour: calendarHourLabel, }} getEventColor={(event) => calendarColor(document, event.calendarId)} /> @@ -583,3 +584,9 @@ export function CalendarDemoRoute(props: { function calendarColor(document: CalendarDocument, calendarId: string): "accent" | "subtle" { return calendarDocumentCalendar(document, calendarId)?.color === "accent" ? "accent" : "subtle"; } + +function calendarHourLabel(hour: number): string { + const period = hour < 12 ? "AM" : "PM"; + const displayHour = hour % 12 || 12; + return `${displayHour} ${period}`; +} diff --git a/site/src/routes/calendar-demo/calendar-demo-styles.ts b/site/src/routes/calendar-demo/calendar-demo-styles.ts index 5c9ae08b..caf7f013 100644 --- a/site/src/routes/calendar-demo/calendar-demo-styles.ts +++ b/site/src/routes/calendar-demo/calendar-demo-styles.ts @@ -22,7 +22,7 @@ export const calendarDemoRecipe = tv({ monthHead: "px-2 py-1.5 text-center text-xs text-foreground-muted", weekSticky: "z-30 shrink-0 border-b border-line-subtle/40 bg-background-canvas pt-14", weekHours: "min-h-0 flex-1 overflow-auto", - weekHead: "flex flex-col items-center gap-0.5 px-1 py-2 text-center", + weekHead: "flex min-h-12 items-center justify-center gap-1 px-1 py-2 text-center", weekCell: "relative border-l border-line-subtle/30 outline-none focus-visible:ring-0 focus-visible:ring-offset-0", selectedSlot: "pointer-events-none absolute inset-x-1 z-10 rounded-control bg-background-accent-subtle/70 before:absolute before:inset-y-1 before:left-1 before:w-0.5 before:rounded-full before:bg-background-accent", resizeEdge: "absolute inset-x-0 bottom-0 h-2", @@ -38,6 +38,7 @@ export const calendarDemoRecipe = tv({ nowLine: "pointer-events-none absolute inset-x-0 z-20 border-t border-line-accent", today: "font-semibold text-foreground-accent", todayMark: "font-semibold text-foreground-strong", + weekToday: "rounded-full bg-background-accent text-foreground-inverse", dayNumber: "inline-flex size-7 items-center justify-center font-medium text-foreground-strong", sidebar: "absolute right-0 top-[calc(100%+0.75rem)] flex max-h-[calc(100vh-8rem)] w-44 shrink-0 flex-col gap-3 overflow-auto rounded-surface border border-line-subtle/45 bg-background-canvas p-3 shadow-overlay", inspector: "group/details z-50 flex w-80 min-w-0 flex-col gap-3 overflow-auto rounded-surface border border-line-subtle/45 bg-background-canvas p-3.5 shadow-surface", @@ -51,7 +52,7 @@ export const calendarDemoRecipe = tv({ calendarSwatch: "size-2.5 shrink-0 rounded-full bg-foreground-muted opacity-40 data-[calendar-color=accent]:bg-background-accent group-aria-pressed:opacity-100", eventTime: "truncate font-normal text-foreground-muted", creationTimeHint: "pointer-events-none absolute left-1 z-20 -translate-y-1/2 whitespace-nowrap tabular-nums text-foreground-muted/55", - hourLabel: "absolute right-2 whitespace-nowrap text-right tabular-nums text-foreground-muted/70", + hourLabel: "absolute right-2 -translate-y-1/2 whitespace-nowrap text-right tabular-nums text-foreground-muted/70", composerDock: "bottom-4 left-1/2 z-30 flex w-[min(36rem,calc(100%-2rem))] -translate-x-1/2 items-center gap-2 rounded-full border border-line-subtle/55 bg-background-canvas p-2 pl-3 shadow-none", composerDockFixed: "fixed", composerDockEmbedded: "absolute", diff --git a/site/src/routes/date-controls-demo/date-controls-demo-styles.ts b/site/src/routes/date-controls-demo/date-controls-demo-styles.ts index 6fc7fd2c..e04785c1 100644 --- a/site/src/routes/date-controls-demo/date-controls-demo-styles.ts +++ b/site/src/routes/date-controls-demo/date-controls-demo-styles.ts @@ -31,7 +31,7 @@ export const dateControlsDemoRecipe = tv({ timeViewport: "grid", timeHourGutter: "relative overflow-hidden", timeViewportAnchor: "pointer-events-none absolute left-0 top-0", - timeHourLabel: "absolute right-1 text-xs text-foreground-muted", + timeHourLabel: "absolute right-1 -translate-y-1/2 text-xs text-foreground-muted", timeCell: "relative overflow-hidden border-l border-line-subtle", timeSelectedSlot: "pointer-events-none absolute inset-x-0 bg-background-subtle", timeHourRule: "absolute inset-x-0 border-t border-line-subtle", From ca0917b4e358059064774a90c2ed881c5f383e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=8B=E1=85=AD=E1=86=BC=E1=84=90?= =?UTF-8?q?=E1=85=A2?= Date: Tue, 1 Sep 2026 01:36:45 +0900 Subject: [PATCH 6/8] =?UTF-8?q?=EC=8B=9C=EA=B0=84=20=EC=8A=AC=EB=A1=AF?= =?UTF-8?q?=EC=97=90=20=EC=9D=BC=EC=A0=95=20=EC=B9=B4=EB=93=9C=EC=99=80=20?= =?UTF-8?q?=EB=93=9C=EB=9E=98=EA=B7=B8=20=EC=A0=95=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/use-calendar-pointer-interactions.ts | 12 +++++++++--- .../tests/use-calendar-hand.test.tsx | 6 +++--- site/src/routes/calendar-demo/CalendarDemoRoute.tsx | 2 +- .../src/routes/calendar-demo/calendar-demo-styles.ts | 2 +- site/tests/unit/calendar-product-design.test.ts | 2 ++ 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/json-document-calendar/src/use-calendar-pointer-interactions.ts b/packages/json-document-calendar/src/use-calendar-pointer-interactions.ts index 1fc18bec..940b8882 100644 --- a/packages/json-document-calendar/src/use-calendar-pointer-interactions.ts +++ b/packages/json-document-calendar/src/use-calendar-pointer-interactions.ts @@ -130,7 +130,10 @@ export function useCalendarPointerInteractions(hand: CalendarHand, policy: Calen return; } setHoveredTime(null); - const targetInstant = instantAt(day, event.clientY, grid); + const targetGridMinutes = calendarMinutesFromWebGrid(event.clientY, grid.getBoundingClientRect(), { + hourStart: policy.hourStart, hourEnd: policy.hourEnd, stepMinutes: policy.stepMinutes, + }); + const targetInstant = calendarInstantAt(day, targetGridMinutes); if (targetInstant === null) return; const next = timePointer.preview(event.pointerId, (state) => { const dragSource = state.dragSource ?? (state.dragCandidate !== null && targetInstant !== state.originInstant @@ -139,8 +142,11 @@ export function useCalendarPointerInteractions(hand: CalendarHand, policy: Calen return { ...state, targetInstant, dragSource }; }); if (next?.dragSource !== null && next?.dragSource !== undefined) { - if (selectionDrag.getActive() === null) selectionDrag.begin({ type: "calendar-selection-drag", source: next.dragSource, target: { type: "instant", instant: next.originInstant } }); - const gesture = selectionDrag.preview((active) => ({ ...active, target: { type: "instant", instant: targetInstant } })); + const originAnchor = next.dragSource.anchor.occurrenceStart; + const move = interpretCalendarTimeGridPointer(next); + if (move?.type !== "event.move") return; + if (selectionDrag.getActive() === null) selectionDrag.begin({ type: "calendar-selection-drag", source: next.dragSource, target: { type: "instant", instant: originAnchor } }); + const gesture = selectionDrag.preview((active) => ({ ...active, target: { type: "instant", instant: move.start } })); hand.previewSelectionDrag(gesture); } else if (next !== null) hand.setTimePreview(next); } diff --git a/packages/json-document-calendar/tests/use-calendar-hand.test.tsx b/packages/json-document-calendar/tests/use-calendar-hand.test.tsx index 2851e9a9..999ec4bf 100644 --- a/packages/json-document-calendar/tests/use-calendar-hand.test.tsx +++ b/packages/json-document-calendar/tests/use-calendar-hand.test.tsx @@ -210,17 +210,17 @@ describe("useCalendarHand", () => { releasePointerCapture: () => undefined, }; act(() => result.current.pointer.timePointerDown({ - button: 0, clientY: 540, currentTarget: target, pointerId: 7, + button: 0, clientY: 555, currentTarget: target, pointerId: 7, } as never, "2026-08-03", "standup", "2026-08-03T09:00", "2026-08-03T09:30", "body")); act(() => result.current.pointer.timePointerMove({ pointerId: 7, clientX: 50, clientY: 600, target } as never)); expect(result.current.hand.selectionDragPreview).not.toBeNull(); expect(result.current.hand.paintedEvents.map((item) => item.start)).toEqual([ - "2026-08-03T10:00", "2026-08-04T12:00", + "2026-08-03T09:45", "2026-08-04T11:45", ]); act(() => result.current.pointer.timePointerUp({ pointerId: 7 } as never)); expect(result.current.hand.selectionDragPreview).toBeNull(); expect(result.current.hand.document.events.map((item) => item.start)).toEqual([ - "2026-08-03T10:00", "2026-08-04T12:00", + "2026-08-03T09:45", "2026-08-04T11:45", ]); expect(result.current.hand.selectedOccurrences).toHaveLength(2); act(() => result.current.hand.undo()); diff --git a/site/src/routes/calendar-demo/CalendarDemoRoute.tsx b/site/src/routes/calendar-demo/CalendarDemoRoute.tsx index cffbc90e..4cec5d73 100644 --- a/site/src/routes/calendar-demo/CalendarDemoRoute.tsx +++ b/site/src/routes/calendar-demo/CalendarDemoRoute.tsx @@ -284,7 +284,7 @@ export function CalendarDemoRoute(props: { hourRule: styles.hourRule(), nowLine: styles.nowLine(), creationTimeHint: classes(styles.creationTimeHint(), ui.text.meta), - timedEventContainer: "group/event absolute z-10", + timedEventContainer: "group/event absolute z-10 py-0.5", timedEvent: styles.timedEvent(), eventTitle: classes("min-w-0 truncate", ui.text.meta), eventTime: classes(styles.eventTime(), ui.text.meta), diff --git a/site/src/routes/calendar-demo/calendar-demo-styles.ts b/site/src/routes/calendar-demo/calendar-demo-styles.ts index caf7f013..fd9e1731 100644 --- a/site/src/routes/calendar-demo/calendar-demo-styles.ts +++ b/site/src/routes/calendar-demo/calendar-demo-styles.ts @@ -24,7 +24,7 @@ export const calendarDemoRecipe = tv({ weekHours: "min-h-0 flex-1 overflow-auto", weekHead: "flex min-h-12 items-center justify-center gap-1 px-1 py-2 text-center", weekCell: "relative border-l border-line-subtle/30 outline-none focus-visible:ring-0 focus-visible:ring-offset-0", - selectedSlot: "pointer-events-none absolute inset-x-1 z-10 rounded-control bg-background-accent-subtle/70 before:absolute before:inset-y-1 before:left-1 before:w-0.5 before:rounded-full before:bg-background-accent", + selectedSlot: "pointer-events-none absolute inset-x-1 z-10 rounded-control border-y-2 border-transparent bg-background-accent-subtle/70 bg-clip-padding before:absolute before:inset-y-1 before:left-1 before:w-0.5 before:rounded-full before:bg-background-accent", resizeEdge: "absolute inset-x-0 bottom-0 h-2", resizeEdgeVertical: "absolute right-0 top-0 h-full w-2", periodHeading: "pointer-events-none absolute left-14 top-4 z-40 m-0 hidden whitespace-nowrap text-sm font-medium text-foreground-strong sm:block", diff --git a/site/tests/unit/calendar-product-design.test.ts b/site/tests/unit/calendar-product-design.test.ts index 59f38cd1..edd289e0 100644 --- a/site/tests/unit/calendar-product-design.test.ts +++ b/site/tests/unit/calendar-product-design.test.ts @@ -58,6 +58,8 @@ describe("calendar product design", () => { expect(styles.monthWeek()).toContain("border-line-subtle/60"); expect(styles.creationTimeHint()).toContain("text-foreground-muted/55"); expect(styles.hourLabel()).toContain("text-foreground-muted"); + expect(styles.selectedSlot()).toContain("border-y-2"); + expect(styles.selectedSlot()).toContain("bg-clip-padding"); expect(css).toContain('[data-ui-presentation="calendar-time-grid"]:hover'); expect(css).toContain("bg-transparent"); }); From 1b85e590d976834df02504d0076c92a98a6601fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=8B=E1=85=AD=E1=86=BC=E1=84=90?= =?UTF-8?q?=E1=85=A2?= Date: Tue, 1 Sep 2026 01:41:54 +0900 Subject: [PATCH 7/8] =?UTF-8?q?=EC=BB=A4=EC=84=9C=20=EC=8B=9C=EA=B0=84?= =?UTF-8?q?=EC=9D=84=20=EC=8A=AC=EB=A1=AF=20=EB=82=B4=EB=B6=80=EC=97=90=20?= =?UTF-8?q?=EB=B0=B0=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- site/src/routes/calendar-demo/calendar-demo-styles.ts | 2 +- site/tests/unit/calendar-product-design.test.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/site/src/routes/calendar-demo/calendar-demo-styles.ts b/site/src/routes/calendar-demo/calendar-demo-styles.ts index fd9e1731..f270dae7 100644 --- a/site/src/routes/calendar-demo/calendar-demo-styles.ts +++ b/site/src/routes/calendar-demo/calendar-demo-styles.ts @@ -51,7 +51,7 @@ export const calendarDemoRecipe = tv({ calendarToggle: "group flex w-full items-center justify-start gap-2 rounded-control border-0 bg-transparent px-2 py-1.5 text-left shadow-none outline-none hover:border-0 hover:bg-background-subtle focus-visible:ring-2 focus-visible:ring-foreground-muted/25 aria-pressed:border-0 aria-pressed:bg-transparent aria-pressed:text-foreground-strong aria-[pressed=false]:text-foreground-muted", calendarSwatch: "size-2.5 shrink-0 rounded-full bg-foreground-muted opacity-40 data-[calendar-color=accent]:bg-background-accent group-aria-pressed:opacity-100", eventTime: "truncate font-normal text-foreground-muted", - creationTimeHint: "pointer-events-none absolute left-1 z-20 -translate-y-1/2 whitespace-nowrap tabular-nums text-foreground-muted/55", + creationTimeHint: "pointer-events-none absolute left-2 z-20 translate-y-1 whitespace-nowrap tabular-nums text-foreground-muted/55", hourLabel: "absolute right-2 -translate-y-1/2 whitespace-nowrap text-right tabular-nums text-foreground-muted/70", composerDock: "bottom-4 left-1/2 z-30 flex w-[min(36rem,calc(100%-2rem))] -translate-x-1/2 items-center gap-2 rounded-full border border-line-subtle/55 bg-background-canvas p-2 pl-3 shadow-none", composerDockFixed: "fixed", diff --git a/site/tests/unit/calendar-product-design.test.ts b/site/tests/unit/calendar-product-design.test.ts index edd289e0..73722288 100644 --- a/site/tests/unit/calendar-product-design.test.ts +++ b/site/tests/unit/calendar-product-design.test.ts @@ -57,6 +57,8 @@ describe("calendar product design", () => { expect(styles.weekSticky()).toContain("border-line-subtle/40"); expect(styles.monthWeek()).toContain("border-line-subtle/60"); expect(styles.creationTimeHint()).toContain("text-foreground-muted/55"); + expect(styles.creationTimeHint()).toContain("translate-y-1"); + expect(styles.creationTimeHint()).not.toContain("-translate-y-1/2"); expect(styles.hourLabel()).toContain("text-foreground-muted"); expect(styles.selectedSlot()).toContain("border-y-2"); expect(styles.selectedSlot()).toContain("bg-clip-padding"); From eba5017a98e7a95af133b32613fdd30035e58f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=8B=E1=85=AD=E1=86=BC=E1=84=90?= =?UTF-8?q?=E1=85=A2?= Date: Tue, 1 Sep 2026 01:56:13 +0900 Subject: [PATCH 8/8] =?UTF-8?q?=EB=93=9C=EB=9E=98=EA=B7=B8=20=EC=A4=91=20?= =?UTF-8?q?=EC=9D=BC=EC=A0=95=20=EC=83=81=EC=84=B8=20=EC=B0=BD=20=EC=88=A8?= =?UTF-8?q?=EA=B9=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- site/src/routes/calendar-demo/CalendarDemoRoute.tsx | 11 ++++++++--- site/tests/unit/calendar-product-design.test.ts | 3 +++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/site/src/routes/calendar-demo/CalendarDemoRoute.tsx b/site/src/routes/calendar-demo/CalendarDemoRoute.tsx index 4cec5d73..41424d63 100644 --- a/site/src/routes/calendar-demo/CalendarDemoRoute.tsx +++ b/site/src/routes/calendar-demo/CalendarDemoRoute.tsx @@ -179,8 +179,13 @@ export function CalendarDemoRoute(props: { const document = hand.document; const calendars = calendarDocumentCalendars(document); const selectedEvent = hand.selectedEvent; + const pointerGestureActive = hand.timePreview !== null + || hand.allDayPreview !== null + || hand.monthPreview !== null + || hand.selectionDragPreview !== null; + const eventInspectorVisible = selectedEvent !== null && !pointerGestureActive; const eventDetailsPosition = useAnchoredFloatingPosition({ - active: selectedEvent !== null, + active: eventInspectorVisible, policy: { type: "preferred", placement: "right-start", @@ -390,7 +395,7 @@ export function CalendarDemoRoute(props: { >
-