@@ -9,8 +9,16 @@ import {
9
9
} from ' vue' ;
10
10
11
11
import { preferences } from ' @vben-core/preferences' ;
12
+ import {
13
+ CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT ,
14
+ CSS_VARIABLE_LAYOUT_CONTENT_WIDTH ,
15
+ CSS_VARIABLE_LAYOUT_FOOTER_HEIGHT ,
16
+ CSS_VARIABLE_LAYOUT_HEADER_HEIGHT ,
17
+ } from ' @vben-core/shared/constants' ;
12
18
import { cn } from ' @vben-core/shared/utils' ;
13
19
20
+ import { useElementSize } from ' @vueuse/core' ;
21
+
14
22
interface Props {
15
23
title? : string ;
16
24
description? : string ;
@@ -37,34 +45,65 @@ const {
37
45
fixedHeader = false ,
38
46
} = defineProps <Props >();
39
47
40
- const headerHeight = ref (0 );
41
- const footerHeight = ref (0 );
42
48
const shouldAutoHeight = ref (false );
43
49
44
50
const headerRef = useTemplateRef <HTMLDivElement >(' headerRef' );
45
51
const footerRef = useTemplateRef <HTMLDivElement >(' footerRef' );
52
+ const { height : headerHeight } = useElementSize (
53
+ headerRef ,
54
+ {
55
+ height: 0 ,
56
+ width: 0 ,
57
+ },
58
+ { box: ' border-box' },
59
+ );
60
+ const { height : footerHeight } = useElementSize (
61
+ footerRef ,
62
+ {
63
+ height: 0 ,
64
+ width: 0 ,
65
+ },
66
+ { box: ' border-box' },
67
+ );
46
68
47
69
const headerStyle = computed <StyleValue >(() => {
48
70
return fixedHeader
49
71
? {
50
- position: ' sticky ' ,
72
+ position: ' fixed ' ,
51
73
zIndex: 200 ,
74
+ width: ` var(${CSS_VARIABLE_LAYOUT_CONTENT_WIDTH }) ` ,
52
75
top:
53
- preferences .header .mode === ' fixed' ? ' var(--vben-header-height)' : 0 ,
76
+ preferences .header .mode === ' fixed'
77
+ ? ` var(${CSS_VARIABLE_LAYOUT_HEADER_HEIGHT }) `
78
+ : 0 ,
54
79
}
55
80
: undefined ;
56
81
});
57
82
83
+ const footerStyle = computed <StyleValue >(() => {
84
+ return {
85
+ bottom:
86
+ preferences .footer .enable && preferences .footer .fixed
87
+ ? ` var(${CSS_VARIABLE_LAYOUT_FOOTER_HEIGHT }) `
88
+ : 0 ,
89
+ width: ` var(${CSS_VARIABLE_LAYOUT_CONTENT_WIDTH }) ` ,
90
+ };
91
+ });
92
+
58
93
const contentStyle = computed (() => {
94
+ const style: StyleValue = {};
95
+ if (headerHeight .value > 0 && fixedHeader ) {
96
+ style .marginTop = ` ${headerHeight .value }px ` ;
97
+ }
98
+ if (footerHeight .value > 0 ) {
99
+ style .marginBottom = ` ${footerHeight .value }px ` ;
100
+ }
59
101
if (autoContentHeight ) {
60
- return {
61
- height: shouldAutoHeight .value
62
- ? ` calc(var(--vben-content-height) - ${headerHeight .value }px - ${footerHeight .value }px) `
63
- : ' 0' ,
64
- // 'overflow-y': shouldAutoHeight.value?'auto':'unset',
65
- };
102
+ style .height = shouldAutoHeight .value
103
+ ? ` calc(var(${CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT }) - ${headerHeight .value }px - ${footerHeight .value }px) `
104
+ : ' 0' ;
66
105
}
67
- return {} ;
106
+ return style ;
68
107
});
69
108
70
109
async function calcContentHeight() {
@@ -97,7 +136,7 @@ onMounted(() => {
97
136
ref =" headerRef"
98
137
:class ="
99
138
cn(
100
- 'bg-card relative px-6 py-4',
139
+ 'bg-card relative flex gap-2 px-6 py-4',
101
140
headerClass,
102
141
fixedHeader
103
142
? 'border-border border-b transition-all duration-200'
@@ -106,19 +145,21 @@ onMounted(() => {
106
145
"
107
146
:style =" headerStyle"
108
147
>
109
- <slot name =" title" >
110
- <div v-if =" title" class =" mb-2 flex text-lg font-semibold" >
111
- {{ title }}
112
- </div >
113
- </slot >
114
-
115
- <slot name =" description" >
116
- <p v-if =" description" class =" text-muted-foreground" >
117
- {{ description }}
118
- </p >
119
- </slot >
120
-
121
- <div v-if =" $slots.extra" class =" absolute bottom-4 right-4" >
148
+ <div class =" flex-auto" >
149
+ <slot name =" title" >
150
+ <div v-if =" title" class =" mb-2 flex text-lg font-semibold" >
151
+ {{ title }}
152
+ </div >
153
+ </slot >
154
+
155
+ <slot name =" description" >
156
+ <p v-if =" description" class =" text-muted-foreground" >
157
+ {{ description }}
158
+ </p >
159
+ </slot >
160
+ </div >
161
+
162
+ <div v-if =" $slots.extra" class =" mb-2 self-end" >
122
163
<slot name =" extra" ></slot >
123
164
</div >
124
165
</div >
@@ -133,9 +174,10 @@ onMounted(() => {
133
174
:class ="
134
175
cn(
135
176
footerClass,
136
- 'bg-card align-center absolute bottom-0 left-0 right-0 flex px-6 py-4',
177
+ 'bg-card align-center border-border fixed right-0 flex border-t px-6 py-4 transition-all duration-200 ',
137
178
)
138
179
"
180
+ :style =" footerStyle"
139
181
>
140
182
<slot name =" footer" ></slot >
141
183
</div >
0 commit comments