diff --git a/.storybook/main.ts b/packages/ui/.storybook/main.ts similarity index 83% rename from .storybook/main.ts rename to packages/ui/.storybook/main.ts index cfd3a61..34237be 100644 --- a/.storybook/main.ts +++ b/packages/ui/.storybook/main.ts @@ -2,7 +2,6 @@ import type { StorybookConfig } from "@storybook/react-vite"; const config: StorybookConfig = { stories: ["../src/**/*.stories.@(js|ts|tsx)"], - staticDirs: ["../static"], addons: [ "@storybook/addon-a11y", "@storybook/addon-vitest", @@ -11,9 +10,6 @@ const config: StorybookConfig = { name: "@storybook/react-vite", options: {}, }, - docs: { - autodocs: "tag", - }, }; export default config; diff --git a/.storybook/preview.ts b/packages/ui/.storybook/preview.ts similarity index 63% rename from .storybook/preview.ts rename to packages/ui/.storybook/preview.ts index 964f47b..87df132 100644 --- a/.storybook/preview.ts +++ b/packages/ui/.storybook/preview.ts @@ -1,17 +1,5 @@ -import "../src/app.css"; +import "../src/styles.css"; import type { Preview } from "@storybook/react-vite"; -import { setupWorker } from "msw/browser"; -import { externalApiHandlers } from "../src/lib/testing/external-api-mocks"; - -if (typeof window !== "undefined") { - const worker = setupWorker(...externalApiHandlers); - void worker.start({ - onUnhandledRequest: "bypass", - serviceWorker: { - url: "/mockServiceWorker.js", - }, - }); -} const preview: Preview = { decorators: [ @@ -44,10 +32,10 @@ const preview: Preview = { backgrounds: { default: "canvas", values: [ - { name: "canvas", value: "#020302" }, - { name: "raised", value: "#0b0d0c" }, - { name: "light canvas", value: "#f3f5ed" }, - { name: "light raised", value: "#eef1e7" }, + { name: "canvas", value: "#0b0f0d" }, + { name: "raised", value: "#151d18" }, + { name: "light canvas", value: "#eef2e7" }, + { name: "light raised", value: "#f1f5ea" }, ], }, controls: { diff --git a/src/lib/ui/components/Badge.tsx b/packages/ui/src/components/Badge.tsx similarity index 100% rename from src/lib/ui/components/Badge.tsx rename to packages/ui/src/components/Badge.tsx diff --git a/src/lib/ui/components/Button.tsx b/packages/ui/src/components/Button.tsx similarity index 100% rename from src/lib/ui/components/Button.tsx rename to packages/ui/src/components/Button.tsx diff --git a/src/lib/ui/components/CornerBracketFrame.tsx b/packages/ui/src/components/CornerBracketFrame.tsx similarity index 100% rename from src/lib/ui/components/CornerBracketFrame.tsx rename to packages/ui/src/components/CornerBracketFrame.tsx diff --git a/src/lib/ui/components/DashboardFrame.tsx b/packages/ui/src/components/DashboardFrame.tsx similarity index 100% rename from src/lib/ui/components/DashboardFrame.tsx rename to packages/ui/src/components/DashboardFrame.tsx diff --git a/src/lib/ui/components/DashboardHeader.tsx b/packages/ui/src/components/DashboardHeader.tsx similarity index 100% rename from src/lib/ui/components/DashboardHeader.tsx rename to packages/ui/src/components/DashboardHeader.tsx diff --git a/src/lib/ui/components/DiagonalStripeField.tsx b/packages/ui/src/components/DiagonalStripeField.tsx similarity index 100% rename from src/lib/ui/components/DiagonalStripeField.tsx rename to packages/ui/src/components/DiagonalStripeField.tsx diff --git a/src/lib/ui/components/FooterCell.tsx b/packages/ui/src/components/FooterCell.tsx similarity index 100% rename from src/lib/ui/components/FooterCell.tsx rename to packages/ui/src/components/FooterCell.tsx diff --git a/src/lib/ui/components/FooterStatusCell.tsx b/packages/ui/src/components/FooterStatusCell.tsx similarity index 100% rename from src/lib/ui/components/FooterStatusCell.tsx rename to packages/ui/src/components/FooterStatusCell.tsx diff --git a/src/lib/ui/components/GridFrame.tsx b/packages/ui/src/components/GridFrame.tsx similarity index 100% rename from src/lib/ui/components/GridFrame.tsx rename to packages/ui/src/components/GridFrame.tsx diff --git a/src/lib/ui/components/IconButton.tsx b/packages/ui/src/components/IconButton.tsx similarity index 100% rename from src/lib/ui/components/IconButton.tsx rename to packages/ui/src/components/IconButton.tsx diff --git a/src/lib/ui/components/IconGlyph.tsx b/packages/ui/src/components/IconGlyph.tsx similarity index 100% rename from src/lib/ui/components/IconGlyph.tsx rename to packages/ui/src/components/IconGlyph.tsx diff --git a/src/lib/ui/components/LineChart.tsx b/packages/ui/src/components/LineChart.tsx similarity index 100% rename from src/lib/ui/components/LineChart.tsx rename to packages/ui/src/components/LineChart.tsx diff --git a/src/lib/ui/components/ModuleCard.tsx b/packages/ui/src/components/ModuleCard.tsx similarity index 100% rename from src/lib/ui/components/ModuleCard.tsx rename to packages/ui/src/components/ModuleCard.tsx diff --git a/src/lib/ui/components/Panel.tsx b/packages/ui/src/components/Panel.tsx similarity index 100% rename from src/lib/ui/components/Panel.tsx rename to packages/ui/src/components/Panel.tsx diff --git a/src/lib/ui/components/ProgressMeter.tsx b/packages/ui/src/components/ProgressMeter.tsx similarity index 100% rename from src/lib/ui/components/ProgressMeter.tsx rename to packages/ui/src/components/ProgressMeter.tsx diff --git a/src/lib/ui/components/ScanlineField.tsx b/packages/ui/src/components/ScanlineField.tsx similarity index 100% rename from src/lib/ui/components/ScanlineField.tsx rename to packages/ui/src/components/ScanlineField.tsx diff --git a/src/lib/ui/components/Separator.tsx b/packages/ui/src/components/Separator.tsx similarity index 100% rename from src/lib/ui/components/Separator.tsx rename to packages/ui/src/components/Separator.tsx diff --git a/src/lib/ui/components/ServiceGroupPanel.tsx b/packages/ui/src/components/ServiceGroupPanel.tsx similarity index 100% rename from src/lib/ui/components/ServiceGroupPanel.tsx rename to packages/ui/src/components/ServiceGroupPanel.tsx diff --git a/src/lib/ui/components/ServicePanel.tsx b/packages/ui/src/components/ServicePanel.tsx similarity index 100% rename from src/lib/ui/components/ServicePanel.tsx rename to packages/ui/src/components/ServicePanel.tsx diff --git a/src/lib/ui/components/ServiceRow.tsx b/packages/ui/src/components/ServiceRow.tsx similarity index 100% rename from src/lib/ui/components/ServiceRow.tsx rename to packages/ui/src/components/ServiceRow.tsx diff --git a/src/lib/ui/components/SignalTrace.tsx b/packages/ui/src/components/SignalTrace.tsx similarity index 100% rename from src/lib/ui/components/SignalTrace.tsx rename to packages/ui/src/components/SignalTrace.tsx diff --git a/src/lib/ui/components/Sparkline.tsx b/packages/ui/src/components/Sparkline.tsx similarity index 100% rename from src/lib/ui/components/Sparkline.tsx rename to packages/ui/src/components/Sparkline.tsx diff --git a/src/lib/ui/components/StatusBadge.tsx b/packages/ui/src/components/StatusBadge.tsx similarity index 100% rename from src/lib/ui/components/StatusBadge.tsx rename to packages/ui/src/components/StatusBadge.tsx diff --git a/src/lib/ui/components/StatusStrip.tsx b/packages/ui/src/components/StatusStrip.tsx similarity index 100% rename from src/lib/ui/components/StatusStrip.tsx rename to packages/ui/src/components/StatusStrip.tsx diff --git a/src/lib/ui/components/SystemState.tsx b/packages/ui/src/components/SystemState.tsx similarity index 100% rename from src/lib/ui/components/SystemState.tsx rename to packages/ui/src/components/SystemState.tsx diff --git a/src/lib/ui/components/TelemetryCard.tsx b/packages/ui/src/components/TelemetryCard.tsx similarity index 100% rename from src/lib/ui/components/TelemetryCard.tsx rename to packages/ui/src/components/TelemetryCard.tsx diff --git a/src/lib/ui/components/TelemetryGrid.tsx b/packages/ui/src/components/TelemetryGrid.tsx similarity index 100% rename from src/lib/ui/components/TelemetryGrid.tsx rename to packages/ui/src/components/TelemetryGrid.tsx diff --git a/src/lib/ui/components/TelemetryStrip.tsx b/packages/ui/src/components/TelemetryStrip.tsx similarity index 100% rename from src/lib/ui/components/TelemetryStrip.tsx rename to packages/ui/src/components/TelemetryStrip.tsx diff --git a/src/lib/ui/components/ThemeToggle.tsx b/packages/ui/src/components/ThemeToggle.tsx similarity index 100% rename from src/lib/ui/components/ThemeToggle.tsx rename to packages/ui/src/components/ThemeToggle.tsx diff --git a/src/lib/ui/components/WeatherModule.tsx b/packages/ui/src/components/WeatherModule.tsx similarity index 100% rename from src/lib/ui/components/WeatherModule.tsx rename to packages/ui/src/components/WeatherModule.tsx diff --git a/src/lib/ui/components/render.test.tsx b/packages/ui/src/components/render.test.tsx similarity index 100% rename from src/lib/ui/components/render.test.tsx rename to packages/ui/src/components/render.test.tsx diff --git a/src/lib/ui/components/styles.css b/packages/ui/src/components/styles.css similarity index 100% rename from src/lib/ui/components/styles.css rename to packages/ui/src/components/styles.css diff --git a/packages/ui/src/content-boundary.test.ts b/packages/ui/src/content-boundary.test.ts new file mode 100644 index 0000000..80b85ce --- /dev/null +++ b/packages/ui/src/content-boundary.test.ts @@ -0,0 +1,74 @@ +import { existsSync, readdirSync, readFileSync, statSync } from "node:fs"; +import { join } from "node:path"; +import { describe, expect, test } from "vitest"; + +const root = process.cwd(); +const uiSourceRoot = existsSync(join(root, "packages/ui/src")) + ? join(root, "packages/ui/src") + : join(root, "src"); + +const forbiddenTerms = [ + "dimensionlab", + "dimension lab", + "vaultwarden", + "forgejo", + "grafana", + "uptime kuma", + "prometheus", + "backrest", + "open webui", + "comfyui", + "adminer", + "cockpit", + "ollama", +]; + +describe("UI package content boundary", () => { + test("contains the reusable dashboard component inventory", () => { + expect(existsSync(join(uiSourceRoot, "index.ts"))).toBe(true); + expect(existsSync(join(uiSourceRoot, "components/DashboardFrame.tsx"))).toBe( + true, + ); + expect(existsSync(join(uiSourceRoot, "components/ThemeToggle.tsx"))).toBe( + true, + ); + expect(existsSync(join(uiSourceRoot, "styles.css"))).toBe(true); + }); + + test("keeps environment-specific content out of reusable UI source", () => { + const source = readUiSource(uiSourceRoot).toLowerCase(); + + expect(forbiddenTerms.filter((term) => source.includes(term))).toEqual([]); + }); + + test("does not import website runtime modules", () => { + const source = readUiSource(uiSourceRoot); + + expect(source).not.toMatch( + /from ["'](?:apps\/web|\$lib\/server|\$lib\/model)/, + ); + expect(source).not.toContain("../web/"); + }); + + test("keeps icon rendering driven by icon identifiers", () => { + const source = readUiSource(uiSourceRoot); + + expect(source).not.toContain("@iconify-json/"); + expect(source).not.toContain("/icons/"); + }); +}); + +function readUiSource(path: string): string { + if (!existsSync(path)) return ""; + + const stats = statSync(path); + if (stats.isFile()) { + if (path.endsWith(".test.ts") || path.endsWith(".test.tsx")) return ""; + if (!/\.(tsx|ts|css)$/.test(path)) return ""; + return readFileSync(path, "utf8"); + } + + return readdirSync(path) + .map((entry) => readUiSource(join(path, entry))) + .join("\n"); +} diff --git a/src/lib/ui/fixtures.ts b/packages/ui/src/fixtures.ts similarity index 100% rename from src/lib/ui/fixtures.ts rename to packages/ui/src/fixtures.ts diff --git a/src/lib/ui/format.ts b/packages/ui/src/format.ts similarity index 100% rename from src/lib/ui/format.ts rename to packages/ui/src/format.ts diff --git a/src/lib/ui/index.ts b/packages/ui/src/index.ts similarity index 96% rename from src/lib/ui/index.ts rename to packages/ui/src/index.ts index 9eb5448..a9a83df 100644 --- a/src/lib/ui/index.ts +++ b/packages/ui/src/index.ts @@ -29,7 +29,6 @@ export { TelemetryStrip } from "./components/TelemetryStrip"; export { ThemeToggle } from "./components/ThemeToggle"; export { WeatherModule } from "./components/WeatherModule"; export { dashboardPreviewFixtures } from "./fixtures"; -export { dashboardDocumentToUiDashboard } from "./model-renderer"; export { getNextUiTheme, isUiTheme, diff --git a/src/lib/components/ui/alert.tsx b/packages/ui/src/primitives/alert.tsx similarity index 98% rename from src/lib/components/ui/alert.tsx rename to packages/ui/src/primitives/alert.tsx index fc34841..d5d1609 100644 --- a/src/lib/components/ui/alert.tsx +++ b/packages/ui/src/primitives/alert.tsx @@ -1,7 +1,7 @@ import * as React from "react" import { cva, type VariantProps } from "class-variance-authority" -import { cn } from "$lib/utils" +import { cn } from "../utils" const alertVariants = cva( "group/alert relative grid w-full gap-0.5 rounded-lg border px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4", diff --git a/src/lib/components/ui/badge.tsx b/packages/ui/src/primitives/badge.tsx similarity index 98% rename from src/lib/components/ui/badge.tsx rename to packages/ui/src/primitives/badge.tsx index a3d91d7..baa1535 100644 --- a/src/lib/components/ui/badge.tsx +++ b/packages/ui/src/primitives/badge.tsx @@ -2,7 +2,7 @@ import * as React from "react" import { cva, type VariantProps } from "class-variance-authority" import { Slot } from "radix-ui" -import { cn } from "$lib/utils" +import { cn } from "../utils" const badgeVariants = cva( "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", diff --git a/src/lib/components/ui/button.tsx b/packages/ui/src/primitives/button.tsx similarity index 99% rename from src/lib/components/ui/button.tsx rename to packages/ui/src/primitives/button.tsx index 8dda5f2..e37f9b0 100644 --- a/src/lib/components/ui/button.tsx +++ b/packages/ui/src/primitives/button.tsx @@ -2,7 +2,7 @@ import * as React from "react" import { cva, type VariantProps } from "class-variance-authority" import { Slot } from "radix-ui" -import { cn } from "$lib/utils" +import { cn } from "../utils" const buttonVariants = cva( "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", diff --git a/src/lib/components/ui/card.tsx b/packages/ui/src/primitives/card.tsx similarity index 98% rename from src/lib/components/ui/card.tsx rename to packages/ui/src/primitives/card.tsx index bcb9e07..e5e5996 100644 --- a/src/lib/components/ui/card.tsx +++ b/packages/ui/src/primitives/card.tsx @@ -1,6 +1,6 @@ import * as React from "react" -import { cn } from "$lib/utils" +import { cn } from "../utils" function Card({ className, diff --git a/src/lib/components/ui/progress.tsx b/packages/ui/src/primitives/progress.tsx similarity index 95% rename from src/lib/components/ui/progress.tsx rename to packages/ui/src/primitives/progress.tsx index 65d0a6b..59fac6c 100644 --- a/src/lib/components/ui/progress.tsx +++ b/packages/ui/src/primitives/progress.tsx @@ -1,7 +1,7 @@ import * as React from "react" import { Progress as ProgressPrimitive } from "radix-ui" -import { cn } from "$lib/utils" +import { cn } from "../utils" function Progress({ className, diff --git a/src/lib/components/ui/separator.tsx b/packages/ui/src/primitives/separator.tsx similarity index 95% rename from src/lib/components/ui/separator.tsx rename to packages/ui/src/primitives/separator.tsx index 84e3c64..ee9f6cb 100644 --- a/src/lib/components/ui/separator.tsx +++ b/packages/ui/src/primitives/separator.tsx @@ -3,7 +3,7 @@ import * as React from "react" import { Separator as SeparatorPrimitive } from "radix-ui" -import { cn } from "$lib/utils" +import { cn } from "../utils" function Separator({ className, diff --git a/src/lib/components/ui/skeleton.tsx b/packages/ui/src/primitives/skeleton.tsx similarity index 88% rename from src/lib/components/ui/skeleton.tsx rename to packages/ui/src/primitives/skeleton.tsx index 61466a8..a1df193 100644 --- a/src/lib/components/ui/skeleton.tsx +++ b/packages/ui/src/primitives/skeleton.tsx @@ -1,4 +1,4 @@ -import { cn } from "$lib/utils" +import { cn } from "../utils" function Skeleton({ className, ...props }: React.ComponentProps<"div">) { return ( diff --git a/src/lib/ui/stories/Badge.stories.tsx b/packages/ui/src/stories/Badge.stories.tsx similarity index 100% rename from src/lib/ui/stories/Badge.stories.tsx rename to packages/ui/src/stories/Badge.stories.tsx diff --git a/src/lib/ui/stories/Button.stories.tsx b/packages/ui/src/stories/Button.stories.tsx similarity index 100% rename from src/lib/ui/stories/Button.stories.tsx rename to packages/ui/src/stories/Button.stories.tsx diff --git a/src/lib/ui/stories/CornerBracketFrame.stories.tsx b/packages/ui/src/stories/CornerBracketFrame.stories.tsx similarity index 100% rename from src/lib/ui/stories/CornerBracketFrame.stories.tsx rename to packages/ui/src/stories/CornerBracketFrame.stories.tsx diff --git a/src/lib/ui/stories/DashboardFrame.stories.tsx b/packages/ui/src/stories/DashboardFrame.stories.tsx similarity index 100% rename from src/lib/ui/stories/DashboardFrame.stories.tsx rename to packages/ui/src/stories/DashboardFrame.stories.tsx diff --git a/src/lib/ui/stories/DashboardHeader.stories.tsx b/packages/ui/src/stories/DashboardHeader.stories.tsx similarity index 100% rename from src/lib/ui/stories/DashboardHeader.stories.tsx rename to packages/ui/src/stories/DashboardHeader.stories.tsx diff --git a/src/lib/ui/stories/DashboardOnePager.stories.tsx b/packages/ui/src/stories/DashboardOnePager.stories.tsx similarity index 100% rename from src/lib/ui/stories/DashboardOnePager.stories.tsx rename to packages/ui/src/stories/DashboardOnePager.stories.tsx diff --git a/src/lib/ui/stories/DiagonalStripeField.stories.tsx b/packages/ui/src/stories/DiagonalStripeField.stories.tsx similarity index 100% rename from src/lib/ui/stories/DiagonalStripeField.stories.tsx rename to packages/ui/src/stories/DiagonalStripeField.stories.tsx diff --git a/src/lib/ui/stories/FooterCell.stories.tsx b/packages/ui/src/stories/FooterCell.stories.tsx similarity index 100% rename from src/lib/ui/stories/FooterCell.stories.tsx rename to packages/ui/src/stories/FooterCell.stories.tsx diff --git a/src/lib/ui/stories/FooterStatusCell.stories.tsx b/packages/ui/src/stories/FooterStatusCell.stories.tsx similarity index 100% rename from src/lib/ui/stories/FooterStatusCell.stories.tsx rename to packages/ui/src/stories/FooterStatusCell.stories.tsx diff --git a/src/lib/ui/stories/GridFrame.stories.tsx b/packages/ui/src/stories/GridFrame.stories.tsx similarity index 100% rename from src/lib/ui/stories/GridFrame.stories.tsx rename to packages/ui/src/stories/GridFrame.stories.tsx diff --git a/src/lib/ui/stories/IconButton.stories.tsx b/packages/ui/src/stories/IconButton.stories.tsx similarity index 100% rename from src/lib/ui/stories/IconButton.stories.tsx rename to packages/ui/src/stories/IconButton.stories.tsx diff --git a/src/lib/ui/stories/IconGlyph.stories.tsx b/packages/ui/src/stories/IconGlyph.stories.tsx similarity index 100% rename from src/lib/ui/stories/IconGlyph.stories.tsx rename to packages/ui/src/stories/IconGlyph.stories.tsx diff --git a/src/lib/ui/stories/LineChart.stories.tsx b/packages/ui/src/stories/LineChart.stories.tsx similarity index 100% rename from src/lib/ui/stories/LineChart.stories.tsx rename to packages/ui/src/stories/LineChart.stories.tsx diff --git a/src/lib/ui/stories/ModuleCard.stories.tsx b/packages/ui/src/stories/ModuleCard.stories.tsx similarity index 100% rename from src/lib/ui/stories/ModuleCard.stories.tsx rename to packages/ui/src/stories/ModuleCard.stories.tsx diff --git a/src/lib/ui/stories/Panel.stories.tsx b/packages/ui/src/stories/Panel.stories.tsx similarity index 100% rename from src/lib/ui/stories/Panel.stories.tsx rename to packages/ui/src/stories/Panel.stories.tsx diff --git a/src/lib/ui/stories/ProgressMeter.stories.tsx b/packages/ui/src/stories/ProgressMeter.stories.tsx similarity index 100% rename from src/lib/ui/stories/ProgressMeter.stories.tsx rename to packages/ui/src/stories/ProgressMeter.stories.tsx diff --git a/src/lib/ui/stories/ScanlineField.stories.tsx b/packages/ui/src/stories/ScanlineField.stories.tsx similarity index 100% rename from src/lib/ui/stories/ScanlineField.stories.tsx rename to packages/ui/src/stories/ScanlineField.stories.tsx diff --git a/src/lib/ui/stories/Separator.stories.tsx b/packages/ui/src/stories/Separator.stories.tsx similarity index 100% rename from src/lib/ui/stories/Separator.stories.tsx rename to packages/ui/src/stories/Separator.stories.tsx diff --git a/src/lib/ui/stories/ServiceGroupPanel.stories.tsx b/packages/ui/src/stories/ServiceGroupPanel.stories.tsx similarity index 100% rename from src/lib/ui/stories/ServiceGroupPanel.stories.tsx rename to packages/ui/src/stories/ServiceGroupPanel.stories.tsx diff --git a/src/lib/ui/stories/ServicePanel.stories.tsx b/packages/ui/src/stories/ServicePanel.stories.tsx similarity index 100% rename from src/lib/ui/stories/ServicePanel.stories.tsx rename to packages/ui/src/stories/ServicePanel.stories.tsx diff --git a/src/lib/ui/stories/ServiceRow.stories.tsx b/packages/ui/src/stories/ServiceRow.stories.tsx similarity index 100% rename from src/lib/ui/stories/ServiceRow.stories.tsx rename to packages/ui/src/stories/ServiceRow.stories.tsx diff --git a/src/lib/ui/stories/SignalTrace.stories.tsx b/packages/ui/src/stories/SignalTrace.stories.tsx similarity index 100% rename from src/lib/ui/stories/SignalTrace.stories.tsx rename to packages/ui/src/stories/SignalTrace.stories.tsx diff --git a/src/lib/ui/stories/Sparkline.stories.tsx b/packages/ui/src/stories/Sparkline.stories.tsx similarity index 100% rename from src/lib/ui/stories/Sparkline.stories.tsx rename to packages/ui/src/stories/Sparkline.stories.tsx diff --git a/src/lib/ui/stories/StatusBadge.stories.tsx b/packages/ui/src/stories/StatusBadge.stories.tsx similarity index 100% rename from src/lib/ui/stories/StatusBadge.stories.tsx rename to packages/ui/src/stories/StatusBadge.stories.tsx diff --git a/src/lib/ui/stories/StatusStrip.stories.tsx b/packages/ui/src/stories/StatusStrip.stories.tsx similarity index 100% rename from src/lib/ui/stories/StatusStrip.stories.tsx rename to packages/ui/src/stories/StatusStrip.stories.tsx diff --git a/src/lib/ui/stories/SystemState.stories.tsx b/packages/ui/src/stories/SystemState.stories.tsx similarity index 100% rename from src/lib/ui/stories/SystemState.stories.tsx rename to packages/ui/src/stories/SystemState.stories.tsx diff --git a/src/lib/ui/stories/TelemetryCard.stories.tsx b/packages/ui/src/stories/TelemetryCard.stories.tsx similarity index 100% rename from src/lib/ui/stories/TelemetryCard.stories.tsx rename to packages/ui/src/stories/TelemetryCard.stories.tsx diff --git a/src/lib/ui/stories/TelemetryGrid.stories.tsx b/packages/ui/src/stories/TelemetryGrid.stories.tsx similarity index 100% rename from src/lib/ui/stories/TelemetryGrid.stories.tsx rename to packages/ui/src/stories/TelemetryGrid.stories.tsx diff --git a/src/lib/ui/stories/TelemetryStrip.stories.tsx b/packages/ui/src/stories/TelemetryStrip.stories.tsx similarity index 100% rename from src/lib/ui/stories/TelemetryStrip.stories.tsx rename to packages/ui/src/stories/TelemetryStrip.stories.tsx diff --git a/src/lib/ui/stories/ThemeToggle.stories.tsx b/packages/ui/src/stories/ThemeToggle.stories.tsx similarity index 100% rename from src/lib/ui/stories/ThemeToggle.stories.tsx rename to packages/ui/src/stories/ThemeToggle.stories.tsx diff --git a/src/lib/ui/stories/WeatherModule.stories.tsx b/packages/ui/src/stories/WeatherModule.stories.tsx similarity index 100% rename from src/lib/ui/stories/WeatherModule.stories.tsx rename to packages/ui/src/stories/WeatherModule.stories.tsx diff --git a/src/lib/ui/stories/story-data.ts b/packages/ui/src/stories/story-data.ts similarity index 100% rename from src/lib/ui/stories/story-data.ts rename to packages/ui/src/stories/story-data.ts diff --git a/src/lib/ui/storybook.test.ts b/packages/ui/src/storybook.test.ts similarity index 86% rename from src/lib/ui/storybook.test.ts rename to packages/ui/src/storybook.test.ts index aa76cad..4ef14ba 100644 --- a/src/lib/ui/storybook.test.ts +++ b/packages/ui/src/storybook.test.ts @@ -3,8 +3,11 @@ import { join } from "node:path"; import { describe, expect, test } from "vitest"; const root = process.cwd(); -const componentsDir = join(root, "src/lib/ui/components"); -const storiesDir = join(root, "src/lib/ui/stories"); +const packageRoot = existsSync(join(root, "packages/ui/package.json")) + ? join(root, "packages/ui") + : root; +const componentsDir = join(packageRoot, "src/components"); +const storiesDir = join(packageRoot, "src/stories"); const requiredStoryFiles = [ "Badge.stories.tsx", @@ -49,7 +52,7 @@ const forbiddenStoryContent = [ describe("Storybook inventory", () => { test("exposes scripts for local and static Storybook review", () => { - const packageJson = JSON.parse(readFileSync(join(root, "package.json"), "utf8")) as { + const packageJson = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8")) as { scripts?: Record; }; @@ -65,21 +68,22 @@ describe("Storybook inventory", () => { }); test("loads dashboard component styles through the global app stylesheet", () => { - const appStyles = readFileSync(join(root, "src/app.css"), "utf8"); + const packageStyles = readFileSync(join(packageRoot, "src/styles.css"), "utf8"); const dashboardFrame = readFileSync( join(componentsDir, "DashboardFrame.tsx"), "utf8", ); - expect(appStyles).toContain('./lib/ui/components/styles.css'); + expect(packageStyles).toContain('./components/styles.css'); expect(dashboardFrame).not.toContain('./styles.css'); }); test("configures Storybook theme switching for reusable components", () => { - const previewSource = readFileSync(join(root, ".storybook/preview.ts"), "utf8"); + const previewSource = readFileSync(join(packageRoot, ".storybook/preview.ts"), "utf8"); expect(previewSource).toContain("globalTypes"); expect(previewSource).toContain("data-ui-theme"); + expect(previewSource).toContain("../src/styles.css"); }); test("keeps component and story files paired as the UI inventory changes", () => { @@ -135,7 +139,7 @@ describe("Storybook inventory", () => { test("does not add deferred form/navigation primitives", () => { for (const component of ["Input", "ToggleGroup", "ScrollArea"]) { - expect(existsSync(join(root, `src/lib/ui/components/${component}.tsx`))).toBe(false); + expect(existsSync(join(componentsDir, `${component}.tsx`))).toBe(false); expect(existsSync(join(storiesDir, `${component}.stories.tsx`))).toBe(false); } }); diff --git a/packages/ui/src/styles.css b/packages/ui/src/styles.css new file mode 100644 index 0000000..fd6f4a2 --- /dev/null +++ b/packages/ui/src/styles.css @@ -0,0 +1,4 @@ +@import "@fontsource-variable/geist"; +@import "uplot/dist/uPlot.min.css"; +@import "./tokens.css"; +@import "./components/styles.css"; diff --git a/src/lib/ui/theme.test.ts b/packages/ui/src/theme.test.ts similarity index 100% rename from src/lib/ui/theme.test.ts rename to packages/ui/src/theme.test.ts diff --git a/src/lib/ui/theme.ts b/packages/ui/src/theme.ts similarity index 100% rename from src/lib/ui/theme.ts rename to packages/ui/src/theme.ts diff --git a/src/lib/ui/tokens.css b/packages/ui/src/tokens.css similarity index 100% rename from src/lib/ui/tokens.css rename to packages/ui/src/tokens.css diff --git a/src/lib/ui/types.ts b/packages/ui/src/types.ts similarity index 100% rename from src/lib/ui/types.ts rename to packages/ui/src/types.ts diff --git a/src/lib/utils.ts b/packages/ui/src/utils.ts similarity index 100% rename from src/lib/utils.ts rename to packages/ui/src/utils.ts diff --git a/packages/ui/tsconfig.build.json b/packages/ui/tsconfig.build.json index d942d59..bd56366 100644 --- a/packages/ui/tsconfig.build.json +++ b/packages/ui/tsconfig.build.json @@ -7,6 +7,7 @@ "outDir": "dist", "rootDir": "src" }, + "include": ["src/**/*.ts", "src/**/*.tsx"], "exclude": [ "dist", "node_modules", diff --git a/src/lib/ui/content-boundary.test.ts b/src/lib/ui/content-boundary.test.ts deleted file mode 100644 index 6613644..0000000 --- a/src/lib/ui/content-boundary.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { readdirSync, readFileSync, statSync } from "node:fs"; -import { join } from "node:path"; -import { describe, expect, test } from "vitest"; - -const forbiddenTerms = [ - "dimensionlab", - "dimension lab", - "vaultwarden", - "forgejo", - "grafana", - "uptime kuma", - "prometheus", - "backrest", - "open webui", - "comfyui", - "adminer", - "cockpit", - "ollama", -]; - -describe("UI content boundary", () => { - test("keeps environment-specific content out of reusable UI source", () => { - const source = readUiSource(join(process.cwd(), "src", "lib", "ui")); - const normalized = source.toLowerCase(); - - expect( - forbiddenTerms.filter((term) => normalized.includes(term)), - ).toEqual([]); - }); - - test("keeps icon rendering driven by icon identifiers", () => { - const source = readUiSource(join(process.cwd(), "src", "lib", "ui")); - - expect(source).not.toContain("@iconify-json/"); - expect(source).not.toContain("/icons/"); - }); -}); - -function readUiSource(path: string): string { - const stats = statSync(path); - if (stats.isFile()) { - if (path.endsWith(".test.ts")) return ""; - return readFileSync(path, "utf8"); - } - - return readdirSync(path) - .map((entry) => readUiSource(join(path, entry))) - .join("\n"); -}