feat: thèmes rapides gérés par le backend via fichiers CSS
Les thèmes ne sont plus codés en dur dans le JS. Chaque thème est un fichier CSS dans src-tauri/resources/themes/, embarqué à la compilation via include_str!. Le backend expose list_themes et get_theme_css comme commandes Tauri ; le frontend charge et met en cache le CSS à la demande. Ajout du thème "Défaut" (basé sur Shell Indigo) avec commentaires sur chaque règle et rendu complet des tableaux (en-têtes en majuscules, bordure extérieure, séparateurs verticaux, lignes alternées) aligné sur MarkdownRender-nodejs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+1
-6
@@ -76,12 +76,7 @@
|
||||
<div class="css-modal__body">
|
||||
<div class="css-modal__quick-themes">
|
||||
<p class="css-modal__quick-themes-label">Thèmes rapides</p>
|
||||
<div class="css-modal__quick-themes-list">
|
||||
<button class="css-modal__theme-badge" data-theme="dark">Mode sombre</button>
|
||||
<button class="css-modal__theme-badge" data-theme="sepia">Sépia</button>
|
||||
<button class="css-modal__theme-badge" data-theme="large-text">Grand texte</button>
|
||||
<button class="css-modal__theme-badge" data-theme="emerald">Accent émeraude</button>
|
||||
</div>
|
||||
<div id="quick-themes-list" class="css-modal__quick-themes-list"></div>
|
||||
</div>
|
||||
<p class="css-modal__description">Personnalisez l'apparence de vos pages en modifiant le CSS ci-dessous. Les styles s'appliquent à l'onglet actif.</p>
|
||||
<textarea id="css-editor" class="css-modal__editor" placeholder="/* Entrez votre CSS ici */ /* Exemple : .content { font-size: 18px; } */"></textarea>
|
||||
|
||||
+1
-1
@@ -32,5 +32,5 @@ document.getElementById('btn-open-dir').addEventListener('click', async () => {
|
||||
|
||||
document.getElementById('btn-back').addEventListener('click', showHome);
|
||||
|
||||
initCssModal();
|
||||
await initCssModal();
|
||||
showHome();
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
const { invoke } = window.__TAURI__.core;
|
||||
|
||||
export function listThemes() {
|
||||
return invoke('list_themes');
|
||||
}
|
||||
|
||||
export function getThemeCss(id) {
|
||||
return invoke('get_theme_css', { id });
|
||||
}
|
||||
+42
-39
@@ -1,33 +1,10 @@
|
||||
import { listThemes, getThemeCss } from '../services/themes.js';
|
||||
|
||||
const CSS_TABS = ['general', 'police', 'contenu', 'avance'];
|
||||
let activeTab = CSS_TABS[0];
|
||||
|
||||
const QUICK_THEME_KEY = 'pena_quick_theme';
|
||||
|
||||
const QUICK_THEMES = {
|
||||
dark: `.content { background: #1e1e2e; color: #cdd6f4; }
|
||||
.content h1, .content h2, .content h3, .content h4, .content h5, .content h6 { color: #cdd6f4; }
|
||||
.content p, .content ul li, .content ol li { color: #cdd6f4; }
|
||||
.content a { color: #89b4fa; }
|
||||
.content a:visited { color: #cba6f7; }
|
||||
.content code { background: #313244; color: #cba6f7; }
|
||||
.content pre { background: #313244; }
|
||||
.content blockquote { border-color: #6c7086; color: #a6adc8; }
|
||||
.content table td, .content table th { color: #cdd6f4; }`,
|
||||
|
||||
sepia: `.content { background: #f4ecd8; }
|
||||
.content h1, .content h2, .content h3, .content h4, .content h5, .content h6 { color: #5c4a1e; }
|
||||
.content p, .content ul li, .content ol li { color: #5c4a1e; }
|
||||
.content a { color: #7a5c2e; }
|
||||
.content code { background: #e8d5b0; color: #5c4a1e; }
|
||||
.content pre { background: #e8d5b0; }`,
|
||||
|
||||
'large-text': `.content { font-size: 18px; }
|
||||
.content p { line-height: 1.8; }`,
|
||||
|
||||
emerald: `.content a:hover { color: #10b981; }
|
||||
.content table th { border-bottom-color: #10b981; }
|
||||
.content table td { border-bottom-color: rgba(16, 185, 129, 0.25); }`,
|
||||
};
|
||||
const themeCssCache = new Map();
|
||||
|
||||
function cssKey(tab) { return `pena_css_${tab}`; }
|
||||
|
||||
@@ -47,7 +24,7 @@ function applyCustomCss() {
|
||||
}
|
||||
const tabCss = CSS_TABS.map(t => loadTabCss(t)).filter(Boolean).join('\n');
|
||||
const activeTheme = localStorage.getItem(QUICK_THEME_KEY);
|
||||
const themeCss = activeTheme ? (QUICK_THEMES[activeTheme] ?? '') : '';
|
||||
const themeCss = activeTheme ? (themeCssCache.get(activeTheme) ?? '') : '';
|
||||
styleEl.textContent = [tabCss, themeCss].filter(Boolean).join('\n');
|
||||
}
|
||||
|
||||
@@ -58,7 +35,44 @@ function syncThemeBadges() {
|
||||
});
|
||||
}
|
||||
|
||||
export function initCssModal() {
|
||||
function buildThemeBadges(themes) {
|
||||
const list = document.getElementById('quick-themes-list');
|
||||
list.innerHTML = '';
|
||||
for (const { id, label } of themes) {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'css-modal__theme-badge';
|
||||
btn.dataset.theme = id;
|
||||
btn.textContent = label;
|
||||
btn.addEventListener('click', async () => {
|
||||
const current = localStorage.getItem(QUICK_THEME_KEY);
|
||||
if (current === id) {
|
||||
localStorage.removeItem(QUICK_THEME_KEY);
|
||||
} else {
|
||||
if (!themeCssCache.has(id)) {
|
||||
const css = await getThemeCss(id);
|
||||
if (css) themeCssCache.set(id, css);
|
||||
}
|
||||
localStorage.setItem(QUICK_THEME_KEY, id);
|
||||
}
|
||||
applyCustomCss();
|
||||
syncThemeBadges();
|
||||
});
|
||||
list.appendChild(btn);
|
||||
}
|
||||
}
|
||||
|
||||
async function preloadActiveThemeCss() {
|
||||
const activeTheme = localStorage.getItem(QUICK_THEME_KEY);
|
||||
if (activeTheme && !themeCssCache.has(activeTheme)) {
|
||||
const css = await getThemeCss(activeTheme);
|
||||
if (css) themeCssCache.set(activeTheme, css);
|
||||
}
|
||||
}
|
||||
|
||||
export async function initCssModal() {
|
||||
const themes = await listThemes();
|
||||
buildThemeBadges(themes);
|
||||
await preloadActiveThemeCss();
|
||||
applyCustomCss();
|
||||
syncThemeBadges();
|
||||
|
||||
@@ -104,15 +118,4 @@ export function initCssModal() {
|
||||
applyCustomCss();
|
||||
syncThemeBadges();
|
||||
});
|
||||
|
||||
document.querySelectorAll('.css-modal__theme-badge').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
const theme = btn.dataset.theme;
|
||||
const current = localStorage.getItem(QUICK_THEME_KEY);
|
||||
if (current === theme) localStorage.removeItem(QUICK_THEME_KEY);
|
||||
else localStorage.setItem(QUICK_THEME_KEY, theme);
|
||||
applyCustomCss();
|
||||
syncThemeBadges();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user