Compare commits

...

16 Commits

Author SHA1 Message Date
Soybean
56ad0df974 chore(projects): release v2.0.0-beta.1 2025-10-25 15:06:55 +08:00
Soybean
6cbf5705bb chore(deps): update deps 2025-10-25 15:01:41 +08:00
Soybean
87a66a4236 optimize(projects): optimize radius settings 2025-10-25 14:52:10 +08:00
CyberShen123
3549c4dbd5 feat(projects): support set global redius 2025-10-25 14:47:04 +08:00
CyberShen123
24c6df528b feat(projects): support set global redius 2025-10-25 14:47:04 +08:00
whyang
dac5075be9 fix(styles): show light color scrollbar while dark mode is on 2025-10-25 14:42:18 +08:00
wenyuan
a8d1e5d266 feat(projects): support closing tabs with middle mouse button click 2025-10-25 14:34:33 +08:00
wenyuan
345aa2932f feat(styles): add text-autospace property to improve text layout 2025-10-25 14:25:20 +08:00
Soybean
d5a3a25d3d fix(types): fix ts type error 2025-10-13 16:48:33 +08:00
Soybean
d567c057a8 chore(deps): update deps 2025-10-13 16:39:36 +08:00
HongxuanG
91fae50260 typo(other): Correct the typos in the Chinese translation and change "局右" to "居右"。 2025-10-04 00:08:25 +08:00
Lijun Shen
61fa4b7f3b feat(packages): materials support slider-tab. closed #823 2025-10-02 22:09:59 +08:00
Azir-11
ef7acc626f feat(projects): optimize tabs cache cleaning strategy. close #820. 2025-10-02 11:17:44 +08:00
恕瑞玛的皇帝
2a0c9f1b41 docs(projects): add github trendshift info. 2025-09-27 21:18:05 +08:00
Soybean
5be864a80b fix(packages): axios: fix json response. fixed #815 2025-09-17 17:06:01 +08:00
Soybean
b041fdd864 chore(deps): update deps 2025-09-17 14:38:20 +08:00
43 changed files with 1580 additions and 1356 deletions

View File

