aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver/frontend/html/theme.js
blob: 52ca116abfa6bab36b4b0a6ae740d4bab063657f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Copyright Epic Games, Inc. All Rights Reserved.

// Theme toggle: cycles system → light → dark → system.
// Persists choice in localStorage. Applies data-theme attribute on <html>.

(function() {
	var KEY = 'zen-theme';

	function getStored() {
		try { return localStorage.getItem(KEY); } catch (e) { return null; }
	}

	function setStored(value) {
		try {
			if (value) localStorage.setItem(KEY, value);
			else localStorage.removeItem(KEY);
		} catch (e) {}
	}

	function apply(theme) {
		if (theme)
			document.documentElement.setAttribute('data-theme', theme);
		else
			document.documentElement.removeAttribute('data-theme');
	}

	function getEffective(stored) {
		if (stored) return stored;
		return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
	}

	// Apply stored preference immediately (before paint)
	var stored = getStored();
	apply(stored);

	// Create toggle button once DOM is ready
	function createToggle() {
		var btn = document.createElement('button');
		btn.id = 'zen_theme_toggle';
		btn.title = 'Toggle theme';

		function updateIcon() {
			var effective = getEffective(getStored());
			// Show sun in dark mode (click to go light), moon in light mode (click to go dark)
			btn.textContent = effective === 'dark' ? '\u2600' : '\u263E';

			var isManual = getStored() != null;
			btn.title = isManual
				? 'Theme: ' + effective + ' (click to change, double-click for system)'
				: 'Theme: system (click to change)';
		}

		btn.addEventListener('click', function() {
			var current = getStored();
			var effective = getEffective(current);
			// Toggle to the opposite
			var next = effective === 'dark' ? 'light' : 'dark';
			setStored(next);
			apply(next);
			updateIcon();
		});

		btn.addEventListener('dblclick', function(e) {
			e.preventDefault();
			// Reset to system preference
			setStored(null);
			apply(null);
			updateIcon();
		});

		// Update icon when system preference changes
		window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function() {
			if (!getStored()) updateIcon();
		});

		updateIcon();
		document.body.appendChild(btn);

		// WebSocket pause/play toggle
		var WS_KEY = 'zen-ws-paused';
		var wsBtn = document.createElement('button');
		wsBtn.id = 'zen_ws_toggle';

		var initialPaused = false;
		try { initialPaused = localStorage.getItem(WS_KEY) === 'true'; } catch (e) {}

		function updateWsIcon(paused) {
			wsBtn.dataset.paused = paused ? 'true' : 'false';
			wsBtn.textContent = paused ? '\u25B6' : '\u23F8';
			wsBtn.title = paused ? 'Resume live updates' : 'Pause live updates';
		}

		updateWsIcon(initialPaused);

		// Fire initial event so pages pick up persisted state
		document.addEventListener('DOMContentLoaded', function() {
			if (initialPaused) {
				document.dispatchEvent(new CustomEvent('zen-ws-toggle', { detail: { paused: true } }));
			}
		});

		wsBtn.addEventListener('click', function() {
			var paused = wsBtn.dataset.paused !== 'true';
			try { localStorage.setItem(WS_KEY, paused ? 'true' : 'false'); } catch (e) {}
			updateWsIcon(paused);
			document.dispatchEvent(new CustomEvent('zen-ws-toggle', { detail: { paused: paused } }));
		});

		document.body.appendChild(wsBtn);
	}

	if (document.readyState === 'loading')
		document.addEventListener('DOMContentLoaded', createToggle);
	else
		createToggle();
})();