@bagelink/vue 1.4.109 → 1.4.115

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/bin/generateFormSchema.ts +12 -12
  2. package/dist/components/Card.vue.d.ts.map +1 -1
  3. package/dist/components/ImportData.vue.d.ts.map +1 -1
  4. package/dist/components/ListItem.vue.d.ts +6 -1
  5. package/dist/components/ListItem.vue.d.ts.map +1 -1
  6. package/dist/components/analytics/BarChart.vue.d.ts +39 -0
  7. package/dist/components/analytics/BarChart.vue.d.ts.map +1 -0
  8. package/dist/components/analytics/KpiCard.vue.d.ts +24 -0
  9. package/dist/components/analytics/KpiCard.vue.d.ts.map +1 -0
  10. package/dist/components/analytics/LineChart.vue.d.ts +26 -0
  11. package/dist/components/analytics/LineChart.vue.d.ts.map +1 -0
  12. package/dist/components/analytics/PieChart.vue.d.ts +24 -0
  13. package/dist/components/analytics/PieChart.vue.d.ts.map +1 -0
  14. package/dist/components/analytics/index.d.ts +5 -0
  15. package/dist/components/analytics/index.d.ts.map +1 -0
  16. package/dist/components/calendar/Index.vue.d.ts.map +1 -1
  17. package/dist/components/calendar/index.d.ts +2 -0
  18. package/dist/components/calendar/index.d.ts.map +1 -0
  19. package/dist/components/calendar/views/MonthView.vue.d.ts.map +1 -1
  20. package/dist/components/calendar/views/WeekView.vue.d.ts.map +1 -1
  21. package/dist/components/dataTable/DataTable.vue.d.ts.map +1 -1
  22. package/dist/components/form/BagelForm.vue.d.ts.map +1 -1
  23. package/dist/components/form/inputs/DatePicker.vue.d.ts +2 -0
  24. package/dist/components/form/inputs/DatePicker.vue.d.ts.map +1 -1
  25. package/dist/components/form/inputs/RadioGroup.vue.d.ts +6 -10
  26. package/dist/components/form/inputs/RadioGroup.vue.d.ts.map +1 -1
  27. package/dist/components/form/inputs/RichText/utils/media.d.ts.map +1 -1
  28. package/dist/components/form/inputs/SelectInput.vue.d.ts +2 -2
  29. package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
  30. package/dist/components/layout/AppContent.vue.d.ts +34 -0
  31. package/dist/components/layout/AppContent.vue.d.ts.map +1 -0
  32. package/dist/components/layout/AppLayout.vue.d.ts +27 -0
  33. package/dist/components/layout/AppLayout.vue.d.ts.map +1 -0
  34. package/dist/components/layout/AppSidebar.vue.d.ts +44 -0
  35. package/dist/components/layout/AppSidebar.vue.d.ts.map +1 -0
  36. package/dist/components/layout/index.d.ts +3 -0
  37. package/dist/components/layout/index.d.ts.map +1 -1
  38. package/dist/composables/useFormField.d.ts.map +1 -1
  39. package/dist/composables/useSchemaField.d.ts +2 -2
  40. package/dist/composables/useSchemaField.d.ts.map +1 -1
  41. package/dist/index.cjs +19 -19
  42. package/dist/index.mjs +10 -10
  43. package/dist/style.css +1 -1
  44. package/dist/types/BagelForm.d.ts +25 -13
  45. package/dist/types/BagelForm.d.ts.map +1 -1
  46. package/dist/utils/BagelFormUtils.d.ts +11 -8
  47. package/dist/utils/BagelFormUtils.d.ts.map +1 -1
  48. package/dist/utils/calendar/dateUtils.d.ts +21 -0
  49. package/dist/utils/calendar/dateUtils.d.ts.map +1 -1
  50. package/dist/utils/elementUtils.d.ts +5 -0
  51. package/dist/utils/elementUtils.d.ts.map +1 -1
  52. package/dist/utils/useSearch.d.ts.map +1 -1
  53. package/package.json +1 -1
  54. package/src/components/Card.vue +1 -2
  55. package/src/components/DataPreview.vue +1 -1
  56. package/src/components/ImportData.vue +94 -88
  57. package/src/components/ListItem.vue +32 -24
  58. package/src/components/analytics/BarChart.vue +153 -0
  59. package/src/components/analytics/KpiCard.vue +84 -0
  60. package/src/components/analytics/LineChart.vue +267 -0
  61. package/src/components/analytics/PieChart.vue +183 -0
  62. package/src/components/analytics/index.ts +4 -0
  63. package/src/components/calendar/Index.vue +15 -35
  64. package/src/components/calendar/views/MonthView.vue +84 -88
  65. package/src/components/calendar/views/WeekView.vue +143 -89
  66. package/src/components/dataTable/DataTable.vue +2 -3
  67. package/src/components/form/BagelForm.vue +27 -6
  68. package/src/components/form/inputs/DateInput.vue +2 -2
  69. package/src/components/form/inputs/DatePicker.vue +42 -48
  70. package/src/components/form/inputs/RadioGroup.vue +60 -35
  71. package/src/components/form/inputs/RichText/utils/media.ts +1 -2
  72. package/src/components/form/inputs/SelectInput.vue +94 -101
  73. package/src/components/form/inputs/Upload/upload.css +135 -138
  74. package/src/components/layout/AppContent.vue +125 -0
  75. package/src/components/layout/AppLayout.vue +124 -0
  76. package/src/components/layout/AppSidebar.vue +271 -0
  77. package/src/components/layout/index.ts +5 -0
  78. package/src/composables/useFormField.ts +6 -0
  79. package/src/composables/useSchemaField.ts +38 -10
  80. package/src/styles/inputs.css +9 -0
  81. package/src/styles/theme.css +2 -2
  82. package/src/types/BagelForm.ts +68 -13
  83. package/src/utils/BagelFormUtils.ts +49 -52
  84. package/src/utils/calendar/dateUtils.ts +71 -17
  85. package/src/utils/elementUtils.ts +23 -4
  86. package/src/utils/useSearch.ts +14 -7
  87. /package/src/components/{dialog → calendar}/index.ts +0 -0
