feat: ajouter ShaaritThemeConfig.load() pour lecture config bookmark et refactorer sync thème background avec IIFE async au lieu de setTimeout, éliminer fetch/parsing HTML manuel au profit de load() unifié, appliquer remote theme/mode uniquement si différents de localStorage, dispatch themeChanged seulement si changements effectués, et cleanup code dupliqué avec gestion erreurs try/catch centralisée

This commit is contained in:
Bruno Charest 2026-04-20 22:24:38 -04:00
parent aaf8e902a1
commit 7621eeef7a

View File

@ -139,7 +139,18 @@
return inflight; return inflight;
} }
window.ShaaritThemeConfig = { save, findCandidates }; // Reads the current persisted config from the bookmark (no write).
// Returns null when no bookmark exists yet or JSON is invalid.
async function load() {
try {
const { existing } = await readEditForm(CONFIG_URL);
return existing || null;
} catch (e) {
return null;
}
}
window.ShaaritThemeConfig = { save, load, findCandidates };
})(); })();
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
@ -3556,54 +3567,53 @@ document.addEventListener('DOMContentLoaded', () => {
})(); })();
// ===== Sync Theme from Bookmark in Background ===== // ===== Sync Theme from Bookmark in Background =====
setTimeout(() => { // On every page load (including hard refresh): fetch the single config
// Run sync after a slight delay to avoid blocking initial load // bookmark and apply {default, mode} if they differ from localStorage.
if (!window.shaarli || !window.shaarli.basePath) return; // This makes the bookmark the source of truth across devices/sessions.
(async function syncFromBookmark() {
fetch(window.shaarli.basePath + '/?searchtags=themes')
.then(res => res.text())
.then(text => {
const parser = new DOMParser();
const doc = parser.parseFromString(text, 'text/html');
const linkCard = doc.querySelector('.linklist-item');
if (linkCard) {
const descEl = linkCard.querySelector('.link-description p');
if (descEl) {
try { try {
const config = JSON.parse(descEl.textContent.trim()); if (!window.ShaaritThemeConfig) return;
const config = await window.ShaaritThemeConfig.load();
if (!config) return;
const remoteThemeId = config.default; const remoteThemeId = config.default;
const remoteMode = config.mode; const remoteMode = config.mode;
const localThemeId = localStorage.getItem('shaarit_theme_id') || 'DEFAULT'; const localThemeId = localStorage.getItem('shaarit_theme_id') || 'DEFAULT';
const localMode = localStorage.getItem('theme') || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'); const localMode = localStorage.getItem('theme')
|| (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
// Sync theme if different let changed = false;
if (remoteThemeId && remoteThemeId !== localThemeId) { if (remoteThemeId && remoteThemeId !== localThemeId) {
localStorage.setItem('shaarit_theme_id', remoteThemeId); localStorage.setItem('shaarit_theme_id', remoteThemeId);
document.documentElement.setAttribute('data-theme-id', remoteThemeId); document.documentElement.setAttribute('data-theme-id', remoteThemeId);
console.log('[shaarit] Theme synced from bookmark:', remoteThemeId); console.log('[shaarit] Theme synced from bookmark:', remoteThemeId);
changed = true;
} }
// Sync mode if different
if (remoteMode && remoteMode !== localMode) { if (remoteMode && remoteMode !== localMode) {
localStorage.setItem('theme', remoteMode); localStorage.setItem('theme', remoteMode);
document.documentElement.setAttribute('data-theme', remoteMode); document.documentElement.setAttribute('data-theme', remoteMode);
console.log('[shaarit] Mode synced from bookmark:', remoteMode); console.log('[shaarit] Mode synced from bookmark:', remoteMode);
changed = true;
} }
// Enforce light/dark constraints based on synced theme // Enforce dark-only theme constraints after remote apply
const darkOnlyThemes = ['LINEAR', 'SPOTIFY', 'NOTION', 'DISCORD', 'DRACULA', 'ONE_DARK_PRO', 'TOKYO_NIGHT', 'NORD', 'NIGHT_OWL', 'ANTHRACITE', 'CYBERPUNK', 'NAVY_ELEGANCE', 'EARTHY']; const darkOnlyThemes = ['LINEAR', 'SPOTIFY', 'NOTION', 'DISCORD', 'DRACULA',
const syncedThemeId = remoteThemeId || localThemeId; 'ONE_DARK_PRO', 'TOKYO_NIGHT', 'NORD', 'NIGHT_OWL', 'ANTHRACITE',
if (darkOnlyThemes.indexOf(syncedThemeId) !== -1) { 'CYBERPUNK', 'NAVY_ELEGANCE', 'EARTHY'];
const effectiveThemeId = remoteThemeId || localThemeId;
if (darkOnlyThemes.indexOf(effectiveThemeId) !== -1
&& localStorage.getItem('theme') !== 'dark') {
localStorage.setItem('theme', 'dark'); localStorage.setItem('theme', 'dark');
document.documentElement.setAttribute('data-theme', 'dark'); document.documentElement.setAttribute('data-theme', 'dark');
changed = true;
} }
if (changed) {
window.dispatchEvent(new Event('themeChanged')); window.dispatchEvent(new Event('themeChanged'));
} catch(e) {}
} }
} catch (err) {
console.log('[shaarit] Background theme sync failed:', err);
} }
}) })();
.catch(err => console.log('[shaarit] Background theme sync failed:', err));
}, 1500);
}); });