@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.
@@ -1,104 +1,161 @@
1
- /**
2
- * Kupola Theme Standalone — lightweight theme toggle (~1KB).
3
- *
4
- * Usage: Include this single script in your page. No other Kupola JS required.
5
- * <script src="theme-standalone.js"></script>
6
- *
7
- * Features:
8
- * - Reads/writes theme preference from localStorage
9
- * - Sets data-theme attribute on <html>
10
- * - Auto-binds [data-theme-toggle] buttons
11
- * - Supports prefers-color-scheme as default
12
- * - Optional: auto-detects brand preference
13
- */
14
- (function () {
15
- 'use strict';
16
-
17
- var THEME_KEY = 'kupola-theme';
18
- var BRAND_KEY = 'kupola-brand';
19
-
20
- function getPreferred() {
21
- var saved = localStorage.getItem(THEME_KEY);
22
- if (saved === 'dark' || saved === 'light') {
23
- return saved;
24
- }
25
- if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) {
26
- return 'light';
27
- }
28
- return 'dark';
29
- }
30
-
31
- function applyTheme(theme) {
32
- var root = document.documentElement;
33
-
34
- if (root.hasAttribute('data-kupola-theme-preloaded')) {
35
- root.style.removeProperty('--bg-base-default');
36
- root.style.removeProperty('--text-default');
37
- root.removeAttribute('data-kupola-theme-preloaded');
38
- }
39
-
40
- root.setAttribute('data-theme', theme);
41
- localStorage.setItem(THEME_KEY, theme);
42
- }
43
-
44
- function applyBrand(brand) {
45
- if (brand) {
46
- document.documentElement.setAttribute('data-brand', brand);
47
- localStorage.setItem(BRAND_KEY, brand);
48
- }
49
- }
50
-
51
- function toggleTheme() {
52
- var current = document.documentElement.getAttribute('data-theme') || getPreferred();
53
- var next = current === 'dark' ? 'light' : 'dark';
54
- applyTheme(next);
55
- }
56
-
57
- function bindToggleButtons() {
58
- var buttons = document.querySelectorAll('[data-theme-toggle]');
59
- buttons.forEach(function (btn) {
60
- btn.addEventListener('click', function (e) {
61
- e.preventDefault();
62
- toggleTheme();
63
- });
64
- });
65
- }
66
-
67
- // Initialize immediately (works even before DOMContentLoaded)
68
- applyTheme(getPreferred());
69
- applyBrand(localStorage.getItem(BRAND_KEY));
70
-
71
- document.body.classList.add('theme-initialized');
72
-
73
- setTimeout(function() {
74
- document.body.classList.add('theme-initialized');
75
- }, 1500);
76
-
77
- // Bind toggle buttons when DOM is ready
78
- if (document.readyState === 'loading') {
79
- document.addEventListener('DOMContentLoaded', bindToggleButtons);
80
- } else {
81
- bindToggleButtons();
82
- }
83
-
84
- // Listen for system theme changes
85
- if (window.matchMedia) {
86
- var mq = window.matchMedia('(prefers-color-scheme: dark)');
87
- if (mq.addEventListener) {
88
- mq.addEventListener('change', function (e) {
89
- if (!localStorage.getItem(THEME_KEY)) {
90
- applyTheme(e.matches ? 'dark' : 'light');
91
- }
92
- });
93
- }
94
- }
95
-
96
- // Expose minimal API
97
- window.KupolaTheme = {
98
- toggle: toggleTheme,
99
- set: applyTheme,
100
- get: function () {
101
- return document.documentElement.getAttribute('data-theme') || 'dark';
102
- },
103
- };
104
- })();
1
+ (function () {
2
+ 'use strict';
3
+
4
+ const THEME_KEY = 'kupola-theme';
5
+ const BRAND_KEY = 'kupola-brand';
6
+
7
+ const BRAND_OPTIONS = [
8
+ { id: 'green', name: '翠绿', color: '#32F08C' },
9
+ { id: 'xionghuang', name: '雄黄', color: '#FF9900' },
10
+ { id: 'jianghuang', name: '姜黄', color: '#E2C027' },
11
+ { id: 'lanlv', name: '蓝绿', color: '#12A182' },
12
+ { id: 'kongquelan', name: '孔雀蓝', color: '#0EB0C9' },
13
+ { id: 'meiguizi', name: '玫瑰紫', color: '#BA2F7B' },
14
+ { id: 'shihong', name: '柿红', color: '#F2481B' },
15
+ { id: 'quhong', name: '紫云', color: '#B1A6CC' },
16
+ { id: 'shanchahong', name: '山茶红', color: '#F05A46' },
17
+ { id: 'zengqing', name: '曾青', color: '#535164' },
18
+ { id: 'roulan', name: '柔蓝', color: '#106898' }
19
+ ];
20
+
21
+ const KUPOLA_CONFIG = window.KupolaConfig || {
22
+ theme: { default: 'dark', brand: 'zengqing' },
23
+ paths: { icons: '/icons/', base: '/' }
24
+ };
25
+
26
+ function getPreferredTheme() {
27
+ const saved = localStorage.getItem(THEME_KEY);
28
+ if (saved === 'dark' || saved === 'light') {
29
+ return saved;
30
+ }
31
+ if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) {
32
+ return 'light';
33
+ }
34
+ return KUPOLA_CONFIG.theme.default;
35
+ }
36
+
37
+ function getPreferredBrand() {
38
+ const saved = localStorage.getItem(BRAND_KEY);
39
+ if (saved) return saved;
40
+ return KUPOLA_CONFIG.theme.brand;
41
+ }
42
+
43
+ function applyTheme(theme) {
44
+ const root = document.documentElement;
45
+
46
+ if (root.hasAttribute('data-kupola-theme-preloaded')) {
47
+ root.style.removeProperty('--bg-base-default');
48
+ root.style.removeProperty('--text-default');
49
+ root.removeAttribute('data-kupola-theme-preloaded');
50
+ }
51
+
52
+ root.setAttribute('data-theme', theme);
53
+ localStorage.setItem(THEME_KEY, theme);
54
+
55
+ updateThemeIcons();
56
+ }
57
+
58
+ function applyBrand(brand) {
59
+ if (brand) {
60
+ document.documentElement.setAttribute('data-brand', brand);
61
+ localStorage.setItem(BRAND_KEY, brand);
62
+ updateBrandIcons();
63
+ }
64
+ }
65
+
66
+ function updateThemeIcons() {
67
+ const iconsPath = KUPOLA_CONFIG.paths.base + KUPOLA_CONFIG.paths.icons.replace(/^\//, '');
68
+ const currentTheme = document.documentElement.getAttribute('data-theme') || getPreferredTheme();
69
+
70
+ document.querySelectorAll('[data-theme-toggle]').forEach(toggleBtn => {
71
+ const iconEl = toggleBtn.querySelector('.theme-icon');
72
+ if (iconEl) {
73
+ iconEl.src = currentTheme === 'dark' ? iconsPath + 'sun.svg' : iconsPath + 'moon.svg';
74
+ }
75
+ });
76
+ }
77
+
78
+ function updateBrandIcons() {
79
+ const currentBrand = document.documentElement.getAttribute('data-brand') || getPreferredBrand();
80
+
81
+ document.querySelectorAll('[data-brand-toggle]').forEach(brandToggle => {
82
+ const brandIcon = brandToggle.querySelector('.brand-icon');
83
+ if (brandIcon) {
84
+ const brand = BRAND_OPTIONS.find(b => b.id === currentBrand);
85
+ if (brand) {
86
+ brandIcon.style.backgroundColor = brand.color;
87
+ }
88
+ }
89
+ const brandName = brandToggle.querySelector('.brand-name');
90
+ if (brandName) {
91
+ const brand = BRAND_OPTIONS.find(b => b.id === currentBrand);
92
+ if (brand) {
93
+ brandName.textContent = brand.name;
94
+ }
95
+ }
96
+ });
97
+ }
98
+
99
+ function toggleTheme() {
100
+ const current = document.documentElement.getAttribute('data-theme') || getPreferredTheme();
101
+ const next = current === 'dark' ? 'light' : 'dark';
102
+ applyTheme(next);
103
+ }
104
+
105
+ function bindToggleButtons() {
106
+ document.querySelectorAll('[data-theme-toggle]').forEach(btn => {
107
+ btn.onclick = function (e) {
108
+ e.preventDefault();
109
+ toggleTheme();
110
+ };
111
+ });
112
+
113
+ document.querySelectorAll('[data-brand-btn]').forEach(btn => {
114
+ btn.onclick = function(e) {
115
+ e.stopPropagation();
116
+ const brandId = btn.getAttribute('data-brand-btn');
117
+ applyBrand(brandId);
118
+
119
+ const brandPicker = document.getElementById('brand-picker') ||
120
+ document.getElementById('brand-picker-auto');
121
+ if (brandPicker) {
122
+ brandPicker.style.display = 'none';
123
+ }
124
+ };
125
+ });
126
+ }
127
+
128
+ applyTheme(getPreferredTheme());
129
+ applyBrand(getPreferredBrand());
130
+
131
+ document.body.classList.add('theme-initialized');
132
+
133
+ if (document.readyState === 'loading') {
134
+ document.addEventListener('DOMContentLoaded', bindToggleButtons);
135
+ } else {
136
+ bindToggleButtons();
137
+ }
138
+
139
+ if (window.matchMedia) {
140
+ const mq = window.matchMedia('(prefers-color-scheme: dark)');
141
+ if (mq.addEventListener) {
142
+ mq.addEventListener('change', function (e) {
143
+ if (!localStorage.getItem(THEME_KEY)) {
144
+ applyTheme(e.matches ? 'dark' : 'light');
145
+ }
146
+ });
147
+ }
148
+ }
149
+
150
+ window.KupolaTheme = {
151
+ toggle: toggleTheme,
152
+ set: applyTheme,
153
+ get: function () {
154
+ return document.documentElement.getAttribute('data-theme') || getPreferredTheme();
155
+ },
156
+ setBrand: applyBrand,
157
+ getBrand: function () {
158
+ return document.documentElement.getAttribute('data-brand') || getPreferredBrand();
159
+ }
160
+ };
161
+ })();