vome-core 0.1.25 → 0.1.27
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/dist/admin/config/plugin-dev.js +1 -1
- package/dist/admin/crud/components/vm-color-picker.vue +355 -15
- package/dist/admin/crud/components/vm-richtext.vue +180 -236
- package/dist/admin/crud/config.js +1 -1
- package/dist/admin/crud/confirm.js +1 -1
- package/dist/admin/crud/dict.js +1 -1
- package/dist/admin/crud/key.js +1 -1
- package/dist/admin/crud/mitt.js +1 -1
- package/dist/admin/crud/plugins.js +1 -1
- package/dist/admin/crud/span.js +1 -1
- package/dist/admin/crud/style.js +1 -1
- package/dist/admin/crud/validate.js +1 -1
- package/dist/admin/directives/perm.js +1 -1
- package/dist/admin/hooks/useUpload.js +1 -1
- package/dist/admin/lib/browser.js +1 -1
- package/dist/admin/lib/cn.js +1 -1
- package/dist/admin/lib/dialog-float.js +1 -1
- package/dist/admin/lib/export-excel.js +1 -1
- package/dist/admin/lib/import-excel.js +1 -1
- package/dist/admin/lib/json.js +1 -1
- package/dist/admin/lib/menu.js +1 -1
- package/dist/admin/lib/tree.js +1 -1
- package/dist/admin/lib/upload.js +1 -1
- package/dist/admin/lib/video-frame.js +1 -1
- package/dist/index.js +1 -1
- package/dist/server/index.js +1 -1
- package/dist/shared/excel.js +1 -1
- package/dist/shared/index.js +1 -1
- package/dist/shared/locale-json.js +1 -1
- package/dist/shared/tree.js +1 -1
- package/package.json +9 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const _0x245ea6=_0x5738;(function(_0x217bd0,_0x3783bd){const _0x8ef90f=_0x5738,_0x24f6a2=_0x217bd0();while(!![]){try{const _0x19b1e6=parseInt(_0x8ef90f(0x178))/0x1+-parseInt(_0x8ef90f(0x193))/0x2+parseInt(_0x8ef90f(0x189))/0x3+-parseInt(_0x8ef90f(0x18f))/0x4+parseInt(_0x8ef90f(0x191))/0x5*(-parseInt(_0x8ef90f(0x183))/0x6)+-parseInt(_0x8ef90f(0x190))/0x7*(parseInt(_0x8ef90f(0x17d))/0x8)+parseInt(_0x8ef90f(0x186))/0x9*(parseInt(_0x8ef90f(0x181))/0xa);if(_0x19b1e6===_0x3783bd)break;else _0x24f6a2['push'](_0x24f6a2['shift']());}catch(_0x318829){_0x24f6a2['push'](_0x24f6a2['shift']());}}}(_0x1ba4,0xadcb7));const ORG=_0x245ea6(0x17e);export function serviceUrlFromDocs(_0x518aec){const _0x368b3f=_0x245ea6,_0x12bba5=new URL(_0x518aec),_0x515ef0=_0x12bba5['hostname'][_0x368b3f(0x18c)](/^www\./,'')['replace'](/^service\./,'');return _0x12bba5[_0x368b3f(0x182)]+'//service.'+_0x515ef0;}export function seatApiBaseFromDocs(_0x167144){const _0xd6b169=_0x245ea6;return serviceUrlFromDocs(_0x167144)+_0xd6b169(0x17a);}export function licenseIssueUrlFromDocs(_0x58196e){const _0x84dd57=_0x245ea6;return serviceUrlFromDocs(_0x58196e)+_0x84dd57(0x180);}function _0x1ba4(){const _0x4d745a=['mtGZmJK5mhHjEMPQDa','ChjVDg9JB2W','nte3og1TtwHdzG','5yMn56UVicSG5zco56UV','DM9Tzs1WBhvNAw4TC2vYDMLJzq','mta4z1fTwgn4','z2L0zwu','l2fYy2HPDMuVCMvMCY9OzwfKCY9Tyxn0zxiUEMLW','mZyYnJG3neros2Dctq','zNvSBa','DM9Tzs1WBhvNAw4TzNvSBa','CMvWBgfJzq','5zco5y+W5B6U5BQu55sO6isA5OMl5P6277YilNzVBwxVVjRLKkSGD2vIl++8IE+8Jos7Psb3DwPPzsdMJilOVB3NI6ZNQ4VLIy3NQ6/POBxPNAlJGii','57QV5yMn56UV','ndyXnJe2ohH4ywDSDG','n0XvsfjNwG','nJq3mgnMwNrvwG','Ahr0Chm6lY9NAxrODwiUy29TlW','mJuYota4mNzTs0rbrW','6zkP5A2qic8G5PYn5yQH56UV5O+s5lU26isA5OMl5P6277YilNzVBwxVVjRKU4uGC2vYDMvY77Yj77Ym6ycc5zci5lIk5lYG44cb55+T5l+H44cb5PsV5lUy562j6io95yQB5OMP5Bgv44cc','Ahr0Chm6lY9NAxrLzs5JB20V','DM9Tzs1WBhvNAw4TzNjVBNq','mteYnZC3m0zey2L4sG','yMfJA2vUza','l2fWCc9WBhvNAw5tDg9Yzs9Zzwf0','5A6m5Pw05lIA5yQH5QIH5z2x6isA5OMl5P6277YilNzVBwxVVjRLKkSGC2vYDMvYios4JIb3zwlVViNVViZMNkZLNldLVidLJ5hMIzpLJixLKi7LJ5hLUipJGii','zNjVBNrLBMq','mJmXmZiWohLmDhH6uq','DM9TzwTQ','l3bSDwDPBNmVDxbSB2fK','l2fWCc9WBhvNAw5tDg9Yzs93ywXSzxqVBgLJzw5Zzs9PC3n1zq'];_0x1ba4=function(){return _0x4d745a;};return _0x1ba4();}function giteeArchive(_0x31818e){const _0x3f07f3=_0x245ea6;return _0x3f07f3(0x176)+ORG+'/'+_0x31818e+'/repository/archive/master.zip';}function githubArchive(_0x37a8f5){const _0x51d5ee=_0x245ea6;return _0x51d5ee(0x192)+ORG+'/'+_0x37a8f5+_0x51d5ee(0x188);}function giteeRepo(_0x649b87){return'https://gitee.com/'+ORG+'/'+_0x649b87;}function githubRepo(_0x39d849){return'https://github.com/'+ORG+'/'+_0x39d849;}function _0x5738(_0x3d205a,_0x49a45f){_0x3d205a=_0x3d205a-0x175;const _0x1ba4c1=_0x1ba4();let _0x573808=_0x1ba4c1[_0x3d205a];if(_0x5738['BzNZAs']===undefined){var _0x32c628=function(_0x3248e0){const _0x9056ea='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x518aec='',_0x12bba5='';for(let _0x515ef0=0x0,_0x167144,_0x58196e,_0x31818e=0x0;_0x58196e=_0x3248e0['charAt'](_0x31818e++);~_0x58196e&&(_0x167144=_0x515ef0%0x4?_0x167144*0x40+_0x58196e:_0x58196e,_0x515ef0++%0x4)?_0x518aec+=String['fromCharCode'](0xff&_0x167144>>(-0x2*_0x515ef0&0x6)):0x0){_0x58196e=_0x9056ea['indexOf'](_0x58196e);}for(let _0x37a8f5=0x0,_0x649b87=_0x518aec['length'];_0x37a8f5<_0x649b87;_0x37a8f5++){_0x12bba5+='%'+('00'+_0x518aec['charCodeAt'](_0x37a8f5)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x12bba5);};_0x5738['UlgIzL']=_0x32c628,_0x5738['zMFEqs']={},_0x5738['BzNZAs']=!![];}const _0x956bbb=_0x1ba4c1[0x0],_0x506e04=_0x3d205a+_0x956bbb,_0x1be382=_0x5738['zMFEqs'][_0x506e04];return!_0x1be382?(_0x573808=_0x5738['UlgIzL'](_0x573808),_0x5738['zMFEqs'][_0x506e04]=_0x573808):_0x573808=_0x1be382,_0x573808;}const docsUrl='https://vomekj.com';export const pluginDev={'docsUrl':docsUrl,'serviceUrl':serviceUrlFromDocs(docsUrl),'uploadUrl':docsUrl+_0x245ea6(0x17f),'mirrors':{'prefer':_0x245ea6(0x187),'giteeOrg':_0x245ea6(0x176)+ORG,'githubOrg':_0x245ea6(0x192)+ORG},'scaffolds':{'full':{'key':_0x245ea6(0x18a),'title':_0x245ea6(0x184),'desc':_0x245ea6(0x17b),'repo':'vome-plugin-full','repoUrl':giteeRepo(_0x245ea6(0x18b)),'githubRepoUrl':githubRepo(_0x245ea6(0x18b)),'downloadUrl':giteeArchive('vome-plugin-full'),'githubDownloadUrl':githubArchive(_0x245ea6(0x18b))},'backend':{'key':_0x245ea6(0x179),'title':'纯后端','desc':_0x245ea6(0x175),'repo':_0x245ea6(0x185),'repoUrl':giteeRepo(_0x245ea6(0x185)),'githubRepoUrl':githubRepo('vome-plugin-service'),'downloadUrl':giteeArchive(_0x245ea6(0x185)),'githubDownloadUrl':githubArchive(_0x245ea6(0x185))},'frontend':{'key':_0x245ea6(0x17c),'title':_0x245ea6(0x18e),'desc':_0x245ea6(0x18d),'repo':'vome-plugin-front','repoUrl':giteeRepo(_0x245ea6(0x177)),'githubRepoUrl':githubRepo(_0x245ea6(0x177)),'downloadUrl':giteeArchive(_0x245ea6(0x177)),'githubDownloadUrl':githubArchive(_0x245ea6(0x177))}}};
|
|
@@ -21,15 +21,16 @@
|
|
|
21
21
|
<input
|
|
22
22
|
type="text"
|
|
23
23
|
class="vm-color-picker__input"
|
|
24
|
-
:value="
|
|
24
|
+
:value="inlineDisplay"
|
|
25
25
|
:placeholder="placeholderText"
|
|
26
26
|
:disabled="disabled"
|
|
27
27
|
spellcheck="false"
|
|
28
28
|
autocomplete="off"
|
|
29
|
+
:title="isThemeBound ? themeBoundLabel : undefined"
|
|
29
30
|
@input="onInlineInput"
|
|
30
31
|
@focus="openPanel"
|
|
31
32
|
@blur="onInlineBlur"
|
|
32
|
-
@keydown.esc.stop="
|
|
33
|
+
@keydown.esc.stop="onEscEnd"
|
|
33
34
|
/>
|
|
34
35
|
|
|
35
36
|
<Teleport to="body">
|
|
@@ -47,6 +48,69 @@
|
|
|
47
48
|
@pointerdown.stop
|
|
48
49
|
@mousedown.stop
|
|
49
50
|
>
|
|
51
|
+
<div class="vm-color-picker__toolbar">
|
|
52
|
+
<div
|
|
53
|
+
v-if="hasThemeOptions"
|
|
54
|
+
class="vm-color-picker__modes"
|
|
55
|
+
role="tablist"
|
|
56
|
+
>
|
|
57
|
+
<button
|
|
58
|
+
type="button"
|
|
59
|
+
class="vm-color-picker__mode"
|
|
60
|
+
:class="{ 'is-on': panelMode === 'theme' }"
|
|
61
|
+
role="tab"
|
|
62
|
+
@click="panelMode = 'theme'"
|
|
63
|
+
>
|
|
64
|
+
主题
|
|
65
|
+
</button>
|
|
66
|
+
<button
|
|
67
|
+
type="button"
|
|
68
|
+
class="vm-color-picker__mode"
|
|
69
|
+
:class="{ 'is-on': panelMode === 'picker' }"
|
|
70
|
+
role="tab"
|
|
71
|
+
@click="panelMode = 'picker'"
|
|
72
|
+
>
|
|
73
|
+
取色器
|
|
74
|
+
</button>
|
|
75
|
+
</div>
|
|
76
|
+
<span v-else class="vm-color-picker__toolbar-spacer" />
|
|
77
|
+
<button
|
|
78
|
+
type="button"
|
|
79
|
+
class="vm-color-picker__close"
|
|
80
|
+
title="关闭"
|
|
81
|
+
aria-label="关闭"
|
|
82
|
+
@click="closePanel"
|
|
83
|
+
>
|
|
84
|
+
<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true">
|
|
85
|
+
<path
|
|
86
|
+
fill="currentColor"
|
|
87
|
+
d="M6.4 19 5 17.6 10.6 12 5 6.4 6.4 5 12 10.6 17.6 5 19 6.4 13.4 12 19 17.6 17.6 19 12 13.4 6.4 19Z"
|
|
88
|
+
/>
|
|
89
|
+
</svg>
|
|
90
|
+
</button>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<div v-if="panelMode === 'theme' && hasThemeOptions" class="vm-color-picker__theme">
|
|
94
|
+
<button
|
|
95
|
+
v-for="opt in themeOptions"
|
|
96
|
+
:key="opt.key"
|
|
97
|
+
type="button"
|
|
98
|
+
class="vm-color-picker__theme-item"
|
|
99
|
+
:class="{ 'is-on': themeBoundKey === opt.key }"
|
|
100
|
+
@click="pickTheme(opt.key)"
|
|
101
|
+
>
|
|
102
|
+
<span
|
|
103
|
+
class="vm-color-picker__theme-swatch"
|
|
104
|
+
:style="{ background: opt.value }"
|
|
105
|
+
/>
|
|
106
|
+
<span class="vm-color-picker__theme-meta">
|
|
107
|
+
<span class="vm-color-picker__theme-label">{{ opt.label }}</span>
|
|
108
|
+
<span class="vm-color-picker__theme-key">{{ opt.key }}</span>
|
|
109
|
+
</span>
|
|
110
|
+
</button>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<template v-else>
|
|
50
114
|
<div
|
|
51
115
|
ref="svRef"
|
|
52
116
|
class="vm-color-picker__sv"
|
|
@@ -154,7 +218,7 @@
|
|
|
154
218
|
autocomplete="off"
|
|
155
219
|
@input="onPanelValueInput"
|
|
156
220
|
@blur="onPanelValueBlur"
|
|
157
|
-
@keydown.esc.stop="
|
|
221
|
+
@keydown.esc.stop="onEscEnd"
|
|
158
222
|
/>
|
|
159
223
|
<input
|
|
160
224
|
type="text"
|
|
@@ -164,9 +228,10 @@
|
|
|
164
228
|
autocomplete="off"
|
|
165
229
|
@input="onAlphaPctInput"
|
|
166
230
|
@blur="onAlphaPctBlur"
|
|
167
|
-
@keydown.esc.stop="
|
|
231
|
+
@keydown.esc.stop="onEscEnd"
|
|
168
232
|
/>
|
|
169
233
|
</div>
|
|
234
|
+
</template>
|
|
170
235
|
</div>
|
|
171
236
|
</FocusScope>
|
|
172
237
|
</Teleport>
|
|
@@ -179,16 +244,26 @@ import { FocusScope } from 'reka-ui'
|
|
|
179
244
|
|
|
180
245
|
defineOptions({ name: 'vm-color-picker' })
|
|
181
246
|
|
|
247
|
+
/** 主题色选项(有则显示「主题 / 取色器」) */
|
|
248
|
+
export type VmColorThemeOption = {
|
|
249
|
+
key: string
|
|
250
|
+
label: string
|
|
251
|
+
/** 当前模式下的预览色 */
|
|
252
|
+
value: string
|
|
253
|
+
}
|
|
254
|
+
|
|
182
255
|
const props = withDefaults(
|
|
183
256
|
defineProps<{
|
|
184
257
|
modelValue?: string | null
|
|
185
258
|
disabled?: boolean
|
|
186
259
|
placeholder?: string
|
|
187
260
|
size?: 'default' | 'sm'
|
|
261
|
+
themeOptions?: VmColorThemeOption[]
|
|
188
262
|
}>(),
|
|
189
263
|
{
|
|
190
264
|
placeholder: '#000000',
|
|
191
265
|
size: 'default',
|
|
266
|
+
themeOptions: () => [],
|
|
192
267
|
},
|
|
193
268
|
)
|
|
194
269
|
|
|
@@ -201,6 +276,19 @@ type Rgba = { r: number; g: number; b: number; a: number }
|
|
|
201
276
|
type Hsv = { h: number; s: number; v: number }
|
|
202
277
|
type ColorFormat = 'hex' | 'rgb' | 'css' | 'hsl' | 'hsb'
|
|
203
278
|
|
|
279
|
+
function parseCssVarRef(raw: string): string | null {
|
|
280
|
+
const s = String(raw || '').trim()
|
|
281
|
+
const m = s.match(/^var\(\s*--([a-zA-Z0-9_-]+)\s*(?:,[^)]*)?\)$/i)
|
|
282
|
+
return m ? m[1]! : null
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function toCssVarRef(key: string): string {
|
|
286
|
+
const k = String(key || '')
|
|
287
|
+
.trim()
|
|
288
|
+
.replace(/^--/, '')
|
|
289
|
+
return k ? `var(--${k})` : ''
|
|
290
|
+
}
|
|
291
|
+
|
|
204
292
|
const FORMAT_OPTS: { id: ColorFormat; label: string }[] = [
|
|
205
293
|
{ id: 'hex', label: 'Hex' },
|
|
206
294
|
{ id: 'rgb', label: 'RGB' },
|
|
@@ -223,6 +311,8 @@ const suppressOpen = ref(false)
|
|
|
223
311
|
const panelStyle = ref<Record<string, string>>({})
|
|
224
312
|
const formatOpen = ref(false)
|
|
225
313
|
const colorFormat = ref<ColorFormat>('hex')
|
|
314
|
+
/** 面板:主题变量 | 取色器 */
|
|
315
|
+
const panelMode = ref<'theme' | 'picker'>('picker')
|
|
226
316
|
|
|
227
317
|
const hue = ref(0)
|
|
228
318
|
const sat = ref(0)
|
|
@@ -236,6 +326,38 @@ const alphaPctText = ref('100%')
|
|
|
236
326
|
|
|
237
327
|
const hasEyeDropper = ref(false)
|
|
238
328
|
|
|
329
|
+
const themeOptions = computed(() => props.themeOptions || [])
|
|
330
|
+
const hasThemeOptions = computed(() => themeOptions.value.length > 0)
|
|
331
|
+
const themeBoundKey = computed(() => parseCssVarRef(props.modelValue ?? ''))
|
|
332
|
+
const isThemeBound = computed(() => Boolean(themeBoundKey.value))
|
|
333
|
+
const themeBoundOpt = computed(() => {
|
|
334
|
+
const k = themeBoundKey.value
|
|
335
|
+
if (!k) return null
|
|
336
|
+
return themeOptions.value.find((o) => o.key === k) || null
|
|
337
|
+
})
|
|
338
|
+
const themeBoundLabel = computed(() => {
|
|
339
|
+
const opt = themeBoundOpt.value
|
|
340
|
+
if (opt) return opt.label
|
|
341
|
+
const k = themeBoundKey.value
|
|
342
|
+
return k ? k : ''
|
|
343
|
+
})
|
|
344
|
+
const inlineDisplay = computed(() => {
|
|
345
|
+
if (isThemeBound.value) {
|
|
346
|
+
return String(props.modelValue || '').trim() || themeBoundLabel.value
|
|
347
|
+
}
|
|
348
|
+
return inlineHex.value
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
/** 行内:主题变量 / mustache,不当作 hex 强行加 # */
|
|
352
|
+
function isInlineExpr(raw: string): boolean {
|
|
353
|
+
const s = String(raw || '').trim()
|
|
354
|
+
if (!s) return false
|
|
355
|
+
if (/\{\{[\s\S]*?\}\}/.test(s)) return true
|
|
356
|
+
if (parseCssVarRef(s)) return true
|
|
357
|
+
if (/^var\s*\(/i.test(s)) return true
|
|
358
|
+
return false
|
|
359
|
+
}
|
|
360
|
+
|
|
239
361
|
const placeholderText = computed(() => {
|
|
240
362
|
const p = props.placeholder || '#000000'
|
|
241
363
|
return p.startsWith('#') ? p.slice(1) : p
|
|
@@ -520,13 +642,33 @@ function formatPanelValue(): string {
|
|
|
520
642
|
}
|
|
521
643
|
|
|
522
644
|
const cssColor = computed(() => {
|
|
523
|
-
const
|
|
524
|
-
if (
|
|
645
|
+
const themePreview = themeBoundOpt.value?.value
|
|
646
|
+
if (themePreview) {
|
|
647
|
+
const parsed = parseColor(themePreview)
|
|
648
|
+
if (parsed) {
|
|
649
|
+
const { r, g, b, a } = parsed
|
|
650
|
+
return a < 1 ? `rgba(${r},${g},${b},${a})` : `rgb(${r},${g},${b})`
|
|
651
|
+
}
|
|
652
|
+
return String(themePreview)
|
|
653
|
+
}
|
|
654
|
+
if (themeBoundKey.value) {
|
|
655
|
+
return `var(--${themeBoundKey.value})`
|
|
656
|
+
}
|
|
657
|
+
const raw = props.modelValue ?? ''
|
|
658
|
+
const parsed = parseColor(raw)
|
|
659
|
+
if (!parsed && !String(raw).trim()) return 'transparent'
|
|
525
660
|
if (!parsed) return 'transparent'
|
|
526
661
|
const { r, g, b, a } = parsed
|
|
527
662
|
return a < 1 ? `rgba(${r},${g},${b},${a})` : `rgb(${r},${g},${b})`
|
|
528
663
|
})
|
|
529
664
|
|
|
665
|
+
function pickTheme(key: string) {
|
|
666
|
+
const ref = toCssVarRef(key)
|
|
667
|
+
if (!ref) return
|
|
668
|
+
commit(ref)
|
|
669
|
+
closePanel()
|
|
670
|
+
}
|
|
671
|
+
|
|
530
672
|
const svBg = computed(() => {
|
|
531
673
|
const { r, g, b } = hsvToRgb(hue.value, 1, 1)
|
|
532
674
|
return `linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, rgb(${Math.round(r)},${Math.round(g)},${Math.round(b)}))`
|
|
@@ -563,6 +705,26 @@ function applyRgba(c: Rgba, emitValue = true) {
|
|
|
563
705
|
|
|
564
706
|
function loadFromModel(raw: string | null | undefined) {
|
|
565
707
|
const s = raw ?? ''
|
|
708
|
+
const varKey = parseCssVarRef(s)
|
|
709
|
+
if (varKey) {
|
|
710
|
+
const opt = themeOptions.value.find((o) => o.key === varKey)
|
|
711
|
+
const preview = opt?.value || ''
|
|
712
|
+
if (preview) {
|
|
713
|
+
const parsed = parseColor(preview)
|
|
714
|
+
if (parsed) {
|
|
715
|
+
const hsv = rgbToHsv(parsed.r, parsed.g, parsed.b)
|
|
716
|
+
hue.value = hsv.h
|
|
717
|
+
sat.value = hsv.s
|
|
718
|
+
val.value = hsv.v
|
|
719
|
+
alpha.value = parsed.a
|
|
720
|
+
syncTextsFromState()
|
|
721
|
+
return
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
inlineHex.value = varKey
|
|
725
|
+
panelValue.value = varKey
|
|
726
|
+
return
|
|
727
|
+
}
|
|
566
728
|
if (!s.trim()) {
|
|
567
729
|
hue.value = 0
|
|
568
730
|
sat.value = 0
|
|
@@ -610,9 +772,15 @@ function commitFromState() {
|
|
|
610
772
|
}
|
|
611
773
|
|
|
612
774
|
function onInlineInput(e: Event) {
|
|
613
|
-
const
|
|
614
|
-
|
|
615
|
-
|
|
775
|
+
const rawInput = (e.target as HTMLInputElement).value
|
|
776
|
+
if (isInlineExpr(rawInput)) {
|
|
777
|
+
inlineHex.value = rawInput
|
|
778
|
+
commit(rawInput.trim())
|
|
779
|
+
return
|
|
780
|
+
}
|
|
781
|
+
const v = rawInput.replace(/^#/, '')
|
|
782
|
+
inlineHex.value = v
|
|
783
|
+
const parsed = parseColor(v)
|
|
616
784
|
if (parsed) {
|
|
617
785
|
parsed.a = alpha.value
|
|
618
786
|
const hsv = rgbToHsv(parsed.r, parsed.g, parsed.b)
|
|
@@ -621,26 +789,44 @@ function onInlineInput(e: Event) {
|
|
|
621
789
|
val.value = hsv.v
|
|
622
790
|
panelValue.value = formatPanelValue()
|
|
623
791
|
commit(currentHex())
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
792
|
+
return
|
|
793
|
+
}
|
|
794
|
+
const raw = v.trim()
|
|
795
|
+
if (!raw) {
|
|
796
|
+
commit('')
|
|
797
|
+
return
|
|
798
|
+
}
|
|
799
|
+
if (/^[0-9a-fA-F]{1,8}$/.test(raw)) {
|
|
800
|
+
commit(`#${raw}`)
|
|
801
|
+
return
|
|
627
802
|
}
|
|
803
|
+
commit(raw)
|
|
628
804
|
}
|
|
629
805
|
|
|
630
806
|
function onInlineBlur() {
|
|
631
807
|
const t = inlineHex.value.trim()
|
|
632
808
|
if (!t) {
|
|
633
809
|
commit('')
|
|
634
|
-
|
|
810
|
+
hue.value = 0
|
|
811
|
+
sat.value = 0
|
|
812
|
+
val.value = 0
|
|
813
|
+
alpha.value = 1
|
|
814
|
+
inlineHex.value = ''
|
|
815
|
+
panelValue.value = ''
|
|
816
|
+
alphaPctText.value = '100%'
|
|
817
|
+
return
|
|
818
|
+
}
|
|
819
|
+
if (isInlineExpr(t)) {
|
|
820
|
+
commit(t)
|
|
635
821
|
return
|
|
636
822
|
}
|
|
637
823
|
const parsed = parseColor(t)
|
|
638
824
|
if (parsed) {
|
|
639
825
|
parsed.a = alpha.value
|
|
640
826
|
applyRgba(parsed, true)
|
|
641
|
-
|
|
642
|
-
loadFromModel(props.modelValue)
|
|
827
|
+
return
|
|
643
828
|
}
|
|
829
|
+
loadFromModel(props.modelValue)
|
|
644
830
|
}
|
|
645
831
|
|
|
646
832
|
function onPanelValueInput(e: Event) {
|
|
@@ -801,6 +987,13 @@ async function openPanel() {
|
|
|
801
987
|
if (props.disabled || suppressOpen.value) return
|
|
802
988
|
loadFromModel(props.modelValue)
|
|
803
989
|
formatOpen.value = false
|
|
990
|
+
if (hasThemeOptions.value) {
|
|
991
|
+
const bound = parseCssVarRef(props.modelValue ?? '')
|
|
992
|
+
const empty = !(props.modelValue ?? '').trim()
|
|
993
|
+
panelMode.value = bound || empty ? 'theme' : 'picker'
|
|
994
|
+
} else {
|
|
995
|
+
panelMode.value = 'picker'
|
|
996
|
+
}
|
|
804
997
|
open.value = true
|
|
805
998
|
await nextTick()
|
|
806
999
|
syncPanelPos()
|
|
@@ -822,6 +1015,13 @@ function closePanel() {
|
|
|
822
1015
|
})
|
|
823
1016
|
}
|
|
824
1017
|
|
|
1018
|
+
/** Esc:收起面板并失焦 */
|
|
1019
|
+
function onEscEnd(e: KeyboardEvent) {
|
|
1020
|
+
closePanel()
|
|
1021
|
+
const el = e.target
|
|
1022
|
+
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) el.blur()
|
|
1023
|
+
}
|
|
1024
|
+
|
|
825
1025
|
async function toggle() {
|
|
826
1026
|
if (props.disabled) return
|
|
827
1027
|
if (open.value) {
|
|
@@ -964,6 +1164,146 @@ onUnmounted(() => {
|
|
|
964
1164
|
overflow: visible;
|
|
965
1165
|
}
|
|
966
1166
|
|
|
1167
|
+
.vm-color-picker__toolbar {
|
|
1168
|
+
display: flex;
|
|
1169
|
+
align-items: center;
|
|
1170
|
+
gap: 8px;
|
|
1171
|
+
margin-bottom: 10px;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
.vm-color-picker__toolbar-spacer {
|
|
1175
|
+
flex: 1;
|
|
1176
|
+
min-width: 0;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
.vm-color-picker__close {
|
|
1180
|
+
display: inline-flex;
|
|
1181
|
+
flex-shrink: 0;
|
|
1182
|
+
align-items: center;
|
|
1183
|
+
justify-content: center;
|
|
1184
|
+
width: 28px;
|
|
1185
|
+
height: 28px;
|
|
1186
|
+
margin: 0;
|
|
1187
|
+
padding: 0;
|
|
1188
|
+
border: 0;
|
|
1189
|
+
border-radius: 6px;
|
|
1190
|
+
background: transparent;
|
|
1191
|
+
color: var(--muted-foreground, #9aa0b0);
|
|
1192
|
+
cursor: pointer;
|
|
1193
|
+
|
|
1194
|
+
&:hover {
|
|
1195
|
+
background: var(--muted, #f4f6fc);
|
|
1196
|
+
color: var(--foreground);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
.vm-color-picker__modes {
|
|
1201
|
+
display: grid;
|
|
1202
|
+
flex: 1;
|
|
1203
|
+
min-width: 0;
|
|
1204
|
+
grid-template-columns: 1fr 1fr;
|
|
1205
|
+
gap: 4px;
|
|
1206
|
+
margin: 0;
|
|
1207
|
+
padding: 3px;
|
|
1208
|
+
border-radius: 8px;
|
|
1209
|
+
background: var(--muted, #f4f6fc);
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
.vm-color-picker__mode {
|
|
1213
|
+
height: 28px;
|
|
1214
|
+
border: 0;
|
|
1215
|
+
border-radius: 6px;
|
|
1216
|
+
background: transparent;
|
|
1217
|
+
color: var(--muted-foreground, #9aa0b0);
|
|
1218
|
+
font-size: 12px;
|
|
1219
|
+
font-weight: 600;
|
|
1220
|
+
cursor: pointer;
|
|
1221
|
+
|
|
1222
|
+
&.is-on {
|
|
1223
|
+
background: var(--card, #fff);
|
|
1224
|
+
color: var(--foreground);
|
|
1225
|
+
box-shadow: 0 1px 2px rgb(0 0 0 / 6%);
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
.vm-color-picker__theme {
|
|
1230
|
+
display: flex;
|
|
1231
|
+
flex-direction: column;
|
|
1232
|
+
gap: 4px;
|
|
1233
|
+
max-height: 280px;
|
|
1234
|
+
overflow: auto;
|
|
1235
|
+
margin: 0 -4px;
|
|
1236
|
+
padding: 0 4px;
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
.vm-color-picker__theme-item {
|
|
1240
|
+
display: flex;
|
|
1241
|
+
align-items: center;
|
|
1242
|
+
gap: 10px;
|
|
1243
|
+
width: 100%;
|
|
1244
|
+
margin: 0;
|
|
1245
|
+
padding: 8px;
|
|
1246
|
+
border: 1px solid transparent;
|
|
1247
|
+
border-radius: 8px;
|
|
1248
|
+
background: transparent;
|
|
1249
|
+
text-align: left;
|
|
1250
|
+
cursor: pointer;
|
|
1251
|
+
color: inherit;
|
|
1252
|
+
|
|
1253
|
+
&:hover {
|
|
1254
|
+
background: color-mix(in srgb, var(--brand, #4e5dff) 8%, transparent);
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
&.is-on {
|
|
1258
|
+
border-color: color-mix(in srgb, var(--brand, #4e5dff) 45%, transparent);
|
|
1259
|
+
background: color-mix(in srgb, var(--brand, #4e5dff) 10%, transparent);
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
.vm-color-picker__theme-swatch {
|
|
1264
|
+
flex-shrink: 0;
|
|
1265
|
+
width: 22px;
|
|
1266
|
+
height: 22px;
|
|
1267
|
+
border-radius: 6px;
|
|
1268
|
+
border: 1px solid var(--border, #e8ebf5);
|
|
1269
|
+
background-image:
|
|
1270
|
+
linear-gradient(45deg, #ccc 25%, transparent 25%),
|
|
1271
|
+
linear-gradient(-45deg, #ccc 25%, transparent 25%),
|
|
1272
|
+
linear-gradient(45deg, transparent 75%, #ccc 75%),
|
|
1273
|
+
linear-gradient(-45deg, transparent 75%, #ccc 75%);
|
|
1274
|
+
background-size: 8px 8px;
|
|
1275
|
+
background-position:
|
|
1276
|
+
0 0,
|
|
1277
|
+
0 4px,
|
|
1278
|
+
4px -4px,
|
|
1279
|
+
-4px 0;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
.vm-color-picker__theme-meta {
|
|
1283
|
+
min-width: 0;
|
|
1284
|
+
display: flex;
|
|
1285
|
+
flex-direction: column;
|
|
1286
|
+
gap: 2px;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
.vm-color-picker__theme-label {
|
|
1290
|
+
font-size: 13px;
|
|
1291
|
+
font-weight: 600;
|
|
1292
|
+
line-height: 1.2;
|
|
1293
|
+
overflow: hidden;
|
|
1294
|
+
text-overflow: ellipsis;
|
|
1295
|
+
white-space: nowrap;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
.vm-color-picker__theme-key {
|
|
1299
|
+
font-size: 11px;
|
|
1300
|
+
color: var(--muted-foreground, #9aa0b0);
|
|
1301
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
1302
|
+
overflow: hidden;
|
|
1303
|
+
text-overflow: ellipsis;
|
|
1304
|
+
white-space: nowrap;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
967
1307
|
.vm-color-picker__sv {
|
|
968
1308
|
position: relative;
|
|
969
1309
|
width: 100%;
|