@linxin666/dsh-usage 0.3.7
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/LICENSE +202 -0
- package/README.i18n.yaml +5 -0
- package/README.md +50 -0
- package/README.zh.md +50 -0
- package/cordis.patch.yml +10 -0
- package/lib/client.js +755 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +1443 -0
- package/lib/types/client/UsageSectionCard.d.ts +36 -0
- package/lib/types/client/index.d.ts +34 -0
- package/lib/types/client/locales.d.ts +62 -0
- package/lib/types/client/usage-store.d.ts +27 -0
- package/lib/types/core/adapters.d.ts +58 -0
- package/lib/types/core/ledger.d.ts +31 -0
- package/lib/types/core/types.d.ts +112 -0
- package/lib/types/dsh-home.d.ts +16 -0
- package/lib/types/host/http.d.ts +42 -0
- package/lib/types/host/loopback.d.ts +24 -0
- package/lib/types/host/routes.d.ts +14 -0
- package/lib/types/host/usage-service.d.ts +82 -0
- package/lib/types/index.d.ts +21 -0
- package/lib/types/mount-once.d.ts +24 -0
- package/package.json +92 -0
- package/src/client/UsageSectionCard.tsx +368 -0
- package/src/client/css-modules.d.ts +4 -0
- package/src/client/index.ts +131 -0
- package/src/client/locales.ts +116 -0
- package/src/client/usage-store.ts +52 -0
- package/src/client/usage.module.css +311 -0
- package/src/core/adapters.ts +370 -0
- package/src/core/ledger.ts +108 -0
- package/src/core/types.ts +127 -0
- package/src/dsh-home.ts +42 -0
- package/src/host/http.ts +105 -0
- package/src/host/loopback.ts +63 -0
- package/src/host/routes.ts +54 -0
- package/src/host/usage-service.ts +530 -0
- package/src/index.ts +90 -0
- package/src/mount-once.ts +48 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-usage locale dictionaries (zh/en). The zh dictionary is the key source;
|
|
3
|
+
* `en` mirrors its full key set (packages/AGENTS.md bilingual discipline).
|
|
4
|
+
* @module @linxin666/dsh-usage/client/locales
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Dictionary namespace this package registers. */
|
|
8
|
+
export const NS = 'dsh-web-ui-usage'
|
|
9
|
+
|
|
10
|
+
/** Chinese copy. */
|
|
11
|
+
export const zh = {
|
|
12
|
+
'usage.title': '使用统计',
|
|
13
|
+
'usage.tab.usage': '用量',
|
|
14
|
+
'usage.tab.plans': '个人套餐',
|
|
15
|
+
'usage.refresh': '刷新',
|
|
16
|
+
'usage.refreshing': '刷新中…',
|
|
17
|
+
'usage.updated': '更新于 {time}',
|
|
18
|
+
'usage.loading': '正在加载用量数据…',
|
|
19
|
+
'usage.error': '加载失败:{error}',
|
|
20
|
+
'usage.current': '当前',
|
|
21
|
+
'usage.today': '今日用量',
|
|
22
|
+
'usage.calls': '{n} 次调用',
|
|
23
|
+
'usage.tokens.total': '总 tokens',
|
|
24
|
+
'usage.tokens.input': '输入',
|
|
25
|
+
'usage.tokens.output': '输出',
|
|
26
|
+
'usage.tokens.cacheRead': '缓存读',
|
|
27
|
+
'usage.tokens.cacheWrite': '缓存写',
|
|
28
|
+
'usage.trend': '近 30 天',
|
|
29
|
+
'usage.noData': '暂无用量数据(统计自插件启用起)',
|
|
30
|
+
'usage.balance': '余额',
|
|
31
|
+
'usage.balance.unsupported': '暂不支持余额查询',
|
|
32
|
+
'usage.balance.noCredential': '未配置凭据',
|
|
33
|
+
'usage.oauth': 'OAuth 凭据,不做余额查询',
|
|
34
|
+
'usage.plan.reset': '{date} 重置',
|
|
35
|
+
'usage.plan.noPlan': '未检测到套餐数据',
|
|
36
|
+
'usage.plan.windows.5h': '5 小时',
|
|
37
|
+
'usage.plan.windows.week': '每周',
|
|
38
|
+
'usage.plan.windows.month': '每月',
|
|
39
|
+
'usage.provider.error': '查询失败:{error}',
|
|
40
|
+
'usage.config.title': '设置',
|
|
41
|
+
'usage.config.enabled': '启用插件',
|
|
42
|
+
'usage.config.pollIntervalSec': '轮询间隔(秒)',
|
|
43
|
+
'usage.config.bubbleMode': '宠物气泡',
|
|
44
|
+
'usage.config.bubbleMode.always': '常驻显示',
|
|
45
|
+
'usage.config.bubbleMode.change': '仅变化时',
|
|
46
|
+
'usage.config.bubbleMode.off': '关闭',
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** English mirror; every zh key present. */
|
|
50
|
+
export const en: Record<UsageKey, string> = {
|
|
51
|
+
'usage.title': 'Usage Statistics',
|
|
52
|
+
'usage.tab.usage': 'Usage',
|
|
53
|
+
'usage.tab.plans': 'Plans',
|
|
54
|
+
'usage.refresh': 'Refresh',
|
|
55
|
+
'usage.refreshing': 'Refreshing…',
|
|
56
|
+
'usage.updated': 'Updated {time}',
|
|
57
|
+
'usage.loading': 'Loading usage data…',
|
|
58
|
+
'usage.error': 'Failed to load: {error}',
|
|
59
|
+
'usage.current': 'Current',
|
|
60
|
+
'usage.today': 'Today',
|
|
61
|
+
'usage.calls': '{n} calls',
|
|
62
|
+
'usage.tokens.total': 'Total tokens',
|
|
63
|
+
'usage.tokens.input': 'Input',
|
|
64
|
+
'usage.tokens.output': 'Output',
|
|
65
|
+
'usage.tokens.cacheRead': 'Cache read',
|
|
66
|
+
'usage.tokens.cacheWrite': 'Cache write',
|
|
67
|
+
'usage.trend': 'Last 30 days',
|
|
68
|
+
'usage.noData': 'No usage data yet (counting starts when the plugin is enabled)',
|
|
69
|
+
'usage.balance': 'Balance',
|
|
70
|
+
'usage.balance.unsupported': 'Balance query not supported',
|
|
71
|
+
'usage.balance.noCredential': 'No credential configured',
|
|
72
|
+
'usage.oauth': 'OAuth credential, no balance query',
|
|
73
|
+
'usage.plan.reset': 'resets {date}',
|
|
74
|
+
'usage.plan.noPlan': 'No plan data detected',
|
|
75
|
+
'usage.plan.windows.5h': '5 hours',
|
|
76
|
+
'usage.plan.windows.week': 'Weekly',
|
|
77
|
+
'usage.plan.windows.month': 'Monthly',
|
|
78
|
+
'usage.provider.error': 'Query failed: {error}',
|
|
79
|
+
'usage.config.title': 'Settings',
|
|
80
|
+
'usage.config.enabled': 'Enable plugin',
|
|
81
|
+
'usage.config.pollIntervalSec': 'Poll interval (seconds)',
|
|
82
|
+
'usage.config.bubbleMode': 'Pet bubble',
|
|
83
|
+
'usage.config.bubbleMode.always': 'Always visible',
|
|
84
|
+
'usage.config.bubbleMode.change': 'On change',
|
|
85
|
+
'usage.config.bubbleMode.off': 'Off',
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export type UsageKey = keyof typeof zh
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Active dictionary, picked by the document language at call time. The
|
|
92
|
+
* section resolves its copy the same tiny way the pet's DOM-injected surface
|
|
93
|
+
* does (the settings section has no framework locale seat of its own).
|
|
94
|
+
*/
|
|
95
|
+
export function dictionary(): Record<UsageKey, string> {
|
|
96
|
+
const lang = typeof document !== 'undefined' ? document.documentElement.lang : 'zh'
|
|
97
|
+
return lang.toLowerCase().startsWith('en') ? en : zh
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Translate a key with optional `{name}` template params; missing keys degrade to the key. */
|
|
101
|
+
export function t(key: string, params?: Record<string, unknown>): string {
|
|
102
|
+
let text: string = (dictionary() as Record<string, string>)[key] ?? key
|
|
103
|
+
if (params !== undefined) {
|
|
104
|
+
for (const [name, value] of Object.entries(params)) {
|
|
105
|
+
text = text.replaceAll(`{${name}}`, String(value))
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return text
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
112
|
+
interface LocaleNamespaceMap {
|
|
113
|
+
/** dsh-usage UI copy. */
|
|
114
|
+
'dsh-web-ui-usage': UsageKey
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-side usage store: the overview snapshot polled from the host plus
|
|
3
|
+
* the fetch lifecycle. Section-local: the store lives while the settings
|
|
4
|
+
* section is mounted, so polling only runs while the page is open.
|
|
5
|
+
* @module @linxin666/dsh-usage/client/usage-store
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { defineStore } from '@deepseek-ai/dsh-client-store'
|
|
9
|
+
import type { EngineStoreHandle, EngineStoreInstance } from '@deepseek-ai/dsh-client-store'
|
|
10
|
+
import type { UsageOverviewView } from '../core/types.ts'
|
|
11
|
+
|
|
12
|
+
/** Section UI state as consumers see it. */
|
|
13
|
+
export interface UsageUiState {
|
|
14
|
+
/** Latest host overview; null before the first successful fetch. */
|
|
15
|
+
snapshot: UsageOverviewView | null
|
|
16
|
+
/** Fetch lifecycle. */
|
|
17
|
+
status: 'loading' | 'ready' | 'error'
|
|
18
|
+
/** Transport error message, when any. */
|
|
19
|
+
error: string | null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Store write set. */
|
|
23
|
+
export type UsageUiActions = {
|
|
24
|
+
/** Replace the overview (poll result). */
|
|
25
|
+
setSnapshot: (draft: UsageUiState, snapshot: UsageOverviewView) => void
|
|
26
|
+
/** Mark the fetch lifecycle. */
|
|
27
|
+
setState: (draft: UsageUiState, status: UsageUiState['status'], error: string | null) => void
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Create the usage store handle (apply world only; never module-level). */
|
|
31
|
+
export function createUsageStore(): EngineStoreHandle<UsageUiState, UsageUiActions> {
|
|
32
|
+
return defineStore({
|
|
33
|
+
init: (): UsageUiState => ({
|
|
34
|
+
snapshot: null,
|
|
35
|
+
status: 'loading',
|
|
36
|
+
error: null,
|
|
37
|
+
}),
|
|
38
|
+
actions: {
|
|
39
|
+
setSnapshot: (draft, snapshot) => {
|
|
40
|
+
draft.snapshot = snapshot
|
|
41
|
+
draft.status = 'ready'
|
|
42
|
+
draft.error = null
|
|
43
|
+
},
|
|
44
|
+
setState: (draft, status, error) => {
|
|
45
|
+
draft.status = status
|
|
46
|
+
draft.error = error
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type UsageStoreInstance = EngineStoreInstance<UsageUiState, UsageUiActions>
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
/* dsh-usage settings section: quiet cards on the host surface tokens, no
|
|
2
|
+
framework style imports. Neutral grays follow the GUI text color so the
|
|
3
|
+
section reads on light and dark themes alike. */
|
|
4
|
+
|
|
5
|
+
.section {
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
gap: 16px;
|
|
9
|
+
color: inherit;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.header {
|
|
13
|
+
display: flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
justify-content: space-between;
|
|
16
|
+
gap: 12px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.currentProvider {
|
|
20
|
+
font-size: 13px;
|
|
21
|
+
opacity: 0.75;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.refreshBtn {
|
|
25
|
+
appearance: none;
|
|
26
|
+
border: 1px solid currentColor;
|
|
27
|
+
border-radius: 8px;
|
|
28
|
+
background: transparent;
|
|
29
|
+
color: inherit;
|
|
30
|
+
font: inherit;
|
|
31
|
+
font-size: 12px;
|
|
32
|
+
padding: 4px 12px;
|
|
33
|
+
cursor: pointer;
|
|
34
|
+
opacity: 0.85;
|
|
35
|
+
transition: opacity 120ms ease, background-color 120ms ease;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.refreshBtn:hover:not(:disabled) {
|
|
39
|
+
opacity: 1;
|
|
40
|
+
background: color-mix(in srgb, currentColor 8%, transparent);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.refreshBtn:disabled {
|
|
44
|
+
cursor: default;
|
|
45
|
+
opacity: 0.5;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.refreshBtn:focus-visible {
|
|
49
|
+
outline: none;
|
|
50
|
+
box-shadow: 0 0 0 2px color-mix(in srgb, currentColor 45%, transparent);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.tabs {
|
|
54
|
+
display: flex;
|
|
55
|
+
gap: 4px;
|
|
56
|
+
border-bottom: 1px solid color-mix(in srgb, currentColor 14%, transparent);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.tab {
|
|
60
|
+
appearance: none;
|
|
61
|
+
border: none;
|
|
62
|
+
background: transparent;
|
|
63
|
+
color: inherit;
|
|
64
|
+
font: inherit;
|
|
65
|
+
font-size: 13px;
|
|
66
|
+
padding: 6px 14px;
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
opacity: 0.65;
|
|
69
|
+
border-bottom: 2px solid transparent;
|
|
70
|
+
margin-bottom: -1px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.tab:hover {
|
|
74
|
+
opacity: 0.9;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.tab:focus-visible {
|
|
78
|
+
outline: none;
|
|
79
|
+
box-shadow: 0 0 0 2px color-mix(in srgb, currentColor 45%, transparent);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.tabActive {
|
|
83
|
+
opacity: 1;
|
|
84
|
+
font-weight: 600;
|
|
85
|
+
border-bottom-color: currentColor;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.card {
|
|
89
|
+
border: 1px solid color-mix(in srgb, currentColor 14%, transparent);
|
|
90
|
+
border-radius: 12px;
|
|
91
|
+
padding: 14px 16px;
|
|
92
|
+
display: flex;
|
|
93
|
+
flex-direction: column;
|
|
94
|
+
gap: 10px;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.cardTitle {
|
|
98
|
+
font-size: 12px;
|
|
99
|
+
font-weight: 600;
|
|
100
|
+
letter-spacing: 0.04em;
|
|
101
|
+
text-transform: uppercase;
|
|
102
|
+
opacity: 0.6;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.statRow {
|
|
106
|
+
display: flex;
|
|
107
|
+
flex-wrap: wrap;
|
|
108
|
+
gap: 18px;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.stat {
|
|
112
|
+
display: flex;
|
|
113
|
+
flex-direction: column;
|
|
114
|
+
gap: 2px;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.statValue {
|
|
118
|
+
font-size: 18px;
|
|
119
|
+
font-weight: 600;
|
|
120
|
+
font-variant-numeric: tabular-nums;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.statLabel {
|
|
124
|
+
font-size: 11px;
|
|
125
|
+
opacity: 0.6;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.providerRow {
|
|
129
|
+
display: flex;
|
|
130
|
+
align-items: center;
|
|
131
|
+
justify-content: space-between;
|
|
132
|
+
gap: 12px;
|
|
133
|
+
padding: 6px 0;
|
|
134
|
+
border-top: 1px solid color-mix(in srgb, currentColor 8%, transparent);
|
|
135
|
+
font-size: 13px;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.providerRow:first-of-type {
|
|
139
|
+
border-top: none;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.providerName {
|
|
143
|
+
display: flex;
|
|
144
|
+
align-items: center;
|
|
145
|
+
gap: 8px;
|
|
146
|
+
min-width: 0;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.providerTokens {
|
|
150
|
+
font-variant-numeric: tabular-nums;
|
|
151
|
+
opacity: 0.75;
|
|
152
|
+
white-space: nowrap;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.providerBalance {
|
|
156
|
+
font-variant-numeric: tabular-nums;
|
|
157
|
+
font-weight: 600;
|
|
158
|
+
white-space: nowrap;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.currentBadge {
|
|
162
|
+
font-size: 10px;
|
|
163
|
+
font-weight: 600;
|
|
164
|
+
border: 1px solid color-mix(in srgb, currentColor 35%, transparent);
|
|
165
|
+
border-radius: 999px;
|
|
166
|
+
padding: 1px 7px;
|
|
167
|
+
opacity: 0.8;
|
|
168
|
+
flex: none;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.trend {
|
|
172
|
+
display: flex;
|
|
173
|
+
align-items: flex-end;
|
|
174
|
+
gap: 3px;
|
|
175
|
+
height: 56px;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.trendBar {
|
|
179
|
+
flex: 1 1 0;
|
|
180
|
+
min-width: 4px;
|
|
181
|
+
border-radius: 3px 3px 0 0;
|
|
182
|
+
background: color-mix(in srgb, currentColor 30%, transparent);
|
|
183
|
+
min-height: 2px;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.trendBarToday {
|
|
187
|
+
background: color-mix(in srgb, currentColor 65%, transparent);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.trendAxis {
|
|
191
|
+
display: flex;
|
|
192
|
+
justify-content: space-between;
|
|
193
|
+
font-size: 10px;
|
|
194
|
+
opacity: 0.5;
|
|
195
|
+
font-variant-numeric: tabular-nums;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.muted {
|
|
199
|
+
font-size: 12px;
|
|
200
|
+
opacity: 0.6;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.errorLine {
|
|
204
|
+
font-size: 12px;
|
|
205
|
+
opacity: 0.75;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.planCard {
|
|
209
|
+
display: flex;
|
|
210
|
+
flex-direction: column;
|
|
211
|
+
gap: 8px;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.planHead {
|
|
215
|
+
display: flex;
|
|
216
|
+
align-items: baseline;
|
|
217
|
+
justify-content: space-between;
|
|
218
|
+
gap: 10px;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.planName {
|
|
222
|
+
font-size: 14px;
|
|
223
|
+
font-weight: 600;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.windowRow {
|
|
227
|
+
display: flex;
|
|
228
|
+
flex-direction: column;
|
|
229
|
+
gap: 4px;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.windowLabel {
|
|
233
|
+
display: flex;
|
|
234
|
+
justify-content: space-between;
|
|
235
|
+
font-size: 12px;
|
|
236
|
+
opacity: 0.8;
|
|
237
|
+
font-variant-numeric: tabular-nums;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.bar {
|
|
241
|
+
height: 6px;
|
|
242
|
+
border-radius: 999px;
|
|
243
|
+
background: color-mix(in srgb, currentColor 10%, transparent);
|
|
244
|
+
overflow: hidden;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.barFill {
|
|
248
|
+
height: 100%;
|
|
249
|
+
border-radius: 999px;
|
|
250
|
+
background: color-mix(in srgb, currentColor 55%, transparent);
|
|
251
|
+
transition: width 300ms ease;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.barWarn {
|
|
255
|
+
background: #d97706;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.barLow {
|
|
259
|
+
background: #dc2626;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.resetLine {
|
|
263
|
+
font-size: 11px;
|
|
264
|
+
opacity: 0.55;
|
|
265
|
+
font-variant-numeric: tabular-nums;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.settingsGrid {
|
|
269
|
+
display: flex;
|
|
270
|
+
flex-wrap: wrap;
|
|
271
|
+
gap: 16px;
|
|
272
|
+
align-items: center;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.settingItem {
|
|
276
|
+
display: flex;
|
|
277
|
+
align-items: center;
|
|
278
|
+
gap: 8px;
|
|
279
|
+
font-size: 13px;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.settingItem input[type='checkbox'] {
|
|
283
|
+
accent-color: currentColor;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.settingItem input[type='number'] {
|
|
287
|
+
width: 90px;
|
|
288
|
+
border: 1px solid color-mix(in srgb, currentColor 25%, transparent);
|
|
289
|
+
border-radius: 6px;
|
|
290
|
+
background: transparent;
|
|
291
|
+
color: inherit;
|
|
292
|
+
font: inherit;
|
|
293
|
+
font-size: 13px;
|
|
294
|
+
padding: 3px 8px;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.settingItem select {
|
|
298
|
+
border: 1px solid color-mix(in srgb, currentColor 25%, transparent);
|
|
299
|
+
border-radius: 6px;
|
|
300
|
+
background: transparent;
|
|
301
|
+
color: inherit;
|
|
302
|
+
font: inherit;
|
|
303
|
+
font-size: 13px;
|
|
304
|
+
padding: 3px 8px;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.settingItem input:focus-visible,
|
|
308
|
+
.settingItem select:focus-visible {
|
|
309
|
+
outline: none;
|
|
310
|
+
box-shadow: 0 0 0 2px color-mix(in srgb, currentColor 45%, transparent);
|
|
311
|
+
}
|