Files
Shaarli_bm_theme/shaarli-pro/js/modules/theme.js
T
bruno f753b27542
CI / build (push) Failing after 6m2s
Add asset pipeline and professionalize theme
Introduce a Node build system for minified CSS/JS with content hashes,
add PWA support, i18n helpers, accessibility improvements, and more
translatable strings. Move theme configuration from bookmarks to
localStorage, add Playwright tests, and set up CI workflows.
2026-08-09 09:25:03 -04:00

123 lines
4.3 KiB
JavaScript

// =====================================================================
// Theme configuration and dark/light toggle for Shaarli Pro.
// Keeps theme/mode preferences client-side without creating bookmarks.
// Used by the dark/light switch AND the theme picker (tools.html).
// =====================================================================
(function () {
'use strict';
const STORAGE_KEY = 'shaarit_themes_config';
function readConfig() {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return null;
const parsed = JSON.parse(raw);
return (parsed && typeof parsed === 'object') ? parsed : null;
} catch (e) {
return null;
}
}
function writeConfig(config) {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(config));
return true;
} catch (e) {
return false;
}
}
// Merge partial updates into the persisted config and save to localStorage.
function save(partial) {
const base = readConfig() || {};
const config = Object.assign(
{ version: 2, themes: [], default: 'DEFAULT', mode: 'dark' },
base,
partial || {}
);
const ok = writeConfig(config);
return Promise.resolve({ ok, config });
}
// Reads the current persisted config from localStorage (no write).
function load() {
return Promise.resolve(readConfig());
}
// Kept for backward compatibility with older callers.
function findCandidates() {
return Promise.resolve([]);
}
window.ShaaritThemeConfig = { save, load, findCandidates };
})();
document.addEventListener('DOMContentLoaded', () => {
'use strict';
const themeCheckbox = document.getElementById('theme-toggle-checkbox');
const themeIconLight = document.getElementById('theme-icon-light');
const themeLabelSpan = document.querySelector('.theme-toggle-label span');
const i18n = window.ShaarliProI18n || { t: function (k) { return k; } };
function checkThemeRestrictions() {
const themeId = localStorage.getItem('shaarit_theme_id') || 'DEFAULT';
const darkOnlyThemes = ['LINEAR', 'SPOTIFY', 'NOTION', 'DISCORD', 'DRACULA', 'ONE_DARK_PRO', 'TOKYO_NIGHT', 'NORD', 'NIGHT_OWL', 'ANTHRACITE', 'CYBERPUNK', 'NAVY_ELEGANCE', 'EARTHY'];
return darkOnlyThemes.indexOf(themeId) !== -1;
}
function updateTheme(theme) {
// Enforce dark mode if the theme only supports dark
if (checkThemeRestrictions()) {
theme = 'dark';
}
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
if (themeCheckbox) {
themeCheckbox.checked = theme === 'dark';
// Disable the checkbox if restricted to dark mode
themeCheckbox.disabled = checkThemeRestrictions();
themeCheckbox.closest('.theme-switch').style.opacity = themeCheckbox.disabled ? '0.5' : '1';
}
if (themeIconLight) {
themeIconLight.className = theme === 'dark' ? 'mdi mdi-weather-night' : 'mdi mdi-weather-sunny';
}
if (themeLabelSpan) {
themeLabelSpan.textContent = theme === 'dark' ? i18n.t('Dark Mode') : i18n.t('Light Mode');
}
}
async function syncModeToBookmark(mode) {
try {
if (!window.ShaaritThemeConfig) return;
await window.ShaaritThemeConfig.save({ mode });
} catch (e) {
// eslint-disable-next-line no-console
console.error('[shaarit] Failed to sync mode to bookmark', e);
}
}
// Handle themeChanged event fired by tools.html
window.addEventListener('themeChanged', () => {
updateTheme(localStorage.getItem('theme') || 'dark');
});
// Init Theme
const savedTheme = localStorage.getItem('theme') ||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
updateTheme(savedTheme);
if (themeCheckbox) {
themeCheckbox.addEventListener('change', () => {
if (checkThemeRestrictions()) return; // Extra safety
const next = themeCheckbox.checked ? 'dark' : 'light';
updateTheme(next);
// Sync mode to bookmark in background
syncModeToBookmark(next);
});
}
});