Merge branch 'preview-features' into preview

This commit is contained in:
the1812 2025-07-22 23:12:43 +08:00
commit 3fad1960d9
50 changed files with 927 additions and 462 deletions

View File

@ -102,6 +102,7 @@
"tagid",
"Tampermonkey",
"Touhou",
"trendings",
"truetype",
"uname",
"usercard",

View File

@ -1,6 +1,69 @@
<!-- spell-checker: disable -->
# 更新日志
## v2.10.3-preview
包含 [v2.10.3](https://github.com/the1812/Bilibili-Evolved/releases/tag/v2.10.3) 的所有更新内容.
- 新增 `深色模式` 组件, 用于跟随 b 站官方的内测深色模式. (#5272)
> 脚本自身的元素配色也会逐步适配官方的配色, 目前仅适配设置面板、自定义顶栏和动态首页中的元素
- `插件 - 下载视频 - WASM 混流输出` 修正下载限制为 2GB, 新增下载速度和剩余时间显示. (#5102, PR #5233 by [WakelessSloth56](https://github.com/WakelessSloth56))
- `弹幕空降` 支持识别中文数字, 修复对特殊弹幕未触发的问题. (PR #5265 by [fixfeat](https://github.com/fixfeat))
- 新增 `视频预览放大` 组件. (PR #5281 by [wsgh0202](https://github.com/wsgh0202))
> 放大鼠标悬停于视频卡片时播放的 5 分钟预览
>
> - 点击放大镜图标放大预览
> - 点击缩小图标或者预览框外空白处关闭预览
- 修复 `隐藏首页轮播图` 失效, 并增加了一些局部元素控制功能. (PR #5287 [wsgh0202](https://github.com/wsgh0202))
## v2.10.3
`2025-07-22`
<details>
<summary>正式版用户将获得 v2.10.1-preview ~ v2.10.2-preview 的所有改动, 点击展开查看</summary>
- 新增 `稍后再看页面-重定向` 组件. (PR #5205 by [undefined](https://github.com/magicFeirl))
> 重定向**稍后再看页面**到普通视频页面,和`稍后再看重定向`组件的区别在于,该组件是在进入稍后再看的视频页面后进行重定向,而非直接替换链接到普通视频的链接,用于补充`稍后再看重定向`组件的功能。
- `隐藏热搜` 支持隐藏直播间搜索框的热搜. (PR #5207 by [undefined](https://github.com/magicFeirl))
- 修复 `视频链接增强` 对 niconico 链接的处理. (PR #5215 by [Alan Ye](https://github.com/at-wr))
- 新增 `动态分组过滤` 组件. (PR #5217 by [Rinne](https://github.com/OharaRinneY))
> 按照关注分组筛选动态
- `直播信息扩充` 支持配置置顶和隐藏的关注列表. (#5183)
- 新增组件 `一键点亮直播间粉丝勋章`. (PR #5171 by [undefined](https://github.com/magicFeirl))
> 在直播间页面的功能面板添加一键点亮粉丝勋章功能,仅适用于有粉丝勋章且正在直播的直播间。原理:发送一个 300 次点赞的请求点亮粉丝勋章。
- 新增组件 `下载表情`. (PR #5176 by [Pencil](https://github.com/pencilqaq))
> 支持下载 up 主专属表情包,处于任意直播间页面时,下载按钮会在 `功能` 面板显示,以压缩包形式保存。
- 新增组件 `视频链接增强`. (PR #5197 by [Alan Ye](https://github.com/at-wr))
> 这个组件会将视频简介中的普通网址转换为可点击的链接,并将<del>被 Bilibili 抛弃</del>已失效的 `acg.tv` 跳转链接修复为 `nicovideo.jp` 链接。
>
> 例如: `https://acg.tv/sm37507315``https://www.nicovideo.jp/watch/sm37507315`
>
> <i>本组件不会保证目标链接的安全性,因此在点击前请自行验证其是否可信</i>
- `自定义顶栏` 新增 `使用主题色 Logo` 选项, 关闭时可以使用黑白纯色的 Logo. (#4996)
- `自定义顶栏` 更新 `游戏中心`, `漫画`, `赛事` 的弹窗, 废弃 `直播` 的弹窗. (#5055)
</details>
(以下其实都是 6 月就更新了, 只要你的 `自动更新器` 正常使用, 应该早已收到更新了, 这些改动无需更新本体)
✨新增
- `显示视频投稿时间` 支持在合集类页面显示. (#5247, PR #5266 by [呼乎户](https://github.com/wisokey))
- `动态过滤` 支持过滤新出现的热搜面板. (#5273, PR #5276 by [Whalko](https://github.com/RtYkk))
🐛修复
- 修复 `夜间模式` 在首页 svg 图标的颜色. (PR #5240 by [hyrious](https://github.com/hyrious))
- 修复 `自动移出稍后再看` 重复调用接口的 bug. (PR #5241 by [sunfkny](https://github.com/sunfkny))
- 修复 `关注时间显示` 失效. (#5096, #5212, PR 5282 by [CNOCM](https://github.com/CNOCM))
## v2.10.2-preview
`2025-05-30`

View File

@ -74,7 +74,7 @@
## 最低配置
- 操作系统: Windows 8.1 / macOS Big Sur
- 分辨率: 1920x1080, 缩放 125%
- 浏览器: Chrome 105+ / Firefox 127+ / Safari 15.4+ (仅理论上能运行, 没测试过)
- 浏览器: Chrome 105+ / Firefox 140+ / Safari 18.4+ (仅理论上能运行, 没测试过)
- 处理器: Intel Core i5-10500 / AMD Ryzen 5 3600
- 内存: 8GB
- 脚本管理器: Tampermonkey 5.0 / Violentmonkey 2.18
@ -84,7 +84,7 @@
## 推荐配置
- 操作系统: Windows 10 / macOS Sonoma
- 分辨率: 3840x2160, 缩放 200%
- 浏览器: Chrome 120+ / Firefox 127+
- 浏览器: Chrome 120+ / Firefox 140+
- 处理器: Intel Core i7-11700 / AMD Ryzen 7 5800
- 内存: 32GB
- 脚本管理器: Tampermonkey 5.0 / Violentmonkey 2.18

View File

@ -30,6 +30,9 @@ https://afdian.com/a/the1812?tab=sponsor
| 时间 | 用户名 | 单号后4位 | 金额 |
| ------------------- | --------------------- | --------- | ------- |
| 2025.07.12 16:44:24 | 爱音allin | 3957 | ¥5.00 |
| 2025.06.29 10:53:44 | f*x | 9352 | ¥10.00 |
| 2025.06.10 01:22:23 | *匆 | 5332 | ¥5.00 |
| 2025.05.21 19:55:02 | mobmaster69 | 7644 | ¥5.00 |
| 2025.05.20 02:38:45 | Duane | 3937 | ¥5.00 |
| 2025.05.15 22:12:22 | 匿名 | 3901 | ¥23.33 |

View File

@ -279,6 +279,14 @@
"fullRelativePath": "../../registry/dist/components/style/dark-mode.js",
"fullAbsolutePath": "registry/dist/components/style/dark-mode.js"
},
{
"type": "component",
"name": "integratedDarkMode",
"displayName": "深色模式",
"description": "简化版的夜间模式,跟随 b 站官方的深色主题。\r\n",
"fullRelativePath": "../../registry/dist/components/style/dark-mode/integrated.js",
"fullAbsolutePath": "registry/dist/components/style/dark-mode/integrated.js"
},
{
"type": "component",
"name": "darkModeSchedule",
@ -315,7 +323,7 @@
"type": "component",
"name": "hideHomeCarousel",
"displayName": "隐藏首页轮播图",
"description": "隐藏首页的轮播图区域.\r\n",
"description": "隐藏首页的轮播图区域\r\n\r\n选项说明\r\n\r\n- `禁用轮播`:禁用图片轮播,可以手动切换\r\n- `图片模糊`模糊轮播图片为0时不模糊\r\n- `样式开关`\r\n - `隐藏轮播区域占位`:完全隐藏整个轮播区域\r\n - `透明化轮播区域`:完全透明化整个轮播区域,同时禁止点击打开链接\r\n - `隐藏轮播图片`:隐藏轮播图片,同时禁止点击图片打开链接\r\n - `隐藏图片标题`:隐藏图片标题,同时禁止点击标题打开链接\r\n\r\n > 注:样式开关可以同时启用,但是最终显示效果以作用范围大的为准 \r\n > 例如启用 `隐藏轮播区域占位`,由于整个区域都被隐藏,不管 `隐藏轮播图片`、`隐藏图片标题` 等选项是否启用都已经看不见了\r\n",
"fullRelativePath": "../../registry/dist/components/style/hide/home-carousel.js",
"fullAbsolutePath": "registry/dist/components/style/hide/home-carousel.js"
},
@ -543,6 +551,14 @@
"fullRelativePath": "../../registry/dist/components/utils/auto-like.js",
"fullAbsolutePath": "registry/dist/components/utils/auto-like.js"
},
{
"type": "component",
"name": "biggerVideoPreview",
"displayName": "视频预览放大",
"description": "放大鼠标悬停于视频卡片时播放的5分钟预览\r\n\r\n- 点击放大镜图标放大预览\r\n- 点击缩小图标或者预览框外空白处关闭预览\r\n",
"fullRelativePath": "../../registry/dist/components/utils/bigger-video-preview.js",
"fullAbsolutePath": "registry/dist/components/utils/bigger-video-preview.js"
},
{
"type": "component",
"name": "blackList",
@ -675,7 +691,7 @@
"type": "component",
"name": "subscribeTimeShow",
"displayName": "关注时间显示",
"description": "by [@Light_Quanta](https://github.com/LightQuanta)\n\n在粉丝/关注列表显示关注的具体时间",
"description": "by [@CNOCM](https://github.com/CNOCM)\n\n在粉丝/关注列表及用户主页显示关注的具体时间。",
"fullRelativePath": "../../registry/dist/components/utils/subscribe-time-show.js",
"fullAbsolutePath": "registry/dist/components/utils/subscribe-time-show.js"
},

View File

@ -373,6 +373,15 @@ by [@Tinhone](https://github.com/Tinhone)
启用夜间模式能更好地适应光线暗的环境, 并会大量应用主题颜色.
### [深色模式](../../registry/dist/components/style/dark-mode/integrated.js)
`integratedDarkMode`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/registry/dist/components/style/dark-mode/integrated.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/dark-mode/integrated.js)
**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/style/dark-mode/integrated.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/style/dark-mode/integrated.js)
简化版的夜间模式,跟随 b 站官方的深色主题。
### [夜间模式计划时段](../../registry/dist/components/style/dark-mode/schedule.js)
`darkModeSchedule`
@ -416,7 +425,20 @@ by [@Tinhone](https://github.com/Tinhone)
**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/style/hide/home-carousel.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/style/hide/home-carousel.js)
隐藏首页的轮播图区域.
隐藏首页的轮播图区域
选项说明:
- `禁用轮播`:禁用图片轮播,可以手动切换
- `图片模糊`模糊轮播图片为0时不模糊
- `样式开关`
- `隐藏轮播区域占位`:完全隐藏整个轮播区域
- `透明化轮播区域`:完全透明化整个轮播区域,同时禁止点击打开链接
- `隐藏轮播图片`:隐藏轮播图片,同时禁止点击图片打开链接
- `隐藏图片标题`:隐藏图片标题,同时禁止点击标题打开链接
> 注:样式开关可以同时启用,但是最终显示效果以作用范围大的为准
> 例如启用 `隐藏轮播区域占位`,由于整个区域都被隐藏,不管 `隐藏轮播图片`、`隐藏图片标题` 等选项是否启用都已经看不见了
### [隐藏热搜](../../registry/dist/components/style/hide/trending-search.js)
`hideTrendingSearch`
@ -719,6 +741,18 @@ by [@CrazyboyQCD](https://github.com/CrazyboyQCD)
安装快捷键扩展后可以点击【l】键或【L】键触发\
还可以添加动态点赞的黑名单\
### [视频预览放大](../../registry/dist/components/utils/bigger-video-preview.js)
`biggerVideoPreview`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/registry/dist/components/utils/bigger-video-preview.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/bigger-video-preview.js)
**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/utils/bigger-video-preview.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/utils/bigger-video-preview.js)
放大鼠标悬停于视频卡片时播放的5分钟预览
- 点击放大镜图标放大预览
- 点击缩小图标或者预览框外空白处关闭预览
### [屏蔽黑名单up主](../../registry/dist/components/utils/black-list.js)
`blackList`
@ -946,9 +980,9 @@ by [@Light_Quanta](https://github.com/LightQuanta)
**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/utils/subscribe-time-show.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/utils/subscribe-time-show.js)
by [@Light_Quanta](https://github.com/LightQuanta)
by [@CNOCM](https://github.com/CNOCM)
在粉丝/关注列表显示关注的具体时间
在粉丝/关注列表及用户主页显示关注的具体时间
### [网址参数清理](../../registry/dist/components/utils/url-params-clean.js)
`urlParamsClean`

View File

@ -59,7 +59,7 @@
"terser-webpack-plugin": "^5.0.1",
"to-string-loader": "^1.2.0",
"ts-node": "^10.7.0",
"typescript": "^4.9.5",
"typescript": "5.8.3",
"vue-eslint-parser": "^9.4.3",
"vue-loader": "^15.10.1",
"webpack": "^5.31.2",

82
pnpm-lock.yaml generated
View File

@ -99,10 +99,10 @@ importers:
version: 8.5.14
'@typescript-eslint/eslint-plugin':
specifier: ^5.50.0
version: 5.62.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@4.9.5))(eslint@7.32.0)(typescript@4.9.5)
version: 5.62.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0)(typescript@5.8.3)
'@typescript-eslint/parser':
specifier: ^5.50.0
version: 5.62.0(eslint@7.32.0)(typescript@4.9.5)
version: 5.62.0(eslint@7.32.0)(typescript@5.8.3)
async-exit-hook:
specifier: ^2.0.1
version: 2.0.1
@ -123,13 +123,13 @@ importers:
version: 7.32.0
eslint-config-airbnb-base:
specifier: ^14.1.0
version: 14.2.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@4.9.5))(eslint@7.32.0))(eslint@7.32.0)
version: 14.2.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0))(eslint@7.32.0)
eslint-config-prettier:
specifier: ^8.6.0
version: 8.10.0(eslint@7.32.0)
eslint-plugin-import:
specifier: ^2.20.1
version: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@4.9.5))(eslint@7.32.0)
version: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0)
eslint-plugin-prettier:
specifier: ^4.2.1
version: 4.2.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8)
@ -177,10 +177,10 @@ importers:
version: 1.2.0
ts-node:
specifier: ^10.7.0
version: 10.9.2(@types/node@17.0.45)(typescript@4.9.5)
version: 10.9.2(@types/node@17.0.45)(typescript@5.8.3)
typescript:
specifier: ^4.9.5
version: 4.9.5
specifier: 5.8.3
version: 5.8.3
vue-eslint-parser:
specifier: ^9.4.3
version: 9.4.3(eslint@7.32.0)
@ -3540,9 +3540,9 @@ packages:
resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
engines: {node: '>= 0.4'}
typescript@4.9.5:
resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==}
engines: {node: '>=4.2.0'}
typescript@5.8.3:
resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
engines: {node: '>=14.17'}
hasBin: true
unbox-primitive@1.1.0:
@ -4803,34 +4803,34 @@ snapshots:
dependencies:
'@types/node': 17.0.45
'@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@4.9.5))(eslint@7.32.0)(typescript@4.9.5)':
'@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0)(typescript@5.8.3)':
dependencies:
'@eslint-community/regexpp': 4.12.1
'@typescript-eslint/parser': 5.62.0(eslint@7.32.0)(typescript@4.9.5)
'@typescript-eslint/parser': 5.62.0(eslint@7.32.0)(typescript@5.8.3)
'@typescript-eslint/scope-manager': 5.62.0
'@typescript-eslint/type-utils': 5.62.0(eslint@7.32.0)(typescript@4.9.5)
'@typescript-eslint/utils': 5.62.0(eslint@7.32.0)(typescript@4.9.5)
'@typescript-eslint/type-utils': 5.62.0(eslint@7.32.0)(typescript@5.8.3)
'@typescript-eslint/utils': 5.62.0(eslint@7.32.0)(typescript@5.8.3)
debug: 4.4.0
eslint: 7.32.0
graphemer: 1.4.0
ignore: 5.3.2
natural-compare-lite: 1.4.0
semver: 7.7.1
tsutils: 3.21.0(typescript@4.9.5)
tsutils: 3.21.0(typescript@5.8.3)
optionalDependencies:
typescript: 4.9.5
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@4.9.5)':
'@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3)':
dependencies:
'@typescript-eslint/scope-manager': 5.62.0
'@typescript-eslint/types': 5.62.0
'@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5)
'@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3)
debug: 4.4.0
eslint: 7.32.0
optionalDependencies:
typescript: 4.9.5
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
@ -4839,21 +4839,21 @@ snapshots:
'@typescript-eslint/types': 5.62.0
'@typescript-eslint/visitor-keys': 5.62.0
'@typescript-eslint/type-utils@5.62.0(eslint@7.32.0)(typescript@4.9.5)':
'@typescript-eslint/type-utils@5.62.0(eslint@7.32.0)(typescript@5.8.3)':
dependencies:
'@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5)
'@typescript-eslint/utils': 5.62.0(eslint@7.32.0)(typescript@4.9.5)
'@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3)
'@typescript-eslint/utils': 5.62.0(eslint@7.32.0)(typescript@5.8.3)
debug: 4.4.0
eslint: 7.32.0
tsutils: 3.21.0(typescript@4.9.5)
tsutils: 3.21.0(typescript@5.8.3)
optionalDependencies:
typescript: 4.9.5
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/types@5.62.0': {}
'@typescript-eslint/typescript-estree@5.62.0(typescript@4.9.5)':
'@typescript-eslint/typescript-estree@5.62.0(typescript@5.8.3)':
dependencies:
'@typescript-eslint/types': 5.62.0
'@typescript-eslint/visitor-keys': 5.62.0
@ -4861,20 +4861,20 @@ snapshots:
globby: 11.1.0
is-glob: 4.0.3
semver: 7.7.1
tsutils: 3.21.0(typescript@4.9.5)
tsutils: 3.21.0(typescript@5.8.3)
optionalDependencies:
typescript: 4.9.5
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@5.62.0(eslint@7.32.0)(typescript@4.9.5)':
'@typescript-eslint/utils@5.62.0(eslint@7.32.0)(typescript@5.8.3)':
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@7.32.0)
'@types/json-schema': 7.0.15
'@types/semver': 7.5.8
'@typescript-eslint/scope-manager': 5.62.0
'@typescript-eslint/types': 5.62.0
'@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5)
'@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3)
eslint: 7.32.0
eslint-scope: 5.1.1
semver: 7.7.1
@ -5683,11 +5683,11 @@ snapshots:
escape-string-regexp@4.0.0: {}
eslint-config-airbnb-base@14.2.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@4.9.5))(eslint@7.32.0))(eslint@7.32.0):
eslint-config-airbnb-base@14.2.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0))(eslint@7.32.0):
dependencies:
confusing-browser-globals: 1.0.11
eslint: 7.32.0
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@4.9.5))(eslint@7.32.0)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0)
object.assign: 4.1.7
object.entries: 1.1.8
@ -5703,17 +5703,17 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0):
eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 5.62.0(eslint@7.32.0)(typescript@4.9.5)
'@typescript-eslint/parser': 5.62.0(eslint@7.32.0)(typescript@5.8.3)
eslint: 7.32.0
eslint-import-resolver-node: 0.3.9
transitivePeerDependencies:
- supports-color
eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@4.9.5))(eslint@7.32.0):
eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.8
@ -5724,7 +5724,7 @@ snapshots:
doctrine: 2.1.0
eslint: 7.32.0
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0)
eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@7.32.0)
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@ -5736,7 +5736,7 @@ snapshots:
string.prototype.trimend: 1.0.9
tsconfig-paths: 3.15.0
optionalDependencies:
'@typescript-eslint/parser': 5.62.0(eslint@7.32.0)(typescript@4.9.5)
'@typescript-eslint/parser': 5.62.0(eslint@7.32.0)(typescript@5.8.3)
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
@ -7382,7 +7382,7 @@ snapshots:
totalist@3.0.1: {}
ts-node@10.9.2(@types/node@17.0.45)(typescript@4.9.5):
ts-node@10.9.2(@types/node@17.0.45)(typescript@5.8.3):
dependencies:
'@cspotcode/source-map-support': 0.8.1
'@tsconfig/node10': 1.0.11
@ -7396,7 +7396,7 @@ snapshots:
create-require: 1.1.1
diff: 4.0.2
make-error: 1.3.6
typescript: 4.9.5
typescript: 5.8.3
v8-compile-cache-lib: 3.0.1
yn: 3.1.1
@ -7409,10 +7409,10 @@ snapshots:
tslib@1.14.1: {}
tsutils@3.21.0(typescript@4.9.5):
tsutils@3.21.0(typescript@5.8.3):
dependencies:
tslib: 1.14.1
typescript: 4.9.5
typescript: 5.8.3
type-check@0.4.0:
dependencies:
@ -7453,7 +7453,7 @@ snapshots:
possible-typed-array-names: 1.1.0
reflect.getprototypeof: 1.0.10
typescript@4.9.5: {}
typescript@5.8.3: {}
unbox-primitive@1.1.0:
dependencies:

