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
4 changes: 2 additions & 2 deletions apps/calendar-web/src/common/utils/grid/grid.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const SCROLL_TO_NOW_BUFFER_PX = 150;
const SCROLL_TO_NOW_TOLERANCE_PX = 2;

/** When the now line is visible and scroll is within this window, "t" pulses. */
export const SCROLL_TO_NOW_PULSE_NEAR_MINUTES = 5;
const SCROLL_TO_NOW_PULSE_NEAR_MINUTES = 5;

export const getScrollToNowTop = (clientHeight: number) =>
Math.max(
Expand All @@ -76,7 +76,7 @@ export const getScrollToNowTop = (clientHeight: number) =>
SCROLL_TO_NOW_BUFFER_PX,
);

export const getScrollToNowDelta = (timedGrid: HTMLElement) => {
const getScrollToNowDelta = (timedGrid: HTMLElement) => {
const targetTop = getScrollToNowTop(timedGrid.clientHeight);
return Math.abs(timedGrid.scrollTop - targetTop);
};
Expand Down
17 changes: 5 additions & 12 deletions apps/calendar-web/src/components/SelectView/SelectView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,7 @@ import {
import { ROOT_ROUTES } from "@web/common/constants/routes";
import { Z_INDEX_FLOATING_MENU } from "@web/common/constants/web.constants";
import { ShortcutKeys } from "@web/components/Shortcuts/ShortcutKeys";
import {
selectNowCueActive,
selectNowCuePulseGeneration,
useNowCueStore,
} from "@web/grid/now-cue/now-cue.store";
import { useNowCuePulse } from "@web/grid/now-cue/useNowCuePulse";
import { useFloatingLayer } from "@web/shortcuts/floating-layer";
import { pageJumpAttrs } from "@web/shortcuts/page-jump/page-jump.targets";
import { pulseClickTaughtShortcut } from "@web/shortcuts/pointer-intent/pulseClickTaughtShortcut";
Expand Down Expand Up @@ -52,8 +48,8 @@ export const SelectView = ({
const navigate = useNavigate();
const listRef = useRef<Array<HTMLElement | null>>([]);
useFloatingLayer("viewSelect", isOpen);
const pulseDayLabel = useNowCueStore(selectNowCueActive) && emphasizeDayLabel;
const pulseGeneration = useNowCueStore(selectNowCuePulseGeneration);
const { pulsing, pulseKey } = useNowCuePulse();
const pulseDayLabel = pulsing && emphasizeDayLabel;

const getCurrentView = (): "Day" | "Week" | "Life" => {
const pathname = location.pathname;
Expand Down Expand Up @@ -188,11 +184,8 @@ export const SelectView = ({
aria-controls={isOpen ? dropdownId : undefined}
>
<span
className={classNames(
pulseDayLabel &&
"c-now-cue-label-pulse motion-reduce:transition-none",
)}
key={emphasizeDayLabel ? pulseGeneration : undefined}
className={classNames(pulseDayLabel && "c-now-cue-label-pulse")}
key={pulseKey("view-label", emphasizeDayLabel)}
>
{label}
</span>
Expand Down
13 changes: 4 additions & 9 deletions apps/calendar-web/src/grid/components/TimedGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,7 @@ import {
TIMED_VISIBLE_HOURS,
} from "@web/grid/grid.constants";
import { useGridMarginLeft } from "@web/grid/grid-margin";
import {
selectNowCueActive,
selectNowCuePulseGeneration,
useNowCueStore,
} from "@web/grid/now-cue/now-cue.store";
import { useNowCuePulse } from "@web/grid/now-cue/useNowCuePulse";
import { type GridVisibleDate } from "@web/grid/types/grid.types";
import { allDayColumnTintStyle } from "@web/grid/utils/allDayColumnTint.util";
import {
Expand Down Expand Up @@ -164,17 +160,16 @@ const CalendarNowLine = ({
}) => {
useMinuteTick();
const percentOfDay = getCurrentPercentOfDay(effectiveTimeZone);
const pulseNowLine = useNowCueStore(selectNowCueActive);
const pulseGeneration = useNowCueStore(selectNowCuePulseGeneration);
const { pulsing: pulseNowLine, pulseKey } = useNowCuePulse();

return (
<div
aria-hidden="true"
className={cn(
"c-now-line-rim absolute h-px motion-reduce:transition-none",
"c-now-line-rim absolute h-px",
pulseNowLine && "c-now-cue-pulse",
)}
key={pulseGeneration}
key={pulseKey("now-line")}
style={{
background: accentGradient,
top: `${percentOfDay}%`,
Expand Down
23 changes: 9 additions & 14 deletions apps/calendar-web/src/grid/now-cue/scroll-to-now-or-pulse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,19 @@ import {
import { nowCueActions } from "@web/grid/now-cue/now-cue.store";

export const scrollToNowOrPulse = (
timedGrid: HTMLElement | null | undefined,
timedGrid: HTMLElement | null,
behavior: ScrollBehavior = "smooth",
) => {
if (!timedGrid) return;

const strictAtNow = isTimedGridScrolledToNow(timedGrid);
const teachPulse =
strictAtNow ||
(isNowLineInTimedGridViewport(timedGrid) &&
isTimedGridNearScrollToNow(timedGrid));
// Read both before scrolling: afterwards every grid looks like "at now".
const atNow = isTimedGridScrolledToNow(timedGrid);
const nearNow =
isNowLineInTimedGridViewport(timedGrid) &&
isTimedGridNearScrollToNow(timedGrid);

if (teachPulse) {
if (!strictAtNow) {
scrollTimedGridToNow(timedGrid, behavior);
}
nowCueActions.pulse();
return;
}
if (!atNow) scrollTimedGridToNow(timedGrid, behavior);

scrollTimedGridToNow(timedGrid, behavior);
// Already looking at now, so there is nothing to scroll to: teach instead.
if (atNow || nearNow) nowCueActions.pulse();
};
25 changes: 25 additions & 0 deletions apps/calendar-web/src/grid/now-cue/useNowCuePulse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {
selectNowCueActive,
selectNowCuePulseGeneration,
useNowCueStore,
} from "@web/grid/now-cue/now-cue.store";

/**
* Subscribes an element to the go-to-today teach pulse.
*
* `pulsing` gates the pulse utility class. `pulseKey` is a remount key: a CSS
* animation only replays on a fresh node, so repeated "t" presses need a key
* that changes with every pulse. Name it per element so sibling cues under
* one parent stay distinct, and pass `isTarget` where the element is only
* sometimes the cue (today's column) so the rest never remount.
*/
export const useNowCuePulse = () => {
const active = useNowCueStore(selectNowCueActive);
const generation = useNowCueStore(selectNowCuePulseGeneration);

return {
pulsing: active,
pulseKey: (name: string, isTarget = true) =>
isTarget ? `${name}-${generation}` : undefined,
};
};
19 changes: 6 additions & 13 deletions apps/calendar-web/src/views/Week/components/Header/DayLabels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@ import {
} from "@web/events/stores/draft.store";
import { EVENT_WIDTH_MINIMUM } from "@web/grid/grid.constants";
import { useGridMarginLeft } from "@web/grid/grid-margin";
import {
selectNowCueActive,
selectNowCuePulseGeneration,
useNowCueStore,
} from "@web/grid/now-cue/now-cue.store";
import { useNowCuePulse } from "@web/grid/now-cue/useNowCuePulse";
import {
selectPageJumpHintsVisible,
usePageJumpHintStore,
Expand Down Expand Up @@ -55,8 +51,7 @@ export const DayLabels: FC<Props> = ({
const showDayJumpPrefixes =
!isEventFormOpen && (pageJumpHintsVisible || isEventJumpActive);
const marginLeft = useGridMarginLeft();
const pulseTodayLabel = useNowCueStore(selectNowCueActive);
const pulseGeneration = useNowCueStore(selectNowCuePulseGeneration);
const { pulsing: pulseTodayLabel, pulseKey } = useNowCuePulse();
const dayJumpHowTo = isEventJumpActive
? "Type the day key to focus that column."
: "Hold Shift and press the day key to focus that column.";
Expand Down Expand Up @@ -128,9 +123,9 @@ export const DayLabels: FC<Props> = ({
isToday && "c-text-gradient",
isToday &&
pulseTodayLabel &&
"c-now-cue-label-gradient-pulse motion-reduce:transition-none",
"c-now-cue-label-gradient-pulse",
)}
key={isToday ? `day-num-${pulseGeneration}` : undefined}
key={pulseKey("day-num", isToday)}
>
{dayNumber}
</span>
Expand All @@ -144,11 +139,9 @@ export const DayLabels: FC<Props> = ({
<span
className={cn(
"relative text-[clamp(var(--font-size-m),2cqw,var(--font-size-l))] leading-none",
isToday &&
pulseTodayLabel &&
"c-now-cue-label-pulse motion-reduce:transition-none",
isToday && pulseTodayLabel && "c-now-cue-label-pulse",
)}
key={isToday ? `day-name-${pulseGeneration}` : undefined}
key={pulseKey("day-name", isToday)}
>
{day.format("ddd")}
</span>
Expand Down
Loading