specweave 1.0.262 → 1.0.264
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/CLAUDE.md +31 -27
- package/dist/src/cli/commands/docs.js +4 -4
- package/dist/src/cli/commands/docs.js.map +1 -1
- package/dist/src/dashboard/server/dashboard-server.d.ts.map +1 -1
- package/dist/src/dashboard/server/dashboard-server.js +2 -1
- package/dist/src/dashboard/server/dashboard-server.js.map +1 -1
- package/dist/src/dashboard/server/data/dashboard-data-aggregator.d.ts +9 -1
- package/dist/src/dashboard/server/data/dashboard-data-aggregator.d.ts.map +1 -1
- package/dist/src/dashboard/server/data/dashboard-data-aggregator.js +140 -13
- package/dist/src/dashboard/server/data/dashboard-data-aggregator.js.map +1 -1
- package/dist/src/dashboard/server/data/plugin-scanner.d.ts +1 -1
- package/dist/src/dashboard/server/data/plugin-scanner.d.ts.map +1 -1
- package/dist/src/dashboard/server/data/plugin-scanner.js +2 -2
- package/dist/src/dashboard/server/data/plugin-scanner.js.map +1 -1
- package/dist/src/utils/docs-preview/config-generator.d.ts +14 -6
- package/dist/src/utils/docs-preview/config-generator.d.ts.map +1 -1
- package/dist/src/utils/docs-preview/config-generator.js +504 -126
- package/dist/src/utils/docs-preview/config-generator.js.map +1 -1
- package/dist/src/utils/docs-preview/docusaurus-setup.d.ts +1 -1
- package/dist/src/utils/docs-preview/docusaurus-setup.d.ts.map +1 -1
- package/dist/src/utils/docs-preview/docusaurus-setup.js +92 -48
- package/dist/src/utils/docs-preview/docusaurus-setup.js.map +1 -1
- package/dist/src/utils/docs-preview/index.d.ts +2 -1
- package/dist/src/utils/docs-preview/index.d.ts.map +1 -1
- package/dist/src/utils/docs-preview/index.js +2 -1
- package/dist/src/utils/docs-preview/index.js.map +1 -1
- package/dist/src/utils/docs-preview/project-detector.d.ts +16 -0
- package/dist/src/utils/docs-preview/project-detector.d.ts.map +1 -0
- package/dist/src/utils/docs-preview/project-detector.js +215 -0
- package/dist/src/utils/docs-preview/project-detector.js.map +1 -0
- package/dist/src/utils/docs-preview/types.d.ts +26 -0
- package/dist/src/utils/docs-preview/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/hooks/hooks.json +9 -0
- package/plugins/specweave/hooks/v2/dispatchers/post-tool-use-analytics.sh +83 -0
- package/plugins/specweave/scripts/progress.js +148 -50
- package/plugins/specweave/scripts/read-progress.sh +128 -52
- package/plugins/specweave/scripts/rebuild-dashboard-cache.sh +23 -17
- package/plugins/specweave/scripts/track-analytics.sh +4 -0
- package/plugins/specweave/skills/progress/SKILL.md +7 -21
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Docusaurus configuration generator
|
|
3
|
-
* Generates docusaurus.config.js with
|
|
3
|
+
* Generates docusaurus.config.js with professional defaults
|
|
4
4
|
*/
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import * as fs from '../../utils/fs-native.js';
|
|
@@ -8,10 +8,23 @@ import * as fs from '../../utils/fs-native.js';
|
|
|
8
8
|
* Generate docusaurus.config.js content
|
|
9
9
|
*/
|
|
10
10
|
export function generateDocusaurusConfig(config) {
|
|
11
|
-
const { title, tagline, url, baseUrl, docsPath
|
|
11
|
+
const { title, tagline, url, baseUrl, docsPath } = config;
|
|
12
|
+
const projectName = config.projectMetadata?.name || title;
|
|
13
|
+
// Generate footer links from detected categories (max 4)
|
|
14
|
+
const categories = config.projectMetadata?.categories || [];
|
|
15
|
+
const footerItems = categories.slice(0, 4).map(cat => ` {\n label: '${cat.label}',\n to: '/${cat.id}',\n }`).join(',\n');
|
|
16
|
+
const footerLinksBlock = footerItems
|
|
17
|
+
? `[
|
|
18
|
+
{
|
|
19
|
+
title: 'Documentation',
|
|
20
|
+
items: [
|
|
21
|
+
${footerItems},
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
]`
|
|
25
|
+
: `[]`;
|
|
12
26
|
return `// @ts-check
|
|
13
|
-
//
|
|
14
|
-
// Auto-generated by SpecWeave docs-preview plugin
|
|
27
|
+
// Auto-generated documentation site configuration
|
|
15
28
|
// Generated: ${new Date().toISOString()}
|
|
16
29
|
|
|
17
30
|
import {themes as prismThemes} from 'prism-react-renderer';
|
|
@@ -19,17 +32,13 @@ import {themes as prismThemes} from 'prism-react-renderer';
|
|
|
19
32
|
/** @type {import('@docusaurus/types').Config} */
|
|
20
33
|
const config = {
|
|
21
34
|
title: '${title}',
|
|
22
|
-
tagline: '${tagline}',
|
|
23
|
-
favicon: 'img/favicon.
|
|
35
|
+
tagline: '${escapeQuotes(tagline)}',
|
|
36
|
+
favicon: 'img/favicon.svg',
|
|
24
37
|
|
|
25
38
|
// Production URL
|
|
26
39
|
url: '${url}',
|
|
27
40
|
baseUrl: '${baseUrl}',
|
|
28
41
|
|
|
29
|
-
// GitHub Pages deployment config
|
|
30
|
-
organizationName: 'your-org',
|
|
31
|
-
projectName: 'your-repo',
|
|
32
|
-
|
|
33
42
|
onBrokenLinks: 'warn',
|
|
34
43
|
onBrokenMarkdownLinks: 'warn',
|
|
35
44
|
onBrokenAnchors: 'warn',
|
|
@@ -49,17 +58,14 @@ const config = {
|
|
|
49
58
|
routeBasePath: '/',
|
|
50
59
|
path: '${docsPath}',
|
|
51
60
|
sidebarPath: './sidebars.js',
|
|
52
|
-
editUrl: undefined,
|
|
53
|
-
// CRITICAL: Override default exclude to include _ folders (_archive, _orphans, etc.)
|
|
54
|
-
// Docusaurus default excludes: ['**/_*.{js,jsx,ts,tsx,md,mdx}', '**/_*/**', '**/__tests__/**']
|
|
55
|
-
// We want ALL folders and files visible, so we set exclude to empty array
|
|
61
|
+
editUrl: undefined,
|
|
56
62
|
exclude: [],
|
|
57
63
|
remarkPlugins: [],
|
|
58
64
|
rehypePlugins: [],
|
|
59
65
|
beforeDefaultRemarkPlugins: [],
|
|
60
66
|
beforeDefaultRehypePlugins: [],
|
|
61
67
|
},
|
|
62
|
-
blog: false,
|
|
68
|
+
blog: false,
|
|
63
69
|
theme: {
|
|
64
70
|
customCss: './src/css/custom.css',
|
|
65
71
|
},
|
|
@@ -70,13 +76,10 @@ const config = {
|
|
|
70
76
|
themeConfig:
|
|
71
77
|
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
|
|
72
78
|
({
|
|
73
|
-
// Social card image (optional)
|
|
74
|
-
image: 'img/docusaurus-social-card.jpg',
|
|
75
|
-
|
|
76
79
|
navbar: {
|
|
77
80
|
title: '${title}',
|
|
78
81
|
logo: {
|
|
79
|
-
alt: '${
|
|
82
|
+
alt: '${projectName} Logo',
|
|
80
83
|
src: 'img/logo.svg',
|
|
81
84
|
},
|
|
82
85
|
items: [
|
|
@@ -91,22 +94,8 @@ const config = {
|
|
|
91
94
|
|
|
92
95
|
footer: {
|
|
93
96
|
style: 'dark',
|
|
94
|
-
links:
|
|
95
|
-
|
|
96
|
-
title: 'Documentation',
|
|
97
|
-
items: [
|
|
98
|
-
{
|
|
99
|
-
label: 'Strategy',
|
|
100
|
-
to: '/strategy',
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
label: 'Architecture',
|
|
104
|
-
to: '/architecture',
|
|
105
|
-
},
|
|
106
|
-
],
|
|
107
|
-
},
|
|
108
|
-
],
|
|
109
|
-
copyright: \`Copyright © \${new Date().getFullYear()} SpecWeave. Built with Docusaurus.\`,
|
|
97
|
+
links: ${footerLinksBlock},
|
|
98
|
+
copyright: \`Copyright \u00a9 \${new Date().getFullYear()} ${escapeQuotes(projectName)}. Built with Docusaurus.\`,
|
|
110
99
|
},
|
|
111
100
|
|
|
112
101
|
prism: {
|
|
@@ -114,10 +103,14 @@ const config = {
|
|
|
114
103
|
darkTheme: prismThemes.dracula,
|
|
115
104
|
additionalLanguages: ['bash', 'typescript', 'javascript', 'json', 'yaml'],
|
|
116
105
|
},
|
|
106
|
+
|
|
107
|
+
colorMode: {
|
|
108
|
+
defaultMode: 'light',
|
|
109
|
+
respectPrefersColorScheme: true,
|
|
110
|
+
},
|
|
117
111
|
}),
|
|
118
112
|
|
|
119
113
|
// Mermaid diagrams support
|
|
120
|
-
// Use 'md' format since SpecWeave docs are .md files, not .mdx
|
|
121
114
|
markdown: {
|
|
122
115
|
mermaid: true,
|
|
123
116
|
format: 'md',
|
|
@@ -142,7 +135,7 @@ export async function writeDocusaurusConfig(targetDir, config) {
|
|
|
142
135
|
*/
|
|
143
136
|
export function generatePackageJSON(title) {
|
|
144
137
|
return JSON.stringify({
|
|
145
|
-
name: '
|
|
138
|
+
name: 'docs-site',
|
|
146
139
|
version: '1.0.0',
|
|
147
140
|
description: `${title} - Documentation Site`,
|
|
148
141
|
private: true,
|
|
@@ -186,83 +179,340 @@ export async function writePackageJSON(targetDir, title) {
|
|
|
186
179
|
await fs.writeFile(packagePath, content, 'utf-8');
|
|
187
180
|
}
|
|
188
181
|
/**
|
|
189
|
-
* Generate
|
|
182
|
+
* Generate a professional SVG logo from project initials
|
|
183
|
+
*/
|
|
184
|
+
export function generateLogoSVG(initials, primaryColor = '#4f46e5') {
|
|
185
|
+
const darkerColor = darkenColor(primaryColor, 20);
|
|
186
|
+
const fontSize = initials.length > 1 ? 76 : 90;
|
|
187
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="200" height="200">
|
|
188
|
+
<defs>
|
|
189
|
+
<linearGradient id="logo-bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
190
|
+
<stop offset="0%" style="stop-color:${primaryColor}" />
|
|
191
|
+
<stop offset="100%" style="stop-color:${darkerColor}" />
|
|
192
|
+
</linearGradient>
|
|
193
|
+
</defs>
|
|
194
|
+
<rect x="8" y="8" width="184" height="184" rx="44" ry="44" fill="url(#logo-bg)" />
|
|
195
|
+
<text x="100" y="100" font-family="system-ui, -apple-system, 'Segoe UI', sans-serif"
|
|
196
|
+
font-size="${fontSize}" font-weight="700" fill="white"
|
|
197
|
+
text-anchor="middle" dominant-baseline="central" letter-spacing="-2">${initials}</text>
|
|
198
|
+
</svg>`;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Generate a favicon SVG (simplified, optimized for small sizes)
|
|
202
|
+
*/
|
|
203
|
+
export function generateFaviconSVG(initials, primaryColor = '#4f46e5') {
|
|
204
|
+
const firstChar = initials.charAt(0);
|
|
205
|
+
const darkerColor = darkenColor(primaryColor, 20);
|
|
206
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
|
207
|
+
<defs>
|
|
208
|
+
<linearGradient id="fav-bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
209
|
+
<stop offset="0%" style="stop-color:${primaryColor}" />
|
|
210
|
+
<stop offset="100%" style="stop-color:${darkerColor}" />
|
|
211
|
+
</linearGradient>
|
|
212
|
+
</defs>
|
|
213
|
+
<rect x="1" y="1" width="30" height="30" rx="7" ry="7" fill="url(#fav-bg)" />
|
|
214
|
+
<text x="16" y="16" font-family="system-ui, sans-serif"
|
|
215
|
+
font-size="18" font-weight="700" fill="white"
|
|
216
|
+
text-anchor="middle" dominant-baseline="central">${firstChar}</text>
|
|
217
|
+
</svg>`;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Generate custom CSS for professional theme
|
|
190
221
|
*/
|
|
191
222
|
export function generateCustomCSS(theme) {
|
|
192
223
|
const themes = {
|
|
193
|
-
default:
|
|
224
|
+
default: {
|
|
225
|
+
light: `
|
|
226
|
+
--ifm-color-primary: #4f46e5;
|
|
227
|
+
--ifm-color-primary-dark: #4338ca;
|
|
228
|
+
--ifm-color-primary-darker: #3730a3;
|
|
229
|
+
--ifm-color-primary-darkest: #312e81;
|
|
230
|
+
--ifm-color-primary-light: #6366f1;
|
|
231
|
+
--ifm-color-primary-lighter: #818cf8;
|
|
232
|
+
--ifm-color-primary-lightest: #a5b4fc;`,
|
|
233
|
+
dark: `
|
|
234
|
+
--ifm-color-primary: #818cf8;
|
|
235
|
+
--ifm-color-primary-dark: #6366f1;
|
|
236
|
+
--ifm-color-primary-darker: #4f46e5;
|
|
237
|
+
--ifm-color-primary-darkest: #4338ca;
|
|
238
|
+
--ifm-color-primary-light: #a5b4fc;
|
|
239
|
+
--ifm-color-primary-lighter: #c7d2fe;
|
|
240
|
+
--ifm-color-primary-lightest: #e0e7ff;`,
|
|
241
|
+
},
|
|
242
|
+
classic: {
|
|
243
|
+
light: `
|
|
244
|
+
--ifm-color-primary: #2563eb;
|
|
245
|
+
--ifm-color-primary-dark: #1d4ed8;
|
|
246
|
+
--ifm-color-primary-darker: #1e40af;
|
|
247
|
+
--ifm-color-primary-darkest: #1e3a8a;
|
|
248
|
+
--ifm-color-primary-light: #3b82f6;
|
|
249
|
+
--ifm-color-primary-lighter: #60a5fa;
|
|
250
|
+
--ifm-color-primary-lightest: #93bbfd;`,
|
|
251
|
+
dark: `
|
|
252
|
+
--ifm-color-primary: #60a5fa;
|
|
253
|
+
--ifm-color-primary-dark: #3b82f6;
|
|
254
|
+
--ifm-color-primary-darker: #2563eb;
|
|
255
|
+
--ifm-color-primary-darkest: #1d4ed8;
|
|
256
|
+
--ifm-color-primary-light: #93bbfd;
|
|
257
|
+
--ifm-color-primary-lighter: #bfdbfe;
|
|
258
|
+
--ifm-color-primary-lightest: #dbeafe;`,
|
|
259
|
+
},
|
|
260
|
+
dark: {
|
|
261
|
+
light: `
|
|
262
|
+
--ifm-color-primary: #6366f1;
|
|
263
|
+
--ifm-color-primary-dark: #4f46e5;
|
|
264
|
+
--ifm-color-primary-darker: #4338ca;
|
|
265
|
+
--ifm-color-primary-darkest: #3730a3;
|
|
266
|
+
--ifm-color-primary-light: #818cf8;
|
|
267
|
+
--ifm-color-primary-lighter: #a5b4fc;
|
|
268
|
+
--ifm-color-primary-lightest: #c7d2fe;`,
|
|
269
|
+
dark: `
|
|
270
|
+
--ifm-color-primary: #a5b4fc;
|
|
271
|
+
--ifm-color-primary-dark: #818cf8;
|
|
272
|
+
--ifm-color-primary-darker: #6366f1;
|
|
273
|
+
--ifm-color-primary-darkest: #4f46e5;
|
|
274
|
+
--ifm-color-primary-light: #c7d2fe;
|
|
275
|
+
--ifm-color-primary-lighter: #e0e7ff;
|
|
276
|
+
--ifm-color-primary-lightest: #eef2ff;`,
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
const selected = themes[theme] || themes.default;
|
|
280
|
+
return `/**
|
|
281
|
+
* Professional documentation theme
|
|
282
|
+
* Auto-generated — customize as needed
|
|
283
|
+
*/
|
|
284
|
+
|
|
285
|
+
/* ===== Color Palette ===== */
|
|
194
286
|
:root {
|
|
195
|
-
|
|
196
|
-
--ifm-color-primary-dark: #29784c;
|
|
197
|
-
--ifm-color-primary-darker: #277148;
|
|
198
|
-
--ifm-color-primary-darkest: #205d3b;
|
|
199
|
-
--ifm-color-primary-light: #33925d;
|
|
200
|
-
--ifm-color-primary-lighter: #359962;
|
|
201
|
-
--ifm-color-primary-lightest: #3cad6e;
|
|
287
|
+
${selected.light}
|
|
202
288
|
--ifm-code-font-size: 95%;
|
|
203
|
-
--
|
|
289
|
+
--ifm-heading-font-weight: 600;
|
|
290
|
+
--ifm-font-size-base: 16px;
|
|
291
|
+
--ifm-line-height-base: 1.65;
|
|
292
|
+
--docusaurus-highlighted-code-line-bg: rgba(79, 70, 229, 0.1);
|
|
204
293
|
}
|
|
205
294
|
|
|
206
295
|
[data-theme='dark'] {
|
|
207
|
-
|
|
208
|
-
--
|
|
209
|
-
--ifm-color-primary-darker: #1fa588;
|
|
210
|
-
--ifm-color-primary-darkest: #1a8870;
|
|
211
|
-
--ifm-color-primary-light: #29d5b0;
|
|
212
|
-
--ifm-color-primary-lighter: #32d8b4;
|
|
213
|
-
--ifm-color-primary-lightest: #4fddbf;
|
|
214
|
-
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
|
|
215
|
-
}
|
|
216
|
-
`,
|
|
217
|
-
classic: `
|
|
218
|
-
:root {
|
|
219
|
-
--ifm-color-primary: #0066cc;
|
|
220
|
-
--ifm-color-primary-dark: #005cb8;
|
|
221
|
-
--ifm-color-primary-darker: #0056ad;
|
|
222
|
-
--ifm-color-primary-darkest: #00478f;
|
|
223
|
-
--ifm-color-primary-light: #0070e0;
|
|
224
|
-
--ifm-color-primary-lighter: #0076eb;
|
|
225
|
-
--ifm-color-primary-lightest: #1a85ff;
|
|
226
|
-
--ifm-code-font-size: 95%;
|
|
296
|
+
${selected.dark}
|
|
297
|
+
--docusaurus-highlighted-code-line-bg: rgba(99, 102, 241, 0.15);
|
|
227
298
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
--ifm-background-color: #0d1117;
|
|
233
|
-
--ifm-code-font-size: 95%;
|
|
299
|
+
|
|
300
|
+
/* ===== Global ===== */
|
|
301
|
+
* {
|
|
302
|
+
transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
|
|
234
303
|
}
|
|
235
304
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
--ifm-background-color: #0d1117;
|
|
305
|
+
html {
|
|
306
|
+
scroll-behavior: smooth;
|
|
239
307
|
}
|
|
240
|
-
`
|
|
241
|
-
};
|
|
242
|
-
return `/**
|
|
243
|
-
* Custom CSS for SpecWeave documentation
|
|
244
|
-
* Theme: ${theme}
|
|
245
|
-
* Auto-generated by SpecWeave docs-preview plugin
|
|
246
|
-
*/
|
|
247
308
|
|
|
248
|
-
|
|
309
|
+
/* ===== Navbar ===== */
|
|
310
|
+
.navbar {
|
|
311
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
|
|
312
|
+
border-bottom: 1px solid var(--ifm-color-emphasis-200);
|
|
313
|
+
backdrop-filter: blur(8px);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.navbar__title {
|
|
317
|
+
font-weight: 700;
|
|
318
|
+
letter-spacing: -0.01em;
|
|
319
|
+
}
|
|
249
320
|
|
|
250
|
-
|
|
321
|
+
.navbar__logo img {
|
|
322
|
+
border-radius: 8px;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/* ===== Sidebar ===== */
|
|
326
|
+
.theme-doc-sidebar-container {
|
|
327
|
+
border-right: 1px solid var(--ifm-color-emphasis-200);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.menu__link {
|
|
331
|
+
border-radius: 6px;
|
|
332
|
+
font-size: 0.9rem;
|
|
333
|
+
padding: 0.4rem 0.75rem;
|
|
334
|
+
transition: all 0.15s ease;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.menu__link:hover {
|
|
338
|
+
background: var(--ifm-color-emphasis-100);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.menu__link--active {
|
|
342
|
+
font-weight: 600;
|
|
343
|
+
color: var(--ifm-color-primary);
|
|
344
|
+
background: var(--ifm-color-primary-lightest);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
[data-theme='dark'] .menu__link--active {
|
|
348
|
+
background: rgba(99, 102, 241, 0.12);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.menu__list-item-collapsible .menu__caret::before {
|
|
352
|
+
filter: var(--ifm-menu-color-active);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/* ===== Content ===== */
|
|
251
356
|
.markdown {
|
|
252
357
|
--ifm-h1-font-size: 2rem;
|
|
253
358
|
--ifm-h2-font-size: 1.5rem;
|
|
254
359
|
--ifm-h3-font-size: 1.25rem;
|
|
255
360
|
}
|
|
256
361
|
|
|
257
|
-
|
|
362
|
+
.markdown h1, .markdown h2, .markdown h3 {
|
|
363
|
+
letter-spacing: -0.02em;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.markdown h2 {
|
|
367
|
+
margin-top: 2.5rem;
|
|
368
|
+
padding-bottom: 0.5rem;
|
|
369
|
+
border-bottom: 1px solid var(--ifm-color-emphasis-200);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/* ===== Links ===== */
|
|
373
|
+
.markdown a {
|
|
374
|
+
text-decoration: none;
|
|
375
|
+
border-bottom: 1px solid transparent;
|
|
376
|
+
transition: border-color 0.15s ease;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.markdown a:hover {
|
|
380
|
+
border-bottom-color: var(--ifm-color-primary);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/* ===== Code Blocks ===== */
|
|
258
384
|
.prism-code {
|
|
259
|
-
font-size: 0.
|
|
385
|
+
font-size: 0.875rem;
|
|
386
|
+
border-radius: 8px;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
pre {
|
|
390
|
+
border-radius: 8px !important;
|
|
391
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
[data-theme='dark'] pre {
|
|
395
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
code {
|
|
399
|
+
border-radius: 4px;
|
|
400
|
+
padding: 2px 6px;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/* ===== Tables ===== */
|
|
404
|
+
table {
|
|
405
|
+
display: table;
|
|
406
|
+
width: 100%;
|
|
407
|
+
border-collapse: separate;
|
|
408
|
+
border-spacing: 0;
|
|
409
|
+
border-radius: 8px;
|
|
410
|
+
overflow: hidden;
|
|
411
|
+
border: 1px solid var(--ifm-color-emphasis-200);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
table thead tr {
|
|
415
|
+
background: var(--ifm-color-emphasis-100);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
table thead th {
|
|
419
|
+
font-weight: 600;
|
|
420
|
+
font-size: 0.875rem;
|
|
421
|
+
text-transform: uppercase;
|
|
422
|
+
letter-spacing: 0.03em;
|
|
423
|
+
padding: 0.75rem 1rem;
|
|
424
|
+
border-bottom: 2px solid var(--ifm-color-emphasis-200);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
table tbody td {
|
|
428
|
+
padding: 0.65rem 1rem;
|
|
429
|
+
border-bottom: 1px solid var(--ifm-color-emphasis-100);
|
|
260
430
|
}
|
|
261
431
|
|
|
262
|
-
|
|
432
|
+
table tbody tr:last-child td {
|
|
433
|
+
border-bottom: none;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
table tbody tr:hover {
|
|
437
|
+
background: var(--ifm-color-emphasis-50, rgba(0, 0, 0, 0.02));
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/* ===== Blockquotes ===== */
|
|
441
|
+
blockquote {
|
|
442
|
+
border-left: 4px solid var(--ifm-color-primary);
|
|
443
|
+
background: var(--ifm-color-emphasis-100);
|
|
444
|
+
border-radius: 0 8px 8px 0;
|
|
445
|
+
padding: 1rem 1.25rem;
|
|
446
|
+
font-style: normal;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/* ===== Admonitions ===== */
|
|
450
|
+
.admonition {
|
|
451
|
+
border-radius: 8px;
|
|
452
|
+
border: none;
|
|
453
|
+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/* ===== Cards (prev/next navigation) ===== */
|
|
457
|
+
.pagination-nav__link {
|
|
458
|
+
border-radius: 10px;
|
|
459
|
+
border: 1px solid var(--ifm-color-emphasis-200);
|
|
460
|
+
transition: all 0.2s ease;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.pagination-nav__link:hover {
|
|
464
|
+
border-color: var(--ifm-color-primary);
|
|
465
|
+
box-shadow: 0 4px 16px rgba(79, 70, 229, 0.1);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/* ===== Mermaid ===== */
|
|
263
469
|
.docusaurus-mermaid-container {
|
|
264
470
|
text-align: center;
|
|
265
471
|
margin: 2rem 0;
|
|
472
|
+
padding: 1rem;
|
|
473
|
+
background: var(--ifm-color-emphasis-100);
|
|
474
|
+
border-radius: 8px;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/* ===== Table of Contents ===== */
|
|
478
|
+
.table-of-contents__link--active {
|
|
479
|
+
font-weight: 600;
|
|
480
|
+
color: var(--ifm-color-primary);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/* ===== Footer ===== */
|
|
484
|
+
.footer--dark {
|
|
485
|
+
background: #1e1e2e;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
[data-theme='dark'] .footer--dark {
|
|
489
|
+
background: #111118;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/* ===== Scrollbar ===== */
|
|
493
|
+
::-webkit-scrollbar {
|
|
494
|
+
width: 6px;
|
|
495
|
+
height: 6px;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
::-webkit-scrollbar-track {
|
|
499
|
+
background: transparent;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
::-webkit-scrollbar-thumb {
|
|
503
|
+
background: var(--ifm-color-emphasis-300);
|
|
504
|
+
border-radius: 3px;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
::-webkit-scrollbar-thumb:hover {
|
|
508
|
+
background: var(--ifm-color-emphasis-500);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/* ===== Responsive ===== */
|
|
512
|
+
@media screen and (max-width: 996px) {
|
|
513
|
+
.markdown h2 {
|
|
514
|
+
margin-top: 2rem;
|
|
515
|
+
}
|
|
266
516
|
}
|
|
267
517
|
`;
|
|
268
518
|
}
|
|
@@ -276,9 +526,20 @@ export async function writeCustomCSS(targetDir, theme) {
|
|
|
276
526
|
await fs.writeFile(cssPath, content, 'utf-8');
|
|
277
527
|
}
|
|
278
528
|
/**
|
|
279
|
-
* Generate index page (landing page)
|
|
529
|
+
* Generate index page (landing page) with dynamic categories
|
|
280
530
|
*/
|
|
281
|
-
export function generateIndexPage(title, tagline) {
|
|
531
|
+
export function generateIndexPage(title, tagline, categories) {
|
|
532
|
+
const firstCategoryLink = categories.length > 0 ? `/${categories[0].id}` : '/';
|
|
533
|
+
// Build category cards JSX
|
|
534
|
+
const categoryCards = categories.map(cat => {
|
|
535
|
+
const escapedDesc = escapeQuotes(cat.description);
|
|
536
|
+
return ` <a href="${cat.id}" className={styles.categoryCard} key="${cat.id}">
|
|
537
|
+
<span className={styles.categoryIcon}>${cat.icon}</span>
|
|
538
|
+
<h3>${cat.label}</h3>
|
|
539
|
+
<p>${escapedDesc}</p>
|
|
540
|
+
<span className={styles.docCount}>${cat.docCount} document${cat.docCount !== 1 ? 's' : ''}</span>
|
|
541
|
+
</a>`;
|
|
542
|
+
}).join('\n');
|
|
282
543
|
return `import React from 'react';
|
|
283
544
|
import clsx from 'clsx';
|
|
284
545
|
import Link from '@docusaurus/Link';
|
|
@@ -289,15 +550,15 @@ import styles from './index.module.css';
|
|
|
289
550
|
function HomepageHeader() {
|
|
290
551
|
const {siteConfig} = useDocusaurusContext();
|
|
291
552
|
return (
|
|
292
|
-
<header className={clsx('hero
|
|
553
|
+
<header className={clsx('hero', styles.heroBanner)}>
|
|
293
554
|
<div className="container">
|
|
294
|
-
<h1 className=
|
|
295
|
-
<p className=
|
|
555
|
+
<h1 className={styles.heroTitle}>{siteConfig.title}</h1>
|
|
556
|
+
<p className={styles.heroSubtitle}>{siteConfig.tagline}</p>
|
|
296
557
|
<div className={styles.buttons}>
|
|
297
558
|
<Link
|
|
298
|
-
className="button button--
|
|
299
|
-
to="
|
|
300
|
-
|
|
559
|
+
className="button button--primary button--lg"
|
|
560
|
+
to="${firstCategoryLink}">
|
|
561
|
+
Browse Documentation
|
|
301
562
|
</Link>
|
|
302
563
|
</div>
|
|
303
564
|
</div>
|
|
@@ -309,31 +570,14 @@ export default function Home() {
|
|
|
309
570
|
const {siteConfig} = useDocusaurusContext();
|
|
310
571
|
return (
|
|
311
572
|
<Layout
|
|
312
|
-
title={
|
|
313
|
-
description="${tagline}">
|
|
573
|
+
title={siteConfig.title}
|
|
574
|
+
description="${escapeQuotes(tagline)}">
|
|
314
575
|
<HomepageHeader />
|
|
315
576
|
<main>
|
|
316
|
-
<div className="container" style={{
|
|
317
|
-
<div className=
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
<p>
|
|
321
|
-
This is your SpecWeave documentation site, automatically generated from your
|
|
322
|
-
<code>.specweave/docs/</code> folder.
|
|
323
|
-
</p>
|
|
324
|
-
<p>
|
|
325
|
-
Use the sidebar to navigate through your documentation:
|
|
326
|
-
</p>
|
|
327
|
-
<ul>
|
|
328
|
-
<li><strong>Strategy</strong>: Business rationale, PRDs, OKRs</li>
|
|
329
|
-
<li><strong>Specs</strong>: Feature specifications and user stories</li>
|
|
330
|
-
<li><strong>Architecture</strong>: Technical design, ADRs, diagrams</li>
|
|
331
|
-
<li><strong>Delivery</strong>: Build & release processes</li>
|
|
332
|
-
<li><strong>Operations</strong>: Runbooks, SLOs, incidents</li>
|
|
333
|
-
<li><strong>Governance</strong>: Policies, security, compliance</li>
|
|
334
|
-
</ul>
|
|
335
|
-
</div>
|
|
336
|
-
</div>
|
|
577
|
+
<div className="container" style={{padding: '3rem 0'}}>
|
|
578
|
+
${categories.length > 0 ? ` <div className={styles.categoryGrid}>
|
|
579
|
+
${categoryCards}
|
|
580
|
+
</div>` : ''}
|
|
337
581
|
</div>
|
|
338
582
|
</main>
|
|
339
583
|
</Layout>
|
|
@@ -344,9 +588,9 @@ export default function Home() {
|
|
|
344
588
|
/**
|
|
345
589
|
* Write index page to file
|
|
346
590
|
*/
|
|
347
|
-
export async function writeIndexPage(targetDir, title, tagline) {
|
|
591
|
+
export async function writeIndexPage(targetDir, title, tagline, categories = []) {
|
|
348
592
|
const indexPath = path.join(targetDir, 'src', 'pages', 'index.js');
|
|
349
|
-
const content = generateIndexPage(title, tagline);
|
|
593
|
+
const content = generateIndexPage(title, tagline, categories);
|
|
350
594
|
await fs.ensureDir(path.dirname(indexPath));
|
|
351
595
|
await fs.writeFile(indexPath, content, 'utf-8');
|
|
352
596
|
}
|
|
@@ -355,16 +599,32 @@ export async function writeIndexPage(targetDir, title, tagline) {
|
|
|
355
599
|
*/
|
|
356
600
|
export function generateIndexModuleCSS() {
|
|
357
601
|
return `.heroBanner {
|
|
358
|
-
padding:
|
|
602
|
+
padding: 5rem 0 4rem;
|
|
359
603
|
text-align: center;
|
|
360
604
|
position: relative;
|
|
361
605
|
overflow: hidden;
|
|
606
|
+
background: linear-gradient(135deg, #4f46e5 0%, #6366f1 50%, #818cf8 100%);
|
|
607
|
+
color: white;
|
|
362
608
|
}
|
|
363
609
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
610
|
+
[data-theme='dark'] .heroBanner {
|
|
611
|
+
background: linear-gradient(135deg, #312e81 0%, #3730a3 50%, #4338ca 100%);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
.heroTitle {
|
|
615
|
+
font-size: 3rem;
|
|
616
|
+
font-weight: 800;
|
|
617
|
+
letter-spacing: -0.03em;
|
|
618
|
+
margin-bottom: 0.75rem;
|
|
619
|
+
color: white;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
.heroSubtitle {
|
|
623
|
+
font-size: 1.25rem;
|
|
624
|
+
opacity: 0.9;
|
|
625
|
+
max-width: 600px;
|
|
626
|
+
margin: 0 auto 1.5rem;
|
|
627
|
+
color: white;
|
|
368
628
|
}
|
|
369
629
|
|
|
370
630
|
.buttons {
|
|
@@ -374,6 +634,108 @@ export function generateIndexModuleCSS() {
|
|
|
374
634
|
gap: 1rem;
|
|
375
635
|
margin-top: 2rem;
|
|
376
636
|
}
|
|
637
|
+
|
|
638
|
+
.buttons a {
|
|
639
|
+
background: white;
|
|
640
|
+
color: #4f46e5;
|
|
641
|
+
border: none;
|
|
642
|
+
font-weight: 600;
|
|
643
|
+
padding: 0.75rem 2rem;
|
|
644
|
+
border-radius: 8px;
|
|
645
|
+
font-size: 1rem;
|
|
646
|
+
transition: all 0.2s ease;
|
|
647
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
.buttons a:hover {
|
|
651
|
+
background: #f8fafc;
|
|
652
|
+
color: #4338ca;
|
|
653
|
+
transform: translateY(-2px);
|
|
654
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
|
|
655
|
+
text-decoration: none;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/* Category Grid */
|
|
659
|
+
.categoryGrid {
|
|
660
|
+
display: grid;
|
|
661
|
+
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
662
|
+
gap: 1.5rem;
|
|
663
|
+
padding: 1rem 0 2rem;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
.categoryCard {
|
|
667
|
+
background: var(--ifm-card-background-color, white);
|
|
668
|
+
border: 1px solid var(--ifm-color-emphasis-200);
|
|
669
|
+
border-radius: 12px;
|
|
670
|
+
padding: 1.75rem;
|
|
671
|
+
transition: all 0.2s ease;
|
|
672
|
+
text-decoration: none !important;
|
|
673
|
+
color: inherit;
|
|
674
|
+
display: block;
|
|
675
|
+
cursor: pointer;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
.categoryCard:hover {
|
|
679
|
+
transform: translateY(-4px);
|
|
680
|
+
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.08);
|
|
681
|
+
border-color: var(--ifm-color-primary);
|
|
682
|
+
text-decoration: none !important;
|
|
683
|
+
color: inherit;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
[data-theme='dark'] .categoryCard:hover {
|
|
687
|
+
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
.categoryCard h3 {
|
|
691
|
+
margin: 0.5rem 0 0.25rem;
|
|
692
|
+
font-size: 1.15rem;
|
|
693
|
+
font-weight: 600;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
.categoryCard p {
|
|
697
|
+
margin: 0 0 0.75rem;
|
|
698
|
+
font-size: 0.9rem;
|
|
699
|
+
color: var(--ifm-color-emphasis-700);
|
|
700
|
+
line-height: 1.5;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
.categoryIcon {
|
|
704
|
+
font-size: 2rem;
|
|
705
|
+
display: block;
|
|
706
|
+
margin-bottom: 0.25rem;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
.docCount {
|
|
710
|
+
font-size: 0.8rem;
|
|
711
|
+
color: var(--ifm-color-emphasis-500);
|
|
712
|
+
font-weight: 500;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/* Responsive */
|
|
716
|
+
@media screen and (max-width: 996px) {
|
|
717
|
+
.heroBanner {
|
|
718
|
+
padding: 3rem 1.5rem;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
.heroTitle {
|
|
722
|
+
font-size: 2.25rem;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
.categoryGrid {
|
|
726
|
+
grid-template-columns: 1fr;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
@media screen and (max-width: 600px) {
|
|
731
|
+
.heroTitle {
|
|
732
|
+
font-size: 1.75rem;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
.heroSubtitle {
|
|
736
|
+
font-size: 1rem;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
377
739
|
`;
|
|
378
740
|
}
|
|
379
741
|
/**
|
|
@@ -385,4 +747,20 @@ export async function writeIndexModuleCSS(targetDir) {
|
|
|
385
747
|
await fs.ensureDir(path.dirname(cssPath));
|
|
386
748
|
await fs.writeFile(cssPath, content, 'utf-8');
|
|
387
749
|
}
|
|
750
|
+
/**
|
|
751
|
+
* Escape single quotes for template string safety
|
|
752
|
+
*/
|
|
753
|
+
function escapeQuotes(str) {
|
|
754
|
+
return str.replace(/'/g, "\\'").replace(/\n/g, ' ');
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Darken a hex color by a percentage
|
|
758
|
+
*/
|
|
759
|
+
function darkenColor(hex, percent) {
|
|
760
|
+
const num = parseInt(hex.replace('#', ''), 16);
|
|
761
|
+
const r = Math.max(0, (num >> 16) - Math.round(2.55 * percent));
|
|
762
|
+
const g = Math.max(0, ((num >> 8) & 0x00ff) - Math.round(2.55 * percent));
|
|
763
|
+
const b = Math.max(0, (num & 0x0000ff) - Math.round(2.55 * percent));
|
|
764
|
+
return `#${(r << 16 | g << 8 | b).toString(16).padStart(6, '0')}`;
|
|
765
|
+
}
|
|
388
766
|
//# sourceMappingURL=config-generator.js.map
|