feat(theme): Verdrahtung Custom-Theme (applySettings, selectThemeCard, Picker, Reset, Modal-Sync)

This commit is contained in:
2026-06-15 04:00:59 +02:00
parent 1bd2cbb9ad
commit 2af52fc46d
+49 -2
View File
@@ -80,6 +80,8 @@ function openThemeModal() {
document.addEventListener('keydown', _themeTrap);
const first = _focusable(modal)[0];
if (first) first.focus();
syncCustomPickers();
document.getElementById('themeBuilderPanel').classList.toggle('hidden', settings.theme !== 'custom');
}
function closeThemeModal() {
const overlay = document.getElementById('themeOverlay');
@@ -462,7 +464,11 @@ function applySettings() {
const langEl = document.getElementById('settingLanguage');
if (langEl) langEl.value = settings.language || 'auto';
applyTheme(settings.theme || 'nebula', !!settings.bgUrl);
if (settings.theme === 'custom') {
applyCustomTheme(settings.customTheme);
} else {
applyTheme(settings.theme || 'nebula', !!settings.bgUrl);
}
if (settings.bgUrl && isValidBgUrl(settings.bgUrl)) {
document.getElementById('bgLayer').style.backgroundImage = `url('${settings.bgUrl}')`;
@@ -489,10 +495,25 @@ function bindSettingsEvents() {
const themeCards = document.querySelectorAll('.theme-card');
function selectThemeCard(card) {
const name = card.dataset.value;
if (!name || name === settings.theme) return Promise.resolve();
if (!name) return Promise.resolve();
// Custom: VOR dem name===settings.theme-Guard, damit ein Re-Klick das Panel wieder oeffnet.
if (name === 'custom') {
settings.theme = 'custom';
if (!settings.customTheme) settings.customTheme = { ...CUSTOM_DEFAULTS };
themeCards.forEach(c => c.setAttribute('aria-pressed', c === card ? 'true' : 'false'));
applyCustomTheme(settings.customTheme); // setzt data-theme + Inline-Vars; bgUrl UNANGETASTET (Koexistenz)
syncCustomPickers();
document.getElementById('themeBuilderPanel').classList.remove('hidden');
return saveSettings();
}
if (name === settings.theme) return Promise.resolve();
settings.theme = name;
settings.bgUrl = '';
document.getElementById('bgUrlInput').value = '';
clearCustomTheme(); // Inline-Vars weg beim Rueckwechsel auf ein Preset
document.getElementById('themeBuilderPanel').classList.add('hidden');
// aria-pressed synchron halten — applyTheme/switchTheme pflegt nur die .active-Klasse, nicht ARIA
themeCards.forEach(c => c.setAttribute('aria-pressed', c === card ? 'true' : 'false'));
switchTheme(name); // WICHTIG: switchTheme aus Phase 4 (View-Transition-Wrapper), NICHT applyTheme direkt — sonst geht der Theme-Fade verloren
@@ -508,6 +529,31 @@ function bindSettingsEvents() {
});
});
// Theme-Builder Picker
const TB_PICKERS = [['tbAccent', 'accent'], ['tbBg', 'bgPrimary'], ['tbBoard', 'bgBoard'],
['tbText', 'textPrimary'], ['tbTextSec', 'textSecondary'], ['tbTextMuted', 'textMuted']];
TB_PICKERS.forEach(([id, key]) => {
const el = document.getElementById(id);
if (!el) return;
el.addEventListener('input', () => { // live waehrend des Ziehens
if (!settings.customTheme) settings.customTheme = { ...CUSTOM_DEFAULTS };
settings.customTheme[key] = el.value;
settings.theme = 'custom';
applyCustomTheme(settings.customTheme);
});
el.addEventListener('change', () => saveSettings()); // persistiert beim Loslassen/Schliessen
});
const tbReset = document.getElementById('tbReset');
if (tbReset) {
tbReset.addEventListener('click', async () => {
settings.customTheme = { ...CUSTOM_DEFAULTS };
applyCustomTheme(settings.customTheme);
syncCustomPickers();
await saveSettings();
});
}
// Accordion initialisieren
initAccordion();
@@ -639,6 +685,7 @@ function bindSettingsEvents() {
hideExtra: false, visibleCount: 10, bgUrl: '', theme: 'nebula',
showSearch: true, searchEngine: 'google', toolbarPos: 'right',
imageRefEnabled: false, language: 'auto', customTheme: null };
clearCustomTheme();
await saveBoards();
await saveTrash();
await saveSettings();