feat: 1.0.3 引入 Dark Reader 通用暗色引擎

This commit is contained in:
2026-08-08 17:21:22 +08:00
parent b36ad30d7a
commit 202ab537d1
29 changed files with 19555 additions and 207 deletions
+5
View File
@@ -5,6 +5,11 @@ plugins {
group 'run.halo.darkmode.ui'
node {
// 使用系统安装的 Node.js,避免 Gradle 下载的本地 Node 目录缺失时失败
download = false
}
tasks.register('pnpmBuild', PnpmTask) {
group = 'build'
description = 'Build the UI project using pnpm'
+3 -1
View File
@@ -23,10 +23,10 @@
"@halo-dev/ui-shared": "^2.25.1",
"axios": "^1.13.5",
"canvas-confetti": "^1.9.3",
"darkreader": "file:./vendor/darkreader",
"vue": "^3.5.28"
},
"devDependencies": {
"vite": "^8.0.16",
"@halo-dev/ui-plugin-bundler-kit": "^2.25.1",
"@iconify-json/ri": "^1.2.10",
"@tsconfig/node20": "^20.1.6",
@@ -41,6 +41,7 @@
"eslint": "^9.29.0",
"eslint-plugin-oxlint": "^0.16.12",
"eslint-plugin-vue": "~10.0.1",
"jiti": "^2.7.0",
"jsdom": "^26.1.0",
"npm-run-all2": "^7.0.2",
"oxlint": "^0.16.12",
@@ -48,6 +49,7 @@
"sass": "^1.89.2",
"typescript": "~5.8.3",
"unplugin-icons": "^23.0.1",
"vite": "^8.0.16",
"vitest": "^4.1.0",
"vue-tsc": "^3.3.3"
},
+98 -78
View File
@@ -13,23 +13,26 @@ importers:
version: 2.25.2(axios@1.19.0)
'@halo-dev/components':
specifier: ^2.25.1
version: 2.25.2(vue-router@5.2.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3)))(vue@3.5.41(typescript@5.8.3))
version: 2.25.2(vue-router@5.2.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3)))(vue@3.5.41(typescript@5.8.3))
'@halo-dev/ui-shared':
specifier: ^2.25.1
version: 2.25.2(@tiptap/pm@3.29.2)(axios@1.19.0)(vue-router@5.2.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3)))(vue@3.5.41(typescript@5.8.3))
version: 2.25.2(@tiptap/pm@3.29.2)(axios@1.19.0)(vue-router@5.2.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3)))(vue@3.5.41(typescript@5.8.3))
axios:
specifier: ^1.13.5
version: 1.19.0
canvas-confetti:
specifier: ^1.9.3
version: 1.9.4
darkreader:
specifier: file:./vendor/darkreader
version: file:vendor/darkreader
vue:
specifier: ^3.5.28
version: 3.5.41(typescript@5.8.3)
devDependencies:
'@halo-dev/ui-plugin-bundler-kit':
specifier: ^2.25.1
version: 2.25.2(@rsbuild/core@2.1.10)(@rsbuild/plugin-vue@2.0.1(@rsbuild/core@2.1.10)(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(vue@3.5.41(typescript@5.8.3)))(@vitejs/plugin-vue@6.0.8(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3)))(axios@1.19.0)(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))
version: 2.25.2(@rsbuild/core@2.1.10)(@rsbuild/plugin-vue@2.0.1(@rsbuild/core@2.1.10)(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(vue@3.5.41(typescript@5.8.3)))(@vitejs/plugin-vue@6.0.8(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3)))(axios@1.19.0)(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))
'@iconify-json/ri':
specifier: ^1.2.10
version: 1.2.10
@@ -47,13 +50,13 @@ importers:
version: 24.13.3
'@vitest/eslint-plugin':
specifier: ^1.2.7
version: 1.6.26(@typescript-eslint/eslint-plugin@8.66.0(@typescript-eslint/parser@8.66.0(eslint@9.39.5)(typescript@5.8.3))(eslint@9.39.5)(typescript@5.8.3))(eslint@9.39.5)(typescript@5.8.3)(vitest@4.1.10(@types/node@24.13.3)(jsdom@26.1.0)(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0)))
version: 1.6.26(@typescript-eslint/eslint-plugin@8.66.0(@typescript-eslint/parser@8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)(vitest@4.1.10(@types/node@24.13.3)(jsdom@26.1.0)(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0)))
'@vue/eslint-config-prettier':
specifier: ^10.2.0
version: 10.2.0(eslint@9.39.5)(prettier@3.9.6)
version: 10.2.0(eslint@9.39.5(jiti@2.7.0))(prettier@3.9.6)
'@vue/eslint-config-typescript':
specifier: ^14.5.1
version: 14.9.0(eslint-plugin-vue@10.0.1(eslint@9.39.5)(vue-eslint-parser@10.4.1(eslint@9.39.5)))(eslint@9.39.5)(typescript@5.8.3)
version: 14.9.0(eslint-plugin-vue@10.0.1(eslint@9.39.5(jiti@2.7.0))(vue-eslint-parser@10.4.1(eslint@9.39.5(jiti@2.7.0))))(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)
'@vue/test-utils':
specifier: ^2.4.6
version: 2.4.11(@vue/compiler-dom@3.5.41)(@vue/server-renderer@3.5.41)(vue@3.5.41(typescript@5.8.3))
@@ -62,13 +65,16 @@ importers:
version: 0.7.0(typescript@5.8.3)(vue@3.5.41(typescript@5.8.3))
eslint:
specifier: ^9.29.0
version: 9.39.5
version: 9.39.5(jiti@2.7.0)
eslint-plugin-oxlint:
specifier: ^0.16.12
version: 0.16.12
eslint-plugin-vue:
specifier: ~10.0.1
version: 10.0.1(eslint@9.39.5)(vue-eslint-parser@10.4.1(eslint@9.39.5))
version: 10.0.1(eslint@9.39.5(jiti@2.7.0))(vue-eslint-parser@10.4.1(eslint@9.39.5(jiti@2.7.0)))
jiti:
specifier: ^2.7.0
version: 2.7.0
jsdom:
specifier: ^26.1.0
version: 26.1.0
@@ -92,10 +98,10 @@ importers:
version: 23.0.1(@vue/compiler-sfc@3.5.41)
vite:
specifier: ^8.0.16
version: 8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0)
version: 8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0)
vitest:
specifier: ^4.1.0
version: 4.1.10(@types/node@24.13.3)(jsdom@26.1.0)(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))
version: 4.1.10(@types/node@24.13.3)(jsdom@26.1.0)(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))
vue-tsc:
specifier: ^3.3.3
version: 3.3.9(typescript@5.8.3)
@@ -1079,6 +1085,9 @@ packages:
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
darkreader@file:vendor/darkreader:
resolution: {directory: vendor/darkreader, type: directory}
data-urls@5.0.0:
resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
engines: {node: '>=18'}
@@ -1454,6 +1463,10 @@ packages:
jackspeak@3.4.3:
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
jiti@2.7.0:
resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==}
hasBin: true
js-beautify@1.15.4:
resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==}
engines: {node: '>=14'}
@@ -2427,9 +2440,9 @@ snapshots:
tslib: 2.8.1
optional: true
'@eslint-community/eslint-utils@4.10.1(eslint@9.39.5)':
'@eslint-community/eslint-utils@4.10.1(eslint@9.39.5(jiti@2.7.0))':
dependencies:
eslint: 9.39.5
eslint: 9.39.5(jiti@2.7.0)
eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.12.2': {}
@@ -2488,33 +2501,33 @@ snapshots:
axios: 1.19.0
qs: 6.15.3
'@halo-dev/components@2.25.2(vue-router@5.2.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3)))(vue@3.5.41(typescript@5.8.3))':
'@halo-dev/components@2.25.2(vue-router@5.2.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3)))(vue@3.5.41(typescript@5.8.3))':
dependencies:
floating-vue: 5.2.2(vue@3.5.41(typescript@5.8.3))
vue: 3.5.41(typescript@5.8.3)
vue-router: 5.2.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3))
vue-router: 5.2.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3))
transitivePeerDependencies:
- '@nuxt/kit'
'@halo-dev/ui-plugin-bundler-kit@2.25.2(@rsbuild/core@2.1.10)(@rsbuild/plugin-vue@2.0.1(@rsbuild/core@2.1.10)(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(vue@3.5.41(typescript@5.8.3)))(@vitejs/plugin-vue@6.0.8(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3)))(axios@1.19.0)(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))':
'@halo-dev/ui-plugin-bundler-kit@2.25.2(@rsbuild/core@2.1.10)(@rsbuild/plugin-vue@2.0.1(@rsbuild/core@2.1.10)(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(vue@3.5.41(typescript@5.8.3)))(@vitejs/plugin-vue@6.0.8(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3)))(axios@1.19.0)(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))':
dependencies:
'@halo-dev/api-client': 2.25.2(axios@1.19.0)
'@rsbuild/core': 2.1.10
'@rsbuild/plugin-vue': 2.0.1(@rsbuild/core@2.1.10)(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(vue@3.5.41(typescript@5.8.3))
'@vitejs/plugin-vue': 6.0.8(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3))
'@vitejs/plugin-vue': 6.0.8(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3))
js-yaml: 4.3.1
semver: 7.8.5
vite: 8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0)
vite: 8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0)
transitivePeerDependencies:
- axios
'@halo-dev/ui-shared@2.25.2(@tiptap/pm@3.29.2)(axios@1.19.0)(vue-router@5.2.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3)))(vue@3.5.41(typescript@5.8.3))':
'@halo-dev/ui-shared@2.25.2(@tiptap/pm@3.29.2)(axios@1.19.0)(vue-router@5.2.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3)))(vue@3.5.41(typescript@5.8.3))':
dependencies:
'@halo-dev/api-client': 2.25.2(axios@1.19.0)
'@tiptap/core': 3.29.2(@tiptap/pm@3.29.2)
mitt: 3.0.1
vue: 3.5.41(typescript@5.8.3)
vue-router: 5.2.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3))
vue-router: 5.2.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3))
transitivePeerDependencies:
- '@tiptap/pm'
- axios
@@ -2870,15 +2883,15 @@ snapshots:
'@types/tough-cookie@4.0.5': {}
'@typescript-eslint/eslint-plugin@8.66.0(@typescript-eslint/parser@8.66.0(eslint@9.39.5)(typescript@5.8.3))(eslint@9.39.5)(typescript@5.8.3)':
'@typescript-eslint/eslint-plugin@8.66.0(@typescript-eslint/parser@8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.66.0(eslint@9.39.5)(typescript@5.8.3)
'@typescript-eslint/parser': 8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)
'@typescript-eslint/scope-manager': 8.66.0
'@typescript-eslint/type-utils': 8.66.0(eslint@9.39.5)(typescript@5.8.3)
'@typescript-eslint/utils': 8.66.0(eslint@9.39.5)(typescript@5.8.3)
'@typescript-eslint/type-utils': 8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)
'@typescript-eslint/utils': 8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)
'@typescript-eslint/visitor-keys': 8.66.0
eslint: 9.39.5
eslint: 9.39.5(jiti@2.7.0)
ignore: 7.0.6
natural-compare: 1.4.0
ts-api-utils: 2.5.0(typescript@5.8.3)
@@ -2886,14 +2899,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.66.0(eslint@9.39.5)(typescript@5.8.3)':
'@typescript-eslint/parser@8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.66.0
'@typescript-eslint/types': 8.66.0
'@typescript-eslint/typescript-estree': 8.66.0(typescript@5.8.3)
'@typescript-eslint/visitor-keys': 8.66.0
debug: 4.4.3
eslint: 9.39.5
eslint: 9.39.5(jiti@2.7.0)
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
@@ -2916,13 +2929,13 @@ snapshots:
dependencies:
typescript: 5.8.3
'@typescript-eslint/type-utils@8.66.0(eslint@9.39.5)(typescript@5.8.3)':
'@typescript-eslint/type-utils@8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)':
dependencies:
'@typescript-eslint/types': 8.66.0
'@typescript-eslint/typescript-estree': 8.66.0(typescript@5.8.3)
'@typescript-eslint/utils': 8.66.0(eslint@9.39.5)(typescript@5.8.3)
'@typescript-eslint/utils': 8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)
debug: 4.4.3
eslint: 9.39.5
eslint: 9.39.5(jiti@2.7.0)
ts-api-utils: 2.5.0(typescript@5.8.3)
typescript: 5.8.3
transitivePeerDependencies:
@@ -2945,13 +2958,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.66.0(eslint@9.39.5)(typescript@5.8.3)':
'@typescript-eslint/utils@8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)':
dependencies:
'@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5)
'@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(jiti@2.7.0))
'@typescript-eslint/scope-manager': 8.66.0
'@typescript-eslint/types': 8.66.0
'@typescript-eslint/typescript-estree': 8.66.0(typescript@5.8.3)
eslint: 9.39.5
eslint: 9.39.5(jiti@2.7.0)
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
@@ -2961,21 +2974,21 @@ snapshots:
'@typescript-eslint/types': 8.66.0
eslint-visitor-keys: 5.0.1
'@vitejs/plugin-vue@6.0.8(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3))':
'@vitejs/plugin-vue@6.0.8(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3))':
dependencies:
'@rolldown/pluginutils': 1.0.1
vite: 8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0)
vite: 8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0)
vue: 3.5.41(typescript@5.8.3)
'@vitest/eslint-plugin@1.6.26(@typescript-eslint/eslint-plugin@8.66.0(@typescript-eslint/parser@8.66.0(eslint@9.39.5)(typescript@5.8.3))(eslint@9.39.5)(typescript@5.8.3))(eslint@9.39.5)(typescript@5.8.3)(vitest@4.1.10(@types/node@24.13.3)(jsdom@26.1.0)(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0)))':
'@vitest/eslint-plugin@1.6.26(@typescript-eslint/eslint-plugin@8.66.0(@typescript-eslint/parser@8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)(vitest@4.1.10(@types/node@24.13.3)(jsdom@26.1.0)(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0)))':
dependencies:
'@typescript-eslint/scope-manager': 8.66.0
'@typescript-eslint/utils': 8.66.0(eslint@9.39.5)(typescript@5.8.3)
eslint: 9.39.5
'@typescript-eslint/utils': 8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)
eslint: 9.39.5(jiti@2.7.0)
optionalDependencies:
'@typescript-eslint/eslint-plugin': 8.66.0(@typescript-eslint/parser@8.66.0(eslint@9.39.5)(typescript@5.8.3))(eslint@9.39.5)(typescript@5.8.3)
'@typescript-eslint/eslint-plugin': 8.66.0(@typescript-eslint/parser@8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)
typescript: 5.8.3
vitest: 4.1.10(@types/node@24.13.3)(jsdom@26.1.0)(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))
vitest: 4.1.10(@types/node@24.13.3)(jsdom@26.1.0)(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))
transitivePeerDependencies:
- supports-color
@@ -2988,13 +3001,13 @@ snapshots:
chai: 6.2.2
tinyrainbow: 3.1.1
'@vitest/mocker@4.1.10(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))':
'@vitest/mocker@4.1.10(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))':
dependencies:
'@vitest/spy': 4.1.10
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0)
vite: 8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0)
'@vitest/pretty-format@4.1.10':
dependencies:
@@ -3085,23 +3098,23 @@ snapshots:
'@vue/devtools-shared@8.2.1': {}
'@vue/eslint-config-prettier@10.2.0(eslint@9.39.5)(prettier@3.9.6)':
'@vue/eslint-config-prettier@10.2.0(eslint@9.39.5(jiti@2.7.0))(prettier@3.9.6)':
dependencies:
eslint: 9.39.5
eslint-config-prettier: 10.1.8(eslint@9.39.5)
eslint-plugin-prettier: 5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.5))(eslint@9.39.5)(prettier@3.9.6)
eslint: 9.39.5(jiti@2.7.0)
eslint-config-prettier: 10.1.8(eslint@9.39.5(jiti@2.7.0))
eslint-plugin-prettier: 5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0))(prettier@3.9.6)
prettier: 3.9.6
transitivePeerDependencies:
- '@types/eslint'
'@vue/eslint-config-typescript@14.9.0(eslint-plugin-vue@10.0.1(eslint@9.39.5)(vue-eslint-parser@10.4.1(eslint@9.39.5)))(eslint@9.39.5)(typescript@5.8.3)':
'@vue/eslint-config-typescript@14.9.0(eslint-plugin-vue@10.0.1(eslint@9.39.5(jiti@2.7.0))(vue-eslint-parser@10.4.1(eslint@9.39.5(jiti@2.7.0))))(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)':
dependencies:
'@typescript-eslint/utils': 8.66.0(eslint@9.39.5)(typescript@5.8.3)
eslint: 9.39.5
eslint-plugin-vue: 10.0.1(eslint@9.39.5)(vue-eslint-parser@10.4.1(eslint@9.39.5))
'@typescript-eslint/utils': 8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)
eslint: 9.39.5(jiti@2.7.0)
eslint-plugin-vue: 10.0.1(eslint@9.39.5(jiti@2.7.0))(vue-eslint-parser@10.4.1(eslint@9.39.5(jiti@2.7.0)))
fast-glob: 3.3.3
typescript-eslint: 8.66.0(eslint@9.39.5)(typescript@5.8.3)
vue-eslint-parser: 10.4.1(eslint@9.39.5)
typescript-eslint: 8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)
vue-eslint-parser: 10.4.1(eslint@9.39.5(jiti@2.7.0))
optionalDependencies:
typescript: 5.8.3
transitivePeerDependencies:
@@ -3307,6 +3320,8 @@ snapshots:
csstype@3.2.3: {}
darkreader@file:vendor/darkreader: {}
data-urls@5.0.0:
dependencies:
whatwg-mimetype: 4.0.0
@@ -3366,32 +3381,32 @@ snapshots:
escape-string-regexp@4.0.0: {}
eslint-config-prettier@10.1.8(eslint@9.39.5):
eslint-config-prettier@10.1.8(eslint@9.39.5(jiti@2.7.0)):
dependencies:
eslint: 9.39.5
eslint: 9.39.5(jiti@2.7.0)
eslint-plugin-oxlint@0.16.12:
dependencies:
jsonc-parser: 3.3.1
eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.5))(eslint@9.39.5)(prettier@3.9.6):
eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0))(prettier@3.9.6):
dependencies:
eslint: 9.39.5
eslint: 9.39.5(jiti@2.7.0)
prettier: 3.9.6
prettier-linter-helpers: 1.0.1
synckit: 0.11.13
optionalDependencies:
eslint-config-prettier: 10.1.8(eslint@9.39.5)
eslint-config-prettier: 10.1.8(eslint@9.39.5(jiti@2.7.0))
eslint-plugin-vue@10.0.1(eslint@9.39.5)(vue-eslint-parser@10.4.1(eslint@9.39.5)):
eslint-plugin-vue@10.0.1(eslint@9.39.5(jiti@2.7.0))(vue-eslint-parser@10.4.1(eslint@9.39.5(jiti@2.7.0))):
dependencies:
'@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5)
eslint: 9.39.5
'@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(jiti@2.7.0))
eslint: 9.39.5(jiti@2.7.0)
natural-compare: 1.4.0
nth-check: 2.1.1
postcss-selector-parser: 6.1.4
semver: 7.8.5
vue-eslint-parser: 10.4.1(eslint@9.39.5)
vue-eslint-parser: 10.4.1(eslint@9.39.5(jiti@2.7.0))
xml-name-validator: 4.0.0
eslint-scope@8.4.0:
@@ -3412,9 +3427,9 @@ snapshots:
eslint-visitor-keys@5.0.1: {}
eslint@9.39.5:
eslint@9.39.5(jiti@2.7.0):
dependencies:
'@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5)
'@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(jiti@2.7.0))
'@eslint-community/regexpp': 4.12.2
'@eslint/config-array': 0.21.2
'@eslint/config-helpers': 0.4.2
@@ -3448,6 +3463,8 @@ snapshots:
minimatch: 3.1.5
natural-compare: 1.4.0
optionator: 0.9.4
optionalDependencies:
jiti: 2.7.0
transitivePeerDependencies:
- supports-color
@@ -3676,6 +3693,8 @@ snapshots:
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
jiti@2.7.0: {}
js-beautify@1.15.4:
dependencies:
config-chain: 1.1.13
@@ -4259,13 +4278,13 @@ snapshots:
dependencies:
prelude-ls: 1.2.1
typescript-eslint@8.66.0(eslint@9.39.5)(typescript@5.8.3):
typescript-eslint@8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3):
dependencies:
'@typescript-eslint/eslint-plugin': 8.66.0(@typescript-eslint/parser@8.66.0(eslint@9.39.5)(typescript@5.8.3))(eslint@9.39.5)(typescript@5.8.3)
'@typescript-eslint/parser': 8.66.0(eslint@9.39.5)(typescript@5.8.3)
'@typescript-eslint/eslint-plugin': 8.66.0(@typescript-eslint/parser@8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)
'@typescript-eslint/parser': 8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)
'@typescript-eslint/typescript-estree': 8.66.0(typescript@5.8.3)
'@typescript-eslint/utils': 8.66.0(eslint@9.39.5)(typescript@5.8.3)
eslint: 9.39.5
'@typescript-eslint/utils': 8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.8.3)
eslint: 9.39.5(jiti@2.7.0)
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
@@ -4298,7 +4317,7 @@ snapshots:
picomatch: 4.0.5
webpack-virtual-modules: 0.6.2
unplugin@3.3.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0)):
unplugin@3.3.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0)):
dependencies:
'@jridgewell/remapping': 2.3.5
picomatch: 4.0.5
@@ -4306,7 +4325,7 @@ snapshots:
optionalDependencies:
'@rspack/core': 2.1.8(@swc/helpers@0.5.23)
rolldown: 1.2.3
vite: 8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0)
vite: 8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0)
uri-js@4.4.1:
dependencies:
@@ -4314,7 +4333,7 @@ snapshots:
util-deprecate@1.0.2: {}
vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0):
vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0):
dependencies:
lightningcss: 1.33.0
picomatch: 4.0.5
@@ -4324,13 +4343,14 @@ snapshots:
optionalDependencies:
'@types/node': 24.13.3
fsevents: 2.3.3
jiti: 2.7.0
sass: 1.102.0
yaml: 2.9.0
vitest@4.1.10(@types/node@24.13.3)(jsdom@26.1.0)(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0)):
vitest@4.1.10(@types/node@24.13.3)(jsdom@26.1.0)(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0)):
dependencies:
'@vitest/expect': 4.1.10
'@vitest/mocker': 4.1.10(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))
'@vitest/mocker': 4.1.10(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))
'@vitest/pretty-format': 4.1.10
'@vitest/runner': 4.1.10
'@vitest/snapshot': 4.1.10
@@ -4347,7 +4367,7 @@ snapshots:
tinyexec: 1.3.0
tinyglobby: 0.2.17
tinyrainbow: 3.1.1
vite: 8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0)
vite: 8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 24.13.3
@@ -4359,10 +4379,10 @@ snapshots:
vue-component-type-helpers@3.3.9: {}
vue-eslint-parser@10.4.1(eslint@9.39.5):
vue-eslint-parser@10.4.1(eslint@9.39.5(jiti@2.7.0)):
dependencies:
debug: 4.4.3
eslint: 9.39.5
eslint: 9.39.5(jiti@2.7.0)
eslint-scope: 9.1.2
eslint-visitor-keys: 5.0.1
espree: 11.2.0
@@ -4375,7 +4395,7 @@ snapshots:
dependencies:
vue: 3.5.41(typescript@5.8.3)
vue-router@5.2.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3)):
vue-router@5.2.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.41)(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.8.3)):
dependencies:
'@babel/generator': 8.0.0
'@vue-macros/common': 3.1.4(vue@3.5.41(typescript@5.8.3))
@@ -4392,13 +4412,13 @@ snapshots:
picomatch: 4.0.5
scule: 1.3.0
tinyglobby: 0.2.17
unplugin: 3.3.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0))
unplugin: 3.3.0(@rspack/core@2.1.8(@swc/helpers@0.5.23))(rolldown@1.2.3)(vite@8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0))
unplugin-utils: 0.3.2
vue: 3.5.41(typescript@5.8.3)
yaml: 2.9.0
optionalDependencies:
'@vue/compiler-sfc': 3.5.41
vite: 8.2.0(@types/node@24.13.3)(sass@1.102.0)(yaml@2.9.0)
vite: 8.2.0(@types/node@24.13.3)(jiti@2.7.0)(sass@1.102.0)(yaml@2.9.0)
transitivePeerDependencies:
- '@farmfe/core'
- '@rspack/core'
+48
View File
@@ -0,0 +1,48 @@
import { disable, enable } from 'darkreader'
import { watch } from 'vue'
import { useDarkMode } from './composables/useDarkMode'
/**
* Dark Reader 引擎参数。
* brightness/contrast 保持默认观感,背景色与现有 Halo 暗色变量接近,
* 让 Dark Reader 补全第三方插件页面时不会显得突兀。
*/
const DARK_READER_THEME = {
brightness: 100,
contrast: 90,
grayscale: 0,
sepia: 0,
darkSchemeBackgroundColor: '#181b20',
darkSchemeTextColor: '#e8e6e3',
scrollbarColor: '#3a3f4a',
selectionColor: '#2f6f7a',
styleSystemControls: true,
} as const
let initialized = false
/**
* 初始化 Dark Reader 通用暗色引擎。
* 监听 useDarkMode 的 isDark 状态,深色时启用,浅色时关闭。
*/
export function initDarkReaderEngine(): void {
if (initialized) return
initialized = true
const { isDark } = useDarkMode()
watch(
isDark,
(dark) => {
try {
if (dark) {
enable(DARK_READER_THEME)
} else {
disable()
}
} catch (error) {
console.error('[dark-mode] Dark Reader 引擎异常', error)
}
},
{ immediate: true },
)
}
+5 -1
View File
@@ -2,10 +2,14 @@ import { definePlugin } from '@halo-dev/ui-shared'
import { IconPalette } from '@halo-dev/components'
import { markRaw } from 'vue'
import './styles/index.css'
import { initDarkReaderEngine } from './darkreader-engine'
import { injectThemeToggle } from './injector'
import { initMonacoThemeSync } from './monaco-theme'
// 在插件加载后将切换器注入到侧边栏
// 在插件加载后将切换器注入到侧边栏,并让 Monaco 跟随主题
injectThemeToggle()
initMonacoThemeSync()
initDarkReaderEngine()
export default definePlugin({
components: {},
+43
View File
@@ -0,0 +1,43 @@
/**
* 让 Monaco Editor(日志查看器)跟随 Halo 暗色模式。
* 优先调用 Monaco 官方主题 APICSS 兜底见 styles/overrides/editor.css。
*/
type MonacoLike = {
editor?: {
setTheme: (name: string) => void
}
}
const DARK_THEME = 'vs-dark'
const LIGHT_THEME = 'vs'
function getMonaco(): MonacoLike | undefined {
return (window as unknown as { monaco?: MonacoLike }).monaco
}
function applyMonacoTheme(): void {
const monaco = getMonaco()
if (!monaco?.editor?.setTheme) return
const isDark = document.documentElement.getAttribute('data-halo-theme') === 'dark'
monaco.editor.setTheme(isDark ? DARK_THEME : LIGHT_THEME)
}
/** 初始化 Monaco 主题同步:立即应用,并监听属性变化与实例懒加载。 */
export function initMonacoThemeSync(): void {
applyMonacoTheme()
const attributeObserver = new MutationObserver(() => applyMonacoTheme())
attributeObserver.observe(document.documentElement, {
attributes: true,
attributeFilter: ['data-halo-theme'],
})
// 日志页面可能懒加载 Monaco,实例渲染后再补一次
const instanceObserver = new MutationObserver(() => {
if (document.querySelector('.monaco-editor')) {
applyMonacoTheme()
}
})
instanceObserver.observe(document.body, { childList: true, subtree: true })
}
+1
View File
@@ -6,6 +6,7 @@
@import './variables.css';
@import './overrides/halo-core.css';
@import './overrides/plugin-pages.css';
@import './overrides/uno-fallback.css';
@import './overrides/utilities.css';
@import './overrides/layout.css';
@import './overrides/components.css';
+16 -88
View File
@@ -1,73 +1,21 @@
/* ============================================================
Halo Dark Mode — @halo-dev/components 组件库覆盖
覆盖 Halo 组件库中的 VCard, VModal, VDropdown, VTag 等
Halo Dark Mode — Halo 组件库覆盖(已清理)
已删除 Halo 2.25 中不存在的 Vuetify 类(.v-card 等),
真实 DOM 类覆盖请优先维护 halo-core.css。
============================================================ */
[data-halo-theme="dark"] {
/* ===== 卡片 VCard ===== */
.v-card,
[class*="v-card"] {
background-color: var(--halo-bg-card);
border-color: var(--halo-border-base);
color: var(--halo-text-primary);
}
/* ===== 模态框 VModal ===== */
.v-modal,
.modal-container,
[class*="modal"] {
background-color: var(--halo-bg-card);
color: var(--halo-text-primary);
}
/* ===== 下拉菜单 VDropdown ===== */
.v-dropdown,
.dropdown-menu,
[class*="dropdown"] {
background-color: var(--halo-bg-dropdown);
border-color: var(--halo-border-base);
color: var(--halo-text-primary);
}
.v-dropdown-item:hover,
.dropdown-item:hover {
background-color: var(--halo-bg-hover);
}
/* ===== 提示框 VTooltip ===== */
.v-tooltip,
[class*="tooltip"] {
background-color: var(--halo-bg-tooltip);
color: var(--halo-text-inverse);
}
/* ===== 标签/徽章 VTag, VBadge ===== */
.v-tag,
[class*="tag"],
.v-badge,
[class*="badge"] {
background-color: var(--halo-tag-bg);
color: var(--halo-tag-text);
}
/* ===== 按钮 ===== */
.btn-default,
.btn-secondary,
button:not([class*="btn-primary"]):not([class*="btn-danger"]) {
background-color: var(--halo-bg-card);
color: var(--halo-text-primary);
border-color: var(--halo-border-base);
}
.btn-default:hover,
.btn-secondary:hover {
background-color: var(--halo-bg-hover);
/* ===== 模态框(具体类 + !important,防被核心 scoped 样式覆盖) ===== */
.modal-content,
.modal-header,
.modal-body,
.modal-footer {
background-color: var(--halo-bg-card) !important;
color: var(--halo-text-primary) !important;
}
/* ===== 表格 VTable ===== */
table,
.v-table,
[class*="table"] {
table {
background-color: var(--halo-bg-card);
color: var(--halo-text-primary);
}
@@ -94,49 +42,29 @@
}
/* ===== 分页 ===== */
.pagination,
.v-pagination {
.pagination {
color: var(--halo-text-secondary);
}
.pagination .active,
.v-pagination .active {
.pagination .active {
background-color: var(--halo-accent-primary);
color: var(--halo-accent-primary-text);
}
/* ===== 面包屑 ===== */
.breadcrumb,
.v-breadcrumb {
.breadcrumb {
color: var(--halo-text-secondary);
}
.breadcrumb a,
.v-breadcrumb a {
.breadcrumb a {
color: var(--halo-text-link);
}
/* ===== Toast / 通知 ===== */
.v-toast,
.toast-notification,
[class*="toast"] {
background-color: var(--halo-bg-card);
color: var(--halo-text-primary);
border-color: var(--halo-border-base);
}
/* ===== 步骤条 ===== */
.v-steps,
[class*="steps"] {
color: var(--halo-text-secondary);
}
/* ===== 开关 VSwitch ===== */
.v-switch-track {
background-color: var(--halo-bg-disabled);
}
.v-switch-track[aria-checked="true"] {
background-color: var(--halo-accent-primary);
}
}
}
+29
View File
@@ -232,3 +232,32 @@
background-color: oklch(30% 0.04 160 / 50%);
}
}
/* ===== Monaco Editor(日志查看器,JS 主题优先,此处仅兜底) ===== */
html[data-halo-theme="dark"] .monaco-editor.vs,
html[data-halo-theme="dark"] .monaco-editor.vs .margin,
html[data-halo-theme="dark"] .monaco-editor.vs .lines-content,
html[data-halo-theme="dark"] .monaco-editor.vs .monaco-scrollable-element {
background-color: var(--halo-bg-input) !important;
color: var(--halo-text-primary) !important;
}
html[data-halo-theme="dark"] .monaco-editor.vs .line-numbers {
color: var(--halo-text-tertiary) !important;
}
html[data-halo-theme="dark"] .monaco-editor.vs .cursor {
border-color: var(--halo-text-primary) !important;
}
html[data-halo-theme="dark"] .monaco-editor.vs .selected-text,
html[data-halo-theme="dark"] .monaco-editor.vs .view-overlays .selected-text {
background-color: oklch(30% 0.04 160 / 50%) !important;
}
html[data-halo-theme="dark"] .monaco-editor.vs .find-widget,
html[data-halo-theme="dark"] .monaco-editor.vs .monaco-hover {
background-color: var(--halo-bg-dropdown) !important;
color: var(--halo-text-primary) !important;
}
/* ===== 编辑器链接(覆盖通用链接色规则) ===== */
html[data-halo-theme="dark"] .ProseMirror a,
html[data-halo-theme="dark"] .tiptap a {
color: var(--halo-text-link) !important;
}
+13
View File
@@ -87,3 +87,16 @@
border-color: var(--halo-border-base);
}
}
/* ===== 强表单覆盖(scoped 哈希类特异性更高,需 html 前缀 + !important ===== */
html[data-halo-theme="dark"] input:not([type="checkbox"]):not([type="radio"]):not([type="color"]),
html[data-halo-theme="dark"] textarea,
html[data-halo-theme="dark"] select {
background-color: var(--halo-bg-input) !important;
color: var(--halo-text-primary) !important;
border-color: var(--halo-border-input) !important;
}
html[data-halo-theme="dark"] input:not([type="checkbox"]):not([type="radio"]):not([type="color"])::placeholder,
html[data-halo-theme="dark"] textarea::placeholder,
html[data-halo-theme="dark"] select::placeholder {
color: var(--halo-text-tertiary) !important;
}
+54 -18
View File
@@ -1,11 +1,14 @@
/* ===== 根元素背景(html 自身携带属性,需独立选择器) ===== */
html[data-halo-theme="dark"] {
background-color: var(--halo-bg-body) !important;
}
/* ============================================================
Halo Dark Mode — Halo 核心 BEM 类覆盖
基于 Halo 2.25 真实 DOM 扫描(demo.halocms.site)得出的选择器
============================================================ */
[data-halo-theme="dark"] {
/* ===== 页面根背景(body 溢出时兜底) ===== */
html,
/* ===== 页面根背景(body 溢出时兜底html 见文件顶部独立规则 ===== */
body {
background-color: var(--halo-bg-body) !important;
color: var(--halo-text-primary);
@@ -100,14 +103,6 @@
.entity-field-description {
color: var(--halo-text-secondary);
}
.entity-field-title a,
.entity-field-title-body a {
color: var(--halo-text-primary);
}
.entity-field-title a:hover,
.entity-field-title-body a:hover {
color: var(--halo-text-link);
}
/* ===== 分页 ===== */
.pagination {
@@ -131,8 +126,7 @@
/* ===== 标签/徽章(BEM ===== */
.tag-wrapper,
.tag-default,
.tag-pill,
[class*="tag-"] {
.tag-pill {
background-color: var(--halo-bg-hover);
color: var(--halo-text-secondary);
}
@@ -206,10 +200,10 @@
border-color: var(--halo-border-light);
}
.description-item__label {
color: var(--halo-text-secondary);
color: var(--halo-text-secondary) !important;
}
.description-item__content {
color: var(--halo-text-primary);
color: var(--halo-text-primary) !important;
}
/* ===== 已选指示器 ===== */
@@ -265,8 +259,50 @@
border-color: var(--halo-border-base);
}
/* ===== 通用链接 ===== */
a:not([class]) {
color: var(--halo-text-link);
}
}
/* ===== 侧边栏激活菜单(Halo 核心 .menu-item-title.active ===== */
html[data-halo-theme="dark"] .menu-item-title.active,
html[data-halo-theme="dark"] .menu-item-title.active:hover {
background-color: var(--halo-menu-item-active) !important;
color: var(--halo-text-primary) !important;
}
html[data-halo-theme="dark"] .menu-item-title.active::after {
background: var(--halo-accent-primary) !important;
}
/* ===== 空状态标题 ===== */
html[data-halo-theme="dark"] .empty-wrapper .empty-title {
color: var(--halo-text-secondary) !important;
}
/* ===== 提示条(Alert ===== */
html[data-halo-theme="dark"] .alert-wrapper {
background-color: var(--halo-bg-card) !important;
border-color: var(--halo-border-base) !important;
color: var(--halo-text-primary) !important;
}
html[data-halo-theme="dark"] .alert-wrapper .alert-title,
html[data-halo-theme="dark"] .alert-wrapper .alert-description,
html[data-halo-theme="dark"] .alert-wrapper .alert-icon {
color: var(--halo-text-secondary) !important;
}
html[data-halo-theme="dark"] .alert-wrapper.alert-warning {
border-color: oklch(40% 0.12 85) !important;
}
html[data-halo-theme="dark"] .alert-wrapper.alert-error {
border-color: oklch(40% 0.17 25) !important;
}
html[data-halo-theme="dark"] .alert-wrapper.alert-success {
border-color: oklch(40% 0.14 150) !important;
}
/* ===== 实体列表标题链接(覆盖通用链接色,hover 变链接色) ===== */
html[data-halo-theme="dark"] .entity-field-title a,
html[data-halo-theme="dark"] .entity-field-title-body a {
color: var(--halo-text-primary) !important;
}
html[data-halo-theme="dark"] .entity-field-title a:hover,
html[data-halo-theme="dark"] .entity-field-title-body a:hover {
color: var(--halo-text-link) !important;
}
+1 -2
View File
@@ -55,8 +55,7 @@
}
/* ===== 页面标题 ===== */
.page-title,
.v-card-title {
.page-title {
color: var(--halo-text-primary);
}
}
+134
View File
@@ -247,3 +247,137 @@
color: var(--halo-text-primary) !important;
}
}
/* ===== AstraHub / 心愿便签(共用 ah-* UI ===== */
html[data-halo-theme="dark"] .ah-card,
html[data-halo-theme="dark"] .ah-topbar,
html[data-halo-theme="dark"] .ah-topbar-search,
html[data-halo-theme="dark"] .ah-float-nav {
background-color: var(--halo-bg-card) !important;
border-color: var(--halo-border-base) !important;
color: var(--halo-text-primary) !important;
}
html[data-halo-theme="dark"] .ah-topbar-search {
background-color: var(--halo-bg-input) !important;
}
html[data-halo-theme="dark"] .ah-topbar-brand,
html[data-halo-theme="dark"] .planet-hero-title {
color: var(--halo-text-primary) !important;
}
html[data-halo-theme="dark"] .ah-topbar-search input {
background-color: transparent !important;
color: var(--halo-text-primary) !important;
}
html[data-halo-theme="dark"] .planet-links-more {
background-color: var(--halo-bg-card) !important;
color: var(--halo-text-secondary) !important;
}
/* ===== RSS 订阅(links/rss ===== */
html[data-halo-theme="dark"] .subscription-panel,
html[data-halo-theme="dark"] .feed-main,
html[data-halo-theme="dark"] .feed-toolbar,
html[data-halo-theme="dark"] .feed-stream,
html[data-halo-theme="dark"] .feed-stream__footer {
background-color: var(--halo-bg-card) !important;
border-color: var(--halo-border-base) !important;
color: var(--halo-text-primary) !important;
}
html[data-halo-theme="dark"] .feed-status-tabs {
background-color: var(--halo-bg-hover) !important;
color: var(--halo-text-secondary) !important;
}
html[data-halo-theme="dark"] .feed-brief__title,
html[data-halo-theme="dark"] .feed-stream p,
html[data-halo-theme="dark"] .feed-stream a,
html[data-halo-theme="dark"] .subscription-panel a,
html[data-halo-theme="dark"] .subscription-panel span {
color: var(--halo-text-primary) !important;
}
/* ===== 私密文章插件 ===== */
html[data-halo-theme="dark"] .focus-card,
html[data-halo-theme="dark"] .overview-card,
html[data-halo-theme="dark"] .list-card,
html[data-halo-theme="dark"] .empty-state {
background-color: var(--halo-bg-card) !important;
border-color: var(--halo-border-base) !important;
color: var(--halo-text-primary) !important;
}
html[data-halo-theme="dark"] .overview-card h2,
html[data-halo-theme="dark"] .page-shell h2,
html[data-halo-theme="dark"] .overview-stats dd,
html[data-halo-theme="dark"] .overview-stats dt {
color: var(--halo-text-primary) !important;
}
/* ===== AI 评论自动处理插件 ===== */
html[data-halo-theme="dark"] .settings-container,
html[data-halo-theme="dark"] .setting-panel,
html[data-halo-theme="dark"] .tabs-wrap,
html[data-halo-theme="dark"] .sidebar-card,
html[data-halo-theme="dark"] .list-empty,
html[data-halo-theme="dark"] .reply-card {
background-color: var(--halo-bg-card) !important;
border-color: var(--halo-border-base) !important;
color: var(--halo-text-primary) !important;
}
html[data-halo-theme="dark"] .form-row,
html[data-halo-theme="dark"] .list-col,
html[data-halo-theme="dark"] .panel-header,
html[data-halo-theme="dark"] .card-footer {
background-color: var(--halo-bg-hover) !important;
color: var(--halo-text-primary) !important;
}
html[data-halo-theme="dark"] .section-header__text h3,
html[data-halo-theme="dark"] .sidebar-header h4,
html[data-halo-theme="dark"] .panel-header h3,
html[data-halo-theme="dark"] .reply-card h3 {
color: var(--halo-text-primary) !important;
}
html[data-halo-theme="dark"] .wake-word-tag {
background-color: var(--halo-bg-hover) !important;
color: var(--halo-text-secondary) !important;
}
/* ===== 数据工坊 / 代码注入器等工具页语义容器 ===== */
html[data-halo-theme="dark"] .data-studio-card-body,
html[data-halo-theme="dark"] .injector-view-card-body,
html[data-halo-theme="dark"] .injector-editor-container {
background-color: var(--halo-bg-card) !important;
border-color: var(--halo-border-base) !important;
color: var(--halo-text-primary) !important;
}
/* ===== 示例插件页 ===== */
html[data-halo-theme="dark"] main section#plugin-starter {
background-color: var(--halo-bg-body) !important;
color: var(--halo-text-primary) !important;
}
/* ===== 友链卡片徽章 ===== */
html[data-halo-theme="dark"] .link-badge {
background-color: var(--halo-bg-hover) !important;
color: var(--halo-text-primary) !important;
border-color: var(--halo-border-base) !important;
}
/* ===== 日程日历插件(time-column 布局) ===== */
html[data-halo-theme="dark"] .time-column__header,
html[data-halo-theme="dark"] .time-column__body,
html[data-halo-theme="dark"] [class*="time-column"] {
background-color: var(--halo-bg-card) !important;
color: var(--halo-text-primary) !important;
border-color: var(--halo-border-base) !important;
}
html[data-halo-theme="dark"] .entry-card-header__title {
color: var(--halo-text-primary) !important;
}
/* ===== 存储工具箱补充类 ===== */
html[data-halo-theme="dark"] .stat-value,
html[data-halo-theme="dark"] .stat-card .card-title,
html[data-halo-theme="dark"] .panel-card .card-title {
color: var(--halo-text-primary) !important;
}
html[data-halo-theme="dark"] .bar-track {
background-color: var(--halo-bg-disabled) !important;
}
+34
View File
@@ -0,0 +1,34 @@
/* ============================================================
Halo Dark Mode — UnoCSS 哈希类兜底
Halo 2.25 中 UnoCSS 同时生成 uno-* / i-* 哈希类,
这些类随构建变化,只能按结构定位兜底,不写死哈希值。
注意:本文件规则刻意不加 !important,便于后续语义规则覆盖。
============================================================ */
/* 文字兜底:只修正文本元素,豁免表单控件 */
html[data-halo-theme="dark"] main [class*="uno-"]:not(input):not(select):not(textarea) {
color: var(--halo-text-primary);
}
/* 块级容器背景兜底:豁免交互元素与表单控件 */
html[data-halo-theme="dark"] main [class*="uno-"]:not(button):not(a):not(input):not(select):not(textarea):not(label) {
background-color: var(--halo-bg-card);
border-color: var(--halo-border-base);
}
/* 页面级容器使用内容区背景 */
html[data-halo-theme="dark"] main > [class*="uno-"] {
background-color: var(--halo-bg-content);
}
/* 卡片头/卡片体内的 uno-* 区块使用 hover 级背景 */
html[data-halo-theme="dark"] .card-header [class*="uno-"],
html[data-halo-theme="dark"] .card-body [class*="uno-"] {
background-color: var(--halo-bg-hover);
border-color: var(--halo-border-light);
}
/* 旧版 i-* 哈希:只做文字兜底,避免给图标类设置背景 */
html[data-halo-theme="dark"] main [class*="i-"]:not(input):not(select):not(textarea) {
color: var(--halo-text-primary);
}
+1 -4
View File
@@ -62,10 +62,7 @@
}
/* ===== 链接 ===== */
a:not([class*="text-"]),
.hover\:text-gray-900:hover,
.hover\:text-gray-800:hover,
.hover\:text-gray-700:hover {
html[data-halo-theme="dark"] a:not([class*="text-"]) {
color: var(--halo-text-link);
}
+23
View File
@@ -0,0 +1,23 @@
MIT License
Copyright (c) 2026 Dark Reader Ltd.
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+9366
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+173
View File
@@ -0,0 +1,173 @@
declare namespace DarkReader {
/**
* Enables dark mode for current web page.
* @param theme Theme options.
* @param fixes Fixes for the generated theme.
*/
function enable(theme: Partial<Theme>, fixes?: DynamicThemeFix): void;
/**
* Disables dark mode for current web page.
*/
function disable(): void;
/**
* Enables dark mode when system color scheme is dark.
* @param theme Theme options.
* @param fixes Fixes for the generated theme.
*/
function auto(theme: Partial<Theme> | false, fixes?: DynamicThemeFix): void;
/**
* Stops watching for system color scheme.
* @param isEnabled Boolean `false` value.
*/
function auto(isEnabled: false): void;
/**
* Returns if darkreader is enabled.
*/
function isEnabled(): boolean;
/**
* Sets a function for making CORS requests.
* @param fetch A fetch function.
*/
function setFetchMethod(fetch: (url: string) => Promise<Response>): void;
/**
* Returns the generated CSS by Dark Reader as a string.
*/
function exportGeneratedCSS(): Promise<string>;
/**
* Theme options.
*/
interface Theme {
/**
* 1 - dark mode, 0 - dimmed mode.
* Default 1.
*/
mode: 0 | 1;
/**
* Brightness (0 - 100+).
* Default 100.
*/
brightness: number;
/**
* Contrast (0 - 100+).
* Default 100.
*/
contrast: number;
/**
* Grayscale (0 - 100).
* Default 0.
*/
grayscale: number;
/**
* Sepia (0 - 100).
* Default 0.
*/
sepia: number;
/**
* Specifies if custom font should be used.
* Default false.
*/
useFont: boolean;
/**
* Font family to use.
*/
fontFamily: string;
/**
* Makes text look bolder (0 - 1px).
* Default 0.
*/
textStroke: number;
/**
* Background color to use for dark mode.
* Default #181a1b
*/
darkSchemeBackgroundColor: string;
/**
* Text color to use for dark mode.
* Default #e8e6e3
*/
darkSchemeTextColor: string;
/**
* Background color to use for light mode.
* Default #dcdad7
*/
lightSchemeBackgroundColor: string;
/**
* Text color to use for light mode.
* Default #181a1b
*/
lightSchemeTextColor: string;
/**
* Scrollbar color
* Default auto
*/
scrollbarColor: string;
/**
* Selection color
* Default auto
*/
selectionColor: string;
/**
* Specifies if it has to style system controls
* Default true
*/
styleSystemControls: boolean;
}
/**
* Contains fixes for the generated theme.
*/
interface DynamicThemeFix {
/**
* List of CSS selectors that should be inverted.
* Usually icons that are contained in sprites.
*/
invert: string[];
/**
* Additional CSS.
* ${color} template should be used to apply theme options to a color.
* Example:
* ```
* body {
* background-color: ${white} !important;
* background-image: none !important;
* }
* ```
*/
css: string;
/**
* List of CSS selectors where it's inline style should not be analyzed
* Mostly used for color pickers
*/
ignoreInlineStyle: string[];
/**
* List of CSS selectors where it's image should not be analyzed
* Mostly used for wrongly inverted background-images
*/
ignoreImageAnalysis: string[];
/**
* A toggle to disable the proxying of `document.styleSheets`.
* This is a API-Exclusive option, as it can break legitimate websites,
* who are using the Dark Reader API.
*/
disableStyleSheetsProxy: boolean;
/**
* List of stylesheet URL patterns to ignore.
* Stylesheets matching these patterns will not be processed by Dark Reader.
* - Simple string: matches if URL contains the string (e.g., "crisp")
* - Prefix with ^: matches if URL starts with pattern (e.g., "^https://client.crisp")
* - Suffix with $: matches if URL ends with pattern (e.g., ".css$")
*/
ignoreCSSUrl: string[];
}
}
declare module 'darkreader' {
export = DarkReader;
}
+9
View File
@@ -0,0 +1,9 @@
{
"name": "darkreader",
"version": "4.9.129",
"description": "Dark mode for every website",
"main": "darkreader.js",
"module": "darkreader.mjs",
"types": "index.d.ts",
"license": "MIT"
}