main
1;(function() {
2 var toggle = document.getElementById('theme-toggle')
3 if (!toggle) return
4
5 var STORAGE_KEY = 'flux-theme'
6
7 // Accent presets: one per color family
8 var ACCENT_PRESETS = [
9 { name: 'Forest', light: '#2d6a4f', dark: '#52b788' },
10 { name: 'Teal', light: '#006d5b', dark: '#40b89a' },
11 { name: 'Steel', light: '#2a6496', dark: '#7daacd' },
12 { name: 'Ochre', light: '#9a7b2a', dark: '#d4aa3c' },
13 { name: 'Terracotta', light: '#c05a30', dark: '#e08858' },
14 { name: 'Wine', light: '#8a3a3a', dark: '#c07070' },
15 { name: 'Iris', light: '#5b4a8a', dark: '#8a7ab8' },
16 ]
17
18 var DEFAULT_ACCENT = ACCENT_PRESETS[0]
19
20 // --- Helpers ---
21 function getPreferredTheme() {
22 var stored = localStorage.getItem(STORAGE_KEY)
23 if (stored) return stored
24 return window.matchMedia('(prefers-color-scheme: dark)').matches
25 ? 'dark' : 'light'
26 }
27
28 function hexToRgba(hex, alpha) {
29 hex = hex.replace('#', '')
30 if (hex.length === 3) hex = hex.split('').map(function(c) { return c + c }).join('')
31 var r = parseInt(hex.substring(0, 2), 16)
32 var g = parseInt(hex.substring(2, 4), 16)
33 var b = parseInt(hex.substring(4, 6), 16)
34 return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + alpha + ')'
35 }
36
37 // --- Theme ---
38 function applyTheme(theme) {
39 document.documentElement.setAttribute('data-theme', theme)
40 toggle.textContent = theme === 'dark' ? '☀️' : '🌙'
41 localStorage.setItem(STORAGE_KEY, theme)
42
43 // Update accent dot previews + accent picker swatches
44 updateDotColors(theme)
45 document.querySelectorAll('.accent-swatch').forEach(function(s) {
46 s.style.background = theme === 'dark' ? s.dataset.dark : s.dataset.light
47 })
48
49 // Re-apply accent
50 var l = localStorage.getItem('flux-accent-light')
51 var d = localStorage.getItem('flux-accent-dark')
52 if (l && d) applyAccent(l, d)
53 }
54
55 // --- Accent ---
56 function applyAccent(light, dark) {
57 var root = document.documentElement
58 var isDark = root.getAttribute('data-theme') === 'dark'
59 var color = isDark ? dark : light
60
61 root.style.setProperty('--color-accent', color)
62 root.style.setProperty('--color-accent-soft', hexToRgba(color, 0.08))
63 root.style.setProperty('--callout-design-color', color)
64 root.style.setProperty('--callout-design-bg', hexToRgba(color, 0.06))
65
66 localStorage.setItem('flux-accent-light', light)
67 localStorage.setItem('flux-accent-dark', dark)
68
69 // Update active states on dots
70 document.querySelectorAll('.accent-dot').forEach(function(d) {
71 d.classList.toggle('active', d.dataset.light === light)
72 })
73
74 // Update active states on picker swatches (if present)
75 document.querySelectorAll('.accent-swatch').forEach(function(s) {
76 s.classList.toggle('active', s.dataset.light === light)
77 })
78
79 // Update label (if present)
80 var label = document.getElementById('accent-label')
81 if (label) label.textContent = light + ' / ' + dark
82 }
83
84 function updateDotColors(theme) {
85 document.querySelectorAll('.accent-dot').forEach(function(d) {
86 d.style.backgroundColor = theme === 'dark' ? d.dataset.dark : d.dataset.light
87 })
88 }
89
90 // --- Build accent dots in the controls bar ---
91 function buildAccentDots() {
92 var container = toggle.parentElement
93 if (!container) return
94
95 // Add divider
96 var divider = document.createElement('span')
97 divider.className = 'accent-divider'
98 container.appendChild(divider)
99
100 // Add dots
101 var storedLight = localStorage.getItem('flux-accent-light')
102 var theme = getPreferredTheme()
103
104 ACCENT_PRESETS.forEach(function(preset) {
105 var dot = document.createElement('button')
106 dot.className = 'accent-dot'
107 dot.dataset.light = preset.light
108 dot.dataset.dark = preset.dark
109 dot.title = preset.name
110 dot.style.backgroundColor = theme === 'dark' ? preset.dark : preset.light
111
112 if (storedLight === preset.light || (!storedLight && preset === DEFAULT_ACCENT)) {
113 dot.classList.add('active')
114 }
115
116 dot.addEventListener('click', function() {
117 applyAccent(preset.light, preset.dark)
118 })
119
120 container.appendChild(dot)
121 })
122 }
123
124 // --- Init ---
125 applyTheme(getPreferredTheme())
126
127 var storedLight = localStorage.getItem('flux-accent-light')
128 var storedDark = localStorage.getItem('flux-accent-dark')
129 if (storedLight && storedDark) {
130 applyAccent(storedLight, storedDark)
131 } else {
132 applyAccent(DEFAULT_ACCENT.light, DEFAULT_ACCENT.dark)
133 }
134
135 buildAccentDots()
136
137 // --- Event listeners ---
138 toggle.addEventListener('click', function() {
139 var current = document.documentElement.getAttribute('data-theme')
140 applyTheme(current === 'dark' ? 'light' : 'dark')
141 })
142
143 // Accent picker swatches (on design sandbox page)
144 document.querySelectorAll('.accent-swatch').forEach(function(swatch) {
145 swatch.addEventListener('click', function() {
146 applyAccent(swatch.dataset.light, swatch.dataset.dark)
147 })
148 })
149
150 window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function(e) {
151 if (!localStorage.getItem(STORAGE_KEY)) {
152 applyTheme(e.matches ? 'dark' : 'light')
153 }
154 })
155
156 // Palette demo swatches (on design sandbox page)
157 document.querySelectorAll('.swatch[data-bg]').forEach(function(s) {
158 s.style.backgroundColor = s.dataset.bg
159 })
160})()