@363045841yyt/klinechart 0.8.5 → 0.8.6

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.
Files changed (43) hide show
  1. package/README.md +6 -1
  2. package/dist/components/BaseModal.vue.d.ts +54 -0
  3. package/dist/components/BaseModal.vue.d.ts.map +1 -0
  4. package/dist/components/BatchStockDialog.vue.d.ts.map +1 -1
  5. package/dist/components/ChartSettingsDialog.vue.d.ts.map +1 -1
  6. package/dist/components/ColorPresetPanel.vue.d.ts +4 -1
  7. package/dist/components/ColorPresetPanel.vue.d.ts.map +1 -1
  8. package/dist/components/DrawingStyleToolbar.vue.d.ts.map +1 -1
  9. package/dist/components/ExportProgressDialog.vue.d.ts.map +1 -1
  10. package/dist/components/IndicatorParams.vue.d.ts.map +1 -1
  11. package/dist/components/IndicatorSelector.vue.d.ts.map +1 -1
  12. package/dist/components/KLineChart.vue.d.ts.map +1 -1
  13. package/dist/components/RangeSelectionExport.vue.d.ts +23 -0
  14. package/dist/components/RangeSelectionExport.vue.d.ts.map +1 -0
  15. package/dist/components/common/CanvasToolbar.vue.d.ts +14 -0
  16. package/dist/components/common/CanvasToolbar.vue.d.ts.map +1 -0
  17. package/dist/components/common/CanvasToolbarStack.vue.d.ts +14 -0
  18. package/dist/components/common/CanvasToolbarStack.vue.d.ts.map +1 -0
  19. package/dist/composables/chart/useRangeSelection.d.ts +1 -0
  20. package/dist/composables/chart/useRangeSelection.d.ts.map +1 -1
  21. package/dist/composables/useTeleportedPopup.d.ts.map +1 -1
  22. package/dist/index.cjs +6 -6
  23. package/dist/index.css +1 -1
  24. package/dist/index.js +1293 -1215
  25. package/dist/web-component.d.ts.map +1 -1
  26. package/package.json +1 -1
  27. package/src/components/BaseModal.vue +292 -0
  28. package/src/components/BatchStockDialog.vue +15 -180
  29. package/src/components/ChartSettingsDialog.vue +248 -405
  30. package/src/components/ColorPresetPanel.vue +58 -106
  31. package/src/components/CompareSymbolSelector.vue +2 -2
  32. package/src/components/DrawingStyleToolbar.vue +33 -72
  33. package/src/components/ExportProgressDialog.vue +25 -133
  34. package/src/components/IndicatorParams.vue +194 -321
  35. package/src/components/IndicatorSelector.vue +188 -405
  36. package/src/components/KLineChart.vue +34 -138
  37. package/src/components/LeftToolbar.vue +1 -1
  38. package/src/components/RangeSelectionExport.vue +117 -0
  39. package/src/components/SymbolSelector.vue +2 -2
  40. package/src/components/common/CanvasToolbar.vue +70 -0
  41. package/src/components/common/CanvasToolbarStack.vue +32 -0
  42. package/src/composables/chart/useRangeSelection.ts +7 -0
  43. package/src/composables/useTeleportedPopup.ts +15 -2
@@ -1,183 +1,160 @@
1
1
  <template>
