dsh-token-gauge 0.1.0

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/src/styles.ts ADDED
@@ -0,0 +1,313 @@
1
+ // 风格与配色定义 + 全局 CSS 生成(纯浏览器端,无外部依赖)
2
+
3
+ export interface StyleDef {
4
+ id: string
5
+ labelZh: string
6
+ labelEn: string
7
+ className: string
8
+ }
9
+
10
+ export interface PaletteDef {
11
+ id: string
12
+ labelZh: string
13
+ labelEn: string
14
+ vars: Record<string, string>
15
+ }
16
+
17
+ // ≥5 种风格
18
+ export const STYLES: StyleDef[] = [
19
+ { id: 'ev', labelZh: '现代电车科技', labelEn: 'Modern EV Tech', className: 'tg-style-ev' },
20
+ { id: 'raw', labelZh: '原始机车', labelEn: 'Raw Motorcycle', className: 'tg-style-raw' },
21
+ { id: 'luxury', labelZh: '豪华跑车', labelEn: 'Luxury Sports', className: 'tg-style-luxury' },
22
+ { id: 'cute', labelZh: '可爱小车', labelEn: 'Cute Car', className: 'tg-style-cute' },
23
+ { id: 'cyber', labelZh: '赛博朋克', labelEn: 'Cyberpunk', className: 'tg-style-cyber' },
24
+ { id: 'retro', labelZh: '复古机械表盘', labelEn: 'Retro Dial', className: 'tg-style-retro' },
25
+ ]
26
+
27
+ // ≥8 种配色(每个含一组 CSS 变量)
28
+ export const PALETTES: PaletteDef[] = [
29
+ {
30
+ id: 'amber',
31
+ labelZh: '琥珀金',
32
+ labelEn: 'Amber Gold',
33
+ vars: {
34
+ '--c-bg': '#1c1407',
35
+ '--c-panel': '#2b2009',
36
+ '--c-main': '#f5a623',
37
+ '--c-track': '#3a2c0e',
38
+ '--c-tick': '#f5c451',
39
+ '--c-needle': '#ffcf5c',
40
+ '--c-num': '#ffe39a',
41
+ '--c-danger': '#ff5a3c',
42
+ '--c-glow': 'rgba(245,166,35,0.55)',
43
+ '--c-sub': '#caa85e',
44
+ '--c-font': '"Segoe UI", system-ui, sans-serif',
45
+ },
46
+ },
47
+ {
48
+ id: 'neon',
49
+ labelZh: '霓虹蓝',
50
+ labelEn: 'Neon Blue',
51
+ vars: {
52
+ '--c-bg': '#04111f',
53
+ '--c-panel': '#072438',
54
+ '--c-main': '#22d3ee',
55
+ '--c-track': '#0b3550',
56
+ '--c-tick': '#7fe9ff',
57
+ '--c-needle': '#22d3ee',
58
+ '--c-num': '#d6fbff',
59
+ '--c-danger': '#ff4d6d',
60
+ '--c-glow': 'rgba(34,211,238,0.55)',
61
+ '--c-sub': '#7fb6cf',
62
+ '--c-font': '"Segoe UI", system-ui, sans-serif',
63
+ },
64
+ },
65
+ {
66
+ id: 'track-red',
67
+ labelZh: '赛道红',
68
+ labelEn: 'Track Red',
69
+ vars: {
70
+ '--c-bg': '#1a0608',
71
+ '--c-panel': '#2a0a0e',
72
+ '--c-main': '#ff3b4e',
73
+ '--c-track': '#3a0d12',
74
+ '--c-tick': '#ff8a96',
75
+ '--c-needle': '#ff3b4e',
76
+ '--c-num': '#ffd9dd',
77
+ '--c-danger': '#ff7a00',
78
+ '--c-glow': 'rgba(255,59,78,0.5)',
79
+ '--c-sub': '#cf7a84',
80
+ '--c-font': '"Segoe UI", system-ui, sans-serif',
81
+ },
82
+ },
83
+ {
84
+ id: 'aurora',
85
+ labelZh: '极光绿',
86
+ labelEn: 'Aurora Green',
87
+ vars: {
88
+ '--c-bg': '#04140d',
89
+ '--c-panel': '#07241a',
90
+ '--c-main': '#34e0a1',
91
+ '--c-track': '#0b3a29',
92
+ '--c-tick': '#8af3cd',
93
+ '--c-needle': '#34e0a1',
94
+ '--c-num': '#d8ffee',
95
+ '--c-danger': '#ffb020',
96
+ '--c-glow': 'rgba(52,224,161,0.5)',
97
+ '--c-sub': '#79c7a6',
98
+ '--c-font': '"Segoe UI", system-ui, sans-serif',
99
+ },
100
+ },
101
+ {
102
+ id: 'sakura',
103
+ labelZh: '樱粉',
104
+ labelEn: 'Sakura Pink',
105
+ vars: {
106
+ '--c-bg': '#2a111d',
107
+ '--c-panel': '#3d1a2c',
108
+ '--c-main': '#ff9ecb',
109
+ '--c-track': '#4a2238',
110
+ '--c-tick': '#ffc7e2',
111
+ '--c-needle': '#ff9ecb',
112
+ '--c-num': '#ffe6f3',
113
+ '--c-danger': '#ff5d8f',
114
+ '--c-glow': 'rgba(255,158,203,0.5)',
115
+ '--c-sub': '#d29bbb',
116
+ '--c-font': '"Segoe UI", system-ui, sans-serif',
117
+ },
118
+ },
119
+ {
120
+ id: 'night-purple',
121
+ labelZh: '暗夜紫',
122
+ labelEn: 'Night Purple',
123
+ vars: {
124
+ '--c-bg': '#120a26',
125
+ '--c-panel': '#1d1238',
126
+ '--c-main': '#a78bfa',
127
+ '--c-track': '#2a1c52',
128
+ '--c-tick': '#cdbcff',
129
+ '--c-needle': '#a78bfa',
130
+ '--c-num': '#ece4ff',
131
+ '--c-danger': '#ff5a8a',
132
+ '--c-glow': 'rgba(167,139,250,0.5)',
133
+ '--c-sub': '#9b86d6',
134
+ '--c-font': '"Segoe UI", system-ui, sans-serif',
135
+ },
136
+ },
137
+ {
138
+ id: 'titanium',
139
+ labelZh: '钛银',
140
+ labelEn: 'Titanium Silver',
141
+ vars: {
142
+ '--c-bg': '#0e1116',
143
+ '--c-panel': '#1a1f27',
144
+ '--c-main': '#c7d0db',
145
+ '--c-track': '#2b323d',
146
+ '--c-tick': '#9aa6b4',
147
+ '--c-needle': '#e6edf5',
148
+ '--c-num': '#f2f6fb',
149
+ '--c-danger': '#ff5a3c',
150
+ '--c-glow': 'rgba(199,208,219,0.35)',
151
+ '--c-sub': '#8b95a3',
152
+ '--c-font': '"Segoe UI", system-ui, sans-serif',
153
+ },
154
+ },
155
+ {
156
+ id: 'volcano',
157
+ labelZh: '火山橙',
158
+ labelEn: 'Volcano Orange',
159
+ vars: {
160
+ '--c-bg': '#1f0d04',
161
+ '--c-panel': '#321507',
162
+ '--c-main': '#ff7a18',
163
+ '--c-track': '#45200c',
164
+ '--c-tick': '#ffb070',
165
+ '--c-needle': '#ff7a18',
166
+ '--c-num': '#ffe2cc',
167
+ '--c-danger': '#ff3b2f',
168
+ '--c-glow': 'rgba(255,122,24,0.5)',
169
+ '--c-sub': '#cf9468',
170
+ '--c-font': '"Segoe UI", system-ui, sans-serif',
171
+ },
172
+ },
173
+ ]
174
+
175
+ export function getStyle(id: string): StyleDef {
176
+ return STYLES.find((s) => s.id === id) || STYLES[0]
177
+ }
178
+
179
+ export function getPalette(id: string): PaletteDef {
180
+ return PALETTES.find((p) => p.id === id) || PALETTES[1]
181
+ }
182
+
183
+ export function applyPalette(el: HTMLElement, paletteId: string): void {
184
+ const p = getPalette(paletteId)
185
+ for (const [k, v] of Object.entries(p.vars)) {
186
+ el.style.setProperty(k, v)
187
+ }
188
+ }
189
+
190
+ // 生成全局 CSS(只注入一次)
191
+ export function buildCss(): string {
192
+ return `
193
+ .tg-root {
194
+ --c-bg:#04111f; --c-panel:#072438; --c-main:#22d3ee; --c-track:#0b3550;
195
+ --c-tick:#7fe9ff; --c-needle:#22d3ee; --c-num:#d6fbff; --c-danger:#ff4d6d;
196
+ --c-glow:rgba(34,211,238,0.55); --c-sub:#7fb6cf; --c-font:"Segoe UI",system-ui,sans-serif;
197
+ box-sizing:border-box; color:var(--c-num); font-family:var(--c-font);
198
+ height:100%; display:flex; flex-direction:column; padding:10px; gap:6px;
199
+ background:linear-gradient(160deg, var(--c-bg), var(--c-panel));
200
+ border-radius:14px; overflow:auto; position:relative;
201
+ }
202
+ .tg-root * { box-sizing:border-box; }
203
+ .tg-head { display:flex; align-items:center; justify-content:space-between; }
204
+ .tg-title { font-size:13px; font-weight:700; letter-spacing:.5px; color:var(--c-num); }
205
+ .tg-gear {
206
+ cursor:pointer; border:1px solid var(--c-track); background:var(--c-panel); color:var(--c-main);
207
+ border-radius:8px; width:28px; height:28px; font-size:14px; line-height:1; display:flex;
208
+ align-items:center; justify-content:center;
209
+ }
210
+ .tg-gear:hover { box-shadow:0 0 10px var(--c-glow); }
211
+ .tg-gauge-wrap { display:flex; flex-direction:column; align-items:center; gap:0; }
212
+ .tg-gauge { width:100%; max-width:200px; height:auto; display:block; filter:drop-shadow(0 0 6px var(--c-glow)); }
213
+ .tg-track { fill:none; stroke:var(--c-track); stroke-width:14; stroke-linecap:round; }
214
+ .tg-danger { fill:none; stroke:var(--c-danger); stroke-width:14; stroke-linecap:round; opacity:0; }
215
+ .tg-tick { stroke:var(--c-tick); stroke-width:2; }
216
+ .tg-ticklabel { fill:var(--c-sub); font-size:9px; font-family:var(--c-font); }
217
+ .tg-hub { fill:var(--c-main); }
218
+ .tg-needle { fill:var(--c-needle); transition:transform .6s cubic-bezier(.34,1.4,.5,1); transform-box:view-box; transform-origin:100px 100px; }
219
+ .tg-needle.tg-over { fill:var(--c-danger); }
220
+ .tg-extrashadow { fill:rgba(0,0,0,.25); }
221
+ .tg-readout { text-align:center; width:100%; margin-top:-16px; }
222
+ .tg-usage { font-size:22px; font-weight:800; color:var(--c-num); line-height:1.1; margin-top:1px; }
223
+ .tg-usage small { font-size:12px; color:var(--c-sub); font-weight:600; margin-left:4px; }
224
+ .tg-cost { font-size:17px; font-weight:700; color:var(--c-main); margin-top:0; }
225
+ .tg-cards { display:grid; grid-template-columns:1fr 1fr; gap:6px; width:100%; margin-top:4px; }
226
+ .tg-card { background:var(--c-panel); border:1px solid var(--c-track); border-radius:8px; padding:6px 8px; }
227
+ .tg-card .k { font-size:10px; color:var(--c-sub); }
228
+ .tg-card .v { font-size:13px; font-weight:700; color:var(--c-num); }
229
+ .tg-empty { color:var(--c-sub); font-size:12px; text-align:center; padding:20px 0; }
230
+
231
+ /* 设置弹窗 */
232
+ .tg-modal-mask {
233
+ position:fixed; inset:0; background:rgba(0,0,0,.5); display:flex; align-items:center; justify-content:center;
234
+ z-index:9999; padding:16px;
235
+ }
236
+ .tg-modal {
237
+ width:min(420px, 100%); max-height:88%; overflow:auto; background:var(--c-panel); color:var(--c-num);
238
+ border:1px solid var(--c-main); border-radius:14px; padding:16px; font-family:var(--c-font);
239
+ box-shadow:0 0 24px var(--c-glow);
240
+ }
241
+ .tg-modal h3 { margin:0 0 10px; font-size:15px; color:var(--c-main); }
242
+ .tg-field { margin-bottom:12px; }
243
+ .tg-field > label { display:block; font-size:12px; color:var(--c-sub); margin-bottom:5px; }
244
+ .tg-row { display:flex; flex-wrap:wrap; gap:6px; }
245
+ .tg-chip {
246
+ cursor:pointer; border:1px solid var(--c-track); background:var(--c-bg); color:var(--c-num);
247
+ border-radius:999px; padding:5px 10px; font-size:12px; user-select:none;
248
+ }
249
+ .tg-chip.on { border-color:var(--c-main); color:var(--c-main); box-shadow:0 0 8px var(--c-glow); }
250
+ .tg-input {
251
+ width:100%; background:var(--c-bg); border:1px solid var(--c-track); color:var(--c-num);
252
+ border-radius:8px; padding:7px 9px; font-size:13px; font-family:var(--c-font);
253
+ }
254
+ .tg-input:focus { outline:none; border-color:var(--c-main); }
255
+ .tg-toggle { display:flex; align-items:center; gap:8px; font-size:12px; color:var(--c-sub); margin:3px 0; }
256
+ .tg-actions { display:flex; gap:8px; margin-top:8px; }
257
+ .tg-btn {
258
+ flex:1; cursor:pointer; border:1px solid var(--c-main); background:var(--c-main); color:#06121c;
259
+ border-radius:9px; padding:9px; font-size:13px; font-weight:700; font-family:var(--c-font);
260
+ }
261
+ .tg-btn.ghost { background:transparent; color:var(--c-num); border-color:var(--c-track); }
262
+ .tg-btn:hover { filter:brightness(1.08); }
263
+ .tg-hint { font-size:11px; color:var(--c-sub); margin-top:4px; }
264
+
265
+ /* ---- 风格差异化装饰 ---- */
266
+ .tg-style-ev .tg-gauge-wrap { backdrop-filter:blur(2px); }
267
+ .tg-style-raw {
268
+ background:
269
+ repeating-linear-gradient(90deg, rgba(255,255,255,.04) 0 2px, rgba(0,0,0,.06) 2px 4px),
270
+ linear-gradient(160deg, #2a2a2a, #4a4a4a);
271
+ border:3px solid #6b6b6b;
272
+ }
273
+ .tg-style-raw .tg-panel-deco::before,
274
+ .tg-style-raw .tg-panel-deco::after {
275
+ content:""; position:absolute; width:8px; height:8px; border-radius:50%;
276
+ background:radial-gradient(circle at 30% 30%, #fff, #888); top:8px;
277
+ }
278
+ .tg-style-raw .tg-panel-deco::before { left:8px; }
279
+ .tg-style-raw .tg-panel-deco::after { right:8px; }
280
+ .tg-style-luxury {
281
+ background:
282
+ repeating-linear-gradient(45deg, #0c0c0c 0 6px, #161616 6px 12px),
283
+ linear-gradient(160deg, #1a0a0c, #2a0f12);
284
+ border:2px solid #d4af37;
285
+ }
286
+ .tg-style-luxury .tg-title { color:#f3d27a; }
287
+ .tg-style-cute {
288
+ background:linear-gradient(160deg, #fff0f6, #ffe1ee); color:#7a3b56;
289
+ border:3px solid #ffc2dd; border-radius:22px;
290
+ }
291
+ .tg-style-cute .tg-usage, .tg-style-cute .tg-cost, .tg-style-cute .tg-title, .tg-style-cute .tg-card .v { color:#a6446f; }
292
+ .tg-style-cute .tg-card { background:#fff6fb; border-color:#ffd0e6; }
293
+ .tg-style-cute .tg-card .k { color:#c98bb0; }
294
+ .tg-style-cute .tg-track { stroke:#ffd0e6; }
295
+ .tg-style-cyber {
296
+ background:linear-gradient(160deg, #0a0014, #16002a);
297
+ border:2px solid #ff2bd6;
298
+ }
299
+ .tg-style-cyber .tg-title { color:#22e7ff; text-shadow:1px 0 #ff2bd6, -1px 0 #22e7ff; }
300
+ .tg-style-cyber .tg-gauge { filter:drop-shadow(0 0 8px #22e7ff) drop-shadow(0 0 4px #ff2bd6); }
301
+ .tg-style-retro {
302
+ background:linear-gradient(160deg, #f3e9cf, #e7d8b0); color:#5b3a1a;
303
+ border:3px double #8a6a3a; border-radius:10px;
304
+ }
305
+ .tg-style-retro .tg-usage, .tg-style-retro .tg-cost, .tg-style-retro .tg-title, .tg-style-retro .tg-card .v { color:#5b3a1a; }
306
+ .tg-style-retro .tg-title { font-family:Georgia, "Times New Roman", serif; }
307
+ .tg-style-retro .tg-card { background:#efe3c4; border-color:#b89a64; }
308
+ .tg-style-retro .tg-card .k { color:#8a6a3a; }
309
+ .tg-style-retro .tg-track { stroke:#c9b58a; }
310
+ .tg-style-retro .tg-tick { stroke:#8a6a3a; }
311
+ .tg-style-retro .tg-ticklabel { fill:#8a6a3a; }
312
+ `
313
+ }
package/src/util.ts ADDED
@@ -0,0 +1,31 @@
1
+ // 通用格式化工具(浏览器端)
2
+ export function formatInt(n: number): string {
3
+ return Math.round(n || 0).toLocaleString('en-US')
4
+ }
5
+
6
+ export function formatMoney(n: number): string {
7
+ return '¥' + (n || 0).toFixed(2)
8
+ }
9
+
10
+ export function formatCompact(n: number): string {
11
+ const v = Math.round(n || 0)
12
+ if (v >= 1_000_000) return (v / 1_000_000).toFixed(v >= 10_000_000 ? 0 : 1) + 'M'
13
+ if (v >= 1_000) return (v / 1_000).toFixed(v >= 10_000 ? 0 : 1) + 'K'
14
+ return String(v)
15
+ }
16
+
17
+ export function clamp(v: number, lo: number, hi: number): number {
18
+ return Math.max(lo, Math.min(hi, v))
19
+ }
20
+
21
+ // 自动量程:取 >= value 的最小「整刻度」(1/2/5 ×10^n),下限 1000
22
+ export function autoMax(value: number): number {
23
+ const v = Math.max(0, value)
24
+ for (let exp = 3; exp <= 12; exp++) {
25
+ for (const m of [1, 2, 5]) {
26
+ const cand = m * Math.pow(10, exp)
27
+ if (cand >= v) return cand
28
+ }
29
+ }
30
+ return Math.pow(10, 12)
31
+ }