Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion workbench/_web/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ node_modules/
# Migrations (for now?)

/sqlite-migrations/
/pg-migrations/
/pg-migrations/
*storybook.log
storybook-static
69 changes: 69 additions & 0 deletions workbench/_web/.storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import type { StorybookConfig } from "@storybook/nextjs-vite";
import { fileURLToPath } from "url";
import { dirname, resolve } from "path";
import type { Plugin } from "vite";
import { readFileSync } from "fs";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// Create a Vite plugin to mock server-side dependencies
function mockServerDeps(): Plugin {
const srcDir = resolve(__dirname, "../src");
const mocksDir = resolve(__dirname, "./mocks");

// Read mock file contents
const dbClientMock = readFileSync(resolve(mocksDir, "db-client.ts"), "utf-8");
const dotenvMock = readFileSync(resolve(mocksDir, "dotenv.ts"), "utf-8");

return {
name: "mock-server-deps",
enforce: "pre",
// Intercept file loading
load(id) {
// Mock db/client.ts
if (id.includes("src/db/client") || id.endsWith("db/client.ts")) {
console.log("[mock-server-deps] Mocking:", id);
return dbClientMock;
}
return null;
},
// Also handle module resolution for dotenv
resolveId(source) {
if (source === "dotenv") {
return resolve(mocksDir, "dotenv.ts");
}
return null;
},
};
}

const config: StorybookConfig = {
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
addons: [
"@chromatic-com/storybook",
"@storybook/addon-vitest",
"@storybook/addon-a11y",
"@storybook/addon-docs",
"@storybook/addon-onboarding",
],
framework: "@storybook/nextjs-vite",
staticDirs: ["../public"],
async viteFinal(config) {
return {
...config,
plugins: [mockServerDeps(), ...(config.plugins || [])],
optimizeDeps: {
...config.optimizeDeps,
force: true,
exclude: [
...(config.optimizeDeps?.exclude || []),
"dotenv",
"better-sqlite3",
"postgres",
],
},
};
},
};
export default config;
8 changes: 8 additions & 0 deletions workbench/_web/.storybook/mocks/db-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Mock db client for Storybook
* This file replaces @/db/client in the browser environment
*/
export const db = {
// Mock database instance
// Add any mock methods needed for your stories here
};
21 changes: 21 additions & 0 deletions workbench/_web/.storybook/mocks/dotenv.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Mock dotenv for Storybook browser environment
* The real dotenv uses process.cwd() which doesn't exist in browsers
*/

export function config() {
// No-op in browser
return { parsed: {} };
}

export function parse() {
return {};
}

export const configDotenv = config;

export default {
config,
parse,
configDotenv,
};
54 changes: 54 additions & 0 deletions workbench/_web/.storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { Preview } from "@storybook/nextjs-vite";
import React from "react";
import "../src/app/globals.css";

const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
a11y: {
test: "todo",
},
backgrounds: {
disable: true, // We use CSS variables instead
},
},
globalTypes: {
theme: {
description: "Global theme for components",
toolbar: {
title: "Theme",
icon: "circlehollow",
items: [
{ value: "light", title: "Light", icon: "sun" },
{ value: "dark", title: "Dark", icon: "moon" },
],
dynamicTitle: true,
},
},
},
initialGlobals: {
theme: "light",
},
decorators: [
(Story, context) => {
const theme = context.globals.theme || "light";
// Apply theme class to the document
if (typeof document !== "undefined") {
document.documentElement.classList.remove("light", "dark");
document.documentElement.classList.add(theme);
}
return (
<div className={`min-h-screen bg-background text-foreground ${theme}`}>
<Story />
</div>
);
},
],
};

export default preview;
7 changes: 7 additions & 0 deletions workbench/_web/.storybook/vitest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as a11yAddonAnnotations from "@storybook/addon-a11y/preview";
import { setProjectAnnotations } from "@storybook/nextjs-vite";
import * as projectAnnotations from "./preview";

// This is an important step to apply the right configuration when testing your stories.
// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations
setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]);
4 changes: 4 additions & 0 deletions workbench/_web/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format
import storybook from "eslint-plugin-storybook";

import { dirname } from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";
Expand Down Expand Up @@ -29,6 +32,7 @@ const eslintConfig = [
"jsx-a11y/alt-text": "off",
},
},
...storybook.configs["flat/recommended"],
];

export default eslintConfig;
Loading
Loading