feat(schedule): add timeline nav prototype#121
Conversation
Three structurally different variants on the existing schedule/timeline route, gated by ?variant= (a: slim jump bar, b: segmented rail, c: mini-map), all sharing the agreed scrollTo URL mechanics (debounced write, 5-min rounding, one-way ownership, mount precedence). My-vote chips in three placements/forms; now indicator in three treatments; fake now + fake anon votes for demoability. See prototype/NOTES.md for the questions this answers and the deletion list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WeDJWUoheP7zyhpchNa3DW
Gate on the variant param being present instead of dev-build only, so a shared preview deploy can flip variants; normal users still never see it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WeDJWUoheP7zyhpchNa3DW
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
A future edition without its schedule publicly revealed (reveal level below "full") was hitting ScheduleNotRevealedPlaceholder before the ?variant= check ever ran, hiding the prototype (Now button included) entirely. Testing nav/filtering shouldn't depend on public reveal state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WeDJWUoheP7zyhpchNa3DW
Tomorrowland's schedule reveal level is already "full", so canShowTime was never the actual blocker — the earlier bypass wasn't needed. The real fix for the Now button was already in place (fake "now" computed from the edition's own dates, independent of the real clock). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WeDJWUoheP7zyhpchNa3DW
Two testers tried round 1: one preferred variant a, the other loved
variant c's mini-map for being visual but flagged the plain switcher
and general noise. Folds their feedback into all three variants:
- Filters move into a bottom sheet instead of an inline expanding
panel, so the schedule stays the visual focus.
- Variant c's mini-map now collapses to a's slim day-strip by default,
with a "Show overview" toggle to reveal the full density map — what
testers valued was one control doing "jump to a day" + "filter by my
votes" together, not the density map being loud all the time.
- Day labels now include the date ("Thu 13", not bare "Thu") — a real
bug: multi-weekend festivals (Tomorrowland's two long weekends)
repeat weekday names with no way to tell them apart.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WeDJWUoheP7zyhpchNa3DW
There was a problem hiding this comment.
Pull request overview
Adds a throwaway, URL-driven prototype for timeline navigation + “my-vote” filtering on the existing schedule timeline route, gated behind ?variant= so the production timeline UI remains unchanged when the param is absent.
Changes:
- Adds
variantandscrollTosearch params and aTimelinePrototypeentrypoint rendered only when?variant=is present. - Implements three prototype UI variants (slim jump bar, segmented rail, minimap) sharing a
scrollToURL/scroll synchronization hook. - Introduces prototype-only vote chips, fake “now”, and fake votes (when logged out) to support anonymous demos, plus internal notes.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/pages/EditionView/tabs/ScheduleTab/horizontal/Timeline.tsx | Gates the prototype rendering behind ?variant= on the timeline route. |
| src/pages/EditionView/tabs/ScheduleTab/horizontal/prototype/TimelinePrototype.tsx | Prototype controller: builds filtered timeline data + routes to variant A/B/C UIs. |
| src/pages/EditionView/tabs/ScheduleTab/horizontal/prototype/VariantSlimBar.tsx | Variant A: sticky slim jump bar + filters drawer vote chips + smooth jumps. |
| src/pages/EditionView/tabs/ScheduleTab/horizontal/prototype/VariantSegmented.tsx | Variant B: segmented day rail + inline vote chips with counts + instant jumps. |
| src/pages/EditionView/tabs/ScheduleTab/horizontal/prototype/VariantMinimap.tsx | Variant C: collapsible minimap with draggable viewport and compact vote chips. |
| src/pages/EditionView/tabs/ScheduleTab/horizontal/prototype/useScrollToUrl.ts | Shared scrollTo URL mechanics (debounced write, rounding, mount restore). |
| src/pages/EditionView/tabs/ScheduleTab/horizontal/prototype/PrototypeCanvas.tsx | Shared scroll surface reusing production timeline rows/scale + now indicator overlay. |
| src/pages/EditionView/tabs/ScheduleTab/horizontal/prototype/PrototypeFilters.tsx | Shared bottom-sheet filter UI for day/time/stage (+ optional vote chips slot). |
| src/pages/EditionView/tabs/ScheduleTab/horizontal/prototype/VoteChips.tsx | Prototype vote filter chip UI (optionally compact, optionally with counts). |
| src/pages/EditionView/tabs/ScheduleTab/horizontal/prototype/NowIndicator.tsx | Prototype-only now-indicator visual treatments for each variant. |
| src/pages/EditionView/tabs/ScheduleTab/horizontal/prototype/usePrototypeVotes.ts | Uses real votes when logged in; deterministic fake votes when logged out. |
| src/pages/EditionView/tabs/ScheduleTab/horizontal/prototype/useFakeNow.ts | Fakes “now” within the edition window for consistent demos. |
| src/pages/EditionView/tabs/ScheduleTab/horizontal/prototype/types.ts | Shared types/helpers for variants (e.g., day jump model, now-in-window check). |
| src/pages/EditionView/tabs/ScheduleTab/horizontal/prototype/NOTES.md | Prototype runbook + decision log placeholders + deletion checklist. |
| src/lib/searchSchemas.ts | Extends timeline search schema to include variant and scrollTo. |
| src/components/prototype/PrototypeSwitcher.tsx | Floating in-prototype UI to cycle variants (buttons + ←/→ keys). |
| // PROTOTYPE (timeline nav & filtering) — remove with src/pages/EditionView/tabs/ScheduleTab/horizontal/prototype/ | ||
| variant: z.enum(["a", "b", "c"]).optional(), | ||
| scrollTo: z.string().optional(), | ||
| }); |
| <button | ||
| key={voteType} | ||
| type="button" | ||
| onClick={() => onToggle(voteType)} | ||
| aria-pressed={isSelected} | ||
| title={config.label} | ||
| className={cn( | ||
| "inline-flex items-center gap-1.5 rounded-full border text-xs font-medium transition-colors", | ||
| compact ? "px-2 py-1" : "px-3 py-1.5", | ||
| isSelected | ||
| ? cn("border-transparent text-white", config.buttonSelected) | ||
| : cn("bg-transparent", config.buttonUnselected), | ||
| )} |
| function update() { | ||
| setViewport({ left: el!.scrollLeft, width: el!.clientWidth }); | ||
| setMapWidth(mapRef.current?.clientWidth ?? 0); | ||
| } | ||
|
|
||
| update(); | ||
| el.addEventListener("scroll", update, { passive: true }); | ||
| window.addEventListener("resize", update); | ||
| return () => { | ||
| el.removeEventListener("scroll", update); | ||
| window.removeEventListener("resize", update); | ||
| }; |
| // Jump-bar days derive from the *filtered* strip: nav operates on what is | ||
| // rendered (open sub-question — see NOTES.md). |
The Filters button sat alone on its own line above the nav row, wasting a full row for a single icon on narrow viewports. Moved it inline with each variant's existing toolbar (jump bar, segmented rail, overview toggle) instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WeDJWUoheP7zyhpchNa3DW
Testing (2 users, 2 rounds) is done and the direction is picked: the round-2 synthesis of variant c (collapsed slim strip + optional density-map overview, filters in a bottom sheet, date-qualified day labels). Verdicts recorded per question; the one untested question (day filter + nav interaction) resolved directly with the product owner rather than left blank. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WeDJWUoheP7zyhpchNa3DW
|
Prototype has served its purpose — verdicts are captured in Generated by Claude Code |
Throwaway prototype: three timeline navigation + my-vote filtering variants on the timeline route behind
?variant=(a: slim jump bar, b: segmented rail, c: mini-map), to validate the agreed scrollTo/jump-bar design before the PRD is published.Without
?variant=the production timeline renders untouched; verdict placeholders and the deletion list live inprototype/NOTES.md.Verification
?variant=a; jump bar with day buttons + Now pill renders, clicking a day smooth-scrolls the strip and writesscrollToto the URL.scrollTo(also when returning from a set page via back).?variant=; the existing production timeline renders with no switcher.🤖 Generated with Claude Code
https://claude.ai/code/session_01WeDJWUoheP7zyhpchNa3DW
Generated by Claude Code