import { lazy } from "react" import { createRootRoute, createRoute, createRouter, redirect, useNavigate, } from "@tanstack/react-router" import { Shell } from "@/App" import { NAV } from "@/nav" import { RouteFehler } from "@/components/RouteFehler" import { CockpitView } from "@/views/cockpit/CockpitView" // Routenbaum (v3-Umbau P2). // // Bewusst code-based statt dateibasiert: Es sind zwölf Routen, und sie stehen dadurch // alle an EINER Stelle — inklusive dem, was in den Suchparametern erlaubt ist. Eine // Datei-Konvention würde diese Übersicht auf zwölf Dateien verteilen, ohne dass jemand // etwas davon hätte. // // Code-Splitting bleibt exakt wie bisher: die Views hängen an React.lazy, das Cockpit als // Startseite lädt eifrig. Kein Chunk verschiebt sich durch den Router. const ModelsView = lazy(() => import("@/views/ModelsView").then((m) => ({ default: m.ModelsView }))) const ConnectView = lazy(() => import("@/views/ConnectView").then((m) => ({ default: m.ConnectView }))) const AgentView = lazy(() => import("@/views/AgentView").then((m) => ({ default: m.AgentView }))) const KonsoleView = lazy(() => import("@/views/KonsoleView").then((m) => ({ default: m.KonsoleView }))) const GuideView = lazy(() => import("@/views/GuideView").then((m) => ({ default: m.GuideView }))) const IdeenView = lazy(() => import("@/features/ideen/IdeenAnsicht").then((m) => ({ default: m.IdeenView }))) const SkillsView = lazy(() => import("@/views/SkillsView").then((m) => ({ default: m.SkillsView }))) const ChronikView = lazy(() => import("@/views/ChronikView").then((m) => ({ default: m.ChronikView }))) const WissenView = lazy(() => import("@/views/WissenView").then((m) => ({ default: m.WissenView }))) // ── Suchparameter ─────────────────────────────────────────────────────────── // Regel für das, was hier steht: Alles, was ein Kollege per Link teilen können soll und // was einen Reload überleben muss. Nichts Flüchtiges (Hover, Entwürfe im Eingabefeld). /** Wurzel: die System-Schublade. Gehört hierher, weil sie über JEDER Ansicht liegt. */ export interface WurzelSuche { system?: "wartung" | "logs" } const wurzelSuche = (roh: Record): WurzelSuche => { const s = roh.system return s === "wartung" || s === "logs" ? { system: s } : {} } export const rootRoute = createRootRoute({ component: Shell, validateSearch: wurzelSuche, notFoundComponent: () => ( ), }) // Wurzelpfad → Cockpit. `redirect` statt einer Kopie der Startseite: sonst gäbe es // zwei URLs für denselben Inhalt und die aktive Markierung in der Sidebar flackert. const indexRoute = createRoute({ getParentRoute: () => rootRoute, path: "/", beforeLoad: () => { throw redirect({ to: "/cockpit" }) }, }) /** Eine Route je Ansicht — kurze Schreibweise, weil sich nur Pfad und Bauteil ändern. * Generisch über den Pfad, damit TanStack Router den Literal-Typ behält: mit * `path: string` verlöre `navigate({ to: "/cockpit" })` seine Typprüfung. */ function ansicht

(path: P, component: () => React.ReactNode) { return createRoute({ getParentRoute: () => rootRoute, path, component, // Fehlergrenze PRO Route (Befund B-13): Vorher hing eine einzige Grenze in main.tsx // um die ganze App — ein Renderfehler in den Modellen nahm Cockpit, Konsole und // Chronik mit. Jetzt bleiben Schiene, Kopfzeile und Statusanzeige stehen. errorComponent: ({ error, reset }) => ( ), }) } // Das Cockpit verlinkt in andere Bereiche und bekam den Sprung bisher als Prop von der // App gereicht. Jetzt kommt er aus dem Router — die Ansicht selbst bleibt unverändert. function CockpitSeite() { const navigate = useNavigate() return { const ziel = NAV.find((n) => n.id === v) if (ziel) navigate({ to: ziel.pfad }) }} /> } const cockpitRoute = ansicht("/cockpit", () => ) const skillsRoute = ansicht("/skills", () => ) /** Chronik: `?q=` filtert den Verlauf — Ziel der „Finden"-Einträge der Palette (P6). */ export interface ChronikSuche { q?: string } const chronikRoute = createRoute({ getParentRoute: () => rootRoute, path: "/chronik", validateSearch: (roh: Record): ChronikSuche => typeof roh.q === "string" && roh.q ? { q: roh.q } : {}, component: () => , errorComponent: ({ error, reset }) => ( ), }) const verbindenRoute = ansicht("/verbinden", () => ) const konsoleRoute = ansicht("/konsole", () => ) const anleitungRoute = ansicht("/anleitung", () => ) const agentRoute = ansicht("/agent", () => ) /** Ideen: `?offen=` hält die aufgeklappte Karte fest (Befund B-05). * Vorher lag das in `useState` — wer während eines laufenden Workers neu lud, * verlor seinen Platz in der Liste. */ export interface IdeenSuche { offen?: string } const ideenRoute = createRoute({ getParentRoute: () => rootRoute, path: "/ideen", validateSearch: (roh: Record): IdeenSuche => typeof roh.offen === "string" && roh.offen ? { offen: roh.offen } : {}, component: () => , errorComponent: ({ error, reset }) => ( ), }) /** Wissen: `?datei=` macht jede Notiz verlinkbar, `?suche=` trägt das Suchwort * aus der Befehlspalette herein (P6). */ export interface WissenSuche { datei?: string suche?: string } const wissenRoute = createRoute({ getParentRoute: () => rootRoute, path: "/wissen", validateSearch: (roh: Record): WissenSuche => ({ ...(typeof roh.datei === "string" && roh.datei ? { datei: roh.datei } : {}), ...(typeof roh.suche === "string" && roh.suche ? { suche: roh.suche } : {}), }), component: () => , errorComponent: ({ error, reset }) => ( ), }) /** Modelle: `?reiter=` — der Reiter war lokaler State und damit nicht teilbar. */ export type ModellReiter = "werkbank" | "routing" | "discover" export interface ModelleSuche { reiter?: ModellReiter } const modelleRoute = createRoute({ getParentRoute: () => rootRoute, path: "/modelle", validateSearch: (roh: Record): ModelleSuche => { const r = roh.reiter return r === "werkbank" || r === "routing" || r === "discover" ? { reiter: r } : {} }, component: () => , errorComponent: ({ error, reset }) => ( ), }) export const routeTree = rootRoute.addChildren([ indexRoute, cockpitRoute, ideenRoute, skillsRoute, chronikRoute, wissenRoute, verbindenRoute, konsoleRoute, anleitungRoute, modelleRoute, agentRoute, ]) export const router = createRouter({ routeTree, // Ein LAN-Gerät: der Verlauf muss nicht scrollen-restaurieren, aber die Position // oben zu haben ist beim Ansichtswechsel richtig. scrollRestoration: true, defaultPreload: false, }) declare module "@tanstack/react-router" { interface Register { router: typeof router } }