@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.
- package/README.md +6 -1
- package/dist/components/BaseModal.vue.d.ts +54 -0
- package/dist/components/BaseModal.vue.d.ts.map +1 -0
- package/dist/components/BatchStockDialog.vue.d.ts.map +1 -1
- package/dist/components/ChartSettingsDialog.vue.d.ts.map +1 -1
- package/dist/components/ColorPresetPanel.vue.d.ts +4 -1
- package/dist/components/ColorPresetPanel.vue.d.ts.map +1 -1
- package/dist/components/DrawingStyleToolbar.vue.d.ts.map +1 -1
- package/dist/components/ExportProgressDialog.vue.d.ts.map +1 -1
- package/dist/components/IndicatorParams.vue.d.ts.map +1 -1
- package/dist/components/IndicatorSelector.vue.d.ts.map +1 -1
- package/dist/components/KLineChart.vue.d.ts.map +1 -1
- package/dist/components/RangeSelectionExport.vue.d.ts +23 -0
- package/dist/components/RangeSelectionExport.vue.d.ts.map +1 -0
- package/dist/components/common/CanvasToolbar.vue.d.ts +14 -0
- package/dist/components/common/CanvasToolbar.vue.d.ts.map +1 -0
- package/dist/components/common/CanvasToolbarStack.vue.d.ts +14 -0
- package/dist/components/common/CanvasToolbarStack.vue.d.ts.map +1 -0
- package/dist/composables/chart/useRangeSelection.d.ts +1 -0
- package/dist/composables/chart/useRangeSelection.d.ts.map +1 -1
- package/dist/composables/useTeleportedPopup.d.ts.map +1 -1
- package/dist/index.cjs +6 -6
- package/dist/index.css +1 -1
- package/dist/index.js +1293 -1215
- package/dist/web-component.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/BaseModal.vue +292 -0
- package/src/components/BatchStockDialog.vue +15 -180
- package/src/components/ChartSettingsDialog.vue +248 -405
- package/src/components/ColorPresetPanel.vue +58 -106
- package/src/components/CompareSymbolSelector.vue +2 -2
- package/src/components/DrawingStyleToolbar.vue +33 -72
- package/src/components/ExportProgressDialog.vue +25 -133
- package/src/components/IndicatorParams.vue +194 -321
- package/src/components/IndicatorSelector.vue +188 -405
- package/src/components/KLineChart.vue +34 -138
- package/src/components/LeftToolbar.vue +1 -1
- package/src/components/RangeSelectionExport.vue +117 -0
- package/src/components/SymbolSelector.vue +2 -2
- package/src/components/common/CanvasToolbar.vue +70 -0
- package/src/components/common/CanvasToolbarStack.vue +32 -0
- package/src/composables/chart/useRangeSelection.ts +7 -0
- package/src/composables/useTeleportedPopup.ts +15 -2
|
@@ -1,183 +1,160 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
</
|
|
42
|
+
</template>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<div class="settings-section-divider">
|
|
46
|
+
<span class="settings-section-label">样式 / 颜色</span>
|
|
144
47
|
</div>
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
<
|
|
156
|
-
<
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
</
|
|
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
|
-
</
|
|
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
|
-
</
|
|
180
|
-
</
|
|
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:
|
|
254
|
+
font-size: 16px;
|
|
321
255
|
font-weight: 600;
|
|
322
256
|
color: var(--klc-color-foreground);
|
|
323
|
-
line-height: 1.
|
|
257
|
+
line-height: 1.3;
|
|
324
258
|
}
|
|
325
259
|
|
|
326
260
|
.settings-subtitle {
|
|
327
|
-
font-size:
|
|
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
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
272
|
+
/* 优化区块小标题 */
|
|
273
|
+
.settings-section-divider {
|
|
274
|
+
display: flex;
|
|
275
|
+
align-items: center;
|
|
276
|
+
margin: 18px 0 6px;
|
|
378
277
|
}
|
|
379
278
|
|
|
380
|
-
.settings-
|
|
381
|
-
|
|
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-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
-
|
|
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:
|
|
402
|
-
padding:
|
|
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
|
-
|
|
304
|
+
transition: background 0.15s ease;
|
|
406
305
|
}
|
|
407
306
|
|
|
408
|
-
.settings-
|
|
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.
|
|
313
|
+
line-height: 1.4;
|
|
411
314
|
}
|
|
412
315
|
|
|
413
|
-
|
|
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
|
-
|
|
416
|
-
height: 17px;
|
|
417
|
-
cursor: pointer;
|
|
418
|
-
accent-color: var(--klc-color-foreground);
|
|
323
|
+
margin: 0;
|
|
419
324
|
}
|
|
420
325
|
|
|
421
|
-
.
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
margin: 10px 0 2px;
|
|
326
|
+
.md-switch input {
|
|
327
|
+
opacity: 0;
|
|
328
|
+
width: 0;
|
|
329
|
+
height: 0;
|
|
426
330
|
}
|
|
427
331
|
|
|
428
|
-
.
|
|
429
|
-
|
|
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
|
-
.
|
|
433
|
-
|
|
344
|
+
.md-switch-slider::before {
|
|
345
|
+
position: absolute;
|
|
434
346
|
content: '';
|
|
435
|
-
|
|
436
|
-
|
|
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
|
-
.
|
|
440
|
-
|
|
441
|
-
|
|
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
|
-
.
|
|
447
|
-
|
|
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:
|
|
374
|
+
transition:
|
|
375
|
+
transform 0.15s,
|
|
376
|
+
color 0.15s;
|
|
461
377
|
flex-shrink: 0;
|
|
462
378
|
}
|
|
463
379
|
|
|
464
|
-
.settings-
|
|
465
|
-
|
|
466
|
-
|
|
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:
|
|
396
|
+
gap: 6px;
|
|
486
397
|
min-width: 68px;
|
|
487
|
-
height:
|
|
488
|
-
padding: 0
|
|
489
|
-
border-radius:
|
|
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:
|
|
506
|
-
height:
|
|
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-
|
|
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: #
|
|
519
|
-
color: #
|
|
520
|
-
background: rgba(
|
|
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-
|
|
526
|
-
color: var(--klc-color-
|
|
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-
|
|
531
|
-
color: var(--klc-color-
|
|
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
|
-
|
|
543
|
-
|
|
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:
|
|
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-
|
|
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 {
|