Commit ee1c3498587951a6a4cc0b49edb9dacf3f2af5c3
1 parent
780a8a67
fix(menu): improve menu logic, fix #461
Showing
13 changed files
with
66 additions
and
33 deletions
CHANGELOG.zh_CN.md
src/components/Application/src/AppDarkModeToggle.vue
@@ -3,7 +3,6 @@ | @@ -3,7 +3,6 @@ | ||
3 | v-if="getShowDarkModeToggle" | 3 | v-if="getShowDarkModeToggle" |
4 | :class="[ | 4 | :class="[ |
5 | prefixCls, | 5 | prefixCls, |
6 | - `${prefixCls}--${size}`, | ||
7 | { | 6 | { |
8 | [`${prefixCls}--dark`]: isDark, | 7 | [`${prefixCls}--dark`]: isDark, |
9 | }, | 8 | }, |
@@ -30,13 +29,13 @@ | @@ -30,13 +29,13 @@ | ||
30 | export default defineComponent({ | 29 | export default defineComponent({ |
31 | name: 'DarkModeToggle', | 30 | name: 'DarkModeToggle', |
32 | components: { SvgIcon }, | 31 | components: { SvgIcon }, |
33 | - props: { | ||
34 | - size: { | ||
35 | - type: String, | ||
36 | - default: 'default', | ||
37 | - validate: (val) => ['default', 'large'].includes(val), | ||
38 | - }, | ||
39 | - }, | 32 | + // props: { |
33 | + // size: { | ||
34 | + // type: String, | ||
35 | + // default: 'default', | ||
36 | + // validate: (val) => ['default', 'large'].includes(val), | ||
37 | + // }, | ||
38 | + // }, | ||
40 | setup() { | 39 | setup() { |
41 | const { prefixCls } = useDesign('dark-mode-toggle'); | 40 | const { prefixCls } = useDesign('dark-mode-toggle'); |
42 | const { getDarkMode, setDarkMode, getShowDarkModeToggle } = useRootSetting(); | 41 | const { getDarkMode, setDarkMode, getShowDarkModeToggle } = useRootSetting(); |
@@ -97,15 +96,15 @@ | @@ -97,15 +96,15 @@ | ||
97 | } | 96 | } |
98 | } | 97 | } |
99 | 98 | ||
100 | - &--large { | ||
101 | - width: 72px; | ||
102 | - height: 34px; | ||
103 | - padding: 0 10px; | 99 | + // &--large { |
100 | + // width: 70px; | ||
101 | + // height: 34px; | ||
102 | + // padding: 0 10px; | ||
104 | 103 | ||
105 | - .@{prefix-cls}-inner { | ||
106 | - width: 26px; | ||
107 | - height: 26px; | ||
108 | - } | ||
109 | - } | 104 | + // .@{prefix-cls}-inner { |
105 | + // width: 26px; | ||
106 | + // height: 26px; | ||
107 | + // } | ||
108 | + // } | ||
110 | } | 109 | } |
111 | </style> | 110 | </style> |
src/components/Icon/src/index.vue
@@ -24,8 +24,6 @@ | @@ -24,8 +24,6 @@ | ||
24 | import Iconify from '@purge-icons/generated'; | 24 | import Iconify from '@purge-icons/generated'; |
25 | import { isString } from '/@/utils/is'; | 25 | import { isString } from '/@/utils/is'; |
26 | import { propTypes } from '/@/utils/propTypes'; | 26 | import { propTypes } from '/@/utils/propTypes'; |
27 | - import { useRootSetting } from '/@/hooks/setting/useRootSetting'; | ||
28 | - import { ThemeEnum } from '/@/enums/appEnum'; | ||
29 | 27 | ||
30 | const SVG_END_WITH_FLAG = '|svg'; | 28 | const SVG_END_WITH_FLAG = '|svg'; |
31 | export default defineComponent({ | 29 | export default defineComponent({ |
@@ -46,8 +44,6 @@ | @@ -46,8 +44,6 @@ | ||
46 | setup(props) { | 44 | setup(props) { |
47 | const elRef = ref<ElRef>(null); | 45 | const elRef = ref<ElRef>(null); |
48 | 46 | ||
49 | - const { getDarkMode } = useRootSetting(); | ||
50 | - | ||
51 | const isSvgIcon = computed(() => props.icon?.endsWith(SVG_END_WITH_FLAG)); | 47 | const isSvgIcon = computed(() => props.icon?.endsWith(SVG_END_WITH_FLAG)); |
52 | const getSvgIcon = computed(() => props.icon.replace(SVG_END_WITH_FLAG, '')); | 48 | const getSvgIcon = computed(() => props.icon.replace(SVG_END_WITH_FLAG, '')); |
53 | const getIconRef = computed(() => `${props.prefix ? props.prefix + ':' : ''}${props.icon}`); | 49 | const getIconRef = computed(() => `${props.prefix ? props.prefix + ':' : ''}${props.icon}`); |
@@ -85,7 +81,7 @@ | @@ -85,7 +81,7 @@ | ||
85 | 81 | ||
86 | return { | 82 | return { |
87 | fontSize: `${fs}px`, | 83 | fontSize: `${fs}px`, |
88 | - color: color || (unref(getDarkMode) === ThemeEnum.DARK ? '#fff' : '#303133'), | 84 | + color: color, |
89 | display: 'inline-flex', | 85 | display: 'inline-flex', |
90 | }; | 86 | }; |
91 | } | 87 | } |
src/components/SimpleMenu/src/SimpleMenu.vue
1 | <template> | 1 | <template> |
2 | <Menu | 2 | <Menu |
3 | v-bind="getBindValues" | 3 | v-bind="getBindValues" |
4 | - @select="handleSelect" | ||
5 | :activeName="activeName" | 4 | :activeName="activeName" |
6 | :openNames="getOpenKeys" | 5 | :openNames="getOpenKeys" |
7 | :class="prefixCls" | 6 | :class="prefixCls" |
8 | :activeSubMenuNames="activeSubMenuNames" | 7 | :activeSubMenuNames="activeSubMenuNames" |
8 | + @select="handleSelect" | ||
9 | + @open-change="handleOpenChange" | ||
9 | > | 10 | > |
10 | <template v-for="item in items" :key="item.path"> | 11 | <template v-for="item in items" :key="item.path"> |
11 | <SimpleSubMenu | 12 | <SimpleSubMenu |
@@ -53,6 +54,7 @@ | @@ -53,6 +54,7 @@ | ||
53 | beforeClickFn: { | 54 | beforeClickFn: { |
54 | type: Function as PropType<(key: string) => Promise<boolean>>, | 55 | type: Function as PropType<(key: string) => Promise<boolean>>, |
55 | }, | 56 | }, |
57 | + isSplitMenu: propTypes.bool, | ||
56 | }, | 58 | }, |
57 | emits: ['menuClick'], | 59 | emits: ['menuClick'], |
58 | setup(props, { attrs, emit }) { | 60 | setup(props, { attrs, emit }) { |
@@ -94,6 +96,9 @@ | @@ -94,6 +96,9 @@ | ||
94 | watch( | 96 | watch( |
95 | () => props.items, | 97 | () => props.items, |
96 | () => { | 98 | () => { |
99 | + if (!props.isSplitMenu) { | ||
100 | + return; | ||
101 | + } | ||
97 | setOpenKeys(currentRoute.value.path); | 102 | setOpenKeys(currentRoute.value.path); |
98 | }, | 103 | }, |
99 | { flush: 'post' } | 104 | { flush: 'post' } |
@@ -135,11 +140,17 @@ | @@ -135,11 +140,17 @@ | ||
135 | menuState.activeName = key; | 140 | menuState.activeName = key; |
136 | } | 141 | } |
137 | 142 | ||
143 | + function handleOpenChange(v) { | ||
144 | + console.log('======================'); | ||
145 | + console.log(v); | ||
146 | + console.log('======================'); | ||
147 | + } | ||
138 | return { | 148 | return { |
139 | prefixCls, | 149 | prefixCls, |
140 | getBindValues, | 150 | getBindValues, |
141 | handleSelect, | 151 | handleSelect, |
142 | getOpenKeys, | 152 | getOpenKeys, |
153 | + handleOpenChange, | ||
143 | ...toRefs(menuState), | 154 | ...toRefs(menuState), |
144 | }; | 155 | }; |
145 | }, | 156 | }, |
src/components/SimpleMenu/src/components/Menu.vue
@@ -138,6 +138,15 @@ | @@ -138,6 +138,15 @@ | ||
138 | }); | 138 | }); |
139 | emit('select', name); | 139 | emit('select', name); |
140 | }); | 140 | }); |
141 | + | ||
142 | + rootMenuEmitter.on('open-name-change', ({ name, opened }) => { | ||
143 | + if (opened && !openedNames.value.includes(name)) { | ||
144 | + openedNames.value.push(name); | ||
145 | + } else if (!opened) { | ||
146 | + const index = openedNames.value.findIndex((item) => item === name); | ||
147 | + index !== -1 && openedNames.value.splice(index, 1); | ||
148 | + } | ||
149 | + }); | ||
141 | }); | 150 | }); |
142 | 151 | ||
143 | return { getClass, openedNames }; | 152 | return { getClass, openedNames }; |
src/components/SimpleMenu/src/components/MenuItem.vue
@@ -66,11 +66,16 @@ | @@ -66,11 +66,16 @@ | ||
66 | 66 | ||
67 | function handleClickItem() { | 67 | function handleClickItem() { |
68 | const { disabled } = props; | 68 | const { disabled } = props; |
69 | - if (disabled) return; | 69 | + if (disabled) { |
70 | + return; | ||
71 | + } | ||
70 | 72 | ||
71 | rootMenuEmitter.emit('on-menu-item-select', props.name); | 73 | rootMenuEmitter.emit('on-menu-item-select', props.name); |
72 | - if (unref(getCollapse)) return; | 74 | + if (unref(getCollapse)) { |
75 | + return; | ||
76 | + } | ||
73 | const { uidList } = getParentList(); | 77 | const { uidList } = getParentList(); |
78 | + | ||
74 | rootMenuEmitter.emit('on-update-opened', { | 79 | rootMenuEmitter.emit('on-update-opened', { |
75 | opend: false, | 80 | opend: false, |
76 | parent: instance?.parent, | 81 | parent: instance?.parent, |
src/components/SimpleMenu/src/components/SubMenuItem.vue
@@ -43,8 +43,9 @@ | @@ -43,8 +43,9 @@ | ||
43 | :class="`${prefixCls}-submenu-title-icon`" | 43 | :class="`${prefixCls}-submenu-title-icon`" |
44 | /> | 44 | /> |
45 | </div> | 45 | </div> |
46 | - <template #content> | ||
47 | - <div v-bind="getEvents(true)" v-show="opened"> | 46 | + <!-- eslint-disable-next-line --> |
47 | + <template #content v-show="opened"> | ||
48 | + <div v-bind="getEvents(true)"> | ||
48 | <ul :class="[prefixCls, `${prefixCls}-${getTheme}`, `${prefixCls}-popup`]"> | 49 | <ul :class="[prefixCls, `${prefixCls}-${getTheme}`, `${prefixCls}-popup`]"> |
49 | <slot></slot> | 50 | <slot></slot> |
50 | </ul> | 51 | </ul> |
@@ -78,7 +79,7 @@ | @@ -78,7 +79,7 @@ | ||
78 | import { isBoolean, isObject } from '/@/utils/is'; | 79 | import { isBoolean, isObject } from '/@/utils/is'; |
79 | import Mitt from '/@/utils/mitt'; | 80 | import Mitt from '/@/utils/mitt'; |
80 | 81 | ||
81 | - const DELAY = 250; | 82 | + const DELAY = 200; |
82 | export default defineComponent({ | 83 | export default defineComponent({ |
83 | name: 'SubMenu', | 84 | name: 'SubMenu', |
84 | components: { | 85 | components: { |
@@ -189,6 +190,7 @@ | @@ -189,6 +190,7 @@ | ||
189 | const { disabled } = props; | 190 | const { disabled } = props; |
190 | if (disabled || unref(getCollapse)) return; | 191 | if (disabled || unref(getCollapse)) return; |
191 | const opened = state.opened; | 192 | const opened = state.opened; |
193 | + | ||
192 | if (unref(getAccordion)) { | 194 | if (unref(getAccordion)) { |
193 | const { uidList } = getParentList(); | 195 | const { uidList } = getParentList(); |
194 | rootMenuEmitter.emit('on-update-opened', { | 196 | rootMenuEmitter.emit('on-update-opened', { |
@@ -196,6 +198,11 @@ | @@ -196,6 +198,11 @@ | ||
196 | parent: instance?.parent, | 198 | parent: instance?.parent, |
197 | uidList: uidList, | 199 | uidList: uidList, |
198 | }); | 200 | }); |
201 | + } else { | ||
202 | + rootMenuEmitter.emit('open-name-change', { | ||
203 | + name: props.name, | ||
204 | + opened: !opened, | ||
205 | + }); | ||
199 | } | 206 | } |
200 | state.opened = !opened; | 207 | state.opened = !opened; |
201 | } | 208 | } |
src/components/SimpleMenu/src/useOpenKeys.ts
@@ -8,7 +8,7 @@ import { uniq } from 'lodash-es'; | @@ -8,7 +8,7 @@ import { uniq } from 'lodash-es'; | ||
8 | import { getAllParentPath } from '/@/router/helper/menuHelper'; | 8 | import { getAllParentPath } from '/@/router/helper/menuHelper'; |
9 | 9 | ||
10 | import { useTimeoutFn } from '/@/hooks/core/useTimeout'; | 10 | import { useTimeoutFn } from '/@/hooks/core/useTimeout'; |
11 | -import { useDebounce } from '../../../hooks/core/useDebounce'; | 11 | +import { useDebounce } from '/@/hooks/core/useDebounce'; |
12 | 12 | ||
13 | export function useOpenKeys( | 13 | export function useOpenKeys( |
14 | menuState: MenuState, | 14 | menuState: MenuState, |
src/layouts/default/menu/index.vue
@@ -49,6 +49,7 @@ | @@ -49,6 +49,7 @@ | ||
49 | getAccordion, | 49 | getAccordion, |
50 | getIsHorizontal, | 50 | getIsHorizontal, |
51 | getIsSidebarType, | 51 | getIsSidebarType, |
52 | + getSplit, | ||
52 | } = useMenuSetting(); | 53 | } = useMenuSetting(); |
53 | const { getShowLogo } = useRootSetting(); | 54 | const { getShowLogo } = useRootSetting(); |
54 | 55 | ||
@@ -144,7 +145,7 @@ | @@ -144,7 +145,7 @@ | ||
144 | // console.log(menus); | 145 | // console.log(menus); |
145 | if (!menus || !menus.length) return null; | 146 | if (!menus || !menus.length) return null; |
146 | return !props.isHorizontal ? ( | 147 | return !props.isHorizontal ? ( |
147 | - <SimpleMenu {...menuProps} items={menus} /> | 148 | + <SimpleMenu {...menuProps} isSplitMenu={unref(getSplit)} items={menus} /> |
148 | ) : ( | 149 | ) : ( |
149 | <BasicMenu | 150 | <BasicMenu |
150 | {...menuProps} | 151 | {...menuProps} |
src/layouts/default/setting/SettingDrawer.tsx
@@ -408,7 +408,7 @@ export default defineComponent({ | @@ -408,7 +408,7 @@ export default defineComponent({ | ||
408 | wrapClassName="setting-drawer" | 408 | wrapClassName="setting-drawer" |
409 | > | 409 | > |
410 | {unref(getShowDarkModeToggle) && <Divider>{() => t('layout.setting.darkMode')}</Divider>} | 410 | {unref(getShowDarkModeToggle) && <Divider>{() => t('layout.setting.darkMode')}</Divider>} |
411 | - {unref(getShowDarkModeToggle) && <AppDarkModeToggle class="mx-auto" size="large" />} | 411 | + {unref(getShowDarkModeToggle) && <AppDarkModeToggle class="mx-auto" />} |
412 | <Divider>{() => t('layout.setting.navMode')}</Divider> | 412 | <Divider>{() => t('layout.setting.navMode')}</Divider> |
413 | {renderSidebar()} | 413 | {renderSidebar()} |
414 | <Divider>{() => t('layout.setting.sysTheme')}</Divider> | 414 | <Divider>{() => t('layout.setting.sysTheme')}</Divider> |
src/layouts/default/tabs/index.less
@@ -82,7 +82,7 @@ html[data-theme='dark'] { | @@ -82,7 +82,7 @@ html[data-theme='dark'] { | ||
82 | .ant-tabs-tab-active { | 82 | .ant-tabs-tab-active { |
83 | position: relative; | 83 | position: relative; |
84 | padding-left: 18px; | 84 | padding-left: 18px; |
85 | - color: @white; | 85 | + color: @white !important; |
86 | background: @primary-color; | 86 | background: @primary-color; |
87 | border: 0; | 87 | border: 0; |
88 | transition: none; | 88 | transition: none; |
src/router/routes/modules/demo/charts.ts
@@ -7,7 +7,7 @@ const charts: AppRouteModule = { | @@ -7,7 +7,7 @@ const charts: AppRouteModule = { | ||
7 | path: '/charts', | 7 | path: '/charts', |
8 | name: 'Charts', | 8 | name: 'Charts', |
9 | component: LAYOUT, | 9 | component: LAYOUT, |
10 | - redirect: '/charts/apexChart', | 10 | + redirect: '/charts/echarts/map', |
11 | meta: { | 11 | meta: { |
12 | icon: 'ion:bar-chart-outline', | 12 | icon: 'ion:bar-chart-outline', |
13 | title: t('routes.demo.charts.charts'), | 13 | title: t('routes.demo.charts.charts'), |