From 94016fd4c4c938d19f097715c36c02aa803bc971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Fri, 10 Apr 2026 23:53:43 +0200 Subject: [PATCH] Add sidebar day breakdown and overnight toggle UI - DayBreakdown: Collapsible day sections with per-day stats - WaypointSidebar: Overnight toggle button (moon icon), day-grouped view when any waypoint is marked overnight, route summary in header - SessionView: Wire useDays() hook into sidebar via SidebarTabs - i18n: Add multiDay keys for en + de (day labels, overnight, stats) Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/planner/app/components/DayBreakdown.tsx | 54 +++++++ apps/planner/app/components/SessionView.tsx | 4 +- .../app/components/WaypointSidebar.tsx | 152 ++++++++++++------ openspec/changes/multi-day-routes/tasks.md | 10 +- packages/i18n/src/locales/de.ts | 11 ++ packages/i18n/src/locales/en.ts | 11 ++ 6 files changed, 190 insertions(+), 52 deletions(-) create mode 100644 apps/planner/app/components/DayBreakdown.tsx diff --git a/apps/planner/app/components/DayBreakdown.tsx b/apps/planner/app/components/DayBreakdown.tsx new file mode 100644 index 0000000..9632531 --- /dev/null +++ b/apps/planner/app/components/DayBreakdown.tsx @@ -0,0 +1,54 @@ +import { useState } from "react"; +import { useTranslation } from "react-i18next"; +import type { DayStage } from "@trails-cool/gpx"; + +interface DayBreakdownProps { + days: DayStage[]; + children: (dayStage: DayStage, waypointIndices: { start: number; end: number }) => React.ReactNode; +} + +export function DayBreakdown({ days, children }: DayBreakdownProps) { + const { t } = useTranslation(); + const [expandedDay, setExpandedDay] = useState(1); + + return ( +
+ {days.map((day) => { + const isExpanded = expandedDay === day.dayNumber; + return ( +
+ + + {isExpanded && ( + <> +
+ ↑ {day.ascent} m + ↓ {day.descent} m +
+ {children(day, { start: day.startWaypointIndex, end: day.endWaypointIndex })} + + )} +
+ ); + })} +
+ ); +} diff --git a/apps/planner/app/components/SessionView.tsx b/apps/planner/app/components/SessionView.tsx index 6cea400..614934f 100644 --- a/apps/planner/app/components/SessionView.tsx +++ b/apps/planner/app/components/SessionView.tsx @@ -5,6 +5,7 @@ import type { TFunction } from "i18next"; import * as Sentry from "@sentry/react"; import { useYjs, type YjsState } from "~/lib/use-yjs"; import { useRouting, type RouteError } from "~/lib/use-routing"; +import { useDays } from "~/lib/use-days"; import { useUndo, useUndoShortcuts } from "~/lib/use-undo"; import { ProfileSelector } from "~/components/ProfileSelector"; import { ExportButton } from "~/components/ExportButton"; @@ -144,6 +145,7 @@ function ColorModeToggle({ yjs }: { yjs: YjsState }) { function SidebarTabs({ yjs, routeStats }: { yjs: YjsState; routeStats: ReturnType["routeStats"] }) { const { t } = useTranslation("planner"); const [tab, setTab] = useState<"waypoints" | "notes">("waypoints"); + const days = useDays(yjs); return (