@thjodann/wk 1.0.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/LICENSE +21 -0
- package/README.md +197 -0
- package/dist/cli/commands/article.d.ts +2 -0
- package/dist/cli/commands/article.js +47 -0
- package/dist/cli/commands/article.js.map +1 -0
- package/dist/cli/commands/closeout.d.ts +2 -0
- package/dist/cli/commands/closeout.js +37 -0
- package/dist/cli/commands/closeout.js.map +1 -0
- package/dist/cli/commands/compile.d.ts +2 -0
- package/dist/cli/commands/compile.js +50 -0
- package/dist/cli/commands/compile.js.map +1 -0
- package/dist/cli/commands/concept.d.ts +2 -0
- package/dist/cli/commands/concept.js +36 -0
- package/dist/cli/commands/concept.js.map +1 -0
- package/dist/cli/commands/decision.d.ts +2 -0
- package/dist/cli/commands/decision.js +38 -0
- package/dist/cli/commands/decision.js.map +1 -0
- package/dist/cli/commands/event.d.ts +2 -0
- package/dist/cli/commands/event.js +32 -0
- package/dist/cli/commands/event.js.map +1 -0
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.js +52 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/installAgent.d.ts +2 -0
- package/dist/cli/commands/installAgent.js +130 -0
- package/dist/cli/commands/installAgent.js.map +1 -0
- package/dist/cli/commands/link.d.ts +2 -0
- package/dist/cli/commands/link.js +36 -0
- package/dist/cli/commands/link.js.map +1 -0
- package/dist/cli/commands/note.d.ts +2 -0
- package/dist/cli/commands/note.js +34 -0
- package/dist/cli/commands/note.js.map +1 -0
- package/dist/cli/commands/pages.d.ts +2 -0
- package/dist/cli/commands/pages.js +46 -0
- package/dist/cli/commands/pages.js.map +1 -0
- package/dist/cli/commands/record.d.ts +2 -0
- package/dist/cli/commands/record.js +101 -0
- package/dist/cli/commands/record.js.map +1 -0
- package/dist/cli/commands/render.d.ts +2 -0
- package/dist/cli/commands/render.js +33 -0
- package/dist/cli/commands/render.js.map +1 -0
- package/dist/cli/commands/search.d.ts +2 -0
- package/dist/cli/commands/search.js +125 -0
- package/dist/cli/commands/search.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +2 -0
- package/dist/cli/commands/setup.js +53 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/commands/site.d.ts +2 -0
- package/dist/cli/commands/site.js +47 -0
- package/dist/cli/commands/site.js.map +1 -0
- package/dist/cli/commands/spin.d.ts +2 -0
- package/dist/cli/commands/spin.js +43 -0
- package/dist/cli/commands/spin.js.map +1 -0
- package/dist/cli/commands/status.d.ts +2 -0
- package/dist/cli/commands/status.js +63 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/symbol.d.ts +2 -0
- package/dist/cli/commands/symbol.js +37 -0
- package/dist/cli/commands/symbol.js.map +1 -0
- package/dist/cli/commands/theme.d.ts +2 -0
- package/dist/cli/commands/theme.js +52 -0
- package/dist/cli/commands/theme.js.map +1 -0
- package/dist/cli/commands/validate.d.ts +2 -0
- package/dist/cli/commands/validate.js +44 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/helpers.d.ts +30 -0
- package/dist/cli/helpers.js +131 -0
- package/dist/cli/helpers.js.map +1 -0
- package/dist/core/articles.d.ts +5 -0
- package/dist/core/articles.js +25 -0
- package/dist/core/articles.js.map +1 -0
- package/dist/core/automation.d.ts +96 -0
- package/dist/core/automation.js +384 -0
- package/dist/core/automation.js.map +1 -0
- package/dist/core/beads.d.ts +43 -0
- package/dist/core/beads.js +358 -0
- package/dist/core/beads.js.map +1 -0
- package/dist/core/compiler.d.ts +45 -0
- package/dist/core/compiler.js +399 -0
- package/dist/core/compiler.js.map +1 -0
- package/dist/core/config.d.ts +59 -0
- package/dist/core/config.js +187 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/git.d.ts +21 -0
- package/dist/core/git.js +109 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/ids.d.ts +2 -0
- package/dist/core/ids.js +8 -0
- package/dist/core/ids.js.map +1 -0
- package/dist/core/pages.d.ts +34 -0
- package/dist/core/pages.js +233 -0
- package/dist/core/pages.js.map +1 -0
- package/dist/core/paths.d.ts +15 -0
- package/dist/core/paths.js +67 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/profiles.d.ts +30 -0
- package/dist/core/profiles.js +243 -0
- package/dist/core/profiles.js.map +1 -0
- package/dist/core/renderer.d.ts +8 -0
- package/dist/core/renderer.js +106 -0
- package/dist/core/renderer.js.map +1 -0
- package/dist/core/schemas.d.ts +1039 -0
- package/dist/core/schemas.js +108 -0
- package/dist/core/schemas.js.map +1 -0
- package/dist/core/site.d.ts +20 -0
- package/dist/core/site.js +2684 -0
- package/dist/core/site.js.map +1 -0
- package/dist/core/spin.d.ts +42 -0
- package/dist/core/spin.js +265 -0
- package/dist/core/spin.js.map +1 -0
- package/dist/core/store.d.ts +29 -0
- package/dist/core/store.js +146 -0
- package/dist/core/store.js.map +1 -0
- package/dist/core/theme.d.ts +35 -0
- package/dist/core/theme.js +1086 -0
- package/dist/core/theme.js.map +1 -0
- package/dist/core/validator.d.ts +8 -0
- package/dist/core/validator.js +154 -0
- package/dist/core/validator.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/templates/articlesPage.d.ts +3 -0
- package/dist/templates/articlesPage.js +46 -0
- package/dist/templates/articlesPage.js.map +1 -0
- package/dist/templates/conceptsPage.d.ts +2 -0
- package/dist/templates/conceptsPage.js +24 -0
- package/dist/templates/conceptsPage.js.map +1 -0
- package/dist/templates/decisionsPage.d.ts +2 -0
- package/dist/templates/decisionsPage.js +27 -0
- package/dist/templates/decisionsPage.js.map +1 -0
- package/dist/templates/devlogPage.d.ts +2 -0
- package/dist/templates/devlogPage.js +22 -0
- package/dist/templates/devlogPage.js.map +1 -0
- package/dist/templates/indexPage.d.ts +6 -0
- package/dist/templates/indexPage.js +33 -0
- package/dist/templates/indexPage.js.map +1 -0
- package/dist/templates/linksPage.d.ts +2 -0
- package/dist/templates/linksPage.js +26 -0
- package/dist/templates/linksPage.js.map +1 -0
- package/dist/templates/notesPage.d.ts +2 -0
- package/dist/templates/notesPage.js +26 -0
- package/dist/templates/notesPage.js.map +1 -0
- package/dist/templates/symbolsPage.d.ts +2 -0
- package/dist/templates/symbolsPage.js +25 -0
- package/dist/templates/symbolsPage.js.map +1 -0
- package/docs/concepts.md +249 -0
- package/docs/reference.md +356 -0
- package/docs/setup.md +331 -0
- package/docs/workflows.md +154 -0
- package/package.json +61 -0
- package/skills/wk/SKILL.md +251 -0
- package/skills/wk/agents/openai.yaml +4 -0
|
@@ -0,0 +1,1086 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.themeMoods = void 0;
|
|
7
|
+
exports.previewTheme = previewTheme;
|
|
8
|
+
exports.writeTheme = writeTheme;
|
|
9
|
+
exports.parseThemeMood = parseThemeMood;
|
|
10
|
+
const fs_1 = __importDefault(require("fs"));
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const config_1 = require("./config");
|
|
13
|
+
const paths_1 = require("./paths");
|
|
14
|
+
exports.themeMoods = ["calm", "vivid", "editorial", "utility", "playful", "dark"];
|
|
15
|
+
const defaultDescription = "A project wiki generated from durable repo knowledge.";
|
|
16
|
+
const moodThemes = {
|
|
17
|
+
calm: {
|
|
18
|
+
light: {
|
|
19
|
+
accent: "#2f7d6d",
|
|
20
|
+
accent_strong: "#185143",
|
|
21
|
+
secondary: "#7a6f42",
|
|
22
|
+
bg: "#f4faf6",
|
|
23
|
+
panel: "#fbfdf8",
|
|
24
|
+
panel_soft: "#eaf5ef",
|
|
25
|
+
text: "#1f2a24",
|
|
26
|
+
muted: "#5d6d64",
|
|
27
|
+
border: "#d1e5da",
|
|
28
|
+
code_bg: "#eaf4ee",
|
|
29
|
+
shadow: "0 18px 45px rgba(30, 55, 47, 0.08)",
|
|
30
|
+
shadow_strong: "0 24px 70px rgba(30, 55, 47, 0.14)",
|
|
31
|
+
radius: "8px",
|
|
32
|
+
font_family: "Inter, ui-sans-serif, system-ui, sans-serif",
|
|
33
|
+
sidebar_bg: "linear-gradient(180deg, rgba(251, 253, 248, 0.94), rgba(234, 245, 239, 0.88))",
|
|
34
|
+
hero_gradient: "linear-gradient(135deg, #fbfdf8 0%, #e7f4ed 100%)",
|
|
35
|
+
card_gradient: "linear-gradient(180deg, #fbfdf8 0%, #f2faf5 100%)",
|
|
36
|
+
brand_gradient: "linear-gradient(135deg, #2f7d6d, #185143)",
|
|
37
|
+
brand_mark_text: "#fffaf0",
|
|
38
|
+
badge_bg: "#dff0e8",
|
|
39
|
+
badge_text: "#185143",
|
|
40
|
+
tag_bg: "#f1edd8",
|
|
41
|
+
tag_text: "#605526",
|
|
42
|
+
success_bg: "#e4f3df",
|
|
43
|
+
success_text: "#2d5c1f",
|
|
44
|
+
warning_bg: "#f6ead9",
|
|
45
|
+
warning_text: "#754716",
|
|
46
|
+
focus_ring: "rgba(47, 125, 109, 0.2)",
|
|
47
|
+
gloss: "rgba(47, 125, 109, 0.13)"
|
|
48
|
+
},
|
|
49
|
+
dark: {
|
|
50
|
+
accent: "#74d4bd",
|
|
51
|
+
accent_strong: "#b5f0dd",
|
|
52
|
+
secondary: "#d8c985",
|
|
53
|
+
bg: "#101b18",
|
|
54
|
+
panel: "#162620",
|
|
55
|
+
panel_soft: "#20342c",
|
|
56
|
+
text: "#f4f1e8",
|
|
57
|
+
muted: "#c6d1cb",
|
|
58
|
+
border: "#315044",
|
|
59
|
+
code_bg: "#0c1512",
|
|
60
|
+
shadow: "0 22px 60px rgba(5, 12, 10, 0.36)",
|
|
61
|
+
shadow_strong: "0 30px 90px rgba(5, 12, 10, 0.5)",
|
|
62
|
+
radius: "8px",
|
|
63
|
+
font_family: "Inter, ui-sans-serif, system-ui, sans-serif",
|
|
64
|
+
sidebar_bg: "linear-gradient(180deg, rgba(22, 38, 32, 0.95), rgba(13, 24, 20, 0.9))",
|
|
65
|
+
hero_gradient: "linear-gradient(135deg, #1b3129 0%, #0d1714 100%)",
|
|
66
|
+
card_gradient: "linear-gradient(180deg, #182a24 0%, #111d19 100%)",
|
|
67
|
+
brand_gradient: "linear-gradient(135deg, #74d4bd, #2f7d6d)",
|
|
68
|
+
brand_mark_text: "#0f1a17",
|
|
69
|
+
badge_bg: "rgba(116, 212, 189, 0.17)",
|
|
70
|
+
badge_text: "#d9fff3",
|
|
71
|
+
tag_bg: "rgba(216, 201, 133, 0.18)",
|
|
72
|
+
tag_text: "#f4e6a6",
|
|
73
|
+
success_bg: "rgba(134, 239, 172, 0.16)",
|
|
74
|
+
success_text: "#bbf7d0",
|
|
75
|
+
warning_bg: "rgba(253, 186, 116, 0.16)",
|
|
76
|
+
warning_text: "#fed7aa",
|
|
77
|
+
focus_ring: "rgba(116, 212, 189, 0.28)",
|
|
78
|
+
gloss: "rgba(116, 212, 189, 0.16)"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
vivid: {
|
|
82
|
+
light: {
|
|
83
|
+
accent: "#d9467d",
|
|
84
|
+
accent_strong: "#8f1d4b",
|
|
85
|
+
secondary: "#6d5dfc",
|
|
86
|
+
bg: "#fff6fa",
|
|
87
|
+
panel: "#fffafd",
|
|
88
|
+
panel_soft: "#fde7f0",
|
|
89
|
+
text: "#2b1f28",
|
|
90
|
+
muted: "#76596a",
|
|
91
|
+
border: "#f1bfd2",
|
|
92
|
+
code_bg: "#fdebf3",
|
|
93
|
+
shadow: "0 18px 45px rgba(78, 25, 54, 0.1)",
|
|
94
|
+
shadow_strong: "0 28px 75px rgba(78, 25, 54, 0.17)",
|
|
95
|
+
radius: "8px",
|
|
96
|
+
font_family: "Inter, ui-sans-serif, system-ui, sans-serif",
|
|
97
|
+
sidebar_bg: "linear-gradient(180deg, rgba(255, 250, 253, 0.94), rgba(253, 231, 240, 0.88))",
|
|
98
|
+
hero_gradient: "linear-gradient(135deg, #fffafd 0%, #fde5ef 52%, #eee8ff 100%)",
|
|
99
|
+
card_gradient: "linear-gradient(180deg, #fffafd 0%, #fff3f8 100%)",
|
|
100
|
+
brand_gradient: "linear-gradient(135deg, #d9467d, #6d5dfc)",
|
|
101
|
+
brand_mark_text: "#fffaf0",
|
|
102
|
+
badge_bg: "#f9dce8",
|
|
103
|
+
badge_text: "#8f1d4b",
|
|
104
|
+
tag_bg: "#ece8ff",
|
|
105
|
+
tag_text: "#4236a3",
|
|
106
|
+
success_bg: "#e7f3df",
|
|
107
|
+
success_text: "#2d5c1f",
|
|
108
|
+
warning_bg: "#f8e2d2",
|
|
109
|
+
warning_text: "#7d3414",
|
|
110
|
+
focus_ring: "rgba(217, 70, 125, 0.22)",
|
|
111
|
+
gloss: "rgba(217, 70, 125, 0.15)"
|
|
112
|
+
},
|
|
113
|
+
dark: {
|
|
114
|
+
accent: "#fb7aad",
|
|
115
|
+
accent_strong: "#f9a8d4",
|
|
116
|
+
secondary: "#a99cff",
|
|
117
|
+
bg: "#21111a",
|
|
118
|
+
panel: "#2c1724",
|
|
119
|
+
panel_soft: "#3a2030",
|
|
120
|
+
text: "#fff0f7",
|
|
121
|
+
muted: "#e8c8d8",
|
|
122
|
+
border: "#593147",
|
|
123
|
+
code_bg: "#170c12",
|
|
124
|
+
shadow: "0 22px 60px rgba(13, 4, 9, 0.38)",
|
|
125
|
+
shadow_strong: "0 30px 90px rgba(13, 4, 9, 0.52)",
|
|
126
|
+
radius: "8px",
|
|
127
|
+
font_family: "Inter, ui-sans-serif, system-ui, sans-serif",
|
|
128
|
+
sidebar_bg: "linear-gradient(180deg, rgba(44, 23, 36, 0.95), rgba(28, 13, 22, 0.9))",
|
|
129
|
+
hero_gradient: "linear-gradient(135deg, #3b1d30 0%, #20101a 55%, #191331 100%)",
|
|
130
|
+
card_gradient: "linear-gradient(180deg, #2f1928 0%, #24131d 100%)",
|
|
131
|
+
brand_gradient: "linear-gradient(135deg, #fb7aad, #8b5cf6)",
|
|
132
|
+
brand_mark_text: "#201018",
|
|
133
|
+
badge_bg: "rgba(251, 122, 173, 0.18)",
|
|
134
|
+
badge_text: "#ffd7e8",
|
|
135
|
+
tag_bg: "rgba(169, 156, 255, 0.2)",
|
|
136
|
+
tag_text: "#ddd6fe",
|
|
137
|
+
success_bg: "rgba(134, 239, 172, 0.16)",
|
|
138
|
+
success_text: "#bbf7d0",
|
|
139
|
+
warning_bg: "rgba(253, 186, 116, 0.16)",
|
|
140
|
+
warning_text: "#fed7aa",
|
|
141
|
+
focus_ring: "rgba(251, 122, 173, 0.3)",
|
|
142
|
+
gloss: "rgba(251, 122, 173, 0.18)"
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
editorial: {
|
|
146
|
+
light: {
|
|
147
|
+
accent: "#8a5a2b",
|
|
148
|
+
accent_strong: "#5b3718",
|
|
149
|
+
secondary: "#4f6f82",
|
|
150
|
+
bg: "#faf7f0",
|
|
151
|
+
panel: "#fdfaf4",
|
|
152
|
+
panel_soft: "#f1eadf",
|
|
153
|
+
text: "#292520",
|
|
154
|
+
muted: "#6b6257",
|
|
155
|
+
border: "#dfd4c6",
|
|
156
|
+
code_bg: "#f2eadf",
|
|
157
|
+
shadow: "0 16px 42px rgba(61, 45, 31, 0.09)",
|
|
158
|
+
shadow_strong: "0 24px 70px rgba(61, 45, 31, 0.15)",
|
|
159
|
+
radius: "6px",
|
|
160
|
+
font_family: "Charter, Georgia, serif",
|
|
161
|
+
sidebar_bg: "linear-gradient(180deg, rgba(253, 250, 244, 0.94), rgba(241, 234, 223, 0.88))",
|
|
162
|
+
hero_gradient: "linear-gradient(135deg, #fdfaf4 0%, #efe3d2 100%)",
|
|
163
|
+
card_gradient: "linear-gradient(180deg, #fdfaf4 0%, #f8f1e7 100%)",
|
|
164
|
+
brand_gradient: "linear-gradient(135deg, #8a5a2b, #4f6f82)",
|
|
165
|
+
brand_mark_text: "#fff7e8",
|
|
166
|
+
badge_bg: "#efe1d0",
|
|
167
|
+
badge_text: "#5b3718",
|
|
168
|
+
tag_bg: "#e3edf1",
|
|
169
|
+
tag_text: "#2d566a",
|
|
170
|
+
success_bg: "#e7f0dc",
|
|
171
|
+
success_text: "#2f5e1f",
|
|
172
|
+
warning_bg: "#f4e3d2",
|
|
173
|
+
warning_text: "#7a3c1d",
|
|
174
|
+
focus_ring: "rgba(138, 90, 43, 0.22)",
|
|
175
|
+
gloss: "rgba(138, 90, 43, 0.12)"
|
|
176
|
+
},
|
|
177
|
+
dark: {
|
|
178
|
+
accent: "#d2a063",
|
|
179
|
+
accent_strong: "#f0d4a8",
|
|
180
|
+
secondary: "#9ac5d8",
|
|
181
|
+
bg: "#1d1915",
|
|
182
|
+
panel: "#292219",
|
|
183
|
+
panel_soft: "#352c21",
|
|
184
|
+
text: "#f4ecdf",
|
|
185
|
+
muted: "#d3c5b4",
|
|
186
|
+
border: "#554638",
|
|
187
|
+
code_bg: "#15120f",
|
|
188
|
+
shadow: "0 22px 60px rgba(11, 8, 5, 0.36)",
|
|
189
|
+
shadow_strong: "0 30px 90px rgba(11, 8, 5, 0.5)",
|
|
190
|
+
radius: "6px",
|
|
191
|
+
font_family: "Charter, Georgia, serif",
|
|
192
|
+
sidebar_bg: "linear-gradient(180deg, rgba(41, 34, 25, 0.95), rgba(26, 22, 18, 0.9))",
|
|
193
|
+
hero_gradient: "linear-gradient(135deg, #352719 0%, #1b1713 100%)",
|
|
194
|
+
card_gradient: "linear-gradient(180deg, #2b241b 0%, #211c16 100%)",
|
|
195
|
+
brand_gradient: "linear-gradient(135deg, #d2a063, #7899aa)",
|
|
196
|
+
brand_mark_text: "#20170d",
|
|
197
|
+
badge_bg: "rgba(210, 160, 99, 0.18)",
|
|
198
|
+
badge_text: "#ffe2b8",
|
|
199
|
+
tag_bg: "rgba(154, 197, 216, 0.17)",
|
|
200
|
+
tag_text: "#cae7f3",
|
|
201
|
+
success_bg: "rgba(134, 239, 172, 0.16)",
|
|
202
|
+
success_text: "#bbf7d0",
|
|
203
|
+
warning_bg: "rgba(253, 186, 116, 0.16)",
|
|
204
|
+
warning_text: "#fed7aa",
|
|
205
|
+
focus_ring: "rgba(210, 160, 99, 0.28)",
|
|
206
|
+
gloss: "rgba(210, 160, 99, 0.15)"
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
utility: {
|
|
210
|
+
light: {
|
|
211
|
+
accent: "#2563eb",
|
|
212
|
+
accent_strong: "#1e3a8a",
|
|
213
|
+
secondary: "#0f766e",
|
|
214
|
+
bg: "#f6f9fc",
|
|
215
|
+
panel: "#fbfdff",
|
|
216
|
+
panel_soft: "#eaf1f8",
|
|
217
|
+
text: "#1f2937",
|
|
218
|
+
muted: "#5f6b7a",
|
|
219
|
+
border: "#d3dce8",
|
|
220
|
+
code_bg: "#eaf1f8",
|
|
221
|
+
shadow: "0 18px 45px rgba(30, 58, 138, 0.08)",
|
|
222
|
+
shadow_strong: "0 24px 70px rgba(30, 58, 138, 0.14)",
|
|
223
|
+
radius: "6px",
|
|
224
|
+
font_family: "Inter, ui-sans-serif, system-ui, sans-serif",
|
|
225
|
+
sidebar_bg: "linear-gradient(180deg, rgba(251, 253, 255, 0.94), rgba(234, 241, 248, 0.88))",
|
|
226
|
+
hero_gradient: "linear-gradient(135deg, #fbfdff 0%, #e8f0ff 100%)",
|
|
227
|
+
card_gradient: "linear-gradient(180deg, #fbfdff 0%, #f3f7fb 100%)",
|
|
228
|
+
brand_gradient: "linear-gradient(135deg, #2563eb, #0f766e)",
|
|
229
|
+
brand_mark_text: "#f8fbff",
|
|
230
|
+
badge_bg: "#dfeafe",
|
|
231
|
+
badge_text: "#1e3a8a",
|
|
232
|
+
tag_bg: "#dff4f1",
|
|
233
|
+
tag_text: "#0f5a53",
|
|
234
|
+
success_bg: "#e4f3df",
|
|
235
|
+
success_text: "#2d5c1f",
|
|
236
|
+
warning_bg: "#f6ead9",
|
|
237
|
+
warning_text: "#754716",
|
|
238
|
+
focus_ring: "rgba(37, 99, 235, 0.2)",
|
|
239
|
+
gloss: "rgba(37, 99, 235, 0.13)"
|
|
240
|
+
},
|
|
241
|
+
dark: {
|
|
242
|
+
accent: "#7db1ff",
|
|
243
|
+
accent_strong: "#bfdbfe",
|
|
244
|
+
secondary: "#5eead4",
|
|
245
|
+
bg: "#0f1724",
|
|
246
|
+
panel: "#172131",
|
|
247
|
+
panel_soft: "#202d42",
|
|
248
|
+
text: "#eef5ff",
|
|
249
|
+
muted: "#c4cfdd",
|
|
250
|
+
border: "#33455f",
|
|
251
|
+
code_bg: "#0a111d",
|
|
252
|
+
shadow: "0 22px 60px rgba(4, 8, 16, 0.36)",
|
|
253
|
+
shadow_strong: "0 30px 90px rgba(4, 8, 16, 0.5)",
|
|
254
|
+
radius: "6px",
|
|
255
|
+
font_family: "Inter, ui-sans-serif, system-ui, sans-serif",
|
|
256
|
+
sidebar_bg: "linear-gradient(180deg, rgba(23, 33, 49, 0.95), rgba(12, 19, 31, 0.9))",
|
|
257
|
+
hero_gradient: "linear-gradient(135deg, #1d2b45 0%, #0d1421 100%)",
|
|
258
|
+
card_gradient: "linear-gradient(180deg, #192538 0%, #111a29 100%)",
|
|
259
|
+
brand_gradient: "linear-gradient(135deg, #7db1ff, #2dd4bf)",
|
|
260
|
+
brand_mark_text: "#0b1220",
|
|
261
|
+
badge_bg: "rgba(125, 177, 255, 0.17)",
|
|
262
|
+
badge_text: "#dbeafe",
|
|
263
|
+
tag_bg: "rgba(94, 234, 212, 0.17)",
|
|
264
|
+
tag_text: "#ccfbf1",
|
|
265
|
+
success_bg: "rgba(134, 239, 172, 0.16)",
|
|
266
|
+
success_text: "#bbf7d0",
|
|
267
|
+
warning_bg: "rgba(253, 186, 116, 0.16)",
|
|
268
|
+
warning_text: "#fed7aa",
|
|
269
|
+
focus_ring: "rgba(125, 177, 255, 0.28)",
|
|
270
|
+
gloss: "rgba(125, 177, 255, 0.16)"
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
playful: {
|
|
274
|
+
light: {
|
|
275
|
+
accent: "#f97316",
|
|
276
|
+
accent_strong: "#9a3412",
|
|
277
|
+
secondary: "#0ea5e9",
|
|
278
|
+
bg: "#fff8ec",
|
|
279
|
+
panel: "#fffbf4",
|
|
280
|
+
panel_soft: "#ffe9c7",
|
|
281
|
+
text: "#2c241d",
|
|
282
|
+
muted: "#735b47",
|
|
283
|
+
border: "#f7c98f",
|
|
284
|
+
code_bg: "#fff0da",
|
|
285
|
+
shadow: "0 18px 45px rgba(120, 54, 12, 0.1)",
|
|
286
|
+
shadow_strong: "0 28px 75px rgba(120, 54, 12, 0.17)",
|
|
287
|
+
radius: "8px",
|
|
288
|
+
font_family: "Nunito, Inter, ui-sans-serif, system-ui, sans-serif",
|
|
289
|
+
sidebar_bg: "linear-gradient(180deg, rgba(255, 251, 244, 0.94), rgba(255, 233, 199, 0.88))",
|
|
290
|
+
hero_gradient: "linear-gradient(135deg, #fffbf4 0%, #ffe6bc 58%, #e0f2fe 100%)",
|
|
291
|
+
card_gradient: "linear-gradient(180deg, #fffbf4 0%, #fff3e2 100%)",
|
|
292
|
+
brand_gradient: "linear-gradient(135deg, #f97316, #0ea5e9)",
|
|
293
|
+
brand_mark_text: "#fffaf0",
|
|
294
|
+
badge_bg: "#ffe2bd",
|
|
295
|
+
badge_text: "#9a3412",
|
|
296
|
+
tag_bg: "#dff2ff",
|
|
297
|
+
tag_text: "#075985",
|
|
298
|
+
success_bg: "#e7f3df",
|
|
299
|
+
success_text: "#2d5c1f",
|
|
300
|
+
warning_bg: "#fde2c8",
|
|
301
|
+
warning_text: "#7d3414",
|
|
302
|
+
focus_ring: "rgba(249, 115, 22, 0.22)",
|
|
303
|
+
gloss: "rgba(249, 115, 22, 0.15)"
|
|
304
|
+
},
|
|
305
|
+
dark: {
|
|
306
|
+
accent: "#ffb36b",
|
|
307
|
+
accent_strong: "#fed7aa",
|
|
308
|
+
secondary: "#7dd3fc",
|
|
309
|
+
bg: "#24180f",
|
|
310
|
+
panel: "#302116",
|
|
311
|
+
panel_soft: "#402d1e",
|
|
312
|
+
text: "#fff1e3",
|
|
313
|
+
muted: "#e6cbb2",
|
|
314
|
+
border: "#5a3f29",
|
|
315
|
+
code_bg: "#170f09",
|
|
316
|
+
shadow: "0 22px 60px rgba(13, 6, 2, 0.38)",
|
|
317
|
+
shadow_strong: "0 30px 90px rgba(13, 6, 2, 0.52)",
|
|
318
|
+
radius: "8px",
|
|
319
|
+
font_family: "Nunito, Inter, ui-sans-serif, system-ui, sans-serif",
|
|
320
|
+
sidebar_bg: "linear-gradient(180deg, rgba(48, 33, 22, 0.95), rgba(30, 19, 12, 0.9))",
|
|
321
|
+
hero_gradient: "linear-gradient(135deg, #422a17 0%, #21150d 58%, #0d2536 100%)",
|
|
322
|
+
card_gradient: "linear-gradient(180deg, #332318 0%, #26190f 100%)",
|
|
323
|
+
brand_gradient: "linear-gradient(135deg, #ffb36b, #38bdf8)",
|
|
324
|
+
brand_mark_text: "#1f1309",
|
|
325
|
+
badge_bg: "rgba(255, 179, 107, 0.18)",
|
|
326
|
+
badge_text: "#ffedd5",
|
|
327
|
+
tag_bg: "rgba(125, 211, 252, 0.18)",
|
|
328
|
+
tag_text: "#d8f3ff",
|
|
329
|
+
success_bg: "rgba(134, 239, 172, 0.16)",
|
|
330
|
+
success_text: "#bbf7d0",
|
|
331
|
+
warning_bg: "rgba(253, 186, 116, 0.18)",
|
|
332
|
+
warning_text: "#fed7aa",
|
|
333
|
+
focus_ring: "rgba(255, 179, 107, 0.3)",
|
|
334
|
+
gloss: "rgba(255, 179, 107, 0.18)"
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
dark: {
|
|
338
|
+
light: {
|
|
339
|
+
accent: "#2563eb",
|
|
340
|
+
accent_strong: "#172554",
|
|
341
|
+
secondary: "#64748b",
|
|
342
|
+
bg: "#f3f6fb",
|
|
343
|
+
panel: "#fbfcff",
|
|
344
|
+
panel_soft: "#e7edf7",
|
|
345
|
+
text: "#172033",
|
|
346
|
+
muted: "#5f6b7a",
|
|
347
|
+
border: "#cfd9e8",
|
|
348
|
+
code_bg: "#e7edf7",
|
|
349
|
+
shadow: "0 18px 45px rgba(15, 23, 42, 0.1)",
|
|
350
|
+
shadow_strong: "0 28px 75px rgba(15, 23, 42, 0.17)",
|
|
351
|
+
radius: "8px",
|
|
352
|
+
font_family: "Inter, ui-sans-serif, system-ui, sans-serif",
|
|
353
|
+
sidebar_bg: "linear-gradient(180deg, rgba(251, 252, 255, 0.94), rgba(231, 237, 247, 0.88))",
|
|
354
|
+
hero_gradient: "linear-gradient(135deg, #fbfcff 0%, #e2eaf8 100%)",
|
|
355
|
+
card_gradient: "linear-gradient(180deg, #fbfcff 0%, #f0f4fa 100%)",
|
|
356
|
+
brand_gradient: "linear-gradient(135deg, #2563eb, #172554)",
|
|
357
|
+
brand_mark_text: "#f8fbff",
|
|
358
|
+
badge_bg: "#dce7fa",
|
|
359
|
+
badge_text: "#172554",
|
|
360
|
+
tag_bg: "#e5eaf2",
|
|
361
|
+
tag_text: "#334155",
|
|
362
|
+
success_bg: "#e3f2df",
|
|
363
|
+
success_text: "#2d5c1f",
|
|
364
|
+
warning_bg: "#f5e4d6",
|
|
365
|
+
warning_text: "#7a3c1d",
|
|
366
|
+
focus_ring: "rgba(37, 99, 235, 0.22)",
|
|
367
|
+
gloss: "rgba(37, 99, 235, 0.13)"
|
|
368
|
+
},
|
|
369
|
+
dark: {
|
|
370
|
+
accent: "#38bdf8",
|
|
371
|
+
accent_strong: "#bae6fd",
|
|
372
|
+
secondary: "#a78bfa",
|
|
373
|
+
bg: "#0f172a",
|
|
374
|
+
panel: "#151f33",
|
|
375
|
+
panel_soft: "#202b42",
|
|
376
|
+
text: "#f8fafc",
|
|
377
|
+
muted: "#cbd5e1",
|
|
378
|
+
border: "#334155",
|
|
379
|
+
code_bg: "#0b1220",
|
|
380
|
+
shadow: "0 22px 60px rgba(4, 8, 16, 0.38)",
|
|
381
|
+
shadow_strong: "0 30px 90px rgba(4, 8, 16, 0.54)",
|
|
382
|
+
radius: "8px",
|
|
383
|
+
font_family: "Inter, ui-sans-serif, system-ui, sans-serif",
|
|
384
|
+
sidebar_bg: "linear-gradient(180deg, rgba(21, 31, 51, 0.95), rgba(12, 18, 32, 0.9))",
|
|
385
|
+
hero_gradient: "linear-gradient(135deg, #1d2b48 0%, #0c1220 100%)",
|
|
386
|
+
card_gradient: "linear-gradient(180deg, #172237 0%, #101827 100%)",
|
|
387
|
+
brand_gradient: "linear-gradient(135deg, #38bdf8, #8b5cf6)",
|
|
388
|
+
brand_mark_text: "#07111f",
|
|
389
|
+
badge_bg: "rgba(56, 189, 248, 0.17)",
|
|
390
|
+
badge_text: "#e0f2fe",
|
|
391
|
+
tag_bg: "rgba(167, 139, 250, 0.18)",
|
|
392
|
+
tag_text: "#ede9fe",
|
|
393
|
+
success_bg: "rgba(134, 239, 172, 0.16)",
|
|
394
|
+
success_text: "#bbf7d0",
|
|
395
|
+
warning_bg: "rgba(253, 186, 116, 0.16)",
|
|
396
|
+
warning_text: "#fed7aa",
|
|
397
|
+
focus_ring: "rgba(56, 189, 248, 0.3)",
|
|
398
|
+
gloss: "rgba(56, 189, 248, 0.18)"
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
function previewTheme(root, options = {}) {
|
|
403
|
+
const style = inferProjectStyle(root);
|
|
404
|
+
const identity = inferThemeIdentity(root, options);
|
|
405
|
+
const mood = resolveThemeMood(root, identity, options.mood, style);
|
|
406
|
+
const theme = applyProjectStyle(moodThemes[mood], style);
|
|
407
|
+
return {
|
|
408
|
+
ok: true,
|
|
409
|
+
mode: "preview",
|
|
410
|
+
theme_path: (0, paths_1.relativeReportPath)(root, (0, config_1.siteThemePath)(root)),
|
|
411
|
+
exists: fs_1.default.existsSync((0, config_1.siteThemePath)(root)),
|
|
412
|
+
mood,
|
|
413
|
+
style_sources: style.sources.map((source) => (0, paths_1.relativeReportPath)(root, source.file)),
|
|
414
|
+
identity,
|
|
415
|
+
theme: {
|
|
416
|
+
project_name: identity.project_name,
|
|
417
|
+
project_description: identity.project_description,
|
|
418
|
+
default_color_scheme: style.defaultColorScheme ?? "auto",
|
|
419
|
+
...theme.light,
|
|
420
|
+
modes: {
|
|
421
|
+
light: theme.light,
|
|
422
|
+
dark: theme.dark
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
function writeTheme(root, options = {}) {
|
|
428
|
+
const preview = previewTheme(root, options);
|
|
429
|
+
const file = (0, config_1.siteThemePath)(root);
|
|
430
|
+
const exists = fs_1.default.existsSync(file);
|
|
431
|
+
if (exists && options.force !== true) {
|
|
432
|
+
throw new Error(`Theme already exists at ${preview.theme_path}. Pass --force to overwrite it.`);
|
|
433
|
+
}
|
|
434
|
+
fs_1.default.mkdirSync(path_1.default.dirname(file), { recursive: true });
|
|
435
|
+
fs_1.default.writeFileSync(file, `${JSON.stringify(preview.theme, null, 2)}\n`, "utf8");
|
|
436
|
+
return {
|
|
437
|
+
...preview,
|
|
438
|
+
mode: "init",
|
|
439
|
+
exists: true,
|
|
440
|
+
written: true,
|
|
441
|
+
overwritten: exists
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
function parseThemeMood(value) {
|
|
445
|
+
if (!value) {
|
|
446
|
+
return undefined;
|
|
447
|
+
}
|
|
448
|
+
if (exports.themeMoods.includes(value)) {
|
|
449
|
+
return value;
|
|
450
|
+
}
|
|
451
|
+
throw new Error(`Unknown theme mood: ${value}. Expected one of: ${exports.themeMoods.join(", ")}.`);
|
|
452
|
+
}
|
|
453
|
+
function inferThemeIdentity(root, options) {
|
|
454
|
+
const packageJson = readPackageJson(root);
|
|
455
|
+
const readme = readReadme(root);
|
|
456
|
+
const readmeTitle = readme ? readmeH1(readme) : undefined;
|
|
457
|
+
const readmeDescription = readme ? firstUsefulReadmeParagraph(readme) : undefined;
|
|
458
|
+
const packageName = packageJson?.name && typeof packageJson.name === "string"
|
|
459
|
+
? prettyPackageName(packageJson.name)
|
|
460
|
+
: undefined;
|
|
461
|
+
const packageDescription = packageJson?.description && typeof packageJson.description === "string"
|
|
462
|
+
? plainText(packageJson.description)
|
|
463
|
+
: undefined;
|
|
464
|
+
const optionName = plainText(options.projectName);
|
|
465
|
+
const optionDescription = plainText(options.description);
|
|
466
|
+
const fallbackName = prettyPackageName(path_1.default.basename(root));
|
|
467
|
+
return {
|
|
468
|
+
project_name: optionName || readmeTitle || packageName || fallbackName,
|
|
469
|
+
project_description: optionDescription || packageDescription || readmeDescription || defaultDescription,
|
|
470
|
+
project_name_source: optionName ? "option" : readmeTitle ? "readme" : packageName ? "package" : "repo",
|
|
471
|
+
project_description_source: optionDescription ? "option" : packageDescription ? "package" : readmeDescription ? "readme" : "default"
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
function resolveThemeMood(root, identity, moodOption, style) {
|
|
475
|
+
const parsedMood = parseThemeMood(moodOption);
|
|
476
|
+
if (parsedMood) {
|
|
477
|
+
return parsedMood;
|
|
478
|
+
}
|
|
479
|
+
const readme = readReadme(root) ?? "";
|
|
480
|
+
const packageJson = readPackageJson(root);
|
|
481
|
+
const styleText = style.sources.map((source) => source.content.slice(0, 12000)).join(" ");
|
|
482
|
+
const text = [
|
|
483
|
+
identity.project_name,
|
|
484
|
+
identity.project_description,
|
|
485
|
+
readme,
|
|
486
|
+
styleText,
|
|
487
|
+
typeof packageJson?.description === "string" ? packageJson.description : "",
|
|
488
|
+
typeof packageJson?.name === "string" ? packageJson.name : ""
|
|
489
|
+
].join(" ").toLowerCase();
|
|
490
|
+
const scored = exports.themeMoods.map((mood) => ({
|
|
491
|
+
mood,
|
|
492
|
+
score: moodKeywords[mood].reduce((score, keyword) => score + countKeyword(text, keyword), 0)
|
|
493
|
+
}));
|
|
494
|
+
scored.sort((a, b) => b.score - a.score || exports.themeMoods.indexOf(a.mood) - exports.themeMoods.indexOf(b.mood));
|
|
495
|
+
if (scored[0].score > 0) {
|
|
496
|
+
return scored[0].mood;
|
|
497
|
+
}
|
|
498
|
+
if (style.accents.length >= 3) {
|
|
499
|
+
return "vivid";
|
|
500
|
+
}
|
|
501
|
+
if (style.defaultColorScheme === "dark") {
|
|
502
|
+
return "dark";
|
|
503
|
+
}
|
|
504
|
+
return exports.themeMoods[stableHash(identity.project_name) % exports.themeMoods.length];
|
|
505
|
+
}
|
|
506
|
+
function inferProjectStyle(root) {
|
|
507
|
+
const sources = findStyleSources(root);
|
|
508
|
+
const colors = extractStyleColors(sources);
|
|
509
|
+
const accents = accentColors(colors);
|
|
510
|
+
const darkSurface = surfaceColor(colors, "dark", ["bg", "background", "body", "shell", "app"]);
|
|
511
|
+
const darkPanel = surfaceColor(colors, "dark", ["panel", "card", "surface", "glass"]);
|
|
512
|
+
const lightSurface = surfaceColor(colors, "light", ["bg", "background", "body", "shell", "app"]);
|
|
513
|
+
const lightPanel = surfaceColor(colors, "light", ["panel", "card", "surface", "glass"]);
|
|
514
|
+
const darkText = textColor(colors, "dark");
|
|
515
|
+
const lightText = textColor(colors, "light");
|
|
516
|
+
const combined = sources.map((source) => source.content).join("\n").toLowerCase();
|
|
517
|
+
const darkSignals = [
|
|
518
|
+
/color-scheme\s*:\s*dark/.test(combined),
|
|
519
|
+
/data-theme=["']dark/.test(combined),
|
|
520
|
+
/prefers-color-scheme\s*:\s*dark/.test(combined),
|
|
521
|
+
Boolean(darkSurface),
|
|
522
|
+
colors.filter((color) => relativeLuminance(color.rgb) < 0.18).length > colors.filter((color) => relativeLuminance(color.rgb) > 0.82).length
|
|
523
|
+
].filter(Boolean).length;
|
|
524
|
+
const lightSignals = [
|
|
525
|
+
/color-scheme\s*:\s*light/.test(combined),
|
|
526
|
+
/data-theme=["']light/.test(combined),
|
|
527
|
+
Boolean(lightSurface)
|
|
528
|
+
].filter(Boolean).length;
|
|
529
|
+
return {
|
|
530
|
+
sources,
|
|
531
|
+
colors,
|
|
532
|
+
accents,
|
|
533
|
+
darkSurface,
|
|
534
|
+
darkPanel,
|
|
535
|
+
darkText,
|
|
536
|
+
lightSurface,
|
|
537
|
+
lightPanel,
|
|
538
|
+
lightText,
|
|
539
|
+
defaultColorScheme: darkSignals > lightSignals ? "dark" : lightSignals > darkSignals ? "light" : undefined,
|
|
540
|
+
radius: inferRadius(sources),
|
|
541
|
+
fontFamily: inferFontFamily(sources),
|
|
542
|
+
gradientAngle: inferGradientAngle(sources),
|
|
543
|
+
hasGlow: /radial-gradient|glow|blur\(/i.test(combined),
|
|
544
|
+
hasGlass: /backdrop-filter|glass|rgba\([^)]*,\s*0\.\d+\)/i.test(combined),
|
|
545
|
+
hasShadow: /box-shadow|shadow/i.test(combined)
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
function applyProjectStyle(base, style) {
|
|
549
|
+
if (style.sources.length === 0 || (style.accents.length === 0 && !style.darkSurface && !style.lightSurface)) {
|
|
550
|
+
return {
|
|
551
|
+
light: { ...base.light },
|
|
552
|
+
dark: { ...base.dark }
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
const accents = style.accents.length > 0
|
|
556
|
+
? style.accents
|
|
557
|
+
: [base.light.accent ?? base.dark.accent ?? "#2563eb"];
|
|
558
|
+
const primary = accents[0];
|
|
559
|
+
const secondary = accents[1] ?? base.light.secondary ?? base.dark.secondary ?? primary;
|
|
560
|
+
const tertiary = accents[2] ?? base.dark.secondary ?? secondary;
|
|
561
|
+
const primaryRgb = parseHexColor(primary) ?? { r: 37, g: 99, b: 235 };
|
|
562
|
+
const secondaryRgb = parseHexColor(secondary) ?? primaryRgb;
|
|
563
|
+
const tertiaryRgb = parseHexColor(tertiary) ?? secondaryRgb;
|
|
564
|
+
const lightBgRgb = parseHexColor(style.lightSurface) ?? mixRgb(primaryRgb, { r: 255, g: 250, b: 244 }, 0.06);
|
|
565
|
+
const lightPanelRgb = parseHexColor(style.lightPanel) ?? mixRgb(primaryRgb, { r: 255, g: 253, b: 248 }, 0.04);
|
|
566
|
+
const darkBgRgb = parseHexColor(style.darkSurface) ?? mixRgb(primaryRgb, { r: 15, g: 12, b: 14 }, 0.12);
|
|
567
|
+
const darkPanelRgb = parseHexColor(style.darkPanel) ?? mixRgb(primaryRgb, { r: 25, g: 20, b: 24 }, 0.14);
|
|
568
|
+
const darkAccent = colorToHex(readableAccentFor(primaryRgb, darkPanelRgb, "dark"));
|
|
569
|
+
const lightAccent = colorToHex(readableAccentFor(primaryRgb, lightPanelRgb, "light"));
|
|
570
|
+
const darkSecondary = colorToHex(readableAccentFor(secondaryRgb, darkPanelRgb, "dark"));
|
|
571
|
+
const lightSecondary = colorToHex(readableAccentFor(secondaryRgb, lightPanelRgb, "light"));
|
|
572
|
+
const lightAccentStrong = colorToHex(readableAccentFor(mixRgb(primaryRgb, { r: 17, g: 24, b: 39 }, 0.62), lightPanelRgb, "light"));
|
|
573
|
+
const darkAccentStrong = colorToHex(readableAccentFor(mixRgb(primaryRgb, { r: 255, g: 255, b: 255 }, 0.5), darkPanelRgb, "dark"));
|
|
574
|
+
const lightText = style.defaultColorScheme === "light" ? style.lightText : undefined;
|
|
575
|
+
const darkText = style.defaultColorScheme === "dark" ? style.darkText : undefined;
|
|
576
|
+
const radius = style.radius ?? base.light.radius ?? base.dark.radius ?? "8px";
|
|
577
|
+
const fontFamily = style.fontFamily ?? base.light.font_family ?? base.dark.font_family;
|
|
578
|
+
const angle = style.gradientAngle;
|
|
579
|
+
const brandGradient = gradientFromAccents(angle, accents);
|
|
580
|
+
const lightBadgeBg = colorToHex(mixRgb(primaryRgb, lightPanelRgb, 0.16));
|
|
581
|
+
const darkBadgeBg = colorToHex(mixRgb(primaryRgb, darkPanelRgb, 0.28));
|
|
582
|
+
const lightTagBg = colorToHex(mixRgb(secondaryRgb, lightPanelRgb, 0.15));
|
|
583
|
+
const darkTagBg = colorToHex(mixRgb(secondaryRgb, darkPanelRgb, 0.26));
|
|
584
|
+
return {
|
|
585
|
+
light: {
|
|
586
|
+
...base.light,
|
|
587
|
+
accent: lightAccent,
|
|
588
|
+
accent_strong: lightAccentStrong,
|
|
589
|
+
secondary: lightSecondary,
|
|
590
|
+
bg: colorToHex(lightBgRgb),
|
|
591
|
+
panel: colorToHex(lightPanelRgb),
|
|
592
|
+
panel_soft: colorToHex(mixRgb(tertiaryRgb, lightPanelRgb, 0.1)),
|
|
593
|
+
text: lightText ?? readableTextFor(lightPanelRgb),
|
|
594
|
+
muted: colorToHex(mixRgb(parseHexColor(lightText) ?? { r: 31, g: 41, b: 55 }, lightPanelRgb, 0.65)),
|
|
595
|
+
border: colorToHex(mixRgb(primaryRgb, lightPanelRgb, 0.22)),
|
|
596
|
+
code_bg: colorToHex(mixRgb(tertiaryRgb, lightPanelRgb, 0.08)),
|
|
597
|
+
shadow: style.hasShadow ? `0 24px 70px ${rgba(mixRgb(primaryRgb, { r: 17, g: 24, b: 39 }, 0.38), 0.14)}` : base.light.shadow,
|
|
598
|
+
shadow_strong: style.hasShadow ? `0 32px 100px ${rgba(mixRgb(primaryRgb, { r: 17, g: 24, b: 39 }, 0.4), 0.22)}` : base.light.shadow_strong,
|
|
599
|
+
radius,
|
|
600
|
+
font_family: fontFamily,
|
|
601
|
+
sidebar_bg: `linear-gradient(180deg, ${rgba(lightPanelRgb, 0.95)}, ${rgba(mixRgb(primaryRgb, lightBgRgb, 0.08), 0.9)})`,
|
|
602
|
+
hero_gradient: style.hasGlow
|
|
603
|
+
? `radial-gradient(circle at top left, ${rgba(primaryRgb, 0.18)}, transparent 34%), linear-gradient(${angle}, ${colorToHex(lightPanelRgb)} 0%, ${colorToHex(mixRgb(secondaryRgb, lightBgRgb, 0.12))} 100%)`
|
|
604
|
+
: `linear-gradient(${angle}, ${colorToHex(lightPanelRgb)} 0%, ${colorToHex(mixRgb(primaryRgb, lightBgRgb, 0.14))} 100%)`,
|
|
605
|
+
card_gradient: style.hasGlass
|
|
606
|
+
? `linear-gradient(180deg, ${rgba(lightPanelRgb, 0.92)} 0%, ${rgba(mixRgb(primaryRgb, lightPanelRgb, 0.07), 0.82)} 100%)`
|
|
607
|
+
: `linear-gradient(180deg, ${colorToHex(lightPanelRgb)} 0%, ${colorToHex(mixRgb(primaryRgb, lightPanelRgb, 0.05))} 100%)`,
|
|
608
|
+
brand_gradient: brandGradient,
|
|
609
|
+
brand_mark_text: readableTextFor(primaryRgb),
|
|
610
|
+
badge_bg: lightBadgeBg,
|
|
611
|
+
badge_text: readableTextForPair(lightBadgeBg, lightAccentStrong),
|
|
612
|
+
tag_bg: lightTagBg,
|
|
613
|
+
tag_text: readableTextForPair(lightTagBg, lightSecondary),
|
|
614
|
+
focus_ring: rgba(primaryRgb, 0.22),
|
|
615
|
+
gloss: rgba(primaryRgb, style.hasGlass ? 0.2 : 0.14)
|
|
616
|
+
},
|
|
617
|
+
dark: {
|
|
618
|
+
...base.dark,
|
|
619
|
+
accent: darkAccent,
|
|
620
|
+
accent_strong: darkAccentStrong,
|
|
621
|
+
secondary: darkSecondary,
|
|
622
|
+
bg: colorToHex(darkBgRgb),
|
|
623
|
+
panel: colorToHex(darkPanelRgb),
|
|
624
|
+
panel_soft: colorToHex(mixRgb(tertiaryRgb, darkPanelRgb, 0.12)),
|
|
625
|
+
text: darkText ?? readableTextFor(darkPanelRgb),
|
|
626
|
+
muted: colorToHex(mixRgb(parseHexColor(darkText) ?? { r: 248, g: 250, b: 252 }, darkPanelRgb, 0.7)),
|
|
627
|
+
border: colorToHex(mixRgb(primaryRgb, darkPanelRgb, 0.26)),
|
|
628
|
+
code_bg: colorToHex(mixRgb(darkBgRgb, { r: 0, g: 0, b: 0 }, 0.76)),
|
|
629
|
+
shadow: `0 24px 80px ${rgba({ r: 0, g: 0, b: 0 }, style.hasShadow ? 0.38 : 0.3)}`,
|
|
630
|
+
shadow_strong: `0 36px 120px ${rgba({ r: 0, g: 0, b: 0 }, style.hasShadow ? 0.55 : 0.45)}`,
|
|
631
|
+
radius,
|
|
632
|
+
font_family: fontFamily,
|
|
633
|
+
sidebar_bg: `linear-gradient(180deg, ${rgba(darkPanelRgb, 0.95)}, ${rgba(darkBgRgb, 0.92)})`,
|
|
634
|
+
hero_gradient: style.hasGlow
|
|
635
|
+
? `radial-gradient(circle at top left, ${rgba(primaryRgb, 0.3)}, transparent 34%), linear-gradient(${angle}, ${colorToHex(mixRgb(primaryRgb, darkPanelRgb, 0.16))} 0%, ${colorToHex(darkBgRgb)} 100%)`
|
|
636
|
+
: `linear-gradient(${angle}, ${colorToHex(mixRgb(primaryRgb, darkPanelRgb, 0.14))} 0%, ${colorToHex(darkBgRgb)} 100%)`,
|
|
637
|
+
card_gradient: style.hasGlass
|
|
638
|
+
? `linear-gradient(180deg, ${rgba(mixRgb(primaryRgb, darkPanelRgb, 0.08), 0.86)} 0%, ${rgba(darkPanelRgb, 0.72)} 100%)`
|
|
639
|
+
: `linear-gradient(180deg, ${colorToHex(mixRgb(primaryRgb, darkPanelRgb, 0.08))} 0%, ${colorToHex(darkPanelRgb)} 100%)`,
|
|
640
|
+
brand_gradient: brandGradient,
|
|
641
|
+
brand_mark_text: readableTextFor(primaryRgb),
|
|
642
|
+
badge_bg: darkBadgeBg,
|
|
643
|
+
badge_text: readableTextForPair(darkBadgeBg, darkAccentStrong),
|
|
644
|
+
tag_bg: darkTagBg,
|
|
645
|
+
tag_text: readableTextForPair(darkTagBg, darkSecondary),
|
|
646
|
+
focus_ring: rgba(primaryRgb, 0.32),
|
|
647
|
+
gloss: rgba(primaryRgb, style.hasGlass ? 0.24 : 0.18)
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
function findStyleSources(root) {
|
|
652
|
+
const files = [];
|
|
653
|
+
collectStyleFiles(root, root, files, 0);
|
|
654
|
+
return files
|
|
655
|
+
.map((file) => ({
|
|
656
|
+
file,
|
|
657
|
+
score: styleFileScore((0, paths_1.relativeReportPath)(root, file)),
|
|
658
|
+
content: readStyleFile(file)
|
|
659
|
+
}))
|
|
660
|
+
.filter((source) => source.score > 0 && source.content.trim().length > 0)
|
|
661
|
+
.sort((a, b) => b.score - a.score || a.file.localeCompare(b.file))
|
|
662
|
+
.slice(0, 16);
|
|
663
|
+
}
|
|
664
|
+
function collectStyleFiles(root, directory, files, depth) {
|
|
665
|
+
if (files.length >= 180 || depth > 6) {
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
let entries;
|
|
669
|
+
try {
|
|
670
|
+
entries = fs_1.default.readdirSync(directory, { withFileTypes: true });
|
|
671
|
+
}
|
|
672
|
+
catch {
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
for (const entry of entries) {
|
|
676
|
+
if (entry.name.startsWith(".") && entry.name !== ".storybook") {
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
const file = path_1.default.join(directory, entry.name);
|
|
680
|
+
const relative = (0, paths_1.relativeReportPath)(root, file);
|
|
681
|
+
if (entry.isDirectory()) {
|
|
682
|
+
if (!ignoredStyleDirectory(entry.name)) {
|
|
683
|
+
collectStyleFiles(root, file, files, depth + 1);
|
|
684
|
+
}
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
if (entry.isFile() && styleFileScore(relative) > 0) {
|
|
688
|
+
files.push(file);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
function ignoredStyleDirectory(name) {
|
|
693
|
+
return [
|
|
694
|
+
".git",
|
|
695
|
+
".wikiwiki",
|
|
696
|
+
"node_modules",
|
|
697
|
+
"dist",
|
|
698
|
+
"build",
|
|
699
|
+
"coverage",
|
|
700
|
+
".next",
|
|
701
|
+
".nuxt",
|
|
702
|
+
".svelte-kit",
|
|
703
|
+
"wiki",
|
|
704
|
+
"wiki-site"
|
|
705
|
+
].includes(name);
|
|
706
|
+
}
|
|
707
|
+
function styleFileScore(file) {
|
|
708
|
+
const lower = file.toLowerCase();
|
|
709
|
+
const ext = path_1.default.extname(lower);
|
|
710
|
+
if (lower.endsWith(".min.css")) {
|
|
711
|
+
return 0;
|
|
712
|
+
}
|
|
713
|
+
let score = 0;
|
|
714
|
+
if ([".css", ".scss", ".sass", ".less", ".pcss", ".postcss"].includes(ext)) {
|
|
715
|
+
score += 24;
|
|
716
|
+
}
|
|
717
|
+
else if ([".ts", ".tsx", ".js", ".jsx", ".json"].includes(ext)) {
|
|
718
|
+
if (!/(^|\/)(tailwind\.config|theme\.config|[^/]*(theme|tokens?|design|palette|brand)[^/]*)\./.test(lower)) {
|
|
719
|
+
return 0;
|
|
720
|
+
}
|
|
721
|
+
score += 2;
|
|
722
|
+
}
|
|
723
|
+
else {
|
|
724
|
+
return 0;
|
|
725
|
+
}
|
|
726
|
+
if (/(^|\/)(global|globals|app|layout|landing|home|shell|theme|themes|tokens?|design|palette|brand)[^/]*\./.test(lower)) {
|
|
727
|
+
score += 18;
|
|
728
|
+
}
|
|
729
|
+
if (/(^|\/)(src|app|pages|styles?|css|theme|tokens?|design-system|components)\//.test(lower)) {
|
|
730
|
+
score += 8;
|
|
731
|
+
}
|
|
732
|
+
if (/tailwind\.config|theme\.config|tokens?\.json|design-tokens/.test(lower)) {
|
|
733
|
+
score += 12;
|
|
734
|
+
}
|
|
735
|
+
if (/(test|spec|fixture|mock|snapshot|storybook-static)/.test(lower)) {
|
|
736
|
+
score -= 12;
|
|
737
|
+
}
|
|
738
|
+
return Math.max(0, score);
|
|
739
|
+
}
|
|
740
|
+
function readStyleFile(file) {
|
|
741
|
+
try {
|
|
742
|
+
const stat = fs_1.default.statSync(file);
|
|
743
|
+
if (stat.size > 240000) {
|
|
744
|
+
return fs_1.default.readFileSync(file, "utf8").slice(0, 240000);
|
|
745
|
+
}
|
|
746
|
+
return fs_1.default.readFileSync(file, "utf8");
|
|
747
|
+
}
|
|
748
|
+
catch {
|
|
749
|
+
return "";
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
function extractStyleColors(sources) {
|
|
753
|
+
const colors = new Map();
|
|
754
|
+
for (const source of sources) {
|
|
755
|
+
const pattern = /#(?:[0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})\b/gi;
|
|
756
|
+
let match;
|
|
757
|
+
while ((match = pattern.exec(source.content)) !== null) {
|
|
758
|
+
const hex = normalizeHexColor(match[0]);
|
|
759
|
+
const rgb = parseHexColor(hex);
|
|
760
|
+
if (!rgb) {
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
const context = source.content.slice(Math.max(0, match.index - 90), Math.min(source.content.length, match.index + 120)).toLowerCase();
|
|
764
|
+
const existing = colors.get(hex) ?? {
|
|
765
|
+
hex,
|
|
766
|
+
rgb,
|
|
767
|
+
count: 0,
|
|
768
|
+
score: 0,
|
|
769
|
+
contexts: []
|
|
770
|
+
};
|
|
771
|
+
existing.count += 1;
|
|
772
|
+
existing.score += source.score + colorContextScore(context) + colorfulness(rgb) * 10;
|
|
773
|
+
if (existing.contexts.length < 8) {
|
|
774
|
+
existing.contexts.push(context);
|
|
775
|
+
}
|
|
776
|
+
colors.set(hex, existing);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
return [...colors.values()].sort((a, b) => b.score - a.score || b.count - a.count || a.hex.localeCompare(b.hex));
|
|
780
|
+
}
|
|
781
|
+
function colorContextScore(context) {
|
|
782
|
+
let score = 0;
|
|
783
|
+
if (/(accent|brand|primary|spectrum|rainbow|highlight|active|selected|focus)/.test(context)) {
|
|
784
|
+
score += 24;
|
|
785
|
+
}
|
|
786
|
+
if (/(rose|pink|red|orange|yellow|green|cyan|blue|violet|purple)/.test(context)) {
|
|
787
|
+
score += 10;
|
|
788
|
+
}
|
|
789
|
+
if (/(bg|background|body|shell|surface|panel|card|glass)/.test(context)) {
|
|
790
|
+
score += 8;
|
|
791
|
+
}
|
|
792
|
+
if (/(text|foreground|color)/.test(context)) {
|
|
793
|
+
score += 4;
|
|
794
|
+
}
|
|
795
|
+
if (/(border|shadow|overlay)/.test(context)) {
|
|
796
|
+
score += 2;
|
|
797
|
+
}
|
|
798
|
+
return score;
|
|
799
|
+
}
|
|
800
|
+
function accentColors(colors) {
|
|
801
|
+
return colors
|
|
802
|
+
.filter((color) => {
|
|
803
|
+
const luminance = relativeLuminance(color.rgb);
|
|
804
|
+
const context = color.contexts.join(" ");
|
|
805
|
+
const explicitAccent = /(accent|brand|primary|spectrum|rainbow|highlight|active|selected|focus)/.test(context);
|
|
806
|
+
const textLike = /(muted|text|foreground|fg)/.test(context);
|
|
807
|
+
return colorfulness(color.rgb) >= 0.25 && luminance > 0.08 && luminance < 0.9 && (explicitAccent || !textLike);
|
|
808
|
+
})
|
|
809
|
+
.sort((a, b) => {
|
|
810
|
+
const aAccent = accentContextScore(a);
|
|
811
|
+
const bAccent = accentContextScore(b);
|
|
812
|
+
return bAccent - aAccent || b.score - a.score || a.hex.localeCompare(b.hex);
|
|
813
|
+
})
|
|
814
|
+
.slice(0, 5)
|
|
815
|
+
.map((color) => color.hex);
|
|
816
|
+
}
|
|
817
|
+
function accentContextScore(color) {
|
|
818
|
+
const context = color.contexts.join(" ");
|
|
819
|
+
return color.score
|
|
820
|
+
+ colorfulness(color.rgb) * 30
|
|
821
|
+
+ (/(accent|brand|primary|spectrum|rainbow|highlight|active|selected|focus)/.test(context) ? 60 : 0);
|
|
822
|
+
}
|
|
823
|
+
function surfaceColor(colors, mode, keywords) {
|
|
824
|
+
const candidates = colors.filter((color) => {
|
|
825
|
+
const luminance = relativeLuminance(color.rgb);
|
|
826
|
+
const context = color.contexts.join(" ");
|
|
827
|
+
const hasKeyword = keywords.some((keyword) => context.includes(keyword));
|
|
828
|
+
return hasKeyword && (mode === "dark" ? luminance < 0.24 : luminance > 0.72);
|
|
829
|
+
});
|
|
830
|
+
candidates.sort((a, b) => surfaceKeywordScore(b, keywords) - surfaceKeywordScore(a, keywords) || b.score - a.score || (mode === "dark" ? relativeLuminance(a.rgb) - relativeLuminance(b.rgb) : relativeLuminance(b.rgb) - relativeLuminance(a.rgb)));
|
|
831
|
+
return candidates[0]?.hex;
|
|
832
|
+
}
|
|
833
|
+
function surfaceKeywordScore(color, keywords) {
|
|
834
|
+
const escapedHex = color.hex.replace("#", "\\#");
|
|
835
|
+
return color.contexts.reduce((score, context) => {
|
|
836
|
+
const declarationMatch = keywords.some((keyword) => new RegExp(`${keyword}[a-z0-9_-]*\\s*:\\s*${escapedHex}|[a-z0-9_-]*${keyword}[a-z0-9_-]*\\s*:\\s*${escapedHex}`, "i").test(context));
|
|
837
|
+
if (declarationMatch) {
|
|
838
|
+
return score + 100;
|
|
839
|
+
}
|
|
840
|
+
const keywordMatch = keywords.some((keyword) => context.includes(keyword));
|
|
841
|
+
return keywordMatch ? score + 10 : score;
|
|
842
|
+
}, 0);
|
|
843
|
+
}
|
|
844
|
+
function textColor(colors, mode) {
|
|
845
|
+
const candidates = colors.filter((color) => {
|
|
846
|
+
const luminance = relativeLuminance(color.rgb);
|
|
847
|
+
const context = color.contexts.join(" ");
|
|
848
|
+
const declarationScore = textDeclarationScore(color);
|
|
849
|
+
return (declarationScore > 0 || (/(text|foreground|color)/.test(context) && !/(bg|background|border|shadow)/.test(context)))
|
|
850
|
+
&& (mode === "dark" ? luminance > 0.74 : luminance < 0.28);
|
|
851
|
+
});
|
|
852
|
+
candidates.sort((a, b) => textDeclarationScore(b) - textDeclarationScore(a) || b.score - a.score || a.hex.localeCompare(b.hex));
|
|
853
|
+
return candidates[0]?.hex;
|
|
854
|
+
}
|
|
855
|
+
function textDeclarationScore(color) {
|
|
856
|
+
const escapedHex = color.hex.replace("#", "\\#");
|
|
857
|
+
return color.contexts.reduce((score, context) => {
|
|
858
|
+
const direct = new RegExp(`(?:text|foreground|fg|color)[a-z0-9_-]*\\s*:\\s*${escapedHex}|[a-z0-9_-]*(?:text|foreground|fg)[a-z0-9_-]*\\s*:\\s*${escapedHex}`, "i").test(context);
|
|
859
|
+
return direct ? score + 100 : score;
|
|
860
|
+
}, 0);
|
|
861
|
+
}
|
|
862
|
+
function inferRadius(sources) {
|
|
863
|
+
const candidates = [];
|
|
864
|
+
for (const source of sources) {
|
|
865
|
+
const pattern = /(?:border-radius|--[a-z0-9-]*radius[a-z0-9-]*)\s*:\s*([^;{}\n]+)/gi;
|
|
866
|
+
let match;
|
|
867
|
+
while ((match = pattern.exec(source.content)) !== null) {
|
|
868
|
+
const value = match[1].trim().split(/\s+/)[0].replace(/,$/, "");
|
|
869
|
+
const pixels = radiusPixels(value);
|
|
870
|
+
if (pixels >= 2 && pixels <= 40) {
|
|
871
|
+
candidates.push({ value, pixels, score: source.score + pixels });
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
candidates.sort((a, b) => b.score - a.score || b.pixels - a.pixels);
|
|
876
|
+
return candidates[0]?.value;
|
|
877
|
+
}
|
|
878
|
+
function radiusPixels(value) {
|
|
879
|
+
const match = /^([0-9]+(?:\.[0-9]+)?)(px|rem|em)$/i.exec(value);
|
|
880
|
+
if (!match) {
|
|
881
|
+
return 0;
|
|
882
|
+
}
|
|
883
|
+
const amount = Number.parseFloat(match[1]);
|
|
884
|
+
const unit = match[2].toLowerCase();
|
|
885
|
+
return unit === "px" ? amount : amount * 16;
|
|
886
|
+
}
|
|
887
|
+
function inferFontFamily(sources) {
|
|
888
|
+
for (const source of sources) {
|
|
889
|
+
const match = /font-family\s*:\s*([^;{}\n]+)/i.exec(source.content);
|
|
890
|
+
const value = match?.[1]?.trim();
|
|
891
|
+
if (value && !/^var\(/i.test(value) && !/inherit|initial|unset/i.test(value)) {
|
|
892
|
+
return value.replace(/\s+/g, " ");
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
return undefined;
|
|
896
|
+
}
|
|
897
|
+
function inferGradientAngle(sources) {
|
|
898
|
+
for (const source of sources) {
|
|
899
|
+
const match = /linear-gradient\(\s*([^,\)]+)/i.exec(source.content);
|
|
900
|
+
const value = match?.[1]?.trim();
|
|
901
|
+
if (value && (/^-?\d+(?:\.\d+)?deg$/.test(value) || /^to\s+/.test(value))) {
|
|
902
|
+
return value;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
return "135deg";
|
|
906
|
+
}
|
|
907
|
+
function plainText(value) {
|
|
908
|
+
const cleaned = value
|
|
909
|
+
?.replace(/<script[\s\S]*?<\/script>/gi, " ")
|
|
910
|
+
.replace(/<style[\s\S]*?<\/style>/gi, " ")
|
|
911
|
+
.replace(/<img\b[^>]*alt=["']([^"']*)["'][^>]*>/gi, " $1 ")
|
|
912
|
+
.replace(/<img\b[^>]*>/gi, " ")
|
|
913
|
+
.replace(/!\[[^\]]*]\([^)]+\)/g, " ")
|
|
914
|
+
.replace(/\[([^\]]+)]\([^)]+\)/g, "$1")
|
|
915
|
+
.replace(/<[^>]+>/g, " ")
|
|
916
|
+
.replace(/ /gi, " ")
|
|
917
|
+
.replace(/&/gi, "&")
|
|
918
|
+
.replace(/</gi, "<")
|
|
919
|
+
.replace(/>/gi, ">")
|
|
920
|
+
.replace(/"/gi, "\"")
|
|
921
|
+
.replace(/'/g, "'")
|
|
922
|
+
.replace(/[`*_~]/g, "")
|
|
923
|
+
.replace(/\s+/g, " ")
|
|
924
|
+
.trim();
|
|
925
|
+
return cleaned || undefined;
|
|
926
|
+
}
|
|
927
|
+
function gradientFromAccents(angle, accents) {
|
|
928
|
+
const stops = [...new Set(accents)].slice(0, 5);
|
|
929
|
+
return `linear-gradient(${angle}, ${stops.join(", ")})`;
|
|
930
|
+
}
|
|
931
|
+
function normalizeHexColor(value) {
|
|
932
|
+
const hex = value.replace(/^#/, "");
|
|
933
|
+
if (hex.length === 3) {
|
|
934
|
+
return `#${hex.split("").map((char) => `${char}${char}`).join("")}`.toLowerCase();
|
|
935
|
+
}
|
|
936
|
+
return `#${hex.slice(0, 6)}`.toLowerCase();
|
|
937
|
+
}
|
|
938
|
+
function parseHexColor(value) {
|
|
939
|
+
const trimmed = value?.trim();
|
|
940
|
+
if (!trimmed) {
|
|
941
|
+
return undefined;
|
|
942
|
+
}
|
|
943
|
+
const match = /^#([0-9a-f]{6})$/i.exec(normalizeHexColor(trimmed));
|
|
944
|
+
if (!match) {
|
|
945
|
+
return undefined;
|
|
946
|
+
}
|
|
947
|
+
return {
|
|
948
|
+
r: Number.parseInt(match[1].slice(0, 2), 16),
|
|
949
|
+
g: Number.parseInt(match[1].slice(2, 4), 16),
|
|
950
|
+
b: Number.parseInt(match[1].slice(4, 6), 16)
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
function colorToHex(color) {
|
|
954
|
+
return `#${[color.r, color.g, color.b]
|
|
955
|
+
.map((channel) => Math.round(Math.max(0, Math.min(255, channel))).toString(16).padStart(2, "0"))
|
|
956
|
+
.join("")}`;
|
|
957
|
+
}
|
|
958
|
+
function mixRgb(a, b, aWeight) {
|
|
959
|
+
const clamped = Math.max(0, Math.min(1, aWeight));
|
|
960
|
+
const bWeight = 1 - clamped;
|
|
961
|
+
return {
|
|
962
|
+
r: a.r * clamped + b.r * bWeight,
|
|
963
|
+
g: a.g * clamped + b.g * bWeight,
|
|
964
|
+
b: a.b * clamped + b.b * bWeight
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
function rgba(color, alpha) {
|
|
968
|
+
const clamped = Math.max(0, Math.min(1, alpha));
|
|
969
|
+
return `rgba(${Math.round(color.r)}, ${Math.round(color.g)}, ${Math.round(color.b)}, ${Number(clamped.toFixed(3))})`;
|
|
970
|
+
}
|
|
971
|
+
function relativeLuminance(color) {
|
|
972
|
+
const [r, g, b] = [color.r, color.g, color.b].map((channel) => {
|
|
973
|
+
const value = channel / 255;
|
|
974
|
+
return value <= 0.03928
|
|
975
|
+
? value / 12.92
|
|
976
|
+
: ((value + 0.055) / 1.055) ** 2.4;
|
|
977
|
+
});
|
|
978
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
979
|
+
}
|
|
980
|
+
function contrastRatio(a, b) {
|
|
981
|
+
const lighter = Math.max(relativeLuminance(a), relativeLuminance(b));
|
|
982
|
+
const darker = Math.min(relativeLuminance(a), relativeLuminance(b));
|
|
983
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
984
|
+
}
|
|
985
|
+
function readableTextFor(background) {
|
|
986
|
+
return relativeLuminance(background) > 0.5 ? "#111827" : "#f8fafc";
|
|
987
|
+
}
|
|
988
|
+
function readableTextForPair(background, preferred) {
|
|
989
|
+
const bg = parseHexColor(background);
|
|
990
|
+
const text = parseHexColor(preferred);
|
|
991
|
+
if (bg && text && contrastRatio(bg, text) >= 4.5) {
|
|
992
|
+
return preferred;
|
|
993
|
+
}
|
|
994
|
+
return bg ? readableTextFor(bg) : preferred;
|
|
995
|
+
}
|
|
996
|
+
function readableAccentFor(color, surface, mode) {
|
|
997
|
+
if (contrastRatio(color, surface) >= 3) {
|
|
998
|
+
return color;
|
|
999
|
+
}
|
|
1000
|
+
const target = mode === "dark" ? { r: 255, g: 255, b: 255 } : { r: 17, g: 24, b: 39 };
|
|
1001
|
+
for (const weight of [0.75, 0.6, 0.45, 0.3]) {
|
|
1002
|
+
const candidate = mixRgb(color, target, weight);
|
|
1003
|
+
if (contrastRatio(candidate, surface) >= 3) {
|
|
1004
|
+
return candidate;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
return target;
|
|
1008
|
+
}
|
|
1009
|
+
function colorfulness(color) {
|
|
1010
|
+
const max = Math.max(color.r, color.g, color.b);
|
|
1011
|
+
const min = Math.min(color.r, color.g, color.b);
|
|
1012
|
+
return max === 0 ? 0 : (max - min) / max;
|
|
1013
|
+
}
|
|
1014
|
+
function readPackageJson(root) {
|
|
1015
|
+
const file = path_1.default.join(root, "package.json");
|
|
1016
|
+
if (!fs_1.default.existsSync(file)) {
|
|
1017
|
+
return undefined;
|
|
1018
|
+
}
|
|
1019
|
+
try {
|
|
1020
|
+
const parsed = JSON.parse(fs_1.default.readFileSync(file, "utf8"));
|
|
1021
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
1022
|
+
? parsed
|
|
1023
|
+
: undefined;
|
|
1024
|
+
}
|
|
1025
|
+
catch {
|
|
1026
|
+
return undefined;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
function readReadme(root) {
|
|
1030
|
+
for (const fileName of ["README.md", "readme.md", "Readme.md"]) {
|
|
1031
|
+
const file = path_1.default.join(root, fileName);
|
|
1032
|
+
if (fs_1.default.existsSync(file)) {
|
|
1033
|
+
return fs_1.default.readFileSync(file, "utf8");
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
return undefined;
|
|
1037
|
+
}
|
|
1038
|
+
function readmeH1(readme) {
|
|
1039
|
+
const line = readme.split(/\r?\n/).find((item) => /^#\s+/.test(item.trim()));
|
|
1040
|
+
return plainText(line?.replace(/^#\s+/, "")) || undefined;
|
|
1041
|
+
}
|
|
1042
|
+
function firstUsefulReadmeParagraph(readme) {
|
|
1043
|
+
const withoutCode = readme.replace(/```[\s\S]*?```/g, "\n");
|
|
1044
|
+
const paragraphs = withoutCode.split(/\n{2,}/);
|
|
1045
|
+
for (const paragraph of paragraphs) {
|
|
1046
|
+
const normalized = paragraph
|
|
1047
|
+
.split(/\r?\n/)
|
|
1048
|
+
.map((line) => line.trim())
|
|
1049
|
+
.filter((line) => line && !line.startsWith("#") && !line.startsWith("!") && !line.startsWith("|"))
|
|
1050
|
+
.join(" ")
|
|
1051
|
+
.replace(/\s+/g, " ");
|
|
1052
|
+
const plain = plainText(normalized);
|
|
1053
|
+
if (plain && plain.length >= 24 && !/^(npm|wk|git|cd)\s/.test(plain)) {
|
|
1054
|
+
return plain;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
return undefined;
|
|
1058
|
+
}
|
|
1059
|
+
function prettyPackageName(value) {
|
|
1060
|
+
const unscoped = value.replace(/^@[^/]+\//, "");
|
|
1061
|
+
return unscoped
|
|
1062
|
+
.replace(/[-_]+/g, " ")
|
|
1063
|
+
.replace(/\s+/g, " ")
|
|
1064
|
+
.trim()
|
|
1065
|
+
.replace(/\b\w/g, (char) => char.toUpperCase()) || value;
|
|
1066
|
+
}
|
|
1067
|
+
function countKeyword(text, keyword) {
|
|
1068
|
+
const escaped = keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1069
|
+
return (text.match(new RegExp(`\\b${escaped}\\b`, "g")) ?? []).length;
|
|
1070
|
+
}
|
|
1071
|
+
function stableHash(value) {
|
|
1072
|
+
let hash = 0;
|
|
1073
|
+
for (const char of value) {
|
|
1074
|
+
hash = ((hash << 5) - hash + char.charCodeAt(0)) | 0;
|
|
1075
|
+
}
|
|
1076
|
+
return Math.abs(hash);
|
|
1077
|
+
}
|
|
1078
|
+
const moodKeywords = {
|
|
1079
|
+
calm: ["local", "private", "privacy", "wellness", "calm", "care", "notes", "knowledge"],
|
|
1080
|
+
vivid: ["brand", "visual", "design", "product", "creative", "marketing", "launch"],
|
|
1081
|
+
editorial: ["wiki", "docs", "documentation", "writing", "publishing", "knowledge", "reader"],
|
|
1082
|
+
utility: ["cli", "api", "tool", "automation", "developer", "system", "script", "test"],
|
|
1083
|
+
playful: ["game", "play", "playful", "toy", "fun", "music", "art", "sprite"],
|
|
1084
|
+
dark: ["terminal", "security", "ops", "infra", "backend", "night", "dark", "monitor"]
|
|
1085
|
+
};
|
|
1086
|
+
//# sourceMappingURL=theme.js.map
|