Fix: auto-save all customizations to localStorage on every change

Every color pick, text edit, step change auto-saves (debounced
500ms). No manual save needed. Also fixed syncBadgeColors on
restore and removed stray closing brace.
This commit is contained in:
you committed 2026-03-23 02:56:03 +00:00
1 parent bfc1acbbe6
commit 074dd736d9
2 files changed
+22 -11

No files matched your search

+21 -10
View File
@@ -245,10 +245,19 @@
}
function applyTypeColorCSS() {
// Now handled by syncBadgeColors in roles.js
if (window.syncBadgeColors) window.syncBadgeColors();
}
// Auto-save to localStorage on every change
let _autoSaveTimer = null;
function autoSave() {
if (_autoSaveTimer) clearTimeout(_autoSaveTimer);
_autoSaveTimer = setTimeout(function() {
_autoSaveTimer = null;
try { localStorage.setItem('meshcore-user-theme', JSON.stringify(buildExport())); } catch {}
}, 500);
}
function resetPreview() {
for (var key in THEME_CSS_MAP) {
document.documentElement.style.removeProperty(THEME_CSS_MAP[key]);
@@ -608,6 +617,7 @@
var parts = inp.dataset.key.split('.');
if (parts.length === 2) {
state[parts[0]][parts[1]] = inp.value;
autoSave();
}
// Live DOM updates for branding
if (inp.dataset.key === 'branding.siteName') {
@@ -637,7 +647,7 @@
state[themeKey][key] = inp.value;
var hex = container.querySelector('[data-hex="' + key + '"]');
if (hex) hex.textContent = inp.value;
applyThemePreview();
applyThemePreview(); autoSave();
});
});
@@ -647,7 +657,7 @@
var key = btn.dataset.resetTheme;
var themeKey = isDarkMode() ? 'themeDark' : 'theme';
state[themeKey][key] = activeDefaults()[key];
applyThemePreview();
applyThemePreview(); autoSave();
render(container);
});
});
@@ -671,7 +681,7 @@
if (window.ROLE_COLORS) window.ROLE_COLORS[key] = inp.value;
if (window.ROLE_STYLE && window.ROLE_STYLE[key]) window.ROLE_STYLE[key].color = inp.value;
// Trigger re-render of current page
window.dispatchEvent(new CustomEvent('theme-changed'));
window.dispatchEvent(new CustomEvent('theme-changed')); autoSave();
var dot = container.querySelector('[data-dot="' + key + '"]');
if (dot) dot.style.background = inp.value;
var hex = container.querySelector('[data-nhex="' + key + '"]');
@@ -697,7 +707,7 @@
state.typeColors[key] = inp.value;
if (window.TYPE_COLORS) window.TYPE_COLORS[key] = inp.value;
if (window.syncBadgeColors) window.syncBadgeColors();
window.dispatchEvent(new CustomEvent('theme-changed'));
window.dispatchEvent(new CustomEvent('theme-changed')); autoSave();
var dot = container.querySelector('[data-tdot="' + key + '"]');
if (dot) dot.style.background = inp.value;
var hex = container.querySelector('[data-thex="' + key + '"]');
@@ -717,7 +727,7 @@
container.querySelectorAll('[data-step-field]').forEach(function (inp) {
inp.addEventListener('input', function () {
var i = parseInt(inp.dataset.idx);
state.home.steps[i][inp.dataset.stepField] = inp.value;
state.home.steps[i][inp.dataset.stepField] = inp.value; autoSave();
});
});
container.querySelectorAll('[data-move-step]').forEach(function (btn) {
@@ -748,7 +758,7 @@
container.querySelectorAll('[data-check-field]').forEach(function (inp) {
inp.addEventListener('input', function () {
var i = parseInt(inp.dataset.idx);
state.home.checklist[i][inp.dataset.checkField] = inp.value;
state.home.checklist[i][inp.dataset.checkField] = inp.value; autoSave();
});
});
container.querySelectorAll('[data-rm-check]').forEach(function (btn) {
@@ -767,7 +777,7 @@
container.querySelectorAll('[data-link-field]').forEach(function (inp) {
inp.addEventListener('input', function () {
var i = parseInt(inp.dataset.idx);
state.home.footerLinks[i][inp.dataset.linkField] = inp.value;
state.home.footerLinks[i][inp.dataset.linkField] = inp.value; autoSave();
});
});
container.querySelectorAll('[data-rm-link]').forEach(function (btn) {
@@ -827,7 +837,7 @@
resetPreview();
initState();
render(container);
applyThemePreview();
applyThemePreview(); autoSave();
});
}
@@ -871,7 +881,7 @@
});
render(panelEl.querySelector('.cust-inner'));
applyThemePreview();
applyThemePreview(); autoSave();
}
// Wire up toggle button
@@ -902,6 +912,7 @@
}
if (userTheme.typeColors && window.TYPE_COLORS) {
Object.assign(window.TYPE_COLORS, userTheme.typeColors);
if (window.syncBadgeColors) window.syncBadgeColors();
}
}
} catch {}
+1 -1
View File
@@ -101,6 +101,6 @@
<script src="observer-detail.js?v=1774219440" onerror="console.error('Failed to load:', this.src)"></script>
<script src="node-analytics.js?v=1774126708" onerror="console.error('Failed to load:', this.src)"></script>
<script src="perf.js?v=1773985649" onerror="console.error('Failed to load:', this.src)"></script>
<script src="customize.js?v=1774234000" onerror="console.error('Failed to load:', this.src)"></script>
<script src="customize.js?v=1774234563" onerror="console.error('Failed to load:', this.src)"></script>
</body>
</html>