haufen sachen

This commit is contained in:
th committed 2026-04-08 22:46:48 +02:00
1 parent 416ca9e854
commit e6243701a3
20 files changed
+1562 -116

No files matched your search

+91 -15
View File
@@ -1,25 +1,101 @@
// ── Theme picker ──
// ── Theme + Settings ──
import { $ } from './util.js';
import { $, api, getCsrf } from './util.js';
import { state } from './state.js';
import { renderSettingsPanel as renderNotifSettings } from './notifications.js';
const picker = $('theme-picker');
const list = $('theme-list');
const overlay = $('settings-overlay');
const themeList = $('settings-theme-list');
if (list) {
// Render theme list in settings
function renderThemes() {
if (!themeList) return;
const current = localStorage.getItem('hyprcrd-theme') || 'slate';
themeList.innerHTML = '';
for (const [key, t] of Object.entries(window.themes)) {
const btn = document.createElement('button');
btn.className = 'flex items-center gap-2.5 w-full px-2 py-1.5 text-left text-xs text-t-muted hover:text-t-bright transition-colors rounded';
btn.dataset.themeDot = key;
btn.innerHTML = `<span class="w-3 h-3 rounded-full shrink-0 border border-t-border" style="background:${t.vars['--t-accent']}"></span>
<span class="font-pixel text-[10px]">${t.label}</span>`;
btn.onclick = () => { window.applyTheme(key); window._renderBoard?.(); };
list.appendChild(btn);
const active = key === current;
btn.className = `flex items-center gap-3 px-3 py-2.5 text-left text-xs border transition-colors rounded ${active ? 'border-t-accent text-t-bright' : 'border-t-border text-t-muted hover:border-t-accent hover:text-t-bright'}`;
btn.innerHTML = `<span class="w-4 h-4 rounded-full shrink-0" style="background:${t.vars['--t-accent']}"></span>
<span class="font-pixel text-[10px] flex-1">${t.label}</span>
${active ? '<i class="ph ph-check text-t-accent text-sm"></i>' : ''}`;
btn.onclick = () => { window.applyTheme(key); renderThemes(); window._renderBoard?.(); };
themeList.appendChild(btn);
}
}
window.applyTheme(localStorage.getItem('hyprcrd-theme') || 'slate');
// Tab switching
overlay?.querySelectorAll('.settings-tab').forEach(tab => {
tab.addEventListener('click', () => {
overlay.querySelectorAll('.settings-tab').forEach(t => t.classList.remove('active'));
tab.classList.add('active');
const panel = tab.dataset.tab;
overlay.querySelectorAll('[id^="settings-panel-"]').forEach(p => p.classList.add('hidden'));
$(`settings-panel-${panel}`)?.classList.remove('hidden');
if (panel === 'sync') window._loadCaldavSettings?.();
if (panel === 'notifications') renderNotifSettings();
if (panel === 'behavior') initBehaviorSettings();
});
});
if (picker) {
$('theme-toggle')?.addEventListener('click', () => picker.classList.toggle('open'));
document.addEventListener('click', e => { if (!picker.contains(e.target)) picker.classList.remove('open'); });
// Open/Close
function updateStats() {
const sc = $('stats-cards'); if (sc) sc.textContent = state.cards?.length || 0;
const sb = $('stats-buckets'); if (sb) sb.textContent = state.buckets?.length || 0;
const tags = new Set(); (state.cards || []).forEach(c => (c.tags || '').split(',').forEach(t => { if (t) tags.add(t); }));
const st = $('stats-tags'); if (st) st.textContent = tags.size;
}
$('settings-btn')?.addEventListener('click', () => {
renderThemes();
updateStats();
overlay?.classList.add('open');
});
$('settings-close')?.addEventListener('click', () => overlay?.classList.remove('open'));
overlay?.addEventListener('click', e => { if (e.target === overlay) overlay?.classList.remove('open'); });
// Password change
$('settings-pw-save')?.addEventListener('click', async () => {
const current = $('settings-pw-current')?.value;
const newPw = $('settings-pw-new')?.value;
const confirm = $('settings-pw-confirm')?.value;
const status = $('settings-pw-status');
if (!current || !newPw) { if (status) { status.textContent = 'fill all fields'; status.style.color = 'var(--t-danger)'; } return; }
if (newPw !== confirm) { if (status) { status.textContent = 'passwords do not match'; status.style.color = 'var(--t-danger)'; } return; }
if (newPw.length < 4) { if (status) { status.textContent = 'min 4 characters'; status.style.color = 'var(--t-danger)'; } return; }
const res = await fetch('api/auth/password', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': getCsrf() },
body: JSON.stringify({ current, new: newPw }),
}).then(r => r.json()).catch(() => ({ error: 'network error' }));
if (res.ok) {
if (status) { status.textContent = res.rekey ? 'password changed — re-encrypting notes...' : 'password changed'; status.style.color = 'var(--t-accent)'; }
$('settings-pw-current').value = '';
$('settings-pw-new').value = '';
$('settings-pw-confirm').value = '';
// Trigger sync to re-push notes with new encryption key
if (res.rekey) {
window._triggerSync?.();
setTimeout(() => { if (status) status.textContent = 'password changed, notes re-encrypted'; }, 3000);
}
} else {
if (status) { status.textContent = res.error || 'failed'; status.style.color = 'var(--t-danger)'; }
}
});
function initBehaviorSettings() {
const sel = $('setting-current-days');
if (sel) {
sel.value = localStorage.getItem('hyprcrd-current-days') || '2';
sel.onchange = () => {
localStorage.setItem('hyprcrd-current-days', sel.value);
window._renderBoard?.();
};
}
}
// Apply saved theme on load
window.applyTheme(localStorage.getItem('hyprcrd-theme') || 'slate');