diff --git a/.local/project-ports.json b/.local/project-ports.json index cd79ac8..4760605 100644 --- a/.local/project-ports.json +++ b/.local/project-ports.json @@ -2,8 +2,8 @@ "version": 1, "projectName": "pokemon-inventory", "projectPath": "/Users/fragginwagon/Developer/Source Code/pokemon/pokemon-inventory", - "updatedAt": "2026-09-08T23:54:46.326Z", - "lastSeenAt": "2026-09-08T23:54:46.326Z", + "updatedAt": "2026-09-09T01:42:54.487Z", + "lastSeenAt": "2026-09-09T01:42:54.487Z", "ports": [ { "service": "api", @@ -23,6 +23,12 @@ "port": 5433, "notes": "" }, + { + "service": "storybook", + "protocol": "tcp", + "port": 6006, + "notes": "" + }, { "service": "redis", "protocol": "tcp", diff --git a/README.md b/README.md index c235f02..306f71c 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,16 @@ This command starts healthy PostgreSQL and Redis containers, applies migrations, The command does not provision an administrator automatically. Run `npm run provision:admin` once after setting the initial administrator variables in `.env` when admin access is needed. Stop the application processes with `Ctrl+C`; stop the containers separately with `npm run db:down` when they are no longer needed. +## Visual Development + +Run Storybook to inspect the authoritative design tokens and mock visual fixtures without requiring API data: + +```sh +npm run storybook +``` + +Open `http://localhost:6006/`. Use the Storybook theme toolbar to switch between light and dark themes. The accessibility addon is enabled for component review. The fixture showcase is intentionally mock-only and is not part of the production router. + ## Initial Administrator After the development database is migrated, set `INITIAL_ADMIN_EMAIL`, `INITIAL_ADMIN_PASSWORD`, and `INITIAL_SELLER_NAME` in your local `.env`, then run `npm run provision:admin` once. The command creates the only initial administrator and linked Seller; it refuses to run after any User exists. diff --git a/apps/web/.storybook/main.js b/apps/web/.storybook/main.js new file mode 100644 index 0000000..fd06fe2 --- /dev/null +++ b/apps/web/.storybook/main.js @@ -0,0 +1,20 @@ +import { fileURLToPath } from 'node:url'; + +export default { + stories: ['../src/**/*.stories.js'], + addons: ['@storybook/addon-essentials', '@storybook/addon-a11y'], + framework: { + name: '@storybook/vue3-vite', + options: {}, + }, + viteFinal: async (config) => ({ + ...config, + resolve: { + ...config.resolve, + alias: { + ...config.resolve?.alias, + '@': fileURLToPath(new URL('../src', import.meta.url)), + }, + }, + }), +}; diff --git a/apps/web/.storybook/preview.js b/apps/web/.storybook/preview.js new file mode 100644 index 0000000..a63f80b --- /dev/null +++ b/apps/web/.storybook/preview.js @@ -0,0 +1,26 @@ +import '../src/assets/styles/global.scss'; + +export const globalTypes = { + theme: { + description: 'Global color theme', + defaultValue: 'light', + toolbar: { + icon: 'paintbrush', + items: ['light', 'dark'], + dynamicTitle: true, + }, + }, +}; + +export const decorators = [ + (story, context) => { + document.documentElement.dataset.theme = context.globals.theme; + return story(); + }, +]; + +export const parameters = { + controls: { expanded: true }, + a11y: { test: 'todo' }, + layout: 'fullscreen', +}; diff --git a/apps/web/package.json b/apps/web/package.json index 03969d6..f97e514 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -5,6 +5,8 @@ "scripts": { "dev": "vite", "build": "vite build", + "storybook": "storybook dev -p 6006", + "build-storybook": "storybook build", "test": "node --test tests/*.test.js" }, "dependencies": { diff --git a/apps/web/src/App.vue b/apps/web/src/App.vue index 6a6cd2d..7b84f05 100644 --- a/apps/web/src/App.vue +++ b/apps/web/src/App.vue @@ -1,5 +1,8 @@