sdocs-dev 1.0.0 → 1.1.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/bin/sdocs-dev.js +69 -13
- package/package.json +1 -1
- package/public/css/layout.css +1 -0
- package/public/css/panel.css +45 -0
- package/public/css/rendered.css +7 -1
- package/public/css/tokens.css +1 -0
- package/public/default.md +100 -3
- package/public/index.html +103 -50
- package/public/sdocs-app.js +10 -0
- package/public/sdocs-controls.js +72 -8
- package/public/sdocs-export.js +26 -8
- package/public/sdocs-state.js +19 -3
- package/public/sdocs-styles.js +271 -5
- package/public/sdocs-theme.js +92 -6
- package/public/sdocs-yaml.js +45 -22
package/public/sdocs-controls.js
CHANGED
|
@@ -44,14 +44,12 @@ function linkRangeNum(rangeId, numId) {
|
|
|
44
44
|
|
|
45
45
|
SDocStyles.RANGE_NUM_PAIRS.forEach(function(pair) { linkRangeNum(pair[0], pair[1]); });
|
|
46
46
|
|
|
47
|
-
var STANDALONE_COLOR_IDS = new Set(
|
|
48
|
-
'ctrl-link-color','ctrl-code-bg','ctrl-code-color','ctrl-bq-border-color','ctrl-bq-color',
|
|
49
|
-
]);
|
|
47
|
+
var STANDALONE_COLOR_IDS = new Set(SDocStyles.STANDALONE_COLOR_IDS);
|
|
50
48
|
|
|
51
49
|
[
|
|
52
50
|
'ctrl-font-family','ctrl-h-font-family',
|
|
53
51
|
'ctrl-h1-weight','ctrl-h2-weight','ctrl-h3-weight','ctrl-h4-weight',
|
|
54
|
-
'ctrl-link-color','ctrl-link-decoration',
|
|
52
|
+
'ctrl-bg-color','ctrl-link-color','ctrl-link-decoration',
|
|
55
53
|
'ctrl-code-font','ctrl-code-bg','ctrl-code-color',
|
|
56
54
|
'ctrl-bq-border-color','ctrl-bq-color',
|
|
57
55
|
].forEach(function(id) {
|
|
@@ -99,7 +97,7 @@ document.getElementById('reset-h4-color').addEventListener('click', function()
|
|
|
99
97
|
document.getElementById('reset-p-color').addEventListener('click', function() { resetColorValue('ctrl-p-color'); S.syncAll('controls'); });
|
|
100
98
|
document.getElementById('reset-list-color').addEventListener('click', function() { resetColorValue('ctrl-list-color'); S.syncAll('controls'); });
|
|
101
99
|
|
|
102
|
-
['ctrl-link-color','ctrl-code-bg','ctrl-code-color','ctrl-bq-border-color','ctrl-bq-color'].forEach(function(ctrlId) {
|
|
100
|
+
['ctrl-bg-color','ctrl-link-color','ctrl-code-bg','ctrl-code-color','ctrl-bq-border-color','ctrl-bq-color'].forEach(function(ctrlId) {
|
|
103
101
|
var btnId = 'reset-' + ctrlId.replace('ctrl-', '');
|
|
104
102
|
document.getElementById(btnId).addEventListener('click', function() {
|
|
105
103
|
var defaultVal = S.getStandaloneDefault(ctrlId);
|
|
@@ -133,7 +131,6 @@ function applyStylesFromMeta(s) {
|
|
|
133
131
|
|
|
134
132
|
var result = SDocStyles.stylesToControls(s);
|
|
135
133
|
var controls = result.controls;
|
|
136
|
-
var newOverridden = result.overriddenColors;
|
|
137
134
|
|
|
138
135
|
// Font family selects need special handling to match bare names against <option> values
|
|
139
136
|
[['fontFamily', 'ctrl-font-family'], ['headers.fontFamily', 'ctrl-h-font-family']].forEach(function(pair) {
|
|
@@ -155,6 +152,22 @@ function applyStylesFromMeta(s) {
|
|
|
155
152
|
setCtrl(id, controls[id]);
|
|
156
153
|
});
|
|
157
154
|
|
|
155
|
+
if (result.hasThemeColors) {
|
|
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
|
|
169
|
+
var newOverridden = result.overriddenColors;
|
|
170
|
+
|
|
158
171
|
S.overriddenColors.clear();
|
|
159
172
|
setColorValue('ctrl-color', S.getColorDefault(), false);
|
|
160
173
|
|
|
@@ -163,17 +176,68 @@ function applyStylesFromMeta(s) {
|
|
|
163
176
|
setColorValue(id, controls[id], true);
|
|
164
177
|
});
|
|
165
178
|
|
|
179
|
+
// Also apply standalone colors from legacy format
|
|
180
|
+
if (s.background) {
|
|
181
|
+
S.overriddenColors.add('ctrl-bg-color');
|
|
182
|
+
var elBg = document.getElementById('ctrl-bg-color');
|
|
183
|
+
if (elBg) { elBg.value = s.background; applyCtrl('ctrl-bg-color'); }
|
|
184
|
+
}
|
|
185
|
+
if (s.link && s.link.color) {
|
|
186
|
+
S.overriddenColors.add('ctrl-link-color');
|
|
187
|
+
var el = document.getElementById('ctrl-link-color');
|
|
188
|
+
if (el) { el.value = s.link.color; applyCtrl('ctrl-link-color'); }
|
|
189
|
+
}
|
|
190
|
+
if (s.code) {
|
|
191
|
+
if (s.code.background) {
|
|
192
|
+
S.overriddenColors.add('ctrl-code-bg');
|
|
193
|
+
var el2 = document.getElementById('ctrl-code-bg');
|
|
194
|
+
if (el2) { el2.value = s.code.background; applyCtrl('ctrl-code-bg'); }
|
|
195
|
+
}
|
|
196
|
+
if (s.code.color) {
|
|
197
|
+
S.overriddenColors.add('ctrl-code-color');
|
|
198
|
+
var el3 = document.getElementById('ctrl-code-color');
|
|
199
|
+
if (el3) { el3.value = s.code.color; applyCtrl('ctrl-code-color'); }
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (s.blockquote) {
|
|
203
|
+
if (s.blockquote.borderColor) {
|
|
204
|
+
S.overriddenColors.add('ctrl-bq-border-color');
|
|
205
|
+
var el4 = document.getElementById('ctrl-bq-border-color');
|
|
206
|
+
if (el4) { el4.value = s.blockquote.borderColor; applyCtrl('ctrl-bq-border-color'); }
|
|
207
|
+
}
|
|
208
|
+
if (s.blockquote.color) {
|
|
209
|
+
S.overriddenColors.add('ctrl-bq-color');
|
|
210
|
+
var el5 = document.getElementById('ctrl-bq-color');
|
|
211
|
+
if (el5) { el5.value = s.blockquote.color; applyCtrl('ctrl-bq-color'); }
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
166
215
|
S._syncing = wasSyncing;
|
|
167
216
|
}
|
|
168
217
|
|
|
169
218
|
function collectStyles() {
|
|
219
|
+
S.saveCurrentThemeColors();
|
|
220
|
+
var lightHas = S.themeOverridden.light.size > 0;
|
|
221
|
+
var darkHas = S.themeOverridden.dark.size > 0;
|
|
222
|
+
if (lightHas || darkHas) {
|
|
223
|
+
return SDocStyles.collectStylesDual(
|
|
224
|
+
readAllControlValues(),
|
|
225
|
+
S.themeOverridden.light, S.themeOverridden.dark,
|
|
226
|
+
S.themeColors.light, S.themeColors.dark
|
|
227
|
+
);
|
|
228
|
+
}
|
|
170
229
|
return SDocStyles.collectStyles(readAllControlValues(), S.overriddenColors);
|
|
171
230
|
}
|
|
172
231
|
|
|
173
232
|
// ── Reset all styles ──────────────────────────────────
|
|
174
233
|
|
|
175
234
|
function resetAllStyles() {
|
|
176
|
-
|
|
235
|
+
// Clear both theme states
|
|
236
|
+
S.themeOverridden.light.clear();
|
|
237
|
+
S.themeOverridden.dark.clear();
|
|
238
|
+
S.themeColors.light = {};
|
|
239
|
+
S.themeColors.dark = {};
|
|
240
|
+
|
|
177
241
|
setColorValue('ctrl-color', S.getColorDefault(), false);
|
|
178
242
|
// Set standalone color controls to theme-appropriate defaults
|
|
179
243
|
STANDALONE_COLOR_IDS.forEach(function(ctrlId) {
|
|
@@ -186,7 +250,7 @@ function resetAllStyles() {
|
|
|
186
250
|
else if (el.tagName === 'SELECT') el.selectedIndex = [].slice.call(el.options).findIndex(function(o) { return o.defaultSelected; });
|
|
187
251
|
else if (el.type === 'color') el.value = el.defaultValue;
|
|
188
252
|
});
|
|
189
|
-
['ctrl-font-family','ctrl-base-size-num','ctrl-line-height-num',
|
|
253
|
+
['ctrl-bg-color','ctrl-font-family','ctrl-base-size-num','ctrl-line-height-num',
|
|
190
254
|
'ctrl-h-font-family','ctrl-h-scale-num','ctrl-h-mb-num',
|
|
191
255
|
'ctrl-h1-size-num','ctrl-h1-weight','ctrl-h2-size-num','ctrl-h2-weight',
|
|
192
256
|
'ctrl-h3-size-num','ctrl-h3-weight','ctrl-h4-size-num','ctrl-h4-weight',
|
package/public/sdocs-export.js
CHANGED
|
@@ -10,6 +10,7 @@ function cv(name) {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
function buildExportCSS() {
|
|
13
|
+
var bgColor = cv('--md-bg') || '#ffffff';
|
|
13
14
|
var fontFamily = cv('--md-font-family') || "'Inter', sans-serif";
|
|
14
15
|
var baseSize = cv('--md-base-size') || '16px';
|
|
15
16
|
var lineHeight = cv('--md-line-height') || '1.75';
|
|
@@ -50,7 +51,7 @@ function buildExportCSS() {
|
|
|
50
51
|
var bqPad = cv('--md-bq-padding') || '0.5em 1em';
|
|
51
52
|
var bqMargin = cv('--md-bq-margin') || '1.2em 0';
|
|
52
53
|
|
|
53
|
-
return '\nbody {\n font-family: ' + fontFamily + ';\n font-size: ' + baseSize + ';\n color: ' + color + ';\n line-height: ' + lineHeight + ';\n max-width: 720px;\n margin: 0 auto;\n padding: 40px 48px 60px;\n -webkit-font-smoothing: antialiased;\n}\nh1 { font-family: ' + hFontFamily + '; font-size: ' + h1Size + '; color: ' + h1Color + '; font-weight: ' + h1Weight + '; letter-spacing: -0.02em; line-height: 1.2; margin: 0 0 ' + hMB + '; }\nh2 { font-family: ' + hFontFamily + '; font-size: ' + h2Size + '; color: ' + h2Color + '; font-weight: ' + h2Weight + '; letter-spacing: -0.015em; line-height: 1.3; margin: 1.4em 0 ' + hMB + '; padding-bottom: 0.3em; border-bottom: 1px solid #ede8e2; }\nh3 { font-family: ' + hFontFamily + '; font-size: ' + h3Size + '; color: ' + h3Color + '; font-weight: ' + h3Weight + '; letter-spacing: -0.01em; line-height: 1.4; margin: 1.2em 0 ' + hMB + '; }\nh4 { font-family: ' + hFontFamily + '; font-size: ' + h4Size + '; color: ' + h4Color + '; font-weight: ' + h4Weight + '; line-height: 1.5; margin: 1em 0 ' + hMB + '; }\np { color: ' + pColor + '; line-height: ' + pLH + '; margin: ' + pMargin + '; }\na { color: ' + linkColor + '; text-decoration: ' + linkDec + '; text-underline-offset: 2px; }\ncode { background: ' + codeBG + '; color: ' + codeColor + '; padding: 0.15em 0.45em; border-radius: 4px; font-family: ' + codeFont + '; font-size: 0.85em; }\npre { background: ' + preBG + '; padding: 1.1em 1.25em; border-radius: 8px; overflow-x: auto; margin: 1.2em 0; border: 1px solid #e7e2db; }\npre code { background: none; padding: 0; color: #3c3733; font-size: 0.88em; }\nblockquote { border-left: ' + bqBorder + '; color: ' + bqColor + '; padding: ' + bqPad + '; margin: ' + bqMargin + '; background: #f7f5f2; border-radius: 0 6px 6px 0; }\nblockquote p { margin: 0; color: inherit; }\nul, ol { padding-left: 1.6em; margin: 0.5em 0 1.1em; }\nli { margin-bottom: 0.3em; }\nhr { border: none; border-top: 1px solid #ede8e2; margin: 2em 0; }\ntable { border-collapse: collapse; width: 100%; margin: 1.2em 0; font-size: 0.92em; }\nth, td { border: 1px solid #e2ddd6; padding: 7px 12px; text-align: left; }\nth { background: #f4f1ed; font-weight: 600; }\ntr:nth-child(even) td { background: #fafaf8; }\nimg { max-width: 100%; border-radius: 8px; }\n';
|
|
54
|
+
return '\nbody {\n font-family: ' + fontFamily + ';\n font-size: ' + baseSize + ';\n color: ' + color + ';\n line-height: ' + lineHeight + ';\n background-color: ' + bgColor + ';\n max-width: 720px;\n margin: 0 auto;\n padding: 40px 48px 60px;\n -webkit-font-smoothing: antialiased;\n}\nh1 { font-family: ' + hFontFamily + '; font-size: ' + h1Size + '; color: ' + h1Color + '; font-weight: ' + h1Weight + '; letter-spacing: -0.02em; line-height: 1.2; margin: 0 0 ' + hMB + '; }\nh2 { font-family: ' + hFontFamily + '; font-size: ' + h2Size + '; color: ' + h2Color + '; font-weight: ' + h2Weight + '; letter-spacing: -0.015em; line-height: 1.3; margin: 1.4em 0 ' + hMB + '; padding-bottom: 0.3em; border-bottom: 1px solid #ede8e2; }\nh3 { font-family: ' + hFontFamily + '; font-size: ' + h3Size + '; color: ' + h3Color + '; font-weight: ' + h3Weight + '; letter-spacing: -0.01em; line-height: 1.4; margin: 1.2em 0 ' + hMB + '; }\nh4 { font-family: ' + hFontFamily + '; font-size: ' + h4Size + '; color: ' + h4Color + '; font-weight: ' + h4Weight + '; line-height: 1.5; margin: 1em 0 ' + hMB + '; }\np { color: ' + pColor + '; line-height: ' + pLH + '; margin: ' + pMargin + '; }\na { color: ' + linkColor + '; text-decoration: ' + linkDec + '; text-underline-offset: 2px; }\ncode { background: ' + codeBG + '; color: ' + codeColor + '; padding: 0.15em 0.45em; border-radius: 4px; font-family: ' + codeFont + '; font-size: 0.85em; }\npre { background: ' + preBG + '; padding: 1.1em 1.25em; border-radius: 8px; overflow-x: auto; margin: 1.2em 0; border: 1px solid #e7e2db; }\npre code { background: none; padding: 0; color: #3c3733; font-size: 0.88em; }\nblockquote { border-left: ' + bqBorder + '; color: ' + bqColor + '; padding: ' + bqPad + '; margin: ' + bqMargin + '; background: #f7f5f2; border-radius: 0 6px 6px 0; }\nblockquote p { margin: 0; color: inherit; }\nul, ol { padding-left: 1.6em; margin: 0.5em 0 1.1em; }\nli { margin-bottom: 0.3em; }\nhr { border: none; border-top: 1px solid #ede8e2; margin: 2em 0; }\ntable { border-collapse: collapse; width: 100%; margin: 1.2em 0; font-size: 0.92em; }\nth, td { border: 1px solid #e2ddd6; padding: 7px 12px; text-align: left; }\nth { background: #f4f1ed; font-weight: 600; }\ntr:nth-child(even) td { background: #fafaf8; }\nimg { max-width: 100%; border-radius: 8px; }\n';
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
function buildExportHTML() {
|
|
@@ -149,17 +150,34 @@ document.getElementById('exp-styled').addEventListener('click', function() {
|
|
|
149
150
|
|
|
150
151
|
// ── Save as default styles ──────────────────────────────
|
|
151
152
|
|
|
153
|
+
function formatStyleValue(k, v) {
|
|
154
|
+
if (typeof v !== 'object' || v === null) {
|
|
155
|
+
return k + ': ' + JSON.stringify(v);
|
|
156
|
+
}
|
|
157
|
+
// light/dark theme blocks: serialize as nested block (not inline)
|
|
158
|
+
if (k === 'light' || k === 'dark') {
|
|
159
|
+
var blockLines = [k + ':'];
|
|
160
|
+
Object.keys(v).forEach(function(sk) {
|
|
161
|
+
var sv = v[sk];
|
|
162
|
+
if (typeof sv === 'object' && sv !== null) {
|
|
163
|
+
var inner = Object.keys(sv).map(function(a) { return a + ': ' + JSON.stringify(sv[a]); }).join(', ');
|
|
164
|
+
blockLines.push(' ' + sk + ': { ' + inner + ' }');
|
|
165
|
+
} else {
|
|
166
|
+
blockLines.push(' ' + sk + ': ' + JSON.stringify(sv));
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
return blockLines.join('\n');
|
|
170
|
+
}
|
|
171
|
+
// Default: inline object
|
|
172
|
+
var inner = Object.keys(v).map(function(a) { return a + ': ' + JSON.stringify(v[a]); }).join(', ');
|
|
173
|
+
return k + ': { ' + inner + ' }';
|
|
174
|
+
}
|
|
175
|
+
|
|
152
176
|
function buildStylesYaml() {
|
|
153
177
|
var styles = S.collectStyles();
|
|
154
178
|
var lines = [];
|
|
155
179
|
Object.keys(styles).forEach(function(k) {
|
|
156
|
-
|
|
157
|
-
if (typeof v === 'object' && v !== null) {
|
|
158
|
-
var inner = Object.keys(v).map(function(a) { return a + ': ' + JSON.stringify(v[a]); }).join(', ');
|
|
159
|
-
lines.push(k + ': { ' + inner + ' }');
|
|
160
|
-
} else {
|
|
161
|
-
lines.push(k + ': ' + JSON.stringify(v));
|
|
162
|
-
}
|
|
180
|
+
lines.push(formatStyleValue(k, styles[k]));
|
|
163
181
|
});
|
|
164
182
|
return lines.join('\n');
|
|
165
183
|
}
|
package/public/sdocs-state.js
CHANGED
|
@@ -8,8 +8,10 @@ window.SDocs = {
|
|
|
8
8
|
currentBody: '',
|
|
9
9
|
currentMeta: {},
|
|
10
10
|
|
|
11
|
-
//
|
|
12
|
-
|
|
11
|
+
// Per-theme color state
|
|
12
|
+
activeTheme: 'light',
|
|
13
|
+
themeColors: { light: {}, dark: {} },
|
|
14
|
+
themeOverridden: { light: new Set(), dark: new Set() },
|
|
13
15
|
|
|
14
16
|
// DOM references
|
|
15
17
|
renderedEl: document.getElementById('rendered'),
|
|
@@ -28,16 +30,30 @@ window.SDocs = {
|
|
|
28
30
|
|
|
29
31
|
// Cross-module functions (registered by defining module)
|
|
30
32
|
// Theme: toggleTheme, getThemeDefaults, getColorDefault, getStandaloneDefault,
|
|
31
|
-
// loadGoogleFont, updateDefaultColors, GOOGLE_FONTS
|
|
33
|
+
// loadGoogleFont, updateDefaultColors, GOOGLE_FONTS,
|
|
34
|
+
// switchThemeAndUpdate, saveCurrentThemeColors, loadThemeColors
|
|
32
35
|
// Controls: setColorValue, readAllControlValues, collectStyles,
|
|
33
36
|
// applyStylesFromMeta, resetAllStyles, STANDALONE_COLOR_IDS
|
|
34
37
|
// App: syncAll, setStatus, setMode, render, loadText
|
|
35
38
|
// Write: enterWriteMode, exitWriteMode
|
|
36
39
|
};
|
|
37
40
|
|
|
41
|
+
// Backwards compat: S.overriddenColors delegates to active theme's set
|
|
42
|
+
Object.defineProperty(SDocs, 'overriddenColors', {
|
|
43
|
+
get: function() { return SDocs.themeOverridden[SDocs.activeTheme]; },
|
|
44
|
+
set: function(v) { SDocs.themeOverridden[SDocs.activeTheme] = v; },
|
|
45
|
+
enumerable: true,
|
|
46
|
+
configurable: true,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
SDocs.contentAreaEl = document.getElementById('content-area');
|
|
50
|
+
|
|
38
51
|
SDocs.setStyleVar = function(cssVar, value) {
|
|
39
52
|
SDocs.renderedEl.style.setProperty(cssVar, value);
|
|
40
53
|
if (SDocs.writeEl) SDocs.writeEl.style.setProperty(cssVar, value);
|
|
54
|
+
if (cssVar === '--md-bg') {
|
|
55
|
+
SDocs.contentAreaEl.style.setProperty('background-color', value);
|
|
56
|
+
}
|
|
41
57
|
};
|
|
42
58
|
|
|
43
59
|
})();
|
package/public/sdocs-styles.js
CHANGED
|
@@ -31,6 +31,7 @@ const COLOR_CASCADE = {
|
|
|
31
31
|
// Control ID → { cssVar, suffix?, compound? }
|
|
32
32
|
// Maps every non-color control to its CSS variable and optional unit suffix
|
|
33
33
|
const CTRL_CSS_MAP = {
|
|
34
|
+
'ctrl-bg-color': { cssVar: '--md-bg' },
|
|
34
35
|
'ctrl-font-family': { cssVar: '--md-font-family' },
|
|
35
36
|
'ctrl-base-size-num': { cssVar: '--md-base-size', suffix: 'px' },
|
|
36
37
|
'ctrl-line-height-num': { cssVar: '--md-line-height' },
|
|
@@ -179,7 +180,8 @@ function collectStyles(values, overriddenColors) {
|
|
|
179
180
|
indent: gn('ctrl-list-indent-num'),
|
|
180
181
|
};
|
|
181
182
|
|
|
182
|
-
// Only emit
|
|
183
|
+
// Only emit colors that were explicitly overridden
|
|
184
|
+
if (overriddenColors.has('ctrl-bg-color')) styles.background = gv('ctrl-bg-color');
|
|
183
185
|
if (overriddenColors.has('ctrl-color')) styles.color = gv('ctrl-color');
|
|
184
186
|
if (overriddenColors.has('ctrl-h-color')) styles.headers.color = gv('ctrl-h-color');
|
|
185
187
|
if (overriddenColors.has('ctrl-h1-color')) styles.h1.color = gv('ctrl-h1-color');
|
|
@@ -207,6 +209,10 @@ function stylesToControls(styles) {
|
|
|
207
209
|
if (styles.baseFontSize) controls['ctrl-base-size-num'] = styles.baseFontSize;
|
|
208
210
|
if (styles.lineHeight) controls['ctrl-line-height-num'] = styles.lineHeight;
|
|
209
211
|
|
|
212
|
+
if (styles.background) {
|
|
213
|
+
controls['ctrl-bg-color'] = styles.background;
|
|
214
|
+
overridden.add('ctrl-bg-color');
|
|
215
|
+
}
|
|
210
216
|
if (styles.color) {
|
|
211
217
|
controls['ctrl-color'] = styles.color;
|
|
212
218
|
overridden.add('ctrl-color');
|
|
@@ -265,6 +271,260 @@ function stylesToControls(styles) {
|
|
|
265
271
|
return { controls, overriddenColors: overridden };
|
|
266
272
|
}
|
|
267
273
|
|
|
274
|
+
// ═══════════════════════════════════════════════════════
|
|
275
|
+
// STANDALONE & ALL COLOR IDS
|
|
276
|
+
// ═══════════════════════════════════════════════════════
|
|
277
|
+
|
|
278
|
+
var STANDALONE_COLOR_IDS = [
|
|
279
|
+
'ctrl-bg-color','ctrl-link-color','ctrl-code-bg','ctrl-code-color','ctrl-bq-border-color','ctrl-bq-color',
|
|
280
|
+
];
|
|
281
|
+
|
|
282
|
+
var CASCADE_COLOR_IDS = Object.keys(COLOR_VAR_MAP);
|
|
283
|
+
|
|
284
|
+
var ALL_COLOR_IDS = CASCADE_COLOR_IDS.concat(STANDALONE_COLOR_IDS);
|
|
285
|
+
|
|
286
|
+
// ═══════════════════════════════════════════════════════
|
|
287
|
+
// PER-THEME FUNCTIONS
|
|
288
|
+
// ═══════════════════════════════════════════════════════
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* parseThemeColorBlock(block)
|
|
292
|
+
* Extracts { colors: {ctrlId: val}, overridden: Set } from a light:/dark: sub-object.
|
|
293
|
+
* The block is an object like { color: "#1a1a2e", h1: { color: "#c0392b" }, link: { color: "#2563eb" } }
|
|
294
|
+
*/
|
|
295
|
+
function parseThemeColorBlock(block) {
|
|
296
|
+
if (!block) return { colors: {}, overridden: new Set() };
|
|
297
|
+
var colors = {};
|
|
298
|
+
var overridden = new Set();
|
|
299
|
+
|
|
300
|
+
// Background color
|
|
301
|
+
if (block.background) {
|
|
302
|
+
colors['ctrl-bg-color'] = block.background;
|
|
303
|
+
overridden.add('ctrl-bg-color');
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Top-level color (cascade root)
|
|
307
|
+
if (block.color) {
|
|
308
|
+
colors['ctrl-color'] = block.color;
|
|
309
|
+
overridden.add('ctrl-color');
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Cascade colors nested in sub-objects
|
|
313
|
+
if (block.headers && block.headers.color) {
|
|
314
|
+
colors['ctrl-h-color'] = block.headers.color;
|
|
315
|
+
overridden.add('ctrl-h-color');
|
|
316
|
+
}
|
|
317
|
+
['h1','h2','h3','h4'].forEach(function(t) {
|
|
318
|
+
var obj = block[t];
|
|
319
|
+
if (obj && obj.color) {
|
|
320
|
+
colors['ctrl-' + t + '-color'] = obj.color;
|
|
321
|
+
overridden.add('ctrl-' + t + '-color');
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
if (block.p && block.p.color) {
|
|
325
|
+
colors['ctrl-p-color'] = block.p.color;
|
|
326
|
+
overridden.add('ctrl-p-color');
|
|
327
|
+
}
|
|
328
|
+
if (block.list && block.list.color) {
|
|
329
|
+
colors['ctrl-list-color'] = block.list.color;
|
|
330
|
+
overridden.add('ctrl-list-color');
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Standalone colors
|
|
334
|
+
if (block.link && block.link.color) {
|
|
335
|
+
colors['ctrl-link-color'] = block.link.color;
|
|
336
|
+
overridden.add('ctrl-link-color');
|
|
337
|
+
}
|
|
338
|
+
if (block.code) {
|
|
339
|
+
if (block.code.background) { colors['ctrl-code-bg'] = block.code.background; overridden.add('ctrl-code-bg'); }
|
|
340
|
+
if (block.code.color) { colors['ctrl-code-color'] = block.code.color; overridden.add('ctrl-code-color'); }
|
|
341
|
+
}
|
|
342
|
+
if (block.blockquote) {
|
|
343
|
+
if (block.blockquote.borderColor) { colors['ctrl-bq-border-color'] = block.blockquote.borderColor; overridden.add('ctrl-bq-border-color'); }
|
|
344
|
+
if (block.blockquote.color) { colors['ctrl-bq-color'] = block.blockquote.color; overridden.add('ctrl-bq-color'); }
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return { colors: colors, overridden: overridden };
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* collectThemeColors(colorValues, overriddenSet)
|
|
352
|
+
* Builds the YAML sub-object for one theme (only emits overridden colors).
|
|
353
|
+
*/
|
|
354
|
+
function collectThemeColors(colorValues, overriddenSet) {
|
|
355
|
+
var block = {};
|
|
356
|
+
if (overriddenSet.has('ctrl-bg-color')) block.background = colorValues['ctrl-bg-color'];
|
|
357
|
+
if (overriddenSet.has('ctrl-color')) block.color = colorValues['ctrl-color'];
|
|
358
|
+
|
|
359
|
+
// Heading colors
|
|
360
|
+
var hasHColor = overriddenSet.has('ctrl-h-color');
|
|
361
|
+
if (hasHColor) {
|
|
362
|
+
if (!block.headers) block.headers = {};
|
|
363
|
+
block.headers.color = colorValues['ctrl-h-color'];
|
|
364
|
+
}
|
|
365
|
+
['h1','h2','h3','h4'].forEach(function(t) {
|
|
366
|
+
var id = 'ctrl-' + t + '-color';
|
|
367
|
+
if (overriddenSet.has(id)) {
|
|
368
|
+
if (!block[t]) block[t] = {};
|
|
369
|
+
block[t].color = colorValues[id];
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
// Paragraph and list
|
|
374
|
+
if (overriddenSet.has('ctrl-p-color')) {
|
|
375
|
+
if (!block.p) block.p = {};
|
|
376
|
+
block.p.color = colorValues['ctrl-p-color'];
|
|
377
|
+
}
|
|
378
|
+
if (overriddenSet.has('ctrl-list-color')) {
|
|
379
|
+
if (!block.list) block.list = {};
|
|
380
|
+
block.list.color = colorValues['ctrl-list-color'];
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Standalone colors
|
|
384
|
+
if (overriddenSet.has('ctrl-link-color')) {
|
|
385
|
+
if (!block.link) block.link = {};
|
|
386
|
+
block.link.color = colorValues['ctrl-link-color'];
|
|
387
|
+
}
|
|
388
|
+
if (overriddenSet.has('ctrl-code-bg')) {
|
|
389
|
+
if (!block.code) block.code = {};
|
|
390
|
+
block.code.background = colorValues['ctrl-code-bg'];
|
|
391
|
+
}
|
|
392
|
+
if (overriddenSet.has('ctrl-code-color')) {
|
|
393
|
+
if (!block.code) block.code = {};
|
|
394
|
+
block.code.color = colorValues['ctrl-code-color'];
|
|
395
|
+
}
|
|
396
|
+
if (overriddenSet.has('ctrl-bq-border-color')) {
|
|
397
|
+
if (!block.blockquote) block.blockquote = {};
|
|
398
|
+
block.blockquote.borderColor = colorValues['ctrl-bq-border-color'];
|
|
399
|
+
}
|
|
400
|
+
if (overriddenSet.has('ctrl-bq-color')) {
|
|
401
|
+
if (!block.blockquote) block.blockquote = {};
|
|
402
|
+
block.blockquote.color = colorValues['ctrl-bq-color'];
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return block;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* collectStylesDual(values, lightOverridden, darkOverridden, lightColors, darkColors)
|
|
410
|
+
* Builds full styles object with light:/dark: keys for colors, shared non-color props at top level.
|
|
411
|
+
*/
|
|
412
|
+
function collectStylesDual(values, lightOverridden, darkOverridden, lightColors, darkColors) {
|
|
413
|
+
var gv = function(id) { return values[id] || ''; };
|
|
414
|
+
var gn = function(id) { return parseFloat(values[id]) || 0; };
|
|
415
|
+
|
|
416
|
+
var styles = {
|
|
417
|
+
fontFamily: gv('ctrl-font-family').replace(/['"]/g, '').split(',')[0].trim(),
|
|
418
|
+
baseFontSize: gn('ctrl-base-size-num'),
|
|
419
|
+
lineHeight: gn('ctrl-line-height-num'),
|
|
420
|
+
headers: {
|
|
421
|
+
fontFamily: gv('ctrl-h-font-family').replace(/['"]/g, '').split(',')[0].trim(),
|
|
422
|
+
scale: gn('ctrl-h-scale-num'),
|
|
423
|
+
marginBottom: gn('ctrl-h-mb-num'),
|
|
424
|
+
},
|
|
425
|
+
h1: { fontSize: gn('ctrl-h1-size-num'), fontWeight: parseInt(gv('ctrl-h1-weight')) || 0 },
|
|
426
|
+
h2: { fontSize: gn('ctrl-h2-size-num'), fontWeight: parseInt(gv('ctrl-h2-weight')) || 0 },
|
|
427
|
+
h3: { fontSize: gn('ctrl-h3-size-num'), fontWeight: parseInt(gv('ctrl-h3-weight')) || 0 },
|
|
428
|
+
h4: { fontSize: gn('ctrl-h4-size-num'), fontWeight: parseInt(gv('ctrl-h4-weight')) || 0 },
|
|
429
|
+
p: {
|
|
430
|
+
lineHeight: gn('ctrl-p-lh-num'),
|
|
431
|
+
marginBottom: gn('ctrl-p-mb-num'),
|
|
432
|
+
},
|
|
433
|
+
link: { decoration: gv('ctrl-link-decoration') },
|
|
434
|
+
code: {
|
|
435
|
+
font: gv('ctrl-code-font').replace(/['"]/g, '').split(',')[0].trim(),
|
|
436
|
+
},
|
|
437
|
+
blockquote: {
|
|
438
|
+
borderWidth: gn('ctrl-bq-bw-num'),
|
|
439
|
+
fontSize: gn('ctrl-bq-size-num'),
|
|
440
|
+
},
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
styles.list = {
|
|
444
|
+
spacing: gn('ctrl-list-spacing-num'),
|
|
445
|
+
indent: gn('ctrl-list-indent-num'),
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
// Build theme color blocks
|
|
449
|
+
var lightBlock = collectThemeColors(lightColors, lightOverridden);
|
|
450
|
+
var darkBlock = collectThemeColors(darkColors, darkOverridden);
|
|
451
|
+
|
|
452
|
+
// Only emit light/dark blocks if they have content
|
|
453
|
+
if (Object.keys(lightBlock).length > 0) styles.light = lightBlock;
|
|
454
|
+
if (Object.keys(darkBlock).length > 0) styles.dark = darkBlock;
|
|
455
|
+
|
|
456
|
+
return styles;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* stylesToControls(styles) — extended version
|
|
461
|
+
* Detects styles.light/styles.dark and returns per-theme data when present.
|
|
462
|
+
*/
|
|
463
|
+
var _origStylesToControls = stylesToControls;
|
|
464
|
+
|
|
465
|
+
stylesToControls = function(styles) {
|
|
466
|
+
if (!styles) return { controls: {}, overriddenColors: new Set(), hasThemeColors: false };
|
|
467
|
+
|
|
468
|
+
var hasThemeColors = !!(styles.light || styles.dark);
|
|
469
|
+
|
|
470
|
+
if (!hasThemeColors) {
|
|
471
|
+
var result = _origStylesToControls(styles);
|
|
472
|
+
result.hasThemeColors = false;
|
|
473
|
+
return result;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Parse non-color controls from top level (same as original, but skip colors)
|
|
477
|
+
var controls = {};
|
|
478
|
+
var overridden = new Set();
|
|
479
|
+
|
|
480
|
+
if (styles.fontFamily) controls['ctrl-font-family'] = styles.fontFamily;
|
|
481
|
+
if (styles.baseFontSize) controls['ctrl-base-size-num'] = styles.baseFontSize;
|
|
482
|
+
if (styles.lineHeight) controls['ctrl-line-height-num'] = styles.lineHeight;
|
|
483
|
+
|
|
484
|
+
var h = styles.headers || {};
|
|
485
|
+
if (h.fontFamily) controls['ctrl-h-font-family'] = h.fontFamily;
|
|
486
|
+
if (h.scale) controls['ctrl-h-scale-num'] = h.scale;
|
|
487
|
+
if (h.marginBottom) controls['ctrl-h-mb-num'] = h.marginBottom;
|
|
488
|
+
|
|
489
|
+
['h1', 'h2', 'h3', 'h4'].forEach(function(t) {
|
|
490
|
+
var hs = styles[t] || {};
|
|
491
|
+
if (hs.fontSize) controls['ctrl-' + t + '-size-num'] = hs.fontSize;
|
|
492
|
+
if (hs.fontWeight) controls['ctrl-' + t + '-weight'] = String(hs.fontWeight);
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
var p = styles.p || {};
|
|
496
|
+
if (p.lineHeight) controls['ctrl-p-lh-num'] = p.lineHeight;
|
|
497
|
+
if (p.marginBottom) controls['ctrl-p-mb-num'] = p.marginBottom;
|
|
498
|
+
|
|
499
|
+
var lk = styles.link || {};
|
|
500
|
+
if (lk.decoration) controls['ctrl-link-decoration'] = lk.decoration;
|
|
501
|
+
|
|
502
|
+
var cd = styles.code || {};
|
|
503
|
+
if (cd.font) controls['ctrl-code-font'] = cd.font;
|
|
504
|
+
|
|
505
|
+
var bq = styles.blockquote || {};
|
|
506
|
+
if (bq.borderWidth) controls['ctrl-bq-bw-num'] = bq.borderWidth;
|
|
507
|
+
if (bq.fontSize) controls['ctrl-bq-size-num'] = bq.fontSize;
|
|
508
|
+
|
|
509
|
+
var ll = styles.list || {};
|
|
510
|
+
if (ll.spacing) controls['ctrl-list-spacing-num'] = ll.spacing;
|
|
511
|
+
if (ll.indent) controls['ctrl-list-indent-num'] = ll.indent;
|
|
512
|
+
|
|
513
|
+
// Parse per-theme color blocks
|
|
514
|
+
var lightParsed = parseThemeColorBlock(styles.light);
|
|
515
|
+
var darkParsed = parseThemeColorBlock(styles.dark);
|
|
516
|
+
|
|
517
|
+
return {
|
|
518
|
+
controls: controls,
|
|
519
|
+
overriddenColors: overridden,
|
|
520
|
+
hasThemeColors: true,
|
|
521
|
+
lightColors: lightParsed.colors,
|
|
522
|
+
lightOverridden: lightParsed.overridden,
|
|
523
|
+
darkColors: darkParsed.colors,
|
|
524
|
+
darkOverridden: darkParsed.overridden,
|
|
525
|
+
};
|
|
526
|
+
};
|
|
527
|
+
|
|
268
528
|
// ═══════════════════════════════════════════════════════
|
|
269
529
|
// EXPORTS
|
|
270
530
|
// ═══════════════════════════════════════════════════════
|
|
@@ -274,10 +534,16 @@ exports.COLOR_CASCADE = COLOR_CASCADE;
|
|
|
274
534
|
exports.CTRL_CSS_MAP = CTRL_CSS_MAP;
|
|
275
535
|
exports.RANGE_NUM_PAIRS = RANGE_NUM_PAIRS;
|
|
276
536
|
|
|
277
|
-
exports.
|
|
278
|
-
exports.
|
|
279
|
-
|
|
280
|
-
exports.
|
|
537
|
+
exports.STANDALONE_COLOR_IDS = STANDALONE_COLOR_IDS;
|
|
538
|
+
exports.ALL_COLOR_IDS = ALL_COLOR_IDS;
|
|
539
|
+
|
|
540
|
+
exports.controlToCssVars = controlToCssVars;
|
|
541
|
+
exports.cascadeColor = cascadeColor;
|
|
542
|
+
exports.collectStyles = collectStyles;
|
|
543
|
+
exports.collectStylesDual = collectStylesDual;
|
|
544
|
+
exports.collectThemeColors = collectThemeColors;
|
|
545
|
+
exports.parseThemeColorBlock = parseThemeColorBlock;
|
|
546
|
+
exports.stylesToControls = stylesToControls;
|
|
281
547
|
|
|
282
548
|
// UMD tail: in Node (tests) this writes to module.exports; in the browser
|
|
283
549
|
// it creates window.SDocStyles. We use this pattern instead of ES modules
|