layout-header.vue 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. <script setup lang="ts">
  2. import type { CSSProperties } from 'vue';
  3. import { computed, useSlots } from 'vue';
  4. import { IcRoundMenu } from '@vben-core/iconify';
  5. import { VbenIconButton } from '@vben-core/shadcn-ui';
  6. interface Props {
  7. /**
  8. * 背景颜色
  9. */
  10. backgroundColor?: string;
  11. /**
  12. * 横屏
  13. * @default false
  14. */
  15. fullWidth?: boolean;
  16. /**
  17. * 高度
  18. * @default 60
  19. */
  20. height?: number;
  21. /**
  22. * 是否混合导航
  23. * @default false
  24. */
  25. isMixedNav?: boolean;
  26. /**
  27. * 是否移动端
  28. * @default false
  29. */
  30. isMobile?: boolean;
  31. /**
  32. * 是否显示
  33. * @default true
  34. */
  35. show?: boolean;
  36. /**
  37. * 是否显示关闭菜单按钮
  38. * @default true
  39. */
  40. showToggleBtn?: boolean;
  41. /**
  42. * 侧边菜单宽度
  43. * @default 0
  44. */
  45. sidebarWidth?: number;
  46. /**
  47. * 宽度
  48. * @default 100%
  49. */
  50. width?: string;
  51. /**
  52. * zIndex
  53. * @default 0
  54. */
  55. zIndex?: number;
  56. }
  57. const props = withDefaults(defineProps<Props>(), {
  58. backgroundColor: 'hsl(var(--background))',
  59. // fixed: true,
  60. height: 60,
  61. isMixedNav: false,
  62. show: true,
  63. showToggleBtn: false,
  64. sidebarWidth: 0,
  65. width: '100%',
  66. zIndex: 0,
  67. });
  68. const emit = defineEmits<{ openMenu: []; toggleSidebar: [] }>();
  69. const slots = useSlots();
  70. const style = computed((): CSSProperties => {
  71. const { backgroundColor, fullWidth, height, show } = props;
  72. const right = !show || !fullWidth ? undefined : 0;
  73. return {
  74. // ...(props.isMixedNav ? { left: 0, position: `fixed` } : {}),
  75. backgroundColor,
  76. height: `${height}px`,
  77. marginTop: show ? 0 : `-${height}px`,
  78. right,
  79. };
  80. });
  81. const logoStyle = computed((): CSSProperties => {
  82. return {
  83. minWidth: `${props.isMobile ? 40 : props.sidebarWidth}px`,
  84. };
  85. });
  86. function handleToggleMenu() {
  87. if (props.isMobile) {
  88. emit('openMenu');
  89. } else {
  90. emit('toggleSidebar');
  91. }
  92. }
  93. </script>
  94. <template>
  95. <header
  96. :style="style"
  97. class="border-border top-0 flex w-full flex-[0_0_auto] items-center border-b transition-[margin-top] duration-200"
  98. >
  99. <div v-if="slots.logo" :style="logoStyle">
  100. <slot name="logo"></slot>
  101. </div>
  102. <VbenIconButton
  103. v-if="showToggleBtn || isMobile"
  104. class="my-0 ml-2 mr-1 rounded"
  105. @click="handleToggleMenu"
  106. >
  107. <IcRoundMenu class="size-5" />
  108. </VbenIconButton>
  109. <slot></slot>
  110. </header>
  111. </template>