sdocs-dev 1.2.0 → 1.3.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/README.md +149 -0
- package/bin/sdocs-dev.js +282 -38
- package/package.json +6 -3
- package/public/{brotli-wasm.js → brotli-wasm-v1.js} +5 -6
- package/public/css/layout.css +3 -4
- package/public/css/mobile.css +7 -0
- package/public/css/panel.css +1 -1
- package/public/css/rendered.css +184 -1
- package/public/index.html +137 -43
- package/public/sdoc.md +542 -0
- package/public/sdocs-app.js +222 -63
- package/public/sdocs-charts.js +905 -0
- package/public/sdocs-controls.js +135 -53
- package/public/sdocs-export.js +939 -61
- package/public/sdocs-slugify.js +12 -0
- package/public/sdocs-state.js +14 -0
- package/public/sdocs-styles.js +180 -254
- package/public/sdocs-theme.js +21 -19
- package/public/sdocs-write.js +4 -1
- package/public/sw.js +5 -3
- package/public/vendor/purify.min.js +3 -0
- package/server.js +51 -3
- package/public/default.md +0 -255
package/public/sdocs-controls.js
CHANGED
|
@@ -6,7 +6,7 @@ var S = SDocs;
|
|
|
6
6
|
|
|
7
7
|
// ── CSS var updates ──────────────────────────────────
|
|
8
8
|
|
|
9
|
-
function
|
|
9
|
+
function applyControlToCss(id) {
|
|
10
10
|
var el = document.getElementById(id);
|
|
11
11
|
if (!el) return;
|
|
12
12
|
var v = el.value;
|
|
@@ -35,14 +35,14 @@ function readAllControlValues() {
|
|
|
35
35
|
return vals;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
function
|
|
38
|
+
function syncRangeAndNumber(rangeId, numId) {
|
|
39
39
|
var r = document.getElementById(rangeId);
|
|
40
40
|
var n = document.getElementById(numId);
|
|
41
|
-
r.addEventListener('input', function() { n.value = r.value;
|
|
42
|
-
n.addEventListener('input', function() { r.value = n.value;
|
|
41
|
+
r.addEventListener('input', function() { n.value = r.value; applyControlToCss(numId); });
|
|
42
|
+
n.addEventListener('input', function() { r.value = n.value; applyControlToCss(numId); });
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
SDocStyles.RANGE_NUM_PAIRS.forEach(function(pair) {
|
|
45
|
+
SDocStyles.RANGE_NUM_PAIRS.forEach(function(pair) { syncRangeAndNumber(pair[0], pair[1]); });
|
|
46
46
|
|
|
47
47
|
var STANDALONE_COLOR_IDS = new Set(SDocStyles.STANDALONE_COLOR_IDS);
|
|
48
48
|
|
|
@@ -50,10 +50,11 @@ var STANDALONE_COLOR_IDS = new Set(SDocStyles.STANDALONE_COLOR_IDS);
|
|
|
50
50
|
'ctrl-font-family','ctrl-h-font-family',
|
|
51
51
|
'ctrl-h1-weight','ctrl-h2-weight','ctrl-h3-weight','ctrl-h4-weight',
|
|
52
52
|
'ctrl-bg-color','ctrl-link-color','ctrl-link-decoration',
|
|
53
|
-
'ctrl-code-font',
|
|
54
|
-
'ctrl-bq-border-color',
|
|
53
|
+
'ctrl-code-font',
|
|
54
|
+
'ctrl-bq-border-color',
|
|
55
|
+
'ctrl-chart-accent','ctrl-chart-palette',
|
|
55
56
|
].forEach(function(id) {
|
|
56
|
-
var handler = function() { if (STANDALONE_COLOR_IDS.has(id)) S.overriddenColors.add(id);
|
|
57
|
+
var handler = function() { if (STANDALONE_COLOR_IDS.has(id)) S.overriddenColors.add(id); applyControlToCss(id); S.syncAll('controls'); };
|
|
57
58
|
document.getElementById(id).addEventListener('input', handler);
|
|
58
59
|
document.getElementById(id).addEventListener('change', handler);
|
|
59
60
|
});
|
|
@@ -65,7 +66,12 @@ var COLOR_CHILDREN = SDocStyles.COLOR_CASCADE;
|
|
|
65
66
|
|
|
66
67
|
function setColorValue(ctrlId, value, userAction) {
|
|
67
68
|
if (userAction) S.overriddenColors.add(ctrlId);
|
|
68
|
-
|
|
69
|
+
var varName = COLOR_VAR[ctrlId];
|
|
70
|
+
if (Array.isArray(varName)) {
|
|
71
|
+
varName.forEach(function(v) { S.setStyleVar(v, value); });
|
|
72
|
+
} else {
|
|
73
|
+
S.setStyleVar(varName, value);
|
|
74
|
+
}
|
|
69
75
|
var ctrl = document.getElementById(ctrlId);
|
|
70
76
|
if (ctrl) ctrl.value = value;
|
|
71
77
|
var children = COLOR_CHILDREN[ctrlId] || [];
|
|
@@ -74,30 +80,57 @@ function setColorValue(ctrlId, value, userAction) {
|
|
|
74
80
|
setColorValue(children[i], value, false);
|
|
75
81
|
}
|
|
76
82
|
}
|
|
83
|
+
// Refresh charts when block/chart colors change
|
|
84
|
+
if (S.refreshChartColors && (ctrlId === 'ctrl-chart-bg' || ctrlId === 'ctrl-chart-text' ||
|
|
85
|
+
ctrlId === 'ctrl-block-bg' || ctrlId === 'ctrl-block-text')) {
|
|
86
|
+
S.refreshChartColors();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function findParent(ctrlId) {
|
|
91
|
+
for (var pid in COLOR_CHILDREN) {
|
|
92
|
+
if (COLOR_CHILDREN[pid].indexOf(ctrlId) !== -1) return pid;
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
77
95
|
}
|
|
78
96
|
|
|
79
97
|
function resetColorValue(ctrlId) {
|
|
80
98
|
S.overriddenColors.delete(ctrlId);
|
|
81
|
-
|
|
99
|
+
var parent = findParent(ctrlId);
|
|
100
|
+
var value;
|
|
101
|
+
if (!parent) {
|
|
102
|
+
// Cascade root: use theme default
|
|
103
|
+
value = ctrlId === 'ctrl-color' ? S.getColorDefault() : S.getStandaloneDefault(ctrlId);
|
|
104
|
+
} else {
|
|
105
|
+
var parentEl = document.getElementById(parent);
|
|
106
|
+
value = parentEl ? parentEl.value : S.getColorDefault();
|
|
107
|
+
}
|
|
108
|
+
setColorValue(ctrlId, value, false);
|
|
82
109
|
}
|
|
83
110
|
|
|
84
111
|
Object.keys(COLOR_VAR).forEach(function(ctrlId) {
|
|
85
112
|
var el = document.getElementById(ctrlId);
|
|
86
113
|
if (!el) return;
|
|
87
|
-
|
|
88
|
-
el.addEventListener('
|
|
114
|
+
var handler = function() { setColorValue(ctrlId, el.value, true); S.syncAll('controls'); };
|
|
115
|
+
el.addEventListener('input', handler);
|
|
116
|
+
el.addEventListener('change', handler);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Cascade color reset buttons
|
|
120
|
+
document.getElementById('reset-color').addEventListener('click', function() { S.overriddenColors.delete('ctrl-color'); setColorValue('ctrl-color', S.getColorDefault(), false); S.syncAll('controls'); });
|
|
121
|
+
['ctrl-h-color','ctrl-h1-color','ctrl-h2-color','ctrl-h3-color','ctrl-h4-color','ctrl-p-color','ctrl-list-color'].forEach(function(ctrlId) {
|
|
122
|
+
var btn = document.getElementById('reset-' + ctrlId.replace('ctrl-', ''));
|
|
123
|
+
if (btn) btn.addEventListener('click', function() { resetColorValue(ctrlId); S.syncAll('controls'); });
|
|
89
124
|
});
|
|
90
125
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
document.getElementById('reset-p-color').addEventListener('click', function() { resetColorValue('ctrl-p-color'); S.syncAll('controls'); });
|
|
98
|
-
document.getElementById('reset-list-color').addEventListener('click', function() { resetColorValue('ctrl-list-color'); S.syncAll('controls'); });
|
|
126
|
+
// Block cascade resets
|
|
127
|
+
['ctrl-block-bg','ctrl-block-text','ctrl-code-bg','ctrl-code-color','ctrl-bq-bg','ctrl-bq-color','ctrl-chart-bg','ctrl-chart-text'].forEach(function(ctrlId) {
|
|
128
|
+
var btnId = 'reset-' + ctrlId.replace('ctrl-', '');
|
|
129
|
+
var btn = document.getElementById(btnId);
|
|
130
|
+
if (btn) btn.addEventListener('click', function() { resetColorValue(ctrlId); S.syncAll('controls'); });
|
|
131
|
+
});
|
|
99
132
|
|
|
100
|
-
['ctrl-bg-color','ctrl-link-color','ctrl-
|
|
133
|
+
['ctrl-bg-color','ctrl-link-color','ctrl-bq-border-color','ctrl-chart-accent'].forEach(function(ctrlId) {
|
|
101
134
|
var btnId = 'reset-' + ctrlId.replace('ctrl-', '');
|
|
102
135
|
document.getElementById(btnId).addEventListener('click', function() {
|
|
103
136
|
var defaultVal = S.getStandaloneDefault(ctrlId);
|
|
@@ -112,7 +145,7 @@ document.getElementById('reset-list-color').addEventListener('click', function()
|
|
|
112
145
|
|
|
113
146
|
// ── Apply styles from meta → controls ──────────────────
|
|
114
147
|
|
|
115
|
-
function
|
|
148
|
+
function setControlValue(id, val) {
|
|
116
149
|
if (val === undefined || val === null) return;
|
|
117
150
|
var el = document.getElementById(id);
|
|
118
151
|
if (!el) return;
|
|
@@ -120,7 +153,7 @@ function setCtrl(id, val) {
|
|
|
120
153
|
var rangeId = id.replace(/-num$/, '-range');
|
|
121
154
|
var rng = document.getElementById(rangeId);
|
|
122
155
|
if (rng) rng.value = val;
|
|
123
|
-
|
|
156
|
+
applyControlToCss(id);
|
|
124
157
|
}
|
|
125
158
|
|
|
126
159
|
function applyStylesFromMeta(s) {
|
|
@@ -142,31 +175,17 @@ function applyStylesFromMeta(s) {
|
|
|
142
175
|
return o.value.replace(/['"]/g,'').split(',')[0].trim() === fontName ||
|
|
143
176
|
o.textContent === fontName;
|
|
144
177
|
});
|
|
145
|
-
if (match) { sel.value = match.value;
|
|
178
|
+
if (match) { sel.value = match.value; applyControlToCss(ctrlId); }
|
|
146
179
|
}
|
|
147
180
|
});
|
|
148
181
|
|
|
149
182
|
Object.keys(controls).forEach(function(id) {
|
|
150
183
|
if (id === 'ctrl-font-family' || id === 'ctrl-h-font-family') return;
|
|
151
184
|
if (SDocStyles.COLOR_VAR_MAP[id]) return;
|
|
152
|
-
|
|
185
|
+
setControlValue(id, controls[id]);
|
|
153
186
|
});
|
|
154
187
|
|
|
155
|
-
|
|
156
|
-
// Per-theme color mode: populate both theme states
|
|
157
|
-
S.themeColors.light = result.lightColors || {};
|
|
158
|
-
S.themeColors.dark = result.darkColors || {};
|
|
159
|
-
S.themeOverridden.light = result.lightOverridden || new Set();
|
|
160
|
-
S.themeOverridden.dark = result.darkOverridden || new Set();
|
|
161
|
-
|
|
162
|
-
// Load the active theme's colors into controls
|
|
163
|
-
S._syncing = wasSyncing;
|
|
164
|
-
S.loadThemeColors(S.activeTheme);
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Legacy single-theme path: top-level colors go to light theme only,
|
|
169
|
-
// then loadThemeColors applies the correct theme's colors.
|
|
188
|
+
// Top-level colors = light theme. dark: block = explicit dark overrides.
|
|
170
189
|
var lightOverridden = S.themeOverridden.light;
|
|
171
190
|
var lightColors = S.themeColors.light;
|
|
172
191
|
var newOverridden = result.overriddenColors;
|
|
@@ -187,33 +206,88 @@ function applyStylesFromMeta(s) {
|
|
|
187
206
|
if (s.code.background) legacyStandalone.push(['ctrl-code-bg', s.code.background]);
|
|
188
207
|
if (s.code.color) legacyStandalone.push(['ctrl-code-color', s.code.color]);
|
|
189
208
|
}
|
|
209
|
+
if (s.blocks) {
|
|
210
|
+
if (s.blocks.background) legacyStandalone.push(['ctrl-block-bg', s.blocks.background]);
|
|
211
|
+
if (s.blocks.color) legacyStandalone.push(['ctrl-block-text', s.blocks.color]);
|
|
212
|
+
}
|
|
190
213
|
if (s.blockquote) {
|
|
191
214
|
if (s.blockquote.borderColor) legacyStandalone.push(['ctrl-bq-border-color', s.blockquote.borderColor]);
|
|
192
215
|
if (s.blockquote.background) legacyStandalone.push(['ctrl-bq-bg', s.blockquote.background]);
|
|
193
216
|
if (s.blockquote.color) legacyStandalone.push(['ctrl-bq-color', s.blockquote.color]);
|
|
194
217
|
}
|
|
218
|
+
if (s.chart) {
|
|
219
|
+
if (s.chart.background) legacyStandalone.push(['ctrl-chart-bg', s.chart.background]);
|
|
220
|
+
if (s.chart.textColor) legacyStandalone.push(['ctrl-chart-text', s.chart.textColor]);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// File-info card overrides (no UI controls — driven entirely by YAML).
|
|
224
|
+
S.fileinfoStyles = {};
|
|
225
|
+
if (s.fileinfo) {
|
|
226
|
+
if (s.fileinfo.background) {
|
|
227
|
+
S.fileinfoStyles.background = s.fileinfo.background;
|
|
228
|
+
S.setStyleVar('--md-fic-bg', s.fileinfo.background);
|
|
229
|
+
}
|
|
230
|
+
if (s.fileinfo.color) {
|
|
231
|
+
S.fileinfoStyles.color = s.fileinfo.color;
|
|
232
|
+
S.setStyleVar('--md-fic-text', s.fileinfo.color);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
195
235
|
legacyStandalone.forEach(function(pair) {
|
|
196
236
|
lightOverridden.add(pair[0]);
|
|
197
237
|
lightColors[pair[0]] = pair[1];
|
|
198
238
|
});
|
|
199
239
|
|
|
200
|
-
//
|
|
240
|
+
// Auto-generate dark theme from light colors via lightness inversion
|
|
241
|
+
var darkOverridden = S.themeOverridden.dark;
|
|
242
|
+
var darkColors = S.themeColors.dark;
|
|
243
|
+
|
|
244
|
+
// Parse explicit dark: overrides from YAML and persist for serialization
|
|
245
|
+
var explicitDark = s.dark ? SDocStyles.parseDarkBlock(s.dark) : {};
|
|
246
|
+
S._explicitDarkOverrides = s.dark || null;
|
|
247
|
+
|
|
248
|
+
// For every light color, auto-generate dark unless explicitly overridden
|
|
249
|
+
lightOverridden.forEach(function(id) {
|
|
250
|
+
if (explicitDark[id]) {
|
|
251
|
+
darkOverridden.add(id);
|
|
252
|
+
darkColors[id] = explicitDark[id];
|
|
253
|
+
} else {
|
|
254
|
+
darkOverridden.add(id);
|
|
255
|
+
darkColors[id] = SDocStyles.invertLightness(lightColors[id]);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// Also apply any dark: colors that weren't in light (e.g. dark-only overrides)
|
|
260
|
+
Object.keys(explicitDark).forEach(function(id) {
|
|
261
|
+
if (!darkOverridden.has(id)) {
|
|
262
|
+
darkOverridden.add(id);
|
|
263
|
+
darkColors[id] = explicitDark[id];
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Now apply the active theme's colors
|
|
201
268
|
S._syncing = wasSyncing;
|
|
202
269
|
S.loadThemeColors(S.activeTheme);
|
|
203
270
|
}
|
|
204
271
|
|
|
205
272
|
function collectStyles() {
|
|
206
273
|
S.saveCurrentThemeColors();
|
|
207
|
-
|
|
208
|
-
var
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
274
|
+
// Always emit top-level colors (light) via the simple collector
|
|
275
|
+
var styles = SDocStyles.collectStyles(readAllControlValues(), S.overriddenColors);
|
|
276
|
+
|
|
277
|
+
// Emit dark: block for any explicitly set dark overrides
|
|
278
|
+
// (don't emit auto-inverted values — those are generated on load)
|
|
279
|
+
if (S._explicitDarkOverrides && Object.keys(S._explicitDarkOverrides).length > 0) {
|
|
280
|
+
var darkBlock = SDocStyles.parseDarkBlock(S._explicitDarkOverrides);
|
|
281
|
+
// parseDarkBlock expects the YAML format, but _explicitDarkOverrides IS the YAML dark: object
|
|
282
|
+
styles.dark = S._explicitDarkOverrides;
|
|
215
283
|
}
|
|
216
|
-
|
|
284
|
+
|
|
285
|
+
// File-info card overrides (no UI controls; round-trip from YAML)
|
|
286
|
+
if (S.fileinfoStyles && Object.keys(S.fileinfoStyles).length > 0) {
|
|
287
|
+
styles.fileinfo = Object.assign({}, S.fileinfoStyles);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return styles;
|
|
217
291
|
}
|
|
218
292
|
|
|
219
293
|
// ── Reset all styles ──────────────────────────────────
|
|
@@ -224,8 +298,15 @@ function resetAllStyles() {
|
|
|
224
298
|
S.themeOverridden.dark.clear();
|
|
225
299
|
S.themeColors.light = {};
|
|
226
300
|
S.themeColors.dark = {};
|
|
301
|
+
// Clear file-info-card overrides and the CSS vars they set
|
|
302
|
+
S.fileinfoStyles = {};
|
|
303
|
+
S.setStyleVar('--md-fic-bg', '');
|
|
304
|
+
S.setStyleVar('--md-fic-text', '');
|
|
227
305
|
|
|
228
306
|
setColorValue('ctrl-color', S.getColorDefault(), false);
|
|
307
|
+
// Reset block cascade roots to theme defaults
|
|
308
|
+
setColorValue('ctrl-block-bg', S.getStandaloneDefault('ctrl-block-bg') || '#f4f1ed', false);
|
|
309
|
+
setColorValue('ctrl-block-text', S.getStandaloneDefault('ctrl-block-text') || '#6b6560', false);
|
|
229
310
|
// Set standalone color controls to theme-appropriate defaults
|
|
230
311
|
STANDALONE_COLOR_IDS.forEach(function(ctrlId) {
|
|
231
312
|
var el = document.getElementById(ctrlId);
|
|
@@ -243,10 +324,11 @@ function resetAllStyles() {
|
|
|
243
324
|
'ctrl-h3-size-num','ctrl-h3-weight','ctrl-h4-size-num','ctrl-h4-weight',
|
|
244
325
|
'ctrl-p-lh-num','ctrl-p-mb-num',
|
|
245
326
|
'ctrl-link-color','ctrl-link-decoration',
|
|
246
|
-
'ctrl-code-font',
|
|
247
|
-
'ctrl-bq-border-color','ctrl-bq-
|
|
327
|
+
'ctrl-code-font',
|
|
328
|
+
'ctrl-bq-border-color','ctrl-bq-bw-num','ctrl-bq-size-num',
|
|
248
329
|
'ctrl-list-spacing-num','ctrl-list-indent-num',
|
|
249
|
-
|
|
330
|
+
'ctrl-chart-accent','ctrl-chart-palette',
|
|
331
|
+
].forEach(function(id) { applyControlToCss(id); });
|
|
250
332
|
}
|
|
251
333
|
|
|
252
334
|
// ── Init: set colors to theme-appropriate defaults ──────
|