2
- <Teleport :to="teleportTarget">
3
- <Transition name="overlay">
4
- <div v-if="show" class="settings-overlay" @click="closeSettings">
5
- <Transition name="modal">
6
- <div class="settings-modal" @click.stop>
7
- <div class="settings-header">
8
- <div class="header-left">
9
- <span class="settings-title">图表设置</span>
10
- <span class="settings-subtitle">个性化配置</span>
11
- </div>
12
- <div class="header-right">
13
- <button class="settings-close" @click="closeSettings">
14
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
15
- <path d="M18 6L6 18M6 6l12 12" />
16
- </svg>
17
- </button>
18
- </div>
19
- </div>
20
-
21
- <div class="settings-body">
22
- <template v-if="mainSettings.length > 0">
23
- <div class="settings-section-divider">
24
- <span class="settings-section-label">主图设置</span>
25
- </div>
26
- <template v-for="item in mainSettings" :key="item.key">
27
- <div class="settings-item">
28
- <label class="settings-label">
29
- <span>{{ item.label }}</span>
30
- <template v-if="item.type === 'boolean'">
31
- <input
32
- type="checkbox"
33
- class="settings-checkbox"
34
- v-model="settings[item.key]"
35
- />
36
- </template>
37
- <template v-else-if="item.type === 'select' && item.options">
38
- <Dropdown
39
- :model-value="String(settings[item.key])"
40
- :options="item.options"
41
- size="sm"
42
- min-width="100px"
43
- @update:model-value="settings[item.key] = $event"
44
- />
45
- </template>
46
- </label>
47
- </div>
48
- </template>
49
- </template>
50
-
51
- <div class="settings-section-divider">
52
- <span class="settings-section-label">样式 / 颜色</span>
53
- </div>
54
- <template v-for="item in styleSettings" :key="item.key">
55
- <div class="settings-item">
56
- <label class="settings-label">
57
- <span>{{ item.label }}</span>
58
- <template v-if="item.type === 'boolean'">
59
- <input
60
- type="checkbox"
61
- class="settings-checkbox"
62
- v-model="settings[item.key]"
63
- />
64
- </template>
65
- <template v-else-if="item.type === 'select' && item.options">
66
- <Dropdown
67
- :model-value="String(settings[item.key])"
68
- :options="item.options"
69
- size="sm"
70
- min-width="100px"
71
- @update:model-value="settings[item.key] = $event"
72
- />
73
- </template>
74
- </label>
75
- </div>
76
- </template>
77
- <div class="settings-item nav-item" @click="showColorPresetModal = true">
78
- <label class="settings-label">
79
- <span>颜色配置</span>
80
- <svg
81
- viewBox="0 0 24 24"
82
- fill="none"
83
- stroke="currentColor"
84
- stroke-width="2"
85
- width="16"
86
- height="16"
87
- class="nav-arrow"
88
- >
89
- <path d="M9 18l6-6-6-6" />
90
- </svg>
2
+ <!-- 主弹窗 -->
3
+ <BaseModal
4
+ :show="show"
5
+ width="min(92vw, 460px)"
6
+ max-height="min(720px, calc(100vh - 48px))"
7
+ footer-align="space-between"
8
+ @close="closeSettings"
9
+ >
10
+ <template #header>
11
+ <div class="header-left">
12
+ <span class="settings-title">图表设置</span>
13
+ <span class="settings-subtitle">个性化配置</span>
14
+ </div>
15
+ </template>
16
+
17
+ <div class="settings-body">
18
+ <template v-if="mainSettings.length > 0">
19
+ <div class="settings-section-divider">
20
+ <span class="settings-section-label">主图设置</span>
21
+ </div>
22
+ <template v-for="item in mainSettings" :key="item.key">
23
+ <div class="settings-item">
24
+
25
+ <span>{{ item.label }}</span>
26
+ <template v-if="item.type === 'boolean'">
27
+ <label class="md-switch">
28
+ <input type="checkbox" v-model="settings[item.key]" />
29
+ <span class="md-switch-slider"></span>
91
30
  </label>
92
- </div>
93
-
94
- <template v-if="experimentalSettings.length > 0">
95
- <div class="settings-section-divider">
96
- <span class="settings-section-label">实验性 / 调试设置</span>
97
- </div>
98
- <template v-for="item in experimentalSettings" :key="item.key">
99
- <div class="settings-item experimental">
100
- <label class="settings-label">
101
- <span>{{ item.label }}</span>
102
- <template v-if="item.type === 'boolean'">
103
- <input
104
- type="checkbox"
105
- class="settings-checkbox"
106
- v-model="settings[item.key]"
107
- />
108
- </template>
109
- <template v-else-if="item.type === 'select' && item.options">
110
- <Dropdown
111
- :model-value="String(settings[item.key])"
112
- :options="item.options"
113
- size="sm"
114
- min-width="100px"
115
- @update:model-value="settings[item.key] = $event"
116
- />
117
- </template>
118
- </label>
119
- </div>
120
- </template>
121
31
  </template>
122
- </div>
123
-
124
- <div class="settings-footer">
125
- <button class="settings-btn reset" @click="resetSettings">
126
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
127
- <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
128
- <path d="M3 3v5h5" />
129
- </svg>
130
- 重置
131
- </button>
132
- <div class="footer-right">
133
- <button class="settings-btn cancel" @click="closeSettings">取消</button>
134
- <button class="settings-btn confirm" @click="confirmSettings">
135
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
136
- <path d="M20 6L9 17l-5-5" />
137
- </svg>
138
- 确定
139
- </button>
140
- </div>
141
- </div>
32
+ <template v-else-if="item.type === 'select' && item.options">
33
+ <Dropdown
34
+ :model-value="String(settings[item.key])"
35
+ :options="item.options"
36
+ size="sm"
37
+ min-width="100px"
38
+ @update:model-value="settings[item.key] = $event"
39
+ />
40
+ </template>
142
41
  </div>
143
- </Transition>
42
+ </template>
43
+ </template>
44
+
45
+ <div class="settings-section-divider">
46
+ <span class="settings-section-label">样式 / 颜色</span>
144
47
  </div>
145
- </Transition>
146
-
147
- <Transition name="overlay">
148
- <div
149
- v-if="showColorPresetModal"
150
- class="settings-overlay nested-overlay"
151
- @click="showColorPresetModal = false"
152
- >
153
- <Transition name="modal">
154
- <div class="settings-modal" @click.stop>
155
- <div class="settings-header">
156
- <div class="header-left">
157
- <span class="settings-title">颜色预设</span>
158
- <span class="settings-subtitle">自定义图表颜色</span>
159
- </div>
160
- <div class="header-right">
161
- <button class="settings-close" @click="showColorPresetModal = false">
162
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
163
- <path d="M18 6L6 18M6 6l12 12" />
164
- </svg>
165
- </button>
166
- </div>
167
- </div>
168
- <div class="settings-body">
169
- <ColorPresetPanel
170
- :color-preset-settings="settings.colorPresetSettings"
171
- @update:color-preset-settings="
172
- settings = { ...settings, colorPresetSettings: $event }
173
- "
48
+ <template v-for="item in styleSettings" :key="item.key">
49
+ <div class="settings-item">
50
+
51
+ <span>{{ item.label }}</span>
52
+ <template v-if="item.type === 'boolean'">
53
+ <label class="md-switch">
54
+ <input type="checkbox" v-model="settings[item.key]" />
55
+ <span class="md-switch-slider"></span>
56
+ </label>
57
+ </template>
58
+ <template v-else-if="item.type === 'select' && item.options">
59
+ <Dropdown
60
+ :model-value="String(settings[item.key])"
61
+ :options="item.options"
62
+ size="sm"
63
+ min-width="100px"
64
+ @update:model-value="settings[item.key] = $event"
174
65
  />
175
- </div>
66
+ </template>
67
+ </div>
68
+ </template>
69
+ <div class="settings-item nav-item" @click="showColorPresetModal = true">
70
+
71
+ <span>颜色配置</span>
72
+ <svg
73
+ viewBox="0 0 24 24"
74
+ fill="none"
75
+ stroke="currentColor"
76
+ stroke-width="2"
77
+ width="16"
78
+ height="16"
79
+ class="nav-arrow"
80
+ >
81
+ <path d="M9 18l6-6-6-6" />
82
+ </svg>
83
+ </div>
84
+
85
+ <template v-if="experimentalSettings.length > 0">
86
+ <div class="settings-section-divider">
87
+ <span class="settings-section-label">实验性 / 调试设置</span>
88
+ </div>
89
+ <template v-for="item in experimentalSettings" :key="item.key">
90
+ <div class="settings-item experimental">
91
+
92
+ <span>{{ item.label }}</span>
93
+ <template v-if="item.type === 'boolean'">
94
+ <label class="md-switch">
95
+ <input type="checkbox" v-model="settings[item.key]" />
96
+ <span class="md-switch-slider"></span>
97
+ </label>
98
+ </template>
99
+ <template v-else-if="item.type === 'select' && item.options">
100
+ <Dropdown
101
+ :model-value="String(settings[item.key])"
102
+ :options="item.options"
103
+ size="sm"
104
+ min-width="100px"
105
+ @update:model-value="settings[item.key] = $event"
106
+ />
107
+ </template>
176
108
  </div>
177
- </Transition>
109
+ </template>
110
+ </template>
111
+ </div>
112
+
113
+ <template #footer>
114
+ <button class="settings-btn reset" @click="resetSettings">
115
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
116
+ <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
117
+ <path d="M3 3v5h5" />
118
+ </svg>
119
+ 重置
120
+ </button>
121
+ <div class="footer-right">
122
+ <button class="settings-btn cancel" @click="closeSettings">取消</button>
123
+ <button class="settings-btn confirm" @click="confirmSettings">
124
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
125
+ <path d="M20 6L9 17l-5-5" />
126
+ </svg>
127
+ 确定
128
+ </button>
178
129
  </div>
179
- </Transition>
180
- </Teleport>
130
+ </template>
131
+ </BaseModal>
132
+
133
+ <!-- 嵌套颜色预设弹窗 -->
134
+ <BaseModal
135
+ :show="showColorPresetModal"
136
+ title="颜色预设"
137
+ subtitle="自定义图表颜色"
138
+ width="min(92vw, 460px)"
139
+ max-height="min(720px, calc(100vh - 48px))"
140
+ :z-index="1100"
141
+ footer-align="space-between"
142
+ @close="showColorPresetModal = false"
143
+ >
144
+ <ColorPresetPanel
145
+ ref="colorPresetPanelRef"
146
+ :color-preset-settings="settings.colorPresetSettings"
147
+ @update:color-preset-settings="settings = { ...settings, colorPresetSettings: $event }"
148
+ />
149
+ <template #footer>
150
+ <button type="button" class="settings-btn reset" @click="colorPresetPanelRef?.resetCurrentThemeColors()">
151
+ 重置颜色
152
+ </button>
153
+ <button type="button" class="settings-btn confirm" @click="showColorPresetModal = false">
154
+ 确认
155
+ </button>
156
+ </template>
157
+ </BaseModal>
181
158
  </template>
182
159
 
183
160
  <script setup lang="ts">
@@ -189,8 +166,8 @@ import {
189
166
  type SettingItem,
190
167
  } from '@363045841yyt/klinechart-core/config'
191
168
  import { normalizeColorPresetSettings } from '@363045841yyt/klinechart-core'
169
+ import BaseModal from './BaseModal.vue'
192
170
  import ColorPresetPanel from './ColorPresetPanel.vue'
193
- import { useFullscreenTeleportTarget } from '../composables/useFullscreenTeleportTarget'
194
171
  import Dropdown from './Dropdown.vue'
195
172
 