@@ -1,235 +1,232 @@
1
1
  .fileUploadWrap {
2
- outline: 1px solid var(--border-color);
3
- border-radius: var(--input-border-radius);
4
- text-align: center;
5
- cursor: pointer;
6
- transition: var(--bgl-transition);
7
- position: relative;
8
- font-size: var(--input-font-size);
9
- overflow-y: auto;
10
- background: var(--input-bg);
11
- height: 215px;
2
+ outline: 1px solid var(--border-color);
3
+ border-radius: var(--input-border-radius);
4
+ text-align: center;
5
+ cursor: pointer;
6
+ transition: var(--bgl-transition);
7
+ position: relative;
8
+ font-size: var(--input-font-size);
9
+ overflow-y: auto;
10
+ background: var(--input-bg);
11
+ height: 215px;
12
+ outline-offset: -1px;
12
13
  }
13
14
 
14
15
  .bagel-input .fileUploadWrap.fileDropZone {
15
- background: var(--input-bg);
16
- display: flex;
17
- align-items: center;
18
- justify-content: center;
19
- color: var(--bgl-gray);
20
- flex-direction: column;
16
+ background: var(--input-bg);
17
+ display: flex;
18
+ align-items: center;
19
+ justify-content: center;
20
+ color: var(--bgl-gray);
21
+ flex-direction: column;
21
22
  }
22
23
 
23
24
  .fileUploadWrap.dragover,
24
25
  .fileUploadWrap:hover {
25
- box-shadow: inset 0 0 10px #00000012;
26
+ box-shadow: inset 0 0 10px #00000012;
26
27
  }
