mirror of
https://github.com/vbenjs/gf-vben-admin.git
synced 2025-01-23 11:50:20 +08:00
feat: new menu and top bar color selection color matching
This commit is contained in:
parent
bda3e5da30
commit
7692ffb95b
@ -4,6 +4,7 @@
|
||||
|
||||
- 表单项的`componentsProps`支持函数类型
|
||||
- 菜单新增 tag 显示
|
||||
- 新增菜单及顶栏颜色选择配色
|
||||
|
||||
### ⚡ Performance Improvements
|
||||
|
||||
|
@ -43,7 +43,7 @@
|
||||
|
||||
.app-loading .g-loading {
|
||||
display: block;
|
||||
width: 64px;
|
||||
width: 48px;
|
||||
margin: 30px auto;
|
||||
-webkit-animation: load 1.2s linear infinite;
|
||||
animation: load 1.2s linear infinite;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { MenuState } from './types';
|
||||
import type { Menu as MenuType } from '/@/router/types';
|
||||
|
||||
import { computed, defineComponent, unref, reactive, toRef, watch, onMounted, ref } from 'vue';
|
||||
import { computed, defineComponent, unref, reactive, watch, onMounted, ref, toRefs } from 'vue';
|
||||
import { Menu } from 'ant-design-vue';
|
||||
import SearchInput from './SearchInput.vue';
|
||||
import MenuContent from './MenuContent';
|
||||
@ -40,8 +40,10 @@ export default defineComponent({
|
||||
});
|
||||
const { currentRoute } = useRouter();
|
||||
|
||||
const { items, flatItems, isAppMenu, mode, accordion } = toRefs(props);
|
||||
|
||||
const { handleInputChange, handleInputClick } = useSearchInput({
|
||||
flatMenusRef: toRef(props, 'flatItems'),
|
||||
flatMenusRef: flatItems,
|
||||
emit: emit,
|
||||
menuState,
|
||||
handleMenuChange,
|
||||
@ -49,11 +51,11 @@ export default defineComponent({
|
||||
|
||||
const { handleOpenChange, resetKeys, setOpenKeys } = useOpenKeys(
|
||||
menuState,
|
||||
toRef(props, 'items'),
|
||||
toRef(props, 'flatItems'),
|
||||
toRef(props, 'isAppMenu'),
|
||||
toRef(props, 'mode'),
|
||||
toRef(props, 'accordion')
|
||||
items,
|
||||
flatItems,
|
||||
isAppMenu,
|
||||
mode,
|
||||
accordion
|
||||
);
|
||||
|
||||
const getOpenKeys = computed(() => {
|
||||
@ -98,6 +100,8 @@ export default defineComponent({
|
||||
return cls;
|
||||
});
|
||||
|
||||
const showTitle = computed(() => props.collapsedShowTitle && menuStore.getCollapsedState);
|
||||
|
||||
watch(
|
||||
() => currentRoute.value.name,
|
||||
(name: string) => {
|
||||
@ -130,9 +134,7 @@ export default defineComponent({
|
||||
const { beforeClickFn } = props;
|
||||
if (beforeClickFn && isFunction(beforeClickFn)) {
|
||||
const flag = await beforeClickFn(menu);
|
||||
if (!flag) {
|
||||
return;
|
||||
}
|
||||
if (!flag) return;
|
||||
}
|
||||
const { path } = menu;
|
||||
menuState.selectedKeys = [path];
|
||||
@ -141,9 +143,7 @@ export default defineComponent({
|
||||
|
||||
function handleMenuChange() {
|
||||
const { flatItems } = props;
|
||||
if (!unref(flatItems) || flatItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (!unref(flatItems) || flatItems.length === 0) return;
|
||||
const findMenu = flatItems.find((menu) => menu.path === unref(currentRoute).path);
|
||||
if (findMenu) {
|
||||
if (menuState.mode !== MenuModeEnum.HORIZONTAL) {
|
||||
@ -155,10 +155,6 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
const showTitle = computed(() => {
|
||||
return props.collapsedShowTitle && menuStore.getCollapsedState;
|
||||
});
|
||||
|
||||
// render menu item
|
||||
function renderMenuItem(menuList?: MenuType[], index = 1) {
|
||||
if (!menuList) return;
|
||||
@ -183,6 +179,7 @@ export default defineComponent({
|
||||
<MenuContent
|
||||
item={menu}
|
||||
level={index}
|
||||
isTop={props.isTop}
|
||||
showTitle={unref(showTitle)}
|
||||
searchValue={menuState.searchValue}
|
||||
/>,
|
||||
@ -198,6 +195,7 @@ export default defineComponent({
|
||||
showTitle={unref(showTitle)}
|
||||
item={menu}
|
||||
level={index}
|
||||
isTop={props.isTop}
|
||||
searchValue={menuState.searchValue}
|
||||
/>,
|
||||
],
|
||||
|
@ -26,6 +26,10 @@ export default defineComponent({
|
||||
type: Number as PropType<number>,
|
||||
default: 0,
|
||||
},
|
||||
isTop: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
/**
|
||||
@ -56,14 +60,16 @@ export default defineComponent({
|
||||
if (!props.item) {
|
||||
return null;
|
||||
}
|
||||
const { showTitle } = props;
|
||||
const { showTitle, isTop } = props;
|
||||
const { name, icon } = props.item;
|
||||
const searchValue = props.searchValue || '';
|
||||
const index = name.indexOf(searchValue);
|
||||
|
||||
const beforeStr = name.substr(0, index);
|
||||
const afterStr = name.substr(index + searchValue.length);
|
||||
const cls = showTitle ? 'show-title' : 'basic-menu__name';
|
||||
let cls = showTitle ? ['show-title'] : ['basic-menu__name'];
|
||||
|
||||
isTop && !showTitle && (cls = []);
|
||||
return (
|
||||
<>
|
||||
{renderIcon(icon!)}
|
||||
|
@ -102,7 +102,7 @@
|
||||
|
||||
.set-bg() {
|
||||
color: #fff;
|
||||
background: @input-dark-bg-color;
|
||||
background: @sider-dark-lighten-1-bg-color;
|
||||
border: 0;
|
||||
outline: none;
|
||||
}
|
||||
|
@ -52,10 +52,11 @@
|
||||
// collapsed show title end
|
||||
.ant-menu-submenu-title {
|
||||
> .basic-menu__name {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.basic-menu__tag {
|
||||
float: right;
|
||||
margin-top: @app-menu-item-height / 2;
|
||||
transform: translate(0%, -50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,7 +255,7 @@
|
||||
// 层级样式
|
||||
&.ant-menu-dark:not(.basic-menu__sidebar-hor) {
|
||||
overflow-x: hidden;
|
||||
background: @menu-item-dark-bg-color;
|
||||
background: @sider-dark-bg-color;
|
||||
.active-menu-style();
|
||||
|
||||
.ant-menu-item.ant-menu-item-selected.basic-menu-menu-item__level1,
|
||||
@ -263,21 +264,20 @@
|
||||
}
|
||||
|
||||
.basic-menu-item__level1 {
|
||||
background-color: @menu-item-dark-bg-color;
|
||||
background-color: @sider-dark-bg-color;
|
||||
|
||||
> .ant-menu-sub > li {
|
||||
background-color: lighten(@menu-item-dark-bg-color, 6%);
|
||||
background-color: @sider-dark-lighten-1-bg-color;
|
||||
}
|
||||
}
|
||||
|
||||
.basic-menu-item__level2:not(.ant-menu-item-selected),
|
||||
.ant-menu-sub {
|
||||
background-color: lighten(@menu-item-dark-bg-color, 6%);
|
||||
// background-color: @sub-menu-item-dark-bg-color;
|
||||
background-color: @sider-dark-lighten-1-bg-color;
|
||||
}
|
||||
|
||||
.basic-menu-item__level3:not(.ant-menu-item-selected) {
|
||||
background-color: lighten(@menu-item-dark-bg-color, 10%);
|
||||
background-color: @sider-dark-lighten-2-bg-color;
|
||||
}
|
||||
|
||||
.ant-menu-submenu-title {
|
||||
@ -290,7 +290,7 @@
|
||||
&.ant-menu-inline-collapsed {
|
||||
.ant-menu-submenu-selected,
|
||||
.ant-menu-item-selected {
|
||||
background: darken(@menu-item-dark-bg-color, 6%) !important;
|
||||
background: @sider-dark-darken-bg-color !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -359,7 +359,7 @@
|
||||
.ant-menu-dark {
|
||||
&.ant-menu-submenu-popup {
|
||||
> ul {
|
||||
background: @menu-item-dark-bg-color;
|
||||
background: @sider-dark-bg-color;
|
||||
}
|
||||
|
||||
.active-menu-style();
|
||||
|
@ -1,3 +1,17 @@
|
||||
:root {
|
||||
// header
|
||||
--header-bg-color: #394664;
|
||||
--header-bg-hover-color: #273352;
|
||||
--header-active-menu-bg-color: #273352;
|
||||
|
||||
// sider
|
||||
--sider-dark-bg-color: #273352;
|
||||
--sider-dark-darken-bg-color: #273352;
|
||||
--sider-dark-lighten-1-bg-color: #273352;
|
||||
--sider-dark-lighten-2-bg-color: #273352;
|
||||
--sider-dark-lighten-3-bg-color: #273352;
|
||||
}
|
||||
|
||||
@white: #fff;
|
||||
@info-color: @primary-color;
|
||||
|
||||
@ -53,21 +67,24 @@
|
||||
// ==============Header=============
|
||||
// =================================
|
||||
|
||||
@header-dark-bg-color: #394664;
|
||||
@header-dark-bg-hover-color: #273352;
|
||||
@header-dark-bg-color: var(--header-bg-color);
|
||||
@header-dark-bg-hover-color: var(--header-bg-hover-color);
|
||||
@header-light-bg-hover-color: #f6f6f6;
|
||||
@header-light-desc-color: #7c8087;
|
||||
@header-light-bottom-border-color: #eee;
|
||||
// top-menu
|
||||
@top-menu-active-bg-color: var(--header-active-menu-bg-color);
|
||||
|
||||
// =================================
|
||||
// ==============Menu============
|
||||
// =================================
|
||||
|
||||
// let -menu
|
||||
@menu-item-dark-bg-color: #273352;
|
||||
|
||||
// top-menu
|
||||
@top-menu-active-bg-color: #273352;
|
||||
@sider-dark-bg-color: var(--sider-dark-bg-color);
|
||||
@sider-dark-darken-bg-color: var(--sider-dark-darken-bg-color);
|
||||
@sider-dark-lighten-1-bg-color: var(--sider-dark-lighten-1-bg-color);
|
||||
@sider-dark-lighten-2-bg-color: var(--sider-dark-lighten-2-bg-color);
|
||||
@sider-dark-lighten-3-bg-color: var(--sider-dark-lighten-3-bg-color);
|
||||
|
||||
// trigger
|
||||
@trigger-dark-hover-bg-color: rgba(255, 255, 255, 0.2);
|
||||
|
@ -79,9 +79,8 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
const showHeaderTrigger = computed(() => {
|
||||
const { show, trigger, hidden } = unref(getProjectConfigRef).menuSetting;
|
||||
|
||||
if (!show || !hidden) return false;
|
||||
const { show, trigger, hidden, type } = unref(getProjectConfigRef).menuSetting;
|
||||
if (type === MenuTypeEnum.TOP_MENU || !show || !hidden) return false;
|
||||
return trigger === TriggerEnum.HEADER;
|
||||
});
|
||||
|
||||
|
@ -41,7 +41,7 @@
|
||||
background-size: 100% 100%;
|
||||
|
||||
&.ant-layout-sider-dark {
|
||||
background: @menu-item-dark-bg-color;
|
||||
background: @sider-dark-bg-color;
|
||||
}
|
||||
|
||||
&:not(.ant-layout-sider-dark) {
|
||||
|
@ -25,13 +25,9 @@ export default defineComponent({
|
||||
|
||||
const { getFullContent } = useFullContent();
|
||||
|
||||
const getProjectConfigRef = computed(() => {
|
||||
return appStore.getProjectConfig;
|
||||
});
|
||||
const getProjectConfigRef = computed(() => appStore.getProjectConfig);
|
||||
|
||||
const getLockMainScrollStateRef = computed(() => {
|
||||
return appStore.getLockMainScrollState;
|
||||
});
|
||||
const getLockMainScrollStateRef = computed(() => appStore.getLockMainScrollState);
|
||||
|
||||
const showHeaderRef = computed(() => {
|
||||
const {
|
||||
@ -47,6 +43,12 @@ export default defineComponent({
|
||||
return type !== MenuTypeEnum.SIDEBAR && unref(showHeaderRef);
|
||||
});
|
||||
|
||||
const getIsLockRef = computed(() => {
|
||||
const { getLockInfo } = appStore;
|
||||
const { isLock } = getLockInfo;
|
||||
return isLock;
|
||||
});
|
||||
|
||||
const showSideBarRef = computed(() => {
|
||||
const {
|
||||
menuSetting: { show, mode, split },
|
||||
@ -54,6 +56,38 @@ export default defineComponent({
|
||||
return split || (show && mode !== MenuModeEnum.HORIZONTAL && !unref(getFullContent));
|
||||
});
|
||||
|
||||
const showFullHeaderRef = computed(() => {
|
||||
return !unref(getFullContent) && unref(isShowMixHeaderRef) && unref(showHeaderRef);
|
||||
});
|
||||
|
||||
const showInsetHeaderRef = computed(() => {
|
||||
return !unref(getFullContent) && !unref(isShowMixHeaderRef) && unref(showHeaderRef);
|
||||
});
|
||||
|
||||
const fixedHeaderClsRef = computed(() => {
|
||||
const {
|
||||
headerSetting: { fixed },
|
||||
} = unref(getProjectConfigRef);
|
||||
const fixedHeaderCls = fixed
|
||||
? 'fixed' + (unref(getLockMainScrollStateRef) ? ' lock' : '')
|
||||
: '';
|
||||
return fixedHeaderCls;
|
||||
});
|
||||
|
||||
const showTabsRef = computed(() => {
|
||||
const {
|
||||
multiTabsSetting: { show },
|
||||
} = unref(getProjectConfigRef);
|
||||
return show && !unref(getFullContent);
|
||||
});
|
||||
|
||||
const showClassSideBarRef = computed(() => {
|
||||
const {
|
||||
menuSetting: { split, hidden },
|
||||
} = unref(getProjectConfigRef);
|
||||
return split ? hidden : true;
|
||||
});
|
||||
|
||||
function getTarget(): any {
|
||||
const {
|
||||
headerSetting: { fixed },
|
||||
@ -62,51 +96,34 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
return () => {
|
||||
const { getLockInfo } = appStore;
|
||||
const {
|
||||
useOpenBackTop,
|
||||
showSettingButton,
|
||||
multiTabsSetting: { show: showTabs },
|
||||
headerSetting: { fixed },
|
||||
menuSetting: { split, hidden },
|
||||
} = unref(getProjectConfigRef);
|
||||
|
||||
const fixedHeaderCls = fixed
|
||||
? 'fixed' + (unref(getLockMainScrollStateRef) ? ' lock' : '')
|
||||
: '';
|
||||
|
||||
const { isLock } = getLockInfo;
|
||||
|
||||
const showSideBar = split ? hidden : true;
|
||||
const { useOpenBackTop, showSettingButton } = unref(getProjectConfigRef);
|
||||
return (
|
||||
<Layout class="default-layout relative">
|
||||
{() => (
|
||||
<>
|
||||
{/* lock page */}
|
||||
{isLock && <LockPage />}
|
||||
{unref(getIsLockRef) && <LockPage />}
|
||||
{/* back top */}
|
||||
{useOpenBackTop && <BackTop target={getTarget} />}
|
||||
{/* open setting drawer */}
|
||||
{showSettingButton && <SettingBtn />}
|
||||
|
||||
{!unref(getFullContent) && unref(isShowMixHeaderRef) && unref(showHeaderRef) && (
|
||||
<LayoutHeader />
|
||||
)}
|
||||
{unref(showFullHeaderRef) && <LayoutHeader />}
|
||||
|
||||
<Layout>
|
||||
{() => (
|
||||
<>
|
||||
{unref(showSideBarRef) && <LayoutSideBar class={showSideBar ? '' : 'hidden'} />}
|
||||
<Layout class={[`default-layout__content`, fixedHeaderCls]}>
|
||||
{unref(showSideBarRef) && (
|
||||
<LayoutSideBar class={unref(showClassSideBarRef) ? '' : 'hidden'} />
|
||||
)}
|
||||
<Layout class={[`default-layout__content`, unref(fixedHeaderClsRef)]}>
|
||||
{() => (
|
||||
<>
|
||||
{!unref(getFullContent) &&
|
||||
!unref(isShowMixHeaderRef) &&
|
||||
unref(showHeaderRef) && <LayoutHeader />}
|
||||
{unref(showInsetHeaderRef) && <LayoutHeader />}
|
||||
|
||||
{showTabs && !unref(getFullContent) && <MultipleTabs />}
|
||||
{unref(showTabsRef) && <MultipleTabs />}
|
||||
|
||||
<LayoutContent class={fixedHeaderCls} />
|
||||
<LayoutContent class={unref(fixedHeaderClsRef)} />
|
||||
</>
|
||||
)}
|
||||
</Layout>
|
||||
|
@ -20,12 +20,12 @@ import { updateColorWeak, updateGrayMode } from '/@/setup/theme';
|
||||
import { baseHandler } from './handler';
|
||||
import {
|
||||
HandlerEnum,
|
||||
themeOptions,
|
||||
contentModeOptions,
|
||||
topMenuAlignOptions,
|
||||
menuTriggerOptions,
|
||||
routerTransitionOptions,
|
||||
} from './const';
|
||||
import { HEADER_PRESET_BG_COLOR_LIST, SIDE_BAR_BG_COLOR_LIST } from '/@/settings/colorSetting';
|
||||
|
||||
interface SwitchOptions {
|
||||
config?: DeepPartial<ProjectConfig>;
|
||||
@ -41,6 +41,11 @@ interface SelectConfig {
|
||||
handler?: Fn;
|
||||
}
|
||||
|
||||
interface ThemeOptions {
|
||||
def?: string;
|
||||
handler?: Fn;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SettingDrawer',
|
||||
setup(_, { attrs }) {
|
||||
@ -98,8 +103,7 @@ export default defineComponent({
|
||||
|
||||
function renderSidebar() {
|
||||
const {
|
||||
headerSetting: { theme: headerTheme },
|
||||
menuSetting: { type, theme: menuTheme, split },
|
||||
menuSetting: { type, split },
|
||||
} = unref(getProjectConfigRef);
|
||||
|
||||
const typeList = ref([
|
||||
@ -154,22 +158,22 @@ export default defineComponent({
|
||||
def: split,
|
||||
disabled: !unref(getShowMenuRef) || type !== MenuTypeEnum.MIX,
|
||||
}),
|
||||
renderSelectItem('顶栏主题', {
|
||||
handler: (e) => {
|
||||
baseHandler(HandlerEnum.HEADER_THEME, e);
|
||||
},
|
||||
def: headerTheme,
|
||||
options: themeOptions,
|
||||
disabled: !unref(getShowHeaderRef),
|
||||
}),
|
||||
renderSelectItem('菜单主题', {
|
||||
handler: (e) => {
|
||||
baseHandler(HandlerEnum.MENU_THEME, e);
|
||||
},
|
||||
def: menuTheme,
|
||||
options: themeOptions,
|
||||
disabled: !unref(getShowMenuRef),
|
||||
}),
|
||||
// renderSelectItem('顶栏主题', {
|
||||
// handler: (e) => {
|
||||
// baseHandler(HandlerEnum.HEADER_THEME, e);
|
||||
// },
|
||||
// def: headerTheme,
|
||||
// options: themeOptions,
|
||||
// disabled: !unref(getShowHeaderRef),
|
||||
// }),
|
||||
// renderSelectItem('菜单主题', {
|
||||
// handler: (e) => {
|
||||
// baseHandler(HandlerEnum.MENU_THEME, e);
|
||||
// },
|
||||
// def: menuTheme,
|
||||
// options: themeOptions,
|
||||
// disabled: !unref(getShowMenuRef),
|
||||
// }),
|
||||
];
|
||||
}
|
||||
/**
|
||||
@ -413,7 +417,6 @@ export default defineComponent({
|
||||
return (
|
||||
<div class={`setting-drawer__cell-item`}>
|
||||
<span>{text}</span>
|
||||
{/* @ts-ignore */}
|
||||
<Select
|
||||
{...opt}
|
||||
disabled={disabled}
|
||||
@ -447,6 +450,50 @@ export default defineComponent({
|
||||
);
|
||||
}
|
||||
|
||||
function renderTheme() {
|
||||
const { headerBgColor, menuBgColor } = unref(getProjectConfigRef);
|
||||
return (
|
||||
<>
|
||||
<Divider>{() => '顶栏主题'}</Divider>
|
||||
{renderThemeItem(HEADER_PRESET_BG_COLOR_LIST, {
|
||||
def: headerBgColor,
|
||||
handler: (e) => {
|
||||
baseHandler(HandlerEnum.HEADER_THEME, e);
|
||||
},
|
||||
})}
|
||||
<Divider>{() => '菜单主题'}</Divider>
|
||||
{renderThemeItem(SIDE_BAR_BG_COLOR_LIST, {
|
||||
def: menuBgColor,
|
||||
handler: (e) => {
|
||||
baseHandler(HandlerEnum.MENU_THEME, e);
|
||||
},
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function renderThemeItem(colorList: string[], opt: ThemeOptions) {
|
||||
const { def, handler } = opt;
|
||||
return (
|
||||
<div class={`setting-drawer__theme-item`}>
|
||||
{colorList.map((item) => {
|
||||
return (
|
||||
<span
|
||||
onClick={() => handler && handler(item)}
|
||||
key={item}
|
||||
class={[def === item ? 'active' : '']}
|
||||
style={{
|
||||
background: item,
|
||||
}}
|
||||
>
|
||||
<CheckOutlined class="icon" />
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return () => (
|
||||
<BasicDrawer {...attrs} title="项目配置" width={300} wrapClassName="setting-drawer">
|
||||
{{
|
||||
@ -454,6 +501,9 @@ export default defineComponent({
|
||||
<>
|
||||
<Divider>{() => '导航栏模式'}</Divider>
|
||||
{renderSidebar()}
|
||||
|
||||
{renderTheme()}
|
||||
|
||||
<Divider>{() => '界面功能'}</Divider>
|
||||
{renderFeatures()}
|
||||
<Divider>{() => '界面显示'}</Divider>
|
||||
|
@ -1,6 +1,11 @@
|
||||
import { HandlerEnum } from './const';
|
||||
import { MenuThemeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
|
||||
import { updateColorWeak, updateGrayMode } from '/@/setup/theme';
|
||||
// import { MenuThemeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
|
||||
import {
|
||||
updateColorWeak,
|
||||
updateGrayMode,
|
||||
updateHeaderBgColor,
|
||||
updateSidebarBgColor,
|
||||
} from '/@/setup/theme';
|
||||
import { appStore } from '/@/store/modules/app';
|
||||
import { ProjectConfig } from '/@/types/config';
|
||||
|
||||
@ -14,12 +19,12 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
|
||||
case HandlerEnum.CHANGE_LAYOUT:
|
||||
const { mode, type, split } = value;
|
||||
const splitOpt = split === undefined ? { split } : {};
|
||||
let headerSetting = {};
|
||||
if (type === MenuTypeEnum.TOP_MENU) {
|
||||
headerSetting = {
|
||||
theme: MenuThemeEnum.DARK,
|
||||
};
|
||||
}
|
||||
// let headerSetting = {};
|
||||
// if (type === MenuTypeEnum.TOP_MENU) {
|
||||
// headerSetting = {
|
||||
// theme: MenuThemeEnum.DARK,
|
||||
// };
|
||||
// }
|
||||
return {
|
||||
menuSetting: {
|
||||
mode,
|
||||
@ -28,7 +33,7 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
|
||||
show: true,
|
||||
...splitOpt,
|
||||
},
|
||||
headerSetting,
|
||||
// headerSetting,
|
||||
};
|
||||
|
||||
case HandlerEnum.MENU_HAS_DRAG:
|
||||
@ -81,10 +86,12 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
|
||||
},
|
||||
};
|
||||
case HandlerEnum.MENU_THEME:
|
||||
updateSidebarBgColor(value);
|
||||
return {
|
||||
menuSetting: {
|
||||
theme: value,
|
||||
},
|
||||
menuBgColor: value,
|
||||
// menuSetting: {
|
||||
// theme: value,
|
||||
// },
|
||||
};
|
||||
case HandlerEnum.MENU_SPLIT:
|
||||
return {
|
||||
@ -150,7 +157,7 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
|
||||
showQuick: value,
|
||||
},
|
||||
};
|
||||
case HandlerEnum.TABS_SHOW_QUICK:
|
||||
case HandlerEnum.TABS_SHOW_ICON:
|
||||
return {
|
||||
multiTabsSetting: {
|
||||
showIcon: value,
|
||||
@ -163,10 +170,9 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
|
||||
},
|
||||
};
|
||||
case HandlerEnum.HEADER_THEME:
|
||||
updateHeaderBgColor(value);
|
||||
return {
|
||||
headerSetting: {
|
||||
theme: value,
|
||||
},
|
||||
headerBgColor: value,
|
||||
};
|
||||
case HandlerEnum.HEADER_FIXED:
|
||||
return {
|
||||
|
@ -20,25 +20,26 @@
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 16px 0;
|
||||
justify-content: space-around;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
> span {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-top: 10px;
|
||||
margin-right: 10px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 2px;
|
||||
|
||||
svg {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.active {
|
||||
border: 1px solid lighten(@primary-color, 10%);
|
||||
|
||||
svg {
|
||||
display: inline-block;
|
||||
margin-left: 4px;
|
||||
font-size: 0.8em;
|
||||
margin: 0 0 3px 3px;
|
||||
font-size: 12px;
|
||||
fill: @white;
|
||||
}
|
||||
}
|
||||
|
@ -41,13 +41,12 @@ export default defineComponent({
|
||||
// No longer show animations that are already in the tab
|
||||
const name = route.meta.inTab ? 'fade' : null;
|
||||
|
||||
// TODO add key?
|
||||
const Content = openCache ? (
|
||||
<KeepAlive max={max} include={cacheTabs}>
|
||||
<Component key={route.path} />
|
||||
<Component key={route.fullPath} />
|
||||
</KeepAlive>
|
||||
) : (
|
||||
<Component key={route.path} />
|
||||
<Component key={route.fullPath} />
|
||||
);
|
||||
return openRouterTransition ? (
|
||||
<Transition
|
||||
|
@ -3,7 +3,7 @@ import type { App } from 'vue';
|
||||
|
||||
import { createRouter, createWebHashHistory } from 'vue-router';
|
||||
|
||||
import { scrollWaiter } from '../utils/scrollWaiter';
|
||||
import { scrollWaiter } from './scrollWaiter';
|
||||
|
||||
import { createGuard } from './guard/';
|
||||
|
||||
@ -13,6 +13,7 @@ import { basicRoutes } from './routes/';
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes: basicRoutes as RouteRecordRaw[],
|
||||
strict: true,
|
||||
scrollBehavior: async (to, from, savedPosition) => {
|
||||
await scrollWaiter.wait();
|
||||
if (savedPosition) {
|
||||
|
@ -1,3 +1,4 @@
|
||||
// see https://github.com/vuejs/vue-router-next/blob/master/playground/scrollWaiter.ts
|
||||
class ScrollQueue {
|
||||
private resolve: (() => void) | null = null;
|
||||
private promise: Promise<any> | null = null;
|
24
src/settings/colorSetting.ts
Normal file
24
src/settings/colorSetting.ts
Normal file
@ -0,0 +1,24 @@
|
||||
// header preset color
|
||||
export const HEADER_PRESET_BG_COLOR_LIST: string[] = [
|
||||
'#ffffff',
|
||||
'#009688',
|
||||
'#18bc9c',
|
||||
'#1E9FFF',
|
||||
'#018ffb',
|
||||
'#409eff',
|
||||
'#4e73df',
|
||||
'#e74c3c',
|
||||
'#f39c12',
|
||||
'#394664',
|
||||
'#001529',
|
||||
];
|
||||
|
||||
// sider preset color
|
||||
export const SIDE_BAR_BG_COLOR_LIST: string[] = [
|
||||
'#273352',
|
||||
'#ffffff',
|
||||
'#001529',
|
||||
'#304156',
|
||||
'#28333E',
|
||||
'#344058',
|
||||
];
|
@ -7,6 +7,16 @@ import { isProdMode } from '/@/utils/env';
|
||||
|
||||
// ! You need to clear the browser cache after the change
|
||||
const setting: ProjectConfig = {
|
||||
// color
|
||||
// TODO 主题色
|
||||
themeColor: primaryColor,
|
||||
|
||||
// header bg color
|
||||
headerBgColor: '#ffffff',
|
||||
|
||||
// sidebar menu bg color
|
||||
menuBgColor: '#273352',
|
||||
|
||||
// Whether to show the configuration button
|
||||
showSettingButton: true,
|
||||
// 权限模式
|
||||
@ -15,8 +25,7 @@ const setting: ProjectConfig = {
|
||||
grayMode: false,
|
||||
// 色弱模式
|
||||
colorWeak: false,
|
||||
// 主题色
|
||||
themeColor: primaryColor,
|
||||
|
||||
// 是否取消菜单,顶部,多标签页显示, 用于可能内嵌在别的系统内
|
||||
fullContent: false,
|
||||
// content mode
|
||||
|
@ -1,9 +1,24 @@
|
||||
import useCssVar from '/@/hooks/web/useCssVar';
|
||||
import { isHexColor, colorIsDark, lighten, darken } from '/@/utils/color';
|
||||
import { appStore } from '/@/store/modules/app';
|
||||
import { MenuThemeEnum } from '/@/enums/menuEnum';
|
||||
|
||||
const HEADER_BG_COLOR_VAR = '--header-bg-color';
|
||||
const HEADER_BG_HOVER_COLOR_VAR = '--header-bg-hover-color';
|
||||
const HEADER_MENU_ACTIVE_BG_COLOR_VAR = '--header-active-menu-bg-color';
|
||||
|
||||
const SIDER_DARK_BG_COLOR = '--sider-dark-bg-color';
|
||||
const SIDER_DARK_DARKEN_BG_COLOR = '--sider-dark-darken-bg-color';
|
||||
const SIDER_LIGHTEN_1_BG_COLOR = '--sider-dark-lighten-1-bg-color';
|
||||
const SIDER_LIGHTEN_2_BG_COLOR = '--sider-dark-lighten-2-bg-color';
|
||||
|
||||
function toggleClass(flag: boolean, clsName: string) {
|
||||
const body = document.body;
|
||||
let { className } = body;
|
||||
className = className.replace(clsName, '');
|
||||
document.body.className = flag ? `${className} ${clsName} ` : className;
|
||||
}
|
||||
|
||||
export const updateColorWeak = (colorWeak: boolean) => {
|
||||
toggleClass(colorWeak, 'color-weak');
|
||||
};
|
||||
@ -11,3 +26,46 @@ export const updateColorWeak = (colorWeak: boolean) => {
|
||||
export const updateGrayMode = (gray: boolean) => {
|
||||
toggleClass(gray, 'gray-mode');
|
||||
};
|
||||
|
||||
export function updateHeaderBgColor(color: string) {
|
||||
if (!isHexColor(color)) return;
|
||||
const bgColorRef = useCssVar(HEADER_BG_COLOR_VAR);
|
||||
const bgHoverColorRef = useCssVar(HEADER_BG_HOVER_COLOR_VAR);
|
||||
const topMenuActiveBgColorRef = useCssVar(HEADER_MENU_ACTIVE_BG_COLOR_VAR);
|
||||
// bg color
|
||||
bgColorRef.value = color;
|
||||
// hover color
|
||||
const hoverColor = lighten(color, 6);
|
||||
bgHoverColorRef.value = hoverColor;
|
||||
topMenuActiveBgColorRef.value = hoverColor;
|
||||
|
||||
const isDark = colorIsDark(color);
|
||||
|
||||
appStore.commitProjectConfigState({
|
||||
headerSetting: {
|
||||
theme: isDark ? MenuThemeEnum.DARK : MenuThemeEnum.LIGHT,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function updateSidebarBgColor(color: string) {
|
||||
if (!isHexColor(color)) return;
|
||||
|
||||
const siderBgColor = useCssVar(SIDER_DARK_BG_COLOR);
|
||||
const darkenBgColor = useCssVar(SIDER_DARK_DARKEN_BG_COLOR);
|
||||
const lighten1Color = useCssVar(SIDER_LIGHTEN_1_BG_COLOR);
|
||||
const lighten2Color = useCssVar(SIDER_LIGHTEN_2_BG_COLOR);
|
||||
|
||||
siderBgColor.value = color;
|
||||
darkenBgColor.value = darken(color, 6);
|
||||
lighten1Color.value = lighten(color, 4);
|
||||
lighten2Color.value = lighten(color, 8);
|
||||
// only #ffffff is light
|
||||
const isLight = ['#fff', '#ffffff'].includes(color.toLowerCase());
|
||||
|
||||
appStore.commitProjectConfigState({
|
||||
menuSetting: {
|
||||
theme: isLight ? MenuThemeEnum.LIGHT : MenuThemeEnum.DARK,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
4
src/types/config.d.ts
vendored
4
src/types/config.d.ts
vendored
@ -55,6 +55,10 @@ export interface HeaderSetting {
|
||||
showNotice: boolean;
|
||||
}
|
||||
export interface ProjectConfig {
|
||||
// header背景色
|
||||
headerBgColor: string;
|
||||
// 左侧菜单背景色
|
||||
menuBgColor: string;
|
||||
// 是否显示配置按钮
|
||||
showSettingButton: boolean;
|
||||
// 权限模式
|
||||
|
@ -9,7 +9,12 @@ import { PROJ_CFG_KEY } from '/@/enums/cacheEnum';
|
||||
import projectSetting from '/@/settings/projectSetting';
|
||||
import { getLocal } from '/@/utils/helper/persistent';
|
||||
import { isUnDef, isNull } from '/@/utils/is';
|
||||
import { updateGrayMode, updateColorWeak } from '/@/setup/theme';
|
||||
import {
|
||||
updateGrayMode,
|
||||
updateColorWeak,
|
||||
updateHeaderBgColor,
|
||||
updateSidebarBgColor,
|
||||
} from '/@/setup/theme';
|
||||
|
||||
import { appStore } from '/@/store/modules/app';
|
||||
import { useNetWork } from '/@/hooks/web/useNetWork';
|
||||
@ -48,7 +53,7 @@ export function useInitAppConfigStore() {
|
||||
if (!projCfg) {
|
||||
projCfg = projectSetting;
|
||||
}
|
||||
const { colorWeak, grayMode } = projCfg;
|
||||
const { colorWeak, grayMode, headerBgColor, menuBgColor } = projCfg;
|
||||
try {
|
||||
// if (
|
||||
// themeColor !== primaryColor &&
|
||||
@ -57,6 +62,8 @@ export function useInitAppConfigStore() {
|
||||
// ) {
|
||||
// updateTheme(themeColor);
|
||||
// }
|
||||
headerBgColor && updateHeaderBgColor(headerBgColor);
|
||||
menuBgColor && updateSidebarBgColor(menuBgColor);
|
||||
grayMode && updateGrayMode(grayMode);
|
||||
colorWeak && updateColorWeak(colorWeak);
|
||||
} catch (error) {
|
||||
|
@ -31,13 +31,31 @@ export const rgbToHex = function (r: number, g: number, b: number) {
|
||||
* @returns The RGB representation of the passed color
|
||||
*/
|
||||
export const hexToRGB = function (hex: string) {
|
||||
return (
|
||||
parseInt(hex.substring(0, 2), 16) +
|
||||
',' +
|
||||
parseInt(hex.substring(2, 4), 16) +
|
||||
',' +
|
||||
parseInt(hex.substring(4, 6), 16)
|
||||
);
|
||||
let sHex = hex.toLowerCase();
|
||||
if (isHexColor(hex)) {
|
||||
if (sHex.length === 4) {
|
||||
let sColorNew = '#';
|
||||
for (let i = 1; i < 4; i += 1) {
|
||||
sColorNew += sHex.slice(i, i + 1).concat(sHex.slice(i, i + 1));
|
||||
}
|
||||
sHex = sColorNew;
|
||||
}
|
||||
const sColorChange = [];
|
||||
for (let i = 1; i < 7; i += 2) {
|
||||
sColorChange.push(parseInt('0x' + sHex.slice(i, i + 2)));
|
||||
}
|
||||
return 'RGB(' + sColorChange.join(',') + ')';
|
||||
}
|
||||
return sHex;
|
||||
};
|
||||
|
||||
export const colorIsDark = (color: string) => {
|
||||
if (!isHexColor(color)) return;
|
||||
const [r, g, b] = hexToRGB(color)
|
||||
.replace(/(?:\(|\)|rgb|RGB)*/g, '')
|
||||
.split(',')
|
||||
.map((item) => Number(item));
|
||||
return r * 0.299 + g * 0.578 + b * 0.114 < 192;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -89,7 +107,7 @@ const addLight = (color: string, amount: number) => {
|
||||
* @param {number} g green
|
||||
* @param {number} b blue
|
||||
*/
|
||||
const luminanace = (r: stri, g: number, b: number) => {
|
||||
const luminanace = (r: number, g: number, b: number) => {
|
||||
const a = [r, g, b].map((v) => {
|
||||
v /= 255;
|
||||
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
||||
@ -103,7 +121,7 @@ const luminanace = (r: stri, g: number, b: number) => {
|
||||
* @param {string} rgb2 rgb color 2
|
||||
*/
|
||||
const contrast = (rgb1: string[], rgb2: number[]) =>
|
||||
(luminanace(rgb1[0], ~~rgb1[1], ~~rgb1[2]) + 0.05) /
|
||||
(luminanace(~~rgb1[0], ~~rgb1[1], ~~rgb1[2]) + 0.05) /
|
||||
(luminanace(rgb2[0], rgb2[1], rgb2[2]) + 0.05);
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user