33 <header
44 v-if =" title || hasTitleSlot || hasActionsSlot"
55 class =" page-panel__header"
6- :class =" { 'page-panel__header--with-actions': hasActionsSlot }"
6+ :class =" {
7+ 'page-panel__header--with-actions': hasActionsSlot,
8+ 'page-panel__header--sticky': stickyHeader,
9+ }"
710 :style =" headerStyle"
811 >
912 <div class =" page-panel__title" >
@@ -27,53 +30,56 @@ defineOptions({
2730 name: ' PagePanel' ,
2831})
2932
30- const { title , headerPadding , bodyPadding , bodyClass } = defineProps ({
33+ const { title , headerPadding , bodyPadding , bodyClass , stickyHeader , stickyTop } = defineProps ({
3134 title: {
3235 type: String ,
3336 default: ' ' ,
3437 },
3538 headerPadding: {
3639 type: String ,
37- default: ' 0 40px ' ,
40+ default: ' 0 30px ' ,
3841 },
3942 bodyPadding: {
4043 type: String ,
41- default: ' 20px ' ,
44+ default: ' ' ,
4245 },
4346 bodyClass: {
4447 type: [String , Array , Object ],
4548 default: ' ' ,
4649 },
50+ stickyHeader: {
51+ type: Boolean ,
52+ default: true ,
53+ },
54+ stickyTop: {
55+ type: String ,
56+ default: ' 0px' ,
57+ },
4758})
4859
4960const slots = useSlots ()
5061const hasTitleSlot = computed (() => Boolean (slots .title ))
5162const hasActionsSlot = computed (() => Boolean (slots .actions ))
5263const headerStyle = computed (() => ({
5364 ' --page-panel-header-padding' : headerPadding,
65+ ' --page-panel-sticky-top' : stickyTop,
5466}))
5567const bodyStyle = computed (() => ({
56- ' --page-panel-body-padding' : bodyPadding ,
68+ ' --page-panel-body-padding' : resolveBodyPadding () ,
5769}))
70+
71+ function resolveBodyPadding () {
72+ if (bodyPadding) {
73+ return bodyPadding
74+ }
75+
76+ return ' 20px 30px 30px'
77+ }
5878 </script >
5979
6080<style lang="scss" scoped>
6181.page-panel {
6282 position : relative ;
63- overflow : hidden ;
64- background : var (--theme-panel-gradient );
65- border : 1px solid var (--theme-border );
66- border-radius : 18px ;
67- box-shadow : var (--theme-panel-shadow );
68-
69- & :before {
70- content : ' ' ;
71- position : absolute ;
72- inset : 0 0 auto ;
73- height : 68px ;
74- background : linear-gradient (180deg , var (--theme-panel-highlight ), transparent );
75- pointer-events : none ;
76- }
7783}
7884
7985.page-panel__header {
@@ -83,14 +89,27 @@ const bodyStyle = computed(() => ({
8389 min-height : 59px ;
8490 padding : var (--page-panel-header-padding );
8591 border-bottom : 1px solid var (--theme-border );
86- background : linear-gradient (180deg , rgba (255 , 255 , 255 , 0.14 ), transparent );
8792}
8893
8994.page-panel__header--with-actions {
9095 justify-content : space-between ;
9196 gap : 16px ;
9297}
9398
99+ .page-panel__header--sticky {
100+ position : sticky ;
101+ top : var (--page-panel-sticky-top );
102+ z-index : 9 ;
103+ }
104+
105+ .page-panel__header--sticky :before {
106+ content : ' ' ;
107+ position : absolute ;
108+ inset : 0 ;
109+ z-index : -1 ;
110+ background : var (--theme-main-bg );
111+ }
112+
94113.page-panel__title {
95114 min-width : 0 ;
96115 color : $parent-title-color ;
@@ -103,11 +122,26 @@ const bodyStyle = computed(() => ({
103122.page-panel__actions {
104123 display : flex ;
105124 align-items : center ;
125+ justify-content : flex-end ;
126+ flex-wrap : wrap ;
106127 gap : 12px ;
128+ min-width : 0 ;
107129}
108130
109131.page-panel__body {
110132 position : relative ;
111133 padding : var (--page-panel-body-padding );
112134}
135+
136+ @media screen and (width <= 680px ) {
137+ .page-panel__header--with-actions {
138+ align-items : stretch ;
139+ flex-direction : column ;
140+ }
141+
142+ .page-panel__actions {
143+ width : 100% ;
144+ justify-content : flex-start ;
145+ }
146+ }
113147 </style >
0 commit comments