diff --git a/docs/_document.html b/docs/_document.html index b4f4db151d..2db00323be 100644 --- a/docs/_document.html +++ b/docs/_document.html @@ -9,12 +9,38 @@ + @@ -20,7 +62,7 @@ /> - +

Marked Demo

ยท
Daring Fireball Demo - diff --git a/docs/demo/preview.html b/docs/demo/preview.html index d3f21e6e41..95aabc87db 100644 --- a/docs/demo/preview.html +++ b/docs/demo/preview.html @@ -4,6 +4,45 @@ marked.js preview + diff --git a/docs/js/index.js b/docs/js/index.js index 1a62c665ff..fe69aca6b5 100644 --- a/docs/js/index.js +++ b/docs/js/index.js @@ -1,84 +1,122 @@ document.addEventListener('DOMContentLoaded', function() { // --- Theme Toggling --- const themeToggle = document.getElementById('theme-toggle'); + const themeToggleIcon = themeToggle ? themeToggle.querySelector('[data-theme-icon]') : null; + const themeToggleText = themeToggle ? themeToggle.querySelector('[data-theme-text]') : null; + + const THEME_STORAGE_KEY = 'theme-preference'; + const LEGACY_STORAGE_KEY = 'theme'; + const THEME_ORDER = ['system', 'light', 'dark']; + const TOGGLE_UI = { + system: { icon: 'brightness_auto', text: 'System' }, + light: { icon: 'light_mode', text: 'Light' }, + dark: { icon: 'dark_mode', text: 'Dark' }, + }; - // Function to apply theme function applyTheme(theme) { if (theme === 'dark') { document.documentElement.classList.add('dark'); } else { document.documentElement.classList.remove('dark'); } + document.documentElement.setAttribute('data-theme', theme); } - // Function to get saved theme or system preference - function getPreferredTheme() { - // Check localStorage first - const savedTheme = localStorage.getItem('theme'); - if (savedTheme) { - return savedTheme; - } - - // Check system preference + function getSystemTheme() { if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { return 'dark'; } - - // Default to light return 'light'; } - // Apply theme on page load - const initialTheme = getPreferredTheme(); - applyTheme(initialTheme); - - // Theme toggle click handler - if (themeToggle) { - themeToggle.addEventListener('click', function() { - const currentTheme = document.documentElement.classList.contains('dark') ? 'dark' : 'light'; - const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; + function sanitisePreference(value) { + return THEME_ORDER.includes(value) ? value : null; + } - // Apply and save the new theme - applyTheme(newTheme); - localStorage.setItem('theme', newTheme); - }); + function readStoredPreference() { + try { + const stored = sanitisePreference(localStorage.getItem(THEME_STORAGE_KEY)); + if (stored) { + return stored; + } + return sanitisePreference(localStorage.getItem(LEGACY_STORAGE_KEY)); + } catch { + return null; + } } - // Listen for system theme changes - if (window.matchMedia) { - window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function(e) { - // Only apply system preference if user hasn't manually set a preference - if (!localStorage.getItem('theme')) { - applyTheme(e.matches ? 'dark' : 'light'); + function writeStoredPreference(preference) { + try { + localStorage.setItem(THEME_STORAGE_KEY, preference); + if (preference === 'light' || preference === 'dark') { + localStorage.setItem(LEGACY_STORAGE_KEY, preference); + } else { + localStorage.removeItem(LEGACY_STORAGE_KEY); } - }); + } catch { + // Storage might be unavailable; ignore + } } - // --- Navigation Link Highlighting --- - const navLinks = document.querySelectorAll('nav a'); - const activeClasses = ['text-primary', 'dark:text-primary', 'font-medium']; - const inactiveClasses = ['text-subtle-light', 'dark:text-subtle-dark']; + function getEffectiveTheme(preference) { + return preference === 'system' ? getSystemTheme() : preference; + } - function hashChange() { - // Use location.pathname and location.hash for more accurate matching - const currentUrl = window.location.pathname + window.location.hash; + function updateToggle(preference) { + if (!themeToggle) { + return; + } + const details = TOGGLE_UI[preference] || TOGGLE_UI.system; + if (themeToggleIcon) { + themeToggleIcon.textContent = details.icon; + } + if (themeToggleText) { + themeToggleText.textContent = details.text; + } + themeToggle.setAttribute('data-theme-mode', preference); + const label = `Switch theme (current: ${details.text})`; + themeToggle.setAttribute('aria-label', label); + themeToggle.title = label; + } - navLinks.forEach(function(link) { - const linkUrl = new URL(link.href); - const linkPath = linkUrl.pathname + linkUrl.hash; + let currentPreference = readStoredPreference() || 'system'; - if (linkPath === currentUrl) { - link.classList.add(...activeClasses); - link.classList.remove(...inactiveClasses); - } else { - link.classList.remove(...activeClasses); - link.classList.add(...inactiveClasses); - } + function applyPreference(preference, persist) { + currentPreference = preference; + const effectiveTheme = getEffectiveTheme(preference); + applyTheme(effectiveTheme); + document.documentElement.setAttribute('data-theme-preference', preference); + updateToggle(preference); + if (persist) { + writeStoredPreference(preference); + } + } + + applyPreference(currentPreference, true); + + if (themeToggle) { + themeToggle.addEventListener('click', function() { + const index = THEME_ORDER.indexOf(currentPreference); + const nextIndex = index === -1 ? 0 : (index + 1) % THEME_ORDER.length; + const nextPreference = THEME_ORDER[nextIndex]; + applyPreference(nextPreference, true); }); } - window.addEventListener('hashchange', hashChange); - hashChange(); // Run on initial load + const systemMatcher = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null; + if (systemMatcher) { + const handleSystemChange = function() { + if (currentPreference === 'system') { + applyPreference('system', false); + } + }; + + if (typeof systemMatcher.addEventListener === 'function') { + systemMatcher.addEventListener('change', handleSystemChange); + } else if (typeof systemMatcher.addListener === 'function') { + systemMatcher.addListener(handleSystemChange); + } + } // --- Copy-to-Clipboard Button --- const allPres = document.querySelectorAll('pre');