Audit all 6 user settings sections. Remove dead chat-era code, rename localStorage namespace, clean up stale backend policies. - Remove BYOK nav section (empty BYOK_ITEMS, byokEnabled state, "BYOK Enabled" badge) and personas gate filter from settings nav - Remove auth.permissions.changed listener (existed solely for dead BYOK + personas state) - Remove Message Font Size slider, msgFont state, and --msg-font CSS variable application from appearance section and base template - Rename localStorage key cs-appearance → sb-appearance with one-time migration preserving existing user preferences - Remove allow_user_byok and allow_user_personas from PolicyDefaults, profile bootstrap, permissions handler, PublicSettings, and test seeds - Remove orphaned .settings-nav-footer CSS class - Replace stale policy-gating test assertions with allow_registration Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
88 lines
3.1 KiB
JavaScript
88 lines
3.1 KiB
JavaScript
/**
|
|
* AppearanceSection — theme, UI scale
|
|
*/
|
|
const { html } = window;
|
|
const { useState, useCallback } = hooks;
|
|
|
|
// Migrate cs- prefix to sb- (one-time, preserves existing prefs)
|
|
if (!localStorage.getItem('sb-appearance') && localStorage.getItem('cs-appearance')) {
|
|
localStorage.setItem('sb-appearance', localStorage.getItem('cs-appearance'));
|
|
localStorage.removeItem('cs-appearance');
|
|
}
|
|
|
|
const THEMES = [
|
|
{ key: 'light', icon: '\u2600', label: 'Light' },
|
|
{ key: 'dark', icon: '\u263E', label: 'Dark' },
|
|
{ key: 'system', icon: '\u2395', label: 'System' },
|
|
];
|
|
|
|
function getPrefs() {
|
|
try { return JSON.parse(localStorage.getItem('sb-appearance') || '{}'); }
|
|
catch { return {}; }
|
|
}
|
|
|
|
export function AppearanceSection() {
|
|
const prefs = getPrefs();
|
|
const [theme, setTheme] = useState(sw.theme?.current || 'system');
|
|
const [scale, setScale] = useState(prefs.scale || 100);
|
|
|
|
const applyTheme = useCallback((mode) => {
|
|
setTheme(mode);
|
|
sw.theme.set(mode);
|
|
sw.emit('theme.changed', { mode, resolved: sw.theme.current });
|
|
}, []);
|
|
|
|
const save = useCallback(() => {
|
|
const p = getPrefs();
|
|
p.scale = scale;
|
|
localStorage.setItem('sb-appearance', JSON.stringify(p));
|
|
|
|
// Apply scale to content area only (not shell/nav)
|
|
const inner = document.getElementById('surfaceInner');
|
|
if (inner) {
|
|
if (scale !== 100) {
|
|
const s = scale / 100;
|
|
inner.style.transform = `scale(${s})`;
|
|
inner.style.transformOrigin = 'top left';
|
|
inner.style.width = (100 / s) + '%';
|
|
inner.style.height = (100 / s) + '%';
|
|
} else {
|
|
inner.style.transform = '';
|
|
inner.style.width = '';
|
|
inner.style.height = '';
|
|
}
|
|
}
|
|
|
|
sw.emit('toast', { message: 'Appearance saved', variant: 'success' });
|
|
}, [scale]);
|
|
|
|
return html`
|
|
<div class="settings-section">
|
|
<h3>Theme</h3>
|
|
<div class="toggle-group" style="display:flex;gap:0;">
|
|
${THEMES.map(t => html`
|
|
<button class="toggle-btn ${theme === t.key ? 'active' : ''}"
|
|
onClick=${() => applyTheme(t.key)}>
|
|
${t.icon} ${t.label}
|
|
</button>
|
|
`)}
|
|
</div>
|
|
</div>
|
|
<div class="settings-section">
|
|
<h3>UI Scale</h3>
|
|
<div class="form-group">
|
|
<div style="display:flex;align-items:center;gap:8px;">
|
|
<input type="range" min="80" max="175" step="5"
|
|
value=${scale}
|
|
onInput=${e => setScale(parseInt(e.target.value))}
|
|
style="flex:1;" />
|
|
<span style="font-size:12px;color:var(--text-2);font-family:var(--mono);min-width:32px;">
|
|
${scale}%
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button class="btn-md btn-primary" onClick=${save}>Save</button>
|
|
`;
|
|
}
|