sdocs-dev 1.2.0 → 1.3.1

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.
@@ -1,260 +0,0 @@
1
- // sdocs-theme.js — Theme, fonts, and dark mode
2
- (function () {
3
- 'use strict';
4
-
5
- var S = SDocs;
6
-
7
- // ── Google Fonts ──────────────────────────────────
8
-
9
- const GOOGLE_FONTS = [
10
- 'Inter', 'Roboto', 'Open Sans', 'Lato', 'Montserrat', 'Source Sans 3',
11
- 'Oswald', 'Raleway', 'Poppins', 'Merriweather', 'Ubuntu',
12
- 'Nunito', 'Playfair Display', 'Roboto Slab', 'PT Sans', 'Lora',
13
- 'Mulish', 'Noto Sans', 'Rubik', 'Dosis',
14
- 'Josefin Sans', 'PT Serif', 'Libre Franklin', 'Crimson Text'
15
- ];
16
-
17
- const loadedFonts = new Set(['Inter']);
18
-
19
- function loadGoogleFont(family) {
20
- if (loadedFonts.has(family)) return;
21
- loadedFonts.add(family);
22
- const link = document.createElement('link');
23
- link.rel = 'stylesheet';
24
- link.href = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(family)}:wght@400;600;700&display=swap`;
25
- document.head.appendChild(link);
26
- }
27
-
28
- function populateFontSelect(sel, includeInherit) {
29
- if (includeInherit) {
30
- const opt = document.createElement('option');
31
- opt.value = 'inherit';
32
- opt.textContent = '— Same as body —';
33
- sel.appendChild(opt);
34
- }
35
- GOOGLE_FONTS.forEach(f => {
36
- const opt = document.createElement('option');
37
- opt.value = `'${f}', sans-serif`;
38
- opt.textContent = f;
39
- sel.appendChild(opt);
40
- });
41
- [['Georgia, serif','Georgia'],['Times New Roman, serif','Times New Roman'],
42
- ['system-ui, sans-serif','System UI']].forEach(([v,l]) => {
43
- const opt = document.createElement('option');
44
- opt.value = v; opt.textContent = l;
45
- sel.appendChild(opt);
46
- });
47
- }
48
-
49
- // ── Dark mode ──────────────────────────────────
50
-
51
- const LIGHT_DEFAULTS = {
52
- bgColor: '#ffffff',
53
- colorDefault: '#1c1917',
54
- codeBg: '#f4f1ed',
55
- codeColor: '#6b21a8',
56
- linkColor: '#2563eb',
57
- bqBorderColor: '#2563eb',
58
- bqBg: '#f7f5f2',
59
- bqColor: '#6b6560',
60
- };
61
-
62
- const DARK_DEFAULTS = {
63
- bgColor: '#2c2a26',
64
- colorDefault: '#e7e5e2',
65
- codeBg: '#1a1816',
66
- codeColor: '#b8a99a',
67
- linkColor: '#60a5fa',
68
- bqBorderColor: '#60a5fa',
69
- bqBg: '#252320',
70
- bqColor: '#a8a29e',
71
- };
72
-
73
- function getThemeDefaults() {
74
- return document.documentElement.dataset.theme === 'dark' ? DARK_DEFAULTS : LIGHT_DEFAULTS;
75
- }
76
-
77
- function getThemeDefaultsFor(theme) {
78
- return theme === 'dark' ? DARK_DEFAULTS : LIGHT_DEFAULTS;
79
- }
80
-
81
- function getColorDefault() {
82
- return getThemeDefaults().colorDefault;
83
- }
84
-
85
- function getPreferredTheme() {
86
- const stored = localStorage.getItem('sdocs-theme');
87
- if (stored === 'dark' || stored === 'light') return stored;
88
- return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
89
- }
90
-
91
- const SUN_ICON = '<circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>';
92
- const MOON_ICON = '<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/>';
93
-
94
- function updateThemeIcon(theme) {
95
- const icon = document.getElementById('icon-theme');
96
- if (icon) icon.innerHTML = theme === 'dark' ? SUN_ICON : MOON_ICON;
97
- }
98
-
99
- function applyTheme(theme) {
100
- document.documentElement.dataset.theme = theme;
101
- S.activeTheme = theme;
102
- localStorage.setItem('sdocs-theme', theme);
103
- updateThemeIcon(theme);
104
- }
105
-
106
- // ── Per-theme color save/load ──────────────────────
107
-
108
- function saveCurrentThemeColors() {
109
- var theme = S.activeTheme;
110
- var colors = S.themeColors[theme];
111
- // Save all 13 color control values
112
- SDocStyles.ALL_COLOR_IDS.forEach(function(ctrlId) {
113
- var el = document.getElementById(ctrlId);
114
- if (el) colors[ctrlId] = el.value;
115
- });
116
- }
117
-
118
- function loadThemeColors(theme) {
119
- var colors = S.themeColors[theme];
120
- var overridden = S.themeOverridden[theme];
121
- var defaults = getThemeDefaultsFor(theme);
122
-
123
- // Cascade root first
124
- if (overridden.has('ctrl-color')) {
125
- S.setColorValue('ctrl-color', colors['ctrl-color'], true);
126
- } else {
127
- S.setColorValue('ctrl-color', defaults.colorDefault, false);
128
- }
129
-
130
- // Then cascade children that are overridden
131
- var cascadeIds = Object.keys(SDocStyles.COLOR_VAR_MAP);
132
- cascadeIds.forEach(function(ctrlId) {
133
- if (ctrlId === 'ctrl-color') return; // already handled
134
- if (overridden.has(ctrlId)) {
135
- S.setColorValue(ctrlId, colors[ctrlId], true);
136
- }
137
- // Non-overridden cascade children are already set by cascade from parent
138
- });
139
-
140
- // Standalone colors
141
- var standaloneMap = {
142
- 'ctrl-bg-color': defaults.bgColor,
143
- 'ctrl-link-color': defaults.linkColor,
144
- 'ctrl-code-bg': defaults.codeBg,
145
- 'ctrl-code-color': defaults.codeColor,
146
- 'ctrl-bq-border-color': defaults.bqBorderColor,
147
- 'ctrl-bq-bg': defaults.bqBg,
148
- 'ctrl-bq-color': defaults.bqColor,
149
- };
150
- for (var ctrlId in standaloneMap) {
151
- var el = document.getElementById(ctrlId);
152
- if (!el) continue;
153
- if (overridden.has(ctrlId)) {
154
- el.value = colors[ctrlId];
155
- } else {
156
- el.value = standaloneMap[ctrlId];
157
- }
158
- var allVals = S.readAllControlValues();
159
- SDocStyles.controlToCssVars(ctrlId, el.value, allVals)
160
- .forEach(function(a) { S.setStyleVar(a.cssVar, a.value); });
161
- }
162
- }
163
-
164
- function updateThemeTabs(theme) {
165
- var lightTab = document.getElementById('theme-tab-light');
166
- var darkTab = document.getElementById('theme-tab-dark');
167
- if (lightTab) lightTab.classList.toggle('active', theme === 'light');
168
- if (darkTab) darkTab.classList.toggle('active', theme === 'dark');
169
- }
170
-
171
- function switchThemeAndUpdate(theme) {
172
- if (theme === S.activeTheme) return;
173
- saveCurrentThemeColors();
174
- applyTheme(theme);
175
- loadThemeColors(theme);
176
- updateThemeTabs(theme);
177
- S.syncAll('controls');
178
- }
179
-
180
- function toggleTheme() {
181
- var current = S.activeTheme;
182
- switchThemeAndUpdate(current === 'dark' ? 'light' : 'dark');
183
- }
184
-
185
- function updateDefaultColors() {
186
- const defaults = getThemeDefaults();
187
- if (!S.overriddenColors) return;
188
- if (!S.overriddenColors.has('ctrl-color')) {
189
- S.setColorValue('ctrl-color', defaults.colorDefault, false);
190
- }
191
- // Update standalone color defaults for reset buttons
192
- const standaloneMap = {
193
- 'ctrl-bg-color': defaults.bgColor,
194
- 'ctrl-link-color': defaults.linkColor,
195
- 'ctrl-code-bg': defaults.codeBg,
196
- 'ctrl-code-color': defaults.codeColor,
197
- 'ctrl-bq-border-color': defaults.bqBorderColor,
198
- 'ctrl-bq-bg': defaults.bqBg,
199
- 'ctrl-bq-color': defaults.bqColor,
200
- };
201
- for (const [ctrlId, val] of Object.entries(standaloneMap)) {
202
- if (!S.overriddenColors.has(ctrlId)) {
203
- const el = document.getElementById(ctrlId);
204
- if (el) {
205
- el.value = val;
206
- const allVals = S.readAllControlValues();
207
- SDocStyles.controlToCssVars(ctrlId, val, allVals)
208
- .forEach(a => S.setStyleVar(a.cssVar, a.value));
209
- }
210
- }
211
- }
212
- S.syncAll('controls');
213
- }
214
-
215
- function getStandaloneDefault(ctrlId) {
216
- const d = getThemeDefaults();
217
- const map = {
218
- 'ctrl-bg-color': d.bgColor,
219
- 'ctrl-link-color': d.linkColor,
220
- 'ctrl-code-bg': d.codeBg,
221
- 'ctrl-code-color': d.codeColor,
222
- 'ctrl-bq-border-color': d.bqBorderColor,
223
- 'ctrl-bq-bg': d.bqBg,
224
- 'ctrl-bq-color': d.bqColor,
225
- };
226
- return map[ctrlId];
227
- }
228
-
229
- // ── Init at load time ──────────────────────────────────
230
-
231
- var initTheme = getPreferredTheme();
232
- applyTheme(initTheme);
233
-
234
- window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
235
- if (!localStorage.getItem('sdocs-theme')) {
236
- switchThemeAndUpdate(e.matches ? 'dark' : 'light');
237
- }
238
- });
239
-
240
- populateFontSelect(document.getElementById('ctrl-font-family'), false);
241
- document.getElementById('ctrl-font-family').value = "'Inter', sans-serif";
242
- populateFontSelect(document.getElementById('ctrl-h-font-family'), true);
243
-
244
- // ── Register on SDocs for cross-module access ──────────
245
-
246
- S.GOOGLE_FONTS = GOOGLE_FONTS;
247
- S.loadGoogleFont = loadGoogleFont;
248
- S.getThemeDefaults = getThemeDefaults;
249
- S.getThemeDefaultsFor = getThemeDefaultsFor;
250
- S.getColorDefault = getColorDefault;
251
- S.getStandaloneDefault = getStandaloneDefault;
252
- S.updateDefaultColors = updateDefaultColors;
253
- S.toggleTheme = toggleTheme;
254
- S.switchThemeAndUpdate = switchThemeAndUpdate;
255
- S.getPreferredTheme = getPreferredTheme;
256
- S.saveCurrentThemeColors = saveCurrentThemeColors;
257
- S.loadThemeColors = loadThemeColors;
258
- S.updateThemeTabs = updateThemeTabs;
259
-
260
- })();