feat(topics): add the Topics preview area, its navigation entry and its switch

/topics shows a tile per topic the record holds data for, and names the
empty topics and the module-hidden ones once each. /topics/<topic>
shows the topic today, its signals side by side over 7, 30, 90 days or
a year against their usual range, how they move together, their trends,
its blocks, the single-metric pages behind it and what it is missing.
Every topic links into the metric pages, which stay as they are, and
each page ends on a neutral note that this is a preview.

Settings > System > Preview features is listed again and switches the
area on for the person reading. While it is on, the sidebar carries a
Topics entry with a Beta badge directly below Insights and the phone's
More sheet leads with a Topics tile; the bottom bar does not change.
The pages leave for Insights when the switch is off.

The charts load through the shared chart runtime. The sidebar rows move
into their own module and the More sheet tile into its own component,
so neither shell file grows; the lab trend wording is shared between the
marker page and the metabolism topic. Copy in all nine locales.
This commit is contained in:
Marc-André Bombeck committed 2026-10-23 08:18:53 +02:00
1 parent cc04e0944d
commit c68e833dcc
64 files changed
+4319 -219

No files matched your search

@@ -1,7 +1,7 @@
{
"$comment": "Production files over 800 lines and their length. Maintained by src/__tests__/source-size-ratchet.test.ts.",
"count": 123,
"total": 145428,
"count": 122,
"total": 144573,
"entries": {
"app/api/dashboard/summary/route.ts": 1032,
"app/api/documents/inbound/route.ts": 811,
@@ -25,7 +25,6 @@
"components/insights/derived/vitals-dashboard.tsx": 1033,
"components/insights/health-score-card.tsx": 1023,
"components/insights/insights-tab-strip.tsx": 1086,
"components/layout/sidebar-nav.tsx": 855,
"components/measurement-reminders/vorsorge-section.tsx": 1536,
"components/measurements/measurement-form.tsx": 815,
"components/measurements/measurement-list.tsx": 2019,
@@ -1,7 +1,7 @@
{
"$comment": "Production functions over 200 lines, keyed \"file :: name\", and their length. Maintained by src/__tests__/source-size-ratchet.test.ts.",
"count": 411,
"total": 148109,
"total": 148044,
"entries": {
"app/achievements/page.tsx :: AchievementsPage": 206,
"app/api/admin/backups/upload/route.ts :: apiHandler(arg)": 314,
@@ -9,7 +9,7 @@
"app/api/admin/settings/route.ts :: apiHandler(arg) #2": 217,
"app/api/analytics/route.ts :: buildAnalyticsResponse": 446,
"app/api/auth/login/route.ts :: apiHandler(arg)": 262,
"app/api/auth/me/route.ts :: apiHandler(arg)": 386,
"app/api/auth/me/route.ts :: apiHandler(arg)": 384,
"app/api/auth/oidc/callback/route.ts :: apiHandler(arg)": 499,
"app/api/auth/register/route.ts :: apiHandler(arg)": 275,
"app/api/coach/about-me/route.ts :: apiHandler(arg) #2": 309,
@@ -173,9 +173,9 @@
"components/labs/ocr-review-dialog.tsx :: OcrReviewDialog": 359,
"components/labs/ocr-row-editor.tsx :: OcrRowEditor": 393,
"components/layout/auth-shell.tsx :: AuthShell": 520,
"components/layout/bottom-nav.tsx :: BottomNav": 262,
"components/layout/bottom-nav.tsx :: BottomNav": 229,
"components/layout/capture-picker.tsx :: CapturePicker": 235,
"components/layout/sidebar-nav.tsx :: SidebarNav": 372,
"components/layout/sidebar-nav.tsx :: SidebarNav": 342,
"components/layout/top-bar.tsx :: TopBar": 212,
"components/links/entity-link-picker.tsx :: EntityLinkPicker": 392,
"components/measurement-reminders/vorsorge-dashboard-card.tsx :: VorsorgeDashboardCard": 215,
+2 -3
View File
@@ -1,7 +1,7 @@
{
"$comment": "as never casts in tests, per test file under src/. Maintained by src/__tests__/test-realism-ratchet.test.ts.",
"count": 524,
"total": 5495,
"count": 523,
"total": 5494,
"entries": {
"__tests__/api/auth/login/mfa-branch.test.ts": 10,
"__tests__/api/auth/mfa/verify.test.ts": 9,
@@ -273,7 +273,6 @@
"components/medications/__tests__/use-medication-intake.test.ts": 1,
"components/medications/detail/efficacy/__tests__/change-at-start-summary.test.tsx": 1,
"components/mood/__tests__/mood-list-url-sync.test.tsx": 1,
"components/settings/__tests__/settings-shell.test.tsx": 1,
"components/settings/integrations/__tests__/dawarich-card.test.tsx": 1,
"components/timeline/__tests__/medication-rows.test.ts": 1,
"lib/__tests__/acting-account-resolver.test.ts": 5,
@@ -1,7 +1,7 @@
{
"$comment": "Comment lines that open with a release version, per file under src/. Maintained by src/__tests__/version-stamp-ratchet.test.ts.",
"count": 2954,
"total": 10500,
"total": 10499,
"entries": {
"__tests__/account-payload-consumer-guard.test.ts": 2,
"__tests__/acting-account-boundary-guard.test.ts": 7,
@@ -2807,7 +2807,7 @@
"lib/rollups/mood-rollups.ts": 4,
"lib/rollups/tiered-context.ts": 6,
"lib/score-config/rows.ts": 1,
"lib/settings/section-slugs.ts": 20,
"lib/settings/section-slugs.ts": 19,
"lib/sharing/__tests__/account-access-parse.test.ts": 3,
"lib/sharing/__tests__/account-access.test.ts": 2,
"lib/sharing/__tests__/account-label.test.ts": 1,
+3 -2
View File
@@ -3,8 +3,9 @@
*
* The workout-route switch is off for new accounts, which is what its detail
* says rather than "off by default": an account that already held tracks at
* the upgrade started with it on (migration 0434). (The Topics preview switch
* this file also held is unlisted until its pages ship, and its copy with it.)
* the upgrade started with it on (migration 0434). The Topics preview switch
* this file also held describes pages that now exist, so its copy is in the
* present tense like every other switch.
*/
import { describe, expect, it } from "vitest";
@@ -54,6 +54,8 @@ const HISTORICAL_SETTINGS_PATHS: readonly string[] = [
"/settings/export",
"/settings/advanced",
"/settings/privacy",
// Preview features (Settings > System).
"/settings/preview",
"/settings/about",
// The per-module personalisation slugs before the layout hub.
"/settings/dashboard",