ae51276a03
Web console - Pairing/Library/Stats refactored into self-contained subsections that each own their own queries + mutations; a shared slot-based layout (view.tsx) is filled by the live page (containers) and Storybook (pure cards + fixtures) so the layout can't drift. - All paired devices in one list on Pairing with a protocol column (punktfunk/1 + Moonlight), routing each unpair to the right endpoint; the redundant Clients page is removed. - Library: overview grid split from the add/edit form into separate files. - Login screen links out to the docs. Docs - "Console login password" section on every host page (apt/RPM/Bazzite/SteamOS/Windows) plus a new "Forgot your Password?" troubleshooting page, linked from the login screen. - Console served as HTTP/1.1 over TLS (drop the unusable HTTP/3 advertising) across the Bun entry, launchers, systemd units, and packaging. Tooling - Biome now respects .gitignore (stops linting generated code), config migrated to 2.5.1; all lint issues fixed cleanly. Also includes this branch's in-progress host, Apple client, packaging, and CI changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
72 lines
2.1 KiB
TypeScript
72 lines
2.1 KiB
TypeScript
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
import {
|
|
createMemoryHistory,
|
|
createRootRoute,
|
|
createRoute,
|
|
createRouter,
|
|
RouterProvider,
|
|
} from "@tanstack/react-router";
|
|
import { AppShell } from "@/components/app-shell";
|
|
|
|
// AppShell is built from TanStack Router <Link>s, so it needs a router context.
|
|
// We stand up a throwaway in-memory router whose routes mirror the nav targets
|
|
// (so links resolve + the active highlight works) and render the shell from the
|
|
// root route. No loaders/data — purely for designing the chrome offline.
|
|
function ShellHarness({ initialPath }: { initialPath: string }) {
|
|
const rootRoute = createRootRoute({
|
|
component: () => (
|
|
<AppShell>
|
|
<div className="space-y-3">
|
|
<h1 className="text-2xl font-semibold tracking-tight">Dashboard</h1>
|
|
<p className="text-muted-foreground">
|
|
Placeholder content — swap routes from the sidebar to preview the
|
|
active state.
|
|
</p>
|
|
</div>
|
|
</AppShell>
|
|
),
|
|
});
|
|
|
|
const navPaths = ["/", "/host", "/library", "/pairing", "/settings"];
|
|
const navRoutes = navPaths.map((path) =>
|
|
createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
path,
|
|
component: () => null,
|
|
}),
|
|
);
|
|
// Splat so any other <Link> target still resolves without throwing.
|
|
const splat = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
path: "$",
|
|
component: () => null,
|
|
});
|
|
|
|
const router = createRouter({
|
|
routeTree: rootRoute.addChildren([...navRoutes, splat]),
|
|
history: createMemoryHistory({ initialEntries: [initialPath] }),
|
|
});
|
|
|
|
return <RouterProvider router={router} />;
|
|
}
|
|
|
|
const meta = {
|
|
title: "Shell/AppShell",
|
|
component: AppShell,
|
|
parameters: { layout: "fullscreen" },
|
|
// AppShell requires `children`; the harness supplies the real content, so this
|
|
// placeholder just satisfies the arg type.
|
|
args: { children: null },
|
|
} satisfies Meta<typeof AppShell>;
|
|
|
|
export default meta;
|
|
type Story = StoryObj<typeof meta>;
|
|
|
|
export const Dashboard: Story = {
|
|
render: () => <ShellHarness initialPath="/" />,
|
|
};
|
|
|
|
export const HostActive: Story = {
|
|
render: () => <ShellHarness initialPath="/host" />,
|
|
};
|