@titan-design/react-ui 0.12.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -47
- package/dist/bodymap.js +768 -701
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +770 -703
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +1319 -216
- package/dist/index.d.ts +1319 -216
- package/dist/index.js +5996 -4498
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5773 -4357
- package/dist/index.mjs.map +1 -1
- package/dist/{pages-CvsFqNtx.d.mts → pages-CpW3OB3g.d.mts} +21 -3
- package/dist/{pages-B1hqnGIC.d.ts → pages-_3Ajpiqu.d.ts} +21 -3
- package/dist/pages.d.mts +1 -1
- package/dist/pages.d.ts +1 -1
- package/dist/pages.js +1435 -1428
- package/dist/pages.js.map +1 -1
- package/dist/pages.mjs +1443 -1436
- package/dist/pages.mjs.map +1 -1
- package/dist/theme/index.d.mts +195 -134
- package/dist/theme/index.d.ts +195 -134
- package/dist/theme/index.js +215 -300
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +202 -296
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +62 -5
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +62 -5
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/dist/theme/tokens.d.mts +73 -5
- package/dist/theme/tokens.d.ts +73 -5
- package/dist/theme/tokens.js +55 -7
- package/dist/theme/tokens.js.map +1 -1
- package/dist/theme/tokens.mjs +55 -8
- package/dist/theme/tokens.mjs.map +1 -1
- package/docs/audits/2026-09-08-critique-addenda.md +51 -0
- package/docs/audits/2026-09-08-library-critique.md +212 -0
- package/docs/library-roadmap.md +99 -0
- package/package.json +1 -1
- package/src/arch/arch-graph.freshness.test.ts +52 -0
- package/src/arch/arch-graph.json +5021 -1617
- package/src/components/custom/ActiveWork/CoChangeChip.stories.tsx +44 -0
- package/src/components/custom/ActiveWork/CoChangeChip.test.tsx +29 -0
- package/src/components/custom/ActiveWork/CoChangeChip.tsx +48 -0
- package/src/components/custom/ActiveWork/Eyebrow.stories.tsx +25 -0
- package/src/components/custom/ActiveWork/Eyebrow.test.tsx +16 -0
- package/src/components/custom/ActiveWork/Eyebrow.tsx +26 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.stories.tsx +50 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.test.tsx +66 -0
- package/src/components/custom/ActiveWork/FileActivityDetail.tsx +202 -0
- package/src/components/custom/ActiveWork/FileActivityRow.stories.tsx +70 -0
- package/src/components/custom/ActiveWork/FileActivityRow.test.tsx +67 -0
- package/src/components/custom/ActiveWork/FileActivityRow.tsx +130 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.stories.tsx +84 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.test.tsx +99 -0
- package/src/components/custom/ActiveWork/FileHistoryExplorer.tsx +138 -0
- package/src/components/custom/ActiveWork/FilePathLabel.stories.tsx +39 -0
- package/src/components/custom/ActiveWork/FilePathLabel.test.tsx +53 -0
- package/src/components/custom/ActiveWork/FilePathLabel.tsx +63 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.stories.tsx +50 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.test.tsx +62 -0
- package/src/components/custom/ActiveWork/InitiativeBrief.tsx +181 -0
- package/src/components/custom/ActiveWork/InitiativeCard.stories.tsx +73 -0
- package/src/components/custom/ActiveWork/InitiativeCard.test.tsx +68 -0
- package/src/components/custom/ActiveWork/InitiativeCard.tsx +136 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.stories.tsx +59 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.test.tsx +40 -0
- package/src/components/custom/ActiveWork/InitiativeHeader.tsx +73 -0
- package/src/components/custom/ActiveWork/InitiativeReader.stories.tsx +145 -0
- package/src/components/custom/ActiveWork/OpenLoops.stories.tsx +58 -0
- package/src/components/custom/ActiveWork/OpenLoops.test.tsx +61 -0
- package/src/components/custom/ActiveWork/OpenLoops.tsx +107 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.stories.tsx +101 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.test.tsx +81 -0
- package/src/components/custom/ActiveWork/PortfolioOverview.tsx +83 -0
- package/src/components/custom/ActiveWork/README.md +305 -0
- package/src/components/custom/ActiveWork/SessionDetail.stories.tsx +71 -0
- package/src/components/custom/ActiveWork/SessionDetail.test.tsx +84 -0
- package/src/components/custom/ActiveWork/SessionDetail.tsx +180 -0
- package/src/components/custom/ActiveWork/SessionList.stories.tsx +69 -0
- package/src/components/custom/ActiveWork/SessionList.test.tsx +78 -0
- package/src/components/custom/ActiveWork/SessionList.tsx +103 -0
- package/src/components/custom/ActiveWork/SessionListItem.stories.tsx +64 -0
- package/src/components/custom/ActiveWork/SessionListItem.test.tsx +62 -0
- package/src/components/custom/ActiveWork/SessionListItem.tsx +152 -0
- package/src/components/custom/ActiveWork/SessionReader.stories.tsx +113 -0
- package/src/components/custom/ActiveWork/SeverityLabel.stories.tsx +51 -0
- package/src/components/custom/ActiveWork/SeverityLabel.test.tsx +68 -0
- package/src/components/custom/ActiveWork/SeverityLabel.tsx +97 -0
- package/src/components/custom/ActiveWork/TaskRow.stories.tsx +63 -0
- package/src/components/custom/ActiveWork/TaskRow.test.tsx +112 -0
- package/src/components/custom/ActiveWork/TaskRow.tsx +176 -0
- package/src/components/custom/ActiveWork/TaskTable.stories.tsx +123 -0
- package/src/components/custom/ActiveWork/TaskTable.test.tsx +233 -0
- package/src/components/custom/ActiveWork/TaskTable.tsx +321 -0
- package/src/components/custom/ActiveWork/active-work-depth.test.tsx +102 -0
- package/src/components/custom/ActiveWork/file-history-fixture.ts +91 -0
- package/src/components/custom/ActiveWork/format-time.test.ts +23 -0
- package/src/components/custom/ActiveWork/format-time.ts +32 -0
- package/src/components/custom/ActiveWork/index.ts +19 -0
- package/src/components/custom/ActiveWork/initiative-fixture.ts +104 -0
- package/src/components/custom/ActiveWork/session-fixture.ts +267 -0
- package/src/components/custom/ActiveWork/session-linkers.ts +56 -0
- package/src/components/custom/ActiveWork/task-list-fixture.ts +97 -0
- package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +4 -3
- package/src/components/custom/DateTime/DateTime.stories.tsx +2 -1
- package/src/components/custom/DateTime/DateTime.test.tsx +3 -1
- package/src/components/custom/EmptyState/EmptyState.stories.tsx +22 -9
- package/src/components/custom/EmptyState/EmptyState.test.tsx +7 -13
- package/src/components/custom/EmptyState/EmptyState.tsx +4 -18
- package/src/components/custom/Fatigue/DualGhostSpark.stories.tsx +4 -3
- package/src/components/custom/Fatigue/FatigueLights.stories.tsx +2 -2
- package/src/components/custom/Fatigue/GhostSpark.stories.tsx +4 -3
- package/src/components/custom/Fatigue/LiveFatigueCard.stories.tsx +2 -2
- package/src/components/custom/Fatigue/LiveFatigueCard.tsx +8 -4
- package/src/components/custom/Fatigue/LiveFatiguePanel.stories.tsx +116 -6
- package/src/components/custom/Fatigue/LiveFatiguePanel.test.tsx +134 -0
- package/src/components/custom/Fatigue/LiveFatiguePanel.tsx +54 -83
- package/src/components/custom/Fatigue/README.md +40 -3
- package/src/components/custom/Fatigue/RomProgressionChart.stories.tsx +2 -2
- package/src/components/custom/Fatigue/SilverRedPalette.stories.tsx +2 -1
- package/src/components/custom/Fatigue/VelocityHero.stories.tsx +4 -3
- package/src/components/custom/Fatigue/VerdictHero.stories.tsx +2 -2
- package/src/components/custom/Fatigue/fatigue-mock.test.ts +0 -5
- package/src/components/custom/Fatigue/fatigue-mock.ts +2 -10
- package/src/components/custom/Fatigue/fatigue-tokens.ts +12 -0
- package/src/components/custom/Fatigue/index.ts +17 -5
- package/src/components/custom/Fatigue/panel-layout.test.ts +149 -0
- package/src/components/custom/Fatigue/panel-layout.ts +185 -0
- package/src/components/custom/Gauge/Gauge.stories.tsx +2 -2
- package/src/components/custom/Gauge/Gauge.test.tsx +1 -1
- package/src/components/custom/Gauge/Gauge.tsx +4 -1
- package/src/components/custom/Metric/Metric.stories.tsx +10 -1
- package/src/components/custom/Metric/Metric.test.tsx +1 -3
- package/src/components/custom/Metric/Metric.tsx +5 -20
- package/src/components/custom/Prose/MarkdownProse.stories.tsx +88 -0
- package/src/components/custom/Prose/MarkdownProse.test.tsx +87 -0
- package/src/components/custom/Prose/MarkdownProse.tsx +201 -0
- package/src/components/custom/Prose/README.md +58 -0
- package/src/components/custom/Prose/index.ts +1 -0
- package/src/components/custom/Scatter/Scatter.stories.tsx +46 -8
- package/src/components/custom/Scatter/Scatter.test.tsx +2 -2
- package/src/components/custom/Scatter/Scatter.tsx +116 -14
- package/src/components/custom/Sidebar/Sidebar.stories.tsx +40 -7
- package/src/components/custom/Sidebar/Sidebar.test.tsx +5 -1
- package/src/components/custom/Sidebar/Sidebar.tsx +16 -33
- package/src/components/custom/Table/Table.stories.tsx +98 -15
- package/src/components/custom/Table/Table.test.tsx +273 -86
- package/src/components/custom/Table/Table.tsx +159 -67
- package/src/components/custom/Table/column-fit.test.ts +75 -0
- package/src/components/custom/Table/column-fit.ts +116 -0
- package/src/components/custom/Table/index.ts +9 -0
- package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +8 -6
- package/src/components/custom/Treemap/Treemap.stories.tsx +2 -2
- package/src/components/custom/Treemap/Treemap.test.tsx +1 -1
- package/src/components/custom/Treemap/Treemap.tsx +7 -2
- package/src/components/custom/Typography/Typography.stories.tsx +28 -1
- package/src/components/custom/Typography/Typography.test.tsx +34 -0
- package/src/components/custom/Typography/Typography.tsx +6 -0
- package/src/components/custom/Typography/index.ts +1 -8
- package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +9 -1
- package/src/components/custom/Workout/BaseBadge.stories.tsx +19 -7
- package/src/components/custom/Workout/BaseBadge.test.tsx +31 -11
- package/src/components/custom/Workout/BaseBadge.tsx +3 -0
- package/src/components/custom/Workout/BodyMap.stories.tsx +4 -1
- package/src/components/custom/Workout/BodyMap.tsx +3 -1
- package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +16 -4
- package/src/components/custom/Workout/BodyMapDetailPanel.test.tsx +11 -15
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +45 -9
- package/src/components/custom/Workout/CapacityBandChart.stories.tsx +10 -8
- package/src/components/custom/Workout/CapacityBandChart.test.tsx +24 -51
- package/src/components/custom/Workout/CapacityBandChart.tsx +139 -108
- package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
- package/src/components/custom/Workout/DeviationBar.test.tsx +5 -2
- package/src/components/custom/Workout/DeviationBar.tsx +21 -16
- package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +182 -0
- package/src/components/custom/Workout/DualVelocityStrip.test.tsx +3 -2
- package/src/components/custom/Workout/ExerciseCard.stories.tsx +8 -7
- package/src/components/custom/Workout/ExerciseCard.test.tsx +13 -3
- package/src/components/custom/Workout/ExerciseCard.tsx +42 -51
- package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +7 -7
- package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +9 -1
- package/src/components/custom/Workout/ExerciseHeading.stories.tsx +8 -8
- package/src/components/custom/Workout/ExerciseHeading.tsx +8 -5
- package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +6 -4
- package/src/components/custom/Workout/ExerciseIndicator.test.tsx +27 -11
- package/src/components/custom/Workout/ExerciseIndicator.tsx +14 -15
- package/src/components/custom/Workout/FatigueMeter.stories.tsx +5 -5
- package/src/components/custom/Workout/InputBar.stories.tsx +4 -5
- package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
- package/src/components/custom/Workout/IntensityBar.test.tsx +5 -1
- package/src/components/custom/Workout/IntensityBar.tsx +4 -2
- package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +5 -4
- package/src/components/custom/Workout/MesoCard.stories.tsx +4 -1
- package/src/components/custom/Workout/MesoCard.test.tsx +7 -18
- package/src/components/custom/Workout/MesoCard.tsx +12 -9
- package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
- package/src/components/custom/Workout/MesoProgressBar.test.tsx +18 -11
- package/src/components/custom/Workout/MesoProgressBar.tsx +15 -13
- package/src/components/custom/Workout/MesoStatusCard.stories.tsx +2 -1
- package/src/components/custom/Workout/MesoStatusCard.test.tsx +14 -44
- package/src/components/custom/Workout/MesoStatusCard.tsx +9 -23
- package/src/components/custom/Workout/MetricTiles.stories.tsx +3 -2
- package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +2 -8
- package/src/components/custom/Workout/MuscleGroupChip.test.tsx +23 -31
- package/src/components/custom/Workout/MuscleGroupChip.tsx +28 -67
- package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +1 -1
- package/src/components/custom/Workout/PlaceholderStrip.test.tsx +17 -10
- package/src/components/custom/Workout/PlaceholderStrip.tsx +9 -8
- package/src/components/custom/Workout/PrBadge.stories.tsx +2 -1
- package/src/components/custom/Workout/PrBadge.test.tsx +3 -9
- package/src/components/custom/Workout/PrBadge.tsx +13 -17
- package/src/components/custom/Workout/PrHistoryModal.stories.tsx +4 -1
- package/src/components/custom/Workout/PrHistoryModal.test.tsx +13 -36
- package/src/components/custom/Workout/PrHistoryModal.tsx +8 -4
- package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +6 -1
- package/src/components/custom/Workout/README.md +11 -6
- package/src/components/custom/Workout/ReadinessCheck.stories.tsx +3 -2
- package/src/components/custom/Workout/ReadinessCheck.test.tsx +12 -18
- package/src/components/custom/Workout/ReadinessCheck.tsx +19 -3
- package/src/components/custom/Workout/RestTimer.stories.tsx +3 -2
- package/src/components/custom/Workout/ScheduleTiles.stories.tsx +3 -2
- package/src/components/custom/Workout/ScheduleTiles.test.tsx +3 -4
- package/src/components/custom/Workout/ScheduleTiles.tsx +4 -7
- package/src/components/custom/Workout/SegmentedBar.stories.tsx +5 -5
- package/src/components/custom/Workout/SegmentedBar.tsx +6 -2
- package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +5 -5
- package/src/components/custom/Workout/SessionHeader.stories.tsx +6 -6
- package/src/components/custom/Workout/SessionHeader.tsx +12 -12
- package/src/components/custom/Workout/SessionRail.stories.tsx +12 -11
- package/src/components/custom/Workout/SessionRail.tsx +7 -9
- package/src/components/custom/Workout/SetBar.stories.tsx +10 -6
- package/src/components/custom/Workout/SetBar.test.tsx +49 -4
- package/src/components/custom/Workout/SetBar.tsx +38 -12
- package/src/components/custom/Workout/SetRow.stories.tsx +3 -2
- package/src/components/custom/Workout/SetRow.test.tsx +16 -2
- package/src/components/custom/Workout/SetRow.tsx +61 -23
- package/src/components/custom/Workout/SetStrip.stories.tsx +60 -5
- package/src/components/custom/Workout/SetStrip.test.tsx +25 -0
- package/src/components/custom/Workout/SetStrip.tsx +24 -4
- package/src/components/custom/Workout/SetTableHeader.stories.tsx +6 -6
- package/src/components/custom/Workout/SetTableHeader.tsx +9 -12
- package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +7 -7
- package/src/components/custom/Workout/SetsRepsLoad.tsx +3 -5
- package/src/components/custom/Workout/Sparkline.stories.tsx +1 -1
- package/src/components/custom/Workout/Sparkline.test.tsx +37 -19
- package/src/components/custom/Workout/Sparkline.tsx +14 -18
- package/src/components/custom/Workout/StatusDot.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusDot.test.tsx +44 -5
- package/src/components/custom/Workout/StatusDot.tsx +93 -63
- package/src/components/custom/Workout/StatusPill.stories.tsx +1 -1
- package/src/components/custom/Workout/StatusPill.test.tsx +6 -15
- package/src/components/custom/Workout/StatusPill.tsx +27 -38
- package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +9 -3
- package/src/components/custom/Workout/StrengthTrendChart.test.tsx +15 -37
- package/src/components/custom/Workout/StrengthTrendChart.tsx +31 -30
- package/src/components/custom/Workout/SupersetWrapper.stories.tsx +27 -64
- package/src/components/custom/Workout/SupersetWrapper.test.tsx +16 -14
- package/src/components/custom/Workout/SupersetWrapper.tsx +17 -21
- package/src/components/custom/Workout/TempoDisplay.stories.tsx +22 -7
- package/src/components/custom/Workout/TempoDisplay.test.tsx +18 -4
- package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +9 -1
- package/src/components/custom/Workout/VelocityStrip.compact.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +7 -4
- package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +4 -1
- package/src/components/custom/Workout/VelocityStrip.stories.tsx +12 -6
- package/src/components/custom/Workout/VelocityStrip.tsx +3 -0
- package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +6 -7
- package/src/components/custom/Workout/VolumeLandmarkBar.tsx +15 -6
- package/src/components/custom/Workout/WeekRow.stories.tsx +4 -1
- package/src/components/custom/Workout/WeekRow.test.tsx +18 -15
- package/src/components/custom/Workout/WeekRow.tsx +23 -16
- package/src/components/custom/Workout/WeightBadge.stories.tsx +2 -1
- package/src/components/custom/Workout/WeightBadge.test.tsx +50 -19
- package/src/components/custom/Workout/WeightBadge.tsx +28 -27
- package/src/components/custom/Workout/WorkoutCard.stories.tsx +6 -1
- package/src/components/custom/Workout/WorkoutCard.test.tsx +18 -0
- package/src/components/custom/Workout/WorkoutCard.tsx +35 -57
- package/src/components/custom/Workout/WorkoutPill.stories.tsx +5 -2
- package/src/components/custom/Workout/WorkoutPill.test.tsx +39 -7
- package/src/components/custom/Workout/WorkoutPill.tsx +88 -57
- package/src/components/custom/Workout/ZoneTrack.stories.tsx +7 -6
- package/src/components/custom/Workout/ZoneTrack.tsx +10 -9
- package/src/components/custom/Workout/index.ts +5 -0
- package/src/components/custom/Workout/metricText.stories.tsx +6 -5
- package/src/components/custom/Workout/metricText.tsx +4 -0
- package/src/components/custom/Workout/setHeadingKit.tsx +207 -26
- package/src/components/custom/charts/README.md +61 -0
- package/src/components/custom/charts/SetBarChart.test.tsx +30 -1
- package/src/components/custom/charts/SetBarChart.tsx +42 -4
- package/src/components/custom/charts/SparkBars.stories.tsx +55 -0
- package/src/components/custom/charts/SparkBars.test.tsx +69 -0
- package/src/components/custom/charts/SparkBars.tsx +85 -0
- package/src/components/custom/charts/index.ts +3 -0
- package/src/components/custom/index.ts +3 -0
- package/src/components/custom/stepper/Stepper.stories.tsx +13 -10
- package/src/components/custom/stepper/Stepper.test.tsx +1 -7
- package/src/components/custom/stepper/Stepper.tsx +13 -28
- package/src/components/icons/icons.stories.tsx +1 -1
- package/src/components/icons/icons.tsx +51 -0
- package/src/components/shell/AppShell.stories.tsx +150 -0
- package/src/components/shell/AppShell.test.tsx +70 -0
- package/src/components/shell/AppShell.tsx +90 -0
- package/src/components/shell/BrandLockup.stories.tsx +66 -5
- package/src/components/shell/BrandLockup.test.tsx +34 -1
- package/src/components/shell/BrandLockup.tsx +27 -11
- package/src/components/shell/NavItem.stories.tsx +4 -4
- package/src/components/shell/NavItem.test.tsx +17 -0
- package/src/components/shell/NavItem.tsx +17 -5
- package/src/components/shell/README.md +89 -26
- package/src/components/shell/SideNav.stories.tsx +38 -7
- package/src/components/shell/SideNav.test.tsx +16 -8
- package/src/components/shell/SideNav.tsx +17 -17
- package/src/components/shell/TopBar.stories.tsx +44 -19
- package/src/components/shell/TopBar.test.tsx +34 -12
- package/src/components/shell/TopBar.tsx +61 -40
- package/src/components/shell/brands.tsx +66 -0
- package/src/components/shell/index.ts +9 -8
- package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx} +2 -2
- package/src/components/shell/{DeviceIndicator.tsx → workout/DeviceIndicator.tsx} +2 -2
- package/src/components/shell/{DeviceMenu.stories.tsx → workout/DeviceMenu.stories.tsx} +2 -2
- package/src/components/shell/{DeviceMenu.tsx → workout/DeviceMenu.tsx} +3 -3
- package/src/components/shell/{DeviceRow.stories.tsx → workout/DeviceRow.stories.tsx} +2 -2
- package/src/components/shell/{DeviceRow.tsx → workout/DeviceRow.tsx} +3 -3
- package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx} +2 -2
- package/src/components/shell/{SessionStatePill.tsx → workout/SessionStatePill.tsx} +5 -3
- package/src/components/shell/workout/WorkoutShell.stories.tsx +71 -0
- package/src/components/shell/{DashboardShell.test.tsx → workout/WorkoutShell.test.tsx} +19 -8
- package/src/components/shell/workout/WorkoutShell.tsx +77 -0
- package/src/components/shell/workout/WorkoutTopBar.stories.tsx +58 -0
- package/src/components/shell/workout/WorkoutTopBar.test.tsx +39 -0
- package/src/components/shell/workout/WorkoutTopBar.tsx +52 -0
- package/src/components/shell/workout/index.ts +9 -0
- package/src/components/shell/workout/workoutNavItems.tsx +16 -0
- package/src/components/ui/README.md +110 -0
- package/src/components/ui/alert/Alert.stories.tsx +1 -1
- package/src/components/ui/autocomplete/Autocomplete.stories.tsx +11 -13
- package/src/components/ui/autocomplete/Autocomplete.test.tsx +7 -25
- package/src/components/ui/autocomplete/Autocomplete.tsx +21 -28
- package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
- package/src/components/ui/avatar/Avatar.tsx +2 -10
- package/src/components/ui/badge/Badge.stories.tsx +83 -28
- package/src/components/ui/badge/Badge.test.tsx +19 -3
- package/src/components/ui/badge/Badge.tsx +48 -55
- package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
- package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +4 -16
- package/src/components/ui/button/Button.stories.tsx +46 -12
- package/src/components/ui/button/Button.tsx +32 -25
- package/src/components/ui/card/Card.stories.tsx +90 -94
- package/src/components/ui/card/Card.test.tsx +80 -6
- package/src/components/ui/card/Card.tsx +150 -203
- package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
- package/src/components/ui/checkbox/Checkbox.tsx +6 -26
- package/src/components/ui/chip/Chip.stories.tsx +37 -13
- package/src/components/ui/chip/Chip.test.tsx +10 -6
- package/src/components/ui/chip/Chip.tsx +76 -91
- package/src/components/ui/collapse/Collapse.stories.tsx +23 -23
- package/src/components/ui/collapse/Collapse.tsx +6 -11
- package/src/components/ui/data-row/DataRow.stories.tsx +9 -2
- package/src/components/ui/data-row/DataRow.test.tsx +5 -15
- package/src/components/ui/data-row/DataRow.tsx +18 -7
- package/src/components/ui/divider/Divider.stories.tsx +1 -1
- package/src/components/ui/divider/Divider.tsx +1 -5
- package/src/components/ui/drawer/Drawer.stories.tsx +5 -16
- package/src/components/ui/drawer/Drawer.tsx +13 -30
- package/src/components/ui/floating-overlay-depth.test.tsx +143 -0
- package/src/components/ui/form-field/FormField.stories.tsx +6 -20
- package/src/components/ui/form-field/FormField.test.tsx +1 -5
- package/src/components/ui/form-field/FormField.tsx +10 -46
- package/src/components/ui/help-tip/HelpTip.stories.tsx +8 -19
- package/src/components/ui/help-tip/HelpTip.test.tsx +1 -3
- package/src/components/ui/help-tip/HelpTip.tsx +21 -22
- package/src/components/ui/help-tip/index.ts +7 -1
- package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
- package/src/components/ui/icon-box/IconBox.test.tsx +1 -7
- package/src/components/ui/icon-box/IconBox.tsx +2 -12
- package/src/components/ui/indicator/Indicator.stories.tsx +1 -1
- package/src/components/ui/indicator/Indicator.tsx +20 -14
- package/src/components/ui/input/Input.stories.tsx +3 -11
- package/src/components/ui/input/Input.test.tsx +2 -10
- package/src/components/ui/input/Input.tsx +10 -25
- package/src/components/ui/input/index.ts +7 -1
- package/src/components/ui/link/Link.stories.tsx +19 -7
- package/src/components/ui/list-item/ListItem.stories.tsx +11 -2
- package/src/components/ui/list-item/ListItem.tsx +2 -9
- package/src/components/ui/menu/Menu.stories.tsx +21 -15
- package/src/components/ui/menu/Menu.test.tsx +2 -11
- package/src/components/ui/menu/Menu.tsx +12 -14
- package/src/components/ui/menu/index.ts +8 -1
- package/src/components/ui/modal/Modal.stories.tsx +2 -2
- package/src/components/ui/modal/Modal.tsx +29 -19
- package/src/components/ui/pill/Pill.stories.tsx +58 -23
- package/src/components/ui/pill/Pill.test.tsx +101 -3
- package/src/components/ui/pill/Pill.tsx +164 -49
- package/src/components/ui/pill/index.ts +1 -1
- package/src/components/ui/popover/Popover.stories.tsx +5 -7
- package/src/components/ui/popover/Popover.test.tsx +1 -6
- package/src/components/ui/popover/Popover.tsx +20 -15
- package/src/components/ui/popover/index.ts +7 -1
- package/src/components/ui/progress/Progress.stories.tsx +3 -12
- package/src/components/ui/progress/Progress.test.tsx +1 -5
- package/src/components/ui/radio/Radio.stories.tsx +42 -21
- package/src/components/ui/radio/Radio.test.tsx +6 -2
- package/src/components/ui/radio/Radio.tsx +23 -22
- package/src/components/ui/section/Section.stories.tsx +5 -14
- package/src/components/ui/section/Section.test.tsx +1 -6
- package/src/components/ui/section/Section.tsx +1 -3
- package/src/components/ui/section/index.ts +1 -5
- package/src/components/ui/select/Select.stories.tsx +3 -13
- package/src/components/ui/select/Select.test.tsx +2 -11
- package/src/components/ui/select/Select.tsx +14 -14
- package/src/components/ui/skeleton/Skeleton.stories.tsx +3 -11
- package/src/components/ui/skeleton/Skeleton.tsx +3 -14
- package/src/components/ui/skeleton/index.ts +1 -7
- package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
- package/src/components/ui/spinner/Spinner.tsx +1 -4
- package/src/components/ui/stack/Stack.stories.tsx +1 -1
- package/src/components/ui/stack/Stack.tsx +1 -1
- package/src/components/ui/surface/Surface.stories.tsx +17 -5
- package/src/components/ui/surface/Surface.test.tsx +88 -28
- package/src/components/ui/surface/Surface.tsx +37 -87
- package/src/components/ui/surface/SurfaceContext.ts +22 -62
- package/src/components/ui/surface/index.ts +8 -0
- package/src/components/ui/surface/resolveSurface.ts +98 -0
- package/src/components/ui/surface/surface.contract.test.ts +6 -1
- package/src/components/ui/switch/Switch.stories.tsx +1 -1
- package/src/components/ui/switch/Switch.tsx +7 -6
- package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
- package/src/components/ui/tabs/Tabs.tsx +7 -22
- package/src/components/ui/tabs/index.ts +1 -7
- package/src/components/ui/tile/Tile.stories.tsx +1 -1
- package/src/components/ui/tile/Tile.tsx +3 -0
- package/src/components/ui/toast/Toast.stories.tsx +1 -1
- package/src/components/ui/toast/Toast.test.tsx +2 -8
- package/src/components/ui/toast/Toast.tsx +43 -53
- package/src/components/ui/toast/index.ts +0 -1
- package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +92 -71
- package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +3 -18
- package/src/components/ui/toolbar-button/ToolbarButton.tsx +25 -43
- package/src/components/ui/tooltip/Tooltip.stories.tsx +12 -3
- package/src/components/ui/tooltip/Tooltip.test.tsx +21 -3
- package/src/components/ui/tooltip/Tooltip.tsx +55 -36
- package/src/components/ui/tooltip/index.ts +1 -1
- package/src/components/ui/trigger/TriggerSurface.test.tsx +215 -0
- package/src/components/ui/trigger/TriggerSurface.tsx +81 -0
- package/src/components/ui/trigger/index.ts +2 -0
- package/src/stories/PresetShowcase.stories.tsx +100 -47
- package/src/test/no-device-internals.test.ts +3 -3
- package/src/theme/ChoosingTokens.stories.tsx +48 -0
- package/src/theme/ColorPalettes.stories.tsx +62 -45
- package/src/theme/ColorPrimitives.stories.tsx +35 -35
- package/src/theme/Depth.stories.tsx +132 -65
- package/src/theme/DepthCalibration.stories.tsx +23 -21
- package/src/theme/ThemeProvider.test.tsx +4 -4
- package/src/theme/barrel.ts +7 -6
- package/src/theme/color-stories.coverage.test.ts +1 -1
- package/src/theme/color-utils.ts +41 -29
- package/src/theme/config.completeness.test.ts +1 -1
- package/src/theme/config.ts +28 -0
- package/src/theme/elevation.test.ts +82 -56
- package/src/theme/elevation.ts +77 -561
- package/src/theme/global.css +30 -2
- package/src/theme/grey-ramp.test.ts +24 -8
- package/src/theme/lift.test.ts +39 -0
- package/src/theme/lift.ts +102 -0
- package/src/theme/materials.test.ts +5 -2
- package/src/theme/materials.ts +38 -4
- package/src/theme/native-theming-guard.test.ts +5 -5
- package/src/theme/presets/apply.ts +4 -0
- package/src/theme/presets/audiobook.ts +5 -2
- package/src/theme/presets/default.ts +4 -0
- package/src/theme/presets/index.ts +14 -1
- package/src/theme/presets/types.ts +1 -1
- package/src/theme/semantic-contrast.test.ts +13 -4
- package/src/theme/status-distinctness.test.ts +66 -0
- package/src/theme/surface-planes.test.ts +37 -0
- package/src/theme/surface-planes.ts +68 -0
- package/src/theme/token-export-guard.test.ts +1 -3
- package/src/theme/tokens/primitives.test.ts +15 -7
- package/src/theme/tokens/primitives.ts +65 -33
- package/src/theme/tokens/semantic.ts +71 -37
- package/src/theme/wash-ladder.test.ts +58 -0
- package/src/theme/workout-tokens.ts +1 -7
- package/src/types/jest-axe.d.ts +2 -6
- package/src/types/raw-md.d.ts +5 -0
- package/src/utils/colors.ts +4 -4
- package/src/utils/form.ts +1 -3
- package/src/utils/index.ts +2 -7
- package/src/utils/number-format.ts +17 -0
- package/src/utils/workout-format.ts +15 -6
- package/src/web-jsx/jsx-runtime.ts +1 -5
- package/tailwind.config.js +5 -0
- package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +0 -151
- package/src/components/custom/Workout/RowInventory.stories.tsx +0 -408
- package/src/components/custom/Workout/S3FullRail.stories.tsx +0 -46
- package/src/components/custom/Workout/S3SessionPace.stories.tsx +0 -95
- package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +0 -61
- package/src/components/custom/Workout/S3SetTypes.stories.tsx +0 -176
- package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +0 -240
- package/src/components/shell/DashboardShell.stories.tsx +0 -65
- package/src/components/shell/DashboardShell.tsx +0 -75
- package/src/components/shell/SessionRailSpecimen.stories.tsx +0 -753
- package/src/theme/elevation.stories.tsx +0 -346
- package/src/utils/useTheme.ts +0 -72
- /package/src/components/shell/{DeviceIndicator.test.tsx → workout/DeviceIndicator.test.tsx} +0 -0
- /package/src/components/shell/{DeviceMenu.test.tsx → workout/DeviceMenu.test.tsx} +0 -0
- /package/src/components/shell/{DeviceRow.test.tsx → workout/DeviceRow.test.tsx} +0 -0
- /package/src/components/shell/{SessionStatePill.test.tsx → workout/SessionStatePill.test.tsx} +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from 'react'
|
|
2
2
|
import { View } from 'react-native'
|
|
3
3
|
import { cn } from '../../utils/cn'
|
|
4
|
-
import { ActivityIcon, HistoryIcon, LayersIcon, PersonStandingIcon } from '../icons'
|
|
5
4
|
import { NavItem } from './NavItem'
|
|
6
5
|
|
|
7
6
|
export interface SideNavItem {
|
|
@@ -14,8 +13,8 @@ export interface SideNavItem {
|
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
export interface SideNavProps {
|
|
17
|
-
/** Category items, top → bottom.
|
|
18
|
-
items
|
|
16
|
+
/** Category items, top → bottom. The app owns its own categories. */
|
|
17
|
+
items: SideNavItem[]
|
|
19
18
|
/** Key of the active category. */
|
|
20
19
|
activeKey: string
|
|
21
20
|
/** Called with the tapped item's key. */
|
|
@@ -25,30 +24,29 @@ export interface SideNavProps {
|
|
|
25
24
|
* running off its view) → a quiet green cue on that item's label.
|
|
26
25
|
*/
|
|
27
26
|
liveKey?: string | null
|
|
27
|
+
/** Semantic `text-*` token for the active item. Defaults to the Voltras brand. */
|
|
28
|
+
accentClassName?: string
|
|
29
|
+
/** Semantic `bg-*` token for the active bar. Pair it with `accentClassName`. */
|
|
30
|
+
accentBarClassName?: string
|
|
28
31
|
className?: string
|
|
29
32
|
}
|
|
30
33
|
|
|
31
|
-
/** The four dashboard categories with their locked S2 glyphs (activity · history · layers · figure). */
|
|
32
|
-
export const defaultNavItems: SideNavItem[] = [
|
|
33
|
-
{ key: 'live', label: 'Live', icon: <ActivityIcon size={20} color="currentColor" /> },
|
|
34
|
-
{ key: 'review', label: 'Review', icon: <HistoryIcon size={20} color="currentColor" /> },
|
|
35
|
-
{ key: 'program', label: 'Plan', icon: <LayersIcon size={20} color="currentColor" /> },
|
|
36
|
-
{ key: 'body', label: 'Body', icon: <PersonStandingIcon size={20} color="currentColor" /> },
|
|
37
|
-
]
|
|
38
|
-
|
|
39
34
|
/**
|
|
40
35
|
* Shell S2 · SideNav — the persistent 60px left rail that switches the main
|
|
41
|
-
* viewport between
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* the active view) tints that item's label a muted green.
|
|
45
|
-
* width — labels sit under the glyph, so they never change
|
|
36
|
+
* viewport between an app's categories. Presentational: it renders `items` and
|
|
37
|
+
* reports taps via `onNavigate`; the app owns its categories, routing, and which
|
|
38
|
+
* key is `live`. Active item shows a left accent bar in the app's brand accent;
|
|
39
|
+
* `liveKey` (when not the active view) tints that item's label a muted green.
|
|
40
|
+
* Fixed 60px at every width — labels sit under the glyph, so they never change
|
|
41
|
+
* the rail width.
|
|
46
42
|
*/
|
|
47
43
|
export function SideNav({
|
|
48
|
-
items
|
|
44
|
+
items,
|
|
49
45
|
activeKey,
|
|
50
46
|
onNavigate,
|
|
51
47
|
liveKey = null,
|
|
48
|
+
accentClassName,
|
|
49
|
+
accentBarClassName,
|
|
52
50
|
className,
|
|
53
51
|
}: SideNavProps) {
|
|
54
52
|
return (
|
|
@@ -66,6 +64,8 @@ export function SideNav({
|
|
|
66
64
|
label={item.label}
|
|
67
65
|
active={item.key === activeKey}
|
|
68
66
|
live={item.key === liveKey && item.key !== activeKey}
|
|
67
|
+
accentClassName={accentClassName}
|
|
68
|
+
accentBarClassName={accentBarClassName}
|
|
69
69
|
onPress={() => onNavigate?.(item.key)}
|
|
70
70
|
/>
|
|
71
71
|
))}
|
|
@@ -1,44 +1,41 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
import { Pill } from '../ui/pill'
|
|
2
3
|
import { TopBar } from './TopBar'
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
const DEVICES: Device[] = [
|
|
6
|
-
{ id: 'Voltra-A3F2', nickname: 'Left Cable', slot: 'L', state: 'connected' },
|
|
7
|
-
{ id: 'Voltra-9B1C', nickname: 'Right Cable', slot: 'R', state: 'connected' },
|
|
8
|
-
{ id: 'Voltra-77E0', nickname: 'Spare', slot: null, state: 'available' },
|
|
9
|
-
]
|
|
4
|
+
import { brandKeys } from './brands'
|
|
10
5
|
|
|
11
6
|
const meta: Meta<typeof TopBar> = {
|
|
12
7
|
title: 'Shell/TopBar',
|
|
13
8
|
component: TopBar,
|
|
14
|
-
tags: ['autodocs'],
|
|
15
|
-
args: {
|
|
9
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
10
|
+
args: { brand: 'voltras' },
|
|
16
11
|
argTypes: {
|
|
17
|
-
|
|
18
|
-
devices: { control: 'object' },
|
|
12
|
+
brand: { control: 'select', options: brandKeys },
|
|
19
13
|
subtitle: { control: 'text' },
|
|
20
14
|
showSubtitle: { control: 'boolean' },
|
|
21
15
|
showClock: { control: 'boolean' },
|
|
22
16
|
time: { control: false },
|
|
23
|
-
|
|
17
|
+
leading: { control: false },
|
|
18
|
+
trailing: { control: false },
|
|
24
19
|
},
|
|
25
20
|
parameters: {
|
|
26
21
|
layout: 'fullscreen',
|
|
27
22
|
docs: {
|
|
28
23
|
description: {
|
|
29
24
|
component:
|
|
30
|
-
'**Organism** — the persistent shell chrome band,
|
|
25
|
+
'**Organism** — the persistent shell chrome band, generic over the app ' +
|
|
31
26
|
'(see `shell/README.md` for the full dependency map). Composes ' +
|
|
32
27
|
'[BrandLockup](?path=/docs/shell-brandlockup--docs) + ' +
|
|
33
|
-
'[SessionStatePill](?path=/docs/shell-sessionstatepill--docs) + ' +
|
|
34
28
|
'[Divider](?path=/docs/components-atoms-divider--docs) (`bg-border-prominent`) + ' +
|
|
35
|
-
'[DeviceMenu](?path=/docs/shell-devicemenu--docs) + ' +
|
|
36
29
|
'[DateTime](?path=/docs/components-molecules-datetime--docs) (`variant="mono"` live clock). ' +
|
|
37
30
|
'Background = the shared `surfaceGradient.chrome` primitive.\n\n' +
|
|
38
|
-
'**
|
|
39
|
-
'
|
|
40
|
-
'
|
|
41
|
-
|
|
31
|
+
'**Composition (AW-132).** The bar owns the band, the brand region, the divider ' +
|
|
32
|
+
'rhythm and the edge-pinned clock. An app supplies its own chrome through ' +
|
|
33
|
+
'`trailing` — pass an array and the bar puts its dividers between the items. ' +
|
|
34
|
+
"`leading` replaces the brand region outright. The workout app's cluster lives in " +
|
|
35
|
+
'[WorkoutTopBar](?path=/docs/shell-workout-workouttopbar--docs).\n\n' +
|
|
36
|
+
'**Try it:** switch `brand` in the **Controls**, or toggle `showSubtitle` / ' +
|
|
37
|
+
'`showClock`. **Resize the canvas** to watch the container-responsive collapse ' +
|
|
38
|
+
'(SIZE-D01) — subtitle drops < 1024px, clock < 720px.',
|
|
42
39
|
},
|
|
43
40
|
},
|
|
44
41
|
},
|
|
@@ -46,4 +43,32 @@ const meta: Meta<typeof TopBar> = {
|
|
|
46
43
|
export default meta
|
|
47
44
|
type Story = StoryObj<typeof TopBar>
|
|
48
45
|
|
|
46
|
+
/** Brand + clock only. No app has supplied any chrome. */
|
|
49
47
|
export const Default: Story = {}
|
|
48
|
+
|
|
49
|
+
/** Two app-supplied items in `trailing` — the bar adds the dividers and the clock. */
|
|
50
|
+
export const WithAppChrome: Story = {
|
|
51
|
+
args: {
|
|
52
|
+
brand: 'brain',
|
|
53
|
+
trailing: [
|
|
54
|
+
<Pill key="index" tone="success" leading="dot" size="xs">
|
|
55
|
+
indexed
|
|
56
|
+
</Pill>,
|
|
57
|
+
<Pill key="scope" tone="neutral" size="xs">
|
|
58
|
+
4 vaults
|
|
59
|
+
</Pill>,
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** One item, no array — a single node is a valid `trailing` too. */
|
|
65
|
+
export const SingleTrailingItem: Story = {
|
|
66
|
+
args: {
|
|
67
|
+
brand: 'audiobook',
|
|
68
|
+
trailing: (
|
|
69
|
+
<Pill tone="brand-secondary" size="xs">
|
|
70
|
+
3 downloading
|
|
71
|
+
</Pill>
|
|
72
|
+
),
|
|
73
|
+
},
|
|
74
|
+
}
|
|
@@ -1,36 +1,58 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest'
|
|
2
2
|
import { render, screen } from '@testing-library/react'
|
|
3
|
+
import { Text } from 'react-native'
|
|
3
4
|
import { axe } from 'jest-axe'
|
|
4
5
|
import { TopBar } from './TopBar'
|
|
5
|
-
import { type Device } from './DeviceRow'
|
|
6
|
-
|
|
7
|
-
const devices: Device[] = [
|
|
8
|
-
{ id: 'Voltra-A3F2', nickname: 'Left Cable', slot: 'L', state: 'connected' },
|
|
9
|
-
{ id: 'Voltra-9B1C', nickname: 'Right Cable', slot: 'R', state: 'connected' },
|
|
10
|
-
]
|
|
11
6
|
|
|
12
7
|
const AT_1612 = new Date(2024, 0, 1, 16, 12) // local 16:12
|
|
13
8
|
|
|
14
9
|
describe('TopBar', () => {
|
|
15
|
-
it('renders brand
|
|
16
|
-
render(<TopBar
|
|
10
|
+
it('renders the brand and a 24h clock', () => {
|
|
11
|
+
render(<TopBar time={AT_1612} showClock />)
|
|
17
12
|
expect(screen.getByText('VOLTRAS')).toBeInTheDocument()
|
|
18
|
-
expect(screen.getByText('LIVE')).toBeInTheDocument()
|
|
19
13
|
expect(screen.getByText('16:12')).toBeInTheDocument()
|
|
20
14
|
})
|
|
21
15
|
|
|
16
|
+
it('renders another app brand without knowing anything about it', () => {
|
|
17
|
+
render(<TopBar brand="brain" showClock={false} />)
|
|
18
|
+
expect(screen.getByText('BRAIN')).toBeInTheDocument()
|
|
19
|
+
expect(screen.getByText('/ knowledge')).toBeInTheDocument()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('mounts app chrome from the trailing slot', () => {
|
|
23
|
+
render(
|
|
24
|
+
<TopBar
|
|
25
|
+
showClock={false}
|
|
26
|
+
trailing={[<Text key="a">alpha</Text>, <Text key="b">beta</Text>]}
|
|
27
|
+
/>
|
|
28
|
+
)
|
|
29
|
+
expect(screen.getByText('alpha')).toBeInTheDocument()
|
|
30
|
+
expect(screen.getByText('beta')).toBeInTheDocument()
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('accepts a single trailing node as well as an array', () => {
|
|
34
|
+
render(<TopBar showClock={false} trailing={<Text>solo</Text>} />)
|
|
35
|
+
expect(screen.getByText('solo')).toBeInTheDocument()
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('replaces the brand region when a leading node is given', () => {
|
|
39
|
+
render(<TopBar leading={<Text>my own lockup</Text>} showClock={false} />)
|
|
40
|
+
expect(screen.getByText('my own lockup')).toBeInTheDocument()
|
|
41
|
+
expect(screen.queryByText('VOLTRAS')).not.toBeInTheDocument()
|
|
42
|
+
})
|
|
43
|
+
|
|
22
44
|
it('hides the clock when showClock is false', () => {
|
|
23
|
-
render(<TopBar
|
|
45
|
+
render(<TopBar time={AT_1612} showClock={false} />)
|
|
24
46
|
expect(screen.queryByText('16:12')).not.toBeInTheDocument()
|
|
25
47
|
})
|
|
26
48
|
|
|
27
49
|
it('hides the subtitle when showSubtitle is false', () => {
|
|
28
|
-
render(<TopBar
|
|
50
|
+
render(<TopBar showSubtitle={false} />)
|
|
29
51
|
expect(screen.queryByText('/ wall dashboard')).not.toBeInTheDocument()
|
|
30
52
|
})
|
|
31
53
|
|
|
32
54
|
it('has no accessibility violations', async () => {
|
|
33
|
-
const { container } = render(<TopBar
|
|
55
|
+
const { container } = render(<TopBar time={AT_1612} showClock trailing={<Text>chrome</Text>} />)
|
|
34
56
|
expect(await axe(container)).toHaveNoViolations()
|
|
35
57
|
})
|
|
36
58
|
})
|
|
@@ -1,28 +1,34 @@
|
|
|
1
|
-
import { useState } from 'react'
|
|
1
|
+
import { Fragment, useState, type ReactNode } from 'react'
|
|
2
2
|
import { View, type LayoutChangeEvent } from 'react-native'
|
|
3
3
|
import { cn } from '../../utils/cn'
|
|
4
4
|
import { surfaceGradient } from '../../theme/gradients'
|
|
5
5
|
import { Divider } from '../ui/divider'
|
|
6
6
|
import { DateTime } from '../custom/DateTime'
|
|
7
7
|
import { BrandLockup } from './BrandLockup'
|
|
8
|
-
import {
|
|
9
|
-
import { DeviceMenu } from './DeviceMenu'
|
|
10
|
-
import { type Device } from './DeviceRow'
|
|
8
|
+
import { type BrandKey } from './brands'
|
|
11
9
|
|
|
12
10
|
export interface TopBarProps {
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
devices: Device[]
|
|
17
|
-
/** The moment to display in the clock (Date/timestamp). Omit for a live ticking clock. */
|
|
18
|
-
time?: number | Date
|
|
19
|
-
/** Brand subtitle. Default "wall dashboard". */
|
|
11
|
+
/** Which app identity the default {@link BrandLockup} renders. */
|
|
12
|
+
brand?: BrandKey
|
|
13
|
+
/** Brand subtitle. Defaults to the brand preset's own. */
|
|
20
14
|
subtitle?: string
|
|
21
15
|
/** Force the subtitle on/off; defaults to container-responsive (hidden below ~1024px). */
|
|
22
16
|
showSubtitle?: boolean
|
|
17
|
+
/**
|
|
18
|
+
* Replace the whole brand region. Wins over `brand` / `subtitle`, and opts out
|
|
19
|
+
* of the responsive subtitle collapse — the node owns its own behaviour.
|
|
20
|
+
*/
|
|
21
|
+
leading?: ReactNode
|
|
22
|
+
/**
|
|
23
|
+
* App chrome for the right cluster, left → right. An array is rendered with the
|
|
24
|
+
* bar's own vertical dividers between the items, so an app supplies its
|
|
25
|
+
* controls and the shell keeps the divider rhythm.
|
|
26
|
+
*/
|
|
27
|
+
trailing?: ReactNode | ReactNode[]
|
|
28
|
+
/** The moment to display in the clock (Date/timestamp). Omit for a live ticking clock. */
|
|
29
|
+
time?: number | Date
|
|
23
30
|
/** Force the clock on/off; defaults to container-responsive (hidden below ~720px). */
|
|
24
31
|
showClock?: boolean
|
|
25
|
-
onSelectDevice?: (device: Device) => void
|
|
26
32
|
className?: string
|
|
27
33
|
}
|
|
28
34
|
|
|
@@ -30,20 +36,39 @@ export interface TopBarProps {
|
|
|
30
36
|
const SUBTITLE_MIN = 1024
|
|
31
37
|
const CLOCK_MIN = 720
|
|
32
38
|
|
|
39
|
+
function ClusterDivider() {
|
|
40
|
+
return <Divider orientation="vertical" className="h-4 bg-border-prominent" />
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Interleave the bar's divider between slot items, skipping empty slots. */
|
|
44
|
+
function dividedCluster(items: ReactNode[]) {
|
|
45
|
+
return items
|
|
46
|
+
.filter((item) => item !== null && item !== undefined && item !== false)
|
|
47
|
+
.map((item, i) => (
|
|
48
|
+
<Fragment key={i}>
|
|
49
|
+
{i > 0 ? <ClusterDivider /> : null}
|
|
50
|
+
{item}
|
|
51
|
+
</Fragment>
|
|
52
|
+
))
|
|
53
|
+
}
|
|
54
|
+
|
|
33
55
|
/**
|
|
34
|
-
* S1 · TopBar — the persistent shell chrome band
|
|
35
|
-
*
|
|
36
|
-
* stable as the
|
|
37
|
-
* container narrows.
|
|
56
|
+
* S1 · TopBar — the persistent shell chrome band, generic over the app. Brand
|
|
57
|
+
* (left) + a `trailing` cluster of app-supplied chrome and the wall clock (clock
|
|
58
|
+
* edge-pinned so spacing stays stable as the items' text changes). Collapses
|
|
59
|
+
* subtitle then clock as its container narrows.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* <TopBar brand="brain" trailing={[<IndexStatus />, <SearchScope />]} />
|
|
38
63
|
*/
|
|
39
64
|
export function TopBar({
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
time,
|
|
43
|
-
subtitle = 'wall dashboard',
|
|
65
|
+
brand = 'voltras',
|
|
66
|
+
subtitle,
|
|
44
67
|
showSubtitle,
|
|
68
|
+
leading,
|
|
69
|
+
trailing,
|
|
70
|
+
time,
|
|
45
71
|
showClock,
|
|
46
|
-
onSelectDevice,
|
|
47
72
|
className,
|
|
48
73
|
}: TopBarProps) {
|
|
49
74
|
const [width, setWidth] = useState(SUBTITLE_MIN)
|
|
@@ -52,6 +77,18 @@ export function TopBar({
|
|
|
52
77
|
const subtitleVisible = showSubtitle ?? width >= SUBTITLE_MIN
|
|
53
78
|
const clockVisible = showClock ?? width >= CLOCK_MIN
|
|
54
79
|
|
|
80
|
+
const clock = clockVisible ? (
|
|
81
|
+
<DateTime
|
|
82
|
+
value={time}
|
|
83
|
+
live={time == null}
|
|
84
|
+
format="time"
|
|
85
|
+
hour12={false}
|
|
86
|
+
variant="mono"
|
|
87
|
+
color="secondary"
|
|
88
|
+
className="text-[11px] min-w-[38px] text-right"
|
|
89
|
+
/>
|
|
90
|
+
) : null
|
|
91
|
+
|
|
55
92
|
return (
|
|
56
93
|
<View
|
|
57
94
|
onLayout={onLayout}
|
|
@@ -62,27 +99,11 @@ export function TopBar({
|
|
|
62
99
|
className
|
|
63
100
|
)}
|
|
64
101
|
>
|
|
65
|
-
<BrandLockup subtitle={subtitle} showSubtitle={subtitleVisible} />
|
|
102
|
+
{leading ?? <BrandLockup brand={brand} subtitle={subtitle} showSubtitle={subtitleVisible} />}
|
|
66
103
|
|
|
67
|
-
{/* right cluster —
|
|
104
|
+
{/* right cluster — app chrome then the clock, pinned to the edge */}
|
|
68
105
|
<View className="ml-auto flex-row items-center gap-[12px]">
|
|
69
|
-
|
|
70
|
-
<Divider orientation="vertical" className="h-4 bg-border-prominent" />
|
|
71
|
-
<DeviceMenu devices={devices} onSelectDevice={onSelectDevice} />
|
|
72
|
-
{clockVisible ? (
|
|
73
|
-
<>
|
|
74
|
-
<Divider orientation="vertical" className="h-4 bg-border-prominent" />
|
|
75
|
-
<DateTime
|
|
76
|
-
value={time}
|
|
77
|
-
live={time == null}
|
|
78
|
-
format="time"
|
|
79
|
-
hour12={false}
|
|
80
|
-
variant="mono"
|
|
81
|
-
color="secondary"
|
|
82
|
-
className="text-[11px] min-w-[38px] text-right"
|
|
83
|
-
/>
|
|
84
|
-
</>
|
|
85
|
-
) : null}
|
|
106
|
+
{dividedCluster([...(Array.isArray(trailing) ? trailing : [trailing]), clock])}
|
|
86
107
|
</View>
|
|
87
108
|
</View>
|
|
88
109
|
)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
import { BotIcon, BrainIcon, HeadphonesIcon, KanbanIcon, VoltrasMark } from '../icons'
|
|
3
|
+
|
|
4
|
+
/** The apps that are expected to mount this shell. */
|
|
5
|
+
export type BrandKey = 'voltras' | 'audiobook' | 'active-work' | 'agents' | 'brain'
|
|
6
|
+
|
|
7
|
+
export interface BrandPreset {
|
|
8
|
+
/** The mark glyph, rendered at 14px through the accent token via `currentColor`. */
|
|
9
|
+
mark: ReactNode
|
|
10
|
+
/** Uppercase product wordmark. */
|
|
11
|
+
wordmark: string
|
|
12
|
+
/** Semantic text token that colours the mark. */
|
|
13
|
+
accentClassName: string
|
|
14
|
+
/**
|
|
15
|
+
* The same accent as a background token, for the nav's active bar. Declared as
|
|
16
|
+
* a literal alongside its `text-*` twin because Tailwind only emits classes it
|
|
17
|
+
* can see in the source — a name built at runtime is never generated.
|
|
18
|
+
*/
|
|
19
|
+
accentBarClassName: string
|
|
20
|
+
/** Default "/ subtitle" for that app's shell. */
|
|
21
|
+
subtitle: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Accents come from `data-*` rather than `status-*`: `data-*` is the library's
|
|
25
|
+
// palette of N distinct, CVD-checked hues with no semantic load, which is exactly
|
|
26
|
+
// what a per-app identity accent needs. Voltras keeps the real brand token.
|
|
27
|
+
export const brandPresets: Record<BrandKey, BrandPreset> = {
|
|
28
|
+
voltras: {
|
|
29
|
+
mark: <VoltrasMark size={14} color="currentColor" />,
|
|
30
|
+
wordmark: 'VOLTRAS',
|
|
31
|
+
accentClassName: 'text-brand-primary',
|
|
32
|
+
accentBarClassName: 'bg-brand-primary',
|
|
33
|
+
subtitle: 'wall dashboard',
|
|
34
|
+
},
|
|
35
|
+
audiobook: {
|
|
36
|
+
mark: <HeadphonesIcon size={14} color="currentColor" />,
|
|
37
|
+
wordmark: 'AUDIOBOOK',
|
|
38
|
+
accentClassName: 'text-data-5',
|
|
39
|
+
accentBarClassName: 'bg-data-5',
|
|
40
|
+
subtitle: 'library',
|
|
41
|
+
},
|
|
42
|
+
'active-work': {
|
|
43
|
+
mark: <KanbanIcon size={14} color="currentColor" />,
|
|
44
|
+
wordmark: 'ACTIVE WORK',
|
|
45
|
+
accentClassName: 'text-data-1',
|
|
46
|
+
accentBarClassName: 'bg-data-1',
|
|
47
|
+
subtitle: 'initiatives',
|
|
48
|
+
},
|
|
49
|
+
agents: {
|
|
50
|
+
mark: <BotIcon size={14} color="currentColor" />,
|
|
51
|
+
wordmark: 'AGENTS',
|
|
52
|
+
accentClassName: 'text-data-2',
|
|
53
|
+
accentBarClassName: 'bg-data-2',
|
|
54
|
+
subtitle: 'fleet',
|
|
55
|
+
},
|
|
56
|
+
brain: {
|
|
57
|
+
mark: <BrainIcon size={14} color="currentColor" />,
|
|
58
|
+
wordmark: 'BRAIN',
|
|
59
|
+
accentClassName: 'text-data-3',
|
|
60
|
+
accentBarClassName: 'bg-data-3',
|
|
61
|
+
subtitle: 'knowledge',
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Every brand key, in the order the stories present them. */
|
|
66
|
+
export const brandKeys = Object.keys(brandPresets) as BrandKey[]
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
// Shell chrome — persistent
|
|
2
|
-
//
|
|
1
|
+
// Shell chrome — the GENERIC persistent app frame (nav / top bar / brand).
|
|
2
|
+
// App-specific chrome composes this family; it never leaks back into it.
|
|
3
|
+
// (Icons live in the shared `components/icons` primitive.)
|
|
4
|
+
export * from './brands'
|
|
3
5
|
export * from './BrandLockup'
|
|
4
|
-
|
|
5
|
-
export * from './DeviceIndicator'
|
|
6
|
-
export * from './DeviceRow'
|
|
7
|
-
export * from './DeviceMenu'
|
|
6
|
+
// S1 · Top bar family.
|
|
8
7
|
export * from './TopBar'
|
|
9
8
|
// S2 · Side nav family.
|
|
10
9
|
export * from './NavItem'
|
|
11
10
|
export * from './SideNav'
|
|
12
|
-
// S3 ·
|
|
13
|
-
export * from './
|
|
11
|
+
// S3 · App shell — composes the nav + top-bar chrome over a content slot.
|
|
12
|
+
export * from './AppShell'
|
|
13
|
+
// AW-132 · Workout-app shell, composed over the generic family above.
|
|
14
|
+
export * from './workout'
|
package/src/components/shell/{DeviceIndicator.stories.tsx → workout/DeviceIndicator.stories.tsx}
RENAMED
|
@@ -2,9 +2,9 @@ import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
|
2
2
|
import { DeviceIndicator } from './DeviceIndicator'
|
|
3
3
|
|
|
4
4
|
const meta: Meta<typeof DeviceIndicator> = {
|
|
5
|
-
title: 'Shell/DeviceIndicator',
|
|
5
|
+
title: 'Shell/Workout/DeviceIndicator',
|
|
6
6
|
component: DeviceIndicator,
|
|
7
|
-
tags: ['autodocs'],
|
|
7
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
8
8
|
args: { status: 'connected' },
|
|
9
9
|
argTypes: {
|
|
10
10
|
status: { control: 'select', options: ['connected', 'degraded', 'lost'] },
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { View, Pressable, type ViewProps } from 'react-native'
|
|
2
|
-
import { cn } from '
|
|
3
|
-
import { BluetoothIcon } from '
|
|
2
|
+
import { cn } from '../../../utils/cn'
|
|
3
|
+
import { BluetoothIcon } from '../../icons'
|
|
4
4
|
|
|
5
5
|
export type DeviceConnState = 'connected' | 'degraded' | 'lost'
|
|
6
6
|
|
|
@@ -10,9 +10,9 @@ const DEVICES: Device[] = [
|
|
|
10
10
|
]
|
|
11
11
|
|
|
12
12
|
const meta: Meta<typeof DeviceMenu> = {
|
|
13
|
-
title: 'Shell/DeviceMenu',
|
|
13
|
+
title: 'Shell/Workout/DeviceMenu',
|
|
14
14
|
component: DeviceMenu,
|
|
15
|
-
tags: ['autodocs'],
|
|
15
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
16
16
|
args: { devices: DEVICES, isOpen: false },
|
|
17
17
|
argTypes: {
|
|
18
18
|
devices: { control: 'object' },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { View } from 'react-native'
|
|
2
|
-
import { cn } from '
|
|
3
|
-
import { Typography } from '
|
|
4
|
-
import { Popover, PopoverTrigger, PopoverContent } from '
|
|
2
|
+
import { cn } from '../../../utils/cn'
|
|
3
|
+
import { Typography } from '../../custom/Typography'
|
|
4
|
+
import { Popover, PopoverTrigger, PopoverContent } from '../../ui/popover'
|
|
5
5
|
import { DeviceIndicator, type DeviceConnState } from './DeviceIndicator'
|
|
6
6
|
import { DeviceRow, type Device } from './DeviceRow'
|
|
7
7
|
|
|
@@ -3,9 +3,9 @@ import { View } from 'react-native'
|
|
|
3
3
|
import { DeviceRow } from './DeviceRow'
|
|
4
4
|
|
|
5
5
|
const meta: Meta<typeof DeviceRow> = {
|
|
6
|
-
title: 'Shell/DeviceRow',
|
|
6
|
+
title: 'Shell/Workout/DeviceRow',
|
|
7
7
|
component: DeviceRow,
|
|
8
|
-
tags: ['autodocs'],
|
|
8
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
9
9
|
args: {
|
|
10
10
|
device: { id: 'Voltra-A3F2', nickname: 'Left Cable', slot: 'L', state: 'connected' },
|
|
11
11
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { View, Pressable, type ViewProps } from 'react-native'
|
|
2
|
-
import { cn } from '
|
|
3
|
-
import { Indicator, type IndicatorColor } from '
|
|
4
|
-
import { Typography } from '
|
|
2
|
+
import { cn } from '../../../utils/cn'
|
|
3
|
+
import { Indicator, type IndicatorColor } from '../../ui/indicator'
|
|
4
|
+
import { Typography } from '../../custom/Typography'
|
|
5
5
|
|
|
6
6
|
export type DeviceRowState = 'connected' | 'available' | 'degraded' | 'lost'
|
|
7
7
|
|
package/src/components/shell/{SessionStatePill.stories.tsx → workout/SessionStatePill.stories.tsx}
RENAMED
|
@@ -2,9 +2,9 @@ import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
|
2
2
|
import { SessionStatePill } from './SessionStatePill'
|
|
3
3
|
|
|
4
4
|
const meta: Meta<typeof SessionStatePill> = {
|
|
5
|
-
title: 'Shell/SessionStatePill',
|
|
5
|
+
title: 'Shell/Workout/SessionStatePill',
|
|
6
6
|
component: SessionStatePill,
|
|
7
|
-
tags: ['autodocs'],
|
|
7
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
8
8
|
args: { state: 'live' },
|
|
9
9
|
argTypes: {
|
|
10
10
|
state: { control: 'select', options: ['live', 'rest', 'idle'] },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { View, type ViewProps } from 'react-native'
|
|
2
|
-
import { cn } from '
|
|
3
|
-
import { Indicator, type IndicatorColor, type IndicatorPulse } from '
|
|
4
|
-
import { Typography, type TypographyColor } from '
|
|
2
|
+
import { cn } from '../../../utils/cn'
|
|
3
|
+
import { Indicator, type IndicatorColor, type IndicatorPulse } from '../../ui/indicator'
|
|
4
|
+
import { Typography, type TypographyColor } from '../../custom/Typography'
|
|
5
5
|
|
|
6
6
|
export type SessionState = 'live' | 'rest' | 'idle'
|
|
7
7
|
|
|
@@ -32,6 +32,8 @@ const stateConfig: Record<
|
|
|
32
32
|
* The global session-state readout (dot + label). Shared: the top bar's status
|
|
33
33
|
* and the Live-view header both use it (this is the ledger's "StatusPill",
|
|
34
34
|
* Family C — built once). S1 · SessionStatePill.
|
|
35
|
+
*
|
|
36
|
+
* @deprecated Use `<Pill tone="…" leading="dot">` — removed after AW-127 consumer migration.
|
|
35
37
|
*/
|
|
36
38
|
export function SessionStatePill({ state, label, className, ...props }: SessionStatePillProps) {
|
|
37
39
|
const cfg = stateConfig[state]
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
import { View } from 'react-native'
|
|
3
|
+
import { WorkoutShell } from './WorkoutShell'
|
|
4
|
+
import { Surface } from '../../ui/surface'
|
|
5
|
+
import { Typography } from '../../custom/Typography'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* `Pages/WorkoutShell` — the workout wall-dashboard chrome as one registered surface.
|
|
9
|
+
* Composes the generic AppShell and fills its slots with the workout's own chrome, so
|
|
10
|
+
* the dashboard app mounts a single component.
|
|
11
|
+
*/
|
|
12
|
+
const meta: Meta<typeof WorkoutShell> = {
|
|
13
|
+
title: 'Pages/WorkoutShell',
|
|
14
|
+
component: WorkoutShell,
|
|
15
|
+
tags: ['autodocs', 'status:candidate', '!status:review'],
|
|
16
|
+
parameters: {
|
|
17
|
+
layout: 'fullscreen',
|
|
18
|
+
docs: {
|
|
19
|
+
description: {
|
|
20
|
+
component:
|
|
21
|
+
'**Page shell (workout app).** Composes ' +
|
|
22
|
+
'[AppShell](?path=/docs/pages-appshell--docs) and fills its top-bar slot with ' +
|
|
23
|
+
'[WorkoutTopBar](?path=/docs/shell-workout-workouttopbar--docs) — which pulls in ' +
|
|
24
|
+
'DeviceMenu, DeviceRow, DeviceIndicator and SessionStatePill — and its nav slot with ' +
|
|
25
|
+
'the four workout categories. Mount this instead of re-assembling the chrome per ' +
|
|
26
|
+
'view.\n\nThis is the AW-132 shape: the generic shell knows nothing about devices or ' +
|
|
27
|
+
'session state; this component is the whole workout-specific surface.',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
argTypes: {
|
|
32
|
+
state: { control: 'select', options: ['live', 'rest', 'idle'] },
|
|
33
|
+
activeKey: { control: 'select', options: ['live', 'review', 'program', 'body'] },
|
|
34
|
+
liveKey: { control: 'select', options: [null, 'live', 'review', 'program', 'body'] },
|
|
35
|
+
onNavigate: { control: false },
|
|
36
|
+
onSelectDevice: { control: false },
|
|
37
|
+
},
|
|
38
|
+
decorators: [
|
|
39
|
+
(Story) => (
|
|
40
|
+
<Surface level="base" style={{ height: '100vh' as unknown as number }}>
|
|
41
|
+
<Story />
|
|
42
|
+
</Surface>
|
|
43
|
+
),
|
|
44
|
+
],
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default meta
|
|
48
|
+
type Story = StoryObj<typeof WorkoutShell>
|
|
49
|
+
|
|
50
|
+
export const Default: Story = {
|
|
51
|
+
args: { activeKey: 'live', state: 'live' },
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const WithContent: Story = {
|
|
55
|
+
args: { activeKey: 'review', state: 'rest', liveKey: 'live' },
|
|
56
|
+
render: (args) => (
|
|
57
|
+
<WorkoutShell {...args}>
|
|
58
|
+
<View className="flex-1 gap-1.5 p-7">
|
|
59
|
+
<Typography variant="h4" color="primary">
|
|
60
|
+
Review
|
|
61
|
+
</Typography>
|
|
62
|
+
<Typography variant="body2" color="tertiary">
|
|
63
|
+
A page mounts its content here; the shell keeps the nav + top-bar chrome persistent.
|
|
64
|
+
</Typography>
|
|
65
|
+
</View>
|
|
66
|
+
</WorkoutShell>
|
|
67
|
+
),
|
|
68
|
+
parameters: {
|
|
69
|
+
docs: { description: { story: 'The shell with a page mounted in its content slot.' } },
|
|
70
|
+
},
|
|
71
|
+
}
|