mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-10-12 12:53:42 +08:00
Compare commits
4 Commits
v2.0-route
...
v2.0
Author | SHA1 | Date | |
---|---|---|---|
|
91fae50260 | ||
|
61fa4b7f3b | ||
|
ef7acc626f | ||
|
2a0c9f1b41 |
@@ -13,8 +13,10 @@
|
||||
[](https://gitcode.com/soybeanjs/soybean-admin)
|
||||
[](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="Featured|HelloGitHub" 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="Featured|HelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
||||
</div>
|
||||
|
||||
> [!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!
|
||||
|
@@ -13,7 +13,10 @@
|
||||
[](https://gitcode.com/soybeanjs/soybean-admin)
|
||||
[](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="Featured|HelloGitHub" 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="Featured|HelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
||||
</div>
|
||||
|
||||
> [!NOTE]
|
||||
> 如果您觉得 `SoybeanAdmin`对您有所帮助,或者您喜欢我们的项目,请在 GitHub 上给我们一个 ⭐️。您的支持是我们持续改进和增加新功能的动力!感谢您的支持!
|
||||
|
@@ -95,3 +95,27 @@
|
||||
.chrome-tab_dark .chrome-tab-divider {
|
||||
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);
|
||||
}
|
||||
|
@@ -10,6 +10,10 @@ declare const styles: {
|
||||
readonly 'chrome-tab_dark': string;
|
||||
readonly 'chrome-tab-divider': 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;
|
||||
|
@@ -5,6 +5,7 @@ import type { PageTabMode, PageTabProps } from '../../types';
|
||||
import { ACTIVE_COLOR, createTabCssVars } from './shared';
|
||||
import ChromeTab from './chrome-tab.vue';
|
||||
import ButtonTab from './button-tab.vue';
|
||||
import SliderTab from './slider-tab.vue';
|
||||
import SvgClose from './svg-close.vue';
|
||||
import style from './index.module.css';
|
||||
|
||||
@@ -26,7 +27,7 @@ interface Emits {
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const activeTabComponent = computed(() => {
|
||||
const { mode, chromeClass, buttonClass } = props;
|
||||
const { mode, chromeClass, buttonClass, sliderClass } = props;
|
||||
|
||||
const tabComponentMap = {
|
||||
chrome: {
|
||||
@@ -36,6 +37,10 @@ const activeTabComponent = computed(() => {
|
||||
button: {
|
||||
component: ButtonTab,
|
||||
class: buttonClass
|
||||
},
|
||||
slider: {
|
||||
component: SliderTab,
|
||||
class: sliderClass
|
||||
}
|
||||
} satisfies Record<PageTabMode, { component: Component; class?: string }>;
|
||||
|
||||
@@ -45,7 +50,7 @@ const activeTabComponent = computed(() => {
|
||||
const cssVars = computed(() => createTabCssVars(props.activeColor));
|
||||
|
||||
const bindProps = computed(() => {
|
||||
const { chromeClass: _chromeCls, buttonClass: _btnCls, ...rest } = props;
|
||||
const { chromeClass: _chromeCls, buttonClass: _btnCls, sliderClass: _sliderCls, ...rest } = props;
|
||||
|
||||
return rest;
|
||||
});
|
||||
|
53
packages/materials/src/libs/page-tab/slider-tab.vue
Normal file
53
packages/materials/src/libs/page-tab/slider-tab.vue
Normal 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>
|
@@ -239,7 +239,7 @@ export type LayoutCssVars = {
|
||||
*
|
||||
* @default chrome
|
||||
*/
|
||||
export type PageTabMode = 'button' | 'chrome';
|
||||
export type PageTabMode = 'button' | 'chrome' | 'slider';
|
||||
|
||||
export interface PageTabProps {
|
||||
/** Whether is dark mode */
|
||||
@@ -262,6 +262,8 @@ export interface PageTabProps {
|
||||
buttonClass?: string;
|
||||
/** The class of the chrome tab */
|
||||
chromeClass?: string;
|
||||
/** The class of the title tab */
|
||||
sliderClass?: string;
|
||||
/** Whether the tab is active */
|
||||
active?: boolean;
|
||||
/** The color of the active tab */
|
||||
|
@@ -40,7 +40,8 @@ export const themeScrollModeOptions = transformRecordToOption(themeScrollModeRec
|
||||
|
||||
export const themeTabModeRecord: Record<UnionKey.ThemeTabMode, App.I18n.I18nKey> = {
|
||||
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);
|
||||
@@ -57,13 +58,6 @@ export const themePageAnimationModeRecord: Record<UnionKey.ThemePageAnimateMode,
|
||||
|
||||
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 watermarkTimeFormatOptions = [
|
||||
|
@@ -169,7 +169,9 @@ init();
|
||||
<div
|
||||
ref="tabRef"
|
||||
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
|
||||
v-for="tab in tabStore.tabs"
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { resetCacheStrategyOptions, themeTabModeOptions } from '@/constants/app';
|
||||
import { themeTabModeOptions } from '@/constants/app';
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import { translateOptions } from '@/utils/common';
|
||||
import { $t } from '@/locales';
|
||||
@@ -15,14 +15,6 @@ const themeStore = useThemeStore();
|
||||
<template>
|
||||
<NDivider>{{ $t('theme.layout.tab.title') }}</NDivider>
|
||||
<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')">
|
||||
<NSwitch v-model:value="themeStore.tab.visible" />
|
||||
</SettingItem>
|
||||
|
@@ -16,7 +16,6 @@ type ThemePreset = Pick<
|
||||
| 'themeColor'
|
||||
| 'otherColor'
|
||||
| 'isInfoFollowPrimary'
|
||||
| 'resetCacheStrategy'
|
||||
| 'layout'
|
||||
| 'page'
|
||||
| 'header'
|
||||
|
@@ -135,6 +135,7 @@ const local: App.I18n.Schema = {
|
||||
height: 'Tab Height',
|
||||
mode: {
|
||||
title: 'Tab Mode',
|
||||
slider: 'Slider',
|
||||
chrome: 'Chrome',
|
||||
button: 'Button'
|
||||
}
|
||||
@@ -185,11 +186,6 @@ const local: App.I18n.Schema = {
|
||||
}
|
||||
},
|
||||
fixedHeaderAndTab: 'Fixed Header And Tab'
|
||||
},
|
||||
resetCacheStrategy: {
|
||||
title: 'Reset Cache Strategy',
|
||||
close: 'Close Page',
|
||||
refresh: 'Refresh Page'
|
||||
}
|
||||
},
|
||||
general: {
|
||||
|
@@ -132,6 +132,7 @@ const local: App.I18n.Schema = {
|
||||
height: '标签栏高度',
|
||||
mode: {
|
||||
title: '标签栏风格',
|
||||
slider: '滑块风格',
|
||||
chrome: '谷歌风格',
|
||||
button: '按钮风格'
|
||||
}
|
||||
@@ -158,7 +159,7 @@ const local: App.I18n.Schema = {
|
||||
visible: '显示底部',
|
||||
fixed: '固定底部',
|
||||
height: '底部高度',
|
||||
right: '底部局右'
|
||||
right: '底部居右'
|
||||
},
|
||||
content: {
|
||||
title: '内容区域设置',
|
||||
@@ -182,11 +183,6 @@ const local: App.I18n.Schema = {
|
||||
}
|
||||
},
|
||||
fixedHeaderAndTab: '固定头部和标签栏'
|
||||
},
|
||||
resetCacheStrategy: {
|
||||
title: '重置缓存策略',
|
||||
close: '关闭页面',
|
||||
refresh: '刷新页面'
|
||||
}
|
||||
},
|
||||
general: {
|
||||
|
@@ -46,10 +46,7 @@ export const useAppStore = defineStore(SetupStoreId.App, () => {
|
||||
});
|
||||
|
||||
setReloadFlag(true);
|
||||
|
||||
if (themeStore.resetCacheStrategy === 'refresh') {
|
||||
routeStore.resetRouteCache();
|
||||
}
|
||||
routeStore.resetRouteCache();
|
||||
}
|
||||
|
||||
const locale = ref<App.I18n.LangType>(localStg.get('lang') || 'zh-CN');
|
||||
|
@@ -112,10 +112,8 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
|
||||
await switchRouteByTab(nextTab);
|
||||
}
|
||||
|
||||
// reset route cache if cache strategy is close
|
||||
if (themeStore.resetCacheStrategy === 'close') {
|
||||
routeStore.resetRouteCache(removedTabRouteKey);
|
||||
}
|
||||
// reset route cache
|
||||
routeStore.resetRouteCache(removedTabRouteKey);
|
||||
}
|
||||
|
||||
/** remove active tab */
|
||||
@@ -147,10 +145,8 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
|
||||
const tabsToRemove = tabs.value.filter(tab => !remainTabIds.includes(tab.id));
|
||||
const routeKeysToReset: RouteKey[] = [];
|
||||
|
||||
if (themeStore.resetCacheStrategy === 'close') {
|
||||
for (const tab of tabsToRemove) {
|
||||
routeKeysToReset.push(tab.routeKey);
|
||||
}
|
||||
for (const tab of tabsToRemove) {
|
||||
routeKeysToReset.push(tab.routeKey);
|
||||
}
|
||||
|
||||
const removedTabsIds = tabsToRemove.map(tab => tab.id);
|
||||
|
@@ -15,7 +15,6 @@
|
||||
"error": "#c49a9a"
|
||||
},
|
||||
"isInfoFollowPrimary": true,
|
||||
"resetCacheStrategy": "refresh",
|
||||
"layout": {
|
||||
"mode": "vertical-mix",
|
||||
"scrollMode": "wrapper"
|
||||
|
@@ -15,7 +15,6 @@
|
||||
"error": "#f5222d"
|
||||
},
|
||||
"isInfoFollowPrimary": true,
|
||||
"resetCacheStrategy": "close",
|
||||
"layout": {
|
||||
"mode": "vertical",
|
||||
"scrollMode": "content"
|
||||
|
@@ -15,7 +15,6 @@
|
||||
"error": "#f5222d"
|
||||
},
|
||||
"isInfoFollowPrimary": true,
|
||||
"resetCacheStrategy": "close",
|
||||
"layout": {
|
||||
"mode": "vertical",
|
||||
"scrollMode": "content"
|
||||
|
@@ -15,7 +15,6 @@
|
||||
"error": "#f5222d"
|
||||
},
|
||||
"isInfoFollowPrimary": true,
|
||||
"resetCacheStrategy": "close",
|
||||
"layout": {
|
||||
"mode": "vertical",
|
||||
"scrollMode": "content"
|
||||
|
@@ -12,7 +12,6 @@ export const themeSettings: App.Theme.ThemeSetting = {
|
||||
error: '#f5222d'
|
||||
},
|
||||
isInfoFollowPrimary: true,
|
||||
resetCacheStrategy: 'refresh',
|
||||
layout: {
|
||||
mode: 'vertical',
|
||||
scrollMode: 'content'
|
||||
|
3
src/typings/app.d.ts
vendored
3
src/typings/app.d.ts
vendored
@@ -20,8 +20,6 @@ declare namespace App {
|
||||
otherColor: OtherColor;
|
||||
/** Whether info color is followed by the primary color */
|
||||
isInfoFollowPrimary: boolean;
|
||||
/** Reset cache strategy */
|
||||
resetCacheStrategy: UnionKey.ResetCacheStrategy;
|
||||
/** Layout */
|
||||
layout: {
|
||||
/** Layout mode */
|
||||
@@ -436,7 +434,6 @@ declare namespace App {
|
||||
};
|
||||
fixedHeaderAndTab: string;
|
||||
};
|
||||
resetCacheStrategy: { title: string } & Record<UnionKey.ResetCacheStrategy, string>;
|
||||
};
|
||||
general: {
|
||||
title: string;
|
||||
|
8
src/typings/union-key.d.ts
vendored
8
src/typings/union-key.d.ts
vendored
@@ -14,14 +14,6 @@ declare namespace UnionKey {
|
||||
/** Theme scheme */
|
||||
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
|
||||
*
|
||||
|
Reference in New Issue
Block a user