src/lib/settings.js
Rama main · réplica de lectura del repositorio original.
import { useStorage } from './storage';
const settingsStorage = useStorage('settings');
export const DEFAULT_UI_FONT_STACK =
"system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Inter, sans-serif";
const settingDefs = {
theme: { legacyKey: 'theme', defaultValue: 'system', parse: String },
selectedLanguage: {
legacyKey: 'selectedLanguage',
defaultValue: 'en',
parse: String,
},
directionPreference: {
legacyKey: 'directionPreference',
defaultValue: 'ltr',
parse: String,
},
colorScheme: {
legacyKey: 'color-scheme',
defaultValue: 'light',
parse: String,
},
zoomLevel: { legacyKey: 'zoomLevel', defaultValue: '1.0', parse: String },
selectedFont: {
legacyKey: 'selected-font',
defaultValue: DEFAULT_UI_FONT_STACK,
parse: String,
},
selectedCodeFont: {
legacyKey: 'selected-font-code',
defaultValue: 'JetBrains Mono',
parse: String,
},
selectedDarkText: {
legacyKey: 'selected-dark-text',
defaultValue: 'white',
parse: String,
},
visibilityMenubar: {
legacyKey: 'visibility-menubar',
defaultValue: false,
parse: (value) => value === true || value === 'true',
},
spellcheckEnabled: {
legacyKey: 'spellcheckEnabled',
defaultValue: true,
parse: (value) => value === true || value === 'true',
},
reducedMotion: {
legacyKey: 'reducedMotion',
defaultValue: false,
parse: (value) => value === true || value === 'true',
},
highContrast: {
legacyKey: 'highContrast',
defaultValue: false,
parse: (value) => value === true || value === 'true',
},
advancedSettings: {
legacyKey: 'advanced-settings',
defaultValue: false,
parse: (value) => value === true || value === 'true',
},
todayDateFormat: {
legacyKey: 'todayDateFormat',
defaultValue: 'DD-MM-YYYY',
parse: String,
},
timeFormat: {
legacyKey: 'timeFormat',
defaultValue: 'HH:mm',
parse: String,
},
collapsibleHeading: {
legacyKey: 'collapsibleHeading',
defaultValue: true,
parse: (value) => value === true || value === 'true',
},
openLastEdited: {
legacyKey: 'openLastEdited',
defaultValue: true,
parse: (value) => value === true || value === 'true',
},
openAfterCreation: {
legacyKey: 'openAfterCreation',
defaultValue: true,
parse: (value) => value === true || value === 'true',
},
soundsEnabled: {
legacyKey: 'soundsEnabled',
defaultValue: true,
parse: (value) => value === true || value === 'true',
},
spotlightEnabled: {
legacyKey: 'spotlightEnabled',
defaultValue: false,
parse: (value) => value === true || value === 'true',
},
toolbarConfig: {
legacyKey: 'toolbarConfig',
defaultValue: null,
parse: (value) => {
if (value == null || value === '') return null;
if (Array.isArray(value)) return value;
try {
const parsed = JSON.parse(value);
return Array.isArray(parsed) ? parsed : null;
} catch {
return null;
}
},
},
onboardingCompleted: {
legacyKey: 'onboardingCompleted',
defaultValue: false,
parse: (value) => value === true || value === 'true',
},
beaverAccountServerUrl: {
legacyKey: 'beaverAccountServerUrl',
defaultValue: 'https://api.beavernotes.com',
parse: String,
},
syncTransport: {
legacyKey: 'syncTransport',
defaultValue: 'folder',
parse: String,
},
};
function getSettingDef(key) {
const def = settingDefs[key];
if (!def) {
throw new Error(`Unknown setting key: ${key}`);
}
return def;
}
function mirrorToLocalStorage(key, value) {
const { legacyKey } = getSettingDef(key);
if (value == null) {
localStorage.removeItem(legacyKey);
return;
}
if (typeof value === 'object') {
localStorage.setItem(legacyKey, JSON.stringify(value));
return;
}
localStorage.setItem(legacyKey, String(value));
}
export function getSettingSync(key) {
const { legacyKey, defaultValue, parse } = getSettingDef(key);
const raw = localStorage.getItem(legacyKey);
return raw == null ? defaultValue : parse(raw);
}
function hasMirroredValue(key) {
const { legacyKey } = getSettingDef(key);
return localStorage.getItem(legacyKey) != null;
}
export async function getSetting(key) {
const { defaultValue } = getSettingDef(key);
// Fast path: the value is mirrored to localStorage on every read/write, so a
// mirrored value can be returned without an IPC round-trip.
if (hasMirroredValue(key)) {
return getSettingSync(key);
}
const value = await settingsStorage.get(key, null);
if (value == null) {
await settingsStorage.set(key, defaultValue);
mirrorToLocalStorage(key, defaultValue);
return defaultValue;
}
mirrorToLocalStorage(key, value);
return value;
}
export async function setSetting(key, value) {
mirrorToLocalStorage(key, value);
await settingsStorage.set(key, value);
return value;
}
export async function hydrateSettingsStore(keys = Object.keys(settingDefs)) {
const entries = await Promise.all(
keys.map(async (key) => {
try {
return [key, await getSetting(key)];
} catch (err) {
console.warn(`[settings] Failed to hydrate "${key}":`, err);
return [key, getSettingDef(key).defaultValue];
}
})
);
return Object.fromEntries(entries);
}