perf: improve overall theme color matching
This commit is contained in:
@@ -37,6 +37,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@vben-core/hooks": "workspace:*",
|
||||
"@vben-core/icons": "workspace:*",
|
||||
"@vben-core/shadcn-ui": "workspace:*",
|
||||
"@vben-core/toolkit": "workspace:*",
|
||||
|
@@ -2,11 +2,9 @@
|
||||
import type { ContentCompactType } from '@vben-core/typings';
|
||||
|
||||
import type { CSSProperties } from 'vue';
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { getElementVisibleHeight } from '@vben-core/toolkit';
|
||||
|
||||
import { useCssVar, useDebounceFn, useWindowSize } from '@vueuse/core';
|
||||
import { useContentHeightListener } from '@vben-core/hooks';
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
@@ -56,13 +54,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
paddingTop: 16,
|
||||
});
|
||||
|
||||
const contentElement = ref<HTMLDivElement | null>();
|
||||
|
||||
const { height, width } = useWindowSize();
|
||||
const contentClientHeight = useCssVar('--vben-content-client-height');
|
||||
const debouncedCalcHeight = useDebounceFn(() => {
|
||||
contentClientHeight.value = `${getElementVisibleHeight(contentElement.value)}px`;
|
||||
}, 200);
|
||||
const { contentElement } = useContentHeightListener();
|
||||
|
||||
const style = computed((): CSSProperties => {
|
||||
const {
|
||||
@@ -88,14 +80,6 @@ const style = computed((): CSSProperties => {
|
||||
paddingTop: `${paddingTop}px`,
|
||||
};
|
||||
});
|
||||
|
||||
watch([height, width], () => {
|
||||
debouncedCalcHeight();
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
debouncedCalcHeight();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@@ -7,10 +7,6 @@ import { VbenScrollbar } from '@vben-core/shadcn-ui';
|
||||
import { SidebarCollapseButton, SidebarFixedButton } from './widgets';
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* 背景颜色
|
||||
*/
|
||||
backgroundColor: string;
|
||||
/**
|
||||
* 折叠区域高度
|
||||
* @default 32
|
||||
@@ -26,10 +22,6 @@ interface Props {
|
||||
* @default true
|
||||
*/
|
||||
domVisible?: boolean;
|
||||
/**
|
||||
* 扩展区域背景颜色
|
||||
*/
|
||||
extraBackgroundColor: string;
|
||||
/**
|
||||
* 扩展区域宽度
|
||||
* @default 180
|
||||
@@ -113,15 +105,15 @@ const slots = useSlots();
|
||||
|
||||
const asideRef = shallowRef<HTMLDivElement | null>();
|
||||
|
||||
const hiddenSideStyle = computed((): CSSProperties => {
|
||||
return calcMenuWidthStyle(true);
|
||||
});
|
||||
const hiddenSideStyle = computed((): CSSProperties => calcMenuWidthStyle(true));
|
||||
|
||||
const isDark = computed(() => props.theme === 'dark');
|
||||
|
||||
const style = computed((): CSSProperties => {
|
||||
const { isSidebarMixed, paddingTop, theme, zIndex } = props;
|
||||
const { isSidebarMixed, paddingTop, zIndex } = props;
|
||||
|
||||
return {
|
||||
'--scroll-shadow': theme === 'dark' ? 'var(--menu-dark)' : 'var(--menu)',
|
||||
'--scroll-shadow': isDark.value ? 'var(--menu-dark)' : 'var(--menu)',
|
||||
...calcMenuWidthStyle(false),
|
||||
paddingTop: `${paddingTop}px`,
|
||||
zIndex,
|
||||
@@ -130,9 +122,14 @@ const style = computed((): CSSProperties => {
|
||||
});
|
||||
|
||||
const extraStyle = computed((): CSSProperties => {
|
||||
const { extraBackgroundColor, extraWidth, show, width, zIndex } = props;
|
||||
const { extraWidth, show, width, zIndex } = props;
|
||||
|
||||
const backgroundColor = isDark.value
|
||||
? 'hsl(var(--menu-dark))'
|
||||
: 'hsl(var(--menu))';
|
||||
|
||||
return {
|
||||
backgroundColor: extraBackgroundColor,
|
||||
backgroundColor,
|
||||
left: `${width}px`,
|
||||
width: extraVisible.value && show ? `${extraWidth}px` : 0,
|
||||
zIndex,
|
||||
@@ -196,14 +193,7 @@ watchEffect(() => {
|
||||
});
|
||||
|
||||
function calcMenuWidthStyle(isHiddenDom: boolean): CSSProperties {
|
||||
const {
|
||||
backgroundColor,
|
||||
extraWidth,
|
||||
fixedExtra,
|
||||
isSidebarMixed,
|
||||
show,
|
||||
width,
|
||||
} = props;
|
||||
const { extraWidth, fixedExtra, isSidebarMixed, show, width } = props;
|
||||
|
||||
let widthValue = `${width + (isSidebarMixed && fixedExtra && extraVisible.value ? extraWidth : 0)}px`;
|
||||
|
||||
@@ -213,6 +203,18 @@ function calcMenuWidthStyle(isHiddenDom: boolean): CSSProperties {
|
||||
widthValue = `${collapseWidth}px`;
|
||||
}
|
||||
|
||||
let backgroundColor = '';
|
||||
|
||||
if (isDark.value) {
|
||||
backgroundColor = isSidebarMixed
|
||||
? 'hsl(var(--menu-dark-deep))'
|
||||
: 'hsl(var(--menu-dark))';
|
||||
} else {
|
||||
backgroundColor = isSidebarMixed
|
||||
? 'hsl(var(--menu-deep))'
|
||||
: 'hsl(var(--menu))';
|
||||
}
|
||||
|
||||
return {
|
||||
...(widthValue === '0px' ? { overflow: 'hidden' } : {}),
|
||||
backgroundColor,
|
||||
@@ -254,8 +256,9 @@ function handleMouseleave() {
|
||||
class="h-full transition-all duration-200"
|
||||
></div>
|
||||
<aside
|
||||
:data-theme="theme"
|
||||
:style="style"
|
||||
class="border-border fixed left-0 top-0 h-full border-r transition-all duration-200"
|
||||
class="data-[theme=dark]:border-border-dark border-border fixed left-0 top-0 h-full border-r transition-all duration-200"
|
||||
@mouseenter="handleMouseenter"
|
||||
@mouseleave="handleMouseleave"
|
||||
>
|
||||
@@ -280,8 +283,9 @@ function handleMouseleave() {
|
||||
<div
|
||||
v-if="isSidebarMixed"
|
||||
ref="asideRef"
|
||||
:data-theme="theme"
|
||||
:style="extraStyle"
|
||||
class="fixed top-0 h-full overflow-hidden transition-all duration-200"
|
||||
class="data-[theme=dark]:border-border-dark border-border fixed top-0 h-full overflow-hidden border-x transition-all duration-200"
|
||||
>
|
||||
<SidebarCollapseButton
|
||||
v-if="isSidebarMixed && expandOnHover"
|
||||
@@ -294,10 +298,15 @@ function handleMouseleave() {
|
||||
v-model:expand-on-hover="expandOnHover"
|
||||
:theme="theme"
|
||||
/>
|
||||
<div v-if="!extraCollapse" :style="extraTitleStyle">
|
||||
<div v-if="!extraCollapse" :style="extraTitleStyle" class="pl-2">
|
||||
<slot name="extra-title"></slot>
|
||||
</div>
|
||||
<VbenScrollbar :style="extraContentStyle" class="py-4" shadow>
|
||||
<VbenScrollbar
|
||||
:data-theme="theme"
|
||||
:style="extraContentStyle"
|
||||
class="data-[theme=dark]:border-border-dark border-border border-t py-2"
|
||||
shadow
|
||||
>
|
||||
<slot name="extra"></slot>
|
||||
</VbenScrollbar>
|
||||
</div>
|
||||
|
@@ -5,7 +5,7 @@ interface Props {
|
||||
theme: string;
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {});
|
||||
defineProps<Props>();
|
||||
|
||||
const collapsed = defineModel<boolean>('collapsed');
|
||||
|
||||
@@ -17,7 +17,7 @@ function handleCollapsed() {
|
||||
<template>
|
||||
<div
|
||||
:data-theme="theme"
|
||||
class="flex-center hover:text-foreground text-foreground/60 hover:bg-accent-hover bg-accent absolute bottom-2 left-3 z-10 cursor-pointer rounded-sm p-1 transition-all duration-300 data-[theme=dark]:bg-[hsl(var(--dark-accent))] data-[theme=dark]:text-[hsl(var(--dark-foreground)/60%)] data-[theme=dark]:hover:bg-[hsl(var(--dark-accent-hover))] data-[theme=dark]:hover:text-[hsl(var(--dark-foreground))]"
|
||||
class="flex-center hover:text-foreground text-foreground/60 hover:bg-accent-hover bg-accent data-[theme=dark]:hover:bg-accent-dark-hover data-[theme=dark]:bg-accent-dark data-[theme=dark]:text-foreground-dark/60 data-[theme=dark]:hover:text-foreground-dark absolute bottom-2 left-3 z-10 cursor-pointer rounded-sm p-1 transition-all duration-300"
|
||||
@click.stop="handleCollapsed"
|
||||
>
|
||||
<MdiMenuClose v-if="collapsed" />
|
||||
|
@@ -5,7 +5,7 @@ interface Props {
|
||||
theme: string;
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {});
|
||||
defineProps<Props>();
|
||||
|
||||
const expandOnHover = defineModel<boolean>('expandOnHover');
|
||||
|
||||
@@ -17,7 +17,7 @@ function toggleFixed() {
|
||||
<template>
|
||||
<div
|
||||
:data-theme="theme"
|
||||
class="flex-center hover:text-foreground text-foreground/60 hover:bg-accent-hover bg-accent absolute bottom-2 right-3 z-10 cursor-pointer rounded-sm p-1 transition-all duration-300 data-[theme=dark]:bg-[hsl(var(--dark-accent))] data-[theme=dark]:text-[hsl(var(--dark-foreground)/60%)] data-[theme=dark]:hover:bg-[hsl(var(--dark-accent-hover))] data-[theme=dark]:hover:text-[hsl(var(--dark-foreground))]"
|
||||
class="flex-center hover:text-foreground text-foreground/60 hover:bg-accent-hover bg-accent data-[theme=dark]:hover:bg-accent-dark-hover data-[theme=dark]:bg-accent-dark data-[theme=dark]:text-foreground-dark/60 data-[theme=dark]:hover:text-foreground-dark absolute bottom-2 right-3 z-10 cursor-pointer rounded-sm p-1 transition-all duration-300"
|
||||
@click="toggleFixed"
|
||||
>
|
||||
<MdiPinOff v-if="!expandOnHover" />
|
||||
|
@@ -41,11 +41,6 @@ interface VbenLayoutProps {
|
||||
* @default 16
|
||||
*/
|
||||
contentPaddingTop?: number;
|
||||
/**
|
||||
* footer背景颜色
|
||||
* @default #fff
|
||||
*/
|
||||
footerBackgroundColor?: string;
|
||||
/**
|
||||
* footer 是否可见
|
||||
* @default false
|
||||
@@ -61,11 +56,7 @@ interface VbenLayoutProps {
|
||||
* @default 32
|
||||
*/
|
||||
footerHeight?: number;
|
||||
/**
|
||||
* 背景颜色
|
||||
* @default #fff
|
||||
*/
|
||||
headerBackgroundColor?: string;
|
||||
|
||||
/**
|
||||
* header高度
|
||||
* @default 48
|
||||
@@ -157,11 +148,6 @@ interface VbenLayoutProps {
|
||||
* @default 210
|
||||
*/
|
||||
sidebarWidth?: number;
|
||||
/**
|
||||
* footer背景颜色
|
||||
* @default #fff
|
||||
*/
|
||||
tabbarBackgroundColor?: string;
|
||||
/**
|
||||
* tab是否可见
|
||||
* @default true
|
||||
|
@@ -205,25 +205,7 @@ const showSidebar = computed(() => {
|
||||
const sidebarFace = computed(() => {
|
||||
const { sidebarSemiDark, sidebarTheme } = props;
|
||||
const isDark = sidebarTheme === 'dark' || sidebarSemiDark;
|
||||
|
||||
let backgroundColor = '';
|
||||
let extraBackgroundColor = '';
|
||||
|
||||
if (isDark) {
|
||||
backgroundColor = isSidebarMixedNav.value
|
||||
? 'hsl(var(--menu-dark-deep))'
|
||||
: 'hsl(var(--menu-dark))';
|
||||
} else {
|
||||
backgroundColor = isSidebarMixedNav.value
|
||||
? 'hsl(var(--menu-deep))'
|
||||
: 'hsl(var(--menu))';
|
||||
}
|
||||
|
||||
extraBackgroundColor = isDark ? 'hsl(var(--menu-dark))' : 'hsl(var(--menu))';
|
||||
|
||||
return {
|
||||
backgroundColor,
|
||||
extraBackgroundColor,
|
||||
theme: isDark ? 'dark' : 'light',
|
||||
};
|
||||
});
|
||||
@@ -476,9 +458,9 @@ function handleOpenMenu() {
|
||||
:mixed-width="sidebarMixedWidth"
|
||||
:padding-top="sidePaddingTop"
|
||||
:show="showSidebar"
|
||||
:theme="sidebarFace.theme"
|
||||
:width="getSidebarWidth"
|
||||
:z-index="sidebarZIndex"
|
||||
v-bind="sidebarFace"
|
||||
@leave="() => emit('sideMouseLeave')"
|
||||
>
|
||||
<template v-if="isSideMode && !isMixedNav" #logo>
|
||||
|
@@ -423,9 +423,9 @@ $namespace: vben;
|
||||
--menu-title-width: 140px;
|
||||
--menu-item-icon-width: 20px;
|
||||
--menu-item-height: 38px;
|
||||
--menu-item-padding-y: 26px;
|
||||
--menu-item-padding-y: 22px;
|
||||
--menu-item-padding-x: 12px;
|
||||
--menu-item-popup-padding-y: 22px;
|
||||
--menu-item-popup-padding-y: 20px;
|
||||
--menu-item-popup-padding-x: 12px;
|
||||
--menu-item-margin-y: 4px;
|
||||
--menu-item-margin-x: 0px;
|
||||
@@ -443,14 +443,14 @@ $namespace: vben;
|
||||
--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-color: hsl(var(--foreground-dark) / 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-item-active-color: hsl(var(--foreground-dark));
|
||||
--menu-item-active-background-color: hsl(var(--menu-dark-background));
|
||||
--menu-submenu-hover-color: hsl(var(--foreground-dark));
|
||||
--menu-submenu-hover-background-color: hsl(var(--menu-dark-background));
|
||||
--menu-submenu-active-color: hsl(var(--dark-foreground));
|
||||
--menu-submenu-active-color: hsl(var(--foreground-dark));
|
||||
--menu-submenu-active-background-color: transparent;
|
||||
--menu-submenu-background-color: var(--menu-background-color);
|
||||
}
|
||||
@@ -462,8 +462,8 @@ $namespace: vben;
|
||||
--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-item-active-color: hsl(var(--primary));
|
||||
--menu-item-active-background-color: hsl(var(--primary) / 15%);
|
||||
--menu-submenu-hover-color: hsl(var(--primary));
|
||||
--menu-submenu-hover-background-color: hsl(var(--menu-light-background));
|
||||
--menu-submenu-active-color: hsl(var(--primary));
|
||||
@@ -512,10 +512,10 @@ $namespace: vben;
|
||||
--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-active-color: hsl(var(--primary));
|
||||
--menu-submenu-active-background-color: hsl(var(--primary) / 15%);
|
||||
--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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -666,7 +666,7 @@ $namespace: vben;
|
||||
.#{$namespace}-sub-menu-content,
|
||||
.#{$namespace}-menu-item {
|
||||
&.is-active {
|
||||
color: hsl(var(--primary-foreground)) !important;
|
||||
// color: hsl(var(--primary-foreground)) !important;
|
||||
background: var(--menu-item-active-background-color) !important;
|
||||
}
|
||||
}
|
||||
@@ -788,6 +788,7 @@ $namespace: vben;
|
||||
&.is-active {
|
||||
div[data-state='open'] > .#{$namespace}-sub-menu-content,
|
||||
> .#{$namespace}-sub-menu-content {
|
||||
font-weight: 500;
|
||||
color: var(--menu-submenu-active-color);
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
@@ -806,7 +807,7 @@ $namespace: vben;
|
||||
&__icon-arrow {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 6px;
|
||||
right: 10px;
|
||||
width: inherit;
|
||||
margin-top: -8px;
|
||||
margin-right: 0;
|
||||
|
@@ -63,7 +63,7 @@ $namespace: vben;
|
||||
.#{$namespace}-normal-menu {
|
||||
--menu-item-margin-y: 4px;
|
||||
--menu-item-margin-x: 0px;
|
||||
--menu-item-padding-y: 11px;
|
||||
--menu-item-padding-y: 8px;
|
||||
--menu-item-padding-x: 0px;
|
||||
--menu-item-radius: 0px;
|
||||
--menu-dark-background: 0deg 0% 100% / 10%;
|
||||
@@ -77,12 +77,21 @@ $namespace: vben;
|
||||
|
||||
&.is-dark {
|
||||
.#{$namespace}-normal-menu__item {
|
||||
color: hsl(var(--dark-foreground) / 80%);
|
||||
color: hsl(var(--foreground-dark) / 80%);
|
||||
|
||||
&:not(.is-active):hover {
|
||||
color: hsl(var(--primary-foreground));
|
||||
background-color: hsl(var(--menu-dark-background));
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background-color: hsl(var(--menu-dark-background));
|
||||
|
||||
.#{$namespace}-normal-menu__name,
|
||||
.#{$namespace}-normal-menu__icon {
|
||||
color: hsl(var(--primary-foreground));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,26 +124,21 @@ $namespace: vben;
|
||||
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-active {
|
||||
font-weight: 700;
|
||||
color: hsl(var(--primary-foreground));
|
||||
background-color: hsl(var(--primary));
|
||||
|
||||
.#{$namespace}-normal-menu__name {
|
||||
color: hsl(var(--primary-foreground));
|
||||
}
|
||||
@apply text-primary bg-primary/20;
|
||||
|
||||
.#{$namespace}-normal-menu__name,
|
||||
.#{$namespace}-normal-menu__icon {
|
||||
color: hsl(var(--primary-foreground));
|
||||
@apply text-primary font-semibold;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.is-active):hover {
|
||||
color: hsl(var(--foreground));
|
||||
@apply text-foreground;
|
||||
|
||||
background-color: hsl(var(--menu-dark-background));
|
||||
}
|
||||
|
||||
|
@@ -1,506 +0,0 @@
|
||||
$namespace: vben;
|
||||
|
||||
.#{$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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -66,10 +66,9 @@ const logoClass = computed(() => {
|
||||
/>
|
||||
<span
|
||||
v-if="!collapse"
|
||||
class="text-primary truncate text-nowrap group-[.dark]:text-[hsl(var(--dark-foreground))]"
|
||||
class="text-primary group-[.dark]:text-foreground-dark truncate text-nowrap"
|
||||
>
|
||||
{{ text }}
|
||||
<!-- <span class="text-primary ml-1 align-super text-[smaller]">Pro</span> -->
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
|
@@ -43,7 +43,7 @@ const badgeStyle = computed(() => {
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<span v-if="isDot || badge" :class="$attrs.class" class="absolute right-5">
|
||||
<span v-if="isDot || badge" :class="$attrs.class" class="absolute right-6">
|
||||
<BadgeDot v-if="isDot" :dot-class="badgeClass" :dot-style="badgeStyle" />
|
||||
<div
|
||||
v-else
|
||||
|
@@ -6,7 +6,7 @@ import type { TabConfig, TabsProps } from '../../types';
|
||||
import { computed, nextTick, onMounted, ref, watch } from 'vue';
|
||||
|
||||
import { IcRoundClose, MdiPin } from '@vben-core/icons';
|
||||
import { VbenContextMenu, VbenIcon } from '@vben-core/shadcn-ui';
|
||||
import { VbenContextMenu, VbenIcon, VbenScrollbar } from '@vben-core/shadcn-ui';
|
||||
|
||||
interface Props extends TabsProps {}
|
||||
|
||||
@@ -21,7 +21,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
contextMenus: () => [],
|
||||
gap: 7,
|
||||
maxWidth: 150,
|
||||
minWidth: 40,
|
||||
minWidth: 80,
|
||||
tabs: () => [],
|
||||
});
|
||||
|
||||
@@ -40,20 +40,20 @@ const style = computed(() => {
|
||||
});
|
||||
|
||||
const layout = () => {
|
||||
const { gap, maxWidth, minWidth, tabs } = props;
|
||||
const { maxWidth, minWidth } = props;
|
||||
if (!contentRef.value) {
|
||||
return Math.max(maxWidth, minWidth);
|
||||
}
|
||||
const contentWidth = contentRef.value.clientWidth - gap * 3;
|
||||
let width = contentWidth / tabs.length;
|
||||
width += gap * 2;
|
||||
if (width > maxWidth) {
|
||||
width = maxWidth;
|
||||
}
|
||||
if (width < minWidth) {
|
||||
width = minWidth;
|
||||
}
|
||||
tabWidth.value = width;
|
||||
// const contentWidth = contentRef.value.clientWidth - gap * 3;
|
||||
// let width = contentWidth / tabs.length;
|
||||
// width += gap * 2;
|
||||
// if (width > maxWidth) {
|
||||
// width = maxWidth;
|
||||
// }
|
||||
// if (width < minWidth) {
|
||||
// width = minWidth;
|
||||
// }
|
||||
tabWidth.value = maxWidth;
|
||||
};
|
||||
|
||||
const tabsView = computed((): TabConfig[] => {
|
||||
@@ -95,121 +95,115 @@ function handleUnpinTab(tab: TabConfig) {
|
||||
|
||||
<template>
|
||||
<div :style="style" class="tabs-chrome size-full flex-1 overflow-hidden pt-1">
|
||||
<!-- footer -> 4px -->
|
||||
<div
|
||||
ref="contentRef"
|
||||
:class="contentClass"
|
||||
class="relative h-full overflow-hidden"
|
||||
>
|
||||
<TransitionGroup name="slide-down">
|
||||
<div
|
||||
v-for="(tab, i) in tabsView"
|
||||
:key="tab.key"
|
||||
ref="tabRef"
|
||||
:class="[
|
||||
{ 'is-active': tab.key === active, dragable: !tab.affixTab },
|
||||
]"
|
||||
:data-index="i"
|
||||
:style="{
|
||||
width: `${tabWidth}px`,
|
||||
left: `${(tabWidth - gap * 2) * i}px`,
|
||||
}"
|
||||
class="tabs-chrome__item group absolute flex h-full select-none items-center transition-all"
|
||||
@click="active = tab.key"
|
||||
>
|
||||
<VbenContextMenu
|
||||
:handler-data="tab"
|
||||
:menus="contextMenus"
|
||||
:modal="false"
|
||||
item-class="pr-6"
|
||||
<VbenScrollbar class="h-full" horizontal>
|
||||
<!-- footer -> 4px -->
|
||||
<div
|
||||
ref="contentRef"
|
||||
:class="contentClass"
|
||||
class="relative !flex h-full w-max"
|
||||
>
|
||||
<TransitionGroup name="slide-down">
|
||||
<div
|
||||
v-for="(tab, i) in tabsView"
|
||||
:key="tab.key"
|
||||
ref="tabRef"
|
||||
:class="[
|
||||
{ 'is-active': tab.key === active, dragable: !tab.affixTab },
|
||||
]"
|
||||
:data-index="i"
|
||||
:style="{
|
||||
width: `${tabWidth}px`,
|
||||
left: `${(tabWidth - gap * 2) * i}px`,
|
||||
}"
|
||||
class="tabs-chrome__item group absolute flex h-full select-none items-center transition-all"
|
||||
@click="active = tab.key"
|
||||
>
|
||||
<div class="size-full">
|
||||
<!-- divider -->
|
||||
<div
|
||||
v-if="i !== 0"
|
||||
class="tabs-chrome__divider bg-foreground/80 absolute left-[var(--gap)] top-1/2 z-0 h-4 w-[1px] translate-y-[-50%] transition-all"
|
||||
></div>
|
||||
<!-- background -->
|
||||
<div
|
||||
class="tabs-chrome__background absolute z-[1] size-full px-[calc(var(--gap)-1px)] py-0 transition-opacity duration-150"
|
||||
>
|
||||
<VbenContextMenu
|
||||
:handler-data="tab"
|
||||
:menus="contextMenus"
|
||||
:modal="false"
|
||||
item-class="pr-6"
|
||||
>
|
||||
<div class="size-full">
|
||||
<!-- divider -->
|
||||
<div
|
||||
class="tabs-chrome__background-content h-full rounded-tl-[var(--gap)] rounded-tr-[var(--gap)] duration-150"
|
||||
v-if="i !== 0 && tab.key !== active"
|
||||
class="tabs-chrome__divider bg-foreground/80 absolute left-[var(--gap)] top-1/2 z-0 h-4 w-[1px] translate-y-[-50%] transition-all"
|
||||
></div>
|
||||
<svg
|
||||
class="tabs-chrome__background-before absolute bottom-[-1px] left-[-1px] fill-transparent transition-all duration-150"
|
||||
height="7"
|
||||
width="7"
|
||||
<!-- background -->
|
||||
<div
|
||||
class="tabs-chrome__background absolute z-[1] size-full px-[calc(var(--gap)-1px)] py-0 transition-opacity duration-150"
|
||||
>
|
||||
<path d="M 0 7 A 7 7 0 0 0 7 0 L 7 7 Z" />
|
||||
</svg>
|
||||
<svg
|
||||
class="tabs-chrome__background-after absolute bottom-[-1px] right-[-1px] fill-transparent transition-all duration-150"
|
||||
height="7"
|
||||
width="7"
|
||||
>
|
||||
<path d="M 0 0 A 7 7 0 0 0 7 7 L 0 7 Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="tabs-chrome__background-content h-full rounded-tl-[var(--gap)] rounded-tr-[var(--gap)] duration-150"
|
||||
></div>
|
||||
<svg
|
||||
class="tabs-chrome__background-before absolute bottom-[-1px] left-[-1px] fill-transparent transition-all duration-150"
|
||||
height="7"
|
||||
width="7"
|
||||
>
|
||||
<path d="M 0 7 A 7 7 0 0 0 7 0 L 7 7 Z" />
|
||||
</svg>
|
||||
<svg
|
||||
class="tabs-chrome__background-after absolute bottom-[-1px] right-[-1px] fill-transparent transition-all duration-150"
|
||||
height="7"
|
||||
width="7"
|
||||
>
|
||||
<path d="M 0 0 A 7 7 0 0 0 7 7 L 0 7 Z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- extra -->
|
||||
<div
|
||||
class="tabs-chrome__extra absolute right-[calc(var(--gap)*2)] top-1/2 z-[3] size-4 translate-y-[-50%]"
|
||||
>
|
||||
<!-- <div
|
||||
<!-- extra -->
|
||||
<div
|
||||
class="tabs-chrome__extra absolute right-[calc(var(--gap)*1.5)] top-1/2 z-[3] size-4 translate-y-[-50%]"
|
||||
>
|
||||
<!-- <div
|
||||
class="tabs-chrome__extra absolute right-[calc(var(--gap)*2)] top-1/2 z-[3] size-4 translate-y-[-50%] opacity-0 transition-opacity group-hover:opacity-100"
|
||||
> -->
|
||||
<!-- close-icon -->
|
||||
<IcRoundClose
|
||||
v-show="!tab.affixTab && tabsView.length > 1 && tab.closable"
|
||||
class="hover:bg-accent stroke-accent-foreground/80 hover:stroke-accent-foreground group-[.is-active]:text-primary mt-[2px] size-3 cursor-pointer rounded-full transition-all"
|
||||
@click.stop="handleClose(tab.key)"
|
||||
/>
|
||||
<MdiPin
|
||||
v-show="tab.affixTab && tabsView.length > 1 && tab.closable"
|
||||
class="hover:bg-accent hover:stroke-accent-foreground group-[.is-active]:text-primary mt-[2px] size-3.5 cursor-pointer rounded-full transition-all"
|
||||
@click.stop="handleUnpinTab(tab)"
|
||||
/>
|
||||
</div>
|
||||
<!-- close-icon -->
|
||||
<IcRoundClose
|
||||
v-show="
|
||||
!tab.affixTab && tabsView.length > 1 && tab.closable
|
||||
"
|
||||
class="hover:bg-accent stroke-accent-foreground/80 hover:stroke-accent-foreground group-[.is-active]:text-primary mt-[2px] size-3 cursor-pointer rounded-full transition-all"
|
||||
@click.stop="handleClose(tab.key)"
|
||||
/>
|
||||
<MdiPin
|
||||
v-show="tab.affixTab && tabsView.length > 1 && tab.closable"
|
||||
class="hover:bg-accent hover:stroke-accent-foreground group-[.is-active]:text-primary mt-[2px] size-3.5 cursor-pointer rounded-full transition-all"
|
||||
@click.stop="handleUnpinTab(tab)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- tab-item-main -->
|
||||
<div
|
||||
class="tabs-chrome__item-main group-[.is-active]:text-primary text-accent-foreground absolute left-0 right-0 z-[2] mx-[calc(var(--gap)*2)] my-0 flex h-full items-center overflow-hidden rounded-tl-[5px] rounded-tr-[5px] pr-4 duration-150 group-hover:pr-3 group-[.is-active]:font-semibold"
|
||||
>
|
||||
<VbenIcon
|
||||
v-if="showIcon"
|
||||
:icon="tab.icon"
|
||||
class="ml-[var(--gap)] flex size-4 items-center overflow-hidden"
|
||||
fallback
|
||||
/>
|
||||
|
||||
<span
|
||||
class="tabs-chrome__label ml-[var(--gap)] flex-1 overflow-hidden whitespace-nowrap"
|
||||
<!-- tab-item-main -->
|
||||
<div
|
||||
class="tabs-chrome__item-main group-[.is-active]:text-primary text-accent-foreground absolute left-0 right-0 z-[2] mx-[calc(var(--gap)*2)] my-0 flex h-full items-center overflow-hidden rounded-tl-[5px] rounded-tr-[5px] pr-4 duration-150 group-hover:pr-3"
|
||||
>
|
||||
{{ tab.title }}
|
||||
</span>
|
||||
<VbenIcon
|
||||
v-if="showIcon"
|
||||
:icon="tab.icon"
|
||||
class="ml-[var(--gap)] flex size-4 items-center overflow-hidden"
|
||||
fallback
|
||||
/>
|
||||
|
||||
<span
|
||||
class="tabs-chrome__label ml-[var(--gap)] flex-1 overflow-hidden whitespace-nowrap"
|
||||
>
|
||||
{{ tab.title }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</VbenContextMenu>
|
||||
</div>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
<!-- footer -->
|
||||
<div class="bg-background h-1"></div>
|
||||
</VbenContextMenu>
|
||||
</div>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
<!-- footer -->
|
||||
<div class="bg-background h-1"></div>
|
||||
</VbenScrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* html.dark {
|
||||
.tabs-chrome {
|
||||
.is-active {
|
||||
.tabs-chrome__item-main {
|
||||
@apply text-accent-foreground;
|
||||
}
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
.tabs-chrome {
|
||||
.dragging {
|
||||
.tabs-chrome__item-main {
|
||||
@@ -222,7 +216,7 @@ function handleUnpinTab(tab: TabConfig) {
|
||||
}
|
||||
|
||||
&__item {
|
||||
&:hover {
|
||||
&:hover:not(.is-active) {
|
||||
& + .tabs-chrome__item {
|
||||
.tabs-chrome__divider {
|
||||
@apply opacity-0;
|
||||
@@ -235,12 +229,12 @@ function handleUnpinTab(tab: TabConfig) {
|
||||
|
||||
.tabs-chrome__background {
|
||||
&-content {
|
||||
@apply bg-heavy;
|
||||
@apply bg-primary/10 mx-1 rounded-md pb-2;
|
||||
}
|
||||
|
||||
&-before,
|
||||
&-after {
|
||||
@apply fill-heavy;
|
||||
@apply fill-primary/0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,16 +242,22 @@ function handleUnpinTab(tab: TabConfig) {
|
||||
&.is-active {
|
||||
@apply z-[2];
|
||||
|
||||
& + .tabs-chrome__item {
|
||||
.tabs-chrome__divider {
|
||||
@apply opacity-0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.tabs-chrome__background {
|
||||
@apply opacity-100;
|
||||
|
||||
&-content {
|
||||
@apply bg-background-content;
|
||||
@apply bg-primary/15;
|
||||
}
|
||||
|
||||
&-before,
|
||||
&-after {
|
||||
@apply fill-background-content;
|
||||
@apply fill-primary/15;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -26,14 +26,14 @@ const active = defineModel<string>('active');
|
||||
const typeWithClass = computed(() => {
|
||||
const typeClasses: Record<string, { content: string }> = {
|
||||
brisk: {
|
||||
content: `h-full after:content-[''] after:absolute after:bottom-0 after:left-0 after:w-full after:h-[1.5px] after:bg-primary after:scale-x-0 after:transition-[transform] after:ease-out after:duration-300 hover:after:scale-x-100 after:origin-left [&.is-active]:after:scale-x-100`,
|
||||
content: `h-full after:content-[''] after:absolute after:bottom-0 after:left-0 after:w-full after:h-[1.5px] after:bg-primary after:scale-x-0 after:transition-[transform] after:ease-out after:duration-300 hover:after:scale-x-100 after:origin-left [&.is-active]:after:scale-x-100 border-l border-border`,
|
||||
},
|
||||
card: {
|
||||
content:
|
||||
'h-[calc(100%-6px)] rounded-md mr-2 border-border [&.is-active]:border-primary border transition-all',
|
||||
'h-[calc(100%-6px)] rounded-md ml-2 border border-border transition-all',
|
||||
},
|
||||
plain: {
|
||||
content: 'h-full',
|
||||
content: 'h-full border-l border-border',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -77,7 +77,7 @@ function handleUnpinTab(tab: TabConfig) {
|
||||
:key="tab.key"
|
||||
:class="[
|
||||
{
|
||||
'tabs-item is-active bg-background-content': tab.key === active,
|
||||
'is-active bg-primary/15': tab.key === active,
|
||||
dragable: !tab.affixTab,
|
||||
},
|
||||
typeWithClass.content,
|
||||
@@ -110,14 +110,14 @@ function handleUnpinTab(tab: TabConfig) {
|
||||
/>
|
||||
<MdiPin
|
||||
v-show="tab.affixTab && tabsView.length > 1 && tab.closable"
|
||||
class="hover:bg-accent hover:stroke-accent-foreground group-[.is-active]:text-primary mt-[2px] size-3.5 cursor-pointer rounded-full transition-all"
|
||||
class="hover:bg-heavy hover:stroke-accent-foreground group-[.is-active]:text-primary mt-[2px] size-3.5 cursor-pointer rounded-full transition-all"
|
||||
@click.stop="handleUnpinTab(tab)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- tab-item-main -->
|
||||
<div
|
||||
class="tabs-item__main group-[.is-active]:text-primary text-accent-foreground mx-3 mr-4 flex h-full items-center overflow-hidden rounded-tl-[5px] rounded-tr-[5px] pr-3 transition-all duration-300"
|
||||
class="group-[.is-active]:text-primary text-accent-foreground mx-3 mr-4 flex h-full items-center overflow-hidden rounded-tl-[5px] rounded-tr-[5px] pr-3 transition-all duration-300"
|
||||
>
|
||||
<!-- <div
|
||||
class="mx-3 ml-3 mr-2 flex h-full items-center overflow-hidden rounded-tl-[5px] rounded-tr-[5px] transition-all duration-300 group-hover:mr-2 group-hover:pr-4 group-[.is-active]:pr-4"
|
||||
@@ -141,15 +141,3 @@ function handleUnpinTab(tab: TabConfig) {
|
||||
</VbenScrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* html.dark {
|
||||
.tabs-item {
|
||||
&.is-active {
|
||||
.tabs-item__main {
|
||||
@apply text-accent-foreground;
|
||||
}
|
||||
}
|
||||
}
|
||||
} */
|
||||
</style>
|
||||
|
Reference in New Issue
Block a user