From 7fd88cdccef62db2e7165b853529c918732ebd77 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 14 Oct 2026 19:14:47 +0000 Subject: [PATCH] fix(web): pulse today label text instead of clipped outline Co-authored-by: Tyler Dane --- .../components/SelectView/SelectView.test.tsx | 22 ++++++++++ .../src/components/SelectView/SelectView.tsx | 2 +- apps/calendar-web/src/index.css | 40 ++++++++++++++++++- .../Week/components/Header/DayLabels.test.tsx | 16 ++++++++ .../Week/components/Header/DayLabels.tsx | 13 +++++- 5 files changed, 89 insertions(+), 4 deletions(-) diff --git a/apps/calendar-web/src/components/SelectView/SelectView.test.tsx b/apps/calendar-web/src/components/SelectView/SelectView.test.tsx index 5bc6cbbfeb..de2077ca8e 100644 --- a/apps/calendar-web/src/components/SelectView/SelectView.test.tsx +++ b/apps/calendar-web/src/components/SelectView/SelectView.test.tsx @@ -8,6 +8,7 @@ import userEvent from "@testing-library/user-event"; import { createTestRouter } from "@web/__tests__/utils/providers/createTestRouter"; import * as trackModule from "@web/auth/posthog/track"; import { ROOT_ROUTES } from "@web/common/constants/routes"; +import { nowCueActions } from "@web/grid/now-cue/now-cue.store"; import { initialPointerHintState, usePointerHintStore, @@ -82,6 +83,7 @@ describe("SelectView", () => { afterEach(() => { resetPointerIntentSessionForTests(); usePointerHintStore.setState(initialPointerHintState, true); + nowCueActions.resetForTests(); }); const renderWithRouter = async ( @@ -127,6 +129,26 @@ describe("SelectView", () => { expect(button).toHaveAttribute("aria-expanded", "false"); }); + it("pulses the day heading text when the now cue is active", async () => { + nowCueActions.pulse(); + const router = createTestRouter( + , + { initialEntries: [ROOT_ROUTES.DAY] }, + ); + render(); + await waitFor(() => { + expect(router.state.status).toBe("idle"); + }); + + expect(screen.getByText("Monday, July 20")).toHaveClass( + "c-now-cue-label-pulse", + ); + }); + it("renders the label as the page heading", async () => { await renderWithRouter("Monday, July 20", ROOT_ROUTES.DAY); diff --git a/apps/calendar-web/src/components/SelectView/SelectView.tsx b/apps/calendar-web/src/components/SelectView/SelectView.tsx index 68b09167cf..4b9ec76d16 100644 --- a/apps/calendar-web/src/components/SelectView/SelectView.tsx +++ b/apps/calendar-web/src/components/SelectView/SelectView.tsx @@ -188,7 +188,7 @@ export const SelectView = ({ {label} diff --git a/apps/calendar-web/src/index.css b/apps/calendar-web/src/index.css index 1822a4668c..53a9218610 100644 --- a/apps/calendar-web/src/index.css +++ b/apps/calendar-web/src/index.css @@ -159,6 +159,10 @@ --animate-keycap-flash: keycapFlash 700ms ease-out both; --animate-level-pulse: levelPulse 700ms cubic-bezier(0.16, 1, 0.3, 1) both; --animate-now-cue-pulse: nowCuePulse 700ms cubic-bezier(0.16, 1, 0.3, 1) both; + --animate-now-cue-label-pulse: nowCueLabelPulse 700ms + cubic-bezier(0.16, 1, 0.3, 1) both; + --animate-now-cue-label-gradient-pulse: nowCueLabelGradientPulse 700ms + cubic-bezier(0.16, 1, 0.3, 1) both; --animate-keycap-next: keycapNext 1.1s ease-in-out infinite; --animate-game-howto-in: gameHowtoIn 500ms cubic-bezier(0.16, 1, 0.3, 1) both; --animate-game-hint-in: gameHintIn 300ms ease-out both; @@ -259,7 +263,7 @@ } } - /* Go-to-today no-op: briefly highlight today's label and the now line. */ + /* Go-to-today no-op: ring pulse on the now line only. */ @keyframes nowCuePulse { 0%, 100% { @@ -273,6 +277,30 @@ } } + /* Go-to-today no-op: accent color pulse on day labels (solid text). */ + @keyframes nowCueLabelPulse { + 0%, + 100% { + color: inherit; + filter: brightness(1); + } + 45% { + color: var(--color-accent); + filter: brightness(1.2); + } + } + + /* Same cue on gradient day numbers: brightness only, no layout shift. */ + @keyframes nowCueLabelGradientPulse { + 0%, + 100% { + filter: brightness(1); + } + 45% { + filter: brightness(1.35); + } + } + /* The exact next key to press pulses until it is pressed. */ @keyframes keycapNext { 0%, @@ -766,6 +794,16 @@ @apply motion-reduce:animate-none; } +@utility c-now-cue-label-pulse { + animation: var(--animate-now-cue-label-pulse); + @apply motion-reduce:animate-none; +} + +@utility c-now-cue-label-gradient-pulse { + animation: var(--animate-now-cue-label-gradient-pulse); + @apply motion-reduce:animate-none; +} + /* The task card's "press this next" chip: accent glow, insistent pulse. */ @utility c-keycap-next { border-color: var(--color-accent); diff --git a/apps/calendar-web/src/views/Week/components/Header/DayLabels.test.tsx b/apps/calendar-web/src/views/Week/components/Header/DayLabels.test.tsx index 1cfb807e96..ead64fb8bb 100644 --- a/apps/calendar-web/src/views/Week/components/Header/DayLabels.test.tsx +++ b/apps/calendar-web/src/views/Week/components/Header/DayLabels.test.tsx @@ -1,5 +1,6 @@ import { cleanup, render, screen } from "@testing-library/react"; import dayjs from "@core/util/date/dayjs"; +import { nowCueActions, useNowCueStore } from "@web/grid/now-cue/now-cue.store"; import { pageJumpHintActions } from "@web/shortcuts/page-jump/page-jump.store"; import { eventJumpActions } from "@web/shortcuts/shift-hint/event-jump.store"; import { getEffectiveTimeZone } from "@web/timezone/effective-timezone.store"; @@ -30,6 +31,21 @@ describe("DayLabels", () => { cleanup(); eventJumpActions.reset(); pageJumpHintActions.reset(); + nowCueActions.resetForTests(); + }); + + it("pulses today label text when the now cue is active", () => { + nowCueActions.pulse(); + renderLabels(); + + expect(useNowCueStore.getState().active).toBe(true); + expect(screen.getByText("17")).toHaveClass( + "c-now-cue-label-gradient-pulse", + ); + expect(screen.getByText("Mon")).toHaveClass("c-now-cue-label-pulse"); + expect( + screen.getByText("17").closest("[class*='c-now-cue-pulse']"), + ).toBeNull(); }); it("shows the effective timezone in the grid corner", () => { diff --git a/apps/calendar-web/src/views/Week/components/Header/DayLabels.tsx b/apps/calendar-web/src/views/Week/components/Header/DayLabels.tsx index 5f918279c9..aba19c689d 100644 --- a/apps/calendar-web/src/views/Week/components/Header/DayLabels.tsx +++ b/apps/calendar-web/src/views/Week/components/Header/DayLabels.tsx @@ -114,7 +114,6 @@ export const DayLabels: FC = ({ className={cn( "flex items-end justify-center gap-1 rounded-sm px-1 transition-colors duration-150 motion-reduce:transition-none", isJumpDay && "bg-accent/15 text-accent", - isToday && pulseTodayLabel && "c-now-cue-pulse", )} data-jump-day={isJumpDay ? "true" : undefined} key={getWeekDayLabel(day)} @@ -125,6 +124,9 @@ export const DayLabels: FC = ({ className={cn( "relative text-[clamp(var(--font-size-xl),2.7cqw,var(--font-size-xxl))] leading-none", isToday && "c-text-gradient", + isToday && + pulseTodayLabel && + "c-now-cue-label-gradient-pulse motion-reduce:transition-none", )} > {dayNumber} @@ -136,7 +138,14 @@ export const DayLabels: FC = ({ {isEventJumpActive ? prefix : `⇧${prefix}`} ) : ( - + {day.format("ddd")} )}