|
|
|
@ -18,8 +18,9 @@ import { |
|
|
|
watchEffect, |
|
|
|
} from 'vue'; |
|
|
|
|
|
|
|
import { useNamespace } from '@vben-core/hooks'; |
|
|
|
import { IcRoundMoreHoriz } from '@vben-core/iconify'; |
|
|
|
import { isHttpUrl, useNamespace } from '@vben-core/toolkit'; |
|
|
|
import { isHttpUrl } from '@vben-core/toolkit'; |
|
|
|
|
|
|
|
import { UseResizeObserverReturn, useResizeObserver } from '@vueuse/core'; |
|
|
|
|
|
|
|
@ -348,3 +349,512 @@ function removeMenuItem(item: MenuItemRegistered) { |
|
|
|
</template> |
|
|
|
</ul> |
|
|
|
</template> |
|
|
|
|
|
|
|
<style lang="scss"> |
|
|
|
$namespace: vben; |
|
|
|
|
|
|
|
@mixin menu-item-active { |
|
|
|
color: var(--menu-item-active-color); |
|
|
|
text-decoration: none; |
|
|
|
cursor: pointer; |
|
|
|
background: var(--menu-item-active-background-color); |
|
|
|
} |
|
|
|
|
|
|
|
@mixin menu-item { |
|
|
|
position: relative; |
|
|
|
display: flex; |
|
|
|
// gap: 12px; |
|
|
|
align-items: center; |
|
|
|
height: var(--menu-item-height); |
|
|
|
padding: var(--menu-item-padding-y) var(--menu-item-padding-x); |
|
|
|
margin: 0 var(--menu-item-margin-x) var(--menu-item-margin-y) |
|
|
|
var(--menu-item-margin-x); |
|
|
|
font-size: var(--menu-font-size); |
|
|
|
color: var(--menu-item-color); |
|
|
|
text-decoration: none; |
|
|
|
white-space: nowrap; |
|
|
|
list-style: none; |
|
|
|
cursor: pointer; |
|
|
|
background: var(--menu-item-background-color); |
|
|
|
border: none; |
|
|
|
border-radius: var(--menu-item-radius); |
|
|
|
transition: |
|
|
|
background 0.15s ease, |
|
|
|
color 0.15s ease, |
|
|
|
padding 0.15s ease, |
|
|
|
border-color 0.15s ease; |
|
|
|
|
|
|
|
&.is-disabled { |
|
|
|
cursor: not-allowed; |
|
|
|
background: none !important; |
|
|
|
opacity: 0.25; |
|
|
|
} |
|
|
|
|
|
|
|
.#{$namespace}-menu__icon { |
|
|
|
transition: transform 0.25s; |
|
|
|
} |
|
|
|
|
|
|
|
&:hover { |
|
|
|
.#{$namespace}-menu__icon { |
|
|
|
transform: scale(1.3); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&:hover, |
|
|
|
&:focus { |
|
|
|
outline: none; |
|
|
|
} |
|
|
|
|
|
|
|
* { |
|
|
|
vertical-align: bottom; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@mixin menu-title { |
|
|
|
max-width: var(--menu-title-width); |
|
|
|
overflow: hidden; |
|
|
|
text-overflow: ellipsis; |
|
|
|
white-space: nowrap; |
|
|
|
opacity: 1; |
|
|
|
} |
|
|
|
|
|
|
|
.#{$namespace}-menu__popup-container, |
|
|
|
.#{$namespace}-menu { |
|
|
|
--menu-title-width: 140px; |
|
|
|
--menu-item-icon-width: 20px; |
|
|
|
--menu-item-height: 38px; |
|
|
|
--menu-item-padding-y: 26px; |
|
|
|
--menu-item-padding-x: 12px; |
|
|
|
--menu-item-popup-padding-y: 22px; |
|
|
|
--menu-item-popup-padding-x: 12px; |
|
|
|
--menu-item-margin-y: 4px; |
|
|
|
--menu-item-margin-x: 0px; |
|
|
|
--menu-item-collapse-padding-y: 25px; |
|
|
|
--menu-item-collapse-padding-x: 0px; |
|
|
|
--menu-item-collapse-margin-y: 4px; |
|
|
|
--menu-item-collapse-margin-x: 0px; |
|
|
|
--menu-item-radius: 0px; |
|
|
|
--menu-item-indent: 16px; |
|
|
|
--menu-font-size: 14px; |
|
|
|
--menu-dark-background: 0deg 0% 100% / 10%; |
|
|
|
--menu-light-background: 192deg 1% 93%; |
|
|
|
|
|
|
|
&.is-dark { |
|
|
|
--menu-background-color: hsl(var(--menu-dark)); |
|
|
|
// --menu-submenu-opened-background-color: hsl(var(--menu-opened-dark)); |
|
|
|
--menu-item-background-color: var(--menu-background-color); |
|
|
|
--menu-item-color: hsl(var(--dark-foreground) / 80%); |
|
|
|
--menu-item-hover-color: hsl(var(--primary-foreground)); |
|
|
|
--menu-item-hover-background-color: hsl(var(--menu-dark-background)); |
|
|
|
--menu-item-active-color: hsl(var(--primary-foreground)); |
|
|
|
--menu-item-active-background-color: hsl(var(--primary)); |
|
|
|
--menu-submenu-hover-color: hsl(var(--dark-foreground)); |
|
|
|
--menu-submenu-hover-background-color: hsl(var(--menu-dark-background)); |
|
|
|
--menu-submenu-active-color: hsl(var(--dark-foreground)); |
|
|
|
--menu-submenu-active-background-color: transparent; |
|
|
|
--menu-submenu-background-color: var(--menu-background-color); |
|
|
|
} |
|
|
|
|
|
|
|
&.is-light { |
|
|
|
--menu-background-color: hsl(var(--menu)); |
|
|
|
// --menu-submenu-opened-background-color: hsl(var(--menu-opened)); |
|
|
|
--menu-item-background-color: var(--menu-background-color); |
|
|
|
--menu-item-color: hsl(var(--foreground)); |
|
|
|
--menu-item-hover-color: var(--menu-item-color); |
|
|
|
--menu-item-hover-background-color: hsl(var(--menu-light-background)); |
|
|
|
--menu-item-active-color: hsl(var(--primary-foreground)); |
|
|
|
--menu-item-active-background-color: hsl(var(--primary)); |
|
|
|
--menu-submenu-hover-color: hsl(var(--primary)); |
|
|
|
--menu-submenu-hover-background-color: hsl(var(--menu-light-background)); |
|
|
|
--menu-submenu-active-color: hsl(var(--primary)); |
|
|
|
--menu-submenu-active-background-color: transparent; |
|
|
|
--menu-submenu-background-color: var(--menu-background-color); |
|
|
|
} |
|
|
|
|
|
|
|
&.is-rounded { |
|
|
|
--menu-item-margin-x: 8px; |
|
|
|
--menu-item-collapse-margin-x: 6px; |
|
|
|
--menu-item-radius: 6px; |
|
|
|
} |
|
|
|
|
|
|
|
&.is-horizontal:not(.is-rounded) { |
|
|
|
--menu-item-height: 60px; |
|
|
|
--menu-item-radius: 0px; |
|
|
|
} |
|
|
|
|
|
|
|
&.is-horizontal.is-rounded { |
|
|
|
--menu-item-height: 40px; |
|
|
|
--menu-item-radius: 6px; |
|
|
|
--menu-item-padding-x: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
// .vben-menu__popup, |
|
|
|
&.is-horizontal { |
|
|
|
--menu-item-padding-y: 0px; |
|
|
|
--menu-item-padding-x: 10px; |
|
|
|
--menu-item-margin-y: 0px; |
|
|
|
--menu-item-margin-x: 1px; |
|
|
|
--menu-background-color: transparent; |
|
|
|
|
|
|
|
&.is-dark { |
|
|
|
--menu-item-hover-color: var(--foreground); |
|
|
|
--menu-item-hover-background-color: hsl(var(--menu-dark-background)); |
|
|
|
--menu-item-active-color: hsl(var(--foreground)); |
|
|
|
--menu-item-active-background-color: hsl(var(--menu-dark-background)); |
|
|
|
--menu-submenu-active-color: hsl(var(--foreground)); |
|
|
|
--menu-submenu-active-background-color: hsl(var(--menu-dark-background)); |
|
|
|
--menu-submenu-hover-color: hsl(var(--foreground)); |
|
|
|
--menu-submenu-hover-background-color: hsl(var(--menu-dark-background)); |
|
|
|
} |
|
|
|
|
|
|
|
&.is-light { |
|
|
|
--menu-item-active-color: hsl(var(--foreground)); |
|
|
|
--menu-item-active-background-color: hsl(var(--menu-light-background)); |
|
|
|
--menu-item-hover-background-color: hsl(var(--menu-light-background)); |
|
|
|
--menu-item-hover-color: hsl(var(--primary)); |
|
|
|
--menu-submenu-hover-color: hsl(var(--primary)); |
|
|
|
--menu-submenu-hover-background-color: hsl(var(--menu-light-background)); |
|
|
|
--menu-submenu-active-color: hsl(var(--foreground)); |
|
|
|
--menu-submenu-active-background-color: hsl(var(--menu-light-background)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.#{$namespace}-menu { |
|
|
|
position: relative; |
|
|
|
box-sizing: border-box; |
|
|
|
padding-left: 0; |
|
|
|
margin: 0; |
|
|
|
list-style: none; |
|
|
|
background: hsl(var(--menu-background-color)); |
|
|
|
|
|
|
|
// 垂直菜单 |
|
|
|
&.is-vertical { |
|
|
|
&:not(.#{$namespace}-menu.is-collapse) { |
|
|
|
& .#{$namespace}-menu-item, |
|
|
|
& .#{$namespace}-sub-menu-content, |
|
|
|
& .#{$namespace}-menu-item-group__title { |
|
|
|
padding-left: calc( |
|
|
|
var(--menu-item-indent) + var(--menu-level) * var(--menu-item-indent) |
|
|
|
); |
|
|
|
white-space: nowrap; |
|
|
|
} |
|
|
|
|
|
|
|
& > .#{$namespace}-sub-menu { |
|
|
|
// .#{$namespace}-menu { |
|
|
|
// background: var(--menu-submenu-opened-background-color); |
|
|
|
|
|
|
|
// .#{$namespace}-sub-menu, |
|
|
|
// .#{$namespace}-menu-item:not(.is-active), |
|
|
|
// .#{$namespace}-sub-menu-content:not(.is-active) { |
|
|
|
// background: var(--menu-submenu-opened-background-color); |
|
|
|
// } |
|
|
|
// } |
|
|
|
& > .#{$namespace}-menu { |
|
|
|
& > .#{$namespace}-menu-item { |
|
|
|
padding-left: calc( |
|
|
|
0px + var(--menu-item-indent) + var(--menu-level) * |
|
|
|
var(--menu-item-indent) |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
& > .#{$namespace}-sub-menu-content { |
|
|
|
padding-left: calc(var(--menu-item-indent) - 8px); |
|
|
|
} |
|
|
|
} |
|
|
|
& > .#{$namespace}-menu-item { |
|
|
|
padding-left: calc(var(--menu-item-indent) - 8px); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&.is-horizontal { |
|
|
|
display: flex; |
|
|
|
flex-wrap: nowrap; |
|
|
|
max-width: 100%; |
|
|
|
height: var(--height-horizontal-height); |
|
|
|
border-right: none; |
|
|
|
|
|
|
|
.#{$namespace}-menu-item { |
|
|
|
display: inline-flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
height: var(--menu-item-height); |
|
|
|
padding-right: calc(var(--menu-item-padding-x) + 6px); |
|
|
|
margin: 0; |
|
|
|
margin-right: 2px; |
|
|
|
// border-bottom: 2px solid transparent; |
|
|
|
border-radius: var(--menu-item-radius); |
|
|
|
} |
|
|
|
|
|
|
|
& > .#{$namespace}-sub-menu { |
|
|
|
height: var(--menu-item-height); |
|
|
|
margin-right: 2px; |
|
|
|
|
|
|
|
&:focus, |
|
|
|
&:hover { |
|
|
|
outline: none; |
|
|
|
} |
|
|
|
|
|
|
|
& .#{$namespace}-sub-menu-content { |
|
|
|
height: 100%; |
|
|
|
padding-right: 40px; |
|
|
|
// border-bottom: 2px solid transparent; |
|
|
|
border-radius: var(--menu-item-radius); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
& .#{$namespace}-menu-item:not(.is-disabled):hover, |
|
|
|
& .#{$namespace}-menu-item:not(.is-disabled):focus { |
|
|
|
outline: none; |
|
|
|
} |
|
|
|
|
|
|
|
& > .#{$namespace}-menu-item.is-active { |
|
|
|
color: var(--menu-item-active-color); |
|
|
|
} |
|
|
|
|
|
|
|
// &.is-light { |
|
|
|
// & > .#{$namespace}-sub-menu { |
|
|
|
// &.is-active { |
|
|
|
// border-bottom: 2px solid var(--menu-item-active-color); |
|
|
|
// } |
|
|
|
// &:not(.is-active) .#{$namespace}-sub-menu-content { |
|
|
|
// &:hover { |
|
|
|
// border-bottom: 2px solid var(--menu-item-active-color); |
|
|
|
// } |
|
|
|
// } |
|
|
|
// } |
|
|
|
// & > .#{$namespace}-menu-item.is-active { |
|
|
|
// border-bottom: 2px solid var(--menu-item-active-color); |
|
|
|
// } |
|
|
|
|
|
|
|
// & .#{$namespace}-menu-item:not(.is-disabled):hover, |
|
|
|
// & .#{$namespace}-menu-item:not(.is-disabled):focus { |
|
|
|
// border-bottom: 2px solid var(--menu-item-active-color); |
|
|
|
// } |
|
|
|
// } |
|
|
|
} |
|
|
|
// 折叠菜单 |
|
|
|
|
|
|
|
&.is-collapse { |
|
|
|
.#{$namespace}-menu__icon { |
|
|
|
margin-right: 0; |
|
|
|
} |
|
|
|
.#{$namespace}-sub-menu__icon-arrow { |
|
|
|
display: none; |
|
|
|
} |
|
|
|
|
|
|
|
.#{$namespace}-sub-menu-content, |
|
|
|
.#{$namespace}-menu-item { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
padding: var(--menu-item-collapse-padding-y) |
|
|
|
var(--menu-item-collapse-padding-x); |
|
|
|
margin: var(--menu-item-collapse-margin-y) |
|
|
|
var(--menu-item-collapse-margin-x); |
|
|
|
transition: all 0.3s; |
|
|
|
|
|
|
|
&.is-active { |
|
|
|
background: var(--menu-item-active-background-color) !important; |
|
|
|
border-radius: var(--menu-item-radius); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&.is-light { |
|
|
|
.#{$namespace}-sub-menu-content, |
|
|
|
.#{$namespace}-menu-item { |
|
|
|
&.is-active { |
|
|
|
color: hsl(var(--primary-foreground)) !important; |
|
|
|
background: var(--menu-item-active-background-color) !important; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&.is-rounded { |
|
|
|
.#{$namespace}-sub-menu-content, |
|
|
|
.#{$namespace}-menu-item { |
|
|
|
&.is-collapse-show-title { |
|
|
|
// padding: 32px 0 !important; |
|
|
|
margin: 4px 8px !important; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&__popup-container { |
|
|
|
max-width: 240px; |
|
|
|
height: unset; |
|
|
|
padding: 0; |
|
|
|
background: var(--menu-background-color); |
|
|
|
} |
|
|
|
|
|
|
|
&__popup { |
|
|
|
padding: 4px 0; |
|
|
|
border-radius: var(--menu-item-radius); |
|
|
|
|
|
|
|
.#{$namespace}-sub-menu-content, |
|
|
|
.#{$namespace}-menu-item { |
|
|
|
padding: var(--menu-item-popup-padding-y) var(--menu-item-popup-padding-x); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&__icon { |
|
|
|
flex-shrink: 0; |
|
|
|
// width: var(--menu-item-icon-width); |
|
|
|
max-height: var(--menu-item-icon-width); |
|
|
|
margin-right: 12px; |
|
|
|
font-size: 20px; |
|
|
|
text-align: center; |
|
|
|
vertical-align: middle; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.#{$namespace}-menu-item { |
|
|
|
fill: var(--menu-item-color); |
|
|
|
stroke: var(--menu-item-color); |
|
|
|
|
|
|
|
@include menu-item; |
|
|
|
|
|
|
|
&.is-active { |
|
|
|
fill: var(--menu-item-active-color); |
|
|
|
stroke: var(--menu-item-active-color); |
|
|
|
|
|
|
|
@include menu-item-active; |
|
|
|
} |
|
|
|
|
|
|
|
&__content { |
|
|
|
display: inline-flex; |
|
|
|
align-items: center; |
|
|
|
width: 100%; |
|
|
|
height: var(--menu-item-height); |
|
|
|
} |
|
|
|
|
|
|
|
&.is-collapse-show-title { |
|
|
|
padding: 32px 0 !important; |
|
|
|
// margin: 4px 8px !important; |
|
|
|
.#{$namespace}-menu-tooltip__trigger { |
|
|
|
flex-direction: column; |
|
|
|
} |
|
|
|
.#{$namespace}-menu__icon { |
|
|
|
display: block; |
|
|
|
font-size: 20px !important; |
|
|
|
transition: all 0.25s ease; |
|
|
|
} |
|
|
|
|
|
|
|
.#{$namespace}-menu__name { |
|
|
|
display: inline-flex; |
|
|
|
margin-top: 8px; |
|
|
|
margin-bottom: 0; |
|
|
|
font-size: 12px; |
|
|
|
font-weight: 400; |
|
|
|
line-height: normal; |
|
|
|
transition: all 0.25s ease; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&:not(.is-active):hover { |
|
|
|
color: var(--menu-item-hover-color); |
|
|
|
text-decoration: none; |
|
|
|
cursor: pointer; |
|
|
|
background: var(--menu-item-hover-background-color) !important; |
|
|
|
} |
|
|
|
|
|
|
|
.#{$namespace}-menu-tooltip__trigger { |
|
|
|
position: absolute; |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
box-sizing: border-box; |
|
|
|
display: inline-flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
padding: 0 var(--menu-item-padding-x); |
|
|
|
font-size: var(--menu-font-size); |
|
|
|
line-height: var(--menu-item-height); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.#{$namespace}-sub-menu { |
|
|
|
padding-left: 0; |
|
|
|
margin: 0; |
|
|
|
list-style: none; |
|
|
|
background: var(--menu-submenu-background-color); |
|
|
|
fill: var(--menu-item-color); |
|
|
|
stroke: var(--menu-item-color); |
|
|
|
|
|
|
|
&.is-active { |
|
|
|
div[data-state='open'] > .#{$namespace}-sub-menu-content, |
|
|
|
> .#{$namespace}-sub-menu-content { |
|
|
|
color: var(--menu-submenu-active-color); |
|
|
|
text-decoration: none; |
|
|
|
cursor: pointer; |
|
|
|
background: var(--menu-submenu-active-background-color); |
|
|
|
fill: var(--menu-submenu-active-color); |
|
|
|
stroke: var(--menu-submenu-active-color); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.#{$namespace}-sub-menu-content { |
|
|
|
height: var(--menu-item-height); |
|
|
|
|
|
|
|
@include menu-item; |
|
|
|
|
|
|
|
&__icon-arrow { |
|
|
|
position: absolute; |
|
|
|
top: 50%; |
|
|
|
right: 6px; |
|
|
|
width: inherit; |
|
|
|
margin-top: -8px; |
|
|
|
margin-right: 0; |
|
|
|
font-size: 16px; |
|
|
|
font-weight: normal; |
|
|
|
opacity: 1; |
|
|
|
transition: transform 0.25s ease; |
|
|
|
} |
|
|
|
|
|
|
|
&__title { |
|
|
|
@include menu-title; |
|
|
|
} |
|
|
|
|
|
|
|
&.is-collapse-show-title { |
|
|
|
flex-direction: column; |
|
|
|
padding: 32px 0 !important; |
|
|
|
// margin: 4px 8px !important; |
|
|
|
.#{$namespace}-menu__icon { |
|
|
|
display: block; |
|
|
|
font-size: 20px !important; |
|
|
|
transition: all 0.25s ease; |
|
|
|
} |
|
|
|
.#{$namespace}-sub-menu-content__title { |
|
|
|
display: inline-flex; |
|
|
|
flex-shrink: 0; |
|
|
|
margin-top: 8px; |
|
|
|
margin-bottom: 0; |
|
|
|
font-size: 12px; |
|
|
|
font-weight: 400; |
|
|
|
line-height: normal; |
|
|
|
transition: all 0.25s ease; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&.is-more { |
|
|
|
padding-right: 12px !important; |
|
|
|
} |
|
|
|
|
|
|
|
// &:not(.is-active):hover { |
|
|
|
&:hover { |
|
|
|
color: var(--menu-submenu-hover-color); |
|
|
|
text-decoration: none; |
|
|
|
cursor: pointer; |
|
|
|
background: var(--menu-submenu-hover-background-color) !important; |
|
|
|
|
|
|
|
svg { |
|
|
|
fill: var(--menu-submenu-hover-color); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
</style> |
|
|
|
|