@kupola/kupola 1.9.11 → 1.9.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/js/theme.js CHANGED
@@ -1,372 +1,372 @@
1
- import { getIconsPath, getDefaultTheme, getDefaultBrand, setConfig, onConfigChange } from './kupola-config.js';
2
-
3
- const THEME_KEY = 'kupola-theme';
4
- const BRAND_KEY = 'kupola-brand';
5
- let _themeInitialized = false;
6
-
7
- onConfigChange((newConfig) => {
8
- const toggleBtn = document.querySelector('[data-theme-toggle]');
9
- if (toggleBtn) {
10
- const currentTheme = getTheme();
11
- updateThemeIcon(toggleBtn);
12
- setTheme(currentTheme);
13
- }
14
- });
15
-
16
- const BRAND_OPTIONS = [
17
- { id: 'green', name: '翠绿', color: '#32F08C' },
18
- { id: 'xionghuang', name: '雄黄', color: '#FF9900' },
19
- { id: 'jianghuang', name: '姜黄', color: '#E2C027' },
20
- { id: 'lanlv', name: '蓝绿', color: '#12A182' },
21
- { id: 'kongquelan', name: '孔雀蓝', color: '#0EB0C9' },
22
- { id: 'meiguizi', name: '玫瑰紫', color: '#BA2F7B' },
23
- { id: 'shihong', name: '柿红', color: '#F2481B' },
24
- { id: 'quhong', name: '紫云', color: '#B1A6CC' },
25
- { id: 'shanchahong', name: '山茶红', color: '#F05A46' },
26
- { id: 'zengqing', name: '曾青', color: '#535164' },
27
- { id: 'roulan', name: '柔蓝', color: '#106898' }
28
- ];
29
-
30
- function getTheme() {
31
- return localStorage.getItem(THEME_KEY) || getDefaultTheme();
32
- }
33
-
34
- function setTheme(theme) {
35
- if (theme !== 'dark' && theme !== 'light') return;
36
-
37
- var root = document.documentElement;
38
-
39
- if (root.hasAttribute('data-kupola-theme-preloaded')) {
40
- root.style.removeProperty('--bg-base-default');
41
- root.style.removeProperty('--text-default');
42
- root.removeAttribute('data-kupola-theme-preloaded');
43
- }
44
-
45
- root.setAttribute('data-theme', theme);
46
- localStorage.setItem(THEME_KEY, theme);
47
-
48
- const toggleBtn = document.querySelector('[data-theme-toggle]');
49
- if (toggleBtn) {
50
- toggleBtn.setAttribute('data-current-theme', theme);
51
- updateThemeIcon(toggleBtn);
52
- }
53
- }
54
-
55
- function getBrand() {
56
- return localStorage.getItem(BRAND_KEY) || getDefaultBrand();
57
- }
58
-
59
- function setBrand(brandId) {
60
- const brand = BRAND_OPTIONS.find(b => b.id === brandId);
61
- if (!brand) return;
62
-
63
- document.documentElement.setAttribute('data-brand', brandId);
64
- localStorage.setItem(BRAND_KEY, brandId);
65
-
66
- const brandToggle = document.querySelector('[data-brand-toggle]');
67
- if (brandToggle) {
68
- brandToggle.setAttribute('data-current-brand', brandId);
69
- const brandIcon = brandToggle.querySelector('.brand-icon');
70
- if (brandIcon) {
71
- brandIcon.style.backgroundColor = brand.color;
72
- }
73
- const brandName = brandToggle.querySelector('.brand-name');
74
- if (brandName) {
75
- brandName.textContent = brand.name;
76
- }
77
- }
78
-
79
- const brandButtons = document.querySelectorAll('[data-brand-btn]');
80
- brandButtons.forEach(btn => {
81
- if (btn.getAttribute('data-brand-btn') === brandId) {
82
- btn.classList.add('is-active');
83
- } else {
84
- btn.classList.remove('is-active');
85
- }
86
- });
87
- }
88
-
89
- function updateThemeIcon(toggleBtn) {
90
- const iconEl = toggleBtn.querySelector('.theme-icon');
91
- if (iconEl) {
92
- const currentTheme = getTheme();
93
- const iconsPath = getIconsPath();
94
- iconEl.src = currentTheme === 'dark'
95
- ? iconsPath + 'sun.svg'
96
- : iconsPath + 'moon.svg';
97
- }
98
- }
99
-
100
- function _themeToggleHandler(e) {
101
- e.preventDefault();
102
- const currentTheme = getTheme();
103
- const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
104
- setTheme(newTheme);
105
- }
106
-
107
- function initTheme() {
108
-
109
- var root = document.documentElement;
110
-
111
- if (root.hasAttribute('data-kupola-theme-preloaded')) {
112
- root.style.removeProperty('--bg-base-default');
113
- root.style.removeProperty('--text-default');
114
- root.removeAttribute('data-kupola-theme-preloaded');
115
- }
116
-
117
- const toggleBtn = document.querySelector('[data-theme-toggle]');
118
-
119
- if (!_themeInitialized) {
120
- _themeInitialized = true;
121
- }
122
-
123
- const savedTheme = getTheme();
124
- setTheme(savedTheme);
125
-
126
- const savedBrand = getBrand();
127
- setBrand(savedBrand);
128
-
129
- document.body.classList.add('theme-initialized');
130
-
131
- setTimeout(() => {
132
- document.body.classList.add('theme-initialized');
133
- }, 1500);
134
-
135
- if (toggleBtn) {
136
- updateThemeIcon(toggleBtn);
137
-
138
- toggleBtn.removeEventListener('click', _themeToggleHandler);
139
- toggleBtn.addEventListener('click', _themeToggleHandler);
140
- }
141
-
142
- let brandPicker = document.getElementById('brand-picker');
143
- if (!brandPicker) {
144
- brandPicker = document.createElement('div');
145
- brandPicker.id = 'brand-picker';
146
- brandPicker.style.position = 'fixed';
147
- brandPicker.style.top = '64px';
148
- brandPicker.style.right = '16px';
149
- brandPicker.style.zIndex = '9998';
150
- brandPicker.style.display = 'none';
151
- brandPicker.style.padding = '12px';
152
- brandPicker.style.width = '200px';
153
- brandPicker.style.gridTemplateColumns = 'repeat(3, 1fr)';
154
- brandPicker.style.gap = '6px';
155
- brandPicker.style.backgroundColor = 'var(--bg-base-secondary)';
156
- brandPicker.style.border = '1px solid var(--border-neutral-l1)';
157
- brandPicker.style.borderRadius = '8px';
158
- brandPicker.style.boxShadow = '0 4px 20px rgba(0, 0, 0, 0.2)';
159
- brandPicker.style.overflow = 'hidden';
160
-
161
- BRAND_OPTIONS.forEach(brand => {
162
- const btn = document.createElement('button');
163
- btn.setAttribute('data-brand-btn', brand.id);
164
- btn.style.display = 'flex';
165
- btn.style.justifyContent = 'center';
166
- btn.style.alignItems = 'center';
167
- btn.style.height = '60px';
168
- btn.style.backgroundColor = brand.color;
169
- btn.style.color = ['#32F08C', '#FF9900', '#E2C027', '#0EB0C9', '#B1A6CC'].includes(brand.color) ? '#0C0C0D' : '#FFFFFF';
170
- btn.style.fontWeight = '500';
171
- btn.style.borderRadius = '4px';
172
- btn.style.border = 'none';
173
- btn.style.cursor = 'pointer';
174
- btn.style.margin = '0';
175
- btn.style.padding = '0';
176
- btn.textContent = brand.name;
177
- brandPicker.appendChild(btn);
178
- });
179
-
180
- document.body.appendChild(brandPicker);
181
- }
182
-
183
- const brandToggle = document.querySelector('[data-brand-toggle]');
184
-
185
- if (brandToggle && brandPicker) {
186
- brandToggle.onclick = function(e) {
187
- e.stopPropagation();
188
- e.preventDefault();
189
- const isHidden = brandPicker.style.display === 'none';
190
- brandPicker.style.display = isHidden ? 'grid' : 'none';
191
-
192
- if (isHidden) {
193
- setTimeout(() => {
194
- document.addEventListener('click', closeBrandPicker, true);
195
- }, 0);
196
- } else {
197
- document.removeEventListener('click', closeBrandPicker, true);
198
- }
199
- };
200
-
201
- brandPicker.onclick = function(e) {
202
- e.stopPropagation();
203
- };
204
- }
205
-
206
- function closeBrandPicker(e) {
207
- if (brandPicker && brandToggle) {
208
- if (!brandPicker.contains(e.target) && !brandToggle.contains(e.target)) {
209
- brandPicker.style.display = 'none';
210
- document.removeEventListener('click', closeBrandPicker, true);
211
- }
212
- }
213
- }
214
-
215
- const brandButtons = document.querySelectorAll('[data-brand-btn]');
216
-
217
- brandButtons.forEach(btn => {
218
- btn.addEventListener('click', (e) => {
219
- e.stopPropagation();
220
- const brandId = btn.getAttribute('data-brand-btn');
221
- setBrand(brandId);
222
- if (brandPicker) {
223
- brandPicker.style.display = 'none';
224
- }
225
- });
226
- });
227
- }
228
-
229
- function createThemeToggle() {
230
- const btn = document.createElement('button');
231
- btn.setAttribute('data-theme-toggle', '');
232
- btn.setAttribute('data-current-theme', getTheme());
233
- btn.className = 'ds-btn ds-btn--ghost ds-btn--sm ds-btn--icon';
234
- btn.style.position = 'fixed';
235
- btn.style.top = '16px';
236
- btn.style.right = '16px';
237
- btn.style.zIndex = '9999';
238
-
239
- const icon = document.createElement('img');
240
- icon.className = 'theme-icon';
241
- const iconsPath = getIconsPath();
242
- icon.src = getTheme() === 'dark'
243
- ? iconsPath + 'sun.svg'
244
- : iconsPath + 'moon.svg';
245
- icon.width = 14;
246
- icon.height = 14;
247
- icon.alt = 'Toggle theme';
248
-
249
- btn.appendChild(icon);
250
- document.body.appendChild(btn);
251
-
252
- btn.onclick = function(e) {
253
- e.preventDefault();
254
- const currentTheme = getTheme();
255
- const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
256
- setTheme(newTheme);
257
- };
258
-
259
- return btn;
260
- }
261
-
262
- function createBrandPicker() {
263
- const container = document.createElement('div');
264
- container.id = 'brand-picker-auto';
265
- container.style.position = 'fixed';
266
- container.style.top = '56px';
267
- container.style.right = '16px';
268
- container.style.zIndex = '9998';
269
- container.style.display = 'none';
270
- container.style.padding = '12px';
271
- container.style.width = '200px';
272
- container.style.gridTemplateColumns = 'repeat(3, 1fr)';
273
- container.style.gap = '6px';
274
- container.style.backgroundColor = 'var(--bg-base-secondary)';
275
- container.style.border = '1px solid var(--border-neutral-l1)';
276
- container.style.borderRadius = '8px';
277
- container.style.boxShadow = '0 4px 20px rgba(0, 0, 0, 0.2)';
278
- container.style.overflow = 'hidden';
279
-
280
- BRAND_OPTIONS.forEach(brand => {
281
- const btn = document.createElement('button');
282
- btn.setAttribute('data-brand-btn', brand.id);
283
- btn.style.display = 'flex';
284
- btn.style.justifyContent = 'center';
285
- btn.style.alignItems = 'center';
286
- btn.style.height = '60px';
287
- btn.style.backgroundColor = brand.color;
288
- btn.style.color = ['#32F08C', '#FF9900', '#E2C027', '#0EB0C9', '#B1A6CC'].includes(brand.color) ? '#0C0C0D' : '#FFFFFF';
289
- btn.style.fontWeight = '500';
290
- btn.style.borderRadius = '4px';
291
- btn.style.border = 'none';
292
- btn.style.cursor = 'pointer';
293
- btn.style.margin = '0';
294
- btn.style.padding = '0';
295
- btn.textContent = brand.name;
296
- container.appendChild(btn);
297
- });
298
-
299
- document.body.appendChild(container);
300
-
301
- const toggleBtn = document.createElement('button');
302
- toggleBtn.setAttribute('data-brand-toggle', '');
303
- toggleBtn.setAttribute('data-current-brand', getBrand());
304
- toggleBtn.className = 'ds-btn ds-btn--ghost ds-btn--sm';
305
- toggleBtn.style.position = 'fixed';
306
- toggleBtn.style.top = '16px';
307
- toggleBtn.style.right = '56px';
308
- toggleBtn.style.zIndex = '9999';
309
- toggleBtn.style.display = 'flex';
310
- toggleBtn.style.alignItems = 'center';
311
- toggleBtn.style.gap = '6px';
312
-
313
- const brandIcon = document.createElement('span');
314
- brandIcon.className = 'brand-icon';
315
- brandIcon.style.width = '12px';
316
- brandIcon.style.height = '12px';
317
- brandIcon.style.borderRadius = '50%';
318
- brandIcon.style.backgroundColor = BRAND_OPTIONS.find(b => b.id === getBrand()).color;
319
-
320
- const brandName = document.createElement('span');
321
- brandName.className = 'brand-name';
322
- brandName.style.fontSize = '11px';
323
- brandName.textContent = BRAND_OPTIONS.find(b => b.id === getBrand()).name;
324
-
325
- toggleBtn.appendChild(brandIcon);
326
- toggleBtn.appendChild(brandName);
327
- document.body.appendChild(toggleBtn);
328
-
329
- toggleBtn.onclick = function(e) {
330
- e.stopPropagation();
331
- e.preventDefault();
332
- const isHidden = container.style.display === 'none';
333
- container.style.display = isHidden ? 'grid' : 'none';
334
-
335
- if (isHidden) {
336
- setTimeout(() => {
337
- document.addEventListener('click', closeBrandPickerAuto, true);
338
- }, 0);
339
- } else {
340
- document.removeEventListener('click', closeBrandPickerAuto, true);
341
- }
342
- };
343
-
344
- container.onclick = function(e) {
345
- e.stopPropagation();
346
- };
347
-
348
- function closeBrandPickerAuto(e) {
349
- if (!container.contains(e.target) && !toggleBtn.contains(e.target)) {
350
- container.style.display = 'none';
351
- document.removeEventListener('click', closeBrandPickerAuto, true);
352
- }
353
- }
354
-
355
- const brandButtons = container.querySelectorAll('[data-brand-btn]');
356
- brandButtons.forEach(btn => {
357
- btn.addEventListener('click', (e) => {
358
- e.stopPropagation();
359
- const brandId = btn.getAttribute('data-brand-btn');
360
- setBrand(brandId);
361
- container.style.display = 'none';
362
- });
363
- });
364
-
365
- return { toggleBtn, container };
366
- }
367
-
368
- export {
369
- getTheme, setTheme, initTheme, createThemeToggle,
370
- getBrand, setBrand, BRAND_OPTIONS, createBrandPicker,
371
- THEME_KEY, BRAND_KEY
1
+ import { getIconsPath, getDefaultTheme, getDefaultBrand, setConfig, onConfigChange } from './kupola-config.js';
2
+
3
+ const THEME_KEY = 'kupola-theme';
4
+ const BRAND_KEY = 'kupola-brand';
5
+ let _themeInitialized = false;
6
+
7
+ onConfigChange((newConfig) => {
8
+ const toggleBtn = document.querySelector('[data-theme-toggle]');
9
+ if (toggleBtn) {
10
+ const currentTheme = getTheme();
11
+ updateThemeIcon(toggleBtn);
12
+ setTheme(currentTheme);
13
+ }
14
+ });
15
+
16
+ const BRAND_OPTIONS = [
17
+ { id: 'green', name: '翠绿', color: '#32F08C' },
18
+ { id: 'xionghuang', name: '雄黄', color: '#FF9900' },
19
+ { id: 'jianghuang', name: '姜黄', color: '#E2C027' },
20
+ { id: 'lanlv', name: '蓝绿', color: '#12A182' },
21
+ { id: 'kongquelan', name: '孔雀蓝', color: '#0EB0C9' },
22
+ { id: 'meiguizi', name: '玫瑰紫', color: '#BA2F7B' },
23
+ { id: 'shihong', name: '柿红', color: '#F2481B' },
24
+ { id: 'quhong', name: '紫云', color: '#B1A6CC' },
25
+ { id: 'shanchahong', name: '山茶红', color: '#F05A46' },
26
+ { id: 'zengqing', name: '曾青', color: '#535164' },
27
+ { id: 'roulan', name: '柔蓝', color: '#106898' }
28
+ ];
29
+
30
+ function getTheme() {
31
+ return localStorage.getItem(THEME_KEY) || getDefaultTheme();
32
+ }
33
+
34
+ function setTheme(theme) {
35
+ if (theme !== 'dark' && theme !== 'light') return;
36
+
37
+ const root = document.documentElement;
38
+
39
+ if (root.hasAttribute('data-kupola-theme-preloaded')) {
40
+ root.style.removeProperty('--bg-base-default');
41
+ root.style.removeProperty('--text-default');
42
+ root.removeAttribute('data-kupola-theme-preloaded');
43
+ }
44
+
45
+ root.setAttribute('data-theme', theme);
46
+ localStorage.setItem(THEME_KEY, theme);
47
+
48
+ const toggleBtn = document.querySelector('[data-theme-toggle]');
49
+ if (toggleBtn) {
50
+ toggleBtn.setAttribute('data-current-theme', theme);
51
+ updateThemeIcon(toggleBtn);
52
+ }
53
+ }
54
+
55
+ function getBrand() {
56
+ return localStorage.getItem(BRAND_KEY) || getDefaultBrand();
57
+ }
58
+
59
+ function setBrand(brandId) {
60
+ const brand = BRAND_OPTIONS.find(b => b.id === brandId);
61
+ if (!brand) return;
62
+
63
+ document.documentElement.setAttribute('data-brand', brandId);
64
+ localStorage.setItem(BRAND_KEY, brandId);
65
+
66
+ const brandToggle = document.querySelector('[data-brand-toggle]');
67
+ if (brandToggle) {
68
+ brandToggle.setAttribute('data-current-brand', brandId);
69
+ const brandIcon = brandToggle.querySelector('.brand-icon');
70
+ if (brandIcon) {
71
+ brandIcon.style.backgroundColor = brand.color;
72
+ }
73
+ const brandName = brandToggle.querySelector('.brand-name');
74
+ if (brandName) {
75
+ brandName.textContent = brand.name;
76
+ }
77
+ }
78
+
79
+ const brandButtons = document.querySelectorAll('[data-brand-btn]');
80
+ brandButtons.forEach(btn => {
81
+ if (btn.getAttribute('data-brand-btn') === brandId) {
82
+ btn.classList.add('is-active');
83
+ } else {
84
+ btn.classList.remove('is-active');
85
+ }
86
+ });
87
+ }
88
+
89
+ function updateThemeIcon(toggleBtn) {
90
+ const iconEl = toggleBtn.querySelector('.theme-icon');
91
+ if (iconEl) {
92
+ const currentTheme = getTheme();
93
+ const iconsPath = getIconsPath();
94
+ iconEl.src = currentTheme === 'dark'
95
+ ? iconsPath + 'sun.svg'
96
+ : iconsPath + 'moon.svg';
97
+ }
98
+ }
99
+
100
+ function _themeToggleHandler(e) {
101
+ e.preventDefault();
102
+ const currentTheme = getTheme();
103
+ const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
104
+ setTheme(newTheme);
105
+ }
106
+
107
+ function _createBrandPicker() {
108
+ let brandPicker = document.getElementById('brand-picker');
109
+ if (brandPicker) return brandPicker;
110
+
111
+ brandPicker = document.createElement('div');
112
+ brandPicker.id = 'brand-picker';
113
+ brandPicker.style.position = 'fixed';
114
+ brandPicker.style.top = '64px';
115
+ brandPicker.style.right = '16px';
116
+ brandPicker.style.zIndex = '9998';
117
+ brandPicker.style.display = 'none';
118
+ brandPicker.style.padding = '12px';
119
+ brandPicker.style.width = '200px';
120
+ brandPicker.style.gridTemplateColumns = 'repeat(3, 1fr)';
121
+ brandPicker.style.gap = '6px';
122
+ brandPicker.style.backgroundColor = 'var(--bg-base-secondary)';
123
+ brandPicker.style.border = '1px solid var(--border-neutral-l1)';
124
+ brandPicker.style.borderRadius = '8px';
125
+ brandPicker.style.boxShadow = '0 4px 20px rgba(0, 0, 0, 0.2)';
126
+ brandPicker.style.overflow = 'hidden';
127
+
128
+ BRAND_OPTIONS.forEach(brand => {
129
+ const btn = document.createElement('button');
130
+ btn.setAttribute('data-brand-btn', brand.id);
131
+ btn.style.display = 'flex';
132
+ btn.style.justifyContent = 'center';
133
+ btn.style.alignItems = 'center';
134
+ btn.style.height = '60px';
135
+ btn.style.backgroundColor = brand.color;
136
+ btn.style.color = ['#32F08C', '#FF9900', '#E2C027', '#0EB0C9', '#B1A6CC'].includes(brand.color) ? '#0C0C0D' : '#FFFFFF';
137
+ btn.style.fontWeight = '500';
138
+ btn.style.borderRadius = '4px';
139
+ btn.style.border = 'none';
140
+ btn.style.cursor = 'pointer';
141
+ btn.style.margin = '0';
142
+ btn.style.padding = '0';
143
+ btn.textContent = brand.name;
144
+ brandPicker.appendChild(btn);
145
+ });
146
+
147
+ document.body.appendChild(brandPicker);
148
+ return brandPicker;
149
+ }
150
+
151
+ function _bindBrandPicker(brandPicker) {
152
+ const brandToggle = document.querySelector('[data-brand-toggle]');
153
+ if (!brandToggle || !brandPicker) return;
154
+
155
+ brandToggle.onclick = function(e) {
156
+ e.stopPropagation();
157
+ e.preventDefault();
158
+ const isHidden = brandPicker.style.display === 'none';
159
+ brandPicker.style.display = isHidden ? 'grid' : 'none';
160
+
161
+ if (isHidden) {
162
+ setTimeout(() => {
163
+ document.addEventListener('click', closeBrandPicker, true);
164
+ }, 0);
165
+ } else {
166
+ document.removeEventListener('click', closeBrandPicker, true);
167
+ }
168
+ };
169
+
170
+ brandPicker.onclick = function(e) {
171
+ e.stopPropagation();
172
+ };
173
+
174
+ function closeBrandPicker(e) {
175
+ if (!brandPicker.contains(e.target) && !brandToggle.contains(e.target)) {
176
+ brandPicker.style.display = 'none';
177
+ document.removeEventListener('click', closeBrandPicker, true);
178
+ }
179
+ }
180
+
181
+ const brandButtons = brandPicker.querySelectorAll('[data-brand-btn]');
182
+ brandButtons.forEach(btn => {
183
+ btn.onclick = function(e) {
184
+ e.stopPropagation();
185
+ const brandId = btn.getAttribute('data-brand-btn');
186
+ setBrand(brandId);
187
+ brandPicker.style.display = 'none';
188
+ };
189
+ });
190
+ }
191
+
192
+ function initTheme() {
193
+
194
+ const root = document.documentElement;
195
+
196
+ if (root.hasAttribute('data-kupola-theme-preloaded')) {
197
+ root.style.removeProperty('--bg-base-default');
198
+ root.style.removeProperty('--text-default');
199
+ root.removeAttribute('data-kupola-theme-preloaded');
200
+ }
201
+
202
+ const toggleBtn = document.querySelector('[data-theme-toggle]');
203
+
204
+ if (!_themeInitialized) {
205
+ _themeInitialized = true;
206
+ }
207
+
208
+ const savedTheme = getTheme();
209
+ setTheme(savedTheme);
210
+
211
+ const savedBrand = getBrand();
212
+ setBrand(savedBrand);
213
+
214
+ document.body.classList.add('theme-initialized');
215
+
216
+ if (toggleBtn) {
217
+ updateThemeIcon(toggleBtn);
218
+
219
+ toggleBtn.onclick = _themeToggleHandler;
220
+ }
221
+
222
+ const brandToggle = document.querySelector('[data-brand-toggle]');
223
+ if (brandToggle) {
224
+ const brandPicker = _createBrandPicker();
225
+ _bindBrandPicker(brandPicker);
226
+ }
227
+ }
228
+
229
+ function createThemeToggle() {
230
+ const btn = document.createElement('button');
231
+ btn.setAttribute('data-theme-toggle', '');
232
+ btn.setAttribute('data-current-theme', getTheme());
233
+ btn.className = 'ds-btn ds-btn--ghost ds-btn--sm ds-btn--icon';
234
+ btn.style.position = 'fixed';
235
+ btn.style.top = '16px';
236
+ btn.style.right = '16px';
237
+ btn.style.zIndex = '9999';
238
+
239
+ const icon = document.createElement('img');
240
+ icon.className = 'theme-icon';
241
+ const iconsPath = getIconsPath();
242
+ icon.src = getTheme() === 'dark'
243
+ ? iconsPath + 'sun.svg'
244
+ : iconsPath + 'moon.svg';
245
+ icon.width = 14;
246
+ icon.height = 14;
247
+ icon.alt = 'Toggle theme';
248
+
249
+ btn.appendChild(icon);
250
+ document.body.appendChild(btn);
251
+
252
+ btn.onclick = function(e) {
253
+ e.preventDefault();
254
+ const currentTheme = getTheme();
255
+ const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
256
+ setTheme(newTheme);
257
+ };
258
+
259
+ return btn;
260
+ }
261
+
262
+ function createBrandPicker() {
263
+ const container = document.createElement('div');
264
+ container.id = 'brand-picker-auto';
265
+ container.style.position = 'fixed';
266
+ container.style.top = '56px';
267
+ container.style.right = '16px';
268
+ container.style.zIndex = '9998';
269
+ container.style.display = 'none';
270
+ container.style.padding = '12px';
271
+ container.style.width = '200px';
272
+ container.style.gridTemplateColumns = 'repeat(3, 1fr)';
273
+ container.style.gap = '6px';
274
+ container.style.backgroundColor = 'var(--bg-base-secondary)';
275
+ container.style.border = '1px solid var(--border-neutral-l1)';
276
+ container.style.borderRadius = '8px';
277
+ container.style.boxShadow = '0 4px 20px rgba(0, 0, 0, 0.2)';
278
+ container.style.overflow = 'hidden';
279
+
280
+ BRAND_OPTIONS.forEach(brand => {
281
+ const btn = document.createElement('button');
282
+ btn.setAttribute('data-brand-btn', brand.id);
283
+ btn.style.display = 'flex';
284
+ btn.style.justifyContent = 'center';
285
+ btn.style.alignItems = 'center';
286
+ btn.style.height = '60px';
287
+ btn.style.backgroundColor = brand.color;
288
+ btn.style.color = ['#32F08C', '#FF9900', '#E2C027', '#0EB0C9', '#B1A6CC'].includes(brand.color) ? '#0C0C0D' : '#FFFFFF';
289
+ btn.style.fontWeight = '500';
290
+ btn.style.borderRadius = '4px';
291
+ btn.style.border = 'none';
292
+ btn.style.cursor = 'pointer';
293
+ btn.style.margin = '0';
294
+ btn.style.padding = '0';
295
+ btn.textContent = brand.name;
296
+ container.appendChild(btn);
297
+ });
298
+
299
+ document.body.appendChild(container);
300
+
301
+ const toggleBtn = document.createElement('button');
302
+ toggleBtn.setAttribute('data-brand-toggle', '');
303
+ toggleBtn.setAttribute('data-current-brand', getBrand());
304
+ toggleBtn.className = 'ds-btn ds-btn--ghost ds-btn--sm';
305
+ toggleBtn.style.position = 'fixed';
306
+ toggleBtn.style.top = '16px';
307
+ toggleBtn.style.right = '56px';
308
+ toggleBtn.style.zIndex = '9999';
309
+ toggleBtn.style.display = 'flex';
310
+ toggleBtn.style.alignItems = 'center';
311
+ toggleBtn.style.gap = '6px';
312
+
313
+ const brandIcon = document.createElement('span');
314
+ brandIcon.className = 'brand-icon';
315
+ brandIcon.style.width = '12px';
316
+ brandIcon.style.height = '12px';
317
+ brandIcon.style.borderRadius = '50%';
318
+ brandIcon.style.backgroundColor = BRAND_OPTIONS.find(b => b.id === getBrand()).color;
319
+
320
+ const brandName = document.createElement('span');
321
+ brandName.className = 'brand-name';
322
+ brandName.style.fontSize = '11px';
323
+ brandName.textContent = BRAND_OPTIONS.find(b => b.id === getBrand()).name;
324
+
325
+ toggleBtn.appendChild(brandIcon);
326
+ toggleBtn.appendChild(brandName);
327
+ document.body.appendChild(toggleBtn);
328
+
329
+ toggleBtn.onclick = function(e) {
330
+ e.stopPropagation();
331
+ e.preventDefault();
332
+ const isHidden = container.style.display === 'none';
333
+ container.style.display = isHidden ? 'grid' : 'none';
334
+
335
+ if (isHidden) {
336
+ setTimeout(() => {
337
+ document.addEventListener('click', closeBrandPickerAuto, true);
338
+ }, 0);
339
+ } else {
340
+ document.removeEventListener('click', closeBrandPickerAuto, true);
341
+ }
342
+ };
343
+
344
+ container.onclick = function(e) {
345
+ e.stopPropagation();
346
+ };
347
+
348
+ function closeBrandPickerAuto(e) {
349
+ if (!container.contains(e.target) && !toggleBtn.contains(e.target)) {
350
+ container.style.display = 'none';
351
+ document.removeEventListener('click', closeBrandPickerAuto, true);
352
+ }
353
+ }
354
+
355
+ const brandButtons = container.querySelectorAll('[data-brand-btn]');
356
+ brandButtons.forEach(btn => {
357
+ btn.onclick = function(e) {
358
+ e.stopPropagation();
359
+ const brandId = btn.getAttribute('data-brand-btn');
360
+ setBrand(brandId);
361
+ container.style.display = 'none';
362
+ };
363
+ });
364
+
365
+ return { toggleBtn, container };
366
+ }
367
+
368
+ export {
369
+ getTheme, setTheme, initTheme, createThemeToggle,
370
+ getBrand, setBrand, BRAND_OPTIONS, createBrandPicker,
371
+ THEME_KEY, BRAND_KEY
372
372
  };