27
28
 
28
29
  .fileUploadWrap[style*='height: auto;'] {
29
- min-height: 215px;
30
+ min-height: 215px;
30
31
  }
31
32
 
32
33
  .multi-image-item-preview {
33
- border: 1px solid var(--border-color) !important;
34
- border-radius: var(--input-border-radius);
35
- margin: 0.5rem !important;
36
- background: var(--bgl-popup-bg);
37
- padding: 0;
38
- padding-inline-end: 1rem;
39
- padding-inline-start: 0.25rem;
40
- text-align: start;
41
- color: var(--input-color);
42
- display: grid;
43
- grid-template-columns: auto 1fr 22px;
44
- gap: 0.5rem;
45
- align-items: center;
46
- height: var(--btn-height);
47
- font-size: var(--label-font-size);
34
+ border: 1px solid var(--border-color) !important;
35
+ border-radius: var(--input-border-radius);
36
+ margin: 0.5rem !important;
37
+ background: var(--bgl-popup-bg);
38
+ padding: 0;
39
+ padding-inline-end: 1rem;
40
+ padding-inline-start: 0.25rem;
41
+ text-align: start;
42
+ color: var(--input-color);
43
+ display: grid;
44
+ grid-template-columns: auto 1fr 22px;
45
+ gap: 0.5rem;
46
+ align-items: center;
47
+ height: var(--btn-height);
48
+ font-size: var(--label-font-size);
48
49
  }
49
50
 
50
51
  .multi-image-item-preview p {
51
- overflow: hidden;
52
- text-overflow: ellipsis;
53
- white-space: nowrap;
52
+ overflow: hidden;
53
+ text-overflow: ellipsis;
54
+ white-space: nowrap;
54
55
  }
55
56
 
56
57
  .multi-preview {
57
- /* width: 40px; */
58
- height: calc(var(--btn-height) - 0.5rem);
59
- max-width: calc(var(--btn-height) - 0.5rem);
60
- border-radius: calc(var(--input-border-radius) / 2);
61
- object-fit: cover;
62
- background: var(--bgl-gray-light);
63
- text-align: center !important;
64
- justify-content: center;
65
- align-items: center;
66
- display: flex;
58
+ /* width: 40px; */
59
+ height: calc(var(--btn-height) - 0.5rem);
60
+ max-width: calc(var(--btn-height) - 0.5rem);
61
+ border-radius: calc(var(--input-border-radius) / 2);
62
+ object-fit: cover;
63
+ background: var(--bgl-gray-light);
64
+ text-align: center !important;
65
+ justify-content: center;
66
+ align-items: center;
67
+ display: flex;
67
68
  }
68
69
 
69
70
  .bgl-single-preview {
70
- height: 100%;
71
- position: relative;
71
+ height: 100%;
72
+ position: relative;
72
73
  }
73
74
 
