diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 84cd712a..b056ec87 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,12 +50,12 @@ jobs: - name: Install Node.js uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 24 - - uses: pnpm/action-setup@v4 + - uses: pnpm/action-setup@v6 name: Install pnpm with: - version: 9 + version: 12.14.0 run_install: false - name: Get pnpm store directory @@ -127,12 +127,12 @@ jobs: - name: Install Node.js uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 24 - - uses: pnpm/action-setup@v4 + - uses: pnpm/action-setup@v6 name: Install pnpm with: - version: 9 + version: 12.14.0 run_install: false - name: Get pnpm store directory diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index b3aed4e6..fd967e48 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -27,14 +27,14 @@ jobs: with: fetch-depth: 0 # lastUpdated 需要完整 git 历史 - - uses: pnpm/action-setup@v4 + - uses: pnpm/action-setup@v6 with: - version: 9 + version: 12.14.0 run_install: false - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 24 cache: pnpm cache-dependency-path: docs/pnpm-lock.yaml diff --git a/.github/workflows/e2e-nightly.yml b/.github/workflows/e2e-nightly.yml index 0c60376b..9b2dab19 100644 --- a/.github/workflows/e2e-nightly.yml +++ b/.github/workflows/e2e-nightly.yml @@ -14,7 +14,7 @@ concurrency: env: E2E_VERSION: 3.3.999-e2e.1 - PNPM_VERSION: 9.11.0 + PNPM_VERSION: 12.14.0 PLAYWRIGHT_VERSION: 1.61.1 jobs: @@ -82,7 +82,7 @@ jobs: python-version: "3.14" - name: Set up pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@v6 with: version: ${{ env.PNPM_VERSION }} run_install: false @@ -90,7 +90,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: "20" + node-version: 24 cache: pnpm cache-dependency-path: webui/pnpm-lock.yaml diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 9a634ee1..c0112ce5 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -13,7 +13,7 @@ concurrency: env: E2E_VERSION: 3.3.999-e2e.1 - PNPM_VERSION: 9.11.0 + PNPM_VERSION: 12.14.0 PLAYWRIGHT_VERSION: 1.61.1 jobs: @@ -57,7 +57,7 @@ jobs: cache-dependency-glob: backend/uv.lock - name: Set up pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@v6 with: version: ${{ env.PNPM_VERSION }} run_install: false @@ -65,7 +65,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: "20" + node-version: 24 cache: pnpm cache-dependency-path: webui/pnpm-lock.yaml @@ -177,7 +177,7 @@ jobs: python-version: "3.14" - name: Set up pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@v6 with: version: ${{ env.PNPM_VERSION }} run_install: false @@ -185,7 +185,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: "20" + node-version: 24 cache: pnpm cache-dependency-path: webui/pnpm-lock.yaml @@ -304,7 +304,7 @@ jobs: cache-dependency-glob: backend/uv.lock - name: Set up pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@v6 with: version: ${{ env.PNPM_VERSION }} run_install: false @@ -312,7 +312,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: "20" + node-version: 24 cache: pnpm cache-dependency-path: webui/pnpm-lock.yaml diff --git a/.github/workflows/plugin-registry.yml b/.github/workflows/plugin-registry.yml index 03d3a2fd..caafd0aa 100644 --- a/.github/workflows/plugin-registry.yml +++ b/.github/workflows/plugin-registry.yml @@ -60,14 +60,14 @@ jobs: with: version: "0.13.x" - &pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@v6 with: - version: 9 + version: 12.14.0 run_install: false - &node uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 24 - &deps name: Install backend run: mkdir -p backend/config && cd backend && uv sync --group dev diff --git a/.gitignore b/.gitignore index 2d7eef35..c35a27fc 100644 --- a/.gitignore +++ b/.gitignore @@ -197,7 +197,6 @@ webui/test-results/ dist.zip dist-ssr *.local -dev-dist # Editor directories and files .vscode/* diff --git a/CLAUDE.md b/CLAUDE.md index 0ea02468..710540d5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -55,7 +55,6 @@ pnpm test:build # Linting and formatting pnpm lint pnpm lint:fix -pnpm format ``` ### Docker @@ -127,7 +126,7 @@ webui/src/ ## Code Style - Python: ruff format (88 char lines), Ruff linter (E, F, I rules), target Python 3.14 -- TypeScript: ESLint + Prettier +- TypeScript: ESLint (@antfu/eslint-config) - Run formatters before committing ## Git Branching diff --git a/DESIGN.md b/DESIGN.md index 2602f2a4..1dbe1c72 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -1,6 +1,6 @@ # Design -Visual system of the AutoBangumi web UI (Vue 3 + naive-ui + UnoCSS). Source of truth for tokens: `webui/src/style/var.scss` (`:root` light, `.dark` overrides). naive-ui components are themed via `GlobalThemeOverrides` in `webui/src/App.vue`, which reference these same CSS custom properties. +Visual system of the AutoBangumi web UI (Vue 3 + naive-ui + UnoCSS). Source of truth for tokens: `webui/src/style/var.scss` (`:root` light, `.dark` overrides). naive-ui components are themed via the `abNaiveTheme` `GlobalThemeOverrides` in `webui/src/style/naive-theme.ts` (provided by the root `NConfigProvider` in `webui/src/App.vue`), which reference these same CSS custom properties. Icons come from `@lucide/vue`. ## Color @@ -52,9 +52,9 @@ Semantic scale only: `--z-dropdown` 10 · `--z-sticky` 20 · `--z-fixed` 30 · ` ## Components -- **Universal `ab-*` layer** (`src/components/basic/`): pages and composites use only `ab-*` components — never raw `NButton`/`NInput`/bare styled ` diff --git a/webui/src/components/basic/ab-empty.stories.ts b/webui/src/components/basic/ab-empty.stories.ts index ebe0b1d3..df6fb136 100644 --- a/webui/src/components/basic/ab-empty.stories.ts +++ b/webui/src/components/basic/ab-empty.stories.ts @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/vue3'; +import type { Meta, StoryObj } from '@storybook/vue3-vite'; import AbEmpty from './ab-empty.vue'; diff --git a/webui/src/components/basic/ab-empty.vue b/webui/src/components/basic/ab-empty.vue index 768feba7..4b7a5916 100644 --- a/webui/src/components/basic/ab-empty.vue +++ b/webui/src/components/basic/ab-empty.vue @@ -1,23 +1,22 @@ diff --git a/webui/src/components/basic/ab-field.stories.ts b/webui/src/components/basic/ab-field.stories.ts index b29c183e..d00905de 100644 --- a/webui/src/components/basic/ab-field.stories.ts +++ b/webui/src/components/basic/ab-field.stories.ts @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/vue3'; +import type { Meta, StoryObj } from '@storybook/vue3-vite'; import AbField from './ab-field.vue'; import AbInput from './ab-input.vue'; diff --git a/webui/src/components/basic/ab-field.vue b/webui/src/components/basic/ab-field.vue index ded8f374..4923e661 100644 --- a/webui/src/components/basic/ab-field.vue +++ b/webui/src/components/basic/ab-field.vue @@ -22,19 +22,12 @@ export const abFieldInjectionKey: InjectionKey = @@ -40,7 +37,7 @@ function onClick(event: MouseEvent) { :disabled="disabled" @click="onClick" > - + diff --git a/webui/src/components/basic/ab-input.stories.ts b/webui/src/components/basic/ab-input.stories.ts index d26d1040..cec71c2d 100644 --- a/webui/src/components/basic/ab-input.stories.ts +++ b/webui/src/components/basic/ab-input.stories.ts @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/vue3'; +import type { Meta, StoryObj } from '@storybook/vue3-vite'; import { ref } from 'vue'; import AbInput from './ab-input.vue'; diff --git a/webui/src/components/basic/ab-input.vue b/webui/src/components/basic/ab-input.vue index 344a3e21..3a956120 100644 --- a/webui/src/components/basic/ab-input.vue +++ b/webui/src/components/basic/ab-input.vue @@ -4,35 +4,26 @@ import { abFieldInjectionKey } from './ab-field.vue'; // 文本输入组件(取代 UnoCSS 的 ab-input 快捷类): // Soft Ink 填充式,左对齐;支持前后缀、清空、密码可见切换、错误态。 -const props = withDefaults( - defineProps<{ - type?: 'text' | 'password' | 'number' | 'url' | 'search'; - placeholder?: string; - disabled?: boolean; - clearable?: boolean; - /** 错误态样式;错误文案由外层 ab-field 显示 */ - error?: boolean; - ariaLabel?: string; - min?: number; - max?: number; - step?: number; - maxlength?: number; - autocomplete?: string; - }>(), - { - type: 'text', - placeholder: '', - disabled: false, - clearable: false, - error: false, - ariaLabel: undefined, - min: undefined, - max: undefined, - step: undefined, - maxlength: undefined, - autocomplete: undefined, - } -); +const { + type = 'text', + placeholder = '', + disabled = false, + clearable = false, + error = false, +} = defineProps<{ + type?: 'text' | 'password' | 'number' | 'url' | 'search'; + placeholder?: string; + disabled?: boolean; + clearable?: boolean; + /** 错误态样式;错误文案由外层 ab-field 显示 */ + error?: boolean; + ariaLabel?: string; + min?: number; + max?: number; + step?: number; + maxlength?: number; + autocomplete?: string; +}>(); const model = defineModel({ default: '' }); @@ -42,15 +33,15 @@ if (field) field.adopted.value = true; const revealed = ref(false); const effectiveType = computed(() => { - if (props.type === 'password') return revealed.value ? 'text' : 'password'; - return props.type; + if (type === 'password') return revealed.value ? 'text' : 'password'; + return type; }); -const invalid = computed(() => props.error || field?.invalid.value === true); +const invalid = computed(() => error || field?.invalid.value === true); function onInput(event: Event) { const value = (event.target as HTMLInputElement).value; - model.value = props.type === 'number' && value !== '' ? Number(value) : value; + model.value = type === 'number' && value !== '' ? Number(value) : value; } function clear() { @@ -67,7 +58,7 @@ function clear() { }" > - + + >