From 468e601096ec498af37187bf6bebc56436f87da3 Mon Sep 17 00:00:00 2001 From: you Date: Mon, 23 Mar 2026 00:53:17 +0000 Subject: [PATCH] Customization: personal user themes via localStorage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Export tab now has two sections: - "My Preferences" — save colors to browser localStorage, auto-applied on every page load. Personal to you, no server changes. - "Admin Export" — download config.json for server deployment, applies to all users. User theme auto-loads on DOMContentLoaded, overriding CSS variables and node colors from localStorage. --- public/customize.js | 54 ++++++++++++++++++++++++++++++++++++++++++--- public/index.html | 2 +- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/public/customize.js b/public/customize.js index f5a15321..23fd9297 100644 --- a/public/customize.js +++ b/public/customize.js @@ -199,11 +199,15 @@ .cust-export-area { width: 100%; min-height: 300px; font-family: var(--mono); font-size: 12px; background: var(--surface-1); border: 1px solid var(--border); border-radius: 6px; padding: 12px; color: var(--text); resize: vertical; box-sizing: border-box; } - .cust-export-btns { display: flex; gap: 8px; margin-top: 12px; } - .cust-export-btns button { padding: 8px 16px; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; font-weight: 500; } + .cust-export-btns { display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap; } + .cust-export-btns button { padding: 6px 14px; border: none; border-radius: 6px; cursor: pointer; font-size: 12px; font-weight: 500; } .cust-copy-btn { background: var(--accent); color: #fff; } .cust-copy-btn:hover { opacity: 0.9; } .cust-dl-btn { background: var(--surface-2); color: var(--text); border: 1px solid var(--border) !important; } + .cust-save-user { background: #22c55e; color: #fff; } + .cust-save-user:hover { background: #16a34a; } + .cust-reset-user { background: var(--surface-2); color: #ef4444; border: 1px solid #ef4444 !important; } + .cust-reset-user:hover { background: #ef4444; color: #fff; } .cust-dl-btn:hover { background: var(--surface-3); } .cust-reset-preview { margin-top: 12px; padding: 8px 16px; border: 1px solid var(--border); border-radius: 6px; background: var(--surface-2); color: var(--text); cursor: pointer; font-size: 13px; } @@ -369,8 +373,17 @@ function renderExport() { var json = JSON.stringify(buildExport(), null, 2); + var hasUserTheme = !!localStorage.getItem('meshcore-user-theme'); return '
' + - '

Export Configuration

' + + '

My Preferences

' + + '

Save these colors just for you — stored in your browser, works on any instance.

' + + '
' + + '' + + (hasUserTheme ? '' : '') + + '
' + + '
' + + '

Admin Export

' + + '

Export as config.json for server deployment — applies to all users of this instance.

' + '' + '
' + '' + @@ -567,6 +580,25 @@ a.click(); URL.revokeObjectURL(a.href); }); + + // Save user theme to localStorage + var saveUserBtn = document.getElementById('custSaveUser'); + if (saveUserBtn) saveUserBtn.addEventListener('click', function () { + var exportData = buildExport(); + localStorage.setItem('meshcore-user-theme', JSON.stringify(exportData)); + saveUserBtn.textContent = '✓ Saved!'; + setTimeout(function () { saveUserBtn.textContent = '💾 Save as my theme'; }, 2000); + }); + + // Reset user theme + var resetUserBtn = document.getElementById('custResetUser'); + if (resetUserBtn) resetUserBtn.addEventListener('click', function () { + localStorage.removeItem('meshcore-user-theme'); + resetPreview(); + initState(); + render(container); + applyThemePreview(); + }); } function toggle() { @@ -616,5 +648,21 @@ document.addEventListener('DOMContentLoaded', () => { const btn = document.getElementById('customizeToggle'); if (btn) btn.addEventListener('click', toggle); + + // Auto-apply saved user theme from localStorage + try { + const saved = localStorage.getItem('meshcore-user-theme'); + if (saved) { + const userTheme = JSON.parse(saved); + if (userTheme.theme) { + for (const [key, val] of Object.entries(userTheme.theme)) { + if (THEME_CSS_MAP[key]) document.documentElement.style.setProperty(THEME_CSS_MAP[key], val); + } + } + if (userTheme.nodeColors && window.ROLE_COLORS) { + Object.assign(window.ROLE_COLORS, userTheme.nodeColors); + } + } + } catch {} }); })(); diff --git a/public/index.html b/public/index.html index f94f3467..94cd758e 100644 --- a/public/index.html +++ b/public/index.html @@ -101,6 +101,6 @@ - +