feat: add visual customization presets to Settings > Appearance tab
Some checks failed
Lint & Test / test (push) Failing after 30s
Some checks failed
Lint & Test / test (push) Failing after 30s
Add style presets (font + color combinations) and background effect presets as a new Appearance tab in the settings modal. Style presets include Default, Midnight, Ember, Arctic, Terminal, and Neon — each with curated dark/light theme colors and Google Font pairings. Background effects (Dot Grid, Gradient Mesh, Scanlines, Particles) use a dedicated overlay div alongside the existing WebGL Noise Field. All choices persist to localStorage and restore on page load.
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
<button class="demo-banner-dismiss" onclick="dismissDemoBanner()" aria-label="Dismiss">×</button>
|
||||
</div>
|
||||
<canvas id="bg-anim-canvas"></canvas>
|
||||
<div id="bg-effect-layer"></div>
|
||||
<div id="connection-overlay" class="connection-overlay" style="display:none" aria-hidden="true">
|
||||
<div class="connection-overlay-content">
|
||||
<div class="connection-spinner-lg"></div>
|
||||
@@ -221,18 +222,46 @@
|
||||
// Initialize ambient background
|
||||
const savedBgAnim = localStorage.getItem('bgAnim') || 'off';
|
||||
document.documentElement.setAttribute('data-bg-anim', savedBgAnim);
|
||||
updateBgAnimBtn(savedBgAnim);
|
||||
|
||||
// All known CSS bg-effect classes (must match appearance.ts BG_EFFECT_PRESETS)
|
||||
var _bgEffectClasses = ['bg-effect-grid', 'bg-effect-mesh', 'bg-effect-scanlines', 'bg-effect-particles'];
|
||||
|
||||
function toggleBgAnim() {
|
||||
const cur = document.documentElement.getAttribute('data-bg-anim');
|
||||
const next = cur === 'on' ? 'off' : 'on';
|
||||
document.documentElement.setAttribute('data-bg-anim', next);
|
||||
localStorage.setItem('bgAnim', next);
|
||||
updateBgAnimBtn(next);
|
||||
var savedEffect = localStorage.getItem('bgEffect') || 'none';
|
||||
var isOn = _isBgEffectActive();
|
||||
|
||||
if (isOn) {
|
||||
// Turn everything off
|
||||
document.documentElement.setAttribute('data-bg-anim', 'off');
|
||||
document.documentElement.removeAttribute('data-bg-effect');
|
||||
var lyr = document.getElementById('bg-effect-layer');
|
||||
if (lyr) _bgEffectClasses.forEach(function(c) { lyr.classList.remove(c); });
|
||||
updateBgAnimBtn('off');
|
||||
} else {
|
||||
// Restore saved effect (or fallback to WebGL noise)
|
||||
if (savedEffect === 'none') savedEffect = 'noise';
|
||||
if (typeof window.applyBgEffect === 'function') {
|
||||
window.applyBgEffect(savedEffect);
|
||||
} else {
|
||||
// Fallback before bundle loads: just toggle WebGL
|
||||
document.documentElement.setAttribute('data-bg-anim', 'on');
|
||||
}
|
||||
updateBgAnimBtn('on');
|
||||
}
|
||||
}
|
||||
|
||||
function _isBgEffectActive() {
|
||||
if (document.documentElement.getAttribute('data-bg-anim') === 'on') return true;
|
||||
var lyr = document.getElementById('bg-effect-layer');
|
||||
if (!lyr) return false;
|
||||
for (var i = 0; i < _bgEffectClasses.length; i++) {
|
||||
if (lyr.classList.contains(_bgEffectClasses[i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function updateBgAnimBtn(state) {
|
||||
const btn = document.getElementById('bg-anim-btn');
|
||||
var btn = document.getElementById('bg-anim-btn');
|
||||
if (btn) btn.style.opacity = state === 'on' ? '1' : '0.5';
|
||||
}
|
||||
|
||||
@@ -341,12 +370,18 @@
|
||||
const savedAccent = localStorage.getItem('accentColor');
|
||||
if (savedAccent) applyAccentColor(savedAccent, true);
|
||||
|
||||
// Early-apply saved background effect class (before bundle loads)
|
||||
// Early-apply saved background effect class on the dedicated layer element
|
||||
const savedBgEffect = localStorage.getItem('bgEffect');
|
||||
if (savedBgEffect && savedBgEffect !== 'none') {
|
||||
const effectClasses = { grid: 'bg-effect-grid', mesh: 'bg-effect-mesh', scanlines: 'bg-effect-scanlines', particles: 'bg-effect-particles' };
|
||||
if (effectClasses[savedBgEffect]) document.documentElement.classList.add(effectClasses[savedBgEffect]);
|
||||
if (savedBgEffect && savedBgEffect !== 'none' && savedBgEffect !== 'noise') {
|
||||
var effectClasses = { grid: 'bg-effect-grid', mesh: 'bg-effect-mesh', scanlines: 'bg-effect-scanlines', particles: 'bg-effect-particles' };
|
||||
var layer = document.getElementById('bg-effect-layer');
|
||||
if (layer && effectClasses[savedBgEffect]) {
|
||||
layer.classList.add(effectClasses[savedBgEffect]);
|
||||
document.documentElement.setAttribute('data-bg-effect', savedBgEffect);
|
||||
}
|
||||
}
|
||||
// Set header toggle button state (reflects both WebGL and CSS effects)
|
||||
updateBgAnimBtn(_isBgEffectActive() ? 'on' : 'off');
|
||||
|
||||
// Initialize auth state
|
||||
function updateAuthUI() {
|
||||
|
||||
Reference in New Issue
Block a user