Merge branch 'main' into refactor/router-redirect
This commit is contained in:
@@ -68,6 +68,8 @@ const defaultPreferences: Preferences = {
|
||||
enable: true,
|
||||
fit: 'contain',
|
||||
source: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
|
||||
showText: true,
|
||||
logoMode: 'icon',
|
||||
},
|
||||
navigation: {
|
||||
accordion: true,
|
||||
|
||||
@@ -228,6 +228,12 @@ interface LogoPreferences {
|
||||
enable: boolean;
|
||||
/** logo图片适应方式 */
|
||||
fit: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
|
||||
/** logo高度, 只在 logoMode=full时生效 */
|
||||
fullLogoHeight?: number | string;
|
||||
/** logo 展示类型,icon 图标模式, full 铺满logo区域 */
|
||||
logoMode: 'full' | 'icon';
|
||||
/** logo text是否展示 */
|
||||
showText: boolean;
|
||||
/** logo地址 */
|
||||
source: string;
|
||||
/** 暗色主题logo地址 (可选,若不设置则使用 source) */
|
||||
|
||||
@@ -16,6 +16,10 @@ interface Props {
|
||||
* 是否移动端
|
||||
*/
|
||||
isMobile: boolean;
|
||||
/**
|
||||
* logo是否显示
|
||||
*/
|
||||
logoVisible?: boolean;
|
||||
/**
|
||||
* 是否显示
|
||||
*/
|
||||
@@ -38,7 +42,9 @@ interface Props {
|
||||
zIndex: number;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {});
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
logoVisible: true,
|
||||
});
|
||||
|
||||
const slots = useSlots();
|
||||
|
||||
@@ -54,6 +60,12 @@ const style = computed((): CSSProperties => {
|
||||
});
|
||||
|
||||
const logoStyle = computed((): CSSProperties => {
|
||||
if (!props.logoVisible) {
|
||||
return {
|
||||
minWidth: '12px',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
minWidth: `${props.isMobile ? 40 : props.sidebarWidth}px`,
|
||||
};
|
||||
@@ -66,7 +78,7 @@ const logoStyle = computed((): CSSProperties => {
|
||||
:style="style"
|
||||
class="top-0 flex w-full flex-[0_0_auto] items-center border-b border-border bg-header pl-2 transition-[margin-top] duration-200"
|
||||
>
|
||||
<div v-if="slots.logo" :style="logoStyle">
|
||||
<div v-if="slots.logo || (!logoVisible && !isMobile)" :style="logoStyle">
|
||||
<slot name="logo"></slot>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -26,6 +26,10 @@ interface Props {
|
||||
* @default true
|
||||
*/
|
||||
domVisible?: boolean;
|
||||
/**
|
||||
* 扩展区域extra-title的高度
|
||||
*/
|
||||
extraTitleHeight?: number;
|
||||
/**
|
||||
* 扩展区域宽度
|
||||
*/
|
||||
@@ -97,6 +101,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
collapseHeight: 42,
|
||||
collapseWidth: 48,
|
||||
domVisible: true,
|
||||
extraTitleHeight: undefined,
|
||||
fixedExtra: false,
|
||||
isSidebarMixed: false,
|
||||
marginTop: 0,
|
||||
@@ -149,10 +154,10 @@ const extraStyle = computed((): CSSProperties => {
|
||||
});
|
||||
|
||||
const extraTitleStyle = computed((): CSSProperties => {
|
||||
const { headerHeight } = props;
|
||||
const { extraTitleHeight, headerHeight } = props;
|
||||
|
||||
return {
|
||||
height: `${headerHeight - 1}px`,
|
||||
height: `${extraTitleHeight ?? headerHeight - 1}px`,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -185,9 +190,10 @@ const headerStyle = computed((): CSSProperties => {
|
||||
});
|
||||
|
||||
const extraContentStyle = computed((): CSSProperties => {
|
||||
const { collapseHeight, headerHeight } = props;
|
||||
const { collapseHeight, extraTitleHeight, headerHeight } = props;
|
||||
const titleHeight = extraTitleHeight ?? headerHeight;
|
||||
return {
|
||||
height: `calc(100% - ${headerHeight + collapseHeight}px)`,
|
||||
height: `calc(100% - ${titleHeight + collapseHeight}px)`,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -126,6 +126,10 @@ interface VbenLayoutProps {
|
||||
* @default 48
|
||||
*/
|
||||
sidebarExtraCollapsedWidth?: number;
|
||||
/**
|
||||
* 扩展区域extra-title的高度
|
||||
*/
|
||||
sidebarExtraTitleHeight?: number;
|
||||
/**
|
||||
* 侧边菜单折叠按钮是否固定
|
||||
* @default true
|
||||
@@ -136,6 +140,10 @@ interface VbenLayoutProps {
|
||||
* @default false
|
||||
*/
|
||||
sidebarHidden?: boolean;
|
||||
/**
|
||||
* 侧边栏 Logo 区域是否显示
|
||||
*/
|
||||
sidebarLogoVisible: boolean;
|
||||
/**
|
||||
* 混合侧边栏宽度
|
||||
* @default 80
|
||||
|
||||
@@ -368,6 +368,17 @@ const maskStyle = computed((): CSSProperties => {
|
||||
return { zIndex: props.zIndex };
|
||||
});
|
||||
|
||||
/**
|
||||
* 侧边栏 Logo 区域是否显示
|
||||
*/
|
||||
const sidebarHeaderHeight = computed(() => {
|
||||
if (isMixedNav.value || !props.sidebarLogoVisible) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return props.headerHeight;
|
||||
});
|
||||
|
||||
const showHeaderToggleButton = computed(() => {
|
||||
return (
|
||||
props.isMobile ||
|
||||
@@ -510,7 +521,10 @@ const idMainContent = ELEMENT_ID_MAIN_CONTENT;
|
||||
:dom-visible="!isMobile"
|
||||
:extra-width="sidebarExtraWidth"
|
||||
:fixed-extra="sidebarExpandOnHover"
|
||||
:header-height="isMixedNav ? 0 : headerHeight"
|
||||
:header-height="sidebarHeaderHeight"
|
||||
:extra-title-height="
|
||||
isSidebarMixedNav || isHeaderMixedNav ? sidebarExtraTitleHeight : 0
|
||||
"
|
||||
:is-sidebar-mixed="isSidebarMixedNav || isHeaderMixedNav"
|
||||
:margin-top="sidebarMarginTop"
|
||||
:mixed-width="sidebarMixedWidth"
|
||||
@@ -522,7 +536,7 @@ const idMainContent = ELEMENT_ID_MAIN_CONTENT;
|
||||
@leave="() => emit('sideMouseLeave')"
|
||||
@update:width="(val) => emit('update:sidebarWidth', val)"
|
||||
>
|
||||
<template v-if="isSideMode && !isMixedNav" #logo>
|
||||
<template v-if="isSideMode && !isMixedNav && sidebarLogoVisible" #logo>
|
||||
<slot name="logo"></slot>
|
||||
</template>
|
||||
|
||||
@@ -565,6 +579,7 @@ const idMainContent = ELEMENT_ID_MAIN_CONTENT;
|
||||
:theme="headerTheme"
|
||||
:width="mainStyle.width"
|
||||
:z-index="headerZIndex"
|
||||
:logo-visible="sidebarLogoVisible"
|
||||
>
|
||||
<template v-if="showHeaderLogo" #logo>
|
||||
<slot name="logo"></slot>
|
||||
|
||||
@@ -5,21 +5,33 @@ import { VbenAvatar } from '../avatar';
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* @zh_CN 是否收起文本
|
||||
* @zh_CN 是否收起文本;布局状态,侧边栏收起时隐藏文字。
|
||||
*/
|
||||
collapsed?: boolean;
|
||||
/**
|
||||
* @zh_CN Logo 图片适应方式
|
||||
*/
|
||||
fit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
|
||||
/**
|
||||
* @zh_CN logo高度, 只在 logoMode=full时失效
|
||||
*/
|
||||
fullLogoHeight?: number | string;
|
||||
/**
|
||||
* @zh_CN Logo 跳转地址
|
||||
*/
|
||||
href?: string;
|
||||
/**
|
||||
* @zh_CN logo 展示类型,icon 图标模式, full 铺满logo区域
|
||||
*/
|
||||
logoMode?: 'full' | 'icon';
|
||||
/**
|
||||
* @zh_CN Logo 图片大小
|
||||
*/
|
||||
logoSize?: number;
|
||||
/**
|
||||
* @zh_CN Logo 是否展示文本
|
||||
*/
|
||||
showText?: boolean;
|
||||
/**
|
||||
* @zh_CN Logo 图标
|
||||
*/
|
||||
@@ -28,10 +40,12 @@ interface Props {
|
||||
* @zh_CN 暗色主题 Logo 图标 (可选,若不设置则使用 src)
|
||||
*/
|
||||
srcDark?: string;
|
||||
|
||||
/**
|
||||
* @zh_CN Logo 文本
|
||||
*/
|
||||
text: string;
|
||||
|
||||
/**
|
||||
* @zh_CN Logo 主题
|
||||
*/
|
||||
@@ -45,11 +59,14 @@ defineOptions({
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
collapsed: false,
|
||||
href: 'javascript:void 0',
|
||||
logoMode: 'icon',
|
||||
logoSize: 32,
|
||||
fullLogoHeight: 42,
|
||||
src: '',
|
||||
srcDark: '',
|
||||
theme: 'light',
|
||||
fit: 'cover',
|
||||
showText: true,
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -63,24 +80,67 @@ const logoSrc = computed(() => {
|
||||
// 否则使用默认的 src
|
||||
return props.src;
|
||||
});
|
||||
|
||||
/**
|
||||
* @zh_CN 是否铺满容器显示log
|
||||
*/
|
||||
const shouldUseFullLogo = computed(() => {
|
||||
return props.logoMode === 'full' && !props.collapsed;
|
||||
});
|
||||
|
||||
/**
|
||||
* @zh_CN 根据配置展示 logo text
|
||||
*/
|
||||
const shouldShowText = computed(() => {
|
||||
return (
|
||||
props.showText &&
|
||||
!props.collapsed &&
|
||||
!shouldUseFullLogo.value &&
|
||||
!!props.text
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* @zh_CN full 模式下logo的样式
|
||||
*/
|
||||
const fullLogoStyle = computed(() => ({
|
||||
height:
|
||||
typeof props.fullLogoHeight === 'number'
|
||||
? `${props.fullLogoHeight}px`
|
||||
: props.fullLogoHeight,
|
||||
objectFit: props.fit,
|
||||
}));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="theme" class="flex h-full items-center text-lg">
|
||||
<a
|
||||
:class="$attrs.class"
|
||||
:class="[
|
||||
$attrs.class,
|
||||
shouldShowText
|
||||
? 'gap-2 px-3 justify-start'
|
||||
: 'w-full p-0 justify-center',
|
||||
]"
|
||||
:href="href"
|
||||
class="flex h-full items-center gap-2 overflow-hidden px-3 text-lg leading-normal transition-all duration-500"
|
||||
class="flex h-full items-center overflow-hidden text-lg leading-normal transition-all duration-500"
|
||||
>
|
||||
<img
|
||||
v-if="logoSrc && shouldUseFullLogo"
|
||||
:alt="text"
|
||||
:src="logoSrc"
|
||||
:style="fullLogoStyle"
|
||||
class="w-full"
|
||||
/>
|
||||
|
||||
<VbenAvatar
|
||||
v-if="logoSrc"
|
||||
v-else-if="logoSrc"
|
||||
:alt="text"
|
||||
:src="logoSrc"
|
||||
:size="logoSize"
|
||||
:fit="fit"
|
||||
class="relative rounded-none bg-transparent"
|
||||
/>
|
||||
<template v-if="!collapsed">
|
||||
<template v-if="shouldShowText">
|
||||
<slot name="text">
|
||||
<span class="text-foreground truncate font-semibold text-nowrap">
|
||||
{{ text }}
|
||||
|
||||
@@ -118,6 +118,15 @@ const logoTheme = computed(() => {
|
||||
return showLogoInHeader ? headerTheme.value : sidebarTheme.value;
|
||||
});
|
||||
|
||||
/**
|
||||
* layout-sidebar扩展区域插槽extra-title的高度
|
||||
*/
|
||||
const sidebarExtraTitleHeight = computed<number | undefined>(() => {
|
||||
const showSideExtraTitle =
|
||||
preferences.logo.enable && preferences.logo.showText;
|
||||
return showSideExtraTitle ? undefined : 0;
|
||||
});
|
||||
|
||||
const {
|
||||
handleMenuSelect,
|
||||
handleMenuOpen,
|
||||
@@ -253,12 +262,14 @@ const headerSlots = computed(() => {
|
||||
:sidebar-expand-on-hover="preferences.sidebar.expandOnHover"
|
||||
:sidebar-extra-collapse="preferences.sidebar.extraCollapse"
|
||||
:sidebar-extra-collapsed-width="preferences.sidebar.extraCollapsedWidth"
|
||||
:sidebar-extra-title-height="sidebarExtraTitleHeight"
|
||||
:sidebar-hidden="preferences.sidebar.hidden"
|
||||
:sidebar-mixed-width="preferences.sidebar.mixedWidth"
|
||||
:sidebar-theme="sidebarTheme"
|
||||
:sidebar-theme-sub="sidebarThemeSub"
|
||||
:sidebar-width="preferences.sidebar.width"
|
||||
:side-collapse-width="preferences.sidebar.collapseWidth"
|
||||
:sidebar-logo-visible="preferences.logo.enable"
|
||||
:tabbar-enable="preferences.tabbar.enable"
|
||||
:tabbar-height="preferences.tabbar.height"
|
||||
:z-index="preferences.app.zIndex"
|
||||
@@ -292,6 +303,9 @@ const headerSlots = computed(() => {
|
||||
:src="preferences.logo.source"
|
||||
:src-dark="preferences.logo.sourceDark"
|
||||
:text="preferences.app.name"
|
||||
:show-text="preferences.logo.showText"
|
||||
:logo-mode="preferences.logo.logoMode"
|
||||
:full-logo-height="preferences.logo.fullLogoHeight"
|
||||
:theme="logoTheme"
|
||||
@click="clickLogo"
|
||||
>
|
||||
@@ -382,6 +396,7 @@ const headerSlots = computed(() => {
|
||||
<VbenLogo
|
||||
v-if="preferences.logo.enable"
|
||||
:fit="preferences.logo.fit"
|
||||
:show-text="preferences.logo.showText"
|
||||
:text="preferences.app.name"
|
||||
:theme="sidebarThemeSub"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user