74
- .bgl-single-preview + .fileUploadPlaceHolder {
75
- position: absolute;
76
- inset: 0;
77
- margin: auto;
78
- top: calc(50% - 2rem);
75
+ .bgl-single-preview+.fileUploadPlaceHolder {
76
+ position: absolute;
77
+ inset: 0;
78
+ margin: auto;
79
+ top: calc(50% - 2rem);
79
80
  }
80
81
 
81
82
  .single-image-item-preview {
82
- height: 100%;
83
- min-height: 100%;
84
- position: relative;
85
- display: flex;
86
- align-items: center;
87
- justify-content: center;
83
+ height: 100%;
84
+ min-height: 100%;
85
+ position: relative;
86
+ display: flex;
87
+ align-items: center;
88
+ justify-content: center;
88
89
  }
89
90
 
90
91
  .fileUploadWrap[style*='height: auto'] .single-image-item-preview {
91
- min-height: 215px;
92
+ min-height: 215px;
92
93
  }
93
94
 
94
95
  .fileUploadWrap[style*='height: auto'] .single-preview {
95
- margin: 0rem !important;
96
+ margin: 0rem !important;
96
97
  }
97
98
 
98
99
  .single-preview {
99
- margin: 1rem;
100
- padding: 0px;
101
- height: calc(100% - 2rem);
102
- max-height: calc(100% - 2rem);
103
- background: var(--bgl-gray-light);
104
- max-width: calc(100% - 2rem);
105
- object-fit: contain;
100
+ margin: 1rem;
101
+ padding: 0px;
102
+ height: calc(100% - 2rem);
103
+ max-height: calc(100% - 2rem);
104
+ background: var(--bgl-gray-light);
105
+ max-width: calc(100% - 2rem);
106
+ object-fit: contain;
106
107
  }
107
108
 
108
109
  .single-image-item-preview:hover::after {
109
- content: 'zoom_in';
110
- font-size: 32px;
111
- font-family: 'Material Symbols Outlined', serif;
112
- position: absolute;
113
- border-radius: 100%;
114
- color: var(--bgl-white);
115
- z-index: 9;
116
- pointer-events: none;
110
+ content: 'zoom_in';
111
+ font-size: 32px;
112
+ font-family: 'Material Symbols Outlined', serif;
113
+ position: absolute;
114
+ border-radius: 100%;
115
+ color: var(--bgl-white);
116
+ z-index: 9;
117
+ pointer-events: none;
117
118
  }
118
119
 
119
120
  .single-image-item-preview:hover img {
120
- filter: brightness(70%);
121
+ filter: brightness(70%);
121
122
  }
122
123
 
123
124
  .bgl_fill-image.single-image-item-preview {
124
- height: 100%;
125
+ height: 100%;
125
126
  }
126
127
 
127
128
  .bgl_fill-image.single-image-item-preview .single-preview {
128
- border-radius: unset;
129
- object-fit: cover;
130
- box-shadow: unset;
131
- width: 100%;
132
- height: auto;
129
+ border-radius: unset;
130
+ object-fit: cover;
131
+ box-shadow: unset;
132
+ width: 100%;
133
+ height: auto;
133
134
  }
134
135
 
135
136
  .single-image-item-preview .pie {
136
- transform-origin: top;
137
- transform: scale(1.4);
138
- position: absolute;
139
- text-align: center;
140
- inset: 0;
141
- margin: auto;
142
- display: flex;
143
- justify-content: center;
144
- align-items: center;
145
- background: transparent;
146
- border: none !important;
147
- padding: 0 !important;
137
+ transform-origin: top;
138
+ transform: scale(1.4);
139
+ position: absolute;
140
+ text-align: center;
141
+ inset: 0;
142
+ margin: auto;
143
+ display: flex;
144
+ justify-content: center;
145
+ align-items: center;
146
+ background: transparent;
147
+ border: none !important;
148
+ padding: 0 !important;
148
149
  }
149
150
 
150
151
  .bgl_oval-upload {
151
- border-radius: 100% !important;
152
- overflow: hidden;
152
+ border-radius: 100% !important;
153
+ overflow: hidden;
153
154
  }
154
155
 
155
156
  .bgl_oval-upload p {
156
- padding: 0.75rem !important;
157
- font-size: 12px;
157
+ padding: 0.75rem !important;
158
+ font-size: 12px;
158
159
  }
159
160
 
160
161
  .bgl_oval-upload .fileUploadPlaceHolder {
161
- top: 0;
162
+ top: 0;
162
163
  }
163
164
 
164
165
  .bgl_oval-upload .pie {
165
- transform: scale(1);
166
+ transform: scale(1);
166
167
  }
167
168
 
168
169
  .bgl_oval-upload span.bgl_icon-font.color-primary {
169
- transform: scale(0.4) !important;
170
+ transform: scale(0.4) !important;
170
171
  }
171
172
 
172
173
  .bgl_oval-upload .single-image-item-preview {
173
- height: 100%;
174
+ height: 100%;
174
175
  }
175
176
 
176
177
  .bgl_oval-upload .single-preview {
177
- margin: 0;
178
- height: 100% !important;
178
+ margin: 0;
179
+ height: 100% !important;
179
180
  }
180
181
 
181
182
  .pie {
182
- width: 30px;
183
- height: 30px;
184
- position: relative;
185
- display: flex;
186
- align-items: center;
187
- justify-content: center;
183
+ width: 30px;
184
+ height: 30px;
185
+ position: relative;
186
+ display: flex;
187
+ align-items: center;
188
+ justify-content: center;
188
189
  }
189
190
 
190
191
  .pie:before {
191
- content: '';
192
- position: absolute;
193
- border-radius: 50%;
194
- inset: 0;
195
- transition: all 0.2s ease-in-out;
196
- background: conic-gradient(var(--bgl-primary) calc(var(--p) * 1%), #0000 0);
197
- -webkit-mask: radial-gradient(
198
- farthest-side,
199
- #0000 calc(99% - var(--b)),
200
- #000 calc(100% - var(--b))
201
- );
202
- mask: radial-gradient(
203
- farthest-side,
204
- #0000 calc(99% - var(--b)),
205
- #000 calc(100% - var(--b))
206
- );
192
+ content: '';
193
+ position: absolute;
194
+ border-radius: 50%;
195
+ inset: 0;
196
+ transition: all 0.2s ease-in-out;
197
+ background: conic-gradient(var(--bgl-primary) calc(var(--p) * 1%), #0000 0);
198
+ -webkit-mask: radial-gradient(farthest-side,
199
+ #0000 calc(99% - var(--b)),
200
+ #000 calc(100% - var(--b)));
201
+ mask: radial-gradient(farthest-side,
202
+ #0000 calc(99% - var(--b)),
203
+ #000 calc(100% - var(--b)));
207
204
  }
208
205
 
209
206
  .pie .success {
210
- transform: scale(0);
211
- opacity: 0;
212
- transition: all 0.3s ease-in-out;
207
+ transform: scale(0);
208
+ opacity: 0;
209
+ transition: all 0.3s ease-in-out;
213
210
  }
214
211
 
215
212
  .pie .progress {
216
- position: absolute;
217
- font-size: 10px;
213
+ position: absolute;
214
+ font-size: 10px;
218
215
  }
219
216
 
220
217
  .pie.complete .progress {
221
- display: none;
218
+ display: none;
222
219
  }
223
220
 
224
221
  .pie.complete .success {
225
- transform: scale(1.3);
226
- opacity: 1;
222
+ transform: scale(1.3);
223
+ opacity: 1;
227
224
  }
228
225
 
229
226
  .pie.complete:before {
230
- background: conic-gradient(var(--bgl-green) calc(var(--p) * 1%), #0000 0);
227
+ background: conic-gradient(var(--bgl-green) calc(var(--p) * 1%), #0000 0);
231
228
  }
232
229
 
233
230
  .pie.complete {
234
- color: var(--bgl-green);
235
- }
231
+ color: var(--bgl-green);
232
+ }
@@ -0,0 +1,125 @@
1
+ <script lang="ts" setup>
2
+ import { inject } from 'vue'
3
+ import { Btn, PageTitle } from '@bagelink/vue'
4
+
5
+ interface Props {
6
+ title?: string
7
+ showMenuButton?: boolean
8
+ showBackButton?: boolean
9
+ backTo?: string
10
+ border?: boolean
11
+ }
12
+
13
+ withDefaults(defineProps<Props>(), {
14
+ showMenuButton: true,
15
+ showBackButton: false,
16
+ backTo: '/',
17
+ border: true,
18
+ })
19
+
20
+ // Inject menu state from parent
21
+ const menuState = inject('menuState') as {
22
+ isOpen: { value: boolean }
23
+ isMobile: { value: boolean }
24
+ toggleMenu: () => void
25
+ }
26
+
27
+ // Inject sidebar card style state
28
+ const sidebarCardStyle = inject('sidebarCardStyle', { value: true })
29
+ </script>
30
+
31
+ <template>
32
+ <div class="app-content h-100p flex column" :class="{
33
+ 'paddingAppContent': sidebarCardStyle?.value,
34
+ }">
35
+ <!-- Header -->
36
+ <header class="app-header flex align-items-center space-between py-1 min-h60px w-100p m_flex-wrap" :class="{
37
+ 'border-bottom': border,
38
+ 'px-1': !sidebarCardStyle?.value,
39
+ }">
40
+ <!-- Left Side -->
41
+ <div class="flex align-items-center gap-col-075 m_flex-wrap">
42
+ <!-- Menu Toggle Button -->
43
+ <Btn v-if="showMenuButton" flat icon="dock_to_right" @click="menuState.toggleMenu" />
44
+
45
+ <!-- Back Button -->
46
+ <Btn v-if="showBackButton" flat icon="arrow_back" :to="backTo" class="back-btn" />
47
+
48
+ <!-- Page Title -->
49
+ <PageTitle v-if="title">
50
+ {{ title }}
51
+ </PageTitle>
52
+
53
+ <!-- Custom Left Content -->
54
+ <slot name="header-left" />
55
+ </div>
56
+
57
+ <!-- Center Content -->
58
+ <div class="flex align-items-center">
59
+ <slot name="header-center" />
60
+ </div>
61
+
62
+ <!-- Right Side -->
63
+ <div class="flex align-items-center gap-row-05 m_flex-grow-1">
64
+ <slot name="header-right" />
65
+ </div>
66
+ </header>
67
+
68
+ <!-- Page Content -->
69
+ <main class="pageContent flex-grow overflow py-1 w-100p m_p-05 m_scrollbar-gutter-stable-both m_vw100" :class="{
70
+ 'px-1': !sidebarCardStyle?.value,
71
+ }">
72
+ <slot name="content">
73
+ <!-- Default slot for content without explicit template -->
74
+ <slot />
75
+ </slot>
76
+ </main>
77
+ </div>
78
+ </template>
79
+
80
+ <style>
81
+ .slide-fade-enter-from:has(.app-header),
82
+ .slide-fade-leave-to:has(.app-header) {
83
+ transform: translateX(0) !important;
84
+ opacity: 1 !important;
85
+ }
86
+
87
+ .slide-fade-enter-from:has(.app-header) .pageContent,
88
+ .slide-fade-leave-to:has(.app-header) .pageContent {
89
+ transform: translateX(-20px) !important;
90
+ opacity: 0 !important;
91
+ }
92
+
93
+ .slide-fade-enter-active:has(.app-header) .pageContent,
94
+ .slide-fade-leave-active:has(.app-header) .pageContent {
95
+ transition: all 0.15s ease-in;
96
+ overflow: hidden;
97
+ }
98
+ </style>
99
+
100
+ <style scoped>
101
+ .paddingAppContent {
102
+ padding-inline-start: 0.5rem;
103
+ padding-inline-end: 1rem;
104
+ }
105
+
106
+ body:has(.sidebar-collapsed) .paddingAppContent {
107
+ padding-inline-start: 1.5rem;
108
+ }
109
+ .app-content {
110
+ height: 100vh;
111
+ }
112
+
113
+ .app-header {
114
+ flex-shrink: 0;
115
+ }
116
+
117
+ main {
118
+ min-height: 0; /* חשוב לאפשר overflow נכון */
119
+ }
120
+ @media screen and (max-width: 910px) {
121
+ .paddingAppContent {
122
+ padding-inline: 0.5rem;
123
+ }
124
+ }
125
+ </style>
@@ -0,0 +1,124 @@
1
+ <script lang="ts" setup>
2
+ import { ref, provide, onMounted, onUnmounted, computed } from 'vue'
3
+
4
+ interface Props {
5
+ sidebarWidth?: string
6
+ sidebarCardStyle?: boolean
7
+ }
8
+
9
+ const props = withDefaults(defineProps<Props>(), {
10
+ sidebarWidth: '260px',
11
+ sidebarCardStyle: false
12
+ })
13
+
14
+ // Menu state
15
+ const isOpen = ref(true)
16
+ const isMobile = ref(false)
17
+
18
+ // Check if mobile
19
+ function checkMobile() {
20
+ isMobile.value = window.innerWidth < 768
21
+ if (isMobile.value) {
22
+ isOpen.value = false
23
+ }
24
+ }
25
+
26
+ // Toggle menu
27
+ function toggleMenu() {
28
+ isOpen.value = !isOpen.value
29
+ }
30
+
31
+ // Close menu on mobile when clicking outside
32
+ function closeOnMobile() {
33
+ if (isMobile.value) {
34
+ isOpen.value = false
35
+ }
36
+ }
37
+
38
+ // Computed styles for main content margin
39
+ const mainContentStyles = computed(() => {
40
+ if (isMobile.value) {
41
+ return { marginLeft: '0' }
42
+ }
43
+ const collapsedWidth = props.sidebarCardStyle ? '82px' : '66px'
44
+ return {
45
+ marginLeft: isOpen.value ? props.sidebarWidth : collapsedWidth
46
+ }
47
+ })
48
+
49
+ // Provide state to child components
50
+ provide('menuState', {
51
+ isOpen,
52
+ isMobile,
53
+ toggleMenu,
54
+ closeOnMobile,
55
+ sidebarWidth: props.sidebarWidth,
56
+ sidebarCollapsedWidth: props.sidebarCardStyle ? '82px' : '66px'
57
+ })
58
+
59
+ // Initialize
60
+ onMounted(() => {
61
+ checkMobile()
62
+ window.addEventListener('resize', checkMobile)
63
+ })
64
+
65
+ onUnmounted(() => {
66
+ window.removeEventListener('resize', checkMobile)
67
+ })
68
+ </script>
69
+
70
+ <template>
71
+ <div class="app-layout vh-100 relative">
72
+ <!-- Mobile Overlay -->
73
+ <div
74
+ v-if="isMobile && isOpen"
75
+ class="overlay"
76
+ @click="closeOnMobile"
77
+ />
78
+
79
+ <!-- Sidebar Slot -->
80
+ <slot name="sidebar" />
81
+
82
+ <!-- Main Content Area -->
83
+ <main
84
+ class="main-content flex column ease-300"
85
+ :style="mainContentStyles"
86
+ >
87
+ <!-- Header Slot -->
88
+ <slot name="header" />
89
+
90
+ <!-- Page Content -->
91
+ <div class="page-content overflow w-100p h-100p">
92
+ <slot />
93
+ </div>
94
+ </main>
95
+ </div>
96
+ </template>
97
+
98
+ <style scoped>
99
+ .app-layout {
100
+ display: flex;
101
+ height: 100vh;
102
+ overflow: hidden;
103
+ }
104
+
105
+ /* Overlay for mobile */
106
+ .overlay {
107
+ position: fixed;
108
+ inset: 0;
109
+ background: rgba(0, 0, 0, 0.5);
110
+ z-index: 40;
111
+ }
112
+
113
+ /* Main Content */
114
+ .main-content {
115
+ flex: 1;
116
+ overflow: hidden;
117
+ transition: margin-left 400ms ease;
118
+ min-height: 100vh
119
+ }
120
+
121
+ .page-content {
122
+ overflow: auto;
123
+ }
124
+ </style>