theme.js (2.3 KB)


 1 // Theme system
 2 let currentThemeIndex = 0;
 3 let isF2Pressed = false;
 4 const themes = ['sea-breeze', 'grape-soda', 'grapefruit', 'guac', 'mojito', 'banana', 'pantry'];
 5 const DEFAULT_THEME = 'guac';
 6 const DEFAULT_DARK_THEME = 'pantry';
 7 const THEME_TRANSITION_MS = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--theme-transition'));
 8 let themeTransitionTimer = null;
 9 
10 function syncThemeColorMeta() {
11 	const backgroundColor = getComputedStyle(document.documentElement).getPropertyValue('--desk').trim();
12 	document.querySelector('meta[name="theme-color"]').setAttribute('content', backgroundColor);
13 }
14 
15 function setTheme(theme) {
16 	document.documentElement.setAttribute('data-theme', theme);
17 	syncThemeColorMeta();
18 }
19 
20 function armPageRadiusTransition() {
21 	const page = document.querySelector('.page');
22 	if (!page) return;
23 
24 	page.classList.add('theming');
25 	clearTimeout(themeTransitionTimer);
26 	themeTransitionTimer = setTimeout(() => page.classList.remove('theming'), THEME_TRANSITION_MS + 50);
27 }
28 
29 function cycleTheme(step = 1) {
30 	currentThemeIndex = (currentThemeIndex + step + themes.length) % themes.length;
31 	const newTheme = themes[currentThemeIndex];
32 	armPageRadiusTransition();
33 	setTheme(newTheme);
34 	saveThemeToLocalStorage(newTheme);
35 }
36 
37 function saveThemeToLocalStorage(theme) {
38 	localStorage.setItem('memori-theme', theme);
39 }
40 
41 function loadThemeFromLocalStorage() {
42 	const savedTheme = localStorage.getItem('memori-theme');
43 	const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
44 	const theme = (savedTheme && themes.includes(savedTheme))
45 		? savedTheme
46 		: (prefersDark ? DEFAULT_DARK_THEME : DEFAULT_THEME);
47 
48 	currentThemeIndex = themes.indexOf(theme);
49 
50 	// the document opens on the default theme, so the first swap needs to land unanimated
51 	document.documentElement.classList.add('no-theme-transition');
52 	setTheme(theme);
53 	document.documentElement.offsetWidth; // flush the change before transitions come back
54 	document.documentElement.classList.remove('no-theme-transition');
55 }
56 
57 // F2 cycles themes, shift+F2 cycles backwards
58 document.addEventListener('keydown', (e) => {
59 	if (e.key === 'F2' && !isF2Pressed) {
60 		e.preventDefault();
61 		isF2Pressed = true;
62 		cycleTheme(e.shiftKey ? -1 : 1);
63 	}
64 });
65 
66 document.addEventListener('keyup', (e) => {
67 	if (e.key === 'F2') {
68 		isF2Pressed = false;
69 	}
70 });
71 
72 // Load theme on page load
73 loadThemeFromLocalStorage();