feat(Layout): Add cutMenu layout
This commit is contained in:
parent
1522e925ba
commit
ff4dd3afbf
|
@ -34,7 +34,7 @@ initDark()
|
|||
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
padding: 0 !important;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
.size;
|
||||
|
|
|
@ -6,7 +6,7 @@ const appStore = useAppStore()
|
|||
|
||||
const show = ref(true)
|
||||
|
||||
const title = computed(() => appStore.getLogoTitle)
|
||||
const title = computed(() => appStore.getTitle)
|
||||
|
||||
const layout = computed(() => appStore.getLayout)
|
||||
|
||||
|
@ -19,15 +19,30 @@ onMounted(() => {
|
|||
watch(
|
||||
() => collapse.value,
|
||||
(collapse: boolean) => {
|
||||
if (layout.value !== 'classic') {
|
||||
if (unref(layout) === 'topLeft' || unref(layout) === 'cutMenu') {
|
||||
show.value = true
|
||||
return
|
||||
}
|
||||
if (!collapse) {
|
||||
setTimeout(() => {
|
||||
show.value = !collapse
|
||||
}, 400)
|
||||
} else {
|
||||
show.value = !collapse
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => layout.value,
|
||||
(layout) => {
|
||||
if (layout === 'top' || layout === 'cutMenu') {
|
||||
show.value = true
|
||||
} else {
|
||||
if (!collapse) {
|
||||
setTimeout(() => {
|
||||
show.value = !collapse
|
||||
}, 400)
|
||||
if (unref(collapse)) {
|
||||
show.value = false
|
||||
} else {
|
||||
show.value = !collapse
|
||||
show.value = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +70,8 @@ watch(
|
|||
'ml-10px text-16px font-700',
|
||||
{
|
||||
'text-[var(--logo-title-text-color)]': layout === 'classic',
|
||||
'text-[var(--top-header-text-color)]': layout === 'topLeft'
|
||||
'text-[var(--top-header-text-color)]':
|
||||
layout === 'topLeft' || layout === 'top' || layout === 'cutMenu'
|
||||
}
|
||||
]"
|
||||
>
|
||||
|
@ -66,15 +82,4 @@ watch(
|
|||
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-logo';
|
||||
|
||||
.@{prefix-cls} {
|
||||
&:after {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid var(--logo-border-color);
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="tsx">
|
||||
import { computed, defineComponent, unref } from 'vue'
|
||||
import { computed, defineComponent, unref, PropType } from 'vue'
|
||||
import { ElMenu, ElScrollbar } from 'element-plus'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { usePermissionStore } from '@/store/modules/permission'
|
||||
|
@ -10,25 +10,35 @@ import { isUrl } from '@/utils/is'
|
|||
|
||||
export default defineComponent({
|
||||
name: 'Menu',
|
||||
setup() {
|
||||
props: {
|
||||
menuSelect: {
|
||||
type: Function as PropType<(index: string) => void>,
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const appStore = useAppStore()
|
||||
|
||||
const layout = computed(() => appStore.getLayout)
|
||||
|
||||
const { push, currentRoute } = useRouter()
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
|
||||
const menuMode = computed((): 'vertical' | 'horizontal' => {
|
||||
// 竖
|
||||
const vertical: LayoutType[] = ['classic', 'topLeft']
|
||||
const vertical: LayoutType[] = ['classic', 'topLeft', 'cutMenu']
|
||||
|
||||
if (vertical.includes(appStore.getLayout)) {
|
||||
if (vertical.includes(unref(layout))) {
|
||||
return 'vertical'
|
||||
} else {
|
||||
return 'horizontal'
|
||||
}
|
||||
})
|
||||
|
||||
const routers = computed(() => permissionStore.getRouters)
|
||||
const routers = computed(() =>
|
||||
unref(layout) === 'cutMenu' ? permissionStore.getMenuTabRouters : permissionStore.getRouters
|
||||
)
|
||||
|
||||
const collapse = computed(() => appStore.getCollapse)
|
||||
|
||||
|
@ -42,6 +52,10 @@ export default defineComponent({
|
|||
})
|
||||
|
||||
const menuSelect = (index: string) => {
|
||||
if (props.menuSelect) {
|
||||
props.menuSelect(index)
|
||||
}
|
||||
// 自定义事件
|
||||
if (isUrl(index)) {
|
||||
window.open(index)
|
||||
} else {
|
||||
|
@ -52,19 +66,21 @@ export default defineComponent({
|
|||
return () => (
|
||||
<div
|
||||
class={[
|
||||
'v-menu',
|
||||
'h-[100%] overflow-hidden z-100 flex-col',
|
||||
appStore.getCollapse
|
||||
? 'w-[var(--left-menu-min-width)]'
|
||||
: 'w-[var(--left-menu-max-width)]',
|
||||
'bg-[var(--left-menu-bg-color)]'
|
||||
`v-menu v-menu__${unref(menuMode)}`,
|
||||
'h-[100%] overflow-hidden z-100 flex-col bg-[var(--left-menu-bg-color)]',
|
||||
{
|
||||
'w-[var(--left-menu-min-width)]': unref(collapse) && unref(layout) !== 'cutMenu',
|
||||
'w-[var(--left-menu-max-width)]': !unref(collapse) && unref(layout) !== 'cutMenu'
|
||||
}
|
||||
]}
|
||||
>
|
||||
<ElScrollbar>
|
||||
<ElMenu
|
||||
defaultActive={unref(activeMenu)}
|
||||
mode={unref(menuMode)}
|
||||
collapse={unref(collapse)}
|
||||
collapse={
|
||||
unref(layout) === 'top' || unref(layout) === 'cutMenu' ? false : unref(collapse)
|
||||
}
|
||||
backgroundColor="var(--left-menu-bg-color)"
|
||||
textColor="var(--left-menu-text-color)"
|
||||
activeTextColor="var(--left-menu-text-active-color)"
|
||||
|
@ -180,6 +196,35 @@ export default defineComponent({
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// 水平菜单
|
||||
&__horizontal {
|
||||
height: calc(~'var( - -top-tool-height)') !important;
|
||||
|
||||
:deep(.el-menu--horizontal) {
|
||||
height: calc(~'var( - -top-tool-height)');
|
||||
border-bottom: none;
|
||||
// 重新设置底部高亮颜色
|
||||
& > .el-sub-menu.is-active {
|
||||
.el-sub-menu__title {
|
||||
border-bottom-color: var(--el-color-primary) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-menu-item.is-active {
|
||||
position: relative;
|
||||
|
||||
&:after {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.v-menu__title {
|
||||
max-height: calc(~'var( - -top-tool-height)') !important;
|
||||
line-height: calc(~'var( - -top-tool-height)');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
@ -196,36 +241,35 @@ export default defineComponent({
|
|||
content: '';
|
||||
}
|
||||
|
||||
.@{prefix-cls} {
|
||||
&--vertical {
|
||||
// 设置选中时子标题的颜色
|
||||
.is-active {
|
||||
& > .el-sub-menu__title {
|
||||
color: var(--left-menu-text-active-color) !important;
|
||||
}
|
||||
.@{prefix-cls}--vertical,
|
||||
.@{prefix-cls}--horizontal {
|
||||
// 设置选中时子标题的颜色
|
||||
.is-active {
|
||||
& > .el-sub-menu__title {
|
||||
color: var(--left-menu-text-active-color) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 设置子菜单悬停的高亮和背景色
|
||||
.el-sub-menu__title,
|
||||
.el-menu-item {
|
||||
&:hover {
|
||||
color: var(--left-menu-text-active-color) !important;
|
||||
background-color: var(--left-menu-bg-color) !important;
|
||||
}
|
||||
// 设置子菜单悬停的高亮和背景色
|
||||
.el-sub-menu__title,
|
||||
.el-menu-item {
|
||||
&:hover {
|
||||
color: var(--left-menu-text-active-color) !important;
|
||||
background-color: var(--left-menu-bg-color) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 设置选中时的高亮背景
|
||||
.el-menu-item.is-active {
|
||||
position: relative;
|
||||
// 设置选中时的高亮背景
|
||||
.el-menu-item.is-active {
|
||||
position: relative;
|
||||
background-color: var(--left-menu-bg-active-color) !important;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--left-menu-bg-active-color) !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--left-menu-bg-active-color) !important;
|
||||
}
|
||||
|
||||
&:after {
|
||||
.is-active--after;
|
||||
}
|
||||
&:after {
|
||||
.is-active--after;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { ElDrawer, ElDivider } from 'element-plus'
|
||||
import { ref, unref } from 'vue'
|
||||
import { ref, unref, computed, watch } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { ThemeSwitch } from '@/components/ThemeSwitch'
|
||||
import { colorIsDark, lighten, hexToRGB } from '@/utils/color'
|
||||
|
@ -15,6 +15,8 @@ const appStore = useAppStore()
|
|||
|
||||
const { t } = useI18n()
|
||||
|
||||
const layout = computed(() => appStore.getLayout)
|
||||
|
||||
const drawer = ref(false)
|
||||
|
||||
// 主题色相关
|
||||
|
@ -34,14 +36,20 @@ const setHeaderTheme = (color: string) => {
|
|||
const isDarkColor = colorIsDark(color)
|
||||
const textColor = isDarkColor ? '#fff' : 'inherit'
|
||||
const textHoverColor = isDarkColor ? lighten(color!, 6) : '#f6f6f6'
|
||||
const topToolBorderColor = isDarkColor ? color : '#eee'
|
||||
setCssVar('--top-header-bg-color', color)
|
||||
setCssVar('--top-header-text-color', textColor)
|
||||
setCssVar('--top-header-hover-color', textHoverColor)
|
||||
setCssVar('--top-tool-border-color', topToolBorderColor)
|
||||
appStore.setTheme({
|
||||
topHeaderBgColor: color,
|
||||
topHeaderTextColor: textColor,
|
||||
topHeaderHoverColor: textHoverColor
|
||||
topHeaderHoverColor: textHoverColor,
|
||||
topToolBorderColor
|
||||
})
|
||||
if (unref(layout) === 'top') {
|
||||
setMenuTheme(color)
|
||||
}
|
||||
}
|
||||
|
||||
// 菜单主题相关
|
||||
|
@ -72,11 +80,26 @@ const setMenuTheme = (color: string) => {
|
|||
// logo字体颜色
|
||||
logoTitleTextColor: isDarkColor ? '#fff' : 'inherit',
|
||||
// logo边框颜色
|
||||
logoBorderColor: isDarkColor ? 'inherit' : '#eee'
|
||||
logoBorderColor: isDarkColor ? color : '#eee'
|
||||
}
|
||||
appStore.setTheme(theme)
|
||||
appStore.setCssVarTheme()
|
||||
}
|
||||
|
||||
// 监听layout变化,重置一些主题色
|
||||
watch(
|
||||
() => layout.value,
|
||||
(n, o) => {
|
||||
if (o === 'top') {
|
||||
menuTheme.value = '#fff'
|
||||
setMenuTheme('#fff')
|
||||
}
|
||||
if ((o === 'classic' || o === 'topLeft') && n === 'top') {
|
||||
menuTheme.value = headerTheme.value
|
||||
setMenuTheme(unref(menuTheme))
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -136,21 +159,23 @@ const setMenuTheme = (color: string) => {
|
|||
/>
|
||||
|
||||
<!-- 菜单主题 -->
|
||||
<ElDivider>{{ t('setting.menuTheme') }}</ElDivider>
|
||||
<ColorRadioPicker
|
||||
v-model="menuTheme"
|
||||
:schema="[
|
||||
'#fff',
|
||||
'#001529',
|
||||
'#212121',
|
||||
'#273352',
|
||||
'#191b24',
|
||||
'#383f45',
|
||||
'#001628',
|
||||
'#344058'
|
||||
]"
|
||||
@change="setMenuTheme"
|
||||
/>
|
||||
<template v-if="layout !== 'top'">
|
||||
<ElDivider>{{ t('setting.menuTheme') }}</ElDivider>
|
||||
<ColorRadioPicker
|
||||
v-model="menuTheme"
|
||||
:schema="[
|
||||
'#fff',
|
||||
'#001529',
|
||||
'#212121',
|
||||
'#273352',
|
||||
'#191b24',
|
||||
'#383f45',
|
||||
'#001628',
|
||||
'#344058'
|
||||
]"
|
||||
@change="setMenuTheme"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 界面显示 -->
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import { ElSwitch } from 'element-plus'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { ref } from 'vue'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
|
@ -22,13 +22,6 @@ const breadcrumbIconChange = (show: boolean) => {
|
|||
appStore.setBreadcrumbIcon(show)
|
||||
}
|
||||
|
||||
// 折叠菜单
|
||||
const collapse = ref(appStore.getCollapse)
|
||||
|
||||
const collapseChange = (show: boolean) => {
|
||||
appStore.setCollapse(show)
|
||||
}
|
||||
|
||||
// 折叠图标
|
||||
const hamburger = ref(appStore.getHamburger)
|
||||
|
||||
|
@ -84,6 +77,17 @@ const greyMode = ref(appStore.getGreyMode)
|
|||
const greyModeChange = (show: boolean) => {
|
||||
appStore.setGreyMode(show)
|
||||
}
|
||||
|
||||
const layout = computed(() => appStore.getLayout)
|
||||
|
||||
watch(
|
||||
() => layout.value,
|
||||
(n) => {
|
||||
if (n === 'top') {
|
||||
appStore.setCollapse(false)
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -98,11 +102,6 @@ const greyModeChange = (show: boolean) => {
|
|||
<ElSwitch v-model="breadcrumbIcon" @change="breadcrumbIconChange" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-14px">{{ t('setting.collapseMenu') }}</span>
|
||||
<ElSwitch v-model="collapse" @change="collapseChange" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-14px">{{ t('setting.hamburgerIcon') }}</span>
|
||||
<ElSwitch v-model="hamburger" @change="hamburgerChange" />
|
||||
|
|
|
@ -5,14 +5,13 @@ import { computed } from 'vue'
|
|||
const appStore = useAppStore()
|
||||
|
||||
const layout = computed(() => appStore.getLayout)
|
||||
console.log(layout.value)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="v-layout-radio-picker flex flex-wrap space-x-14px">
|
||||
<div
|
||||
:class="[
|
||||
'v-layout-radio-picker__classic relative w-56px h-48px cursor-pointer bg-gray-100',
|
||||
'v-layout-radio-picker__classic relative w-56px h-48px cursor-pointer bg-gray-300',
|
||||
{
|
||||
'is-acitve': layout === 'classic'
|
||||
}
|
||||
|
@ -21,13 +20,33 @@ console.log(layout.value)
|
|||
></div>
|
||||
<div
|
||||
:class="[
|
||||
'v-layout-radio-picker__top-left relative w-56px h-48px cursor-pointer bg-gray-100',
|
||||
'v-layout-radio-picker__top-left relative w-56px h-48px cursor-pointer bg-gray-300',
|
||||
{
|
||||
'is-acitve': layout === 'topLeft'
|
||||
}
|
||||
]"
|
||||
@click="appStore.setLayout('topLeft')"
|
||||
></div>
|
||||
<div
|
||||
:class="[
|
||||
'v-layout-radio-picker__top relative w-56px h-48px cursor-pointer bg-gray-300',
|
||||
{
|
||||
'is-acitve': layout === 'top'
|
||||
}
|
||||
]"
|
||||
@click="appStore.setLayout('top')"
|
||||
></div>
|
||||
<div
|
||||
:class="[
|
||||
'v-layout-radio-picker__cut-menu relative w-56px h-48px cursor-pointer bg-gray-300',
|
||||
{
|
||||
'is-acitve': layout === 'cutMenu'
|
||||
}
|
||||
]"
|
||||
@click="appStore.setLayout('cutMenu')"
|
||||
>
|
||||
<div class="absolute h-full w-[33%] top-0 left-[10%] bg-gray-200"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -91,6 +110,51 @@ console.log(layout.value)
|
|||
}
|
||||
}
|
||||
|
||||
&__top {
|
||||
border: 2px solid #e5e7eb;
|
||||
border-radius: 4px;
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 33%;
|
||||
background-color: #273352;
|
||||
border-radius: 4px 4px 0 0;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
&__cut-menu {
|
||||
border: 2px solid #e5e7eb;
|
||||
border-radius: 4px;
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 33%;
|
||||
background-color: #273352;
|
||||
border-radius: 4px 4px 0 0;
|
||||
content: '';
|
||||
}
|
||||
|
||||
&:after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 10%;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
border-radius: 4px 0 0 4px;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
.is-acitve {
|
||||
border-color: var(--el-color-primary);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
import TabMenu from './src/TabMenu.vue'
|
||||
|
||||
export { TabMenu }
|
|
@ -0,0 +1,211 @@
|
|||
<script lang="tsx">
|
||||
import { usePermissionStore } from '@/store/modules/permission'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { computed, unref, defineComponent, watch, ref } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { ElScrollbar } from 'element-plus'
|
||||
import { Icon } from '@/components/Icon'
|
||||
import { Menu } from '@/components/Menu'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { pathResolve } from '@/utils/routerHelper'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { filterMenusPath, initTabMap, tabPathMap } from './helper'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TabMenu',
|
||||
setup() {
|
||||
const { push, currentRoute } = useRouter()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
const collapse = computed(() => appStore.getCollapse)
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
|
||||
const routers = computed(() => permissionStore.getRouters)
|
||||
|
||||
const tabRouters = computed(() => unref(routers).filter((v) => !v?.meta?.hidden))
|
||||
|
||||
const setCollapse = () => {
|
||||
appStore.setCollapse(!unref(collapse))
|
||||
}
|
||||
|
||||
watch(
|
||||
() => routers.value,
|
||||
(routers: AppRouteRecordRaw[]) => {
|
||||
initTabMap(routers)
|
||||
filterMenusPath(routers, routers)
|
||||
console.log(tabPathMap)
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
)
|
||||
|
||||
const showTitle = ref(true)
|
||||
|
||||
watch(
|
||||
() => collapse.value,
|
||||
(collapse: boolean) => {
|
||||
if (!collapse) {
|
||||
setTimeout(() => {
|
||||
showTitle.value = !collapse
|
||||
}, 200)
|
||||
} else {
|
||||
showTitle.value = !collapse
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// 是否显示菜单
|
||||
const showMenu = ref(false)
|
||||
|
||||
// tab高亮
|
||||
const tabActive = ref('')
|
||||
|
||||
// tab点击事件
|
||||
const tabClick = (item: AppRouteRecordRaw) => {
|
||||
tabActive.value = item.children ? item.path : item.path.split('/')[0]
|
||||
if (item.children) {
|
||||
showMenu.value = !unref(showMenu)
|
||||
if (unref(showMenu)) {
|
||||
permissionStore.setMenuTabRouters(
|
||||
cloneDeep(item.children).map((v) => {
|
||||
v.path = pathResolve(unref(tabActive), v.path)
|
||||
return v
|
||||
})
|
||||
)
|
||||
}
|
||||
} else {
|
||||
push(item.path)
|
||||
permissionStore.setMenuTabRouters([])
|
||||
showMenu.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 设置高亮
|
||||
const isActice = (currentPath: string) => {
|
||||
const { path } = unref(currentRoute)
|
||||
if (tabPathMap[currentPath].includes(path)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const mouseleave = () => {
|
||||
if (!unref(showMenu)) return
|
||||
showMenu.value = false
|
||||
}
|
||||
|
||||
return () => (
|
||||
<div
|
||||
class={[
|
||||
'v-tab-menu relative bg-[var(--left-menu-bg-color)] top-1px',
|
||||
{
|
||||
'w-[var(--tab-menu-max-width)]': !unref(collapse),
|
||||
'w-[var(--tab-menu-min-width)]': unref(collapse)
|
||||
}
|
||||
]}
|
||||
onMouseleave={mouseleave}
|
||||
>
|
||||
<ElScrollbar class="!h-[calc(100%-var(--tab-menu-collapse-height)-1px)]">
|
||||
<div>
|
||||
{() => {
|
||||
return unref(tabRouters).map((v) => {
|
||||
const item = (
|
||||
v?.children?.length && v?.children?.length > 1
|
||||
? v
|
||||
: {
|
||||
...(v?.children && v?.children[0]),
|
||||
path: pathResolve(v.path, (v?.children && v?.children[0])?.path as string)
|
||||
}
|
||||
) as AppRouteRecordRaw
|
||||
return (
|
||||
<div
|
||||
class={[
|
||||
'v-tab-menu-item text-center text-12px relative py-12px cursor-pointer',
|
||||
{
|
||||
'is-active': isActice(v.path)
|
||||
}
|
||||
]}
|
||||
onClick={() => {
|
||||
tabClick(item)
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<Icon icon={item?.meta?.icon}></Icon>
|
||||
</div>
|
||||
{!unref(showTitle) ? undefined : (
|
||||
<p class="break-words mt-5px px-2px">{t(item.meta?.title)}</p>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}}
|
||||
</div>
|
||||
</ElScrollbar>
|
||||
<div
|
||||
class="v-tab-menu-collapse text-center h-[var(--tab-menu-collapse-height)] leading-[var(--tab-menu-collapse-height)] cursor-pointer"
|
||||
onClick={setCollapse}
|
||||
>
|
||||
<Icon icon={unref(collapse) ? 'ep:d-arrow-right' : 'ep:d-arrow-left'}></Icon>
|
||||
</div>
|
||||
<Menu
|
||||
class={[
|
||||
'!absolute top-0 border-left-1 border-solid border-[var(--left-menu-bg-light-color)]',
|
||||
{
|
||||
'!left-[var(--tab-menu-min-width)]': unref(collapse),
|
||||
'!left-[var(--tab-menu-max-width)]': !unref(collapse),
|
||||
'!w-[calc(var(--left-menu-max-width)+1px)]': unref(showMenu),
|
||||
'!w-0': !unref(showMenu)
|
||||
}
|
||||
]}
|
||||
style="transition: width var(--transition-time-02), left var(--transition-time-02);"
|
||||
></Menu>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-tab-menu';
|
||||
|
||||
.@{prefix-cls} {
|
||||
transition: all var(--transition-time-02);
|
||||
|
||||
&:after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
border-left: 1px solid var(--left-menu-border-color);
|
||||
content: '';
|
||||
}
|
||||
|
||||
&-item {
|
||||
color: var(--left-menu-text-color);
|
||||
transition: all var(--transition-time-02);
|
||||
|
||||
&:hover {
|
||||
color: var(--left-menu-text-active-color);
|
||||
// background-color: var(--left-menu-bg-active-color);
|
||||
}
|
||||
}
|
||||
|
||||
&-collapse {
|
||||
color: var(--left-menu-text-color);
|
||||
background-color: var(--left-menu-bg-light-color);
|
||||
border-top: 1px solid var(--left-menu-border-color);
|
||||
}
|
||||
|
||||
.is-active {
|
||||
color: var(--left-menu-text-active-color);
|
||||
background-color: var(--left-menu-bg-active-color);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,52 @@
|
|||
import { getAllParentPath } from '@/components/Menu/src/helper'
|
||||
import type { RouteMeta } from 'vue-router'
|
||||
import { isUrl } from '@/utils/is'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { reactive } from 'vue'
|
||||
|
||||
export type TabMapTypes = {
|
||||
[key: string]: string[]
|
||||
}
|
||||
|
||||
export const tabPathMap = reactive<TabMapTypes>({})
|
||||
|
||||
export const initTabMap = (routes: AppRouteRecordRaw[]) => {
|
||||
for (const v of routes) {
|
||||
const meta = (v.meta ?? {}) as RouteMeta
|
||||
if (!meta?.hidden) {
|
||||
tabPathMap[v.path] = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const filterMenusPath = (
|
||||
routes: AppRouteRecordRaw[],
|
||||
allRoutes: AppRouteRecordRaw[]
|
||||
): AppRouteRecordRaw[] => {
|
||||
const res: AppRouteRecordRaw[] = []
|
||||
for (const v of routes) {
|
||||
let data: Nullable<AppRouteRecordRaw> = null
|
||||
const meta = (v.meta ?? {}) as RouteMeta
|
||||
if (!meta.hidden) {
|
||||
const allParentPaht = getAllParentPath<AppRouteRecordRaw>(allRoutes, v.path)
|
||||
|
||||
const fullPath = isUrl(v.path) ? v.path : allParentPaht.join('/')
|
||||
|
||||
data = cloneDeep(v)
|
||||
data.path = fullPath
|
||||
if (v.children && data) {
|
||||
data.children = filterMenusPath(v.children, allRoutes)
|
||||
}
|
||||
|
||||
if (data) {
|
||||
res.push(data)
|
||||
}
|
||||
|
||||
if (allParentPaht.length && Reflect.has(tabPathMap, allParentPaht[0])) {
|
||||
tabPathMap[allParentPaht[0]].push(fullPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
|
@ -132,8 +132,8 @@ watch(
|
|||
<Icon icon="ep:d-arrow-left" color="#333" />
|
||||
</span>
|
||||
<div class="overflow-hidden flex-1">
|
||||
<ElScrollbar>
|
||||
<div class="flex h-[var(--tags-view-height)]">
|
||||
<ElScrollbar class="h-full">
|
||||
<div class="flex h-full">
|
||||
<ContextMenu
|
||||
:schema="[
|
||||
{
|
||||
|
@ -202,7 +202,10 @@ watch(
|
|||
]"
|
||||
>
|
||||
<router-link :to="{ ...item }" custom v-slot="{ navigate }">
|
||||
<div @click="navigate" class="h-full flex justify-center items-center">
|
||||
<div
|
||||
@click="navigate"
|
||||
class="h-full flex justify-center items-center whitespace-nowrap"
|
||||
>
|
||||
{{ t(item?.meta?.title as string) }}
|
||||
<Icon
|
||||
class="v-tags-view__item--close"
|
||||
|
@ -291,6 +294,10 @@ watch(
|
|||
@prefix-cls: ~'@{namespace}-tags-view';
|
||||
|
||||
.@{prefix-cls} {
|
||||
:deep(.el-scrollbar__view) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&__tool {
|
||||
position: relative;
|
||||
|
||||
|
@ -302,11 +309,12 @@ watch(
|
|||
|
||||
&:after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
top: 1px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid var(--top-tool-border-color);
|
||||
height: calc(~'100% - 1px');
|
||||
border-right: 1px solid var(--tags-view-border-color);
|
||||
border-left: 1px solid var(--tags-view-border-color);
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import { useCache } from '@/hooks/web/useCache'
|
|||
|
||||
const { wsCache } = useCache()
|
||||
|
||||
export type LayoutType = 'classic' | 'topLeft' | 'leftTop' | 'top' | 'test'
|
||||
export type LayoutType = 'classic' | 'topLeft' | 'top' | 'cutMenu'
|
||||
|
||||
export interface AppState {
|
||||
breadcrumb: boolean
|
||||
|
@ -15,11 +15,11 @@ export interface AppState {
|
|||
tagsView: boolean
|
||||
logo: boolean
|
||||
fixedHeader: boolean
|
||||
fixedMenu: boolean
|
||||
greyMode: boolean
|
||||
|
||||
layout: LayoutType
|
||||
title: string
|
||||
logoTitle: string
|
||||
userInfo: string
|
||||
isDark: boolean
|
||||
currentSize: ElememtPlusSzie
|
||||
|
@ -39,11 +39,11 @@ export const appModules: AppState = {
|
|||
tagsView: true, // 标签页
|
||||
logo: true, // logo
|
||||
fixedHeader: true, // 固定toolheader
|
||||
fixedMenu: false, // 固定切割菜单
|
||||
greyMode: false, // 是否开始灰色模式,用于特殊悼念日
|
||||
|
||||
layout: wsCache.get('layout') || 'classic', // layout布局
|
||||
title: 'butterfly-admin', // 标题
|
||||
logoTitle: 'ButterflyAdmin', // logo标题
|
||||
title: 'ButterflyAdmin', // 标题
|
||||
userInfo: 'userInfo', // 登录信息存储字段-建议每个项目换一个字段,避免与其他项目冲突
|
||||
isDark: wsCache.get('isDark') || false, // 是否是暗黑模式
|
||||
currentSize: wsCache.get('default') || 'default', // 组件尺寸
|
||||
|
@ -75,6 +75,8 @@ export const appModules: AppState = {
|
|||
// 头部字体颜色
|
||||
topHeaderTextColor: 'inherit',
|
||||
// 头部悬停颜色
|
||||
topHeaderHoverColor: '#f6f6f6'
|
||||
topHeaderHoverColor: '#f6f6f6',
|
||||
// 头部边框颜色
|
||||
topToolBorderColor: '#eee'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="tsx">
|
||||
import { computed, defineComponent, unref } from 'vue'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { Backtop } from '@/components/Backtop'
|
||||
// import { Backtop } from '@/components/Backtop'
|
||||
import { Setting } from '@/components/Setting'
|
||||
import { useRenderLayout } from './components/useRenderLayout'
|
||||
|
||||
|
@ -27,6 +27,12 @@ const renderLayout = () => {
|
|||
case 'topLeft':
|
||||
const { renderTopLeft } = useRenderLayout()
|
||||
return renderTopLeft()
|
||||
case 'top':
|
||||
const { renderTop } = useRenderLayout()
|
||||
return renderTop()
|
||||
case 'cutMenu':
|
||||
const { renderCutMenu } = useRenderLayout()
|
||||
return renderCutMenu()
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
@ -46,7 +52,7 @@ export default defineComponent({
|
|||
|
||||
{renderLayout()}
|
||||
|
||||
<Backtop></Backtop>
|
||||
{/*<Backtop></Backtop>*/}
|
||||
|
||||
<Setting></Setting>
|
||||
</section>
|
||||
|
|
|
@ -22,6 +22,9 @@ const screenfull = computed(() => appStore.getScreenfull)
|
|||
// 尺寸图标
|
||||
const size = computed(() => appStore.getSize)
|
||||
|
||||
// 布局
|
||||
const layout = computed(() => appStore.getLayout)
|
||||
|
||||
// 多语言图标
|
||||
const locale = computed(() => appStore.getLocale)
|
||||
|
||||
|
@ -35,12 +38,14 @@ export default defineComponent({
|
|||
'h-[var(--top-tool-height)] relative px-[var(--top-tool-p-x)] flex items-center justify-between'
|
||||
]}
|
||||
>
|
||||
<div class="h-full flex items-center">
|
||||
{hamburger.value ? (
|
||||
<Collapse class="hover-tigger" color="var(--top-header-text-color)"></Collapse>
|
||||
) : undefined}
|
||||
{breadcrumb.value ? <Breadcrumb class="<md:hidden"></Breadcrumb> : undefined}
|
||||
</div>
|
||||
{layout.value !== 'top' ? (
|
||||
<div class="h-full flex items-center">
|
||||
{hamburger.value && layout.value !== 'cutMenu' ? (
|
||||
<Collapse class="hover-tigger" color="var(--top-header-text-color)"></Collapse>
|
||||
) : undefined}
|
||||
{breadcrumb.value ? <Breadcrumb class="<md:hidden"></Breadcrumb> : undefined}
|
||||
</div>
|
||||
) : undefined}
|
||||
<div class="h-full flex items-center">
|
||||
{screenfull.value ? (
|
||||
<Screenfull class="hover-tigger" color="var(--top-header-text-color)"></Screenfull>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { computed } from 'vue'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { Menu } from '@/components/Menu'
|
||||
import { TabMenu } from '@/components/TabMenu'
|
||||
import { TagsView } from '@/components/TagsView'
|
||||
import { Logo } from '@/components/Logo'
|
||||
import AppView from './AppView.vue'
|
||||
|
@ -32,7 +33,7 @@ export const useRenderLayout = () => {
|
|||
{logo.value ? (
|
||||
<Logo
|
||||
class={[
|
||||
'bg-[var(--left-menu-bg-color)]',
|
||||
'bg-[var(--left-menu-bg-color)] border-bottom-1 border-solid border-[var(--logo-border-color)]',
|
||||
{
|
||||
'!pl-0': mobile.value && collapse.value,
|
||||
'w-[var(--left-menu-min-width)]': appStore.getCollapse,
|
||||
|
@ -80,9 +81,11 @@ export const useRenderLayout = () => {
|
|||
]}
|
||||
style="transition: all var(--transition-time-02);"
|
||||
>
|
||||
<ToolHeader class="border-bottom bg-[var(--top-header-bg-color)]"></ToolHeader>
|
||||
<ToolHeader class="border-bottom-1 border-solid border-[var(--top-tool-border-color)] bg-[var(--top-header-bg-color)]"></ToolHeader>
|
||||
|
||||
{tagsView.value ? <TagsView class="border-bottom"></TagsView> : undefined}
|
||||
{tagsView.value ? (
|
||||
<TagsView class="border-bottom-1 border-solid border-[var(--tags-view-border-color)]"></TagsView>
|
||||
) : undefined}
|
||||
</div>
|
||||
|
||||
<AppView></AppView>
|
||||
|
@ -95,12 +98,12 @@ export const useRenderLayout = () => {
|
|||
const renderTopLeft = () => {
|
||||
return (
|
||||
<>
|
||||
<div class="flex items-center bg-[var(--top-header-bg-color)]">
|
||||
<Logo class="hover-tigger !pr-15px"></Logo>
|
||||
<div class="flex items-center bg-[var(--top-header-bg-color)] border-bottom-1 border-solid border-[var(--top-tool-border-color)]">
|
||||
{logo.value ? <Logo class="hover-tigger !pr-15px"></Logo> : undefined}
|
||||
|
||||
<ToolHeader class="flex-1"></ToolHeader>
|
||||
</div>
|
||||
<div class="absolute top-[var(--logo-height)] left-0 w-full h-[calc(100%-var(--logo-height))] flex">
|
||||
<div class="absolute top-[var(--logo-height)+1px] left-0 w-full h-[calc(100%-1px-var(--logo-height))] flex">
|
||||
<Menu class="!h-full"></Menu>
|
||||
<div
|
||||
class={[
|
||||
|
@ -127,7 +130,7 @@ export const useRenderLayout = () => {
|
|||
{tagsView.value ? (
|
||||
<TagsView
|
||||
class={[
|
||||
'border-bottom border-top',
|
||||
'border-bottom-1 border-solid border-[var(--tags-view-border-color)]',
|
||||
{
|
||||
'!fixed top-0 left-0 z-10': fixedHeader.value,
|
||||
'w-[calc(100%-var(--left-menu-min-width))] left-[var(--left-menu-min-width)] mt-[var(--logo-height)]':
|
||||
|
@ -148,8 +151,103 @@ export const useRenderLayout = () => {
|
|||
)
|
||||
}
|
||||
|
||||
const renderTop = () => {
|
||||
return (
|
||||
<>
|
||||
<div class="flex items-center justify-between bg-[var(--top-header-bg-color)] border-bottom-1 border-solid border-[var(--top-tool-border-color)]">
|
||||
{logo.value ? <Logo class="hover-tigger"></Logo> : undefined}
|
||||
<Menu class="flex-1 px-10px h-[var(--top-tool-height)]"></Menu>
|
||||
<ToolHeader></ToolHeader>
|
||||
</div>
|
||||
<div class="v-app-right h-full w-full">
|
||||
<ElScrollbar
|
||||
class={[
|
||||
'v-content',
|
||||
{
|
||||
'mt-[var(--tags-view-height)]': fixedHeader.value
|
||||
}
|
||||
]}
|
||||
>
|
||||
{tagsView.value ? (
|
||||
<TagsView
|
||||
class={[
|
||||
'border-bottom-1 border-solid border-[var(--tags-view-border-color)]',
|
||||
{
|
||||
'!fixed w-full top-[var(--top-tool-height)] left-0': fixedHeader.value
|
||||
}
|
||||
]}
|
||||
style="transition: all var(--transition-time-02);"
|
||||
></TagsView>
|
||||
) : undefined}
|
||||
|
||||
<AppView></AppView>
|
||||
</ElScrollbar>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const renderCutMenu = () => {
|
||||
return (
|
||||
<>
|
||||
<div class="flex items-center bg-[var(--top-header-bg-color)] border-bottom-1 border-solid border-[var(--top-tool-border-color)]">
|
||||
{logo.value ? <Logo class="hover-tigger !pr-15px"></Logo> : undefined}
|
||||
|
||||
<ToolHeader class="flex-1"></ToolHeader>
|
||||
</div>
|
||||
<div class="absolute top-[var(--logo-height)] left-0 w-full h-[calc(100%-var(--logo-height))] flex">
|
||||
<TabMenu></TabMenu>
|
||||
{/* <Menu class="!h-full"></Menu> */}
|
||||
<div
|
||||
class={[
|
||||
'v-app-right',
|
||||
'h-[100%]',
|
||||
{
|
||||
'w-[calc(100%-var(--tab-menu-min-width))] left-[var(--tab-menu-min-width)]':
|
||||
collapse.value,
|
||||
'w-[calc(100%-var(--tab-menu-max-width))] left-[var(--tab-menu-max-width)]':
|
||||
!collapse.value
|
||||
}
|
||||
]}
|
||||
style="transition: all var(--transition-time-02);"
|
||||
>
|
||||
<ElScrollbar
|
||||
class={[
|
||||
'v-content',
|
||||
{
|
||||
'!h-[calc(100%-var(--tags-view-height))] mt-[calc(var(--tags-view-height))]':
|
||||
fixedHeader.value && tagsView.value
|
||||
}
|
||||
]}
|
||||
>
|
||||
{tagsView.value ? (
|
||||
<TagsView
|
||||
class={[
|
||||
'border-bottom-1 border-solid border-[var(--tags-view-border-color)]',
|
||||
{
|
||||
'!fixed top-0 left-0 z-10': fixedHeader.value,
|
||||
'w-[calc(100%-var(--tab-menu-min-width))] left-[var(--tab-menu-min-width)] mt-[var(--logo-height)]':
|
||||
collapse.value && fixedHeader.value,
|
||||
'w-[calc(100%-var(--tab-menu-max-width))] left-[var(--tab-menu-max-width)] mt-[var(--logo-height)]':
|
||||
!collapse.value && fixedHeader.value
|
||||
}
|
||||
]}
|
||||
style="transition: all var(--transition-time-02);"
|
||||
></TagsView>
|
||||
) : undefined}
|
||||
|
||||
<AppView></AppView>
|
||||
</ElScrollbar>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
renderClassic,
|
||||
renderTopLeft
|
||||
renderTopLeft,
|
||||
renderTop,
|
||||
renderCutMenu
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,8 @@ export default {
|
|||
logo: 'Logo',
|
||||
greyMode: 'Grey mode',
|
||||
fixedHeader: 'Fixed header',
|
||||
headerTheme: 'Header theme'
|
||||
headerTheme: 'Header theme',
|
||||
cutMenu: 'Cut Menu'
|
||||
},
|
||||
size: {
|
||||
default: 'Default',
|
||||
|
|
|
@ -37,7 +37,8 @@ export default {
|
|||
logo: '标志',
|
||||
greyMode: '灰色模式',
|
||||
fixedHeader: '固定头部',
|
||||
headerTheme: '头部主题'
|
||||
headerTheme: '头部主题',
|
||||
cutMenu: '切割菜单'
|
||||
},
|
||||
size: {
|
||||
default: '默认',
|
||||
|
|
|
@ -42,6 +42,9 @@ export const useAppStore = defineStore({
|
|||
getFixedHeader(): boolean {
|
||||
return this.fixedHeader
|
||||
},
|
||||
getFixedMenu(): boolean {
|
||||
return this.fixedMenu
|
||||
},
|
||||
getGreyMode(): boolean {
|
||||
return this.greyMode
|
||||
},
|
||||
|
@ -52,9 +55,6 @@ export const useAppStore = defineStore({
|
|||
getTitle(): string {
|
||||
return this.title
|
||||
},
|
||||
getLogoTitle(): string {
|
||||
return this.logoTitle
|
||||
},
|
||||
getUserInfo(): string {
|
||||
return this.userInfo
|
||||
},
|
||||
|
@ -105,6 +105,9 @@ export const useAppStore = defineStore({
|
|||
setFixedHeader(fixedHeader: boolean) {
|
||||
this.fixedHeader = fixedHeader
|
||||
},
|
||||
setFixedMenu(fixedMenu: boolean) {
|
||||
this.fixedMenu = fixedMenu
|
||||
},
|
||||
setGreyMode(greyMode: boolean) {
|
||||
this.greyMode = greyMode
|
||||
},
|
||||
|
@ -120,9 +123,6 @@ export const useAppStore = defineStore({
|
|||
setTitle(title: string) {
|
||||
this.title = title
|
||||
},
|
||||
setLogoTitle(logoTitle: string) {
|
||||
this.logoTitle = logoTitle
|
||||
},
|
||||
setIsDark(isDark: boolean) {
|
||||
this.isDark = isDark
|
||||
if (this.isDark) {
|
||||
|
|
|
@ -15,7 +15,6 @@ export interface PermissionState {
|
|||
routers: AppRouteRecordRaw[]
|
||||
addRouters: AppRouteRecordRaw[]
|
||||
isAddRouters: boolean
|
||||
activeTab: string
|
||||
menuTabRouters: AppRouteRecordRaw[]
|
||||
}
|
||||
|
||||
|
@ -25,8 +24,7 @@ export const usePermissionStore = defineStore({
|
|||
routers: [],
|
||||
addRouters: [],
|
||||
isAddRouters: false,
|
||||
menuTabRouters: [],
|
||||
activeTab: ''
|
||||
menuTabRouters: []
|
||||
}),
|
||||
getters: {
|
||||
getRouters(): AppRouteRecordRaw[] {
|
||||
|
@ -38,9 +36,6 @@ export const usePermissionStore = defineStore({
|
|||
getIsAddRouters(): boolean {
|
||||
return this.isAddRouters
|
||||
},
|
||||
getActiveTab(): string {
|
||||
return this.activeTab
|
||||
},
|
||||
getMenuTabRouters(): AppRouteRecordRaw[] {
|
||||
return this.menuTabRouters
|
||||
}
|
||||
|
@ -84,9 +79,6 @@ export const usePermissionStore = defineStore({
|
|||
},
|
||||
setMenuTabRouters(routers: AppRouteRecordRaw[]): void {
|
||||
this.menuTabRouters = routers
|
||||
},
|
||||
setAcitveTab(activeTab: string): void {
|
||||
this.activeTab = activeTab
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
}
|
||||
|
||||
.border-bottom {
|
||||
border-bottom: 1px solid var(--top-tool-border-color);
|
||||
}
|
||||
|
||||
.border-bottom--after {
|
||||
@apply relative;
|
||||
&:after {
|
||||
content: '';
|
||||
|
@ -16,6 +20,10 @@
|
|||
}
|
||||
|
||||
.border-top {
|
||||
border-top: 1px solid var(--top-tool-border-color);
|
||||
}
|
||||
|
||||
.border-top--before {
|
||||
@apply relative;
|
||||
&:before {
|
||||
content: '';
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
@import './var.css';
|
||||
@import './common.less';
|
||||
// @import './common.less';
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
--dark-bg-color: #293146;
|
||||
|
||||
/* left menu start */
|
||||
--left-menu-border-color: 'inherit';
|
||||
--left-menu-border-color: '#eee';
|
||||
|
||||
--left-menu-max-width: 200px;
|
||||
|
||||
|
@ -43,8 +43,20 @@
|
|||
--top-tool-border-color: #eee;
|
||||
|
||||
--tags-view-height: 35px;
|
||||
|
||||
--tags-view-border-color: #eee;
|
||||
/* header start */
|
||||
|
||||
/* tab menu start */
|
||||
--tab-menu-max-width: 80px;
|
||||
|
||||
--tab-menu-min-width: 30px;
|
||||
|
||||
--tab-menu-collapse-height: 36px;
|
||||
|
||||
--tab-menu-border-color: #eee;
|
||||
/* tab menu end */
|
||||
|
||||
--app-content-padding: 20px;
|
||||
|
||||
--transition-time-02: 0.2s;
|
||||
|
|
|
@ -147,7 +147,7 @@ export const forEach = <T = any>(
|
|||
const list: any[] = [...tree]
|
||||
const { children } = config
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
//func 返回true就终止遍历,避免大量节点场景下无意义循环,引起浏览器卡顿
|
||||
// func 返回true就终止遍历,避免大量节点场景下无意义循环,引起浏览器卡顿
|
||||
if (func(list[i])) {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { defineConfig } from 'windicss/helpers'
|
||||
// import plugin from 'windicss/plugin'
|
||||
import plugin from 'windicss/plugin'
|
||||
|
||||
// function range(size, startAt = 1) {
|
||||
// return Array.from(Array(size).keys()).map((i) => i + startAt)
|
||||
// }
|
||||
function range(size, startAt = 1) {
|
||||
return Array.from(Array(size).keys()).map((i) => i + startAt)
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
extract: {
|
||||
|
@ -34,34 +34,38 @@ export default defineConfig({
|
|||
// // ...range(50).map((i) => `mb-${i}px`),
|
||||
// // ...range(50).map((i) => `ml-${i}px`)
|
||||
// }
|
||||
}
|
||||
// plugins: [
|
||||
// plugin(({ addComponents }) => {
|
||||
// addComponents({
|
||||
// '.hover-tigger': {
|
||||
// display: 'flex',
|
||||
// height: '100%',
|
||||
// padding: '1px 10px 0',
|
||||
// cursor: 'pointer',
|
||||
// alignItems: 'center',
|
||||
// transition: 'background var(--transition-time-02)',
|
||||
// '&:hover': {
|
||||
// backgroundColor: '#f6f6f6'
|
||||
// }
|
||||
// },
|
||||
// '.border-bottom': {
|
||||
// position: 'relative',
|
||||
// '&:after': {
|
||||
// position: 'absolute',
|
||||
// bottom: '0',
|
||||
// left: '0',
|
||||
// width: '100%',
|
||||
// height: '1px',
|
||||
// borderTop: '1px solid var(--top-tool-border-color)',
|
||||
// content: ''
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
// ]
|
||||
},
|
||||
plugins: [
|
||||
plugin(({ addComponents }) => {
|
||||
const obj = {}
|
||||
range(50).map((i) => {
|
||||
obj[`.border-top-${i}`] = {
|
||||
borderTopWidth: `${i}px`
|
||||
}
|
||||
obj[`.border-left-${i}`] = {
|
||||
borderLeftWidth: `${i}px`
|
||||
}
|
||||
obj[`.border-right-${i}`] = {
|
||||
borderRightWidth: `${i}px`
|
||||
}
|
||||
obj[`.border-bottom-${i}`] = {
|
||||
borderBottomWidth: `${i}px`
|
||||
}
|
||||
})
|
||||
addComponents({
|
||||
'.hover-tigger': {
|
||||
display: 'flex',
|
||||
height: '100%',
|
||||
padding: '1px 10px 0',
|
||||
cursor: 'pointer',
|
||||
alignItems: 'center',
|
||||
transition: 'background var(--transition-time-02)',
|
||||
'&:hover': {
|
||||
backgroundColor: 'var(--top-header-hover-color)'
|
||||
}
|
||||
},
|
||||
...obj
|
||||
})
|
||||
})
|
||||
]
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue