123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- <script setup lang="ts">
- import type { PageProps } from './types';
- import {
- computed,
- nextTick,
- onMounted,
- ref,
- type StyleValue,
- useTemplateRef,
- } from 'vue';
- import { CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT } from '@vben-core/shared/constants';
- import { cn } from '@vben-core/shared/utils';
- defineOptions({
- name: 'Page',
- });
- const { autoContentHeight = false } = defineProps<PageProps>();
- const headerHeight = ref(0);
- const footerHeight = ref(0);
- const shouldAutoHeight = ref(false);
- const headerRef = useTemplateRef<HTMLDivElement>('headerRef');
- const footerRef = useTemplateRef<HTMLDivElement>('footerRef');
- const contentStyle = computed<StyleValue>(() => {
- if (autoContentHeight) {
- return {
- height: `calc(var(${CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT}) - ${headerHeight.value}px)`,
- overflowY: shouldAutoHeight.value ? 'auto' : 'unset',
- };
- }
- return {};
- });
- async function calcContentHeight() {
- if (!autoContentHeight) {
- return;
- }
- await nextTick();
- headerHeight.value = headerRef.value?.offsetHeight || 0;
- footerHeight.value = footerRef.value?.offsetHeight || 0;
- setTimeout(() => {
- shouldAutoHeight.value = true;
- }, 30);
- }
- onMounted(() => {
- calcContentHeight();
- });
- </script>
- <template>
- <div class="relative">
- <div
- v-if="
- description ||
- $slots.description ||
- title ||
- $slots.title ||
- $slots.extra
- "
- ref="headerRef"
- :class="
- cn(
- 'bg-card border-border relative flex items-end border-b px-6 py-4',
- headerClass,
- )
- "
- >
- <div class="flex-auto">
- <slot name="title">
- <div v-if="title" class="mb-2 flex text-lg font-semibold">
- {{ title }}
- </div>
- </slot>
- <slot name="description">
- <p v-if="description" class="text-muted-foreground">
- {{ description }}
- </p>
- </slot>
- </div>
- <div v-if="$slots.extra">
- <slot name="extra"></slot>
- </div>
- </div>
- <div :class="cn('h-full p-4', contentClass)" :style="contentStyle">
- <slot></slot>
- </div>
- <div
- v-if="$slots.footer"
- ref="footerRef"
- :class="
- cn(
- 'bg-card align-center absolute bottom-0 left-0 right-0 flex px-6 py-4',
- footerClass,
- )
- "
- >
- <slot name="footer"></slot>
- </div>
- </div>
- </template>
|