Compare commits

..

10 Commits

16 changed files with 761 additions and 921 deletions

View File

@@ -5,7 +5,6 @@
"antfu.unocss", "antfu.unocss",
"dbaeumer.vscode-eslint", "dbaeumer.vscode-eslint",
"editorconfig.editorconfig", "editorconfig.editorconfig",
"esbenp.prettier-vscode",
"lokalise.i18n-ally", "lokalise.i18n-ally",
"mhutchie.git-graph", "mhutchie.git-graph",
"mikestead.dotenv", "mikestead.dotenv",

View File

@@ -139,7 +139,7 @@ Refer to the [Code Synchronization](https://docs.soybeanjs.cn/guide/sync) docume
## Ecosystem ## Ecosystem
- [react-soybean-admin](https://github.com/mufeng889/react-soybean-admin): SoybeanAdmin based version of React. - [skyroc-admin](https://github.com/Ohh-889/skyroc-admin): SoybeanAdmin's React version implementation.
- [electron-mock-admin](https://github.com/lixin59/electron-mock-api): A Mock Api management system that helps front-end developers quickly implement interface mocks. - [electron-mock-admin](https://github.com/lixin59/electron-mock-api): A Mock Api management system that helps front-end developers quickly implement interface mocks.
- [T-Shell](https://github.com/TheBlindM/T-Shell): A terminal emulator and SSH client with configurable command prompts. - [T-Shell](https://github.com/TheBlindM/T-Shell): A terminal emulator and SSH client with configurable command prompts.
- [pea](https://github.com/haitang1894/pea) : Adopting SpringBoot3.2 + JDK21, MyBatis-Plus, SpringSecurity security framework, etc., suitable for the simple permission system developed by [soybean-admin](https://gitee.com/honghuangdc/soybean-admin). - [pea](https://github.com/haitang1894/pea) : Adopting SpringBoot3.2 + JDK21, MyBatis-Plus, SpringSecurity security framework, etc., suitable for the simple permission system developed by [soybean-admin](https://gitee.com/honghuangdc/soybean-admin).
@@ -151,6 +151,8 @@ Refer to the [Code Synchronization](https://docs.soybeanjs.cn/guide/sync) docume
- [ba](https://github.com/xiatianYa/Ba-Server): Backend service docking with soybean admin based on goFrame framework, adapted to dynamic routing, and interface authentication permissions. - [ba](https://github.com/xiatianYa/Ba-Server): Backend service docking with soybean admin based on goFrame framework, adapted to dynamic routing, and interface authentication permissions.
- [soybean-admin-go](https://github.com/WgoW/soybean-admin-go):A Go backend service developed based on the Gin and GORM frameworks, integrated with the example branch of Soybean Admin. It supports dynamic routing and API permission authentication. - [soybean-admin-go](https://github.com/WgoW/soybean-admin-go):A Go backend service developed based on the Gin and GORM frameworks, integrated with the example branch of Soybean Admin. It supports dynamic routing and API permission authentication.
More ecosystem please refer to [Ecosystem](https://docs.soybeanjs.cn/awesome) document.
## How to Contribute ## How to Contribute
@@ -194,7 +196,7 @@ Here are the most active contributors from the past year. Thank you all for your
<div> <div>
<p>QQ Group</p> <p>QQ Group</p>
<img src="https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/qq-soybean-admin-4.jpg" style="width:200px" /> <img src="https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/qq-soybean-admin-5.jpg" style="width:200px" />
</div> </div>
<!-- <div> <!-- <div>
<p>WeChat Group</p> <p>WeChat Group</p>

View File

@@ -165,7 +165,7 @@ pnpm build
## 周边生态 ## 周边生态
- [react-soybean-admin](https://github.com/mufeng889/react-soybean-admin): 基于SoybeanAdmin的React版本. - [skyroc-admin](https://github.com/Ohh-889/skyroc-admin): SoybeanAdmin的React版本实现.
- [electron-mock-admin](https://github.com/lixin59/electron-mock-api): 一个 Mock Api 管理系统,帮助前端开发伙伴快速实现接口的 mock。 - [electron-mock-admin](https://github.com/lixin59/electron-mock-api): 一个 Mock Api 管理系统,帮助前端开发伙伴快速实现接口的 mock。
- [T-Shell](https://github.com/TheBlindM/T-Shell): 是一个可配置命令提示的终端模拟器和 SSH 客户端。 - [T-Shell](https://github.com/TheBlindM/T-Shell): 是一个可配置命令提示的终端模拟器和 SSH 客户端。
- [pea](https://github.com/haitang1894/pea) : 采用SpringBoot3.2 + JDK21、MyBatis-Plus、SpringSecurity安全框架等适配 [soybean-admin](https://gitee.com/honghuangdc/soybean-admin) 开发的简单权限系统。 - [pea](https://github.com/haitang1894/pea) : 采用SpringBoot3.2 + JDK21、MyBatis-Plus、SpringSecurity安全框架等适配 [soybean-admin](https://gitee.com/honghuangdc/soybean-admin) 开发的简单权限系统。
@@ -177,6 +177,8 @@ pnpm build
- [ba](https://github.com/xiatianYa/Ba-Server): 基于goFrame框架开发的后端服务对接soybean-admin,适配动态路由,接口鉴权限。 - [ba](https://github.com/xiatianYa/Ba-Server): 基于goFrame框架开发的后端服务对接soybean-admin,适配动态路由,接口鉴权限。
- [soybean-admin-go](https://github.com/WgoW/soybean-admin-go):基于gin+gorm框架开发的go语言后端服务对接soybean-admin的example分支,适配动态路由,接口鉴权限。 - [soybean-admin-go](https://github.com/WgoW/soybean-admin-go):基于gin+gorm框架开发的go语言后端服务对接soybean-admin的example分支,适配动态路由,接口鉴权限。
更多周边生态请翻阅 [周边生态](https://docs.soybeanjs.cn/zh/awesome) 文档。
## 如何贡献 ## 如何贡献
@@ -222,7 +224,7 @@ pnpm build
<div> <div>
<p>QQ交流群</p> <p>QQ交流群</p>
<img src="https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/qq-soybean-admin-4.jpg" style="width:200px" /> <img src="https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/qq-soybean-admin-5.jpg" style="width:200px" />
</div> </div>
<!-- <div> <!-- <div>
<p>微信群</p> <p>微信群</p>

View File

@@ -62,45 +62,45 @@
"json5": "2.2.3", "json5": "2.2.3",
"naive-ui": "2.43.1", "naive-ui": "2.43.1",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"pinia": "3.0.3", "pinia": "3.0.4",
"tailwind-merge": "3.3.1", "tailwind-merge": "3.4.0",
"vue": "3.5.22", "vue": "3.5.24",
"vue-draggable-plus": "0.6.0", "vue-draggable-plus": "0.6.0",
"vue-i18n": "11.1.12", "vue-i18n": "11.1.12",
"vue-router": "4.6.3" "vue-router": "4.6.3"
}, },
"devDependencies": { "devDependencies": {
"@elegant-router/vue": "0.3.8", "@elegant-router/vue": "0.3.8",
"@iconify/json": "2.2.402", "@iconify/json": "2.2.407",
"@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.3",
"@types/node": "24.9.2", "@types/node": "24.10.1",
"@types/nprogress": "0.2.3", "@types/nprogress": "0.2.3",
"@unocss/eslint-config": "66.5.4", "@unocss/eslint-config": "66.5.6",
"@unocss/preset-icons": "66.5.4", "@unocss/preset-icons": "66.5.6",
"@unocss/preset-uno": "66.5.4", "@unocss/preset-uno": "66.5.6",
"@unocss/transformer-directives": "66.5.4", "@unocss/transformer-directives": "66.5.6",
"@unocss/transformer-variant-group": "66.5.4", "@unocss/transformer-variant-group": "66.5.6",
"@unocss/vite": "66.5.4", "@unocss/vite": "66.5.6",
"@vitejs/plugin-vue": "6.0.1", "@vitejs/plugin-vue": "6.0.1",
"@vitejs/plugin-vue-jsx": "5.1.1", "@vitejs/plugin-vue-jsx": "5.1.1",
"consola": "3.4.2", "consola": "3.4.2",
"eslint": "9.39.0", "eslint": "9.39.1",
"eslint-plugin-vue": "10.5.1", "eslint-plugin-vue": "10.5.1",
"kolorist": "1.8.0", "kolorist": "1.8.0",
"sass": "1.93.3", "sass": "1.94.0",
"simple-git-hooks": "2.13.1", "simple-git-hooks": "2.13.1",
"tsx": "4.20.6", "tsx": "4.20.6",
"typescript": "5.9.3", "typescript": "5.9.3",
"unplugin-icons": "22.5.0", "unplugin-icons": "22.5.0",
"unplugin-vue-components": "30.0.0", "unplugin-vue-components": "30.0.0",
"vite": "7.1.12", "vite": "7.2.2",
"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.3", "vite-plugin-vue-devtools": "8.0.3",
"vue-eslint-parser": "10.2.0", "vue-eslint-parser": "10.2.0",
"vue-tsc": "3.1.2" "vue-tsc": "3.1.4"
}, },
"simple-git-hooks": { "simple-git-hooks": {
"commit-msg": "pnpm sa git-commit-verify", "commit-msg": "pnpm sa git-commit-verify",

View File

@@ -11,7 +11,7 @@
}, },
"dependencies": { "dependencies": {
"@sa/utils": "workspace:*", "@sa/utils": "workspace:*",
"axios": "1.13.1", "axios": "1.13.2",
"axios-retry": "4.5.0", "axios-retry": "4.5.0",
"qs": "6.14.0" "qs": "6.14.0"
}, },

View File

@@ -15,7 +15,7 @@
"devDependencies": { "devDependencies": {
"@soybeanjs/changelog": "0.3.25", "@soybeanjs/changelog": "0.3.25",
"bumpp": "10.3.1", "bumpp": "10.3.1",
"c12": "3.3.1", "c12": "3.3.2",
"cac": "6.7.14", "cac": "6.7.14",
"consola": "3.4.2", "consola": "3.4.2",
"enquirer": "2.4.1", "enquirer": "2.4.1",

1441
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue'; import { computed } from 'vue';
import { defu } from 'defu';
import { useThemeStore } from '@/store/modules/theme'; import { useThemeStore } from '@/store/modules/theme';
import { themeSettings } from '@/theme/settings';
import { $t } from '@/locales'; import { $t } from '@/locales';
defineOptions({ defineOptions({
@@ -31,6 +33,8 @@ type ThemePreset = Pick<
desc: string; desc: string;
i18nkey?: string; i18nkey?: string;
version: string; version: string;
/** Optional NaiveUI theme overrides */
naiveui?: App.Theme.NaiveUIThemeOverride;
}; };
const presetModules = import.meta.glob('@/theme/preset/*.json', { eager: true, import: 'default' }); const presetModules = import.meta.glob('@/theme/preset/*.json', { eager: true, import: 'default' });
@@ -76,7 +80,9 @@ const getPresetDesc = (preset: ThemePreset): string => {
} }
}; };
const applyPreset = ({ themeScheme, grayscale, colourWeakness, layout, watermark, ...rest }: ThemePreset): void => { const applyPreset = (preset: ThemePreset): void => {
const mergedPreset = defu(preset, themeSettings);
const { themeScheme, grayscale, colourWeakness, layout, watermark, naiveui, ...rest } = mergedPreset;
themeStore.setThemeScheme(themeScheme); themeStore.setThemeScheme(themeScheme);
themeStore.setGrayscale(grayscale); themeStore.setGrayscale(grayscale);
themeStore.setColourWeakness(colourWeakness); themeStore.setColourWeakness(colourWeakness);
@@ -96,6 +102,9 @@ const applyPreset = ({ themeScheme, grayscale, colourWeakness, layout, watermark
tokens: { ...rest.tokens } tokens: { ...rest.tokens }
}); });
// Apply NaiveUI theme overrides if present
themeStore.setNaiveThemeOverrides(naiveui);
window.$message?.success($t('theme.appearance.preset.applySuccess')); window.$message?.success($t('theme.appearance.preset.applySuccess'));
}; };
</script> </script>

View File

@@ -24,6 +24,9 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => {
/** Theme settings */ /** Theme settings */
const settings: Ref<App.Theme.ThemeSetting> = ref(initThemeSettings()); const settings: Ref<App.Theme.ThemeSetting> = ref(initThemeSettings());
/** Optional NaiveUI theme overrides from preset */
const naiveThemeOverrides: Ref<App.Theme.NaiveUIThemeOverride | undefined> = ref(undefined);
/** Watermark time instance with controls */ /** Watermark time instance with controls */
const { now: watermarkTime, pause: pauseWatermarkTime, resume: resumeWatermarkTime } = useNow({ controls: true }); const { now: watermarkTime, pause: pauseWatermarkTime, resume: resumeWatermarkTime } = useNow({ controls: true });
@@ -53,7 +56,7 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => {
}); });
/** Naive theme */ /** Naive theme */
const naiveTheme = computed(() => getNaiveTheme(themeColors.value, settings.value)); const naiveTheme = computed(() => getNaiveTheme(themeColors.value, settings.value, naiveThemeOverrides.value));
/** /**
* Settings json * Settings json
@@ -198,6 +201,15 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => {
} }
} }
/**
* Set NaiveUI theme overrides
*
* @param overrides NaiveUI theme overrides or undefined to clear
*/
function setNaiveThemeOverrides(overrides?: App.Theme.NaiveUIThemeOverride) {
naiveThemeOverrides.value = overrides;
}
/** Only run timer when watermark is visible and time display is enabled */ /** Only run timer when watermark is visible and time display is enabled */
function updateWatermarkTimer() { function updateWatermarkTimer() {
const { watermark } = settings.value; const { watermark } = settings.value;
@@ -284,6 +296,7 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => {
updateThemeColors, updateThemeColors,
setThemeLayout, setThemeLayout,
setWatermarkEnableUserName, setWatermarkEnableUserName,
setWatermarkEnableTime setWatermarkEnableTime,
setNaiveThemeOverrides
}; };
}); });

View File

@@ -236,11 +236,15 @@ function getNaiveThemeColors(colors: App.Theme.ThemeColor, recommended = false)
/** /**
* Get naive theme * Get naive theme
* *
* @param settings Theme settings object. * @param colors Theme colors
* @param settings.recommendColor Whether to use recommended color palette. * @param settings Theme settings object
* @param settings.themeRadius Border radius to use in the theme (in px). * @param overrides Optional manual overrides from preset
*/ */
export function getNaiveTheme(colors: App.Theme.ThemeColor, settings: App.Theme.ThemeSetting) { export function getNaiveTheme(
colors: App.Theme.ThemeColor,
settings: App.Theme.ThemeSetting,
overrides?: GlobalThemeOverrides
) {
const { primary: colorLoading } = colors; const { primary: colorLoading } = colors;
const theme: GlobalThemeOverrides = { const theme: GlobalThemeOverrides = {
@@ -256,5 +260,7 @@ export function getNaiveTheme(colors: App.Theme.ThemeColor, settings: App.Theme.
} }
}; };
return theme; // If there are overrides, merge them with priority
// overrides has higher priority than auto-generated theme
return overrides ? defu(overrides, theme) : theme;
} }

View File

@@ -2,10 +2,8 @@
"name": "Azir's Preset", "name": "Azir's Preset",
"desc": "It is a cold and elegant preset that Azir likes", "desc": "It is a cold and elegant preset that Azir likes",
"i18nkey": "theme.appearance.preset.azir", "i18nkey": "theme.appearance.preset.azir",
"version": "1.0.0", "version": "1.0.1",
"themeScheme": "light", "themeScheme": "light",
"grayscale": false,
"colourWeakness": false,
"recommendColor": true, "recommendColor": true,
"themeColor": "#78a878", "themeColor": "#78a878",
"otherColor": { "otherColor": {
@@ -14,57 +12,7 @@
"warning": "#d4bb9d", "warning": "#d4bb9d",
"error": "#c49a9a" "error": "#c49a9a"
}, },
"themeRadius": 6,
"isInfoFollowPrimary": true, "isInfoFollowPrimary": true,
"layout": {
"mode": "vertical-mix",
"scrollMode": "wrapper"
},
"page": {
"animate": true,
"animateMode": "zoom-fade"
},
"header": {
"height": 64,
"breadcrumb": {
"visible": true,
"showIcon": true
},
"multilingual": {
"visible": true
},
"globalSearch": {
"visible": true
}
},
"tab": {
"visible": true,
"cache": true,
"height": 48,
"mode": "chrome"
},
"fixedHeaderAndTab": true,
"sider": {
"inverted": false,
"width": 220,
"collapsedWidth": 64,
"mixWidth": 90,
"mixCollapsedWidth": 64,
"mixChildMenuWidth": 200
},
"footer": {
"visible": true,
"fixed": true,
"height": 56,
"right": true
},
"watermark": {
"visible": false,
"text": "SoybeanAdmin",
"enableUserName": false,
"enableTime": true,
"timeFormat": "YYYY-MM-DD HH:mm:ss"
},
"tokens": { "tokens": {
"light": { "light": {
"colors": { "colors": {
@@ -86,5 +34,19 @@
"base-text": "rgb(224, 224, 224)" "base-text": "rgb(224, 224, 224)"
} }
} }
},
"naiveui": {
"Alert": {
"borderRadiusMedium": "12px",
"fontWeightStrong": "600",
"paddingMedium": "0 20px"
},
"Card": {
"borderRadius": "16px",
"paddingMedium": "24px"
},
"Input": {
"borderRadius": "10px"
}
} }
} }

View File

@@ -2,33 +2,12 @@
"name": "Compact Preset", "name": "Compact Preset",
"desc": "Compact layout preset for small screens", "desc": "Compact layout preset for small screens",
"i18nkey": "theme.appearance.preset.compact", "i18nkey": "theme.appearance.preset.compact",
"version": "1.0.0", "version": "1.0.1",
"themeScheme": "light",
"grayscale": false,
"colourWeakness": false,
"recommendColor": false,
"themeColor": "#646cff",
"otherColor": {
"info": "#2080f0",
"success": "#52c41a",
"warning": "#faad14",
"error": "#f5222d"
},
"themeRadius": 6, "themeRadius": 6,
"isInfoFollowPrimary": true,
"layout": {
"mode": "vertical",
"scrollMode": "content"
},
"page": {
"animate": true,
"animateMode": "fade-slide"
},
"header": { "header": {
"height": 48, "height": 48,
"breadcrumb": { "breadcrumb": {
"visible": true, "visible": false
"showIcon": true
}, },
"multilingual": { "multilingual": {
"visible": false "visible": false
@@ -41,9 +20,9 @@
"visible": true, "visible": true,
"cache": true, "cache": true,
"height": 36, "height": 36,
"mode": "button" "mode": "button",
"closeTabByMiddleClick": false
}, },
"fixedHeaderAndTab": true,
"sider": { "sider": {
"inverted": false, "inverted": false,
"width": 180, "width": 180,
@@ -53,38 +32,6 @@
"mixChildMenuWidth": 180 "mixChildMenuWidth": 180
}, },
"footer": { "footer": {
"visible": false, "visible": false
"fixed": false,
"height": 40,
"right": true
},
"watermark": {
"visible": false,
"text": "SoybeanAdmin",
"enableUserName": false,
"enableTime": false,
"timeFormat": "YYYY-MM-DD HH:mm"
},
"tokens": {
"light": {
"colors": {
"container": "rgb(255, 255, 255)",
"layout": "rgb(247, 250, 252)",
"inverted": "rgb(0, 20, 40)",
"base-text": "rgb(31, 31, 31)"
},
"boxShadow": {
"header": "0 1px 2px rgb(0, 21, 41, 0.08)",
"sider": "2px 0 8px 0 rgb(29, 35, 41, 0.05)",
"tab": "0 1px 2px rgb(0, 21, 41, 0.08)"
}
},
"dark": {
"colors": {
"container": "rgb(28, 28, 28)",
"layout": "rgb(18, 18, 18)",
"base-text": "rgb(224, 224, 224)"
}
}
} }
} }

View File

@@ -2,12 +2,12 @@
"name": "Dark Preset", "name": "Dark Preset",
"desc": "Dark theme preset for night time usage", "desc": "Dark theme preset for night time usage",
"i18nkey": "theme.appearance.preset.dark", "i18nkey": "theme.appearance.preset.dark",
"version": "1.0.0", "version": "1.0.1",
"themeScheme": "dark", "themeScheme": "dark",
"grayscale": false, "grayscale": false,
"colourWeakness": false, "colourWeakness": false,
"recommendColor": false, "recommendColor": false,
"themeColor": "#409eff", "themeColor": "#646cff",
"otherColor": { "otherColor": {
"info": "#2080f0", "info": "#2080f0",
"success": "#52c41a", "success": "#52c41a",
@@ -41,11 +41,12 @@
"visible": true, "visible": true,
"cache": true, "cache": true,
"height": 44, "height": 44,
"mode": "chrome" "mode": "chrome",
"closeTabByMiddleClick": false
}, },
"fixedHeaderAndTab": true, "fixedHeaderAndTab": true,
"sider": { "sider": {
"inverted": true, "inverted": false,
"width": 220, "width": 220,
"collapsedWidth": 64, "collapsedWidth": 64,
"mixWidth": 90, "mixWidth": 90,

View File

@@ -41,7 +41,8 @@
"visible": true, "visible": true,
"cache": true, "cache": true,
"height": 44, "height": 44,
"mode": "chrome" "mode": "chrome",
"closeTabByMiddleClick": false
}, },
"fixedHeaderAndTab": true, "fixedHeaderAndTab": true,
"sider": { "sider": {

View File

@@ -4,6 +4,9 @@ declare namespace App {
namespace Theme { namespace Theme {
type ColorPaletteNumber = import('@sa/color').ColorPaletteNumber; type ColorPaletteNumber = import('@sa/color').ColorPaletteNumber;
/** NaiveUI theme overrides that can be specified in preset */
type NaiveUIThemeOverride = import('naive-ui').GlobalThemeOverrides;
/** Theme setting */ /** Theme setting */
interface ThemeSetting { interface ThemeSetting {
/** Theme scheme */ /** Theme scheme */

View File

@@ -15,7 +15,7 @@ const gap = computed(() => (appStore.isMobile ? 0 : 16));
<template> <template>
<NSpace vertical :size="16"> <NSpace vertical :size="16">
<NAlert :title="$t('common.warning')" type="warning"> <NAlert :title="$t('common.tip')" type="warning">
{{ $t('page.home.branchDesc') }} {{ $t('page.home.branchDesc') }}
</NAlert> </NAlert>
<HeaderBanner /> <HeaderBanner />