mirror of
https://github.com/EstrellaXD/Auto_Bangumi.git
synced 2026-11-06 07:29:09 +08:00
fix(webui): restore config page — naive-ui theme crash and missing controls
Two regressions from the component-system unification left the Config
page blank or control-less:
- App.vue passed var(--color-danger) as common.errorColor*; naive-ui
runs JS color math (seemly rgba) on these tokens and threw
"Invalid color value var(...)" while rendering NSelect, killing the
whole page subtree. Error colors are now per-theme literals.
- ab-setting.vue still referenced the deleted AbSwitch/AbSelect
primitives, which auto-resolution silently rendered as nothing —
every switch/select in settings vanished. Replaced with themed
NSwitch/NSelect plus an items→options adapter for the old API.
- Bumped naive-ui 2.39→2.44: 2.39 predates Vue 3.5 and crashed NTag
rendering inside NDynamicTags ("theme.self undefined").
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTnuEgR78cBk32bLNKar3z
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
"@vueuse/components": "^10.11.1",
|
||||
"@vueuse/core": "^10.11.1",
|
||||
"axios": "^1.7.9",
|
||||
"naive-ui": "^2.39.0",
|
||||
"naive-ui": "^2.44.1",
|
||||
"pinia": "^2.2.2",
|
||||
"vue": "^3.5.8",
|
||||
"vue-i18n": "^9.14.2",
|
||||
|
||||
75
webui/pnpm-lock.yaml
generated
75
webui/pnpm-lock.yaml
generated
@@ -21,8 +21,8 @@ importers:
|
||||
specifier: ^1.7.9
|
||||
version: 1.18.1
|
||||
naive-ui:
|
||||
specifier: ^2.39.0
|
||||
version: 2.39.0(vue@3.5.8(typescript@4.9.5))
|
||||
specifier: ^2.44.1
|
||||
version: 2.44.1(vue@3.5.8(typescript@4.9.5))
|
||||
pinia:
|
||||
specifier: ^2.2.2
|
||||
version: 2.2.2(typescript@4.9.5)(vue@3.5.8(typescript@4.9.5))
|
||||
@@ -1912,12 +1912,12 @@ packages:
|
||||
'@types/json5@0.0.29':
|
||||
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
||||
|
||||
'@types/katex@0.16.7':
|
||||
resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==}
|
||||
|
||||
'@types/lodash-es@4.17.12':
|
||||
resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
|
||||
|
||||
'@types/lodash@4.17.24':
|
||||
resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==}
|
||||
|
||||
'@types/lodash@4.17.7':
|
||||
resolution: {integrity: sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==}
|
||||
|
||||
@@ -2794,14 +2794,13 @@ packages:
|
||||
resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
date-fns-tz@2.0.1:
|
||||
resolution: {integrity: sha512-fJCG3Pwx8HUoLhkepdsP7Z5RsucUi+ZBOxyM5d0ZZ6c4SdYustq0VMmOu6Wf7bli+yS/Jwp91TOCqn9jMcVrUA==}
|
||||
date-fns-tz@3.2.0:
|
||||
resolution: {integrity: sha512-sg8HqoTEulcbbbVXeg84u5UnlsQa8GS5QXMqjjYIhS4abEVVKIUwe0/l/UhrZdKaL/W5eWZNlbTeEIiOXTcsBQ==}
|
||||
peerDependencies:
|
||||
date-fns: 2.x
|
||||
date-fns: ^3.0.0 || ^4.0.0
|
||||
|
||||
date-fns@2.30.0:
|
||||
resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
|
||||
engines: {node: '>=0.11'}
|
||||
date-fns@4.4.0:
|
||||
resolution: {integrity: sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==}
|
||||
|
||||
date-time@3.1.0:
|
||||
resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==}
|
||||
@@ -4367,8 +4366,9 @@ packages:
|
||||
muggle-string@0.3.1:
|
||||
resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==}
|
||||
|
||||
naive-ui@2.39.0:
|
||||
resolution: {integrity: sha512-5oUJzRG+rtLSH8eRU+fJvVYiQids2BxF9jp+fwGoAqHOptEINrBlgBu9uy+95RHE5FLJ7Q/z41o+qkoGnUrKxQ==}
|
||||
naive-ui@2.44.1:
|
||||
resolution: {integrity: sha512-reo8Esw0p58liZwbUutC7meW24Xbn3EwNv91zReWKm2W4JPu+zfgJRn/F7aO0BFmvN+h2brA2M5lRvYqLq4kuA==}
|
||||
engines: {node: '>=20'}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
|
||||
@@ -5158,8 +5158,8 @@ packages:
|
||||
scule@1.3.0:
|
||||
resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==}
|
||||
|
||||
seemly@0.3.8:
|
||||
resolution: {integrity: sha512-MW8Qs6vbzo0pHmDpFSYPna+lwpZ6Zk1ancbajw/7E8TKtHdV+1DfZZD+kKJEhG/cAoB/i+LiT+5msZOqj0DwRA==}
|
||||
seemly@0.3.10:
|
||||
resolution: {integrity: sha512-2+SMxtG1PcsL0uyhkumlOU6Qo9TAQ/WyH7tthnPIOQB05/12jz9naq6GZ6iZ6ApVsO3rr2gsnTf3++OV63kE1Q==}
|
||||
|
||||
semver@5.7.2:
|
||||
resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
|
||||
@@ -5926,8 +5926,8 @@ packages:
|
||||
peerDependencies:
|
||||
vue: ^3.0.1
|
||||
|
||||
vueuc@0.4.63:
|
||||
resolution: {integrity: sha512-QJT0z9yYWXdKpUq6f6IrAgJ83e34iTYMCVHjcAP8lCjldG0JzHnDfJYMpPWkNuLB5SdBZCbYGmYTKnTR+ff7CQ==}
|
||||
vueuc@0.4.65:
|
||||
resolution: {integrity: sha512-lXuMl+8gsBmruudfxnMF9HW4be8rFziylXFu1VHVNbLVhRTXXV4njvpRuJapD/8q+oFEMSfQMH16E/85VoWRyQ==}
|
||||
peerDependencies:
|
||||
vue: ^3.0.11
|
||||
|
||||
@@ -8511,11 +8511,11 @@ snapshots:
|
||||
|
||||
'@types/json5@0.0.29': {}
|
||||
|
||||
'@types/katex@0.16.7': {}
|
||||
|
||||
'@types/lodash-es@4.17.12':
|
||||
dependencies:
|
||||
'@types/lodash': 4.17.7
|
||||
'@types/lodash': 4.17.24
|
||||
|
||||
'@types/lodash@4.17.24': {}
|
||||
|
||||
'@types/lodash@4.17.7': {}
|
||||
|
||||
@@ -9620,13 +9620,11 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
is-data-view: 1.0.1
|
||||
|
||||
date-fns-tz@2.0.1(date-fns@2.30.0):
|
||||
date-fns-tz@3.2.0(date-fns@4.4.0):
|
||||
dependencies:
|
||||
date-fns: 2.30.0
|
||||
date-fns: 4.4.0
|
||||
|
||||
date-fns@2.30.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.6
|
||||
date-fns@4.4.0: {}
|
||||
|
||||
date-time@3.1.0:
|
||||
dependencies:
|
||||
@@ -11375,28 +11373,27 @@ snapshots:
|
||||
|
||||
muggle-string@0.3.1: {}
|
||||
|
||||
naive-ui@2.39.0(vue@3.5.8(typescript@4.9.5)):
|
||||
naive-ui@2.44.1(vue@3.5.8(typescript@4.9.5)):
|
||||
dependencies:
|
||||
'@css-render/plugin-bem': 0.15.14(css-render@0.15.14)
|
||||
'@css-render/vue3-ssr': 0.15.14(vue@3.5.8(typescript@4.9.5))
|
||||
'@types/katex': 0.16.7
|
||||
'@types/lodash': 4.17.7
|
||||
'@types/lodash': 4.17.24
|
||||
'@types/lodash-es': 4.17.12
|
||||
async-validator: 4.2.5
|
||||
css-render: 0.15.14
|
||||
csstype: 3.1.3
|
||||
date-fns: 2.30.0
|
||||
date-fns-tz: 2.0.1(date-fns@2.30.0)
|
||||
date-fns: 4.4.0
|
||||
date-fns-tz: 3.2.0(date-fns@4.4.0)
|
||||
evtd: 0.2.4
|
||||
highlight.js: 11.10.0
|
||||
lodash: 4.17.21
|
||||
lodash-es: 4.17.21
|
||||
seemly: 0.3.8
|
||||
seemly: 0.3.10
|
||||
treemate: 0.3.11
|
||||
vdirs: 0.1.8(vue@3.5.8(typescript@4.9.5))
|
||||
vooks: 0.2.12(vue@3.5.8(typescript@4.9.5))
|
||||
vue: 3.5.8(typescript@4.9.5)
|
||||
vueuc: 0.4.63(vue@3.5.8(typescript@4.9.5))
|
||||
vueuc: 0.4.65(vue@3.5.8(typescript@4.9.5))
|
||||
|
||||
nanoid@3.3.7: {}
|
||||
|
||||
@@ -12193,7 +12190,7 @@ snapshots:
|
||||
|
||||
scule@1.3.0: {}
|
||||
|
||||
seemly@0.3.8: {}
|
||||
seemly@0.3.10: {}
|
||||
|
||||
semver@5.7.2: {}
|
||||
|
||||
@@ -12359,10 +12356,10 @@ snapshots:
|
||||
define-properties: 1.2.1
|
||||
es-abstract: 1.23.3
|
||||
es-errors: 1.3.0
|
||||
es-object-atoms: 1.0.0
|
||||
get-intrinsic: 1.2.4
|
||||
gopd: 1.0.1
|
||||
has-symbols: 1.0.3
|
||||
es-object-atoms: 1.1.2
|
||||
get-intrinsic: 1.3.0
|
||||
gopd: 1.2.0
|
||||
has-symbols: 1.1.0
|
||||
internal-slot: 1.0.7
|
||||
regexp.prototype.flags: 1.5.2
|
||||
set-function-name: 2.0.2
|
||||
@@ -13048,13 +13045,13 @@ snapshots:
|
||||
sortablejs: 1.14.0
|
||||
vue: 3.5.8(typescript@4.9.5)
|
||||
|
||||
vueuc@0.4.63(vue@3.5.8(typescript@4.9.5)):
|
||||
vueuc@0.4.65(vue@3.5.8(typescript@4.9.5)):
|
||||
dependencies:
|
||||
'@css-render/vue3-ssr': 0.15.14(vue@3.5.8(typescript@4.9.5))
|
||||
'@juggle/resize-observer': 3.4.0
|
||||
css-render: 0.15.14
|
||||
evtd: 0.2.4
|
||||
seemly: 0.3.8
|
||||
seemly: 0.3.10
|
||||
vdirs: 0.1.8(vue@3.5.8(typescript@4.9.5))
|
||||
vooks: 0.2.12(vue@3.5.8(typescript@4.9.5))
|
||||
vue: 3.5.8(typescript@4.9.5)
|
||||
|
||||
@@ -17,13 +17,10 @@ if (isLoggedIn.value) {
|
||||
// Button/Select/Switch tokens reference the app's own CSS custom properties
|
||||
// directly (they resolve correctly under both `:root` and `.dark`), so they
|
||||
// don't need to be duplicated between the light/dark override objects below.
|
||||
// 注意:common 里的颜色 token 会进入 naive-ui (seemly) 的 JS 颜色计算,
|
||||
// 写 CSS 变量会抛 "[seemly/rgba]: Invalid color value var(...)" 并让整个
|
||||
// 页面渲染崩溃(Config 页曾因此白屏)——必须用字面量,按主题各写一份。
|
||||
const primitiveOverrides: GlobalThemeOverrides = {
|
||||
common: {
|
||||
errorColor: 'var(--color-danger)',
|
||||
errorColorHover: 'var(--color-danger)',
|
||||
errorColorPressed: 'var(--color-danger)',
|
||||
errorColorSuppl: 'var(--color-danger)',
|
||||
},
|
||||
Button: {
|
||||
borderRadiusTiny: 'var(--radius-sm)',
|
||||
borderRadiusSmall: 'var(--radius-sm)',
|
||||
@@ -38,7 +35,10 @@ const primitiveOverrides: GlobalThemeOverrides = {
|
||||
const lightOverrides: GlobalThemeOverrides = {
|
||||
...primitiveOverrides,
|
||||
common: {
|
||||
...primitiveOverrides.common,
|
||||
errorColor: '#EF4444',
|
||||
errorColorHover: '#DC2626',
|
||||
errorColorPressed: '#B91C1C',
|
||||
errorColorSuppl: '#EF4444',
|
||||
primaryColor: '#6C4AB6',
|
||||
primaryColorHover: '#563A92',
|
||||
primaryColorPressed: '#4A3291',
|
||||
@@ -70,7 +70,10 @@ const lightOverrides: GlobalThemeOverrides = {
|
||||
const darkOverrides: GlobalThemeOverrides = {
|
||||
...primitiveOverrides,
|
||||
common: {
|
||||
...primitiveOverrides.common,
|
||||
errorColor: '#F87171',
|
||||
errorColorHover: '#EF4444',
|
||||
errorColorPressed: '#DC2626',
|
||||
errorColorSuppl: '#F87171',
|
||||
primaryColor: '#8B6CC7',
|
||||
primaryColorHover: '#A78BDB',
|
||||
primaryColorPressed: '#7B5CB7',
|
||||
|
||||
@@ -38,7 +38,7 @@ const abLabel = computed(() => {
|
||||
|
||||
// Make inputs full-width on mobile
|
||||
:deep(input[ab-input]),
|
||||
:deep(.ab-select),
|
||||
:deep(.n-select),
|
||||
:deep(.n-dynamic-tags) {
|
||||
width: 100%;
|
||||
|
||||
|
||||
@@ -1,32 +1,56 @@
|
||||
<script lang="ts" setup>
|
||||
import { NDynamicTags } from 'naive-ui';
|
||||
import type { AbSettingProps } from '#/components';
|
||||
import { NDynamicTags, NSelect, NSwitch } from 'naive-ui';
|
||||
import { isObject } from 'radash';
|
||||
import type { SelectOption } from 'naive-ui';
|
||||
import type { AbSettingProps, SelectItem } from '#/components';
|
||||
|
||||
withDefaults(defineProps<AbSettingProps>(), {
|
||||
const props = withDefaults(defineProps<AbSettingProps>(), {
|
||||
css: '',
|
||||
bottomLine: false,
|
||||
});
|
||||
|
||||
|
||||
|
||||
const data = defineModel<any>('data');
|
||||
|
||||
// 旧 AbSelect 接受 items: Array<SelectItem | string>;NSelect 需要
|
||||
// options: Array<{ label, value }>,这里做一层适配
|
||||
const selectOptions = computed<SelectOption[]>(() => {
|
||||
const items: Array<SelectItem | string> = props.prop?.items ?? [];
|
||||
return items.map((item) =>
|
||||
isObject(item)
|
||||
? { label: item.label ?? item.value, value: item.value }
|
||||
: { label: item, value: item }
|
||||
);
|
||||
});
|
||||
|
||||
// 旧组件允许 v-model 绑定对象(SelectItem);NSelect 只接受基础类型,
|
||||
// 读取时取 .value,写回时保持字符串(配置值均为字符串)
|
||||
const selectValue = computed<string | number | null>({
|
||||
get() {
|
||||
return isObject(data.value) ? (data.value as SelectItem).value : data.value;
|
||||
},
|
||||
set(value) {
|
||||
data.value = value;
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="setting-item">
|
||||
<ab-label :label="label">
|
||||
<AbSwitch
|
||||
<NSwitch
|
||||
v-if="type === 'switch'"
|
||||
v-model:checked="data"
|
||||
v-bind="prop"
|
||||
v-model:value="data"
|
||||
:class="css"
|
||||
></AbSwitch>
|
||||
></NSwitch>
|
||||
|
||||
<AbSelect
|
||||
<NSelect
|
||||
v-else-if="type === 'select'"
|
||||
v-model="data"
|
||||
v-bind="prop"
|
||||
v-model:value="selectValue"
|
||||
:options="selectOptions"
|
||||
:class="css"
|
||||
></AbSelect>
|
||||
class="setting-select"
|
||||
></NSelect>
|
||||
|
||||
<input
|
||||
v-else-if="type === 'input'"
|
||||
@@ -49,6 +73,11 @@ const data = defineModel<any>('data');
|
||||
.setting-item {
|
||||
width: 100%;
|
||||
|
||||
// 无宽度 class 的下拉框给一个下限,避免窄到只剩箭头
|
||||
.setting-select {
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
// Prevent fixed-width inputs from causing horizontal overflow on mobile
|
||||
:deep(input),
|
||||
:deep(select),
|
||||
|
||||
Reference in New Issue
Block a user