/* store.jsx — клиентский стор настроек и категорий. * Источник правды для категорий (динамические!) и пользовательских настроек. * Грузится через api.getSettings(), пишется через api.updateSettings/category. * Любой компонент подписывается хуком useSettings() / useCategories(). */ (function () { // палитра слотов цвета для категорий (классы .cat-c-* в CSS) const COLORS = ["blue", "green", "red", "purple", "amber", "teal", "pink", "gray"]; const COLOR_LABEL = { blue: "Синий", green: "Зелёный", red: "Терракот", purple: "Сирень", amber: "Янтарь", teal: "Бирюза", pink: "Розовый", gray: "Серый", }; const FALLBACK = { categories: [ { key: "work", label: "Работа", color: "blue", system: true }, { key: "personal", label: "Личное", color: "green", system: true }, { key: "important", label: "Важное", color: "red", system: true }, { key: "idea", label: "Идея", color: "purple", system: true }, { key: "other", label: "Прочее", color: "gray", system: true }, ], density: "cozy", defaultCategory: "other", showSource: true, autoReminders: true, lockVault: false, vaultPin: "1234", autoHidePw: 15, }; let settings = JSON.parse(JSON.stringify(FALLBACK)); let loaded = false; const subs = new Set(); const emit = () => subs.forEach((fn) => fn(settings)); async function load() { try { const s = await api.getSettings(); if (s) settings = s; } catch (e) {} loaded = true; emit(); return settings; } function get() { return settings; } function isLoaded() { return loaded; } function subscribe(fn) { subs.add(fn); return () => subs.delete(fn); } function categoryList() { return settings.categories || []; } function catOf(key) { const list = settings.categories || []; return list.find((c) => c.key === key) || { key: key || "other", label: "Прочее", color: "gray", system: true }; } function colorClass(color) { return "cat-c-" + (COLORS.includes(color) ? color : "gray"); } /* --- мутации настроек (через api, затем локально + emit) --- */ async function patchSettings(patch) { settings = { ...settings, ...patch }; emit(); const s = await api.updateSettings(patch); if (s) { settings = s; emit(); } return settings; } async function addCategory(label, color) { const cat = await api.createCategory({ label, color }); settings = { ...settings, categories: [...settings.categories, cat] }; emit(); return cat; } async function editCategory(key, patch) { await api.updateCategory(key, patch); settings = { ...settings, categories: settings.categories.map((c) => (c.key === key ? { ...c, ...patch } : c)), }; emit(); } async function removeCategory(key) { await api.deleteCategory(key); settings = { ...settings, categories: settings.categories.filter((c) => c.key !== key) }; emit(); } /* --- React-хуки --- */ function useSettings() { const [, force] = React.useReducer((x) => x + 1, 0); React.useEffect(() => subscribe(force), []); React.useEffect(() => { if (!loaded) load(); }, []); return settings; } function useCategories() { useSettings(); return categoryList(); } window.Store = { COLORS, COLOR_LABEL, load, get, isLoaded, subscribe, categoryList, catOf, colorClass, patchSettings, addCategory, editCategory, removeCategory, useSettings, useCategories, }; // экспортируем catOf/colorClass и в глобальную область — их зовут компоненты ui.jsx window.catOf = catOf; window.colorClass = colorClass; })();