ultimate-jekyll-manager 0.0.188 → 0.0.190
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/CLAUDE.md +64 -0
- package/README.md +29 -0
- package/TODO.md +2 -0
- package/dist/assets/js/core/appearance.js +197 -0
- package/dist/assets/js/pages/test/libraries/appearance/index.js +214 -0
- package/dist/assets/js/ultimate-jekyll-manager.js +2 -0
- package/dist/assets/themes/bootstrap/_theme.scss +9 -230
- package/dist/assets/themes/bootstrap/overrides/_accordion.scss +21 -0
- package/dist/assets/themes/{classy/css/components → bootstrap/overrides}/_avatars.scss +18 -3
- package/dist/assets/themes/bootstrap/overrides/_blog-images.scss +45 -0
- package/dist/assets/themes/bootstrap/overrides/_buttons-adaptive.scss +122 -0
- package/dist/assets/themes/bootstrap/overrides/_cursor-utilities.scss +13 -0
- package/dist/assets/themes/bootstrap/overrides/_index.scss +29 -0
- package/dist/assets/themes/bootstrap/overrides/_links.scss +31 -0
- package/dist/assets/themes/{classy/css/base → bootstrap/overrides}/_soft-colors.scss +11 -4
- package/dist/assets/themes/bootstrap/overrides/_spacing-extended.scss +74 -0
- package/dist/assets/themes/{classy/css/components → bootstrap/overrides}/_spinners.scss +6 -3
- package/dist/assets/themes/bootstrap/overrides/_typography-utilities.scss +40 -0
- package/dist/assets/themes/classy/_theme.js +2 -1
- package/dist/assets/themes/classy/_theme.scss +4 -5
- package/dist/assets/themes/classy/css/base/_typography.scss +0 -31
- package/dist/assets/themes/classy/css/base/_utilities.scss +1 -14
- package/dist/assets/themes/classy/css/components/_buttons.scss +0 -133
- package/dist/defaults/dist/_includes/core/body.html +46 -10
- package/dist/defaults/dist/pages/test/libraries/appearance.html +271 -0
- package/package.json +1 -1
- package/dist/assets/themes/classy/css/base/_spacing.scss +0 -68
- package/dist/assets/themes/classy/css/components/_links.scss +0 -19
package/CLAUDE.md
CHANGED
|
@@ -558,6 +558,70 @@ data-lazy="@type value"
|
|
|
558
558
|
|
|
559
559
|
**Implementation:** `src/assets/js/core/lazy-loading.js`
|
|
560
560
|
|
|
561
|
+
## Appearance Switching System
|
|
562
|
+
|
|
563
|
+
Ultimate Jekyll supports dark/light/system theme switching with user preference persistence.
|
|
564
|
+
|
|
565
|
+
### Supported Modes
|
|
566
|
+
- `dark` - Force dark mode
|
|
567
|
+
- `light` - Force light mode
|
|
568
|
+
- `system` - Auto-detect from OS preference (`prefers-color-scheme`)
|
|
569
|
+
|
|
570
|
+
### JavaScript API
|
|
571
|
+
|
|
572
|
+
```javascript
|
|
573
|
+
// Get/set preference
|
|
574
|
+
webManager.uj().appearance.get(); // Returns 'dark', 'light', 'system', or null
|
|
575
|
+
webManager.uj().appearance.set('dark'); // Save and apply preference
|
|
576
|
+
webManager.uj().appearance.getResolved(); // Returns actual theme: 'dark' or 'light'
|
|
577
|
+
|
|
578
|
+
// Utilities
|
|
579
|
+
webManager.uj().appearance.toggle(); // Toggle between dark/light
|
|
580
|
+
webManager.uj().appearance.cycle(); // Cycle: dark → light → system → dark
|
|
581
|
+
webManager.uj().appearance.clear(); // Clear saved preference
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
### HTML Data Attributes
|
|
585
|
+
|
|
586
|
+
```html
|
|
587
|
+
<!-- Buttons to set appearance (auto-gets 'active' class) -->
|
|
588
|
+
<button data-appearance-set="light">Light</button>
|
|
589
|
+
<button data-appearance-set="dark">Dark</button>
|
|
590
|
+
<button data-appearance-set="system">System</button>
|
|
591
|
+
|
|
592
|
+
<!-- Display current mode as text -->
|
|
593
|
+
<span data-appearance-current></span>
|
|
594
|
+
|
|
595
|
+
<!-- Show/hide icons based on current mode -->
|
|
596
|
+
<span data-appearance-icon="light" hidden>☀️</span>
|
|
597
|
+
<span data-appearance-icon="dark" hidden>🌙</span>
|
|
598
|
+
<span data-appearance-icon="system" hidden>💻</span>
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
### Dropdown Example
|
|
602
|
+
|
|
603
|
+
```html
|
|
604
|
+
<div class="dropdown">
|
|
605
|
+
<button class="btn dropdown-toggle" data-bs-toggle="dropdown">
|
|
606
|
+
<span data-appearance-icon="light" hidden>{% uj_icon "sun", "fa-md me-2" %}</span>
|
|
607
|
+
<span data-appearance-icon="dark" hidden>{% uj_icon "moon-stars", "fa-md me-2" %}</span>
|
|
608
|
+
<span data-appearance-icon="system" hidden>{% uj_icon "circle-half-stroke", "fa-md me-2" %}</span>
|
|
609
|
+
<span data-appearance-current></span>
|
|
610
|
+
</button>
|
|
611
|
+
<ul class="dropdown-menu">
|
|
612
|
+
<li><a class="dropdown-item" href="#" data-appearance-set="light">Light</a></li>
|
|
613
|
+
<li><a class="dropdown-item" href="#" data-appearance-set="dark">Dark</a></li>
|
|
614
|
+
<li><a class="dropdown-item" href="#" data-appearance-set="system">System</a></li>
|
|
615
|
+
</ul>
|
|
616
|
+
</div>
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
### Implementation
|
|
620
|
+
- **Inline script:** `src/defaults/dist/_includes/core/body.html` - Runs immediately to prevent flash
|
|
621
|
+
- **Module:** `src/assets/js/core/appearance.js` - API and UI handling
|
|
622
|
+
- **Storage:** Saved under `_manager.appearance.preference` in localStorage
|
|
623
|
+
- **Test page:** `/test/libraries/appearance`
|
|
624
|
+
|
|
561
625
|
## JavaScript Libraries
|
|
562
626
|
|
|
563
627
|
### WebManager
|
package/README.md
CHANGED
|
@@ -256,6 +256,35 @@ The `<html>` element has data attributes for JavaScript/CSS targeting:
|
|
|
256
256
|
| `data-runtime` | `web`, `extension`, `electron`, `node` |
|
|
257
257
|
| `aria-busy` | `true` (loading), `false` (ready) |
|
|
258
258
|
|
|
259
|
+
### Appearance Switching
|
|
260
|
+
|
|
261
|
+
Ultimate Jekyll supports dark/light/system theme switching with user preference persistence.
|
|
262
|
+
|
|
263
|
+
**JavaScript API:**
|
|
264
|
+
```javascript
|
|
265
|
+
webManager.uj().appearance.get(); // Returns 'dark', 'light', 'system', or null
|
|
266
|
+
webManager.uj().appearance.set('dark'); // Save and apply preference
|
|
267
|
+
webManager.uj().appearance.toggle(); // Toggle dark/light
|
|
268
|
+
webManager.uj().appearance.cycle(); // Cycle: dark → light → system
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**HTML Dropdown Example:**
|
|
272
|
+
```html
|
|
273
|
+
<div class="dropdown">
|
|
274
|
+
<button class="btn dropdown-toggle" data-bs-toggle="dropdown">
|
|
275
|
+
<span data-appearance-icon="light" hidden>{% uj_icon "sun" %}</span>
|
|
276
|
+
<span data-appearance-icon="dark" hidden>{% uj_icon "moon-stars" %}</span>
|
|
277
|
+
<span data-appearance-icon="system" hidden>{% uj_icon "circle-half-stroke" %}</span>
|
|
278
|
+
<span data-appearance-current></span>
|
|
279
|
+
</button>
|
|
280
|
+
<ul class="dropdown-menu">
|
|
281
|
+
<li><a href="#" data-appearance-set="light">Light</a></li>
|
|
282
|
+
<li><a href="#" data-appearance-set="dark">Dark</a></li>
|
|
283
|
+
<li><a href="#" data-appearance-set="system">System</a></li>
|
|
284
|
+
</ul>
|
|
285
|
+
</div>
|
|
286
|
+
```
|
|
287
|
+
|
|
259
288
|
### Page Loading Protection System
|
|
260
289
|
|
|
261
290
|
Ultimate Jekyll includes an automatic protection system that prevents users from clicking buttons before JavaScript is fully loaded, eliminating race conditions and errors.
|
package/TODO.md
CHANGED
|
@@ -8,6 +8,8 @@ NEW TODO
|
|
|
8
8
|
- form manager should NOT submit if the button that was clicked is disabled (class or attribute)
|
|
9
9
|
- GLOBAL FIXES FOR ALL UJM PROJECTS: nav.json should ahve class only not color
|
|
10
10
|
|
|
11
|
+
/authentication-required
|
|
12
|
+
* ithink this is leftover from Electron Manager auth system??? but lots on proxifly. need to make a version of it for UJM2.0
|
|
11
13
|
|
|
12
14
|
Make an admin dashboard backend
|
|
13
15
|
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Appearance Module
|
|
3
|
+
* Handles theme appearance switching (dark, light, system)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Constants
|
|
7
|
+
const STORAGE_KEY = 'appearance.preference';
|
|
8
|
+
const VALID_VALUES = ['dark', 'light', 'system'];
|
|
9
|
+
|
|
10
|
+
// Module state
|
|
11
|
+
let webManager = null;
|
|
12
|
+
let mediaQuery = null;
|
|
13
|
+
|
|
14
|
+
// Module
|
|
15
|
+
export default (Manager) => {
|
|
16
|
+
// Shortcuts
|
|
17
|
+
webManager = Manager.webManager;
|
|
18
|
+
|
|
19
|
+
// Create appearance API
|
|
20
|
+
const appearanceAPI = {
|
|
21
|
+
/**
|
|
22
|
+
* Get the current saved preference
|
|
23
|
+
* @returns {string|null} 'dark', 'light', 'system', or null if not set
|
|
24
|
+
*/
|
|
25
|
+
get: () => webManager.storage().get(STORAGE_KEY) || null,
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get the resolved (actual) theme being displayed
|
|
29
|
+
* @returns {string} 'dark' or 'light'
|
|
30
|
+
*/
|
|
31
|
+
getResolved: () => document.documentElement.getAttribute('data-bs-theme') || 'dark',
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Set the appearance preference
|
|
35
|
+
* @param {string} value - 'dark', 'light', or 'system'
|
|
36
|
+
*/
|
|
37
|
+
set: (value) => {
|
|
38
|
+
// Validate
|
|
39
|
+
if (!VALID_VALUES.includes(value)) {
|
|
40
|
+
console.warn(`Invalid appearance value: ${value}. Must be one of: ${VALID_VALUES.join(', ')}`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Save preference
|
|
45
|
+
webManager.storage().set(STORAGE_KEY, value);
|
|
46
|
+
|
|
47
|
+
// Apply theme
|
|
48
|
+
applyTheme(value);
|
|
49
|
+
|
|
50
|
+
// Update UI elements
|
|
51
|
+
updateUI(value);
|
|
52
|
+
|
|
53
|
+
// Setup or teardown system preference listener
|
|
54
|
+
setupSystemListener(value === 'system');
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Toggle between dark and light (skips system)
|
|
59
|
+
*/
|
|
60
|
+
toggle() {
|
|
61
|
+
const current = this.getResolved();
|
|
62
|
+
const next = current === 'dark' ? 'light' : 'dark';
|
|
63
|
+
this.set(next);
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Cycle through all three modes: dark → light → system → dark
|
|
68
|
+
*/
|
|
69
|
+
cycle() {
|
|
70
|
+
const current = this.get() || this.getResolved();
|
|
71
|
+
const order = ['dark', 'light', 'system'];
|
|
72
|
+
const currentIndex = order.indexOf(current);
|
|
73
|
+
const nextIndex = (currentIndex + 1) % order.length;
|
|
74
|
+
this.set(order[nextIndex]);
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Clear saved preference (revert to site default)
|
|
79
|
+
*/
|
|
80
|
+
clear: () => {
|
|
81
|
+
webManager.storage().remove(STORAGE_KEY);
|
|
82
|
+
updateUI(null);
|
|
83
|
+
setupSystemListener(false);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// Register on UJ library
|
|
88
|
+
webManager._ujLibrary.appearance = appearanceAPI;
|
|
89
|
+
|
|
90
|
+
// Initialize UI event listeners
|
|
91
|
+
initializeUI();
|
|
92
|
+
|
|
93
|
+
// Setup system listener if current preference is 'system'
|
|
94
|
+
const currentPreference = appearanceAPI.get();
|
|
95
|
+
if (currentPreference === 'system') {
|
|
96
|
+
setupSystemListener(true);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Update UI with current state
|
|
100
|
+
updateUI(currentPreference);
|
|
101
|
+
|
|
102
|
+
console.log('Appearance module loaded');
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Apply theme to the document
|
|
107
|
+
* @param {string} preference - 'dark', 'light', or 'system'
|
|
108
|
+
*/
|
|
109
|
+
const applyTheme = (preference) => {
|
|
110
|
+
let theme = preference;
|
|
111
|
+
|
|
112
|
+
// Resolve system preference
|
|
113
|
+
if (preference === 'system') {
|
|
114
|
+
theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Apply to document
|
|
118
|
+
document.documentElement.setAttribute('data-bs-theme', theme);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Setup or teardown the system preference change listener
|
|
123
|
+
* @param {boolean} enable - Whether to enable the listener
|
|
124
|
+
*/
|
|
125
|
+
const setupSystemListener = (enable) => {
|
|
126
|
+
// Clean up existing listener
|
|
127
|
+
if (mediaQuery) {
|
|
128
|
+
mediaQuery.removeEventListener('change', handleSystemChange);
|
|
129
|
+
mediaQuery = null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Setup new listener if needed
|
|
133
|
+
if (enable) {
|
|
134
|
+
mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
135
|
+
mediaQuery.addEventListener('change', handleSystemChange);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Handle system preference change
|
|
141
|
+
* @param {MediaQueryListEvent} event
|
|
142
|
+
*/
|
|
143
|
+
const handleSystemChange = (event) => {
|
|
144
|
+
const theme = event.matches ? 'dark' : 'light';
|
|
145
|
+
document.documentElement.setAttribute('data-bs-theme', theme);
|
|
146
|
+
updateUI('system');
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Initialize UI event listeners
|
|
151
|
+
*/
|
|
152
|
+
const initializeUI = () => {
|
|
153
|
+
// Use event delegation for appearance controls
|
|
154
|
+
document.addEventListener('click', (event) => {
|
|
155
|
+
const $target = event.target.closest('[data-appearance-set]');
|
|
156
|
+
|
|
157
|
+
if (!$target) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
event.preventDefault();
|
|
162
|
+
|
|
163
|
+
const value = $target.getAttribute('data-appearance-set');
|
|
164
|
+
webManager.uj().appearance.set(value);
|
|
165
|
+
});
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Update UI elements to reflect current state
|
|
170
|
+
* @param {string|null} preference - Current preference
|
|
171
|
+
*/
|
|
172
|
+
const updateUI = (preference) => {
|
|
173
|
+
const resolved = document.documentElement.getAttribute('data-bs-theme');
|
|
174
|
+
const displayValue = preference || resolved;
|
|
175
|
+
|
|
176
|
+
// Update [data-appearance-current] elements with the preference
|
|
177
|
+
document.querySelectorAll('[data-appearance-current]').forEach(($el) => {
|
|
178
|
+
const format = $el.getAttribute('data-appearance-current') || 'preference';
|
|
179
|
+
$el.textContent = format === 'resolved' ? resolved : displayValue;
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Update [data-appearance-icon] elements - show/hide based on current mode
|
|
183
|
+
// Icons should have data-appearance-icon="light|dark|system" attribute
|
|
184
|
+
document.querySelectorAll('[data-appearance-icon]').forEach(($el) => {
|
|
185
|
+
const iconMode = $el.getAttribute('data-appearance-icon');
|
|
186
|
+
$el.hidden = iconMode !== displayValue;
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Update active state on [data-appearance-set] elements
|
|
190
|
+
document.querySelectorAll('[data-appearance-set]').forEach(($el) => {
|
|
191
|
+
const value = $el.getAttribute('data-appearance-set');
|
|
192
|
+
const isActive = value === preference || (!preference && value === resolved);
|
|
193
|
+
|
|
194
|
+
$el.classList.toggle('active', isActive);
|
|
195
|
+
$el.setAttribute('aria-pressed', isActive ? 'true' : 'false');
|
|
196
|
+
});
|
|
197
|
+
};
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Appearance Test Page JavaScript
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Libraries
|
|
6
|
+
let webManager = null;
|
|
7
|
+
|
|
8
|
+
// Module
|
|
9
|
+
export default (Manager) => {
|
|
10
|
+
return new Promise(async function (resolve) {
|
|
11
|
+
// Shortcuts
|
|
12
|
+
webManager = Manager.webManager;
|
|
13
|
+
|
|
14
|
+
// Initialize when DOM is ready
|
|
15
|
+
await webManager.dom().ready();
|
|
16
|
+
|
|
17
|
+
// Initialize debug panel
|
|
18
|
+
initDebugPanel();
|
|
19
|
+
|
|
20
|
+
// Initialize programmatic controls
|
|
21
|
+
initControls();
|
|
22
|
+
|
|
23
|
+
// Initialize event logging
|
|
24
|
+
initEventLog();
|
|
25
|
+
|
|
26
|
+
// Resolve after initialization
|
|
27
|
+
return resolve();
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Initialize debug panel with live values
|
|
33
|
+
*/
|
|
34
|
+
function initDebugPanel() {
|
|
35
|
+
const $debugSaved = document.getElementById('debug-saved');
|
|
36
|
+
const $debugResolved = document.getElementById('debug-resolved');
|
|
37
|
+
const $debugAttr = document.getElementById('debug-attr');
|
|
38
|
+
const $debugLocalStorage = document.getElementById('debug-localstorage');
|
|
39
|
+
const $debugSystem = document.getElementById('debug-system');
|
|
40
|
+
const $btnRefresh = document.getElementById('btn-refresh');
|
|
41
|
+
|
|
42
|
+
// Update function
|
|
43
|
+
function updateDebug() {
|
|
44
|
+
const appearance = webManager.uj().appearance;
|
|
45
|
+
|
|
46
|
+
// Saved preference via API
|
|
47
|
+
const saved = appearance.get();
|
|
48
|
+
$debugSaved.textContent = saved !== null ? `"${saved}"` : 'null (not set)';
|
|
49
|
+
|
|
50
|
+
// Resolved theme via API
|
|
51
|
+
const resolved = appearance.getResolved();
|
|
52
|
+
$debugResolved.textContent = `"${resolved}"`;
|
|
53
|
+
|
|
54
|
+
// Raw HTML attribute
|
|
55
|
+
const attr = document.documentElement.getAttribute('data-bs-theme');
|
|
56
|
+
$debugAttr.textContent = `"${attr}"`;
|
|
57
|
+
|
|
58
|
+
// Raw localStorage value (stored under _manager.appearance.preference)
|
|
59
|
+
let rawStorage = null;
|
|
60
|
+
try {
|
|
61
|
+
const managerData = localStorage.getItem('_manager');
|
|
62
|
+
const parsedData = managerData ? JSON.parse(managerData) : null;
|
|
63
|
+
rawStorage = parsedData?.appearance?.preference || null;
|
|
64
|
+
} catch (e) {
|
|
65
|
+
rawStorage = '(error reading)';
|
|
66
|
+
}
|
|
67
|
+
$debugLocalStorage.textContent = rawStorage !== null ? `"${rawStorage}"` : 'null';
|
|
68
|
+
|
|
69
|
+
// System preference
|
|
70
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
71
|
+
const systemPref = prefersDark ? 'dark' : 'light';
|
|
72
|
+
$debugSystem.textContent = `"${systemPref}" (prefers-color-scheme: ${prefersDark ? 'dark' : 'light'})`;
|
|
73
|
+
|
|
74
|
+
console.log('[Appearance Test] Debug updated:', {
|
|
75
|
+
saved,
|
|
76
|
+
resolved,
|
|
77
|
+
attr,
|
|
78
|
+
rawStorage,
|
|
79
|
+
systemPref,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Initial update
|
|
84
|
+
updateDebug();
|
|
85
|
+
|
|
86
|
+
// Refresh button
|
|
87
|
+
$btnRefresh.addEventListener('click', updateDebug);
|
|
88
|
+
|
|
89
|
+
// Auto-update when theme changes (observe attribute changes)
|
|
90
|
+
const observer = new MutationObserver((mutations) => {
|
|
91
|
+
mutations.forEach((mutation) => {
|
|
92
|
+
if (mutation.attributeName === 'data-bs-theme') {
|
|
93
|
+
updateDebug();
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
observer.observe(document.documentElement, { attributes: true });
|
|
98
|
+
|
|
99
|
+
// Also listen for system preference changes
|
|
100
|
+
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
101
|
+
mediaQuery.addEventListener('change', updateDebug);
|
|
102
|
+
|
|
103
|
+
// Export for console access
|
|
104
|
+
window.updateAppearanceDebug = updateDebug;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Initialize programmatic control buttons
|
|
109
|
+
*/
|
|
110
|
+
function initControls() {
|
|
111
|
+
const appearance = webManager.uj().appearance;
|
|
112
|
+
|
|
113
|
+
// Toggle button
|
|
114
|
+
document.getElementById('btn-toggle').addEventListener('click', () => {
|
|
115
|
+
console.log('[Appearance Test] Toggle clicked');
|
|
116
|
+
appearance.toggle();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Cycle button
|
|
120
|
+
document.getElementById('btn-cycle').addEventListener('click', () => {
|
|
121
|
+
console.log('[Appearance Test] Cycle clicked');
|
|
122
|
+
appearance.cycle();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Clear button
|
|
126
|
+
document.getElementById('btn-clear').addEventListener('click', () => {
|
|
127
|
+
console.log('[Appearance Test] Clear clicked');
|
|
128
|
+
appearance.clear();
|
|
129
|
+
// Trigger debug update
|
|
130
|
+
window.updateAppearanceDebug?.();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Quick set buttons
|
|
134
|
+
document.getElementById('btn-set-light').addEventListener('click', () => {
|
|
135
|
+
console.log('[Appearance Test] set("light") clicked');
|
|
136
|
+
appearance.set('light');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
document.getElementById('btn-set-dark').addEventListener('click', () => {
|
|
140
|
+
console.log('[Appearance Test] set("dark") clicked');
|
|
141
|
+
appearance.set('dark');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
document.getElementById('btn-set-system').addEventListener('click', () => {
|
|
145
|
+
console.log('[Appearance Test] set("system") clicked');
|
|
146
|
+
appearance.set('system');
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Initialize event logging
|
|
152
|
+
*/
|
|
153
|
+
function initEventLog() {
|
|
154
|
+
const $log = document.getElementById('event-log');
|
|
155
|
+
const $clearBtn = document.getElementById('btn-clear-log');
|
|
156
|
+
let logLines = [];
|
|
157
|
+
|
|
158
|
+
function addLogEntry(message) {
|
|
159
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
160
|
+
const entry = `[${timestamp}] ${message}`;
|
|
161
|
+
logLines.push(entry);
|
|
162
|
+
|
|
163
|
+
// Keep last 50 entries
|
|
164
|
+
if (logLines.length > 50) {
|
|
165
|
+
logLines = logLines.slice(-50);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
$log.textContent = logLines.join('\n');
|
|
169
|
+
$log.scrollTop = $log.scrollHeight;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Clear log button
|
|
173
|
+
$clearBtn.addEventListener('click', () => {
|
|
174
|
+
logLines = [];
|
|
175
|
+
$log.textContent = 'Log cleared...';
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Observe data-bs-theme changes
|
|
179
|
+
const observer = new MutationObserver((mutations) => {
|
|
180
|
+
mutations.forEach((mutation) => {
|
|
181
|
+
if (mutation.attributeName === 'data-bs-theme') {
|
|
182
|
+
const oldValue = mutation.oldValue;
|
|
183
|
+
const newValue = document.documentElement.getAttribute('data-bs-theme');
|
|
184
|
+
addLogEntry(`Theme changed: "${oldValue}" -> "${newValue}"`);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
observer.observe(document.documentElement, {
|
|
189
|
+
attributes: true,
|
|
190
|
+
attributeOldValue: true,
|
|
191
|
+
attributeFilter: ['data-bs-theme'],
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Log system preference changes
|
|
195
|
+
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
196
|
+
mediaQuery.addEventListener('change', (event) => {
|
|
197
|
+
const systemPref = event.matches ? 'dark' : 'light';
|
|
198
|
+
addLogEntry(`System preference changed: "${systemPref}"`);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Log click events on appearance controls
|
|
202
|
+
document.addEventListener('click', (event) => {
|
|
203
|
+
const $target = event.target.closest('[data-appearance-set]');
|
|
204
|
+
if ($target) {
|
|
205
|
+
const value = $target.getAttribute('data-appearance-set');
|
|
206
|
+
addLogEntry(`User clicked: set("${value}")`);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Initial log entry
|
|
211
|
+
addLogEntry('Appearance test page loaded');
|
|
212
|
+
addLogEntry(`Initial theme: "${document.documentElement.getAttribute('data-bs-theme')}"`);
|
|
213
|
+
addLogEntry(`Saved preference: ${webManager.uj().appearance.get() || '(none)'}`);
|
|
214
|
+
}
|
|
@@ -4,6 +4,7 @@ import authModule from '__main_assets__/js/core/auth.js';
|
|
|
4
4
|
import lazyLoadingModule from '__main_assets__/js/core/lazy-loading.js';
|
|
5
5
|
import queryStringsModule from '__main_assets__/js/core/query-strings.js';
|
|
6
6
|
import serviceWorkerModule from '__main_assets__/js/core/service-worker.js';
|
|
7
|
+
import appearanceModule from '__main_assets__/js/core/appearance.js';
|
|
7
8
|
import completeModule from '__main_assets__/js/core/complete.js';
|
|
8
9
|
|
|
9
10
|
// Ultimate Jekyll Manager Module
|
|
@@ -32,6 +33,7 @@ export default async function (Manager, options) {
|
|
|
32
33
|
lazyLoadingModule(Manager, options);
|
|
33
34
|
queryStringsModule(Manager, options);
|
|
34
35
|
serviceWorkerModule(Manager, options);
|
|
36
|
+
appearanceModule(Manager, options);
|
|
35
37
|
|
|
36
38
|
// Conditionally loaded modules based on config (keep as dynamic imports)
|
|
37
39
|
const conditionalModules = [
|