@bagelink/vue 1.2.39 → 1.2.43
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.
- package/dist/components/calendar/CalendarPopover.vue.d.ts +179 -0
- package/dist/components/calendar/CalendarPopover.vue.d.ts.map +1 -0
- package/dist/components/calendar/CalendarTypes.d.ts +15 -0
- package/dist/components/calendar/CalendarTypes.d.ts.map +1 -1
- package/dist/components/calendar/Index.vue.d.ts +20 -12
- package/dist/components/calendar/Index.vue.d.ts.map +1 -1
- package/dist/components/calendar/views/AgendaView.vue.d.ts +8 -0
- package/dist/components/calendar/views/AgendaView.vue.d.ts.map +1 -1
- package/dist/components/calendar/views/CalendarPopover.vue.d.ts +175 -0
- package/dist/components/calendar/views/CalendarPopover.vue.d.ts.map +1 -0
- package/dist/components/calendar/views/DayView.vue.d.ts +10 -32
- package/dist/components/calendar/views/DayView.vue.d.ts.map +1 -1
- package/dist/components/calendar/views/MonthView.vue.d.ts +10 -170
- package/dist/components/calendar/views/MonthView.vue.d.ts.map +1 -1
- package/dist/components/calendar/views/WeekView.vue.d.ts +12 -168
- package/dist/components/calendar/views/WeekView.vue.d.ts.map +1 -1
- package/dist/components/form/FieldArray.vue.d.ts +4 -4
- package/dist/components/form/FieldArray.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/DateInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/DatePicker.vue.d.ts.map +1 -1
- package/dist/composables/useDevice.d.ts +3 -0
- package/dist/composables/useDevice.d.ts.map +1 -1
- package/dist/composables/useSchemaField.d.ts +1 -1
- package/dist/composables/useSchemaField.d.ts.map +1 -1
- package/dist/index.cjs +426 -280
- package/dist/index.mjs +426 -280
- package/dist/style.css +210 -167
- package/dist/types/BagelForm.d.ts +20 -17
- package/dist/types/BagelForm.d.ts.map +1 -1
- package/dist/utils/BagelFormUtils.d.ts +14 -20
- package/dist/utils/BagelFormUtils.d.ts.map +1 -1
- package/dist/utils/calendar/dateUtils.d.ts +7 -7
- package/dist/utils/index.d.ts +2 -4
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/calendar/CalendarPopover.vue +102 -0
- package/src/components/calendar/CalendarTypes.ts +14 -0
- package/src/components/calendar/Index.vue +75 -34
- package/src/components/calendar/views/AgendaView.vue +26 -2
- package/src/components/calendar/views/DayView.vue +83 -104
- package/src/components/calendar/views/MonthView.vue +21 -49
- package/src/components/calendar/views/WeekView.vue +227 -134
- package/src/components/form/FieldArray.vue +4 -3
- package/src/components/form/inputs/DateInput.vue +3 -1
- package/src/components/form/inputs/DatePicker.vue +7 -0
- package/src/composables/useDevice.ts +13 -2
- package/src/composables/useSchemaField.ts +4 -4
- package/src/styles/layout.css +14 -0
- package/src/styles/mobilLayout.css +12 -0
- package/src/types/BagelForm.ts +39 -59
- package/src/utils/BagelFormUtils.ts +16 -21
- package/src/utils/calendar/dateUtils.ts +22 -22
- package/src/utils/index.ts +3 -3
- package/src/components/calendar/utils.ts +0 -70
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { SetupContext } from 'vue'
|
|
3
3
|
import type { CalendarEvent } from '../CalendarTypes'
|
|
4
|
-
import type { PopoverState } from '../utils'
|
|
5
4
|
import { formatDate } from '@bagelink/vue'
|
|
6
5
|
import { ref, computed, onMounted, onUnmounted, useSlots } from 'vue'
|
|
7
|
-
import {
|
|
8
|
-
openPopover as openPopoverUtil,
|
|
9
|
-
closePopover as closePopoverUtil,
|
|
10
|
-
} from '../utils'
|
|
11
6
|
|
|
12
7
|
const props = defineProps<{
|
|
13
8
|
events: CalendarEvent[]
|
|
@@ -17,6 +12,7 @@ const props = defineProps<{
|
|
|
17
12
|
const emit = defineEmits<{
|
|
18
13
|
(e: 'eventClick', event: CalendarEvent): void
|
|
19
14
|
(e: 'eventCreate', event: { start_time: Date, end_time: Date }): void
|
|
15
|
+
(e: 'openPopover', event: CalendarEvent, position?: { top: number, left: number }): void
|
|
20
16
|
}>()
|
|
21
17
|
|
|
22
18
|
const slots: SetupContext['slots'] = useSlots()
|
|
@@ -40,19 +36,6 @@ const currentTimeTop = ref(0)
|
|
|
40
36
|
const isToday = ref(false)
|
|
41
37
|
const currentTimeInterval = ref(null as any)
|
|
42
38
|
|
|
43
|
-
// Popover state
|
|
44
|
-
const activeEvent = ref<CalendarEvent | null>(null)
|
|
45
|
-
const showPopover = ref(false)
|
|
46
|
-
const popoverPosition = ref({ top: 0, left: 0, width: 0, height: 0 })
|
|
47
|
-
const popoverRef = ref<HTMLElement | null>(null)
|
|
48
|
-
|
|
49
|
-
const popoverState: PopoverState = {
|
|
50
|
-
activeEvent,
|
|
51
|
-
showPopover,
|
|
52
|
-
popoverPosition,
|
|
53
|
-
popoverRef
|
|
54
|
-
}
|
|
55
|
-
|
|
56
39
|
// Generate hourly time slots
|
|
57
40
|
const timeSlots = computed(() => {
|
|
58
41
|
const slots = []
|
|
@@ -100,7 +83,7 @@ function updateCurrentTimeIndicator() {
|
|
|
100
83
|
// Check if today is the selected day
|
|
101
84
|
isToday.value = now.toDateString() === props.startDate.toDateString()
|
|
102
85
|
|
|
103
|
-
// Calculate the position for the current time line
|
|
86
|
+
// Calculate the position for the current time line - use same formula as events
|
|
104
87
|
const minutes = now.getHours() * 60 + now.getMinutes()
|
|
105
88
|
currentTimeTop.value = (minutes / slotDuration) * slotHeight
|
|
106
89
|
}
|
|
@@ -153,27 +136,39 @@ function getTimeFromPosition(y: number): Date {
|
|
|
153
136
|
const rect = document.querySelector('.time-slots')?.getBoundingClientRect()
|
|
154
137
|
if (!rect) return new Date()
|
|
155
138
|
|
|
156
|
-
|
|
139
|
+
// Calculate time using the same formula as for events
|
|
140
|
+
const relativeY = y - rect.top
|
|
141
|
+
const minutesPerSlot = slotDuration
|
|
142
|
+
const slotsFromTop = relativeY / slotHeight
|
|
143
|
+
const minutes = Math.floor(slotsFromTop * minutesPerSlot)
|
|
144
|
+
|
|
157
145
|
const date = new Date(props.startDate)
|
|
158
146
|
date.setHours(Math.floor(minutes / 60))
|
|
159
147
|
date.setMinutes(minutes % 60)
|
|
148
|
+
date.setSeconds(0)
|
|
149
|
+
date.setMilliseconds(0)
|
|
160
150
|
|
|
161
151
|
return date
|
|
162
152
|
}
|
|
163
153
|
|
|
164
|
-
//
|
|
165
|
-
function
|
|
166
|
-
|
|
167
|
-
event
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
!!slots.eventContent,
|
|
171
|
-
(evt) => { emit('eventClick', evt) }
|
|
172
|
-
)
|
|
173
|
-
}
|
|
154
|
+
// Update event handling to emit the openPopover event
|
|
155
|
+
function handleEventSelection(event: CalendarEvent, domEvent?: MouseEvent) {
|
|
156
|
+
if (!slots.eventContent) {
|
|
157
|
+
emit('eventClick', event)
|
|
158
|
+
return
|
|
159
|
+
}
|
|
174
160
|
|
|
175
|
-
|
|
176
|
-
|
|
161
|
+
// Calculate position from DOM event if available
|
|
162
|
+
if (domEvent) {
|
|
163
|
+
const rect = (domEvent.currentTarget as HTMLElement).getBoundingClientRect()
|
|
164
|
+
const position = {
|
|
165
|
+
top: rect.top + window.scrollY + (rect.height / 2),
|
|
166
|
+
left: rect.left + window.scrollX + rect.width + 10
|
|
167
|
+
}
|
|
168
|
+
emit('openPopover', event, position)
|
|
169
|
+
} else {
|
|
170
|
+
emit('openPopover', event)
|
|
171
|
+
}
|
|
177
172
|
}
|
|
178
173
|
|
|
179
174
|
// Lifecycle hooks
|
|
@@ -218,7 +213,7 @@ onUnmounted(() => {
|
|
|
218
213
|
</div>
|
|
219
214
|
<div class="events-column">
|
|
220
215
|
<!-- Current time indicator -->
|
|
221
|
-
<div v-if="isToday" class="
|
|
216
|
+
<div v-if="isToday" class="absolute end w-100p z-2 flex pointer-events-none" :style="{ top: `${currentTimeTop}px` }">
|
|
222
217
|
<div class="current-time-dot h-10px aspect-ratio-1 round bg-primary" />
|
|
223
218
|
<div class="current-time-line w-100p bg-primary" />
|
|
224
219
|
</div>
|
|
@@ -231,14 +226,14 @@ onUnmounted(() => {
|
|
|
231
226
|
height: `${event.height}px`,
|
|
232
227
|
backgroundColor: event.color || 'var(--bgl-primary)',
|
|
233
228
|
}"
|
|
234
|
-
@click.stop="
|
|
229
|
+
@click.stop="handleEventSelection(event, $event)"
|
|
235
230
|
>
|
|
236
231
|
<div class="event-content">
|
|
237
|
-
<div class="
|
|
232
|
+
<div class="white-space ellipsis-1">
|
|
238
233
|
{{ event.title }}
|
|
239
234
|
</div>
|
|
240
235
|
<div class="event-time opacity-8">
|
|
241
|
-
{{ formatDate(new Date(event.start_time)) }}
|
|
236
|
+
{{ formatDate(new Date(event.start_time), { fmt: 'HH:mm' }) }} - {{ formatDate(new Date(event.end_time), { fmt: 'HH:mm' }) }}
|
|
242
237
|
</div>
|
|
243
238
|
</div>
|
|
244
239
|
</div>
|
|
@@ -247,128 +242,112 @@ onUnmounted(() => {
|
|
|
247
242
|
<!-- Drag selection preview -->
|
|
248
243
|
<div
|
|
249
244
|
v-if="dragState.isDragging && dragState.start && dragState.end"
|
|
250
|
-
class="drag-preview absolute bg-primary pointer-events-none"
|
|
245
|
+
class="drag-preview absolute bg-primary-tint pointer-events-none z-1"
|
|
251
246
|
:style="{
|
|
252
247
|
top: `${Math.min(dragState.start.y, dragState.end.y)}px`,
|
|
253
248
|
height: `${Math.abs(dragState.end.y - dragState.start.y)}px`,
|
|
249
|
+
left: '10px',
|
|
250
|
+
right: '10px',
|
|
254
251
|
}"
|
|
255
|
-
|
|
252
|
+
>
|
|
253
|
+
<div class="color-primary txt-12 p-025">
|
|
254
|
+
{{ dragState.startTime ? formatDate(dragState.startTime, { fmt: 'HH:mm' }) : '' }}
|
|
255
|
+
-
|
|
256
|
+
{{ dragState.endTime ? formatDate(dragState.endTime, { fmt: 'HH:mm' }) : '' }}
|
|
257
|
+
</div>
|
|
258
|
+
</div>
|
|
256
259
|
</div>
|
|
257
260
|
</div>
|
|
258
261
|
|
|
259
|
-
<!-- Custom Popover -->
|
|
260
|
-
<div
|
|
261
|
-
v-if="showPopover && activeEvent"
|
|
262
|
-
ref="popoverRef"
|
|
263
|
-
v-click-outside="closePopover"
|
|
264
|
-
class="custom-popover"
|
|
265
|
-
:style="{
|
|
266
|
-
top: `${popoverPosition.top}px`,
|
|
267
|
-
left: `${popoverPosition.left}px`,
|
|
268
|
-
maxWidth: `${popoverPosition.width}px`,
|
|
269
|
-
}"
|
|
270
|
-
>
|
|
271
|
-
<slot name="eventContent" :event="activeEvent" />
|
|
272
|
-
</div>
|
|
273
262
|
<div class="border-bottom me-1" />
|
|
274
263
|
</div>
|
|
275
264
|
</template>
|
|
276
265
|
|
|
277
266
|
<style scoped>
|
|
278
|
-
.dayGrid{
|
|
267
|
+
.dayGrid {
|
|
279
268
|
display: grid;
|
|
280
269
|
grid-template-columns: 5rem 1fr;
|
|
281
270
|
}
|
|
282
271
|
|
|
283
272
|
.time-column {
|
|
284
|
-
|
|
285
|
-
|
|
273
|
+
width: 80px;
|
|
274
|
+
flex-shrink: 0;
|
|
286
275
|
}
|
|
287
276
|
|
|
288
277
|
.events-column {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
278
|
+
flex-grow: 1;
|
|
279
|
+
position: relative;
|
|
280
|
+
border-inline-start: 1px solid var(--border-color);
|
|
281
|
+
min-height: 100%; /* Ensure the column fills the full height */
|
|
292
282
|
}
|
|
293
283
|
|
|
294
284
|
.date-header {
|
|
295
|
-
|
|
296
|
-
|
|
285
|
+
padding: 0.5rem;
|
|
286
|
+
text-align: center;
|
|
297
287
|
}
|
|
288
|
+
|
|
298
289
|
.day-header .events-column {
|
|
299
|
-
|
|
290
|
+
border-inline-start: 1px solid transparent;
|
|
300
291
|
}
|
|
301
292
|
|
|
302
293
|
.time-slot {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
294
|
+
height: 60px; /* Match this with the slotHeight variable */
|
|
295
|
+
display: flex;
|
|
296
|
+
align-items: flex-start; /* Align to top to match events */
|
|
297
|
+
justify-content: center;
|
|
298
|
+
padding: 0.5rem 0;
|
|
299
|
+
box-sizing: border-box;
|
|
307
300
|
}
|
|
308
301
|
|
|
309
302
|
.time-slots {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
303
|
+
flex-grow: 1;
|
|
304
|
+
display: flex;
|
|
305
|
+
overflow: auto;
|
|
306
|
+
position: relative;
|
|
314
307
|
}
|
|
315
308
|
|
|
316
309
|
.event {
|
|
317
|
-
|
|
318
|
-
|
|
310
|
+
left: 10px;
|
|
311
|
+
right: 10px;
|
|
312
|
+
box-sizing: border-box;
|
|
319
313
|
}
|
|
320
314
|
|
|
321
315
|
.event:hover {
|
|
322
|
-
|
|
323
|
-
|
|
316
|
+
z-index: 2;
|
|
317
|
+
transform: scale(1.02);
|
|
324
318
|
}
|
|
325
319
|
|
|
326
320
|
.event-content {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
321
|
+
padding: 0.5rem;
|
|
322
|
+
color: white;
|
|
323
|
+
font-size: 0.9rem;
|
|
324
|
+
height: 100%;
|
|
325
|
+
overflow: hidden;
|
|
332
326
|
}
|
|
333
327
|
|
|
334
328
|
.event-title {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
329
|
+
white-space: nowrap;
|
|
330
|
+
overflow: hidden;
|
|
331
|
+
text-overflow: ellipsis;
|
|
338
332
|
}
|
|
339
333
|
|
|
340
334
|
.event-time {
|
|
341
|
-
|
|
335
|
+
font-size: 0.8rem;
|
|
342
336
|
}
|
|
343
337
|
|
|
344
338
|
.drag-preview {
|
|
339
|
+
border: 1px solid var(--bgl-primary);
|
|
345
340
|
background-color: rgba(var(--bgl-primary-rgb), 0.1);
|
|
341
|
+
box-sizing: border-box;
|
|
346
342
|
}
|
|
347
343
|
|
|
348
344
|
.current-time-line {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
.custom-popover {
|
|
353
|
-
position: fixed;
|
|
354
|
-
z-index: 1000;
|
|
355
|
-
min-width: 250px;
|
|
356
|
-
max-width: 350px;
|
|
357
|
-
background-color: white;
|
|
358
|
-
border-radius: 4px;
|
|
359
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
360
|
-
animation: fadeIn 0.2s ease;
|
|
361
|
-
transform-origin: center left;
|
|
345
|
+
height: 2px;
|
|
346
|
+
background-color: var(--bgl-primary);
|
|
362
347
|
}
|
|
363
348
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
transform: scale(0.95);
|
|
368
|
-
}
|
|
369
|
-
to {
|
|
370
|
-
opacity: 1;
|
|
371
|
-
transform: scale(1);
|
|
372
|
-
}
|
|
349
|
+
.current-time-dot {
|
|
350
|
+
background-color: var(--bgl-primary);
|
|
351
|
+
margin-right: -5px; /* Adjust dot position */
|
|
373
352
|
}
|
|
374
353
|
</style>
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { SetupContext } from 'vue'
|
|
3
3
|
import type { CalendarEvent } from '../CalendarTypes'
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import { ref, computed, useSlots } from 'vue'
|
|
7
|
-
import {
|
|
8
|
-
openPopover as openPopoverUtil,
|
|
9
|
-
closePopover as closePopoverUtil,
|
|
10
|
-
} from '../utils'
|
|
4
|
+
import { fmtDate } from '@bagelink/vue'
|
|
5
|
+
import { computed, useSlots } from 'vue'
|
|
11
6
|
|
|
12
7
|
interface MonthViewEvent {
|
|
13
8
|
date: Date
|
|
@@ -23,6 +18,7 @@ const props = defineProps<{
|
|
|
23
18
|
|
|
24
19
|
const emit = defineEmits<{
|
|
25
20
|
(e: 'eventClick', event: CalendarEvent): void
|
|
21
|
+
(e: 'openPopover', event: CalendarEvent, position?: { top: number, left: number }): void
|
|
26
22
|
}>()
|
|
27
23
|
|
|
28
24
|
const slots: SetupContext['slots'] = useSlots()
|
|
@@ -30,19 +26,6 @@ const slots: SetupContext['slots'] = useSlots()
|
|
|
30
26
|
// Responsive state
|
|
31
27
|
const isMobile = computed(() => window.innerWidth < 768)
|
|
32
28
|
|
|
33
|
-
// Popover state
|
|
34
|
-
const activeEvent = ref<CalendarEvent | null>(null)
|
|
35
|
-
const showPopover = ref(false)
|
|
36
|
-
const popoverPosition = ref({ top: 0, left: 0, width: 0, height: 0 })
|
|
37
|
-
const popoverRef = ref<HTMLElement | null>(null)
|
|
38
|
-
|
|
39
|
-
const popoverState: PopoverState = {
|
|
40
|
-
activeEvent,
|
|
41
|
-
showPopover,
|
|
42
|
-
popoverPosition,
|
|
43
|
-
popoverRef
|
|
44
|
-
}
|
|
45
|
-
|
|
46
29
|
// Calendar data
|
|
47
30
|
const weekDays = computed(() => ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'])
|
|
48
31
|
|
|
@@ -102,19 +85,24 @@ const currentMonth = computed(() => {
|
|
|
102
85
|
return days
|
|
103
86
|
})
|
|
104
87
|
|
|
105
|
-
//
|
|
106
|
-
function
|
|
107
|
-
|
|
108
|
-
event
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
!!slots.eventContent,
|
|
112
|
-
(evt) => { emit('eventClick', evt) }
|
|
113
|
-
)
|
|
114
|
-
}
|
|
88
|
+
// Update event handling to emit the openPopover event
|
|
89
|
+
function handleEventSelection(event: CalendarEvent, domEvent?: MouseEvent) {
|
|
90
|
+
if (!slots.eventContent) {
|
|
91
|
+
emit('eventClick', event)
|
|
92
|
+
return
|
|
93
|
+
}
|
|
115
94
|
|
|
116
|
-
|
|
117
|
-
|
|
95
|
+
// Calculate position from DOM event if available
|
|
96
|
+
if (domEvent) {
|
|
97
|
+
const rect = (domEvent.currentTarget as HTMLElement).getBoundingClientRect()
|
|
98
|
+
const position = {
|
|
99
|
+
top: rect.top + window.scrollY + (rect.height / 2),
|
|
100
|
+
left: rect.left + window.scrollX + rect.width + 10
|
|
101
|
+
}
|
|
102
|
+
emit('openPopover', event, position)
|
|
103
|
+
} else {
|
|
104
|
+
emit('openPopover', event)
|
|
105
|
+
}
|
|
118
106
|
}
|
|
119
107
|
</script>
|
|
120
108
|
|
|
@@ -149,7 +137,7 @@ function closePopover() {
|
|
|
149
137
|
:key="event.id"
|
|
150
138
|
class="event-item"
|
|
151
139
|
:style="{ backgroundColor: event.color || 'var(--bgl-primary)' }"
|
|
152
|
-
@click.stop="
|
|
140
|
+
@click.stop="handleEventSelection(event, $event)"
|
|
153
141
|
>
|
|
154
142
|
<div class="event-title">
|
|
155
143
|
{{ event.title }}
|
|
@@ -162,22 +150,6 @@ function closePopover() {
|
|
|
162
150
|
</div>
|
|
163
151
|
</div>
|
|
164
152
|
</div>
|
|
165
|
-
|
|
166
|
-
<!-- Custom Popover -->
|
|
167
|
-
<Card
|
|
168
|
-
v-if="showPopover && activeEvent"
|
|
169
|
-
ref="popoverRef"
|
|
170
|
-
v-click-outside="closePopover"
|
|
171
|
-
thin
|
|
172
|
-
class="custom-popover"
|
|
173
|
-
:style="{
|
|
174
|
-
top: `${popoverPosition.top}px`,
|
|
175
|
-
left: `${popoverPosition.left}px`,
|
|
176
|
-
maxWidth: `${popoverPosition.width}px`,
|
|
177
|
-
}"
|
|
178
|
-
>
|
|
179
|
-
<slot name="eventContent" :event="activeEvent" />
|
|
180
|
-
</Card>
|
|
181
153
|
</div>
|
|
182
154
|
</template>
|
|
183
155
|
|