@@ -1,6 +1,117 @@
# Changelog # Changelog
## [v2.0.0-beta.1](https://github.com/soybeanjs/soybean-admin/compare/v1.3.15...v2.0.0-beta.1) (2025-10-25)
###    🚨 Breaking Changes
- **hooks**: refactor useTable and enhance type definitions &nbsp;-&nbsp; by @soybeanjs [<samp>(8cc51)</samp>](https://github.com/soybeanjs/soybean-admin/commit/8cc5177)
- **projects**: optimize layout mode, split horizontal mix component into two layouts, and rename the component. &nbsp;-&nbsp; by **Azir** [<samp>(b6ac3)</samp>](https://github.com/soybeanjs/soybean-admin/commit/b6ac310)
- **request**: remove cancelRequest method and related logic from request instances &nbsp;-&nbsp; by @soybeanjs [<samp>(b4e12)</samp>](https://github.com/soybeanjs/soybean-admin/commit/b4e1253)
### &nbsp;&nbsp;&nbsp;🚀 Features
- **components**:
- add the IconTooltip component. &nbsp;-&nbsp; by **Azir-11** [<samp>(a55b4)</samp>](https://github.com/soybeanjs/soybean-admin/commit/a55b4dc)
- replace NTooltip with IconTooltip and optimize the layout of related components. &nbsp;-&nbsp; by **Azir-11** [<samp>(40057)</samp>](https://github.com/soybeanjs/soybean-admin/commit/4005763)
- **hooks**:
- add scrollX computation for total table width in useNaiveTable &nbsp;-&nbsp; by @Lruihao [<samp>(358e1)</samp>](https://github.com/soybeanjs/soybean-admin/commit/358e129)
- **packages**:
- materials support slider-tab. closed #823 &nbsp;-&nbsp; by @CyberShen in https://github.com/soybeanjs/soybean-admin/issues/823 [<samp>(61fa4)</samp>](https://github.com/soybeanjs/soybean-admin/commit/61fa4b7)
- **projects**:
- refactor theme drawer with tabbed layout for better UX. &nbsp;-&nbsp; by **Azir** [<samp>(8ba71)</samp>](https://github.com/soybeanjs/soybean-admin/commit/8ba71a0)
- Add current time display option for watermark &nbsp;-&nbsp; by @wenyuanw in https://github.com/soybeanjs/soybean-admin/issues/772 [<samp>(f238f)</samp>](https://github.com/soybeanjs/soybean-admin/commit/f238fcb)
- add 'vertical-hybrid-header-first' layout mode &nbsp;-&nbsp; by @wenyuanw [<samp>(b4e5c)</samp>](https://github.com/soybeanjs/soybean-admin/commit/b4e5c6d)
- add prompt information for scrolling mode and tab bar caching. &nbsp;-&nbsp; by **Azir-11** [<samp>(29a2a)</samp>](https://github.com/soybeanjs/soybean-admin/commit/29a2a5c)
- support theme preset function. &nbsp;-&nbsp; by **Azir-11** [<samp>(257f1)</samp>](https://github.com/soybeanjs/soybean-admin/commit/257f118)
- modify the default value of the reset cache policy to 'refresh'. &nbsp;-&nbsp; by **Azir-11** [<samp>(3c0a5)</samp>](https://github.com/soybeanjs/soybean-admin/commit/3c0a528)
- optimize tabs cache cleaning strategy. close #820. &nbsp;-&nbsp; by **Azir-11** in https://github.com/soybeanjs/soybean-admin/issues/820 [<samp>(ef7ac)</samp>](https://github.com/soybeanjs/soybean-admin/commit/ef7acc6)
- support closing tabs with middle mouse button click &nbsp;-&nbsp; by @wenyuanw [<samp>(a8d1e)</samp>](https://github.com/soybeanjs/soybean-admin/commit/a8d1e5d)
- support set global redius &nbsp;-&nbsp; by **CyberShen123** [<samp>(24c6d)</samp>](https://github.com/soybeanjs/soybean-admin/commit/24c6df5)
- support set global redius &nbsp;-&nbsp; by **CyberShen123** [<samp>(3549c)</samp>](https://github.com/soybeanjs/soybean-admin/commit/3549c4d)
- **styles**:
- add text-autospace property to improve text layout &nbsp;-&nbsp; by @wenyuanw [<samp>(345aa)</samp>](https://github.com/soybeanjs/soybean-admin/commit/345aa29)
### &nbsp;&nbsp;&nbsp;🐞 Bug Fixes
- **hooks**:
- correct chart rendering logic in useEcharts &nbsp;-&nbsp; by @soybeanjs [<samp>(8a7cd)</samp>](https://github.com/soybeanjs/soybean-admin/commit/8a7cd59)
- **packages**:
- fix the parsing logic for stored data to ensure correct return of boolean values &nbsp;-&nbsp; by @Lruihao [<samp>(9ea56)</samp>](https://github.com/soybeanjs/soybean-admin/commit/9ea56c9)
- axios: fix json response. fixed #815 &nbsp;-&nbsp; by @soybeanjs in https://github.com/soybeanjs/soybean-admin/issues/815 [<samp>(5be86)</samp>](https://github.com/soybeanjs/soybean-admin/commit/5be864a)
- **projects**:
- Fix i18n-ally not working when setting moduleResolution to bundler. fixed #780 &nbsp;-&nbsp; by @xiaobao0505 in https://github.com/soybeanjs/soybean-admin/issues/780 [<samp>(41191)</samp>](https://github.com/soybeanjs/soybean-admin/commit/41191d5)
- **styles**:
- show light color scrollbar while dark mode is on &nbsp;-&nbsp; by **whyang** [<samp>(dac50)</samp>](https://github.com/soybeanjs/soybean-admin/commit/dac5075)
- **table**:
- add type annotations for records in useTable hook &nbsp;-&nbsp; by @soybeanjs [<samp>(32b8f)</samp>](https://github.com/soybeanjs/soybean-admin/commit/32b8f99)
- **types**:
- fix proxy types &nbsp;-&nbsp; by @soybeanjs [<samp>(3d72f)</samp>](https://github.com/soybeanjs/soybean-admin/commit/3d72f95)
- fix ts type error &nbsp;-&nbsp; by @soybeanjs [<samp>(d5a3a)</samp>](https://github.com/soybeanjs/soybean-admin/commit/d5a3a25)
### &nbsp;&nbsp;&nbsp;🛠 Optimizations
- **hooks**:
- optimize useEcharts &nbsp;-&nbsp; by @soybeanjs [<samp>(936b8)</samp>](https://github.com/soybeanjs/soybean-admin/commit/936b834)
- **packages**:
- remove ofetch package &nbsp;-&nbsp; by @soybeanjs [<samp>(abaaa)</samp>](https://github.com/soybeanjs/soybean-admin/commit/abaaa4a)
- **projects**:
- improve theme drawer responsive width for mobile devices &nbsp;-&nbsp; by @wenyuanw [<samp>(8439a)</samp>](https://github.com/soybeanjs/soybean-admin/commit/8439a60)
- improve robustness of second-level menu key logic &nbsp;-&nbsp; by @wenyuanw [<samp>(8b8a2)</samp>](https://github.com/soybeanjs/soybean-admin/commit/8b8a208)
- optimize theme drawer width &nbsp;-&nbsp; by @soybeanjs [<samp>(81468)</samp>](https://github.com/soybeanjs/soybean-admin/commit/8146858)
- optimize api type file &nbsp;-&nbsp; by @soybeanjs [<samp>(3a343)</samp>](https://github.com/soybeanjs/soybean-admin/commit/3a343ee)
- optimize radius settings &nbsp;-&nbsp; by @soybeanjs [<samp>(87a66)</samp>](https://github.com/soybeanjs/soybean-admin/commit/87a66a4)
- **request**:
- enhance request options and response handling with generic types &nbsp;-&nbsp; by @soybeanjs [<samp>(50a5c)</samp>](https://github.com/soybeanjs/soybean-admin/commit/50a5cba)
### &nbsp;&nbsp;&nbsp;💅 Refactors
- **hooks**:
- optimize useContext and update useMixMenuContext &nbsp;-&nbsp; by @soybeanjs [<samp>(c9651)</samp>](https://github.com/soybeanjs/soybean-admin/commit/c965140)
- streamline column visibility handling in useTable and table components &nbsp;-&nbsp; by @soybeanjs [<samp>(ee434)</samp>](https://github.com/soybeanjs/soybean-admin/commit/ee43414)
- remove useSignal hook and update exports &nbsp;-&nbsp; by @soybeanjs [<samp>(87adc)</samp>](https://github.com/soybeanjs/soybean-admin/commit/87adc35)
- **menu**:
- optimize the margin on the menu &nbsp;-&nbsp; by **NicholasLD** [<samp>(d7311)</samp>](https://github.com/soybeanjs/soybean-admin/commit/d731111)
- **projects**:
- remove unnecessary logic in onRouteSwitchWhenLoggedIn &nbsp;-&nbsp; by @wenyuanw [<samp>(d6c81)</samp>](https://github.com/soybeanjs/soybean-admin/commit/d6c8142)
- **request**:
- unify response transformation methods and deprecate transformBackendResponse &nbsp;-&nbsp; by @soybeanjs [<samp>(f83ee)</samp>](https://github.com/soybeanjs/soybean-admin/commit/f83eefb)
- **types**:
- move Auth and Route namespaces to separate files and clean up api.d.ts &nbsp;-&nbsp; by **Azir** [<samp>(d37ce)</samp>](https://github.com/soybeanjs/soybean-admin/commit/d37ce04)
### &nbsp;&nbsp;&nbsp;📖 Documentation
- **projects**: add github trendshift info. &nbsp;-&nbsp; by **恕瑞玛的皇帝** [<samp>(2a0c9)</samp>](https://github.com/soybeanjs/soybean-admin/commit/2a0c9f1)
### &nbsp;&nbsp;&nbsp;🏡 Chore
- **deps**:
- update NodeJS and pnpm version requirements in package.json and documentation &nbsp;-&nbsp; by **Junior25306** [<samp>(a5c4b)</samp>](https://github.com/soybeanjs/soybean-admin/commit/a5c4b4e)
- update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(5cb1c)</samp>](https://github.com/soybeanjs/soybean-admin/commit/5cb1ceb)
- update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(aeb63)</samp>](https://github.com/soybeanjs/soybean-admin/commit/aeb6369)
- update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(e89b8)</samp>](https://github.com/soybeanjs/soybean-admin/commit/e89b86c)
- update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(c962f)</samp>](https://github.com/soybeanjs/soybean-admin/commit/c962f7b)
- update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(12135)</samp>](https://github.com/soybeanjs/soybean-admin/commit/1213531)
- update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(b041f)</samp>](https://github.com/soybeanjs/soybean-admin/commit/b041fdd)
- update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(d567c)</samp>](https://github.com/soybeanjs/soybean-admin/commit/d567c05)
- update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(6cbf5)</samp>](https://github.com/soybeanjs/soybean-admin/commit/6cbf570)
- **other**:
- update the ESLint validation configuration to support more file types. &nbsp;-&nbsp; by **Azir-11** [<samp>(be8f9)</samp>](https://github.com/soybeanjs/soybean-admin/commit/be8f915)
- **packages**:
- update Vite version to 7 in package.json and documentation. &nbsp;-&nbsp; by **Azir** [<samp>(03dd6)</samp>](https://github.com/soybeanjs/soybean-admin/commit/03dd64c)
- add picomatch to fix scripts &nbsp;-&nbsp; by @soybeanjs [<samp>(805c3)</samp>](https://github.com/soybeanjs/soybean-admin/commit/805c338)
- **vscode**:
- remove unused vue.server.hybridMode setting from .vscode/settings.json &nbsp;-&nbsp; by @soybeanjs [<samp>(13319)</samp>](https://github.com/soybeanjs/soybean-admin/commit/133196f)
### &nbsp;&nbsp;&nbsp;🎨 Styles
- **projects**: format code. &nbsp;-&nbsp; by **Azir-11** [<samp>(100e0)</samp>](https://github.com/soybeanjs/soybean-admin/commit/100e0ea)
### &nbsp;&nbsp;&nbsp;❤️ Contributors
[![soybeanjs](https://github.com/soybeanjs.png?size=48)](https://github.com/soybeanjs)&nbsp;&nbsp;[![wenyuanw](https://github.com/wenyuanw.png?size=48)](https://github.com/wenyuanw)&nbsp;&nbsp;[![CyberShen](https://github.com/CyberShen.png?size=48)](https://github.com/CyberShen)&nbsp;&nbsp;[![Lruihao](https://github.com/Lruihao.png?size=48)](https://github.com/Lruihao)&nbsp;&nbsp;[![xiaobao0505](https://github.com/xiaobao0505.png?size=48)](https://github.com/xiaobao0505)&nbsp;&nbsp;
[CyberShen123](mailto:s.lijun@qq.com),&nbsp;[whyang](mailto:whyang9701@gmail.com),&nbsp;[HongxuanG](mailto:1359774872@qq.com),&nbsp;[Azir-11](mailto:2075125282@qq.com),&nbsp;[NicholasLD](mailto:878639947@qq.com),&nbsp;[Junior25306](mailto:dayu429@qq.com)
## [v1.3.15](https://github.com/soybeanjs/soybean-admin/compare/v1.3.14...v1.3.15) (2025-06-24) ## [v1.3.15](https://github.com/soybeanjs/soybean-admin/compare/v1.3.14...v1.3.15) (2025-06-24)
### &nbsp;&nbsp;&nbsp;🚀 Features ### &nbsp;&nbsp;&nbsp;🚀 Features

View File

@@ -13,8 +13,10 @@
[![gitcode star](https://gitcode.com/soybeanjs/soybean-admin/star/badge.svg)](https://gitcode.com/soybeanjs/soybean-admin) [![gitcode star](https://gitcode.com/soybeanjs/soybean-admin/star/badge.svg)](https://gitcode.com/soybeanjs/soybean-admin)
[![Powered by DartNode](https://dartnode.com/branding/DN-Open-Source-sm.png)](https://dartnode.com "Powered by DartNode - Free VPS for Open Source") [![Powered by DartNode](https://dartnode.com/branding/DN-Open-Source-sm.png)](https://dartnode.com "Powered by DartNode - Free VPS for Open Source")
<a href="https://hellogithub.com/repository/1298f27d5fe54959a16cf9686516ddb3" target="_blank"><img src="https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=1298f27d5fe54959a16cf9686516ddb3&claim_uid=IiDXWmP4TEntjbV" alt="FeaturedHelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a> <div style="display: flex; gap: 12px; align-items: center;">
<a href="https://trendshift.io/repositories/7963" target="_blank"><img src="https://trendshift.io/api/badge/repositories/7963" alt="soybeanjs%2Fsoybean-admin | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
<a href="https://hellogithub.com/repository/1298f27d5fe54959a16cf9686516ddb3" target="_blank"><img src="https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=1298f27d5fe54959a16cf9686516ddb3&claim_uid=IiDXWmP4TEntjbV" alt="FeaturedHelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</div>
> [!NOTE] > [!NOTE]
> If you think `SoybeanAdmin` is helpful to you, or you like our project, please give us a ⭐️ on GitHub. Your support is the driving force for us to continue to improve and add new features! Thank you for your support! > If you think `SoybeanAdmin` is helpful to you, or you like our project, please give us a ⭐️ on GitHub. Your support is the driving force for us to continue to improve and add new features! Thank you for your support!

View File

@@ -13,7 +13,10 @@
[![gitcode star](https://gitcode.com/soybeanjs/soybean-admin/star/badge.svg)](https://gitcode.com/soybeanjs/soybean-admin) [![gitcode star](https://gitcode.com/soybeanjs/soybean-admin/star/badge.svg)](https://gitcode.com/soybeanjs/soybean-admin)
[![Powered by DartNode](https://dartnode.com/branding/DN-Open-Source-sm.png)](https://dartnode.com "Powered by DartNode - Free VPS for Open Source") [![Powered by DartNode](https://dartnode.com/branding/DN-Open-Source-sm.png)](https://dartnode.com "Powered by DartNode - Free VPS for Open Source")
<a href="https://hellogithub.com/repository/1298f27d5fe54959a16cf9686516ddb3" target="_blank"><img src="https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=1298f27d5fe54959a16cf9686516ddb3&claim_uid=IiDXWmP4TEntjbV" alt="FeaturedHelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a> <div style="display: flex; gap: 12px; align-items: center;">
<a href="https://trendshift.io/repositories/7963" target="_blank"><img src="https://trendshift.io/api/badge/repositories/7963" alt="soybeanjs%2Fsoybean-admin | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
<a href="https://hellogithub.com/repository/1298f27d5fe54959a16cf9686516ddb3" target="_blank"><img src="https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=1298f27d5fe54959a16cf9686516ddb3&claim_uid=IiDXWmP4TEntjbV" alt="FeaturedHelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</div>
> [!NOTE] > [!NOTE]
> 如果您觉得 `SoybeanAdmin`对您有所帮助,或者您喜欢我们的项目,请在 GitHub 上给我们一个 ⭐️。您的支持是我们持续改进和增加新功能的动力!感谢您的支持! > 如果您觉得 `SoybeanAdmin`对您有所帮助,或者您喜欢我们的项目,请在 GitHub 上给我们一个 ⭐️。您的支持是我们持续改进和增加新功能的动力!感谢您的支持!

View File

@@ -1,7 +1,7 @@
{ {
"name": "soybean-admin", "name": "soybean-admin",
"type": "module", "type": "module",
"version": "1.3.15", "version": "2.0.0-beta.1",
"description": "A fresh and elegant admin template, based on Vue3、Vite7、TypeScript、NaiveUI and UnoCSS. 一个基于Vue3、Vite7、TypeScript、NaiveUI and UnoCSS的清新优雅的中后台模版。", "description": "A fresh and elegant admin template, based on Vue3、Vite7、TypeScript、NaiveUI and UnoCSS. 一个基于Vue3、Vite7、TypeScript、NaiveUI and UnoCSS的清新优雅的中后台模版。",
"author": { "author": {
"name": "Soybean", "name": "Soybean",
@@ -54,53 +54,53 @@
"@sa/hooks": "workspace:*", "@sa/hooks": "workspace:*",
"@sa/materials": "workspace:*", "@sa/materials": "workspace:*",
"@sa/utils": "workspace:*", "@sa/utils": "workspace:*",
"@vueuse/core": "13.8.0", "@vueuse/core": "14.0.0",
"clipboard": "2.0.11", "clipboard": "2.0.11",
"dayjs": "1.11.14", "dayjs": "1.11.18",
"defu": "6.1.4", "defu": "6.1.4",
"echarts": "6.0.0", "echarts": "6.0.0",
"json5": "2.2.3", "json5": "2.2.3",
"naive-ui": "2.42.0", "naive-ui": "2.43.1",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"pinia": "3.0.3", "pinia": "3.0.3",
"tailwind-merge": "3.3.1", "tailwind-merge": "3.3.1",
"vue": "3.5.20", "vue": "3.5.22",
"vue-draggable-plus": "0.6.0", "vue-draggable-plus": "0.6.0",
"vue-i18n": "11.1.11", "vue-i18n": "11.1.12",
"vue-router": "4.5.1" "vue-router": "4.6.3"
}, },
"devDependencies": { "devDependencies": {
"@elegant-router/vue": "0.3.8", "@elegant-router/vue": "0.3.8",
"@iconify/json": "2.2.378", "@iconify/json": "2.2.400",
"@sa/scripts": "workspace:*", "@sa/scripts": "workspace:*",
"@sa/uno-preset": "workspace:*", "@sa/uno-preset": "workspace:*",
"@soybeanjs/eslint-config": "1.7.1", "@soybeanjs/eslint-config": "1.7.1",
"@types/node": "24.3.0", "@types/node": "24.9.1",
"@types/nprogress": "0.2.3", "@types/nprogress": "0.2.3",
"@unocss/eslint-config": "66.4.2", "@unocss/eslint-config": "66.5.4",
"@unocss/preset-icons": "66.4.2", "@unocss/preset-icons": "66.5.4",
"@unocss/preset-uno": "66.4.2", "@unocss/preset-uno": "66.5.4",
"@unocss/transformer-directives": "66.4.2", "@unocss/transformer-directives": "66.5.4",
"@unocss/transformer-variant-group": "66.4.2", "@unocss/transformer-variant-group": "66.5.4",
"@unocss/vite": "66.4.2", "@unocss/vite": "66.5.4",
"@vitejs/plugin-vue": "6.0.1", "@vitejs/plugin-vue": "6.0.1",
"@vitejs/plugin-vue-jsx": "5.1.0", "@vitejs/plugin-vue-jsx": "5.1.1",
"consola": "3.4.2", "consola": "3.4.2",
"eslint": "9.34.0", "eslint": "9.38.0",
"eslint-plugin-vue": "10.4.0", "eslint-plugin-vue": "10.5.1",
"kolorist": "1.8.0", "kolorist": "1.8.0",
"sass": "1.91.0", "sass": "1.93.2",
"simple-git-hooks": "2.13.1", "simple-git-hooks": "2.13.1",
"tsx": "4.20.5", "tsx": "4.20.6",
"typescript": "5.9.2", "typescript": "5.9.3",
"unplugin-icons": "22.2.0", "unplugin-icons": "22.5.0",
"unplugin-vue-components": "29.0.0", "unplugin-vue-components": "30.0.0",
"vite": "7.1.3", "vite": "7.1.12",
"vite-plugin-progress": "0.0.7", "vite-plugin-progress": "0.0.7",
"vite-plugin-svg-icons": "2.0.1", "vite-plugin-svg-icons": "2.0.1",
"vite-plugin-vue-devtools": "8.0.1", "vite-plugin-vue-devtools": "8.0.3",
"vue-eslint-parser": "10.2.0", "vue-eslint-parser": "10.2.0",
"vue-tsc": "3.0.6" "vue-tsc": "3.1.2"
}, },
"simple-git-hooks": { "simple-git-hooks": {
"commit-msg": "pnpm sa git-commit-verify", "commit-msg": "pnpm sa git-commit-verify",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sa/alova", "name": "@sa/alova",
"version": "1.3.15", "version": "2.0.0-beta.1",
"exports": { "exports": {
".": "./src/index.ts", ".": "./src/index.ts",
"./fetch": "./src/fetch.ts", "./fetch": "./src/fetch.ts",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sa/axios", "name": "@sa/axios",
"version": "1.3.15", "version": "2.0.0-beta.1",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },
@@ -11,7 +11,7 @@
}, },
"dependencies": { "dependencies": {
"@sa/utils": "workspace:*", "@sa/utils": "workspace:*",
"axios": "1.11.0", "axios": "1.12.2",
"axios-retry": "4.5.0", "axios-retry": "4.5.0",
"qs": "6.14.0" "qs": "6.14.0"
}, },

View File

@@ -3,6 +3,7 @@ import type { AxiosResponse, CreateAxiosDefaults, InternalAxiosRequestConfig } f
import axiosRetry from 'axios-retry'; import axiosRetry from 'axios-retry';
import { nanoid } from '@sa/utils'; import { nanoid } from '@sa/utils';
import { createAxiosConfig, createDefaultOptions, createRetryOptions } from './options'; import { createAxiosConfig, createDefaultOptions, createRetryOptions } from './options';
import { transformResponse } from './shared';
import { BACKEND_ERROR_CODE, REQUEST_ID_KEY } from './constant'; import { BACKEND_ERROR_CODE, REQUEST_ID_KEY } from './constant';
import type { import type {
CustomAxiosRequestConfig, CustomAxiosRequestConfig,
@@ -53,6 +54,8 @@ function createCommonRequest<
async response => { async response => {
const responseType: ResponseType = (response.config?.responseType as ResponseType) || 'json'; const responseType: ResponseType = (response.config?.responseType as ResponseType) || 'json';
await transformResponse(response);
if (responseType !== 'json' || opts.isBackendSuccess(response)) { if (responseType !== 'json' || opts.isBackendSuccess(response)) {
return Promise.resolve(response); return Promise.resolve(response);
} }

View File

@@ -1,4 +1,5 @@
import type { AxiosHeaderValue, AxiosResponse, InternalAxiosRequestConfig } from 'axios'; import type { AxiosHeaderValue, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import type { ResponseType } from './type';
export function getContentType(config: InternalAxiosRequestConfig) { export function getContentType(config: InternalAxiosRequestConfig) {
const contentType: AxiosHeaderValue = config.headers?.['Content-Type'] || 'application/json'; const contentType: AxiosHeaderValue = config.headers?.['Content-Type'] || 'application/json';
@@ -26,3 +27,53 @@ export function isResponseJson(response: AxiosResponse) {
return responseType === 'json' || responseType === undefined; return responseType === 'json' || responseType === undefined;
} }
export async function transformResponse(response: AxiosResponse) {
const responseType: ResponseType = (response.config?.responseType as ResponseType) || 'json';
if (responseType === 'json') return;
const isJson = response.headers['content-type']?.includes('application/json');
if (!isJson) return;
if (responseType === 'blob') {
await transformBlobToJson(response);
}
if (responseType === 'arrayBuffer') {
await transformArrayBufferToJson(response);
}
}
export async function transformBlobToJson(response: AxiosResponse) {
try {
let data = response.data;
if (typeof data === 'string') {
data = JSON.parse(data);
}
if (Object.prototype.toString.call(data) === '[object Blob]') {
const json = await data.text();
data = JSON.parse(json);
}
response.data = data;
} catch {}
}
export async function transformArrayBufferToJson(response: AxiosResponse) {
try {
let data = response.data;
if (typeof data === 'string') {
data = JSON.parse(data);
}
if (Object.prototype.toString.call(data) === '[object ArrayBuffer]') {
const json = new TextDecoder().decode(data);
data = JSON.parse(json);
}
response.data = data;
} catch {}
}

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sa/color", "name": "@sa/color",
"version": "1.3.15", "version": "2.0.0-beta.1",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sa/hooks", "name": "@sa/hooks",
"version": "1.3.15", "version": "2.0.0-beta.1",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sa/materials", "name": "@sa/materials",
"version": "1.3.15", "version": "2.0.0-beta.1",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

View File

@@ -95,3 +95,27 @@
.chrome-tab_dark .chrome-tab-divider { .chrome-tab_dark .chrome-tab-divider {
background-color: rgba(255, 255, 255, 0.9); background-color: rgba(255, 255, 255, 0.9);
} }
.slider-tab {
background-color: transparent;
height: 100%;
border-bottom: 2px solid transparent;
}
.slider-tab_dark {
background-color: transparent;
}
.slider-tab:hover {
color: var(--soy-primary-color);
}
.slider-tab_active {
color: var(--soy-primary-color);
background-color: var(--soy-primary-color-opacity1);
border-bottom-color: var(--soy-primary-color);
}
.slider-tab_active_dark {
background-color: var(--soy-primary-color-opacity2);
}

View File

@@ -10,6 +10,10 @@ declare const styles: {
readonly 'chrome-tab_dark': string; readonly 'chrome-tab_dark': string;
readonly 'chrome-tab-divider': string; readonly 'chrome-tab-divider': string;
readonly 'svg-close': string; readonly 'svg-close': string;
readonly 'slider-tab': string;
readonly 'slider-tab_active': string;
readonly 'slider-tab_active_dark': string;
readonly 'slider-tab_dark': string;
}; };
export default styles; export default styles;

View File

@@ -5,6 +5,7 @@ import type { PageTabMode, PageTabProps } from '../../types';
import { ACTIVE_COLOR, createTabCssVars } from './shared'; import { ACTIVE_COLOR, createTabCssVars } from './shared';
import ChromeTab from './chrome-tab.vue'; import ChromeTab from './chrome-tab.vue';
import ButtonTab from './button-tab.vue'; import ButtonTab from './button-tab.vue';
import SliderTab from './slider-tab.vue';
import SvgClose from './svg-close.vue'; import SvgClose from './svg-close.vue';
import style from './index.module.css'; import style from './index.module.css';
@@ -26,7 +27,7 @@ interface Emits {
const emit = defineEmits<Emits>(); const emit = defineEmits<Emits>();
const activeTabComponent = computed(() => { const activeTabComponent = computed(() => {
const { mode, chromeClass, buttonClass } = props; const { mode, chromeClass, buttonClass, sliderClass } = props;
const tabComponentMap = { const tabComponentMap = {
chrome: { chrome: {
@@ -36,6 +37,10 @@ const activeTabComponent = computed(() => {
button: { button: {
component: ButtonTab, component: ButtonTab,
class: buttonClass class: buttonClass
},
slider: {
component: SliderTab,
class: sliderClass
} }
} satisfies Record<PageTabMode, { component: Component; class?: string }>; } satisfies Record<PageTabMode, { component: Component; class?: string }>;
@@ -45,7 +50,7 @@ const activeTabComponent = computed(() => {
const cssVars = computed(() => createTabCssVars(props.activeColor)); const cssVars = computed(() => createTabCssVars(props.activeColor));
const bindProps = computed(() => { const bindProps = computed(() => {
const { chromeClass: _chromeCls, buttonClass: _btnCls, ...rest } = props; const { chromeClass: _chromeCls, buttonClass: _btnCls, sliderClass: _sliderCls, ...rest } = props;
return rest; return rest;
}); });

View File

@@ -0,0 +1,53 @@
<script setup lang="ts">
import type { PageTabProps } from '../../types';
import style from './index.module.css';
defineOptions({
name: 'SliderTab'
});
defineProps<PageTabProps>();
type SlotFn = (props?: Record<string, unknown>) => any;
type Slots = {
/**
* Slot
*
* The center content of the tab
*/
default?: SlotFn;
/**
* Slot
*
* The left content of the tab
*/
prefix?: SlotFn;
/**
* Slot
*
* The right content of the tab
*/
suffix?: SlotFn;
};
defineSlots<Slots>();
</script>
<template>
<div
class=":soy: relative inline-flex cursor-pointer items-center justify-center gap-6px whitespace-nowrap px-12px py-4px"
:class="[
style['slider-tab'],
{ [style['slider-tab_dark']]: darkMode },
{ [style['slider-tab_active']]: active },
{ [style['slider-tab_active_dark']]: active && darkMode }
]"
>
<slot name="prefix"></slot>
<slot></slot>
<slot name="suffix"></slot>
</div>
</template>
<style scoped></style>

View File

@@ -239,7 +239,7 @@ export type LayoutCssVars = {
* *
* @default chrome * @default chrome
*/ */
export type PageTabMode = 'button' | 'chrome'; export type PageTabMode = 'button' | 'chrome' | 'slider';
export interface PageTabProps { export interface PageTabProps {
/** Whether is dark mode */ /** Whether is dark mode */
@@ -262,6 +262,8 @@ export interface PageTabProps {
buttonClass?: string; buttonClass?: string;
/** The class of the chrome tab */ /** The class of the chrome tab */
chromeClass?: string; chromeClass?: string;
/** The class of the title tab */
sliderClass?: string;
/** Whether the tab is active */ /** Whether the tab is active */
active?: boolean; active?: boolean;
/** The color of the active tab */ /** The color of the active tab */

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sa/scripts", "name": "@sa/scripts",
"version": "1.3.15", "version": "2.0.0-beta.1",
"bin": { "bin": {
"sa": "./bin.ts" "sa": "./bin.ts"
}, },
@@ -13,15 +13,15 @@
} }
}, },
"devDependencies": { "devDependencies": {
"@soybeanjs/changelog": "0.3.24", "@soybeanjs/changelog": "0.3.25",
"bumpp": "10.2.3", "bumpp": "10.3.1",
"c12": "3.2.0", "c12": "3.3.1",
"cac": "6.7.14", "cac": "6.7.14",
"consola": "3.4.2", "consola": "3.4.2",
"enquirer": "2.4.1", "enquirer": "2.4.1",
"execa": "9.6.0", "execa": "9.6.0",
"kolorist": "1.8.0", "kolorist": "1.8.0",
"npm-check-updates": "18.0.3", "npm-check-updates": "19.1.1",
"picomatch": "4.0.3", "picomatch": "4.0.3",
"rimraf": "6.0.1" "rimraf": "6.0.1"
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sa/uno-preset", "name": "@sa/uno-preset",
"version": "1.3.15", "version": "2.0.0-beta.1",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sa/utils", "name": "@sa/utils",
"version": "1.3.15", "version": "2.0.0-beta.1",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },
@@ -14,7 +14,7 @@
"crypto-js": "4.2.0", "crypto-js": "4.2.0",
"klona": "2.0.6", "klona": "2.0.6",
"localforage": "1.10.0", "localforage": "1.10.0",
"nanoid": "5.1.5" "nanoid": "5.1.6"
}, },
"devDependencies": { "devDependencies": {
"@types/crypto-js": "4.2.2" "@types/crypto-js": "4.2.2"

2399
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -40,7 +40,8 @@ export const themeScrollModeOptions = transformRecordToOption(themeScrollModeRec
export const themeTabModeRecord: Record<UnionKey.ThemeTabMode, App.I18n.I18nKey> = { export const themeTabModeRecord: Record<UnionKey.ThemeTabMode, App.I18n.I18nKey> = {
chrome: 'theme.layout.tab.mode.chrome', chrome: 'theme.layout.tab.mode.chrome',
button: 'theme.layout.tab.mode.button' button: 'theme.layout.tab.mode.button',
slider: 'theme.layout.tab.mode.slider'
}; };
export const themeTabModeOptions = transformRecordToOption(themeTabModeRecord); export const themeTabModeOptions = transformRecordToOption(themeTabModeRecord);
@@ -57,13 +58,6 @@ export const themePageAnimationModeRecord: Record<UnionKey.ThemePageAnimateMode,
export const themePageAnimationModeOptions = transformRecordToOption(themePageAnimationModeRecord); export const themePageAnimationModeOptions = transformRecordToOption(themePageAnimationModeRecord);
export const resetCacheStrategyRecord: Record<UnionKey.ResetCacheStrategy, App.I18n.I18nKey> = {
refresh: 'theme.layout.resetCacheStrategy.refresh',
close: 'theme.layout.resetCacheStrategy.close'
};
export const resetCacheStrategyOptions = transformRecordToOption(resetCacheStrategyRecord);
export const DARK_CLASS = 'dark'; export const DARK_CLASS = 'dark';
export const watermarkTimeFormatOptions = [ export const watermarkTimeFormatOptions = [

View File

@@ -26,6 +26,7 @@ const tabRef = ref<HTMLElement>();
const isPCFlag = isPC(); const isPCFlag = isPC();
const TAB_DATA_ID = 'data-tab-id'; const TAB_DATA_ID = 'data-tab-id';
const MIDDLE_MOUSE_BUTTON = 1;
type TabNamedNodeMap = NamedNodeMap & { type TabNamedNodeMap = NamedNodeMap & {
[TAB_DATA_ID]: Attr; [TAB_DATA_ID]: Attr;
@@ -84,6 +85,20 @@ function handleCloseTab(tab: App.Global.Tab) {
tabStore.removeTab(tab.id); tabStore.removeTab(tab.id);
} }
function handleMousedown(e: MouseEvent, tab: App.Global.Tab) {
const isMiddleClick = e.button === MIDDLE_MOUSE_BUTTON;
if (!isMiddleClick || !themeStore.tab.closeTabByMiddleClick) {
return;
}
if (tabStore.isTabRetain(tab.id)) {
return;
}
e.preventDefault();
handleCloseTab(tab);
}
async function refresh() { async function refresh() {
appStore.reloadPage(500); appStore.reloadPage(500);
} }
@@ -169,7 +184,9 @@ init();
<div <div
ref="tabRef" ref="tabRef"
class="h-full flex pr-18px" class="h-full flex pr-18px"
:class="[themeStore.tab.mode === 'chrome' ? 'items-end' : 'items-center gap-12px']" :class="[
themeStore.tab.mode === 'chrome' || themeStore.tab.mode === 'slider' ? 'items-end' : 'items-center gap-12px'
]"
> >
<PageTab <PageTab
v-for="tab in tabStore.tabs" v-for="tab in tabStore.tabs"
@@ -181,6 +198,7 @@ init();
:active-color="themeStore.themeColor" :active-color="themeStore.themeColor"
:closable="!tabStore.isTabRetain(tab.id)" :closable="!tabStore.isTabRetain(tab.id)"
@pointerdown="tabStore.switchRouteByTab(tab)" @pointerdown="tabStore.switchRouteByTab(tab)"
@mousedown="handleMousedown($event, tab)"
@close="handleCloseTab(tab)" @close="handleCloseTab(tab)"
@contextmenu="handleContextMenu($event, tab.id)" @contextmenu="handleContextMenu($event, tab.id)"
> >

View File

@@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import ThemeSchema from './modules/theme-schema.vue'; import ThemeSchema from './modules/theme-schema.vue';
import ThemeColor from './modules/theme-color.vue'; import ThemeColor from './modules/theme-color.vue';
import ThemeRadius from './modules/theme-radius.vue';
defineOptions({ defineOptions({
name: 'AppearanceSettings' name: 'AppearanceSettings'
@@ -11,6 +12,7 @@ defineOptions({
<div class="flex-col-stretch gap-16px"> <div class="flex-col-stretch gap-16px">
<ThemeSchema /> <ThemeSchema />
<ThemeColor /> <ThemeColor />
<ThemeRadius />
</div> </div>
</template> </template>

View File

@@ -0,0 +1,22 @@
<script setup lang="ts">
import { useThemeStore } from '@/store/modules/theme';
import { $t } from '@/locales';
import SettingItem from '../../../components/setting-item.vue';
defineOptions({
name: 'ThemeRadius'
});
const themeStore = useThemeStore();
</script>
<template>
<NDivider>{{ $t('theme.appearance.themeRadius.title') }}</NDivider>
<TransitionGroup tag="div" name="setting-list" class="flex-col-stretch gap-12px">
<SettingItem key="1" :label="$t('theme.appearance.themeRadius.title')">
<NInputNumber v-model:value="themeStore.themeRadius" size="small" :step="1" :min="0" :max="16" class="w-120px" />
</SettingItem>
</TransitionGroup>
</template>
<style scoped></style>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { resetCacheStrategyOptions, themeTabModeOptions } from '@/constants/app'; import { themeTabModeOptions } from '@/constants/app';
import { useThemeStore } from '@/store/modules/theme'; import { useThemeStore } from '@/store/modules/theme';
import { translateOptions } from '@/utils/common'; import { translateOptions } from '@/utils/common';
import { $t } from '@/locales'; import { $t } from '@/locales';
@@ -15,14 +15,6 @@ const themeStore = useThemeStore();
<template> <template>
<NDivider>{{ $t('theme.layout.tab.title') }}</NDivider> <NDivider>{{ $t('theme.layout.tab.title') }}</NDivider>
<TransitionGroup tag="div" name="setting-list" class="flex-col-stretch gap-12px"> <TransitionGroup tag="div" name="setting-list" class="flex-col-stretch gap-12px">
<SettingItem key="0" :label="$t('theme.layout.resetCacheStrategy.title')">
<NSelect
v-model:value="themeStore.resetCacheStrategy"
:options="translateOptions(resetCacheStrategyOptions)"
size="small"
class="w-120px"
/>
</SettingItem>
<SettingItem key="1" :label="$t('theme.layout.tab.visible')"> <SettingItem key="1" :label="$t('theme.layout.tab.visible')">
<NSwitch v-model:value="themeStore.tab.visible" /> <NSwitch v-model:value="themeStore.tab.visible" />
</SettingItem> </SettingItem>
@@ -43,6 +35,12 @@ const themeStore = useThemeStore();
class="w-120px" class="w-120px"
/> />
</SettingItem> </SettingItem>
<SettingItem v-if="themeStore.tab.visible" key="5" :label="$t('theme.layout.tab.closeByMiddleClick')">
<template #suffix>
<IconTooltip :desc="$t('theme.layout.tab.closeByMiddleClickTip')" />
</template>
<NSwitch v-model:value="themeStore.tab.closeTabByMiddleClick" />
</SettingItem>
</TransitionGroup> </TransitionGroup>
</template> </template>

View File

@@ -14,9 +14,9 @@ type ThemePreset = Pick<
| 'colourWeakness' | 'colourWeakness'
| 'recommendColor' | 'recommendColor'
| 'themeColor' | 'themeColor'
| 'themeRadius'
| 'otherColor' | 'otherColor'
| 'isInfoFollowPrimary' | 'isInfoFollowPrimary'
| 'resetCacheStrategy'
| 'layout' | 'layout'
| 'page' | 'page'
| 'header' | 'header'

View File

@@ -83,6 +83,9 @@ const local: App.I18n.Schema = {
error: 'Error', error: 'Error',
followPrimary: 'Follow Primary' followPrimary: 'Follow Primary'
}, },
themeRadius: {
title: 'Theme Radius'
},
recommendColor: 'Apply Recommended Color Algorithm', recommendColor: 'Apply Recommended Color Algorithm',
recommendColorDesc: 'The recommended color algorithm refers to', recommendColorDesc: 'The recommended color algorithm refers to',
preset: { preset: {
@@ -135,9 +138,12 @@ const local: App.I18n.Schema = {
height: 'Tab Height', height: 'Tab Height',
mode: { mode: {
title: 'Tab Mode', title: 'Tab Mode',
slider: 'Slider',
chrome: 'Chrome', chrome: 'Chrome',
button: 'Button' button: 'Button'
} },
closeByMiddleClick: 'Close Tab by Middle Click',
closeByMiddleClickTip: 'Enable closing tabs by clicking with the middle mouse button'
}, },
header: { header: {
title: 'Header Settings', title: 'Header Settings',
@@ -185,11 +191,6 @@ const local: App.I18n.Schema = {
} }
}, },
fixedHeaderAndTab: 'Fixed Header And Tab' fixedHeaderAndTab: 'Fixed Header And Tab'
},
resetCacheStrategy: {
title: 'Reset Cache Strategy',
close: 'Close Page',
refresh: 'Refresh Page'
} }
}, },
general: { general: {

View File

@@ -83,6 +83,9 @@ const local: App.I18n.Schema = {
error: '错误色', error: '错误色',
followPrimary: '跟随主色' followPrimary: '跟随主色'
}, },
themeRadius: {
title: '主题圆角'
},
recommendColor: '应用推荐算法的颜色', recommendColor: '应用推荐算法的颜色',
recommendColorDesc: '推荐颜色的算法参照', recommendColorDesc: '推荐颜色的算法参照',
preset: { preset: {
@@ -132,9 +135,12 @@ const local: App.I18n.Schema = {
height: '标签栏高度', height: '标签栏高度',
mode: { mode: {
title: '标签栏风格', title: '标签栏风格',
slider: '滑块风格',
chrome: '谷歌风格', chrome: '谷歌风格',
button: '按钮风格' button: '按钮风格'
} },
closeByMiddleClick: '鼠标中键关闭标签页',
closeByMiddleClickTip: '启用后可以使用鼠标中键点击标签页进行关闭'
}, },
header: { header: {
title: '头部设置', title: '头部设置',
@@ -158,7 +164,7 @@ const local: App.I18n.Schema = {
visible: '显示底部', visible: '显示底部',
fixed: '固定底部', fixed: '固定底部',
height: '底部高度', height: '底部高度',
right: '底部右' right: '底部右'
}, },
content: { content: {
title: '内容区域设置', title: '内容区域设置',
@@ -182,11 +188,6 @@ const local: App.I18n.Schema = {
} }
}, },
fixedHeaderAndTab: '固定头部和标签栏' fixedHeaderAndTab: '固定头部和标签栏'
},
resetCacheStrategy: {
title: '重置缓存策略',
close: '关闭页面',
refresh: '刷新页面'
} }
}, },
general: { general: {

View File

@@ -46,10 +46,7 @@ export const useAppStore = defineStore(SetupStoreId.App, () => {
}); });
setReloadFlag(true); setReloadFlag(true);
routeStore.resetRouteCache();
if (themeStore.resetCacheStrategy === 'refresh') {
routeStore.resetRouteCache();
}
} }
const locale = ref<App.I18n.LangType>(localStg.get('lang') || 'zh-CN'); const locale = ref<App.I18n.LangType>(localStg.get('lang') || 'zh-CN');

View File

@@ -112,10 +112,8 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
await switchRouteByTab(nextTab); await switchRouteByTab(nextTab);
} }
// reset route cache if cache strategy is close // reset route cache
if (themeStore.resetCacheStrategy === 'close') { routeStore.resetRouteCache(removedTabRouteKey);
routeStore.resetRouteCache(removedTabRouteKey);
}
} }
/** remove active tab */ /** remove active tab */
@@ -147,10 +145,8 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
const tabsToRemove = tabs.value.filter(tab => !remainTabIds.includes(tab.id)); const tabsToRemove = tabs.value.filter(tab => !remainTabIds.includes(tab.id));
const routeKeysToReset: RouteKey[] = []; const routeKeysToReset: RouteKey[] = [];
if (themeStore.resetCacheStrategy === 'close') { for (const tab of tabsToRemove) {
for (const tab of tabsToRemove) { routeKeysToReset.push(tab.routeKey);
routeKeysToReset.push(tab.routeKey);
}
} }
const removedTabsIds = tabsToRemove.map(tab => tab.id); const removedTabsIds = tabsToRemove.map(tab => tab.id);

View File

@@ -53,7 +53,7 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => {
}); });
/** Naive theme */ /** Naive theme */
const naiveTheme = computed(() => getNaiveTheme(themeColors.value, settings.value.recommendColor)); const naiveTheme = computed(() => getNaiveTheme(themeColors.value, settings.value));
/** /**
* Settings json * Settings json

View File

@@ -236,22 +236,23 @@ function getNaiveThemeColors(colors: App.Theme.ThemeColor, recommended = false)
/** /**
* Get naive theme * Get naive theme
* *
* @param colors Theme colors * @param settings Theme settings object.
* @param [recommended=false] Use recommended color. Default is `false` * @param settings.recommendColor Whether to use recommended color palette.
* @param settings.themeRadius Border radius to use in the theme (in px).
*/ */
export function getNaiveTheme(colors: App.Theme.ThemeColor, recommended = false) { export function getNaiveTheme(colors: App.Theme.ThemeColor, settings: App.Theme.ThemeSetting) {
const { primary: colorLoading } = colors; const { primary: colorLoading } = colors;
const theme: GlobalThemeOverrides = { const theme: GlobalThemeOverrides = {
common: { common: {
...getNaiveThemeColors(colors, recommended), ...getNaiveThemeColors(colors, settings.recommendColor),
borderRadius: '6px' borderRadius: `${settings.themeRadius}px`
}, },
LoadingBar: { LoadingBar: {
colorLoading colorLoading
}, },
Tag: { Tag: {
borderRadius: '6px' borderRadius: `${settings.themeRadius}px`
} }
}; };

View File

@@ -6,6 +6,7 @@ html,
body, body,
#app { #app {
height: 100%; height: 100%;
text-autospace: normal;
} }
html { html {

View File

@@ -1,7 +1,14 @@
@mixin scrollbar($size: 7px, $color: rgba(0, 0, 0, 0.5)) { @mixin scrollbar($size: 7px, $color: rgba(0, 0, 0, 0.5), $dark-color: rgba(255, 255, 255, 0.5)) {
scrollbar-width: thin; scrollbar-width: thin;
scrollbar-color: $color transparent; scrollbar-color: $color transparent;
// Dark theme override
.dark & {
// guide safari use light color scrollbar
color-scheme: dark;
scrollbar-color: $dark-color transparent;
}
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
background-color: $color; background-color: $color;
border-radius: $size; border-radius: $size;

View File

@@ -14,8 +14,8 @@
"warning": "#d4bb9d", "warning": "#d4bb9d",
"error": "#c49a9a" "error": "#c49a9a"
}, },
"themeRadius": 6,
"isInfoFollowPrimary": true, "isInfoFollowPrimary": true,
"resetCacheStrategy": "refresh",
"layout": { "layout": {
"mode": "vertical-mix", "mode": "vertical-mix",
"scrollMode": "wrapper" "scrollMode": "wrapper"

View File

@@ -14,8 +14,8 @@
"warning": "#faad14", "warning": "#faad14",
"error": "#f5222d" "error": "#f5222d"
}, },
"themeRadius": 6,
"isInfoFollowPrimary": true, "isInfoFollowPrimary": true,
"resetCacheStrategy": "close",
"layout": { "layout": {
"mode": "vertical", "mode": "vertical",
"scrollMode": "content" "scrollMode": "content"

View File

@@ -14,8 +14,8 @@
"warning": "#faad14", "warning": "#faad14",
"error": "#f5222d" "error": "#f5222d"
}, },
"themeRadius": 6,
"isInfoFollowPrimary": true, "isInfoFollowPrimary": true,
"resetCacheStrategy": "close",
"layout": { "layout": {
"mode": "vertical", "mode": "vertical",
"scrollMode": "content" "scrollMode": "content"

View File

@@ -14,8 +14,8 @@
"warning": "#faad14", "warning": "#faad14",
"error": "#f5222d" "error": "#f5222d"
}, },
"themeRadius": 6,
"isInfoFollowPrimary": true, "isInfoFollowPrimary": true,
"resetCacheStrategy": "close",
"layout": { "layout": {
"mode": "vertical", "mode": "vertical",
"scrollMode": "content" "scrollMode": "content"

View File

@@ -5,6 +5,7 @@ export const themeSettings: App.Theme.ThemeSetting = {
colourWeakness: false, colourWeakness: false,
recommendColor: false, recommendColor: false,
themeColor: '#646cff', themeColor: '#646cff',
themeRadius: 6,
otherColor: { otherColor: {
info: '#2080f0', info: '#2080f0',
success: '#52c41a', success: '#52c41a',
@@ -12,7 +13,6 @@ export const themeSettings: App.Theme.ThemeSetting = {
error: '#f5222d' error: '#f5222d'
}, },
isInfoFollowPrimary: true, isInfoFollowPrimary: true,
resetCacheStrategy: 'refresh',
layout: { layout: {
mode: 'vertical', mode: 'vertical',
scrollMode: 'content' scrollMode: 'content'
@@ -38,7 +38,8 @@ export const themeSettings: App.Theme.ThemeSetting = {
visible: true, visible: true,
cache: true, cache: true,
height: 44, height: 44,
mode: 'chrome' mode: 'chrome',
closeTabByMiddleClick: false
}, },
fixedHeaderAndTab: true, fixedHeaderAndTab: true,
sider: { sider: {

14
src/typings/app.d.ts vendored
View File

@@ -16,12 +16,12 @@ declare namespace App {
recommendColor: boolean; recommendColor: boolean;
/** Theme color */ /** Theme color */
themeColor: string; themeColor: string;
/** Theme radius */
themeRadius: number;
/** Other color */ /** Other color */
otherColor: OtherColor; otherColor: OtherColor;
/** Whether info color is followed by the primary color */ /** Whether info color is followed by the primary color */
isInfoFollowPrimary: boolean; isInfoFollowPrimary: boolean;
/** Reset cache strategy */
resetCacheStrategy: UnionKey.ResetCacheStrategy;
/** Layout */ /** Layout */
layout: { layout: {
/** Layout mode */ /** Layout mode */
@@ -71,6 +71,8 @@ declare namespace App {
height: number; height: number;
/** Tab mode */ /** Tab mode */
mode: UnionKey.ThemeTabMode; mode: UnionKey.ThemeTabMode;
/** Whether to close tab by middle click */
closeTabByMiddleClick: boolean;
}; };
/** Fixed header and tab */ /** Fixed header and tab */
fixedHeaderAndTab: boolean; fixedHeaderAndTab: boolean;
@@ -376,9 +378,12 @@ declare namespace App {
themeColor: { themeColor: {
title: string; title: string;
followPrimary: string; followPrimary: string;
} & Theme.ThemeColor; } & Record<Theme.ThemeColorKey, string>;
recommendColor: string; recommendColor: string;
recommendColorDesc: string; recommendColorDesc: string;
themeRadius: {
title: string;
};
preset: { preset: {
title: string; title: string;
apply: string; apply: string;
@@ -402,6 +407,8 @@ declare namespace App {
cacheTip: string; cacheTip: string;
height: string; height: string;
mode: { title: string } & Record<UnionKey.ThemeTabMode, string>; mode: { title: string } & Record<UnionKey.ThemeTabMode, string>;
closeByMiddleClick: string;
closeByMiddleClickTip: string;
}; };
header: { header: {
title: string; title: string;
@@ -436,7 +443,6 @@ declare namespace App {
}; };
fixedHeaderAndTab: string; fixedHeaderAndTab: string;
}; };
resetCacheStrategy: { title: string } & Record<UnionKey.ResetCacheStrategy, string>;
}; };
general: { general: {
title: string; title: string;

View File

@@ -14,14 +14,6 @@ declare namespace UnionKey {
/** Theme scheme */ /** Theme scheme */
type ThemeScheme = 'light' | 'dark' | 'auto'; type ThemeScheme = 'light' | 'dark' | 'auto';
/**
* Reset cache strategy
*
* - close: re-cache when close page
* - refresh: re-cache when refresh page
*/
type ResetCacheStrategy = 'close' | 'refresh';
/** /**
* The layout mode * The layout mode
* *

View File

@@ -23,7 +23,7 @@ const appStore = useAppStore();
const themeStore = useThemeStore(); const themeStore = useThemeStore();
interface LoginModule { interface LoginModule {
label: string; label: App.I18n.I18nKey;
component: Component; component: Component;
} }

View File

@@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue'; import { computed } from 'vue';
import { createReusableTemplate } from '@vueuse/core'; import { createReusableTemplate } from '@vueuse/core';
import { useThemeStore } from '@/store/modules/theme';
import { $t } from '@/locales'; import { $t } from '@/locales';
defineOptions({ defineOptions({
@@ -72,6 +73,8 @@ interface GradientBgProps {
const [DefineGradientBg, GradientBg] = createReusableTemplate<GradientBgProps>(); const [DefineGradientBg, GradientBg] = createReusableTemplate<GradientBgProps>();
const themeStore = useThemeStore();
function getGradientColor(color: CardData['color']) { function getGradientColor(color: CardData['color']) {
return `linear-gradient(to bottom right, ${color.start}, ${color.end})`; return `linear-gradient(to bottom right, ${color.start}, ${color.end})`;
} }
@@ -81,7 +84,10 @@ function getGradientColor(color: CardData['color']) {
<NCard :bordered="false" size="small" class="card-wrapper"> <NCard :bordered="false" size="small" class="card-wrapper">
<!-- define component start: GradientBg --> <!-- define component start: GradientBg -->
<DefineGradientBg v-slot="{ $slots, gradientColor }"> <DefineGradientBg v-slot="{ $slots, gradientColor }">
<div class="rd-8px px-16px pb-4px pt-8px text-white" :style="{ backgroundImage: gradientColor }"> <div
class="px-16px pb-4px pt-8px text-white"
:style="{ backgroundImage: gradientColor, borderRadius: themeStore.themeRadius + 'px' }"
>
<component :is="$slots.default" /> <component :is="$slots.default" />
</div> </div>
</DefineGradientBg> </DefineGradientBg>