feat(web): add light/dark theme switcher to Storybook toolbar

Quentin Gliech and Claude Opus 4.6 (1M context) created

Add a global theme toolbar (sun/moon icons) that toggles the .dark
class on the iframe's <html> element, matching the app's dark mode
mechanism. All components and Shiki themes respond correctly.

Rename preview.ts → preview.tsx for JSX decorator support.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Change summary

webui2/.storybook/preview.ts  | 19 ----------------
webui2/.storybook/preview.tsx | 43 +++++++++++++++++++++++++++++++++++++
2 files changed, 43 insertions(+), 19 deletions(-)

Detailed changes

webui2/.storybook/preview.ts 🔗

@@ -1,19 +0,0 @@
-import type { Preview } from "@storybook/react-vite";
-
-import "../src/index.css";
-
-const preview: Preview = {
-  parameters: {
-    a11y: {
-      test: "error",
-    },
-    controls: {
-      matchers: {
-        color: /(background|color)$/i,
-        date: /date$/i,
-      },
-    },
-  },
-};
-
-export default preview;

webui2/.storybook/preview.tsx 🔗

@@ -0,0 +1,43 @@
+import type { Preview } from "@storybook/react-vite";
+
+import "../src/index.css";
+
+const preview: Preview = {
+  globalTypes: {
+    theme: {
+      description: "Toggle light/dark mode",
+      toolbar: {
+        title: "Theme",
+        icon: "sun",
+        items: [
+          { value: "light", icon: "sun", title: "Light" },
+          { value: "dark", icon: "moon", title: "Dark" },
+        ],
+        dynamicTitle: true,
+      },
+    },
+  },
+  initialGlobals: {
+    theme: "light",
+  },
+  decorators: [
+    (Story, context) => {
+      const theme = context.globals.theme as string;
+      document.documentElement.classList.toggle("dark", theme === "dark");
+      return <Story />;
+    },
+  ],
+  parameters: {
+    a11y: {
+      test: "error",
+    },
+    controls: {
+      matchers: {
+        color: /(background|color)$/i,
+        date: /date$/i,
+      },
+    },
+  },
+};
+
+export default preview;