@auto-engineer/generate-react-client 1.28.0 → 1.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,66 @@
1
1
  # @auto-engineer/generate-react-client
2
2
 
3
+ ## 1.30.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`2181802`](https://github.com/BeOnAuto/auto-engineer/commit/21818027dc5db0ab2b69116e7dae4ed458fa6c3d) Thanks [@github-actions[bot]](https://github.com/github-actions%5Bbot%5D)! - - **pipeline**: use .declare().accepts() in auto.config.ts
8
+ - **pipeline**: add .declare() to EmitChain, SettledChain, HandleChain
9
+ - **pipeline**: add AcceptsDescriptor type and .declare().accepts() builder
10
+ - **react-component-implementer**: parallelize type check and browser validation
11
+ - **react-component-implementer**: wire mcp-pool for connection reuse
12
+
13
+ - [`b095ae5`](https://github.com/BeOnAuto/auto-engineer/commit/b095ae52b9574566f64cc194b8567a001ae1210c) Thanks [@SamHatoum](https://github.com/SamHatoum)! - - **generate-react-client**: add postMessage-based iframe navigation tracking
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies [[`2181802`](https://github.com/BeOnAuto/auto-engineer/commit/21818027dc5db0ab2b69116e7dae4ed458fa6c3d), [`b095ae5`](https://github.com/BeOnAuto/auto-engineer/commit/b095ae52b9574566f64cc194b8567a001ae1210c)]:
18
+ - @auto-engineer/message-bus@1.30.0
19
+
20
+ ## 1.29.0
21
+
22
+ ### Minor Changes
23
+
24
+ - [`2ef9632`](https://github.com/BeOnAuto/auto-engineer/commit/2ef9632a2db081f201981422f2ba26b026fa7277) Thanks [@SamHatoum](https://github.com/SamHatoum)! - ### react-component-implementer
25
+ - Add staging workflow with `writeStagedStory`, `checkStagedTypes`, and `promoteFromStaging`
26
+ - Add MCP connection pool and browser pool for resource reuse
27
+ - Add context filtering and system prompt caching to reduce tokens
28
+ - Add ts-service for type-aware error feedback with property suggestions
29
+ - Parallelize type checking and browser validation
30
+ - Replace score-based visual evaluation with binary ACK/NACK criteria
31
+ - Enable incremental TypeScript checking in staging
32
+
33
+ ### pipeline
34
+ - Add `.declare().accepts()` builder for AcceptsDescriptor type
35
+ - Show source commands in pipeline graph
36
+
37
+ ### job-graph-processor
38
+ - Add `hasFailedJobs` utility and discriminate GraphProcessed vs GraphProcessingFailed
39
+ - Bridge context.emit in command handler for downstream event routing
40
+
41
+ ### server-generator-apollo-emmett
42
+ - Add cleanServerDir to preserve node_modules during regeneration
43
+ - Accept Model directly instead of modelPath
44
+
45
+ ### server-generator-nestjs
46
+ - Accept Model directly instead of modelPath
47
+
48
+ ### generate-react-client
49
+ - Lock in overwrite behavior for copyStarter
50
+
51
+ ### narrative
52
+ - Remove export-schema command
53
+
54
+ ### global
55
+ - Remove references to information-architect and model-diff packages
56
+ - Fix biome lint errors for CI compliance
57
+ - Update examples and configuration files
58
+
59
+ ### Patch Changes
60
+
61
+ - Updated dependencies [[`2ef9632`](https://github.com/BeOnAuto/auto-engineer/commit/2ef9632a2db081f201981422f2ba26b026fa7277)]:
62
+ - @auto-engineer/message-bus@1.29.0
63
+
3
64
  ## 1.28.0
4
65
 
5
66
  ### Minor Changes
@@ -1 +1 @@
1
- {"version":3,"file":"copy-starter.d.ts","sourceRoot":"","sources":["../../src/copy-starter.ts"],"names":[],"mappings":"AA8BA,wBAAsB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAWxF"}
1
+ {"version":3,"file":"copy-starter.d.ts","sourceRoot":"","sources":["../../src/copy-starter.ts"],"names":[],"mappings":"AA8BA,wBAAsB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUxF"}
@@ -26,7 +26,6 @@ export async function copyStarter(starterDir, targetDir) {
26
26
  const src = path.isAbsolute(starterDir) ? starterDir : path.resolve(process.cwd(), starterDir);
27
27
  const dest = path.isAbsolute(targetDir) ? targetDir : path.resolve(process.cwd(), targetDir);
28
28
  debug('Copying starter from %s to %s', src, dest);
29
- await fs.rm(dest, { recursive: true, force: true });
30
29
  const fileCount = await copyDir(src, dest);
31
30
  debug('Copied %d files to %s', fileCount, dest);
32
31
  return fileCount;
@@ -1 +1 @@
1
- {"version":3,"file":"copy-starter.js","sourceRoot":"","sources":["../../src/copy-starter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,WAAW,MAAM,OAAO,CAAC;AAEhC,MAAM,KAAK,GAAG,WAAW,CAAC,yCAAyC,CAAC,CAAC;AAErE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,gBAAgB,EAAE,WAAW,CAAC,CAAC,CAAC;AAEtE,KAAK,UAAU,OAAO,CAAC,GAAW,EAAE,IAAY;IAC9C,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAS;QAEnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAE7C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,KAAK,IAAI,MAAM,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC5C,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1B,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YACrC,KAAK,EAAE,CAAC;QACV,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,UAAkB,EAAE,SAAiB;IACrE,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,CAAC,CAAC;IAC/F,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;IAE7F,KAAK,CAAC,+BAA+B,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAElD,MAAM,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAE3C,KAAK,CAAC,uBAAuB,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAChD,OAAO,SAAS,CAAC;AACnB,CAAC"}
1
+ {"version":3,"file":"copy-starter.js","sourceRoot":"","sources":["../../src/copy-starter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,WAAW,MAAM,OAAO,CAAC;AAEhC,MAAM,KAAK,GAAG,WAAW,CAAC,yCAAyC,CAAC,CAAC;AAErE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,gBAAgB,EAAE,WAAW,CAAC,CAAC,CAAC;AAEtE,KAAK,UAAU,OAAO,CAAC,GAAW,EAAE,IAAY;IAC9C,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAS;QAEnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAE7C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,KAAK,IAAI,MAAM,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC5C,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1B,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YACrC,KAAK,EAAE,CAAC;QACV,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,UAAkB,EAAE,SAAiB;IACrE,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,CAAC,CAAC;IAC/F,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;IAE7F,KAAK,CAAC,+BAA+B,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAElD,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAE3C,KAAK,CAAC,uBAAuB,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAChD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=copy-starter.specs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy-starter.specs.d.ts","sourceRoot":"","sources":["../../src/copy-starter.specs.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import * as os from 'node:os';
3
+ import * as path from 'node:path';
4
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
5
+ import { copyStarter } from './copy-starter.js';
6
+ describe('copyStarter', () => {
7
+ let tmpDir;
8
+ let starterDir;
9
+ let targetDir;
10
+ beforeEach(async () => {
11
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'copy-starter-'));
12
+ starterDir = path.join(tmpDir, 'starter');
13
+ targetDir = path.join(tmpDir, 'target');
14
+ await fs.mkdir(starterDir, { recursive: true });
15
+ await fs.mkdir(targetDir, { recursive: true });
16
+ });
17
+ afterEach(async () => {
18
+ await fs.rm(tmpDir, { recursive: true, force: true });
19
+ });
20
+ it('preserves pre-existing files in target', async () => {
21
+ await fs.writeFile(path.join(starterDir, 'a.txt'), 'from starter');
22
+ await fs.writeFile(path.join(targetDir, 'b.txt'), 'pre-existing');
23
+ await copyStarter(starterDir, targetDir);
24
+ const aContent = await fs.readFile(path.join(targetDir, 'a.txt'), 'utf-8');
25
+ const bContent = await fs.readFile(path.join(targetDir, 'b.txt'), 'utf-8');
26
+ expect(aContent).toBe('from starter');
27
+ expect(bContent).toBe('pre-existing');
28
+ });
29
+ it('overwrites files that exist in both source and target', async () => {
30
+ await fs.writeFile(path.join(starterDir, 'a.txt'), 'new content');
31
+ await fs.writeFile(path.join(targetDir, 'a.txt'), 'old content');
32
+ await copyStarter(starterDir, targetDir);
33
+ const content = await fs.readFile(path.join(targetDir, 'a.txt'), 'utf-8');
34
+ expect(content).toBe('new content');
35
+ });
36
+ });
37
+ //# sourceMappingURL=copy-starter.specs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy-starter.specs.js","sourceRoot":"","sources":["../../src/copy-starter.specs.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,15 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
1
3
  import { fileURLToPath } from "node:url";
2
- import { dirname } from "node:path";
3
4
  import type { StorybookConfig } from "@storybook/react-vite";
4
5
 
5
- const isFastMode = !!process.env.STORYBOOK_FAST;
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const managerHeadContent = readFileSync(
8
+ join(__dirname, "manager-head.html"),
9
+ "utf-8",
10
+ );
11
+
12
+ const isFastMode = process.env.STORYBOOK_FAST === "1";
6
13
 
7
14
  const config: StorybookConfig = {
8
15
  stories: isFastMode
@@ -19,6 +26,7 @@ const config: StorybookConfig = {
19
26
  },
20
27
  },
21
28
  },
29
+ getAbsolutePath("@vueless/storybook-dark-mode"),
22
30
  ],
23
31
  staticDirs: ["../public"],
24
32
  features: {
@@ -39,8 +47,13 @@ const config: StorybookConfig = {
39
47
  ...config.server,
40
48
  allowedHosts: [".worker.on.auto", ".worker-dev.on.auto"],
41
49
  };
50
+ config.define = {
51
+ ...config.define,
52
+ "import.meta.env.STORYBOOK_FAST": JSON.stringify(isFastMode),
53
+ };
42
54
  return config;
43
55
  },
56
+ managerHead: () => managerHeadContent,
44
57
  };
45
58
 
46
59
  export default config;
@@ -0,0 +1,154 @@
1
+ <script>
2
+ (function() {
3
+ // Check localStorage for dark mode state before anything renders
4
+ var isDark = false;
5
+ try {
6
+ var stored = localStorage.getItem('sb-addon-themes-3');
7
+ if (stored) {
8
+ var parsed = JSON.parse(stored);
9
+ isDark = parsed && parsed.current === 'dark';
10
+ }
11
+ } catch(e) {}
12
+
13
+ // Also check URL parameter
14
+ var urlParams = new URLSearchParams(window.location.search);
15
+ var urlTheme = urlParams.get('theme');
16
+ if (urlTheme) {
17
+ isDark = urlTheme === 'dark';
18
+ }
19
+
20
+ // Apply matching theme background colors immediately (blue-tinted grays)
21
+ document.documentElement.style.backgroundColor = isDark ? '#1a1f2e' : '#f0f3f9';
22
+ document.documentElement.style.colorScheme = isDark ? 'dark' : 'light';
23
+
24
+ // Store theme state for CSS
25
+ document.documentElement.dataset.theme = isDark ? 'dark' : 'light';
26
+ })();
27
+ </script>
28
+ <style>
29
+ html, body {
30
+ transition: none !important;
31
+ }
32
+
33
+ /* Force sidebar and nav backgrounds - target the actual container divs */
34
+ #storybook-explorer-tree,
35
+ [class*="sidebar"],
36
+ [class*="Sidebar"],
37
+ nav[class],
38
+ aside[class] {
39
+ background-color: #f0f3f9 !important;
40
+ }
41
+
42
+ html[data-theme="dark"] #storybook-explorer-tree,
43
+ html[data-theme="dark"] [class*="sidebar"],
44
+ html[data-theme="dark"] [class*="Sidebar"],
45
+ html[data-theme="dark"] nav[class],
46
+ html[data-theme="dark"] aside[class] {
47
+ background-color: #1a1f2e !important;
48
+ }
49
+
50
+ /* Force toolbar/header backgrounds */
51
+ [class*="toolbar"],
52
+ [class*="Toolbar"],
53
+ [class*="bar"],
54
+ [class*="Bar"],
55
+ header[class] {
56
+ background-color: #f0f3f9 !important;
57
+ }
58
+
59
+ html[data-theme="dark"] [class*="toolbar"],
60
+ html[data-theme="dark"] [class*="Toolbar"],
61
+ html[data-theme="dark"] [class*="bar"],
62
+ html[data-theme="dark"] [class*="Bar"],
63
+ html[data-theme="dark"] header[class] {
64
+ background-color: #1a1f2e !important;
65
+ }
66
+
67
+ /* Force ALL sidebar text to dark gray instead of blue */
68
+ [data-nodetype],
69
+ [data-nodetype] * {
70
+ color: #2d3748 !important;
71
+ }
72
+
73
+ html[data-theme="dark"] [data-nodetype],
74
+ html[data-theme="dark"] [data-nodetype] * {
75
+ color: #e2e8f0 !important;
76
+ }
77
+
78
+ /* Sidebar selection styles - subtle background */
79
+ [data-nodetype="story"][data-selected="true"],
80
+ [data-nodetype="document"][data-selected="true"],
81
+ [data-nodetype="component"][data-selected="true"],
82
+ [data-nodetype="group"][data-selected="true"] {
83
+ background-color: #e2e8f0 !important;
84
+ border-radius: 0.5rem !important;
85
+ }
86
+
87
+ [data-nodetype="story"][data-selected="true"] *,
88
+ [data-nodetype="document"][data-selected="true"] *,
89
+ [data-nodetype="component"][data-selected="true"] *,
90
+ [data-nodetype="group"][data-selected="true"] * {
91
+ color: #1a202c !important;
92
+ }
93
+
94
+ /* Dark mode selected item */
95
+ html[data-theme="dark"] [data-nodetype="story"][data-selected="true"],
96
+ html[data-theme="dark"] [data-nodetype="document"][data-selected="true"],
97
+ html[data-theme="dark"] [data-nodetype="component"][data-selected="true"],
98
+ html[data-theme="dark"] [data-nodetype="group"][data-selected="true"] {
99
+ background-color: #3d4663 !important;
100
+ }
101
+
102
+ html[data-theme="dark"] [data-nodetype="story"][data-selected="true"] *,
103
+ html[data-theme="dark"] [data-nodetype="document"][data-selected="true"] *,
104
+ html[data-theme="dark"] [data-nodetype="component"][data-selected="true"] *,
105
+ html[data-theme="dark"] [data-nodetype="group"][data-selected="true"] * {
106
+ color: #f7fafc !important;
107
+ }
108
+
109
+ /* Hover state */
110
+ [data-nodetype="story"]:hover,
111
+ [data-nodetype="document"]:hover,
112
+ [data-nodetype="component"]:hover,
113
+ [data-nodetype="group"]:hover {
114
+ background-color: #edf2f7 !important;
115
+ border-radius: 0.5rem !important;
116
+ }
117
+
118
+ html[data-theme="dark"] [data-nodetype="story"]:hover,
119
+ html[data-theme="dark"] [data-nodetype="document"]:hover,
120
+ html[data-theme="dark"] [data-nodetype="component"]:hover,
121
+ html[data-theme="dark"] [data-nodetype="group"]:hover {
122
+ background-color: #2d3748 !important;
123
+ }
124
+
125
+ /* Selected hover - keep selected state */
126
+ [data-nodetype][data-selected="true"]:hover {
127
+ background-color: #e2e8f0 !important;
128
+ }
129
+
130
+ html[data-theme="dark"] [data-nodetype][data-selected="true"]:hover {
131
+ background-color: #3d4663 !important;
132
+ }
133
+ </style>
134
+ <script>
135
+ (function() {
136
+ if (window.parent === window) return;
137
+ function notify() {
138
+ window.parent.postMessage({ type: 'iframe-url-change', url: location.href }, '*');
139
+ }
140
+ var pushState = history.pushState;
141
+ var replaceState = history.replaceState;
142
+ history.pushState = function() {
143
+ pushState.apply(this, arguments);
144
+ notify();
145
+ };
146
+ history.replaceState = function() {
147
+ replaceState.apply(this, arguments);
148
+ notify();
149
+ };
150
+ window.addEventListener('popstate', notify);
151
+ window.addEventListener('hashchange', notify);
152
+ notify();
153
+ })();
154
+ </script>
@@ -0,0 +1,165 @@
1
+ import { addons } from 'storybook/manager-api';
2
+ import { create } from 'storybook/theming';
3
+ import { STORY_CHANGED } from 'storybook/internal/core-events';
4
+ import { UPDATE_DARK_MODE_EVENT_NAME } from '@vueless/storybook-dark-mode';
5
+
6
+ // Get initial theme from localStorage (dark mode addon) or URL parameter
7
+ const urlParams = new URLSearchParams(window.location.search);
8
+ const urlTheme = urlParams.get('theme');
9
+ const getStoredDarkMode = (): boolean => {
10
+ try {
11
+ const stored = localStorage.getItem('sb-addon-themes-3');
12
+ if (stored) {
13
+ const parsed = JSON.parse(stored);
14
+ return parsed?.current === 'dark';
15
+ }
16
+ } catch {}
17
+ return false;
18
+ };
19
+ const initialIsDark = urlTheme ? urlTheme === 'dark' : getStoredDarkMode();
20
+
21
+ // Theme colors matching app's design with subtle blue tint
22
+ // Analyzed from screenshots - app has slight blue undertone in grays
23
+
24
+ const lightTheme = create({
25
+ base: 'light',
26
+ brandTitle: ' ',
27
+ brandUrl: '/',
28
+ brandImage: '/blank.svg',
29
+
30
+ // App background colors - matching your app's blue-tinted sidebar
31
+ appBg: '#f0f3f9', // sidebar background (blue-tinted like your app)
32
+ appContentBg: '#ffffff', // main content area
33
+ appPreviewBg: '#ffffff', // preview/canvas background
34
+ appBorderColor: '#e2e8f0', // borders (blue-tinted)
35
+ appBorderRadius: 10, // 0.625rem = 10px
36
+
37
+ // Text colors - dark gray, not blue
38
+ textColor: '#2d3748', // dark gray text for sidebar items
39
+ textMutedColor: '#718096', // muted gray text
40
+ textInverseColor: '#f7fafc',// inverse text
41
+
42
+ // Toolbar/UI colors
43
+ barBg: '#f0f3f9', // toolbar background (blue-tinted)
44
+ barTextColor: '#2d3748', // toolbar text (dark gray)
45
+ barHoverColor: '#1a202c', // toolbar hover
46
+ barSelectedColor: '#1a202c',// toolbar selected
47
+
48
+ // Form colors
49
+ inputBg: '#ffffff', // input background
50
+ inputBorder: '#e2e8f0', // input border
51
+ inputTextColor: '#2d3748', // input text
52
+
53
+ // Button colors
54
+ buttonBg: '#edf2f7', // button background
55
+ buttonBorder: '#e2e8f0', // button border
56
+
57
+ // Boolean inputs
58
+ booleanBg: '#edf2f7',
59
+ booleanSelectedBg: '#2d3748',
60
+
61
+ // Grid colors for canvas
62
+ gridCellSize: 10,
63
+
64
+ // Color for links/interactive items - override the blue
65
+ colorPrimary: '#2d3748',
66
+ colorSecondary: '#4a5568',
67
+ });
68
+
69
+ const darkTheme = create({
70
+ base: 'dark',
71
+ brandTitle: ' ',
72
+ brandUrl: '/',
73
+ brandImage: '/blank.svg',
74
+
75
+ // App background colors - matching app's dark blue-tinted theme
76
+ appBg: '#1a1f2e', // sidebar background (blue-tinted dark)
77
+ appContentBg: '#131620', // main content area (darker)
78
+ appPreviewBg: '#131620', // preview/canvas background
79
+ appBorderColor: '#2a3142', // borders (blue-tinted)
80
+ appBorderRadius: 10,
81
+
82
+ // Text colors - light gray, not blue
83
+ textColor: '#e2e8f0', // light gray text
84
+ textMutedColor: '#a0aec0', // muted gray text
85
+ textInverseColor: '#1a1f2e',// inverse text
86
+
87
+ // Toolbar/UI colors
88
+ barBg: '#1a1f2e', // toolbar background
89
+ barTextColor: '#e2e8f0', // toolbar text (light gray)
90
+ barHoverColor: '#f7fafc', // toolbar hover
91
+ barSelectedColor: '#f7fafc',// toolbar selected
92
+
93
+ // Form colors
94
+ inputBg: '#242938', // input background
95
+ inputBorder: '#3d4663', // input border
96
+ inputTextColor: '#e2e8f0', // input text
97
+
98
+ // Button colors
99
+ buttonBg: '#242938', // button background
100
+ buttonBorder: '#3d4663', // button border
101
+
102
+ // Boolean inputs
103
+ booleanBg: '#242938',
104
+ booleanSelectedBg: '#e2e8f0',
105
+
106
+ // Grid colors for canvas
107
+ gridCellSize: 10,
108
+
109
+ // Color for links/interactive items - override the blue
110
+ colorPrimary: '#e2e8f0',
111
+ colorSecondary: '#a0aec0',
112
+ });
113
+
114
+ const customTheme = initialIsDark ? darkTheme : lightTheme;
115
+
116
+ // Hide the addon panel globally (Storybook 8+/10 API)
117
+ addons.setConfig({
118
+ bottomPanelHeight: 0,
119
+ layoutCustomisations: {
120
+ showPanel: () => false,
121
+ },
122
+ theme: customTheme,
123
+ });
124
+
125
+ // Set default story to Design System Overview if no path specified
126
+ if (!urlParams.has('path')) {
127
+ const newUrl = new URL(window.location.href);
128
+ newUrl.searchParams.set('path', '/story/design-system-overview--default');
129
+ window.history.replaceState({}, '', newUrl.toString());
130
+ }
131
+
132
+ // Register addon to handle navigation sync and theme after Storybook is ready
133
+ addons.register('url-sync', (api) => {
134
+ const channel = api.getChannel();
135
+ if (!channel) return;
136
+
137
+ // Set initial dark mode state (pass string "dark" or "light", not boolean)
138
+ if (initialIsDark) {
139
+ channel.emit(UPDATE_DARK_MODE_EVENT_NAME, 'dark');
140
+ }
141
+
142
+ // Report navigation changes to parent window for URL bar sync
143
+ channel.on(STORY_CHANGED, (storyId: string) => {
144
+ if (window.parent !== window) {
145
+ window.parent.postMessage({ type: 'storybook-navigation', storyId }, '*');
146
+ }
147
+ });
148
+
149
+ // Listen for theme changes from parent window
150
+ window.addEventListener('message', (event) => {
151
+ if (event.data?.type === 'storybook-theme-change' && event.data?.theme) {
152
+ const isDark = event.data.theme === 'dark';
153
+ // Update the dark mode addon
154
+ channel.emit(UPDATE_DARK_MODE_EVENT_NAME, event.data.theme);
155
+ // Update the Storybook manager theme
156
+ addons.setConfig({
157
+ theme: isDark ? darkTheme : lightTheme,
158
+ });
159
+ // Update CSS theme selector and background
160
+ document.documentElement.dataset.theme = isDark ? 'dark' : 'light';
161
+ document.documentElement.style.backgroundColor = isDark ? '#1a1f2e' : '#f0f3f9';
162
+ document.documentElement.style.colorScheme = isDark ? 'dark' : 'light';
163
+ }
164
+ });
165
+ });
@@ -0,0 +1,31 @@
1
+ <script>
2
+ (function() {
3
+ var isDark = false;
4
+ var stored, parsed, urlParams, urlTheme;
5
+ try {
6
+ stored = localStorage.getItem('sb-addon-themes-3');
7
+ if (stored) {
8
+ parsed = JSON.parse(stored);
9
+ isDark = parsed && parsed.current === 'dark';
10
+ }
11
+ } catch(_) {}
12
+
13
+ urlParams = new URLSearchParams(window.location.search);
14
+ urlTheme = urlParams.get('theme');
15
+ if (urlTheme) {
16
+ isDark = urlTheme === 'dark';
17
+ }
18
+
19
+ if (isDark) {
20
+ document.documentElement.classList.add('dark');
21
+ }
22
+ // Dark: appContentBg=#222325, Light: #FFFFFF
23
+ document.documentElement.style.backgroundColor = isDark ? '#222325' : '#FFFFFF';
24
+ document.documentElement.style.colorScheme = isDark ? 'dark' : 'light';
25
+ })();
26
+ </script>
27
+ <style>
28
+ html, body {
29
+ transition: none;
30
+ }
31
+ </style>
@@ -1,9 +1,51 @@
1
1
  import type { Preview } from '@storybook/react-vite';
2
+ import type { PropsWithChildren } from 'react';
3
+ import { useEffect, useState } from 'react';
4
+ import { addons } from 'storybook/preview-api';
5
+ import { themes } from 'storybook/theming';
6
+ import { DocsContainer } from '@storybook/addon-docs/blocks';
2
7
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
8
+ import { DARK_MODE_EVENT_NAME } from '@vueless/storybook-dark-mode';
3
9
  import { initialize, mswLoader } from 'msw-storybook-addon';
4
10
  import '../src/index.css';
5
11
 
6
- initialize();
12
+ initialize({
13
+ onUnhandledRequest: 'bypass',
14
+ });
15
+
16
+ // Apply theme to the preview iframe (for component styling and background)
17
+ const applyTheme = (isDark: boolean) => {
18
+ if (isDark) {
19
+ document.documentElement.classList.add('dark');
20
+ } else {
21
+ document.documentElement.classList.remove('dark');
22
+ }
23
+ // Update background color to match Storybook theme
24
+ document.documentElement.style.backgroundColor = isDark ? '#222325' : '#FFFFFF';
25
+ document.documentElement.style.colorScheme = isDark ? 'dark' : 'light';
26
+ };
27
+
28
+ // Get initial theme from URL parameter or localStorage
29
+ const urlParams = new URLSearchParams(window.location.search);
30
+ const urlTheme = urlParams.get('theme');
31
+ const getStoredDarkMode = (): boolean => {
32
+ try {
33
+ const stored = localStorage.getItem('sb-addon-themes-3');
34
+ if (stored) {
35
+ const parsed = JSON.parse(stored);
36
+ return parsed?.current === 'dark';
37
+ }
38
+ } catch {}
39
+ return false;
40
+ };
41
+ const initialIsDark = urlTheme ? urlTheme === 'dark' : getStoredDarkMode();
42
+ applyTheme(initialIsDark);
43
+
44
+ // Listen to dark mode addon changes and sync with our CSS class
45
+ const channel = addons.getChannel();
46
+ channel.on(DARK_MODE_EVENT_NAME, (isDark: boolean) => {
47
+ applyTheme(isDark);
48
+ });
7
49
 
8
50
  const queryClient = new QueryClient({
9
51
  defaultOptions: {
@@ -13,7 +55,28 @@ const queryClient = new QueryClient({
13
55
  },
14
56
  });
15
57
 
58
+ // Themed docs container that responds to dark mode
59
+ function ThemedDocsContainer({
60
+ children,
61
+ context,
62
+ }: PropsWithChildren<{ context: Parameters<typeof DocsContainer>[0]['context'] }>) {
63
+ const [isDark, setIsDark] = useState(initialIsDark);
64
+
65
+ useEffect(() => {
66
+ const ch = addons.getChannel();
67
+ ch.on(DARK_MODE_EVENT_NAME, setIsDark);
68
+ return () => ch.off(DARK_MODE_EVENT_NAME, setIsDark);
69
+ }, []);
70
+
71
+ return (
72
+ <DocsContainer context={context} theme={isDark ? themes.dark : themes.light}>
73
+ {children}
74
+ </DocsContainer>
75
+ );
76
+ }
77
+
16
78
  const preview: Preview = {
79
+ tags: ['autodocs'],
17
80
  decorators: [
18
81
  (Story) => (
19
82
  <QueryClientProvider client={queryClient}>
@@ -33,10 +96,20 @@ const preview: Preview = {
33
96
  },
34
97
  layout: 'padded',
35
98
  options: {
99
+ showPanel: false,
36
100
  storySort: {
37
- order: ['Design System', 'UI Components'],
101
+ order: ['Design System', ['Overview', '*'], 'UI Components'],
38
102
  },
39
103
  },
104
+ darkMode: {
105
+ current: initialIsDark ? 'dark' : 'light',
106
+ stylePreview: true,
107
+ dark: themes.dark,
108
+ light: themes.light,
109
+ },
110
+ docs: {
111
+ container: ThemedDocsContainer,
112
+ },
40
113
  },
41
114
  initialGlobals: {
42
115
  showPanel: false,
@@ -9,6 +9,7 @@
9
9
  "preview": "vite preview",
10
10
  "type-check": "tsc --noEmit -p tsconfig.app.json",
11
11
  "storybook": "storybook dev -p 6006",
12
+ "storybook:fast": "STORYBOOK_FAST=1 storybook dev -p 6006",
12
13
  "build-storybook": "storybook build"
13
14
  },
14
15
  "dependencies": {
@@ -20,6 +21,7 @@
20
21
  "cmdk": "^1.1.1",
21
22
  "date-fns": "^4.1.0",
22
23
  "embla-carousel-react": "^8.6.0",
24
+ "graphql-request": "^7.4.0",
23
25
  "input-otp": "^1.4.2",
24
26
  "lucide-react": "^0.539.0",
25
27
  "next-themes": "^0.4.6",
@@ -44,6 +46,7 @@
44
46
  "@types/react": "^19.2.7",
45
47
  "@types/react-dom": "^19.2.3",
46
48
  "@vitejs/plugin-react-swc": "^4.2.2",
49
+ "@vueless/storybook-dark-mode": "^10.0.7",
47
50
  "msw": "^2.12.10",
48
51
  "msw-storybook-addon": "^2.0.6",
49
52
  "storybook": "^10.2.8",