196
173
  const props = defineProps<{
@@ -202,8 +179,6 @@ const emit = defineEmits<{
202
179
  (e: 'confirm', settings: ChartSettings): void
203
180
  }>()
204
181
 
205
- const teleportTarget = useFullscreenTeleportTarget()
206
-
207
182
  const mainSettings = computed(
208
183
  () => DEFAULT_SETTINGS.filter((s) => s.group === 'main') as unknown as SettingItem[],
209
184
  )
@@ -215,6 +190,7 @@ const styleSettings = computed(
215
190
  )
216
191
 
217
192
  const showColorPresetModal = ref(false)
193
+ const colorPresetPanelRef = ref<InstanceType<typeof ColorPresetPanel> | null>(null)
218
194
 
219
195
  function loadSettings(): ChartSettings {
220
196
  try {
@@ -267,42 +243,6 @@ function confirmSettings() {
267
243
  </script>
268
244
 
269
245
  <style scoped>
270
- .settings-overlay {
271
- position: fixed;
272
- inset: 0;
273
- background: rgba(0, 0, 0, 0.3);
274
- backdrop-filter: blur(4px);
275
- padding: 24px;
276
- display: flex;
277
- align-items: center;
278
- justify-content: center;
279
- z-index: 1000;
280
- }
281
-
282
- .settings-modal {
283
- background: var(--klc-color-tag-bg-white);
284
- border: 1px solid var(--klc-color-border-button);
285
- border-radius: 10px;
286
- box-shadow: 0 18px 48px rgba(0, 0, 0, 0.15);
287
- min-width: 360px;
288
- max-width: 460px;
289
- width: min(92vw, 460px);
290
- max-height: min(720px, calc(100vh - 48px));
291
- overflow: hidden;
292
- display: flex;
293
- flex-direction: column;
294
- }
295
-
296
- .settings-header {
297
- display: flex;
298
- justify-content: space-between;
299
- align-items: center;
300
- padding: 14px 18px 14px 20px;
301
- background: var(--klc-color-background);
302
- border-bottom: 1px solid var(--klc-color-grid-major);
303
- flex-shrink: 0;
304
- }
305
-
306
246
  .header-left {
307
247
  display: flex;
308
248
  flex-direction: column;
@@ -310,168 +250,139 @@ function confirmSettings() {
310
250
  min-width: 0;
311
251
  }
312
252
 
313
- .header-right {
314
- display: flex;
315
- align-items: center;
316
- gap: 8px;
317
- }
318
-
319
253
  .settings-title {
320
- font-size: 15px;
254
+ font-size: 16px;
321
255
  font-weight: 600;
322
256
  color: var(--klc-color-foreground);
323
- line-height: 1.35;
257
+ line-height: 1.3;
324
258
  }
325
259
 
326
260
  .settings-subtitle {
327
- font-size: 11px;
261
+ font-size: 12px;
328
262
  color: var(--klc-color-axis-text);
329
263
  line-height: 1.3;
330
- }
331
-
332
- .settings-close {
333
- background: var(--klc-color-tag-bg-white);
334
- border: 1px solid var(--klc-color-border-button);
335
- border-radius: 7px;
336
- width: 30px;
337
- height: 30px;
338
- display: flex;
339
- align-items: center;
340
- justify-content: center;
341
- cursor: pointer;
342
- color: var(--klc-color-axis-text);
343
- transition:
344
- background 0.15s,
345
- color 0.15s,
346
- border-color 0.15s;
347
- padding: 0;
348
- }
349
-
350
- .settings-close:hover {
351
- background: var(--klc-color-tag-bg-hover);
352
- color: var(--klc-color-foreground);
353
- border-color: var(--klc-color-axis-line);
354
- }
355
-
356
- .settings-close svg {
357
- width: 14px;
358
- height: 14px;
264
+ font-weight: 400;
359
265
  }
360
266
 
361
267
  .settings-body {
362
- padding: 16px 20px 18px;
363
268
  display: flex;
364
269
  flex-direction: column;
365
- gap: 8px;
366
- overflow-y: auto;
367
- overscroll-behavior: contain;
368
- }
369
-
370
- .settings-body::-webkit-scrollbar {
371
- width: 8px;
372
270
  }
373
271
 
374
- .settings-body::-webkit-scrollbar-thumb {
375
- background: var(--klc-color-axis-line);
376
- border: 2px solid var(--klc-color-tag-bg-white);
377
- border-radius: 999px;
272
+ /* 优化区块小标题 */
273
+ .settings-section-divider {
274
+ display: flex;
275
+ align-items: center;
276
+ margin: 18px 0 6px;
378
277
  }
379
278
 
380
- .settings-item {
381
- padding: 0;
382
- border-radius: 8px;
383
- background: var(--klc-color-background);
384
- border: 1px solid var(--klc-color-grid-major);
385
- transition:
386
- border-color 0.15s,
387
- background 0.15s,
388
- box-shadow 0.15s;
279
+ .settings-section-divider:first-child {
280
+ margin-top: 0;
389
281
  }
390
282
 
391
- .settings-item:hover {
392
- border-color: var(--klc-color-axis-line);
393
- background: var(--klc-color-tag-bg-white);
283
+ .settings-section-label {
284
+ font-size: 12px;
285
+ color: var(--klc-color-axis-text);
286
+ font-weight: 500;
287
+ white-space: nowrap;
288
+ line-height: 1;
289
+ letter-spacing: 0.3px;
394
290
  }
395
291
 
396
- .settings-label {
292
+ /* 扁平化列表项 */
293
+ .settings-item {
397
294
  display: flex;
398
295
  align-items: center;
399
296
  justify-content: space-between;
400
297
  gap: 16px;
401
- min-height: 42px;
402
- padding: 9px 12px;
298
+ min-height: 40px;
299
+ padding: 8px 12px;
300
+ border-radius: 6px;
301
+ cursor: pointer;
403
302
  font-size: 13px;
404
303
  color: var(--klc-color-foreground);
405
- cursor: pointer;
304
+ transition: background 0.15s ease;
406
305
  }
407
306
 
408
- .settings-label > span {
307
+ .settings-item:hover {
308
+ background: var(--klc-color-grid-minor);
309
+ }
310
+
311
+ .settings-item > span {
409
312
  min-width: 0;
410
- line-height: 1.35;
313
+ line-height: 1.4;
411
314
  }
412
315
 
413
- .settings-checkbox {
316
+ /* Material Design 风格开关 */
317
+ .md-switch {
318
+ position: relative;
319
+ display: inline-block;
320
+ width: 36px;
321
+ height: 20px;
414
322
  flex: 0 0 auto;
415
- width: 17px;
416
- height: 17px;
417
- cursor: pointer;
418
- accent-color: var(--klc-color-foreground);
323
+ margin: 0;
419
324
  }
420
325
 
421
- .settings-section-divider {
422
- display: flex;
423
- align-items: center;
424
- gap: 8px;
425
- margin: 10px 0 2px;
326
+ .md-switch input {
327
+ opacity: 0;
328
+ width: 0;
329
+ height: 0;
426
330
  }
427
331
 
428
- .settings-section-divider:first-child {
429
- margin-top: 0;
332
+ .md-switch-slider {
333
+ position: absolute;
334
+ cursor: pointer;
335
+ top: 0;
336
+ left: 0;
337
+ right: 0;
338
+ bottom: 0;
339
+ background-color: rgba(128, 128, 128, 0.4);
340
+ transition: 0.3s;
341
+ border-radius: 20px;
430
342
  }
431
343
 
432
- .settings-section-divider::before,
433
- .settings-section-divider::after {
344
+ .md-switch-slider::before {
345
+ position: absolute;
434
346
  content: '';
435
- flex: 1;
436
- border-top: 1px solid var(--klc-color-border-button);
347
+ height: 16px;
348
+ width: 16px;
349
+ left: 2px;
350
+ bottom: 2px;
351
+ background-color: #e0e0e0;
352
+ transition: 0.3s;
353
+ border-radius: 50%;
354
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
437
355
  }
438
356
 
439
- .settings-section-label {
440
- font-size: 11px;
441
- color: var(--klc-color-axis-text);
442
- white-space: nowrap;
443
- line-height: 1;
357
+ .md-switch input:checked + .md-switch-slider {
358
+ background-color: #3b82f6;
359
+ opacity: 1;
444
360
  }
445
361
 
446
- .nested-overlay {
447
- z-index: 1100;
362
+ .md-switch input:checked + .md-switch-slider::before {
363
+ transform: translateX(16px);
364
+ background-color: #ffffff;
448
365
  }
449
366
 
367
+ /* 导航项交互优化 */
450
368
  .settings-item.nav-item {
451
369
  cursor: pointer;
452
370
  }
453
371
 
454
- .settings-item.nav-item:hover .nav-arrow {
455
- color: var(--klc-color-foreground);
456
- }
457
-
458
372
  .nav-arrow {
459
373
  color: var(--klc-color-axis-text);
460
- transition: color 0.15s;
374
+ transition:
375
+ transform 0.15s,
376
+ color 0.15s;
461
377
  flex-shrink: 0;
462
378
  }
463
379
 
464
- .settings-footer {
465
- display: flex;
466
- align-items: center;
467
- justify-content: space-between;
468
- gap: 12px;
469
- padding: 12px 20px;
470
- background: var(--klc-color-background);
471
- border-top: 1px solid var(--klc-color-grid-major);
472
- flex-shrink: 0;
380
+ .settings-item.nav-item:hover .nav-arrow {
381
+ color: var(--klc-color-foreground);
382
+ transform: translateX(2px);
473
383
  }
474
384
 
385
+ /* 底部按钮 */
475
386
  .footer-right {
476
387
  display: flex;
477
388
  gap: 8px;
@@ -479,57 +390,50 @@ function confirmSettings() {
479
390
  }
480
391
 
481
392
  .settings-btn {
482
- display: flex;
393
+ display: inline-flex;
483
394
  align-items: center;
484
395
  justify-content: center;
485
- gap: 5px;
396
+ gap: 6px;
486
397
  min-width: 68px;
487
- height: 32px;
488
- padding: 0 14px;
489
- border-radius: 7px;
398
+ height: 34px;
399
+ padding: 0 16px;
400
+ border-radius: 6px;
490
401
  font-size: 13px;
491
402
  font-weight: 500;
492
403
  cursor: pointer;
493
404
  border: 1px solid transparent;
494
- transition:
495
- background 0.15s,
496
- border-color 0.15s,
497
- color 0.15s,
498
- box-shadow 0.15s,
499
- transform 0.15s;
405
+ transition: all 0.15s ease;
500
406
  line-height: 1;
501
407
  white-space: nowrap;
502
408
  }
503
409
 
504
410
  .settings-btn svg {
505
- width: 12px;
506
- height: 12px;
411
+ width: 13px;
412
+ height: 13px;
507
413
  flex-shrink: 0;
508
414
  }
509
415
 
510
416
  .settings-btn.reset {
511
417
  background: transparent;
512
- border-color: var(--klc-color-axis-line);
418
+ border-color: var(--klc-color-border-button);
513
419
  color: var(--klc-color-axis-text);
514
- min-width: 76px;
515
420
  }
516
421
 
517
422
  .settings-btn.reset:hover {
518
- border-color: #c0392b;
519
- color: #e74c3c;
520
- background: rgba(231, 76, 60, 0.08);
423
+ border-color: #f0a020;
424
+ color: #f0a020;
425
+ background: rgba(240, 160, 32, 0.08);
521
426
  }
522
427
 
523
428
  .settings-btn.cancel {
524
429
  background: transparent;
525
- border-color: var(--klc-color-axis-line);
526
- color: var(--klc-color-axis-text);
430
+ border-color: var(--klc-color-border-button);
431
+ color: var(--klc-color-foreground);
527
432
  }
528
433
 
529
434
  .settings-btn.cancel:hover {
530
- background: var(--klc-color-tag-bg-hover);
531
- color: var(--klc-color-foreground);
532
- border-color: var(--klc-color-axis-text);
435
+ background: var(--klc-color-grid-minor);
436
+ border-color: var(--klc-color-axis-line);
533
437
  }
534
438
 
535
439
  .settings-btn.confirm {
@@ -539,84 +443,23 @@ function confirmSettings() {
539
443
  }
540
444
 
541
445
  .settings-btn.confirm:hover {
542
- background: var(--klc-color-foreground);
543
- border-color: var(--klc-color-foreground);
544
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);
545
- transform: translateY(-1px);
446
+ opacity: 0.9;
447
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
546
448
  }
547
449
 
548
450
  .settings-btn.confirm:active {
549
- transform: translateY(0);
550
- box-shadow: none;
551
- }
552
-
553
- .overlay-enter-active,
554
- .overlay-leave-active {
555
- transition: opacity 0.2s ease;
556
- }
557
-
558
- .overlay-enter-from,
559
- .overlay-leave-to {
560
- opacity: 0;
561
- }
562
-
563
- .modal-enter-active {
564
- transition: all 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
565
- }
566
-
567
- .modal-leave-active {
568
- transition: all 0.16s ease-in;
569
- }
570
-
571
- .modal-enter-from {
572
- opacity: 0;
573
- transform: scale(0.96) translateY(-10px);
574
- }
575
-
576
- .modal-leave-to {
577
- opacity: 0;
578
- transform: scale(0.98) translateY(8px);
451
+ transform: scale(0.98);
579
452
  }
580
453
 
581
454
  @media (max-width: 480px) {
582
- .settings-overlay {
583
- padding: 12px;
584
- align-items: flex-end;
585
- }
586
-
587
- .settings-modal {
588
- min-width: 0;
589
- width: 100%;
590
- max-height: calc(100vh - 24px);
591
- border-radius: 10px;
592
- }
593
-
594
- .settings-header,
595
- .settings-body,
596
- .settings-footer {
597
- padding-left: 16px;
598
- padding-right: 16px;
599
- }
600
-
601
- .settings-label {
602
- align-items: flex-start;
603
- flex-direction: column;
455
+ .settings-item {
604
456
  gap: 8px;
605
457
  }
606
458
 
607
- .settings-checkbox {
608
- align-self: flex-end;
609
- margin-top: -26px;
610
- }
611
-
612
- .settings-footer {
613
- align-items: stretch;
614
- flex-direction: column-reverse;
615
- }
616
-
617
459
  .footer-right {
618
460
  display: grid;
619
461
  grid-template-columns: 1fr 1fr;
462
+ width: 100%;
620
463
  }
621
464
 
622
465
  .settings-btn {