Compare commits

..

12 Commits

42 changed files with 1655 additions and 2061 deletions

View File

@@ -9,6 +9,7 @@
"mhutchie.git-graph", "mhutchie.git-graph",
"mikestead.dotenv", "mikestead.dotenv",
"naumovs.color-highlight", "naumovs.color-highlight",
"oxc.oxc-vscode",
"pkief.material-icon-theme", "pkief.material-icon-theme",
"sdras.vue-vscode-snippets", "sdras.vue-vscode-snippets",
"vue.volar", "vue.volar",

View File

@@ -15,6 +15,6 @@
"i18n-ally.parsers.typescript.compilerOptions": { "i18n-ally.parsers.typescript.compilerOptions": {
"moduleResolution": "node" "moduleResolution": "node"
}, },
"prettier.enable": false, "oxc.fmt.configPath": ".oxfmtrc.json",
"unocss.root": ["./"] "unocss.root": ["./"]
} }

View File

@@ -1,5 +1,61 @@
# Changelog # Changelog
## [v2.1.0](https://github.com/soybeanjs/soybean-admin/compare/v2.0.2...v2.1.0) (2026-03-09)
###    🚨 Breaking Changes
- **projects**: integrate oxlint and oxfmt &nbsp;-&nbsp; by **soybeanfe** [<samp>(6ff74)</samp>](https://github.com/soybeanjs/soybean-admin/commit/6ff74c0c)
### &nbsp;&nbsp;&nbsp;🚀 Features
- **components**:
- Column settings support fixed columns. &nbsp;-&nbsp; by @m-xlsea [<samp>(70658)</samp>](https://github.com/soybeanjs/soybean-admin/commit/70658643)
- Add “Select All” to TableColumnSetting &nbsp;-&nbsp; by @wenyuanw [<samp>(0081b)</samp>](https://github.com/soybeanjs/soybean-admin/commit/0081b9c0)
- **logo**:
- use new logo &nbsp;-&nbsp; by @soybeanjs [<samp>(5aac5)</samp>](https://github.com/soybeanjs/soybean-admin/commit/5aac540a)
- **projects**:
- add the plugin: vite-plugin-vue-transition-root-validator, to optimize the development experience. &nbsp;-&nbsp; by **Azir-11** [<samp>(30e3c)</samp>](https://github.com/soybeanjs/soybean-admin/commit/30e3cdc7)
- **types**:
- Added type definition `force` to router push options. &nbsp;-&nbsp; by @m-xlsea [<samp>(a3794)</samp>](https://github.com/soybeanjs/soybean-admin/commit/a37949f2)
- **workflows**:
- add opencode workflow for issue and PR comment triggers &nbsp;-&nbsp; by @soybeanjs [<samp>(dacee)</samp>](https://github.com/soybeanjs/soybean-admin/commit/dacee143)
### &nbsp;&nbsp;&nbsp;🐞 Bug Fixes
- **projects**:
- fix the long list TableColumnSetting component exceeds the viewport. &nbsp;-&nbsp; by **skyfeiz** [<samp>(cbfb9)</samp>](https://github.com/soybeanjs/soybean-admin/commit/cbfb932f)
- fix NButton props conflicts. &nbsp;-&nbsp; by **skyfeiz** [<samp>(54107)</samp>](https://github.com/soybeanjs/soybean-admin/commit/54107aca)
- ensure HTML lang attribute is updated when setting locale &nbsp;-&nbsp; by @pan0xc [<samp>(f96c3)</samp>](https://github.com/soybeanjs/soybean-admin/commit/f96c3c9e)
- correct HTML lang attribute to standard format &nbsp;-&nbsp; by @pan0xc [<samp>(b520d)</samp>](https://github.com/soybeanjs/soybean-admin/commit/b520db3e)
- **router**:
- simplify route guard logic and remove unnecessary next calls &nbsp;-&nbsp; by **soybeanfe** [<samp>(3c2cb)</samp>](https://github.com/soybeanjs/soybean-admin/commit/3c2cbb74)
### &nbsp;&nbsp;&nbsp;🛠 Optimizations
- **projects**:
- modify the injection location of the token. &nbsp;-&nbsp; by **Azir-11** [<samp>(9d48c)</samp>](https://github.com/soybeanjs/soybean-admin/commit/9d48ca5f)
- optimize unocss config &nbsp;-&nbsp; by **soybeanfe** [<samp>(6fc6f)</samp>](https://github.com/soybeanjs/soybean-admin/commit/6fc6f1c9)
### &nbsp;&nbsp;&nbsp;📖 Documentation
- **projects**: V2 has been released. &nbsp;-&nbsp; by **skyfeiz** [<samp>(d7394)</samp>](https://github.com/soybeanjs/soybean-admin/commit/d73947a5)
### &nbsp;&nbsp;&nbsp;🏡 Chore
- **deps**:
- update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(232e1)</samp>](https://github.com/soybeanjs/soybean-admin/commit/232e1ac4)
- update deps &nbsp;-&nbsp; by @soybeanjs [<samp>(2a023)</samp>](https://github.com/soybeanjs/soybean-admin/commit/2a0231da)
- update deps &nbsp;-&nbsp; by **soybeanfe** [<samp>(b867c)</samp>](https://github.com/soybeanjs/soybean-admin/commit/b867c290)
### &nbsp;&nbsp;&nbsp;🎨 Styles
- **projects**: fix lint code and format code &nbsp;-&nbsp; by **soybeanfe** [<samp>(781a1)</samp>](https://github.com/soybeanjs/soybean-admin/commit/781a18f4)
### &nbsp;&nbsp;&nbsp;❤️ Contributors
[![pan0xc](https://github.com/pan0xc.png?size=48)](https://github.com/pan0xc)&nbsp;&nbsp;[![m-xlsea](https://github.com/m-xlsea.png?size=48)](https://github.com/m-xlsea)&nbsp;&nbsp;[![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;
[soybeanfe](mailto:honghuangdc@gmail.com),&nbsp;[Azir-11](mailto:2075125282@qq.com),&nbsp;[skyfeiz](mailto:webzhangfei@163.com),&nbsp;
## [v2.0.2](https://github.com/soybeanjs/soybean-admin/compare/v2.0.1...v2.0.2) (2025-12-23) ## [v2.0.2](https://github.com/soybeanjs/soybean-admin/compare/v2.0.1...v2.0.2) (2025-12-23)
### &nbsp;&nbsp;&nbsp;🐞 Bug Fixes ### &nbsp;&nbsp;&nbsp;🐞 Bug Fixes

View File

@@ -1,7 +1,7 @@
import process from 'node:process'; import process from 'node:process';
import path from 'node:path'; import path from 'node:path';
import unocss from '@unocss/vite'; import { presetIcons } from 'unocss';
import { presetIcons } from '@unocss/preset-icons'; import unocss from 'unocss/vite';
import { FileSystemIconLoader } from '@iconify/utils/lib/loader/node-loaders'; import { FileSystemIconLoader } from '@iconify/utils/lib/loader/node-loaders';
export function setupUnocss(viteEnv: Env.ImportMeta) { export function setupUnocss(viteEnv: Env.ImportMeta) {

View File

@@ -1,3 +1,12 @@
import { defineConfig } from '@soybeanjs/eslint-config-vue'; import { defineConfig } from '@soybeanjs/eslint-config-vue';
export default defineConfig(); export default defineConfig({
'vue/component-name-in-template-casing': [
'warn',
'PascalCase',
{
registeredComponentsOnly: false,
ignores: ['/^icon-/']
}
]
});

View File

@@ -1,6 +1,6 @@
{ {
"name": "soybean-admin", "name": "soybean-admin",
"version": "2.0.2", "version": "2.1.0",
"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的清新优雅的中后台模版。",
"keywords": [ "keywords": [
"TypeScript", "TypeScript",
@@ -53,7 +53,7 @@
"@sa/utils": "workspace:*", "@sa/utils": "workspace:*",
"@vueuse/core": "14.2.1", "@vueuse/core": "14.2.1",
"clipboard": "2.0.11", "clipboard": "2.0.11",
"dayjs": "1.11.19", "dayjs": "1.11.20",
"defu": "6.1.4", "defu": "6.1.4",
"echarts": "6.0.0", "echarts": "6.0.0",
"json5": "2.2.3", "json5": "2.2.3",
@@ -61,43 +61,39 @@
"nprogress": "0.2.0", "nprogress": "0.2.0",
"pinia": "3.0.4", "pinia": "3.0.4",
"tailwind-merge": "3.5.0", "tailwind-merge": "3.5.0",
"vue": "3.5.29", "vue": "3.5.31",
"vue-draggable-plus": "0.6.1", "vue-draggable-plus": "0.6.1",
"vue-i18n": "11.3.0", "vue-i18n": "11.3.0",
"vue-router": "5.0.3" "vue-router": "5.0.4"
}, },
"devDependencies": { "devDependencies": {
"@elegant-router/vue": "0.3.8", "@elegant-router/vue": "0.3.8",
"@iconify/json": "2.2.447", "@iconify/json": "2.2.456",
"@sa/scripts": "workspace:*", "@sa/scripts": "workspace:*",
"@sa/uno-preset": "workspace:*", "@sa/uno-preset": "workspace:*",
"@soybeanjs/eslint-config-vue": "^0.0.2", "@soybeanjs/eslint-config-vue": "^0.0.2",
"@types/node": "25.3.5", "@types/node": "25.5.0",
"@types/nprogress": "0.2.3", "@types/nprogress": "0.2.3",
"@unocss/preset-icons": "66.6.6", "@vitejs/plugin-vue": "6.0.5",
"@unocss/preset-uno": "66.6.6", "@vitejs/plugin-vue-jsx": "5.1.5",
"@unocss/transformer-directives": "66.6.6",
"@unocss/transformer-variant-group": "66.6.6",
"@unocss/vite": "66.6.6",
"@vitejs/plugin-vue": "6.0.4",
"@vitejs/plugin-vue-jsx": "5.1.4",
"consola": "3.4.2", "consola": "3.4.2",
"eslint": "10.0.3", "eslint": "10.1.0",
"kolorist": "1.8.0", "kolorist": "1.8.0",
"oxfmt": "^0.36.0", "oxfmt": "^0.42.0",
"oxlint": "^1.51.0", "oxlint": "^1.57.0",
"sass": "1.97.3", "sass": "1.98.0",
"simple-git-hooks": "2.13.1", "simple-git-hooks": "2.13.1",
"tsx": "4.21.0", "tsx": "4.21.0",
"typescript": "5.9.3", "typescript": "6.0.2",
"unocss": "^66.6.7",
"unplugin-icons": "23.0.1", "unplugin-icons": "23.0.1",
"unplugin-vue-components": "31.0.0", "unplugin-vue-components": "32.0.0",
"vite": "7.3.1", "vite": "8.0.3",
"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.7", "vite-plugin-vue-devtools": "8.1.1",
"vite-plugin-vue-transition-root-validator": "^0.1.0", "vite-plugin-vue-transition-root-validator": "^0.1.0",
"vue-tsc": "3.2.5" "vue-tsc": "3.2.6"
}, },
"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": "2.0.2", "version": "2.1.0",
"typesVersions": { "typesVersions": {
"*": { "*": {
"*": [ "*": [
@@ -15,7 +15,7 @@
"./mock": "./src/mock.ts" "./mock": "./src/mock.ts"
}, },
"dependencies": { "dependencies": {
"@alova/mock": "2.0.19", "@alova/mock": "2.0.20",
"@sa/utils": "workspace:*", "@sa/utils": "workspace:*",
"alova": "3.5.1" "alova": "3.5.1"
} }

View File

@@ -3,9 +3,8 @@
"target": "ESNext", "target": "ESNext",
"jsx": "preserve", "jsx": "preserve",
"lib": ["DOM", "ESNext"], "lib": ["DOM", "ESNext"],
"baseUrl": ".",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "bundler",
"resolveJsonModule": true, "resolveJsonModule": true,
"types": ["node"], "types": ["node"],
"strict": true, "strict": true,

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sa/axios", "name": "@sa/axios",
"version": "2.0.2", "version": "2.1.0",
"typesVersions": { "typesVersions": {
"*": { "*": {
"*": [ "*": [
@@ -13,7 +13,7 @@
}, },
"dependencies": { "dependencies": {
"@sa/utils": "workspace:*", "@sa/utils": "workspace:*",
"axios": "1.13.6", "axios": "1.14.0",
"axios-retry": "4.5.0", "axios-retry": "4.5.0",
"qs": "6.15.0" "qs": "6.15.0"
}, },

View File

@@ -3,9 +3,8 @@
"target": "ESNext", "target": "ESNext",
"jsx": "preserve", "jsx": "preserve",
"lib": ["DOM", "ESNext"], "lib": ["DOM", "ESNext"],
"baseUrl": ".",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "bundler",
"resolveJsonModule": true, "resolveJsonModule": true,
"types": ["node"], "types": ["node"],
"strict": true, "strict": true,

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sa/color", "name": "@sa/color",
"version": "2.0.2", "version": "2.1.0",
"typesVersions": { "typesVersions": {
"*": { "*": {
"*": [ "*": [

View File

@@ -3,9 +3,8 @@
"target": "ESNext", "target": "ESNext",
"jsx": "preserve", "jsx": "preserve",
"lib": ["DOM", "ESNext"], "lib": ["DOM", "ESNext"],
"baseUrl": ".",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "bundler",
"resolveJsonModule": true, "resolveJsonModule": true,
"types": ["node"], "types": ["node"],
"strict": true, "strict": true,

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sa/hooks", "name": "@sa/hooks",
"version": "2.0.2", "version": "2.1.0",
"typesVersions": { "typesVersions": {
"*": { "*": {
"*": [ "*": [

View File

@@ -3,9 +3,8 @@
"target": "ESNext", "target": "ESNext",
"jsx": "preserve", "jsx": "preserve",
"lib": ["DOM", "ESNext"], "lib": ["DOM", "ESNext"],
"baseUrl": ".",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "bundler",
"resolveJsonModule": true, "resolveJsonModule": true,
"types": ["node"], "types": ["node"],
"strict": true, "strict": true,

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sa/materials", "name": "@sa/materials",
"version": "2.0.2", "version": "2.1.0",
"typesVersions": { "typesVersions": {
"*": { "*": {
"*": [ "*": [

View File

@@ -3,9 +3,8 @@
"target": "ESNext", "target": "ESNext",
"jsx": "preserve", "jsx": "preserve",
"lib": ["DOM", "ESNext"], "lib": ["DOM", "ESNext"],
"baseUrl": ".",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "bundler",
"resolveJsonModule": true, "resolveJsonModule": true,
"types": ["node"], "types": ["node"],
"strict": true, "strict": true,

View File

@@ -1,3 +1,3 @@
#!/usr/bin/env tsx #!/usr/bin/env tsx
import './src/index.ts'; import './src/index';

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sa/scripts", "name": "@sa/scripts",
"version": "2.0.2", "version": "2.1.0",
"bin": { "bin": {
"sa": "./bin.ts" "sa": "./bin.ts"
}, },
@@ -15,16 +15,16 @@
".": "./src/index.ts" ".": "./src/index.ts"
}, },
"devDependencies": { "devDependencies": {
"@soybeanjs/changelog": "0.4.3", "@soybeanjs/changelog": "0.4.5",
"bumpp": "10.4.1", "bumpp": "11.0.1",
"c12": "3.3.3", "c12": "3.3.3",
"cac": "6.7.14", "cac": "7.0.0",
"consola": "3.4.2", "consola": "3.4.2",
"enquirer": "2.4.1", "enquirer": "2.4.1",
"execa": "9.6.1", "execa": "9.6.1",
"kolorist": "1.8.0", "kolorist": "1.8.0",
"npm-check-updates": "19.6.3", "npm-check-updates": "19.6.6",
"picomatch": "4.0.3", "picomatch": "4.0.4",
"rimraf": "6.1.3" "rimraf": "6.1.3"
} }
} }

View File

@@ -3,9 +3,8 @@
"target": "ESNext", "target": "ESNext",
"jsx": "preserve", "jsx": "preserve",
"lib": ["DOM", "ESNext"], "lib": ["DOM", "ESNext"],
"baseUrl": ".",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "bundler",
"resolveJsonModule": true, "resolveJsonModule": true,
"types": ["node"], "types": ["node"],
"strict": true, "strict": true,

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sa/uno-preset", "name": "@sa/uno-preset",
"version": "2.0.2", "version": "2.1.0",
"typesVersions": { "typesVersions": {
"*": { "*": {
"*": [ "*": [

View File

@@ -1,7 +1,7 @@
// @unocss-include // @unocss-include
import type { Preset } from '@unocss/core'; import type { Preset } from '@unocss/core';
import type { Theme } from '@unocss/preset-uno'; import type { Theme } from '@unocss/preset-mini';
export function presetSoybeanAdmin(): Preset<Theme> { export function presetSoybeanAdmin(): Preset<Theme> {
const preset: Preset<Theme> = { const preset: Preset<Theme> = {

View File

@@ -3,9 +3,8 @@
"target": "ESNext", "target": "ESNext",
"jsx": "preserve", "jsx": "preserve",
"lib": ["DOM", "ESNext"], "lib": ["DOM", "ESNext"],
"baseUrl": ".",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "bundler",
"resolveJsonModule": true, "resolveJsonModule": true,
"types": ["node"], "types": ["node"],
"strict": true, "strict": true,

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sa/utils", "name": "@sa/utils",
"version": "2.0.2", "version": "2.1.0",
"typesVersions": { "typesVersions": {
"*": { "*": {
"*": [ "*": [
@@ -16,7 +16,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.6" "nanoid": "5.1.7"
}, },
"devDependencies": { "devDependencies": {
"@types/crypto-js": "4.2.2" "@types/crypto-js": "4.2.2"

View File

@@ -3,9 +3,8 @@
"target": "ESNext", "target": "ESNext",
"jsx": "preserve", "jsx": "preserve",
"lib": ["DOM", "ESNext"], "lib": ["DOM", "ESNext"],
"baseUrl": ".",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "bundler",
"resolveJsonModule": true, "resolveJsonModule": true,
"types": ["node"], "types": ["node"],
"strict": true, "strict": true,

3432
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -64,7 +64,7 @@ function toggleSelectAll(checked: boolean) {
<template #trigger> <template #trigger>
<NButton size="small"> <NButton size="small">
<template #icon> <template #icon>
<IconAntDesignSettingOutlined class="text-icon" /> <icon-ant-design-setting-outlined class="text-icon" />
</template> </template>
{{ $t('common.columnSetting') }} {{ $t('common.columnSetting') }}
</NButton> </NButton>
@@ -90,7 +90,7 @@ function toggleSelectAll(checked: boolean) {
:class="{ hidden: !item.visible }" :class="{ hidden: !item.visible }"
> >
<div class="h-full flex-y-center flex-1 rd-4px hover:(bg-primary bg-opacity-20)"> <div class="h-full flex-y-center flex-1 rd-4px hover:(bg-primary bg-opacity-20)">
<IconMdiDrag class="mr-8px h-full cursor-move text-icon" /> <icon-mdi-drag class="mr-8px h-full cursor-move text-icon" />
<NCheckbox v-model:checked="item.checked" class="none_draggable flex-1"> <NCheckbox v-model:checked="item.checked" class="none_draggable flex-1">
<template v-if="typeof item.title === 'function'"> <template v-if="typeof item.title === 'function'">
<component :is="item.title" /> <component :is="item.title" />
@@ -104,9 +104,9 @@ function toggleSelectAll(checked: boolean) {
:tooltip-content="$t(tooltipRecord[item.fixed!])" :tooltip-content="$t(tooltipRecord[item.fixed!])"
@click="handleFixed(item)" @click="handleFixed(item)"
> >
<IconOcticonPin16 v-if="item.fixed === 'unFixed'" /> <icon-octicon-pin-16 v-if="item.fixed === 'unFixed'" />
<IconOcticonPin16 v-else-if="item.fixed === 'left'" class="rotate-270" /> <icon-octicon-pin-16 v-else-if="item.fixed === 'left'" class="rotate-270" />
<IconOcticonPinSlash16 v-else /> <icon-octicon-pin-slash-16 v-else />
</ButtonIcon> </ButtonIcon>
</div> </div>
</VueDraggable> </VueDraggable>

View File

@@ -44,7 +44,7 @@ function refresh() {
<slot name="default"> <slot name="default">
<NButton size="small" ghost type="primary" @click="add"> <NButton size="small" ghost type="primary" @click="add">
<template #icon> <template #icon>
<IconIcRoundPlus class="text-icon" /> <icon-ic-round-plus class="text-icon" />
</template> </template>
{{ $t('common.add') }} {{ $t('common.add') }}
</NButton> </NButton>
@@ -52,7 +52,7 @@ function refresh() {
<template #trigger> <template #trigger>
<NButton size="small" ghost type="error" :disabled="disabledDelete"> <NButton size="small" ghost type="error" :disabled="disabledDelete">
<template #icon> <template #icon>
<IconIcRoundDelete class="text-icon" /> <icon-ic-round-delete class="text-icon" />
</template> </template>
{{ $t('common.batchDelete') }} {{ $t('common.batchDelete') }}
</NButton> </NButton>
@@ -62,7 +62,7 @@ function refresh() {
</slot> </slot>
<NButton size="small" @click="refresh"> <NButton size="small" @click="refresh">
<template #icon> <template #icon>
<IconMdiRefresh class="text-icon" :class="{ 'animate-spin': loading }" /> <icon-mdi-refresh class="text-icon" :class="{ 'animate-spin': loading }" />
</template> </template>
{{ $t('common.refresh') }} {{ $t('common.refresh') }}
</NButton> </NButton>

View File

@@ -14,8 +14,8 @@ defineProps<Props>();
<template> <template>
<ButtonIcon :key="String(full)" :tooltip-content="full ? $t('icon.fullscreenExit') : $t('icon.fullscreen')"> <ButtonIcon :key="String(full)" :tooltip-content="full ? $t('icon.fullscreenExit') : $t('icon.fullscreen')">
<IconGridiconsFullscreenExit v-if="full" /> <icon-gridicons-fullscreen-exit v-if="full" />
<IconGridiconsFullscreen v-else /> <icon-gridicons-fullscreen v-else />
</ButtonIcon> </ButtonIcon>
</template> </template>

View File

@@ -14,7 +14,7 @@ defineProps<Props>();
<template> <template>
<ButtonIcon :tooltip-content="$t('icon.reload')"> <ButtonIcon :tooltip-content="$t('icon.reload')">
<IconAntDesignReloadOutlined :class="{ 'animate-spin animate-duration-750': loading }" /> <icon-ant-design-reload-outlined :class="{ 'animate-spin animate-duration-750': loading }" />
</ButtonIcon> </ButtonIcon>
</template> </template>

View File

@@ -7,16 +7,16 @@ defineOptions({ name: 'SearchFooter' });
<template> <template>
<div class="h-44px flex-y-center gap-14px px-24px"> <div class="h-44px flex-y-center gap-14px px-24px">
<span class="flex-y-center"> <span class="flex-y-center">
<IconMdiKeyboardReturn class="operate-shadow operate-item" /> <icon-mdi-keyboard-return class="operate-shadow operate-item" />
<span>{{ $t('common.confirm') }}</span> <span>{{ $t('common.confirm') }}</span>
</span> </span>
<span class="flex-y-center"> <span class="flex-y-center">
<IconMdiArrowUpThin class="operate-shadow operate-item" /> <icon-mdi-arrow-up-thin class="operate-shadow operate-item" />
<IconMdiArrowDownThin class="operate-shadow operate-item" /> <icon-mdi-arrow-down-thin class="operate-shadow operate-item" />
<span>{{ $t('common.switch') }}</span> <span>{{ $t('common.switch') }}</span>
</span> </span>
<span class="flex-y-center"> <span class="flex-y-center">
<IconMdiKeyboardEsc class="operate-shadow operate-item" /> <icon-mdi-keyboard-esc class="operate-shadow operate-item" />
<span>{{ $t('common.close') }}</span> <span>{{ $t('common.close') }}</span>
</span> </span>
</div> </div>

View File

@@ -104,7 +104,7 @@ registerShortcut();
<NInputGroup> <NInputGroup>
<NInput v-model:value="keyword" clearable :placeholder="$t('common.keywordSearch')" @input="handleSearch"> <NInput v-model:value="keyword" clearable :placeholder="$t('common.keywordSearch')" @input="handleSearch">
<template #prefix> <template #prefix>
<IconUilSearch class="text-15px text-#c2c2c2" /> <icon-uil-search class="text-15px text-#c2c2c2" />
</template> </template>
</NInput> </NInput>
<NButton v-if="isMobile" type="primary" ghost @click="handleClose">{{ $t('common.cancel') }}</NButton> <NButton v-if="isMobile" type="primary" ghost @click="handleClose">{{ $t('common.cancel') }}</NButton>

View File

@@ -46,7 +46,7 @@ function handleTo() {
<span class="ml-5px flex-1"> <span class="ml-5px flex-1">
{{ (item.i18nKey && $t(item.i18nKey)) || item.label }} {{ (item.i18nKey && $t(item.i18nKey)) || item.label }}
</span> </span>
<IconAntDesignEnterOutlined class="icon mr-3px p-2px text-20px" /> <icon-ant-design-enter-outlined class="icon mr-3px p-2px text-20px" />
</div> </div>
</template> </template>
</div> </div>

View File

@@ -10,7 +10,7 @@ const { bool: show, toggle } = useBoolean();
<template> <template>
<ButtonIcon :tooltip-content="$t('common.search')" @click="toggle"> <ButtonIcon :tooltip-content="$t('common.search')" @click="toggle">
<IconUilSearch /> <icon-uil-search />
</ButtonIcon> </ButtonIcon>
<SearchModal v-model:show="show" /> <SearchModal v-model:show="show" />
</template> </template>

View File

@@ -68,14 +68,15 @@ const swatches: string[] = [
{{ $t('theme.appearance.themeColor.followPrimary') }} {{ $t('theme.appearance.themeColor.followPrimary') }}
</NCheckbox> </NCheckbox>
</template> </template>
<NColorPicker <div class="w-90px">
class="w-90px" <NColorPicker
:value="themeStore.themeColors[key]" :value="themeStore.themeColors[key]"
:disabled="key === 'info' && themeStore.isInfoFollowPrimary" :disabled="key === 'info' && themeStore.isInfoFollowPrimary"
:show-alpha="false" :show-alpha="false"
:swatches="swatches" :swatches="swatches"
@update:value="handleUpdateColor($event, key)" @update:value="handleUpdateColor($event, key)"
/> />
</div>
</SettingItem> </SettingItem>
</div> </div>
</template> </template>

View File

@@ -135,7 +135,7 @@ const local: App.I18n.Schema = {
title: 'Tab Settings', title: 'Tab Settings',
visible: 'Tab Visible', visible: 'Tab Visible',
cache: 'Tag Bar Info Cache', cache: 'Tag Bar Info Cache',
cacheTip: 'One-click to open/close global keepalive', cacheTip: 'Keep the tab bar information after leaving the page',
height: 'Tab Height', height: 'Tab Height',
mode: { mode: {
title: 'Tab Mode', title: 'Tab Mode',

View File

@@ -132,7 +132,7 @@ const local: App.I18n.Schema = {
title: '标签栏设置', title: '标签栏设置',
visible: '显示标签栏', visible: '显示标签栏',
cache: '标签栏信息缓存', cache: '标签栏信息缓存',
cacheTip: '一键开启/关闭全局 keepalive', cacheTip: '离开页面后仍然保留标签栏信息',
height: '标签栏高度', height: '标签栏高度',
mode: { mode: {
title: '标签栏风格', title: '标签栏风格',

View File

@@ -1,3 +1,4 @@
// @ts-expect-error ignore type error of svg icons
import 'virtual:svg-icons-register'; import 'virtual:svg-icons-register';
import 'uno.css'; import 'uno.css';
import '../styles/css/global.css'; import '../styles/css/global.css';

View File

@@ -1,11 +1,11 @@
import type { Router } from 'vue-router'; import type { Router } from 'vue-router';
export function createProgressGuard(router: Router) { export function createProgressGuard(router: Router) {
router.beforeEach((_to, _from, next) => { router.beforeEach(() => {
window.NProgress?.start?.(); window.NProgress?.start?.();
next(); return;
}); });
router.afterEach(_to => { router.afterEach(() => {
window.NProgress?.done?.(); window.NProgress?.done?.();
}); });
} }

View File

@@ -1,10 +1,4 @@
import type { import type { LocationQueryRaw, RouteLocationNormalized, RouteLocationRaw, Router } from 'vue-router';
LocationQueryRaw,
NavigationGuardNext,
RouteLocationNormalized,
RouteLocationRaw,
Router
} from 'vue-router';
import type { RouteKey, RoutePath } from '@elegant-router/types'; import type { RouteKey, RoutePath } from '@elegant-router/types';
import { useAuthStore } from '@/store/modules/auth'; import { useAuthStore } from '@/store/modules/auth';
import { useRouteStore } from '@/store/modules/route'; import { useRouteStore } from '@/store/modules/route';
@@ -17,12 +11,11 @@ import { getRouteName } from '@/router/elegant/transform';
* @param router router instance * @param router router instance
*/ */
export function createRouteGuard(router: Router) { export function createRouteGuard(router: Router) {
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from) => {
const location = await initRoute(to); const location = await initRoute(to);
if (location) { if (location) {
next(location); return location;
return;
} }
const authStore = useAuthStore(); const authStore = useAuthStore();
@@ -40,30 +33,26 @@ export function createRouteGuard(router: Router) {
// if it is login route when logged in, then switch to the root page // if it is login route when logged in, then switch to the root page
if (to.name === loginRoute && isLogin) { if (to.name === loginRoute && isLogin) {
next({ name: rootRoute }); return { name: rootRoute };
return;
} }
// if the route does not need login, then it is allowed to access directly // if the route does not need login, then it is allowed to access directly
if (!needLogin) { if (!needLogin) {
handleRouteSwitch(to, from, next); return handleRouteSwitch(to, from);
return;
} }
// the route need login but the user is not logged in, then switch to the login page // the route need login but the user is not logged in, then switch to the login page
if (!isLogin) { if (!isLogin) {
next({ name: loginRoute, query: { redirect: to.fullPath } }); return { name: loginRoute, query: { redirect: to.fullPath } };
return;
} }
// if the user is logged in but does not have authorization, then switch to the 403 page // if the user is logged in but does not have authorization, then switch to the 403 page
if (!hasAuth) { if (!hasAuth) {
next({ name: noAuthorizationRoute }); return { name: noAuthorizationRoute };
return;
} }
// switch route normally // switch route normally
handleRouteSwitch(to, from, next); return handleRouteSwitch(to, from);
}); });
} }
@@ -161,17 +150,13 @@ async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw
return null; return null;
} }
function handleRouteSwitch(to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) { function handleRouteSwitch(to: RouteLocationNormalized, from: RouteLocationNormalized) {
// route with href // route with href
if (to.meta.href) { if (to.meta.href) {
window.open(to.meta.href, '_blank'); window.open(to.meta.href, '_blank');
next({ path: from.fullPath, replace: true, query: from.query, hash: to.hash }); return { path: from.fullPath, replace: true, query: from.query, hash: to.hash };
return;
} }
next();
} }
function getRouteQueryOfLoginRoute(to: RouteLocationNormalized, routeHome: RouteKey) { function getRouteQueryOfLoginRoute(to: RouteLocationNormalized, routeHome: RouteKey) {

View File

@@ -9,7 +9,7 @@ defineOptions({
<template> <template>
<NCard :title="$t('page.home.creativity')" :bordered="false" size="small" class="h-full card-wrapper"> <NCard :title="$t('page.home.creativity')" :bordered="false" size="small" class="h-full card-wrapper">
<div class="h-full flex-center"> <div class="h-full flex-center">
<IconLocalBanner class="text-400px text-primary sm:text-320px" /> <icon-local-banner class="text-400px text-primary sm:text-320px" />
</div> </div>
</NCard> </NCard>
</template> </template>

View File

@@ -4,7 +4,6 @@
"jsx": "preserve", "jsx": "preserve",
"jsxImportSource": "vue", "jsxImportSource": "vue",
"lib": ["DOM", "ESNext"], "lib": ["DOM", "ESNext"],
"baseUrl": ".",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "bundler", "moduleResolution": "bundler",
"paths": { "paths": {

View File

@@ -1,12 +1,8 @@
import { defineConfig } from '@unocss/vite'; import { defineConfig, transformerDirectives, transformerVariantGroup, presetWind3 } from 'unocss';
import transformerDirectives from '@unocss/transformer-directives';
import transformerVariantGroup from '@unocss/transformer-variant-group';
import { presetWind3 } from '@unocss/preset-wind3';
import type { Theme } from '@unocss/preset-uno';
import { presetSoybeanAdmin } from '@sa/uno-preset'; import { presetSoybeanAdmin } from '@sa/uno-preset';
import { themeVars } from './src/theme/vars'; import { themeVars } from './src/theme/vars';
export default defineConfig<Theme>({ export default defineConfig({
content: { content: {
pipeline: { pipeline: {
exclude: ['node_modules', 'dist'] exclude: ['node_modules', 'dist']