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() {
try {
if (!window.ShaaritThemeConfig) return;
const config = await window.ShaaritThemeConfig.load();
if (!config) return;
fetch(window.shaarli.basePath + '/?searchtags=themes') const remoteThemeId = config.default;
.then(res => res.text()) const remoteMode = config.mode;
.then(text => { const localThemeId = localStorage.getItem('shaarit_theme_id') || 'DEFAULT';
const parser = new DOMParser(); const localMode = localStorage.getItem('theme')
const doc = parser.parseFromString(text, 'text/html'); || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
const linkCard = doc.querySelector('.linklist-item');
if (linkCard) {
const descEl = linkCard.querySelector('.link-description p');
if (descEl) {
try {
const config = JSON.parse(descEl.textContent.trim());
const remoteThemeId = config.default;
const remoteMode = config.mode;
const localThemeId = localStorage.getItem('shaarit_theme_id') || 'DEFAULT';
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;
}
if (remoteMode && remoteMode !== localMode) {
localStorage.setItem('theme', remoteMode);
document.documentElement.setAttribute('data-theme', remoteMode);
console.log('[shaarit] Mode synced from bookmark:', remoteMode);
changed = true;
}
// Sync mode if different // Enforce dark-only theme constraints after remote apply
if (remoteMode && remoteMode !== localMode) { const darkOnlyThemes = ['LINEAR', 'SPOTIFY', 'NOTION', 'DISCORD', 'DRACULA',
localStorage.setItem('theme', remoteMode); 'ONE_DARK_PRO', 'TOKYO_NIGHT', 'NORD', 'NIGHT_OWL', 'ANTHRACITE',
document.documentElement.setAttribute('data-theme', remoteMode); 'CYBERPUNK', 'NAVY_ELEGANCE', 'EARTHY'];
console.log('[shaarit] Mode synced from bookmark:', remoteMode); const effectiveThemeId = remoteThemeId || localThemeId;
} if (darkOnlyThemes.indexOf(effectiveThemeId) !== -1
&& localStorage.getItem('theme') !== 'dark') {
localStorage.setItem('theme', 'dark');
document.documentElement.setAttribute('data-theme', 'dark');
changed = true;
}
// Enforce light/dark constraints based on synced theme if (changed) {
const darkOnlyThemes = ['LINEAR', 'SPOTIFY', 'NOTION', 'DISCORD', 'DRACULA', 'ONE_DARK_PRO', 'TOKYO_NIGHT', 'NORD', 'NIGHT_OWL', 'ANTHRACITE', 'CYBERPUNK', 'NAVY_ELEGANCE', 'EARTHY']; window.dispatchEvent(new Event('themeChanged'));
const syncedThemeId = remoteThemeId || localThemeId; }
if (darkOnlyThemes.indexOf(syncedThemeId) !== -1) { } catch (err) {
localStorage.setItem('theme', 'dark'); console.log('[shaarit] Background theme sync failed:', err);
document.documentElement.setAttribute('data-theme', 'dark'); }
} })();
window.dispatchEvent(new Event('themeChanged'));
} catch(e) {}
}
}
})
.catch(err => console.log('[shaarit] Background theme sync failed:', err));
}, 1500);
}); });