Files
certd/packages/ui/certd-client/src/vben/common-ui/components/page/page.vue
T
2025-06-29 14:09:09 +08:00

82 lines
2.2 KiB
Vue

<script setup lang="ts">
import type { StyleValue } from "vue";
import type { PageProps } from "./types";
import { computed, nextTick, onMounted, ref, useTemplateRef } from "vue";
import { CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT } from "/@/vben/shared/constants";
import { cn } from "/@/vben/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>