View File

@ -239,8 +239,8 @@ onBeforeUnmount(() => {
background-color: #fff;
body.dark & {
background-color: #444;
color: #eee;
color: var(--be-color-text-title, #eee);
background-color: var(--be-color-popup-bg, #444);
}
&-header {
@ -327,7 +327,7 @@ onBeforeUnmount(() => {
overflow: hidden;
border-radius: 50%;
display: flex;
border: 1px solid #8884;
border: 1px solid var(--be-color-avatar-border, #8884);
}
&-info {

View File

@ -33,23 +33,20 @@
</div>
<h2>板块</h2>
<div class="filter-side-card">
<div
<FilterSideCard
v-for="[id, type] of Object.entries(allSideCards)"
:id="parseInt(id)"
:key="id"
class="filter-side-card-switch feeds-filter-switch"
@click="toggleBlockSide(id)"
>
<label :class="{ disabled: sideDisabled(id) }">
<span class="name" :class="{ disabled: sideDisabled(id) }">{{ type.displayName }}</span>
<VIcon :size="16" class="disabled" icon="mdi-cancel"></VIcon>
<VIcon :size="16" icon="mdi-check"></VIcon>
</label>
</div>
:name="type.displayName"
:block-side-cards="blockSideCards"
@click="toggleBlockSide(parseInt(id))"
/>
</div>
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import { ref, reactive, watch, onMounted, defineAsyncComponent } from 'vue'
import {
FeedsCard,
FeedsCardType,
@ -64,11 +61,16 @@ import { VIcon, TextBox, VButton } from '@/ui'
import { FeedsFilterOptions } from './options'
import { hasBlockedPattern } from './pattern'
const FilterTypeSwitch = defineAsyncComponent(() => import('./FilterTypeSwitch.vue'))
const FilterSideCard = defineAsyncComponent(() => import('./FilterSideCard.vue'))
const { options } = getComponentSettings<FeedsFilterOptions>('feedsFilter')
interface SideCardType {
className: string
displayName: string
}
const sideCards: { [id: number]: SideCardType } = {
0: {
className: 'profile',
@ -103,126 +105,120 @@ const sideCards: { [id: number]: SideCardType } = {
displayName: '热搜',
},
}
if (getComponentSettings('extendFeedsLive').enabled) {
delete sideCards[3]
}
let cardsManager: typeof import('@/components/feeds/api').feedsCardsManager
const sideBlock = 'feeds-filter-side-block-'
export default Vue.extend({
components: {
FilterTypeSwitch: () => import('./FilterTypeSwitch.vue'),
VIcon,
TextBox,
VButton,
},
data() {
return {
allTypes: [] as [string, FeedsCardType][],
patterns: [...options.patterns],
newPattern: '',
allSideCards: sideCards,
blockSideCards: [...options.sideCards],
collapse: true,
const allTypes = ref<[string, FeedsCardType][]>([])
const patterns = reactive([...options.patterns])
const newPattern = ref('')
const allSideCards = reactive(sideCards)
const blockSideCards = reactive([...options.sideCards])
const collapse = ref(true)
const updateCard = (card: FeedsCard) => {
const blockableCard = {
...card,
}
if (card.type === feedsCardTypes.repost) {
blockableCard.text += `\n${(card as RepostFeedsCard).repostText}`
}
const block = options.patterns.some(p => hasBlockedPattern(p, blockableCard))
if (block) {
card.element.classList.add('pattern-block')
} else {
card.element.classList.remove('pattern-block')
}
}
watch(patterns, () => {
options.patterns = patterns
if (cardsManager) {
cardsManager.cards.forEach(card => updateCard(lodash.clone(card)))
}
})
const deletePattern = (pattern: string) => {
const index = patterns.indexOf(pattern)
if (index !== -1) {
patterns.splice(index, 1)
}
}
const addPattern = (pattern: string) => {
if (pattern && !patterns.includes(pattern)) {
patterns.push(pattern)
}
newPattern.value = ''
}
const updateBlockSide = () => {
Object.entries(sideCards).forEach(([id, type]) => {
const name = sideBlock + type.className
if (blockSideCards.includes(parseInt(id))) {
document.body.classList.add(name)
} else {
document.body.classList.remove(name)
}
},
watch: {
patterns() {
options.patterns = this.patterns
if (cardsManager) {
cardsManager.cards.forEach(card => this.updateCard(lodash.clone(card)))
}
})
}
const toggleBlockSide = (id: number) => {
const index = blockSideCards.indexOf(id)
const type = sideCards[id]
if (index !== -1) {
blockSideCards.splice(index, 1)
document.body.classList.remove(sideBlock + type.className)
} else {
blockSideCards.push(id)
document.body.classList.add(sideBlock + type.className)
}
options.sideCards = blockSideCards
}
onMounted(async () => {
updateBlockSide()
const tabBar = await select('.feed-card .tab-bar, .bili-dyn-list-tabs__list')
if (!tabBar) {
console.error('tabBar not found')
return
}
document.body.classList.add('enable-feeds-filter')
const specialTypes = {
'self-repost': {
id: -1,
name: '自转发',
} as FeedsCardType,
}
allTypes.value = Object.entries(feedsCardTypes)
.concat(Object.entries(specialTypes))
.filter(([, type]) => type.id <= 2048 && type.id !== 0)
.map(([name, type]) => [name, lodash.clone(type)])
cardsManager = await forEachFeedsCard({
added: card => {
updateCard(lodash.clone(card))
},
},
async mounted() {
this.updateBlockSide()
const tabBar = await select('.feed-card .tab-bar, .bili-dyn-list-tabs__list')
if (!tabBar) {
console.error('tabBar not found')
return
}
document.body.classList.add('enable-feeds-filter')
const specialTypes = {
'self-repost': {
id: -1,
name: '自转发',
} as FeedsCardType,
}
this.allTypes = Object.entries(feedsCardTypes)
.concat(Object.entries(specialTypes))
.filter(([, type]) => type.id <= 2048 && type.id !== 0)
.map(([name, type]) => [name, lodash.clone(type)])
cardsManager = await forEachFeedsCard({
added: card => {
this.updateCard(lodash.clone(card))
},
})
if (cardsManager.managerType === 'v1') {
const tab = tabBar.querySelector('.tab:nth-child(1) .tab-text') as HTMLAnchorElement
attributes(tab, () => {
document.body.classList.toggle('by-type', !tab.classList.contains('selected'))
})
if (cardsManager.managerType === 'v1') {
const tab = tabBar.querySelector('.tab:nth-child(1) .tab-text') as HTMLAnchorElement
attributes(tab, () => {
document.body.classList.toggle('by-type', !tab.classList.contains('selected'))
})
}
if (cardsManager.managerType === 'v2') {
const mainContainer = (await select('.bili-dyn-home--member main')) as HTMLElement
/** 类型过滤选中"全部" */
const isAllTypesSelected = () => Boolean(dq('.bili-dyn-list-tabs__item:first-child.active'))
/** 关注列表选中"全部动态" */
const isAllUpsSelected = () => Boolean(dq('.bili-dyn-up-list__item:first-child.active'))
attributesSubtree(mainContainer, () => {
document.body.classList.toggle('by-type', isAllUpsSelected() && !isAllTypesSelected())
})
}
},
methods: {
updateCard(card: FeedsCard) {
const blockableCard = {
...card,
}
if (card.type === feedsCardTypes.repost) {
blockableCard.text += `\n${(card as RepostFeedsCard).repostText}`
}
const block = options.patterns.some(p => hasBlockedPattern(p, blockableCard))
if (block) {
card.element.classList.add('pattern-block')
} else {
card.element.classList.remove('pattern-block')
}
},
deletePattern(pattern: string) {
const index = options.patterns.indexOf(pattern)
if (index !== -1) {
this.patterns.splice(index, 1)
}
},
addPattern(pattern: string) {
if (pattern && !this.patterns.includes(pattern)) {
this.patterns.push(pattern)
}
this.newPattern = ''
},
updateBlockSide() {
Object.entries(sideCards).forEach(([id, type]) => {
const name = sideBlock + type.className
document.body.classList[this.blockSideCards.includes(id) ? 'add' : 'remove'](name)
})
},
toggleBlockSide(id: number) {
const index = this.blockSideCards.indexOf(id)
const type = sideCards[id]
if (index !== -1) {
this.blockSideCards.splice(index, 1)
document.body.classList.remove(sideBlock + type.className)
} else {
this.blockSideCards.push(id)
document.body.classList.add(sideBlock + type.className)
}
options.sideCards = this.blockSideCards
},
sideDisabled(id: number) {
return this.blockSideCards.includes(id)
},
},
}
if (cardsManager.managerType === 'v2') {
const mainContainer = (await select('.bili-dyn-home--member main')) as HTMLElement
/** 类型过滤选中"全部" */
const isAllTypesSelected = () => Boolean(dq('.bili-dyn-list-tabs__item:first-child.active'))
/** 关注列表选中"全部动态" */
const isAllUpsSelected = () => Boolean(dq('.bili-dyn-up-list__item:first-child.active'))
attributesSubtree(mainContainer, () => {
document.body.classList.toggle('by-type', isAllUpsSelected() && !isAllTypesSelected())
})
}
})
</script>
@ -271,8 +267,8 @@ body.disable-feeds-filter {
}
}
body.dark & {
color: #eee;
background-color: #444;
color: var(--be-color-text-title, #eee);
background-color: var(--be-color-panel-bg, #444);
}
.feeds-filter-header {
cursor: pointer;
@ -335,7 +331,7 @@ body.disable-feeds-filter {
padding: 4px 6px;
border-radius: 4px;
font-size: 12px;
border: 1px solid #8884;
border: 1px solid var(--be-color-card-border, #8884);
&:not(:last-child) {
margin-bottom: 4px;
}

View File

@ -0,0 +1,21 @@
<template>
<div class="filter-side-card-switch feeds-filter-switch" v-on="$listeners">
<label :class="{ disabled }">
<span class="name" :class="{ disabled }">{{ name }}</span>
<VIcon :size="16" class="disabled" icon="mdi-cancel"></VIcon>
<VIcon :size="16" icon="mdi-check"></VIcon>
</label>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { VIcon } from '@/ui'
const props = defineProps<{
blockSideCards: number[]
id: number
name: string
}>()
const disabled = computed(() => props.blockSideCards.includes(props.id))
</script>

View File

@ -9,59 +9,56 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import { ref, watch, onMounted, computed } from 'vue'
import { getComponentSettings } from '@/core/settings'
import { VIcon } from '@/ui'
import { FeedsFilterOptions } from './options'
interface Props {
name: string
type: {
id: number
name: string
}
}
const props = defineProps<Props>()
const { options } = getComponentSettings<FeedsFilterOptions>('feedsFilter')
export default Vue.extend({
components: {
VIcon,
},
props: {
name: {
type: String,
required: true,
},
type: {
type: Object,
required: true,
},
},
data() {
const optionKey = this.type.id >= 0 ? 'types' : 'specialTypes'
const disabled = options[optionKey].includes(this.type.id)
return {
disabled,
optionKey,
const optionKey = computed(() => (props.type.id >= 0 ? 'types' : 'specialTypes'))
const disabled = ref(options[optionKey.value].includes(props.type.id))
const setFilter = (isDisabled: boolean, updateSettings = true) => {
if (isDisabled) {
document.body.classList.add(`feeds-filter-block-${props.name}`)
} else {
document.body.classList.remove(`feeds-filter-block-${props.name}`)
}
if (!updateSettings) {
return
}
const key = optionKey.value as 'types' | 'specialTypes'
if (isDisabled) {
options[key].push(props.type.id)
} else {
const index = options[key].indexOf(props.type.id)
if (index !== -1) {
options[key].splice(index, 1)
}
},
watch: {
disabled(newValue: boolean) {
this.setFilter(newValue)
},
},
created() {
this.setFilter(this.disabled, false)
},
methods: {
setFilter(disabled: boolean, updateSettings = true) {
document.body.classList[disabled ? 'add' : 'remove'](`feeds-filter-block-${this.name}`)
if (!updateSettings) {
return
}
const optionKey = this.optionKey as 'types' | 'specialTypes'
if (disabled) {
options[optionKey].push(this.type.id)
} else {
const index = options[optionKey].indexOf(this.type.id)
if (index !== -1) {
options[optionKey].splice(index, 1)
}
}
},
},
}
}
watch(disabled, (newValue: boolean) => {
setFilter(newValue)
})
onMounted(() => {
setFilter(disabled.value, false)
})
</script>
<style lang="scss">
@ -77,7 +74,7 @@ export default Vue.extend({
display: flex;
align-items: center;
justify-content: space-between;
border: 1px solid #8884;
border: 1px solid var(--be-color-card-border, #8884);
.name {
font-size: 12px;
@ -86,7 +83,7 @@ export default Vue.extend({
color: var(--theme-color) !important;
}
&:hover {
background-color: #8882;
background-color: var(--be-color-highlight-bg-hover, #8882);
}
input {
display: none;

View File

@ -19,8 +19,8 @@
color: black;
}
body.dark & {
background-color: #444;
color: #eee;
color: var(--be-color-text-title, #eee);
background-color: var(--be-color-panel-bg, #444);
&:hover {
color: var(--theme-color);
}

View File

@ -87,6 +87,11 @@ html {
--navbar-bounds-padding: 10%;
// --navbar-blur-opacity: 0.7;
--navbar-icon-size: 24px;
--be-color-navbar-bg: var(--bg1);
--be-color-navbar-skeleton-bg: var(--bg1_float);
--be-color-navbar-shadow: rgba(var(--shadow_rgb), 0.4);
--be-color-navbar-bg-blur: rgba(var(--bg1_rgb), 0.8);
}
body.custom-navbar-loading::after {
@ -100,7 +105,7 @@ body.custom-navbar-loading::after {
z-index: 10001;
}
body.dark.custom-navbar-loading::after {
background-color: #333;
background-color: var(--be-color-navbar-skeleton-bg, #333);
}
body.fixed-navbar {
.left-panel {
@ -182,7 +187,7 @@ body.fixed-navbar {
box-shadow: #0002 0 1px 10px 1px;
}
body.dark &.shadow:not(.transparent) {
box-shadow: #0004 0px 2px 10px 1px;
box-shadow: var(--be-color-navbar-shadow, #0004) 0px 2px 10px 1px;
}
&.blur:not(.transparent) {
@ -191,10 +196,10 @@ body.fixed-navbar {
}
body.dark &:not(.fill):not(.transparent) {
--navbar-background: #222;
--navbar-background: var(--be-color-navbar-bg, #222);
--navbar-foreground: #eee;
&.blur {
--navbar-background: #2228;
--navbar-background: var(--be-color-navbar-bg-blur, #2228);
}
}
&.transparent {

View File

@ -258,7 +258,7 @@ export default Vue.extend({
color: black;
background: white;
box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.05);
border: 1px solid #8882;
border: 1px solid var(--be-color-popup-border, #8882);
border-radius: 8px;
transition: opacity 0.2s ease-out 0.2s;
position: absolute;
@ -271,8 +271,8 @@ export default Vue.extend({
cursor: default;
body.dark & {
color: #eee;
background: #222;
color: var(--be-color-text-content, #eee);
background: var(--be-color-popup-bg, #222);
}
&.iframe-container {

View File

@ -40,13 +40,13 @@
@keyframes transparent-to-dark {
to {
--navbar-foreground: #eee;
--navbar-background: #222;
--navbar-background: var(--be-color-navbar-bg, #222);
}
}
@keyframes transparent-to-dark-blur {
to {
--navbar-foreground: #eee;
--navbar-background: #2228;
--navbar-background: var(--be-color-navbar-bg-blur, #2228);
backdrop-filter: blur(24px);
}
}
@ -81,14 +81,14 @@
@keyframes transparent-to-dark-shadow {
to {
--navbar-foreground: #eee;
--navbar-background: #222;
--navbar-background: var(--be-color-navbar-bg, #222);
box-shadow: #0004 0px 2px 10px 1px;
}
}
@keyframes transparent-to-dark-blur-shadow {
to {
--navbar-foreground: #eee;
--navbar-background: #2228;
--navbar-background: var(--be-color-navbar-bg-blur, #2228);
backdrop-filter: blur(24px);
box-shadow: #0004 0px 2px 10px 1px;
}

View File

@ -375,8 +375,8 @@ export default Vue.extend({
'cover info' 1fr / 130px 1fr;
height: 85px;
body.dark & {
background-color: #282828;
color: #eee;
background-color: var(--be-color-card-bg, #282828);
color: var(--be-color-text-title, #eee);
}
&:not(:last-child) {
margin-bottom: 12px;

View File

@ -88,8 +88,8 @@ export default Vue.extend({
width: auto;
flex-shrink: 0;
body.dark & {
background-color: #282828;
color: #eee;
background-color: var(--be-color-card-bg, #282828);
color: var(--be-color-text-title, #eee);
}
.face-container {
flex-shrink: 0;

View File

@ -156,9 +156,15 @@ defineExpose({
.list-game-cards-title {
font-size: large;
@include semi-bold();
body.dark & {
color: var(--be-color-text-title, #eee);
}
}
.list-game-cards {
@include v-stretch();
body.dark & {
color: var(--be-color-text-content, #aaa);
}
.list-game-card {
@include single-line();
padding: 4px 0;

View File

@ -361,7 +361,7 @@ export default Vue.extend({
z-index: 1;
background-color: #fff;
body.dark & {
background-color: #222;
background-color: var(--be-color-popup-bg, #222);
}
}
&-items {
@ -392,8 +392,8 @@ export default Vue.extend({
border: 1px solid #8882;
box-sizing: border-box;
body.dark & {
background-color: #282828;
color: #eee;
background-color: var(--be-color-card-bg, #282828);
color: var(--be-color-text-title, #eee);
}
&:not(:last-child) {
margin-bottom: 8px;

View File

@ -211,7 +211,11 @@ defineExpose({
background-image: linear-gradient(to left, #fff 75%, transparent);
padding: 18px 18px 18px 60px;
body.dark & {
background-image: linear-gradient(to left, #222 75%, transparent);
background-image: linear-gradient(
to left,
var(--be-color-popup-bg, #222) 75%,
transparent
);
}
img {
display: flex;

View File

@ -183,8 +183,8 @@ export default Vue.extend({
$radius: 8px;
border-radius: $radius;
body.dark & {
background-color: #2d2d2d;
color: #eee;
background-color: var(--be-color-card-bg, #2d2d2d);
color: var(--be-color-text-title, #eee);
}
.subscriptions-cover-container {
height: 64px;

View File

@ -465,7 +465,7 @@ export default Vue.extend({
margin: 5px 10px;
background: rgba(0, 0, 0, 0.1);
body.dark & {
background: rgba(255, 255, 255, 0.1);
background: var(--be-color-panel-border, rgba(255, 255, 255, 0.1));
}
}
.level-icon.plus {
@ -531,9 +531,9 @@ export default Vue.extend({
}
}
body.dark & {
background: #282828;
background-color: var(--be-color-button-bg, #282828);
&:hover {
background: #333;
background-color: var(--be-color-button-bg-hover, #333);
}
}
}

View File

@ -288,8 +288,8 @@ export default Vue.extend({
'cover info' 1fr / 130px 1fr;
height: 85px;
body.dark & {
background-color: #282828;
color: #eee;
background-color: var(--be-color-card-bg, #282828);
color: var(--be-color-text-title, #eee);
}
&:not(:last-child) {
margin-bottom: 12px;

View File

@ -3,7 +3,7 @@
--Ga0: #0d0d0e;
--Ga0_s: #1e2022;
--Ga0_t: #1e2022;
--Ga1: #000000;
--Ga1: #000;
--Ga1_s: #232527;
--Ga1_t: #232527;
--Ga1_e: #232527;
@ -29,9 +29,9 @@
--Ga12: #1f2022;
--Wh0: #17181a;
--Wh0_t: #17181a;
--Ba0: #000000;
--Ba0_s: #ffffff;
--Ba0_t: #000000;
--Ba0: #000;
--Ba0_s: #fff;
--Ba0_t: #000;
--Pi0: #26161c;
--Pi1: #2f1a22;
--Pi2: #472030;
@ -187,6 +187,34 @@
--Si8: #c8ced6;
--Si9: #dce0e5;
--Si10: #f0f2f4;
--Pi5_rgb: 212, 78, 125;
--Pi1_rgb: 47, 26, 34;
--Lb5_rgb: 0, 135, 189;
--Lb1_rgb: 11, 32, 42;
--Re5_rgb: 209, 64, 62;
--Re1_rgb: 46, 22, 23;
--Gr5_rgb: 31, 162, 81;
--Gr1_rgb: 17, 39, 27;
--Or5_rgb: 214, 96, 17;
--Or1_rgb: 48, 27, 16;
--Ye5_rgb: 219, 135, 0;
--Ye1_rgb: 52, 36, 16;
--Wh0_rgb: 23, 24, 26;
--Ga0_rgb: 13, 13, 14;
--Ga1_rgb: 0, 0, 0;
--Ga11_rgb: 36, 38, 40;
--Ga12_rgb: 31, 32, 34;
--Wh0_u_rgb: 255, 255, 255;
--Ga10_rgb: 231, 233, 235;
--Ga7_rgb: 162, 167, 174;
--Ga5_rgb: 117, 122, 129;
--Ga3_rgb: 70, 73, 77;
--Lb6_rgb: 44, 156, 200;
--Ye6_rgb: 225, 156, 44;
--Ga1_s_rgb: 35, 37, 39;
--Ga2_rgb: 47, 49, 52;
--Ga0_s_rgb: 30, 32, 34;
--Ba0_rgb: 0, 0, 0;
}
html:root {
--brand_blue: var(--theme-color);

View File

@ -0,0 +1 @@
简化版的夜间模式,跟随 b 站官方的深色主题。

View File

@ -0,0 +1,109 @@
import { defineComponentMetadata } from '@/components/component'
import { getCookieValue } from '@/core/utils'
const name = 'integratedDarkMode'
const darkModeClass = 'dark'
const integratedDarkModeClass = 'integrated-dark'
const darkMetaColor = '#111'
const isOfficialDarkModeEnabled = () => {
return getCookieValue('theme_style') === 'dark'
}
const enableDarkMode = () => {
document.body.classList.add(darkModeClass, integratedDarkModeClass)
const themeColorMeta = dq('meta[name="theme-color"]') as HTMLMetaElement
if (!themeColorMeta) {
document.head.insertAdjacentHTML(
'beforeend',
`<meta name="theme-color" content="${darkMetaColor}">`,
)
} else {
themeColorMeta.dataset.light = themeColorMeta.content
themeColorMeta.content = darkMetaColor
}
const colorSchemeMeta = dq('meta[name="color-scheme"]') as HTMLMetaElement
if (!colorSchemeMeta) {
document.head.insertAdjacentHTML('beforeend', `<meta name="color-scheme" content="dark">`)
} else {
colorSchemeMeta.content = 'dark'
}
}
const disableDarkMode = () => {
document.body.classList.remove(darkModeClass, integratedDarkModeClass)
const themeColorMeta = dq('meta[name="theme-color"]') as HTMLMetaElement
if (themeColorMeta?.dataset.light) {
themeColorMeta.content = themeColorMeta.dataset.light
} else {
themeColorMeta?.remove()
}
const colorSchemeMeta = dq('meta[name="color-scheme"]') as HTMLMetaElement
if (colorSchemeMeta) {
colorSchemeMeta.content = 'light'
}
}
const toggleDarkModeByCookie = () => {
if (isOfficialDarkModeEnabled()) {
enableDarkMode()
} else {
disableDarkMode()
}
}
const cookieChangeHandler = (e: CookieChangedEvent) => {
if (e.changed.some(cookie => cookie.name === 'theme_style')) {
toggleDarkModeByCookie()
}
}
export const component = defineComponentMetadata({
name,
displayName: '深色模式',
entry: () => {
cookieStore.addEventListener('change', cookieChangeHandler)
},
reload: () => {
cookieStore.addEventListener('change', cookieChangeHandler)
toggleDarkModeByCookie()
},
unload: () => {
cookieStore.removeEventListener('change', cookieChangeHandler)
document.body.classList.remove(darkModeClass, integratedDarkModeClass)
},
tags: [componentsTags.style, componentsTags.general],
instantStyles: [
{
name,
style: () => import('./integrated-variables.scss'),
},
{
name: 'integratedDarkModePatches',
style: () => import('./patches.scss'),
},
],
plugin: {
displayName: '深色模式 - 提前注入',
description: {
'zh-CN': '提前注入深色模式的 .dark class 以减少一些组件首屏仍然是白色的问题.',
},
async setup() {
if (!isOfficialDarkModeEnabled()) {
return
}
const { contentLoaded } = await import('@/core/life-cycle')
const { isComponentEnabled } = await import('@/core/settings')
contentLoaded(() => {
if (isComponentEnabled(name)) {
cookieStore.addEventListener('change', cookieChangeHandler)
toggleDarkModeByCookie()
}
})
},
},
})

View File

@ -0,0 +1,33 @@
// https://medium.com/eightshapes-llc/naming-tokens-in-design-systems-9e86c7444676
body.integrated-dark {
--be-color-text-title: var(--text1);
--be-color-text-content: var(--text1);
--be-color-text-placeholder: var(--text2);
--be-color-card-bg: var(--bg1_float);
--be-color-card-border: var(--line_regular);
--be-color-tooltip-bg: var(--bg1_float);
--be-color-button-bg: var(--bg1_float);
--be-color-button-bg-hover: var(--graph_bg_thick);
--be-color-button-border: var(--line_regular);
--be-color-switch-bg: rgba(var(--graph_medium_rgb), 0.3);
--be-color-thumb-bg: var(--Ga4);
--be-color-thumb-border: var(--Ga3);
--be-color-tag-bg: rgba(var(--graph_medium_rgb), 0.1);
--be-color-tag-bg-hover: rgba(var(--graph_medium_rgb), 0.2);
--be-color-tag-bg-active: rgba(var(--graph_medium_rgb), 0.3);
--be-color-avatar-border: var(--line_light);
--be-color-highlight-bg-hover: rgba(var(--graph_medium_rgb), 0.1);
--be-color-panel-bg: var(--bg1);
--be-color-panel-border: var(--line_light);
--be-color-popup-bg: var(--bg1);
--be-color-popup-border: var(--line_light);
}

View File

@ -0,0 +1,3 @@
body:has(.bili-dyn-home--member) {
background-color: #11171F;
}

View File

@ -1,3 +1,24 @@
.recommended-swipe.grid-anchor {
display: none !important;
$prefix: 'hideHomeCarousel-switch';
.#{$prefix} {
&-full .recommended-swipe {
display: none !important;
}
&-transparent .recommended-swipe {
opacity: 0;
pointer-events: none;
}
&-picture .vui_carousel__slide {
display: none !important;
}
&-footerText .carousel-footer-text {
display: none !important;
}
}
.vui_carousel__slide {
filter: blur(var(--blur-amount, 0px));
}

View File

@ -1 +1,14 @@
隐藏首页的轮播图区域.
隐藏首页的轮播图区域
选项说明:
- `禁用轮播`:禁用图片轮播,可以手动切换
- `图片模糊`模糊轮播图片为0时不模糊
- `样式开关`
- `隐藏轮播区域占位`:完全隐藏整个轮播区域
- `透明化轮播区域`:完全透明化整个轮播区域,同时禁止点击打开链接
- `隐藏轮播图片`:隐藏轮播图片,同时禁止点击图片打开链接
- `隐藏图片标题`:隐藏图片标题,同时禁止点击标题打开链接
> 注:样式开关可以同时启用,但是最终显示效果以作用范围大的为准
> 例如启用 `隐藏轮播区域占位`,由于整个区域都被隐藏,不管 `隐藏轮播图片`、`隐藏图片标题` 等选项是否启用都已经看不见了

View File

@ -1,9 +1,84 @@
import { defineComponentMetadata } from '@/components/define'
import { wrapSwitchOptions } from '@/components/switch-options'
import { ComponentEntry } from '@/components/types'
import { addComponentListener } from '@/core/settings'
import { select, selectAll } from '@/core/spin-query'
import { useScopedConsole } from '@/core/utils/log'
export const component = defineComponentMetadata({
const logger = useScopedConsole('hideHomeCarousel')
// 轮播容器 mouseleave 事件拦截
const onCarouselMouseLeaveHandler = (event: MouseEvent) => {
event.stopPropagation()
}
const entry: ComponentEntry = async ({ metadata }) => {
// 监听【禁用轮播】选项
addComponentListener(
`${metadata.name}.disableCarousel`,
async (value: boolean) => {
const node = (await select('.vui_carousel')) as HTMLElement
if (!node) {
logger.error('找不到轮播容器节点')
return
}
if (value) {
node.addEventListener('mouseleave', onCarouselMouseLeaveHandler, true)
// 触发事件停止轮播
const event = new MouseEvent('mouseenter')
node.dispatchEvent(event)
} else {
node.removeEventListener('mouseleave', onCarouselMouseLeaveHandler, true)
// 触发事件恢复轮播
const event = new MouseEvent('mouseleave')
node.dispatchEvent(event)
}
},
true,
)
// 监听【图片模糊】选项
addComponentListener(
`${metadata.name}.blur`,
async (value: number) => {
const nodes = (await selectAll('.vui_carousel__slide')) as HTMLElement[]
if (!nodes || nodes.length === 0) {
logger.error('找不到轮播图片节点')
return
}
nodes.forEach(node => {
node.style.setProperty('--blur-amount', `${value}px`)
})
},
true,
)
}
export const component = wrapSwitchOptions({
name: 'hideHomeCarouselOptions',
switches: {
full: {
displayName: '隐藏轮播区域占位',
defaultValue: true,
},
transparent: {
displayName: '透明化轮播区域',
defaultValue: false,
},
picture: {
displayName: '隐藏轮播图片',
defaultValue: false,
},
footerText: {
displayName: '隐藏图片标题',
defaultValue: false,
},
},
})({
name: 'hideHomeCarousel',
displayName: '隐藏首页轮播图',
entry: none,
entry,
tags: [componentsTags.style],
urlInclude: [/^https:\/\/www\.bilibili\.com\/$/, /^https:\/\/www\.bilibili\.com\/index\.html$/],
instantStyles: [
@ -12,4 +87,19 @@ export const component = defineComponentMetadata({
style: () => import('./hide-home-carousel.scss'),
},
],
options: {
disableCarousel: {
displayName: '禁用轮播',
defaultValue: false,
},
blur: {
displayName: '图片模糊',
defaultValue: 0,
slider: {
min: 0,
max: 100,
step: 1,
},
},
},
})

View File

@ -70,7 +70,7 @@ export default Vue.extend({
padding: 6px 6px 6px 10px;
@include v-stretch(6px);
body.dark & {
background-color: #333;
background-color: var(--be-color-card-bg, #333);
}
.title {
@include semi-bold();

View File

@ -1,6 +1,9 @@
import { defineComponentMetadata } from '@/components/define'
import { useScopedConsole } from '@/core/utils/log'
import { bilibiliApi, getJsonWithCredentials } from '@/core/ajax'
import { select } from '@/core/spin-query'
import { allMutations } from '@/core/observer'
import { getUserInfo } from '@/core/user-info'
const displayName = '关注时间显示'
const console = useScopedConsole(displayName)
@ -22,20 +25,16 @@ type FollowTimeInfo = {
const midMap: Record<number, FollowTimeInfo> = {}
const insertFollowTimeToCard = (mid: number, dateStr: string, label: string) => {
const anchor = document.querySelector<HTMLAnchorElement>(
`${SELECTORS.relationCardAnchor}[href*="/${mid}"]`,
)
const anchor = dq(`${SELECTORS.relationCardAnchor}[href*="/${mid}"]`)
const card = anchor?.closest(SELECTORS.relationCardContainer)
if (!card) {
return
}
if (card.querySelector(`.${SELECTORS.relationCardTimeClass}`)) {
if (!card || card.querySelector(`.${SELECTORS.relationCardTimeClass}`)) {
return
}
const div = document.createElement('div')
div.className = SELECTORS.relationCardTimeClass
div.textContent = `${label}${dateStr}`
div.dataset.mid = mid.toString()
const sign = card.querySelector(SELECTORS.relationCardSign)
if (sign?.parentNode) {
@ -43,57 +42,37 @@ const insertFollowTimeToCard = (mid: number, dateStr: string, label: string) =>
}
}
let fetchWrapped = false
let pendingUpdate = false
const updateCards = () => {
if (pendingUpdate) {
return
}
pendingUpdate = true
requestAnimationFrame(() => {
pendingUpdate = false
const mids = Array.from(
document.querySelectorAll<HTMLAnchorElement>(SELECTORS.relationCardAnchor),
)
.map(el => el.href.match(/\/(\d+)/)?.[1])
.filter(Boolean)
.map(Number)
mids.forEach(mid => {
const data = midMap[mid]
if (data) {
const dateStr = new Date(data.mtime * 1000).toLocaleString()
insertFollowTimeToCard(mid, dateStr, data.label)
}
})
})
}
const waitForProfileContainer = () =>
new Promise<Element>(resolve => {
const check = () => document.querySelector(SELECTORS.profileFollowContainer)
let container = check()
if (container) {
resolve(container)
} else {
const observer = new MutationObserver(() => {
container = check()
if (container) {
observer.disconnect()
resolve(container)
const updateCards = (() => {
let scheduled = false
return () => {
if (scheduled) {
return
}
scheduled = true
requestAnimationFrame(() => {
scheduled = false
dqa(SELECTORS.relationCardAnchor).forEach(el => {
const match = (el as HTMLAnchorElement).href.match(/\/(\d+)/)
if (!match) {
return
}
const mid = Number(match[1])
if (Number.isNaN(mid)) {
return
}
const data = midMap[mid]
if (data) {
const dateStr = new Date(data.mtime * 1000).toLocaleString()
insertFollowTimeToCard(mid, dateStr, data.label)
}
})
observer.observe(document.body, { childList: true, subtree: true })
}
})
})
}
})()
const insertSubscribeTime = (followTimeStr: string) => {
const container = document.querySelector(SELECTORS.profileFollowContainer)
if (!container) {
return
}
if (container.querySelector(`.${SELECTORS.profileTextClass}`)) {
const container = dq(SELECTORS.profileFollowContainer)
if (!container || container.querySelector(`.${SELECTORS.profileTextClass}`)) {
return
}
@ -107,25 +86,22 @@ const insertSubscribeTime = (followTimeStr: string) => {
container.appendChild(infoEl)
}
const entry = async () => {
try {
const { addImportantStyle } = await import('@/core/style')
const { default: style } = await import('./subscribe-time.scss')
addImportantStyle(style, 'subscribe-time-style')
} catch (e) {
console.error('样式加载失败:', e)
}
if (!(unsafeWindow as any).subscribeTimeHooked) {
;(unsafeWindow as any).subscribeTimeHooked = true
const originalFetch = unsafeWindow.fetch
unsafeWindow.fetch = new Proxy(originalFetch, {
apply(target, thisArg, args) {
const url = typeof args[0] === 'string' ? args[0] : args[0].url
const urlObj = new URL(url, location.origin)
new MutationObserver(updateCards).observe(document.body, { childList: true, subtree: true })
if (!fetchWrapped) {
fetchWrapped = true
const originalFetch = unsafeWindow.fetch
unsafeWindow.fetch = new Proxy(originalFetch, {
apply(target, thisArg, args) {
const url = typeof args[0] === 'string' ? args[0] : args[0].url
if (url.includes('/x/relation/fans') || url.includes('/x/relation/followings')) {
return target.apply(thisArg, args).then(res => {
if (
urlObj.hostname === 'api.bilibili.com' &&
(urlObj.pathname.includes('/x/relation/fans') ||
urlObj.pathname.includes('/x/relation/followings'))
) {
return target
.apply(thisArg, args)
.then(res => {
res
.clone()
.json()
@ -137,54 +113,63 @@ const entry = async () => {
}
list.forEach(user => {
if (typeof user.mid === 'number' && typeof user.mtime === 'number') {
const label = url.includes('/x/relation/fans')
? 'Ta 关注你的时间'
: '你关注 Ta 的时间'
const label = url.includes('/fans') ? 'Ta 关注你的时间' : '你关注 Ta 的时间'
midMap[user.mid] = { mtime: user.mtime, label }
insertFollowTimeToCard(
user.mid,
new Date(user.mtime * 1000).toLocaleString(),
label,
)
const dateStr = new Date(user.mtime * 1000).toLocaleString()
insertFollowTimeToCard(user.mid, dateStr, label)
}
})
})
.catch(err => console.warn('JSON 解析失败:', err))
.catch(err => {
console.warn('JSON 解析失败:', err)
})
return res
})
}
return target.apply(thisArg, args)
},
})
.catch(err => {
console.warn('fetch 请求失败:', err)
throw err
})
}
return target.apply(thisArg, args)
},
})
}
const entry = async () => {
try {
const { addImportantStyle } = await import('@/core/style')
const { default: style } = await import('./subscribe-time.scss')
addImportantStyle(style, 'subscribe-time-style')
} catch (e) {
console.error('样式加载失败:', e)
}
allMutations(updateCards)
const userMid = (await getUserInfo()).mid
const match = location.href.match(/space\.bilibili\.com\/(\d+)/)
if (!match) {
console.warn('无法提取 mid')
return
}
const mid = Number(match[1])
if (mid === userMid) {
console.log('当前为本人空间,跳过关注时间显示')
return
}
const info = await bilibiliApi(
getJsonWithCredentials(`https://api.bilibili.com/x/web-interface/relation?mid=${mid}`),
)
if (!info?.relation) {
console.warn('未获取到 relation 信息')
return
}
if (!info.relation.mtime) {
console.log('当前未关注或关注时间无效')
const mtime = info?.relation?.mtime
if (!mtime) {
return
}
try {
await waitForProfileContainer()
} catch (e) {
console.warn('等待关注容器超时,跳过插入关注时间')
return
}
insertSubscribeTime(new Date(info.relation.mtime * 1000).toLocaleString())
await select(SELECTORS.profileFollowContainer)
insertSubscribeTime(new Date(mtime * 1000).toLocaleString())
}
export const component = defineComponentMetadata({
@ -200,5 +185,7 @@ export const component = defineComponentMetadata({
/https:\/\/space\.bilibili\.com\/\d+/,
],
entry,
description: { 'zh-CN': '在粉丝/关注列表及用户主页显示关注的具体时间。' },
description: {
'zh-CN': '在粉丝/关注列表及用户主页显示关注的具体时间。',
},
})

View File

@ -115,7 +115,10 @@ export default Vue.extend({
user-select: text;
box-sizing: border-box;
box-shadow: 0 0 0 1px #8884;
@include default-background-color();
background-color: #fff;
body.dark & {
background-color: var(--be-color-card-bg, #333);
}
&-item {
font-size: 14px;
@include h-center(6px);

View File

@ -1,5 +1,5 @@
{
"version": "2.10.2",
"version": "2.10.3",
"author": "Grant Howard, Coulomb-G",
"copyright": "[year], Grant Howard (https://github.com/the1812) & Coulomb-G (https://github.com/Coulomb-G)",
"license": "MIT",

View File

@ -341,8 +341,8 @@ export default Vue.extend({
color: black;
background-color: #fff;
body.dark & {
color: #eee;
background-color: #222;
color: var(--be-color-text-title, #eee);
background-color: var(--be-color-panel-bg, #222);
}
.suggest-highlight {
color: var(--theme-color);

View File

@ -133,7 +133,7 @@ export default Vue.extend({
min-width: 372px;
padding: 12px;
box-sizing: border-box;
@include card();
@include popup();
&.open {
transform: translateX(0);
}
@ -197,7 +197,7 @@ export default Vue.extend({
border-right: 1px solid #8882;
body.dark & {
background-color: #222;
background-color: var(--be-color-panel-bg, #222);
}
}
.icon-list:hover ~ .component-tags,

View File

@ -163,14 +163,14 @@ export default {
transform: translateX(calc(60% * var(--direction))) scale(1.1);
background-color: #fff;
body.dark & {
background-color: #333;
background-color: var(--be-color-button-bg, #333);
}
.be-icon {
color: #222;
fill: #222;
body.dark & {
color: #eee;
fill: #eee;
color: var(--be-color-text-title, #eee);
fill: var(--be-color-text-title, #eee);
}
}
}

View File

@ -278,8 +278,8 @@ export default {
height: var(--panel-height);
transition: opacity 0.2s 0.2s ease-out;
body.dark & {
--settings-panel-background: #222;
color: #eee;
--settings-panel-background: var(--be-color-panel-bg, #222);
color: var(--be-color-text-title, #eee);
// border-color: #333;
}
.settings-panel-header {
@ -386,7 +386,7 @@ export default {
}
}
.component-detail-panel {
@include card();
@include popup();
@include v-stretch();
top: 50%;
left: calc(100% - 12px);

36
src/cookie-store.d.ts vendored Normal file
View File

@ -0,0 +1,36 @@
interface Cookie {
domain: string
expires: number
name: string
partitioned: boolean
path: string
sameSite: 'Strict' | 'Lax' | 'None'
secure: boolean
value: string
}
interface CookieChangedEvent extends Event {
changed: Readonly<Array<Cookie>>
deleted: Readonly<Array<Cookie>>
}
interface CookieStore {
get(name: string): Promise<Cookie | null>
get(options: { name: string; url?: string }): Promise<Cookie | null>
getAll(): Promise<Cookie[]>
getAll(name: string): Promise<Cookie[]>
getAll(options: { name?: string; url?: string }): Promise<Cookie[]>
set(name: string, value: string): Promise<void>
set(options: Partial<Cookie> & { name: string; value: string }): Promise<void>
delete(name: string): Promise<void>
delete(options: { name: string; url?: string }): Promise<void>
addEventListener(eventName: 'change', handler: (event: CookieChangedEvent) => void): void
removeEventListener(eventName: 'change', handler: (event: CookieChangedEvent) => void): void
onchange: null | ((event: CookieChangedEvent) => void)
}
declare const cookieStore: CookieStore

View File

@ -29,66 +29,60 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { VIcon, ProgressRing } from '@/ui'
import type { Toast } from '.'
export default Vue.extend({
components: {
VIcon,
ProgressRing,
},
props: {
card: {
type: Object,
required: true,
},
},
data() {
return {
progressMax: 0,
remainingTime: 0,
}
},
created() {
this.readDuration()
},
methods: {
durationTick() {
const { closeTime } = this.card as Toast
if (!closeTime) {
return
}
this.remainingTime = closeTime - Number(new Date())
if (this.remainingTime > 0) {
requestAnimationFrame(() => this.durationTick())
}
},
readDuration() {
const { duration, closeTime } = this.card as Toast
if (duration) {
this.progressMax = closeTime - Number(new Date())
this.remainingTime = this.progressMax
requestAnimationFrame(() => this.durationTick())
}
},
stopTimer() {
;(this.card as Toast).clearDuration()
this.progressMax = 0
this.remainingTime = 0
},
startTimer() {
;(this.card as Toast).setDuration()
this.readDuration()
},
},
interface Props {
card: Toast
}
const props = defineProps<Props>()
const progressMax = ref(0)
const remainingTime = ref(0)
const durationTick = () => {
const { closeTime } = props.card
if (!closeTime) {
return
}
remainingTime.value = closeTime - Number(new Date())
if (remainingTime.value > 0) {
requestAnimationFrame(() => durationTick())
}
}
const readDuration = () => {
const { duration, closeTime } = props.card
if (duration) {
progressMax.value = closeTime - Number(new Date())
remainingTime.value = progressMax.value
requestAnimationFrame(() => durationTick())
}
}
const stopTimer = () => {
props.card.clearDuration()
progressMax.value = 0
remainingTime.value = 0
}
const startTimer = () => {
props.card.setDuration()
readDuration()
}
onMounted(() => {
readDuration()
})
</script>
<style lang="scss">
@import 'common';
.toast-card {
background: #fff;
background: var(--be-color-card-bg, #fff);
min-width: var(--card-min-width);
max-width: 60vw;
min-height: 87px;
@ -119,14 +113,11 @@ export default Vue.extend({
}
&-title {
font-size: 18px;
color: #444;
color: var(--be-color-text-title, #444);
opacity: 0.5;
margin: 12px;
@include semi-bold();
flex: 1 1 auto;
body.dark & {
color: #999;
}
}
&-close {
height: 24px;
@ -166,7 +157,7 @@ export default Vue.extend({
}
}
&-message {
color: #000;
color: var(--be-color-text-content, #000);
font-size: 14px;
margin: 0 16px 12px 12px;
white-space: pre-wrap;
@ -196,19 +187,19 @@ export default Vue.extend({
display: inline-block;
padding: 2px 4px;
margin: 2px;
background-color: #8882;
background-color: var(--be-color-tag-bg, #8882);
color: var(--be-color-text-content, #000);
text-decoration: none;
color: #000;
transition: all 0.2s ease-out;
border-radius: 6px;
}
.link {
cursor: pointer;
&:hover {
background-color: #8883;
background-color: var(--be-color-tag-bg-hover, #8883);
}
&:active {
background-color: #8884;
background-color: var(--be-color-tag-bg-active, #8884);
}
}
.download-link,

View File

@ -1,4 +1,8 @@
.tippy-box {
.tippy-box.tippy-box {
font-size: inherit;
filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.2));
background-color: var(--be-color-tooltip-bg, #333);
}
.tippy-arrow.tippy-arrow {
color: var(--be-color-tooltip-bg, #333);
}

View File

@ -322,7 +322,7 @@ export default Vue.extend({
-webkit-tap-highlight-color: transparent;
}
body.dark & {
color: #eee;
color: var(--be-color-text-title, #eee);
}
.selected-color {
cursor: pointer;

View File

@ -71,7 +71,7 @@ export default Vue.extend({
.bar {
position: relative;
background-color: #8884;
background-color: var(--be-color-switch-bg, #8884);
// box-shadow: 0 1px 4px 0 #0004 inset;
@include round-bar(12);
.thumb {
@ -86,8 +86,8 @@ export default Vue.extend({
border: 1px solid #ddd;
// box-shadow: 0 1px 8px 0px #0004;
body.dark & {
border-color: #555;
background-color: #666;
border-color: var(--be-color-thumb-border, #555);
background-color: var(--be-color-thumb-bg, #666);
}
}
}

View File

@ -48,14 +48,14 @@ export default Vue.extend({
color: black;
font-size: inherit;
body.dark & {
color: #eee;
color: var(--be-color-text-content, #eee);
}
&:disabled {
opacity: 0.3;
cursor: not-allowed;
}
&::-webkit-input-placeholder {
color: #888;
color: var(--be-color-text-placeholder, #888);
}
}
}

View File

@ -56,14 +56,14 @@ export default Vue.extend({
width: 0;
font-size: inherit;
body.dark & {
color: #eee;
color: var(--be-color-text-content, #eee);
}
&:disabled {
opacity: 0.3;
cursor: not-allowed;
}
&::-webkit-input-placeholder {
color: #888;
color: var(--be-color-text-placeholder, #888);
}
}
&.linear {

View File

@ -59,7 +59,7 @@ export default Vue.extend({
-webkit-tap-highlight-color: transparent;
}
body.dark & {
color: #eee;
color: var(--be-color-text-title, #eee);
}
&.round {
border-radius: calc(1em + 8px);
@ -93,7 +93,7 @@ export default Vue.extend({
transition: box-shadow 0.2s ease-out;
}
body.dark &.light {
background-color: #333;
background-color: var(--be-color-button-bg, #333);
// box-shadow: 0 0 0 1px transparent;
}
&:not(.disabled) {
@ -135,12 +135,12 @@ export default Vue.extend({
}
body.dark &.light {
&:hover {
background-color: #333;
background-color: var(--be-color-button-bg, #333);
box-shadow: 0 0 0 1px var(--theme-color);
}
&:active,
&:focus-within {
background-color: #333;
background-color: var(--be-color-button-bg, #333);
box-shadow: 0 0 0 1px var(--theme-color), 0 0 0 3px var(--theme-color-20);
}
}

View File

@ -160,7 +160,7 @@ export default Vue.extend({
outline: none !important;
}
body.dark & {
background-color: #333;
background-color: var(--be-color-button-bg, #333);
}
&:not(.disabled) {
&:hover {

View File

@ -84,14 +84,14 @@
box-sizing: border-box;
@include shadow();
body.dark & {
background-color: #282828;
color: #eee;
background-color: var(--be-color-card-bg, #282828);
color: var(--be-color-text-title, #eee);
}
}
@mixin popup($radius: 8px) {
@include card($radius);
body.dark & {
background-color: #222;
background-color: var(--be-color-popup-bg, #222);
}
}
@mixin border-card($radius: 8px) {
@ -100,9 +100,9 @@
border-radius: $radius;
border: 1px solid #e8e8e8;
body.dark & {
background-color: #222;
color: #eee;
border-color: #333;
background-color: var(--be-color-card-bg, #222);
color: var(--be-color-text-title, #eee);
border-color: var(--be-color-card-border, #333);
}
}
// @mixin popup($radius: 8px) {
@ -123,15 +123,15 @@
fill: black;
stroke: black;
body.dark & {
color: #eee;
fill: #eee;
stroke: #eee;
color: var(--be-color-text-title, #eee);
fill: var(--be-color-text-title, #eee);
stroke: var(--be-color-text-title, #eee);
}
}
@mixin semi-bold {
font-weight: 600;
}
@mixin default-background-color($dark-color: #333) {
@mixin default-background-color($dark-color: var(--be-color-panel-bg, #333)) {
background-color: #fff;
body.dark & {
background-color: $dark-color;