@diagrammo/dgmo 0.8.18 → 0.8.20
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/dist/cli.cjs +89 -130
- package/dist/index.cjs +1202 -993
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +216 -114
- package/dist/index.d.ts +216 -114
- package/dist/index.js +1211 -985
- package/dist/index.js.map +1 -1
- package/docs/language-reference.md +73 -0
- package/package.json +22 -9
- package/src/boxes-and-lines/parser.ts +8 -3
- package/src/c4/parser.ts +8 -7
- package/src/class/parser.ts +6 -0
- package/src/cli.ts +1 -9
- package/src/d3.ts +16 -234
- package/src/dgmo-router.ts +97 -5
- package/src/diagnostics.ts +16 -6
- package/src/echarts.ts +43 -10
- package/src/er/parser.ts +22 -2
- package/src/gantt/renderer.ts +153 -91
- package/src/graph/flowchart-parser.ts +89 -52
- package/src/graph/state-parser.ts +60 -35
- package/src/index.ts +23 -18
- package/src/infra/parser.ts +9 -2
- package/src/kanban/renderer.ts +2 -2
- package/src/palettes/color-utils.ts +4 -12
- package/src/palettes/index.ts +0 -4
- package/src/render.ts +30 -16
- package/src/sequence/collapse.ts +169 -0
- package/src/sequence/parser.ts +21 -4
- package/src/sequence/renderer.ts +198 -52
- package/src/sharing.ts +86 -49
- package/src/sitemap/renderer.ts +1 -6
- package/src/utils/arrows.ts +180 -11
- package/src/utils/d3-types.ts +4 -0
- package/src/utils/legend-constants.ts +11 -4
- package/src/utils/legend-d3.ts +171 -0
- package/src/utils/legend-layout.ts +140 -13
- package/src/utils/legend-types.ts +45 -0
- package/src/utils/time-ticks.ts +213 -0
- package/src/branding.ts +0 -67
- package/src/dgmo-mermaid.ts +0 -262
- package/src/palettes/mermaid-bridge.ts +0 -220
package/src/dgmo-mermaid.ts
DELETED
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// .dgmo → Mermaid Translation Layer
|
|
3
|
-
// Parses dgmo quadrant syntax and generates valid Mermaid code.
|
|
4
|
-
// ============================================================
|
|
5
|
-
|
|
6
|
-
import { resolveColorWithDiagnostic } from './colors';
|
|
7
|
-
import type { DgmoError } from './diagnostics';
|
|
8
|
-
import { makeDgmoError, formatDgmoError } from './diagnostics';
|
|
9
|
-
|
|
10
|
-
// ============================================================
|
|
11
|
-
// Types
|
|
12
|
-
// ============================================================
|
|
13
|
-
|
|
14
|
-
interface QuadrantLabel {
|
|
15
|
-
text: string;
|
|
16
|
-
color: string | null;
|
|
17
|
-
lineNumber: number;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface ParsedQuadrant {
|
|
21
|
-
title: string | null;
|
|
22
|
-
titleLineNumber: number | null;
|
|
23
|
-
xAxis: [string, string] | null;
|
|
24
|
-
xAxisLineNumber: number | null;
|
|
25
|
-
yAxis: [string, string] | null;
|
|
26
|
-
yAxisLineNumber: number | null;
|
|
27
|
-
quadrants: {
|
|
28
|
-
topRight: QuadrantLabel | null;
|
|
29
|
-
topLeft: QuadrantLabel | null;
|
|
30
|
-
bottomLeft: QuadrantLabel | null;
|
|
31
|
-
bottomRight: QuadrantLabel | null;
|
|
32
|
-
};
|
|
33
|
-
points: { label: string; x: number; y: number; lineNumber: number }[];
|
|
34
|
-
diagnostics: DgmoError[];
|
|
35
|
-
error: string | null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// ============================================================
|
|
39
|
-
// Parser
|
|
40
|
-
// ============================================================
|
|
41
|
-
|
|
42
|
-
/** Regex for quadrant label lines: `top-right Promote (green)` */
|
|
43
|
-
const QUADRANT_LABEL_RE = /^(.+?)(?:\s*\(([^)]+)\))?\s*$/;
|
|
44
|
-
|
|
45
|
-
/** Regex for data point lines: `Label 0.9, 0.5` */
|
|
46
|
-
const DATA_POINT_RE = /^(.+?)\s+([0-9]*\.?[0-9]+)\s*,\s*([0-9]*\.?[0-9]+)\s*$/;
|
|
47
|
-
|
|
48
|
-
const QUADRANT_POSITIONS = new Set([
|
|
49
|
-
'top-right',
|
|
50
|
-
'top-left',
|
|
51
|
-
'bottom-left',
|
|
52
|
-
'bottom-right',
|
|
53
|
-
]);
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Parses a .dgmo quadrant document into a structured object.
|
|
57
|
-
* Lines are processed sequentially; unknown lines are silently skipped.
|
|
58
|
-
*/
|
|
59
|
-
export function parseQuadrant(content: string): ParsedQuadrant {
|
|
60
|
-
const result: ParsedQuadrant = {
|
|
61
|
-
title: null,
|
|
62
|
-
titleLineNumber: null,
|
|
63
|
-
xAxis: null,
|
|
64
|
-
xAxisLineNumber: null,
|
|
65
|
-
yAxis: null,
|
|
66
|
-
yAxisLineNumber: null,
|
|
67
|
-
quadrants: {
|
|
68
|
-
topRight: null,
|
|
69
|
-
topLeft: null,
|
|
70
|
-
bottomLeft: null,
|
|
71
|
-
bottomRight: null,
|
|
72
|
-
},
|
|
73
|
-
points: [],
|
|
74
|
-
diagnostics: [],
|
|
75
|
-
error: null,
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const lines = content.split('\n');
|
|
79
|
-
|
|
80
|
-
for (let i = 0; i < lines.length; i++) {
|
|
81
|
-
const line = lines[i].trim();
|
|
82
|
-
const lineNumber = i + 1; // 1-indexed for editor
|
|
83
|
-
|
|
84
|
-
// Skip empty lines and comments
|
|
85
|
-
if (!line || line.startsWith('//')) continue;
|
|
86
|
-
|
|
87
|
-
// Skip the chart: directive (already consumed by router)
|
|
88
|
-
if (/^chart\s*:/i.test(line)) continue;
|
|
89
|
-
|
|
90
|
-
// title <text>
|
|
91
|
-
const titleMatch = line.match(/^title\s+(.+)/i);
|
|
92
|
-
if (titleMatch) {
|
|
93
|
-
result.title = titleMatch[1].trim();
|
|
94
|
-
result.titleLineNumber = lineNumber;
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// x-label Low, High
|
|
99
|
-
const xMatch = line.match(/^x-label\s+(.+)/i);
|
|
100
|
-
if (xMatch) {
|
|
101
|
-
const parts = xMatch[1].split(',').map((s) => s.trim());
|
|
102
|
-
if (parts.length >= 2) {
|
|
103
|
-
result.xAxis = [parts[0], parts[1]];
|
|
104
|
-
result.xAxisLineNumber = lineNumber;
|
|
105
|
-
}
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// y-label Low, High
|
|
110
|
-
const yMatch = line.match(/^y-label\s+(.+)/i);
|
|
111
|
-
if (yMatch) {
|
|
112
|
-
const parts = yMatch[1].split(',').map((s) => s.trim());
|
|
113
|
-
if (parts.length >= 2) {
|
|
114
|
-
result.yAxis = [parts[0], parts[1]];
|
|
115
|
-
result.yAxisLineNumber = lineNumber;
|
|
116
|
-
}
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Quadrant position labels: top-right Label (color)
|
|
121
|
-
const posMatch = line.match(
|
|
122
|
-
/^(top-right|top-left|bottom-left|bottom-right)\s+(.+)/i
|
|
123
|
-
);
|
|
124
|
-
if (posMatch) {
|
|
125
|
-
const position = posMatch[1].toLowerCase();
|
|
126
|
-
const labelMatch = posMatch[2].match(QUADRANT_LABEL_RE);
|
|
127
|
-
if (labelMatch) {
|
|
128
|
-
const label: QuadrantLabel = {
|
|
129
|
-
text: labelMatch[1].trim(),
|
|
130
|
-
color: labelMatch[2]
|
|
131
|
-
? (resolveColorWithDiagnostic(
|
|
132
|
-
labelMatch[2].trim(),
|
|
133
|
-
lineNumber,
|
|
134
|
-
result.diagnostics
|
|
135
|
-
) ?? null)
|
|
136
|
-
: null,
|
|
137
|
-
lineNumber,
|
|
138
|
-
};
|
|
139
|
-
if (position === 'top-right') result.quadrants.topRight = label;
|
|
140
|
-
else if (position === 'top-left') result.quadrants.topLeft = label;
|
|
141
|
-
else if (position === 'bottom-left')
|
|
142
|
-
result.quadrants.bottomLeft = label;
|
|
143
|
-
else if (position === 'bottom-right')
|
|
144
|
-
result.quadrants.bottomRight = label;
|
|
145
|
-
}
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Data points: Label x, y
|
|
150
|
-
const pointMatch = line.match(DATA_POINT_RE);
|
|
151
|
-
if (pointMatch) {
|
|
152
|
-
// Make sure this isn't a quadrant position keyword
|
|
153
|
-
const key = pointMatch[1].trim().toLowerCase();
|
|
154
|
-
if (!QUADRANT_POSITIONS.has(key)) {
|
|
155
|
-
result.points.push({
|
|
156
|
-
label: pointMatch[1].trim(),
|
|
157
|
-
x: parseFloat(pointMatch[2]),
|
|
158
|
-
y: parseFloat(pointMatch[3]),
|
|
159
|
-
lineNumber,
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
continue;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (result.points.length === 0) {
|
|
167
|
-
const diag = makeDgmoError(
|
|
168
|
-
1,
|
|
169
|
-
'No data points found. Add lines like: Label 0.5, 0.7'
|
|
170
|
-
);
|
|
171
|
-
result.diagnostics.push(diag);
|
|
172
|
-
result.error = formatDgmoError(diag);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return result;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// ============================================================
|
|
179
|
-
// Mermaid Builder
|
|
180
|
-
// ============================================================
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Generates valid Mermaid quadrantChart syntax from a parsed quadrant.
|
|
184
|
-
* Returns a string ready for the Mermaid renderer.
|
|
185
|
-
*/
|
|
186
|
-
export function buildMermaidQuadrant(
|
|
187
|
-
parsed: ParsedQuadrant,
|
|
188
|
-
options: {
|
|
189
|
-
isDark?: boolean;
|
|
190
|
-
textColor?: string;
|
|
191
|
-
mutedTextColor?: string;
|
|
192
|
-
} = {}
|
|
193
|
-
): string {
|
|
194
|
-
const { isDark = false, textColor, mutedTextColor } = options;
|
|
195
|
-
const lines: string[] = [];
|
|
196
|
-
|
|
197
|
-
// %%{init}%% block — fill colors with reduced opacity + text color overrides
|
|
198
|
-
const fillAlpha = isDark ? '30' : '55';
|
|
199
|
-
const primaryText = textColor ?? (isDark ? '#d0d0d0' : '#333333');
|
|
200
|
-
const quadrantLabelText = mutedTextColor ?? (isDark ? '#888888' : '#666666');
|
|
201
|
-
|
|
202
|
-
const colorMap: Record<string, string> = {};
|
|
203
|
-
if (parsed.quadrants.topRight?.color)
|
|
204
|
-
colorMap.quadrant1Fill = parsed.quadrants.topRight.color + fillAlpha;
|
|
205
|
-
if (parsed.quadrants.topLeft?.color)
|
|
206
|
-
colorMap.quadrant2Fill = parsed.quadrants.topLeft.color + fillAlpha;
|
|
207
|
-
if (parsed.quadrants.bottomLeft?.color)
|
|
208
|
-
colorMap.quadrant3Fill = parsed.quadrants.bottomLeft.color + fillAlpha;
|
|
209
|
-
if (parsed.quadrants.bottomRight?.color)
|
|
210
|
-
colorMap.quadrant4Fill = parsed.quadrants.bottomRight.color + fillAlpha;
|
|
211
|
-
|
|
212
|
-
// Quadrant labels use muted color, points use primary text color
|
|
213
|
-
colorMap.quadrant1TextFill = quadrantLabelText;
|
|
214
|
-
colorMap.quadrant2TextFill = quadrantLabelText;
|
|
215
|
-
colorMap.quadrant3TextFill = quadrantLabelText;
|
|
216
|
-
colorMap.quadrant4TextFill = quadrantLabelText;
|
|
217
|
-
colorMap.quadrantPointTextFill = primaryText;
|
|
218
|
-
colorMap.quadrantXAxisTextFill = primaryText;
|
|
219
|
-
colorMap.quadrantYAxisTextFill = primaryText;
|
|
220
|
-
colorMap.quadrantTitleFill = primaryText;
|
|
221
|
-
|
|
222
|
-
const vars = JSON.stringify(colorMap);
|
|
223
|
-
lines.push(`%%{init: {"themeVariables": ${vars}}}%%`);
|
|
224
|
-
|
|
225
|
-
lines.push('quadrantChart');
|
|
226
|
-
|
|
227
|
-
if (parsed.title) {
|
|
228
|
-
lines.push(` title ${parsed.title}`);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (parsed.xAxis) {
|
|
232
|
-
lines.push(` x-axis ${parsed.xAxis[0]} --> ${parsed.xAxis[1]}`);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (parsed.yAxis) {
|
|
236
|
-
lines.push(` y-axis ${parsed.yAxis[0]} --> ${parsed.yAxis[1]}`);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Helper to quote labels that need it (contain spaces or special chars)
|
|
240
|
-
const quote = (s: string): string => (/[\s,:[\]]/.test(s) ? `"${s}"` : s);
|
|
241
|
-
|
|
242
|
-
// Quadrant labels: 1=top-right, 2=top-left, 3=bottom-left, 4=bottom-right
|
|
243
|
-
if (parsed.quadrants.topRight) {
|
|
244
|
-
lines.push(` quadrant-1 ${quote(parsed.quadrants.topRight.text)}`);
|
|
245
|
-
}
|
|
246
|
-
if (parsed.quadrants.topLeft) {
|
|
247
|
-
lines.push(` quadrant-2 ${quote(parsed.quadrants.topLeft.text)}`);
|
|
248
|
-
}
|
|
249
|
-
if (parsed.quadrants.bottomLeft) {
|
|
250
|
-
lines.push(` quadrant-3 ${quote(parsed.quadrants.bottomLeft.text)}`);
|
|
251
|
-
}
|
|
252
|
-
if (parsed.quadrants.bottomRight) {
|
|
253
|
-
lines.push(` quadrant-4 ${quote(parsed.quadrants.bottomRight.text)}`);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Data points
|
|
257
|
-
for (const point of parsed.points) {
|
|
258
|
-
lines.push(` ${quote(point.label)}: [${point.x}, ${point.y}]`);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
return lines.join('\n');
|
|
262
|
-
}
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
import type { PaletteColors } from './types';
|
|
2
|
-
import { mute, tint, shade, contrastText } from './color-utils';
|
|
3
|
-
|
|
4
|
-
// ============================================================
|
|
5
|
-
// Mermaid Theme Variable Generator
|
|
6
|
-
// ============================================================
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Generates ~121 Mermaid theme variables from palette tokens.
|
|
10
|
-
* Replaces the hardcoded lightThemeVars/darkThemeVars objects.
|
|
11
|
-
*
|
|
12
|
-
* Dark mode fills use `mute()` to derive desaturated variants
|
|
13
|
-
* that are readable with light text.
|
|
14
|
-
*/
|
|
15
|
-
export function buildMermaidThemeVars(
|
|
16
|
-
colors: PaletteColors,
|
|
17
|
-
isDark: boolean
|
|
18
|
-
): Record<string, string> {
|
|
19
|
-
const c = colors.colors;
|
|
20
|
-
|
|
21
|
-
// Ordered accent array for pie/cScale/fillType/actor slots
|
|
22
|
-
const accentOrder = [
|
|
23
|
-
c.blue,
|
|
24
|
-
c.red,
|
|
25
|
-
c.green,
|
|
26
|
-
c.yellow,
|
|
27
|
-
c.purple,
|
|
28
|
-
c.orange,
|
|
29
|
-
c.teal,
|
|
30
|
-
c.cyan,
|
|
31
|
-
colors.secondary,
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
// Dark mode fills use muted variants for readability
|
|
35
|
-
const fills = isDark ? accentOrder.map(mute) : accentOrder;
|
|
36
|
-
|
|
37
|
-
return {
|
|
38
|
-
// ── Backgrounds ──
|
|
39
|
-
background: isDark ? colors.overlay : colors.border,
|
|
40
|
-
mainBkg: colors.surface,
|
|
41
|
-
|
|
42
|
-
// ── Primary/Secondary/Tertiary nodes ──
|
|
43
|
-
primaryColor: isDark ? colors.primary : colors.surface,
|
|
44
|
-
primaryTextColor: colors.text,
|
|
45
|
-
primaryBorderColor: isDark ? colors.secondary : colors.border,
|
|
46
|
-
secondaryColor: colors.secondary,
|
|
47
|
-
secondaryTextColor: contrastText(colors.secondary, colors.text, colors.bg),
|
|
48
|
-
secondaryBorderColor: colors.primary,
|
|
49
|
-
tertiaryColor: colors.accent,
|
|
50
|
-
tertiaryTextColor: contrastText(colors.accent, colors.text, colors.bg),
|
|
51
|
-
tertiaryBorderColor: colors.border,
|
|
52
|
-
|
|
53
|
-
// ── Lines & text ──
|
|
54
|
-
lineColor: colors.textMuted,
|
|
55
|
-
textColor: colors.text,
|
|
56
|
-
|
|
57
|
-
// ── Clusters ──
|
|
58
|
-
clusterBkg: colors.bg,
|
|
59
|
-
clusterBorder: isDark ? colors.border : colors.textMuted,
|
|
60
|
-
titleColor: colors.text,
|
|
61
|
-
|
|
62
|
-
// ── Labels ──
|
|
63
|
-
edgeLabelBackground: 'transparent',
|
|
64
|
-
|
|
65
|
-
// ── Notes (sequence diagrams) ──
|
|
66
|
-
noteBkgColor: colors.bg,
|
|
67
|
-
noteTextColor: colors.text,
|
|
68
|
-
noteBorderColor: isDark ? colors.border : colors.textMuted,
|
|
69
|
-
|
|
70
|
-
// ── Actors (sequence diagrams) ──
|
|
71
|
-
actorBkg: colors.surface,
|
|
72
|
-
actorTextColor: colors.text,
|
|
73
|
-
actorBorder: isDark ? colors.border : colors.textMuted,
|
|
74
|
-
actorLineColor: colors.textMuted,
|
|
75
|
-
|
|
76
|
-
// ── Signals (sequence diagrams) ──
|
|
77
|
-
signalColor: colors.textMuted,
|
|
78
|
-
signalTextColor: colors.text,
|
|
79
|
-
|
|
80
|
-
// ── Labels ──
|
|
81
|
-
labelColor: colors.text,
|
|
82
|
-
labelTextColor: colors.text,
|
|
83
|
-
labelBoxBkgColor: colors.surface,
|
|
84
|
-
labelBoxBorderColor: isDark ? colors.border : colors.textMuted,
|
|
85
|
-
|
|
86
|
-
// ── Loop boxes ──
|
|
87
|
-
loopTextColor: colors.text,
|
|
88
|
-
|
|
89
|
-
// ── Activation (sequence diagrams) ──
|
|
90
|
-
activationBkgColor: isDark ? colors.overlay : colors.border,
|
|
91
|
-
activationBorderColor: isDark ? colors.border : colors.textMuted,
|
|
92
|
-
|
|
93
|
-
// ── Sequence numbers ──
|
|
94
|
-
sequenceNumberColor: isDark ? colors.text : colors.bg,
|
|
95
|
-
|
|
96
|
-
// ── State diagrams ──
|
|
97
|
-
labelBackgroundColor: colors.surface,
|
|
98
|
-
|
|
99
|
-
// ── Pie chart (9 slices) ──
|
|
100
|
-
// Dark mode: use muted fills so light pieSectionTextColor stays readable
|
|
101
|
-
...Object.fromEntries(
|
|
102
|
-
(isDark ? fills : accentOrder).map((col, i) => [`pie${i + 1}`, col])
|
|
103
|
-
),
|
|
104
|
-
pieTitleTextColor: colors.text,
|
|
105
|
-
pieSectionTextColor: isDark ? colors.text : colors.bg,
|
|
106
|
-
pieLegendTextColor: colors.text,
|
|
107
|
-
pieStrokeColor: 'transparent',
|
|
108
|
-
pieOuterStrokeWidth: '0px',
|
|
109
|
-
pieOuterStrokeColor: 'transparent',
|
|
110
|
-
|
|
111
|
-
// ── cScale (9 tiers) — muted in dark mode ──
|
|
112
|
-
...Object.fromEntries(fills.map((f, i) => [`cScale${i}`, f])),
|
|
113
|
-
...Object.fromEntries(
|
|
114
|
-
fills.map((_, i) => [
|
|
115
|
-
`cScaleLabel${i}`,
|
|
116
|
-
isDark ? colors.text : i < 2 || i > 6 ? colors.bg : colors.text,
|
|
117
|
-
])
|
|
118
|
-
),
|
|
119
|
-
|
|
120
|
-
// ── fillType (8 slots) ──
|
|
121
|
-
...Object.fromEntries(
|
|
122
|
-
[0, 1, 2, 3, 4, 5, 6, 7].map((i) => [
|
|
123
|
-
`fillType${i}`,
|
|
124
|
-
fills[i % fills.length],
|
|
125
|
-
])
|
|
126
|
-
),
|
|
127
|
-
|
|
128
|
-
// ── Journey actors (6 slots) ──
|
|
129
|
-
...Object.fromEntries(
|
|
130
|
-
[c.red, c.green, c.yellow, c.purple, c.orange, c.teal].map((color, i) => [
|
|
131
|
-
`actor${i}`,
|
|
132
|
-
color,
|
|
133
|
-
])
|
|
134
|
-
),
|
|
135
|
-
|
|
136
|
-
// ── Flowchart ──
|
|
137
|
-
nodeBorder: isDark ? colors.border : colors.textMuted,
|
|
138
|
-
nodeTextColor: colors.text,
|
|
139
|
-
|
|
140
|
-
// ── Gantt ──
|
|
141
|
-
gridColor: isDark ? colors.textMuted : colors.border,
|
|
142
|
-
doneTaskBkgColor: c.green,
|
|
143
|
-
doneTaskBorderColor: isDark ? colors.border : colors.textMuted,
|
|
144
|
-
activeTaskBkgColor: colors.secondary,
|
|
145
|
-
activeTaskBorderColor: colors.primary,
|
|
146
|
-
critBkgColor: c.orange,
|
|
147
|
-
critBorderColor: c.red,
|
|
148
|
-
taskBkgColor: colors.surface,
|
|
149
|
-
taskBorderColor: isDark ? colors.border : colors.textMuted,
|
|
150
|
-
taskTextColor: contrastText(colors.surface, colors.text, colors.bg),
|
|
151
|
-
taskTextDarkColor: colors.bg,
|
|
152
|
-
taskTextLightColor: colors.text,
|
|
153
|
-
taskTextOutsideColor: colors.text,
|
|
154
|
-
doneTaskTextColor: contrastText(c.green, colors.text, colors.bg),
|
|
155
|
-
activeTaskTextColor: contrastText(colors.secondary, colors.text, colors.bg),
|
|
156
|
-
critTaskTextColor: contrastText(c.orange, colors.text, colors.bg),
|
|
157
|
-
sectionBkgColor: isDark
|
|
158
|
-
? shade(colors.primary, colors.bg, 0.6)
|
|
159
|
-
: tint(colors.primary, 0.6),
|
|
160
|
-
altSectionBkgColor: colors.bg,
|
|
161
|
-
sectionBkgColor2: isDark
|
|
162
|
-
? shade(colors.primary, colors.bg, 0.6)
|
|
163
|
-
: tint(colors.primary, 0.6),
|
|
164
|
-
todayLineColor: c.yellow,
|
|
165
|
-
|
|
166
|
-
// ── Quadrant ──
|
|
167
|
-
quadrant1Fill: isDark
|
|
168
|
-
? shade(c.green, colors.bg, 0.75)
|
|
169
|
-
: tint(c.green, 0.75),
|
|
170
|
-
quadrant2Fill: isDark ? shade(c.blue, colors.bg, 0.75) : tint(c.blue, 0.75),
|
|
171
|
-
quadrant3Fill: isDark ? shade(c.red, colors.bg, 0.75) : tint(c.red, 0.75),
|
|
172
|
-
quadrant4Fill: isDark
|
|
173
|
-
? shade(c.yellow, colors.bg, 0.75)
|
|
174
|
-
: tint(c.yellow, 0.75),
|
|
175
|
-
quadrant1TextFill: colors.text,
|
|
176
|
-
quadrant2TextFill: colors.text,
|
|
177
|
-
quadrant3TextFill: colors.text,
|
|
178
|
-
quadrant4TextFill: colors.text,
|
|
179
|
-
quadrantPointFill: isDark ? c.cyan : c.blue,
|
|
180
|
-
quadrantPointTextFill: colors.text,
|
|
181
|
-
quadrantXAxisTextFill: colors.text,
|
|
182
|
-
quadrantYAxisTextFill: colors.text,
|
|
183
|
-
quadrantTitleFill: colors.text,
|
|
184
|
-
quadrantInternalBorderStrokeFill: colors.border,
|
|
185
|
-
quadrantExternalBorderStrokeFill: colors.border,
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// ============================================================
|
|
190
|
-
// Mermaid Theme CSS Generator
|
|
191
|
-
// ============================================================
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Generates custom CSS overrides for Mermaid SVGs.
|
|
195
|
-
* Handles git graph label backgrounds and dark-mode text readability.
|
|
196
|
-
*/
|
|
197
|
-
export function buildThemeCSS(palette: PaletteColors, isDark: boolean): string {
|
|
198
|
-
const base = `
|
|
199
|
-
.branchLabelBkg { fill: transparent !important; stroke: transparent !important; }
|
|
200
|
-
.commit-label-bkg { fill: transparent !important; stroke: transparent !important; }
|
|
201
|
-
.tag-label-bkg { fill: transparent !important; stroke: transparent !important; }
|
|
202
|
-
|
|
203
|
-
/* GitGraph: ensure commit and branch label text matches palette */
|
|
204
|
-
.commit-label { fill: ${palette.text} !important; }
|
|
205
|
-
.branch-label { fill: ${palette.text} !important; }
|
|
206
|
-
.tag-label { fill: ${palette.text} !important; }
|
|
207
|
-
`;
|
|
208
|
-
|
|
209
|
-
if (!isDark) return base;
|
|
210
|
-
|
|
211
|
-
return (
|
|
212
|
-
base +
|
|
213
|
-
`
|
|
214
|
-
/* Flowchart: ensure node and edge label text is readable */
|
|
215
|
-
.nodeLabel, .label { color: ${palette.text} !important; fill: ${palette.text} !important; }
|
|
216
|
-
.edgeLabel { color: ${palette.text} !important; fill: ${palette.text} !important; }
|
|
217
|
-
.edgeLabel .label { color: ${palette.text} !important; fill: ${palette.text} !important; }
|
|
218
|
-
`
|
|
219
|
-
);
|
|
220
|
-
}
|