@bagelink/vue 1.2.39 → 1.2.41
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/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/index.cjs +426 -280
- package/dist/index.mjs +426 -280
- package/dist/style.css +210 -167
- package/dist/types/BagelForm.d.ts +14 -11
- package/dist/types/BagelForm.d.ts.map +1 -1
- package/dist/utils/BagelFormUtils.d.ts +10 -10
- package/dist/utils/BagelFormUtils.d.ts.map +1 -1
- package/dist/utils/calendar/dateUtils.d.ts +7 -7
- 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/inputs/DateInput.vue +3 -1
- package/src/components/form/inputs/DatePicker.vue +7 -0
- package/src/composables/useDevice.ts +13 -2
- package/src/styles/layout.css +14 -0
- package/src/styles/mobilLayout.css +12 -0
- package/src/types/BagelForm.ts +30 -53
- package/src/utils/BagelFormUtils.ts +11 -10
- package/src/utils/calendar/dateUtils.ts +22 -22
- package/src/components/calendar/utils.ts +0 -70
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { SetupContext } from 'vue'
|
|
2
|
+
import type { SetupContext, ComponentPublicInstance } from 'vue'
|
|
3
3
|
import type { CalendarEvent, WeekStart } from '../CalendarTypes'
|
|
4
|
-
import
|
|
5
|
-
import { Card, fmtDate } from '@bagelink/vue'
|
|
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
|
interface WeekViewEvent extends CalendarEvent {
|
|
13
8
|
top: number
|
|
@@ -31,6 +26,7 @@ const props = withDefaults(defineProps<{
|
|
|
31
26
|
const emit = defineEmits<{
|
|
32
27
|
(e: 'eventClick', event: CalendarEvent): void
|
|
33
28
|
(e: 'eventCreate', event: { start_time: Date, end_time: Date }): void
|
|
29
|
+
(e: 'openPopover', event: CalendarEvent, position?: { top: number, left: number }): void
|
|
34
30
|
}>()
|
|
35
31
|
|
|
36
32
|
const slots: SetupContext['slots'] = useSlots()
|
|
@@ -43,29 +39,23 @@ const timeRange = { start: 0, end: 24 }
|
|
|
43
39
|
// Drag state
|
|
44
40
|
const dragState = ref({
|
|
45
41
|
isDragging: false,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
42
|
+
startDay: -1, // Index of the starting day
|
|
43
|
+
endDay: -1, // Index of the ending day
|
|
44
|
+
start: undefined as { x: number, y: number } | undefined,
|
|
45
|
+
end: undefined as { x: number, y: number } | undefined,
|
|
46
|
+
startTime: undefined as Date | undefined,
|
|
47
|
+
endTime: undefined as Date | undefined
|
|
50
48
|
})
|
|
51
49
|
|
|
52
|
-
// Popover state
|
|
53
|
-
const activeEvent = ref<CalendarEvent | null>(null)
|
|
54
|
-
const showPopover = ref(false)
|
|
55
|
-
const popoverPosition = ref({ top: 0, left: 0, width: 0, height: 0 })
|
|
56
|
-
const popoverRef = ref<HTMLElement | null>(null)
|
|
57
|
-
|
|
58
|
-
const popoverState: PopoverState = {
|
|
59
|
-
activeEvent,
|
|
60
|
-
showPopover,
|
|
61
|
-
popoverPosition,
|
|
62
|
-
popoverRef
|
|
63
|
-
}
|
|
64
|
-
|
|
65
50
|
// Time indicators
|
|
66
51
|
const currentTimeTop = ref(0)
|
|
67
52
|
const isToday = ref(false)
|
|
68
|
-
const currentTimeInterval = ref(
|
|
53
|
+
const currentTimeInterval = ref<any>()
|
|
54
|
+
|
|
55
|
+
const timeSlotsContainer = ref<HTMLElement>()
|
|
56
|
+
const calendarGrid = ref<HTMLElement>()
|
|
57
|
+
const dayColumns = ref<HTMLElement[]>([])
|
|
58
|
+
const dayColumnsContainer = ref<HTMLElement>()
|
|
69
59
|
|
|
70
60
|
// Calculate week days based on start date and week start preference
|
|
71
61
|
const weekDays = computed(() => {
|
|
@@ -76,6 +66,7 @@ const weekDays = computed(() => {
|
|
|
76
66
|
// Adjust to start of week
|
|
77
67
|
const dayOfWeek = start.getDay()
|
|
78
68
|
start.setDate(start.getDate() - dayOfWeek + weekStartOffset)
|
|
69
|
+
start.setHours(0, 0, 0, 0) // Set time to start of day
|
|
79
70
|
|
|
80
71
|
// Create array of 7 day dates
|
|
81
72
|
for (let i = 0; i < 7; i++) {
|
|
@@ -118,11 +109,11 @@ const processedEvents = computed(() => {
|
|
|
118
109
|
|
|
119
110
|
if (dayIndex === -1) return
|
|
120
111
|
|
|
121
|
-
// Calculate vertical positioning
|
|
112
|
+
// Calculate vertical positioning - make sure to use the same formula everywhere
|
|
122
113
|
const startMinutes = startDate.getHours() * 60 + startDate.getMinutes()
|
|
123
114
|
const endMinutes = endDate.getHours() * 60 + endDate.getMinutes()
|
|
124
|
-
const top = (startMinutes / slotDuration) *
|
|
125
|
-
const height = Math.max(((endMinutes - startMinutes) / slotDuration) *
|
|
115
|
+
const top = (startMinutes / slotDuration) * slotHeight
|
|
116
|
+
const height = Math.max(((endMinutes - startMinutes) / slotDuration) * slotHeight, 30)
|
|
126
117
|
|
|
127
118
|
const weekEvent: WeekViewEvent = {
|
|
128
119
|
...event,
|
|
@@ -160,23 +151,103 @@ const processedEvents = computed(() => {
|
|
|
160
151
|
})
|
|
161
152
|
|
|
162
153
|
// Mouse event handlers for drag-to-create functionality
|
|
163
|
-
function handleMouseDown(e: MouseEvent) {
|
|
164
|
-
|
|
165
|
-
|
|
154
|
+
function handleMouseDown(e: MouseEvent, day: Date) {
|
|
155
|
+
if (!calendarGrid.value || !dayColumnsContainer.value) return
|
|
156
|
+
|
|
157
|
+
// Find the clicked day column
|
|
158
|
+
let clickedDayIndex = -1
|
|
159
|
+
for (let i = 0; i < dayColumns.value.length; i++) {
|
|
160
|
+
const columnEl = dayColumns.value[i]
|
|
161
|
+
if (!columnEl) continue
|
|
162
|
+
|
|
163
|
+
const rect = columnEl.getBoundingClientRect()
|
|
164
|
+
if (e.clientX >= rect.left && e.clientX <= rect.right) {
|
|
165
|
+
clickedDayIndex = i
|
|
166
|
+
break
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (clickedDayIndex === -1) return
|
|
171
|
+
|
|
172
|
+
// Get the clicked day column's position and dimensions
|
|
173
|
+
const dayColumnRect = dayColumns.value[clickedDayIndex].getBoundingClientRect()
|
|
174
|
+
const dayColumnsRect = dayColumnsContainer.value.getBoundingClientRect()
|
|
166
175
|
|
|
167
176
|
dragState.value.isDragging = true
|
|
168
|
-
dragState.value.
|
|
169
|
-
dragState.value.
|
|
177
|
+
dragState.value.startDay = clickedDayIndex
|
|
178
|
+
dragState.value.endDay = clickedDayIndex
|
|
179
|
+
dragState.value.start = {
|
|
180
|
+
x: dayColumnRect.left - dayColumnsRect.left, // Left edge of the day column
|
|
181
|
+
y: e.clientY - dayColumnsRect.top
|
|
182
|
+
}
|
|
183
|
+
dragState.value.end = {
|
|
184
|
+
x: dayColumnRect.right - dayColumnsRect.left, // Right edge of the day column
|
|
185
|
+
y: e.clientY - dayColumnsRect.top
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Create a clean copy of the day
|
|
189
|
+
const cleanDay = new Date(day)
|
|
190
|
+
cleanDay.setHours(0, 0, 0, 0)
|
|
191
|
+
|
|
192
|
+
const startTime = getTimeFromPosition(e.clientY, cleanDay)
|
|
193
|
+
dragState.value.startTime = startTime
|
|
170
194
|
|
|
171
195
|
document.addEventListener('mousemove', handleMouseMove)
|
|
172
196
|
document.addEventListener('mouseup', handleMouseUp)
|
|
173
197
|
}
|
|
174
198
|
|
|
175
199
|
function handleMouseMove(e: MouseEvent) {
|
|
176
|
-
if (!dragState.value.isDragging) return
|
|
200
|
+
if (!dragState.value.isDragging || !dragState.value.start || !dayColumns.value.length || !calendarGrid.value || !dayColumnsContainer.value) return
|
|
201
|
+
|
|
202
|
+
// Find which day column we're hovering over
|
|
203
|
+
let targetDayIndex = -1
|
|
204
|
+
for (let i = 0; i < dayColumns.value.length; i++) {
|
|
205
|
+
const columnEl = dayColumns.value[i]
|
|
206
|
+
if (!columnEl) continue
|
|
207
|
+
|
|
208
|
+
const rect = columnEl.getBoundingClientRect()
|
|
209
|
+
if (e.clientX >= rect.left && e.clientX <= rect.right) {
|
|
210
|
+
targetDayIndex = i
|
|
211
|
+
break
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (targetDayIndex === -1) return
|
|
216
|
+
|
|
217
|
+
// Update which days are selected
|
|
218
|
+
const dayColumnsRect = dayColumnsContainer.value.getBoundingClientRect()
|
|
219
|
+
const minDayIndex = Math.min(dragState.value.startDay, targetDayIndex)
|
|
220
|
+
const maxDayIndex = Math.max(dragState.value.startDay, targetDayIndex)
|
|
221
|
+
|
|
222
|
+
// Get the left edge of the leftmost selected day
|
|
223
|
+
const leftDayEl = dayColumns.value[minDayIndex]
|
|
224
|
+
if (!leftDayEl) return
|
|
225
|
+
const leftDayRect = leftDayEl.getBoundingClientRect()
|
|
226
|
+
const leftEdge = leftDayRect.left - dayColumnsRect.left
|
|
227
|
+
|
|
228
|
+
// Get the right edge of the rightmost selected day
|
|
229
|
+
const rightDayEl = dayColumns.value[maxDayIndex]
|
|
230
|
+
if (!rightDayEl) return
|
|
231
|
+
const rightDayRect = rightDayEl.getBoundingClientRect()
|
|
232
|
+
const rightEdge = rightDayRect.right - dayColumnsRect.left
|
|
233
|
+
|
|
234
|
+
dragState.value.endDay = targetDayIndex
|
|
235
|
+
dragState.value.end = {
|
|
236
|
+
x: rightEdge,
|
|
237
|
+
y: e.clientY - dayColumnsRect.top
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Ensure the selection spans the full width of all selected days
|
|
241
|
+
dragState.value.start.x = leftEdge
|
|
177
242
|
|
|
178
|
-
|
|
179
|
-
|
|
243
|
+
if (targetDayIndex >= 0 && targetDayIndex < weekDays.value.length) {
|
|
244
|
+
// Create a clean copy of the day
|
|
245
|
+
const targetDay = new Date(weekDays.value[targetDayIndex])
|
|
246
|
+
targetDay.setHours(0, 0, 0, 0)
|
|
247
|
+
|
|
248
|
+
const endTime = getTimeFromPosition(e.clientY, targetDay)
|
|
249
|
+
dragState.value.endTime = endTime
|
|
250
|
+
}
|
|
180
251
|
}
|
|
181
252
|
|
|
182
253
|
function handleMouseUp() {
|
|
@@ -185,39 +256,53 @@ function handleMouseUp() {
|
|
|
185
256
|
let start = new Date(dragState.value.startTime)
|
|
186
257
|
let end = new Date(dragState.value.endTime)
|
|
187
258
|
|
|
188
|
-
// Ensure end time is after start time
|
|
189
|
-
if (
|
|
259
|
+
// Ensure end time is after start time - handle multi-day and reversed selections
|
|
260
|
+
if (dragState.value.startDay > dragState.value.endDay
|
|
261
|
+
|| (dragState.value.startDay === dragState.value.endDay && end < start)) {
|
|
262
|
+
[start, end] = [end, start]
|
|
263
|
+
}
|
|
190
264
|
|
|
191
265
|
emit('eventCreate', { start_time: start, end_time: end })
|
|
192
266
|
|
|
193
267
|
// Reset drag state
|
|
194
268
|
dragState.value = {
|
|
195
269
|
isDragging: false,
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
270
|
+
startDay: -1,
|
|
271
|
+
endDay: -1,
|
|
272
|
+
start: undefined,
|
|
273
|
+
end: undefined,
|
|
274
|
+
startTime: undefined,
|
|
275
|
+
endTime: undefined
|
|
200
276
|
}
|
|
201
277
|
|
|
202
278
|
document.removeEventListener('mousemove', handleMouseMove)
|
|
203
279
|
document.removeEventListener('mouseup', handleMouseUp)
|
|
204
280
|
}
|
|
205
281
|
|
|
206
|
-
function getTimeFromPosition(
|
|
207
|
-
|
|
208
|
-
|
|
282
|
+
function getTimeFromPosition(y: number, day: Date): Date {
|
|
283
|
+
if (!calendarGrid.value || !timeSlotsContainer.value) return new Date(day)
|
|
284
|
+
|
|
285
|
+
const gridRect = calendarGrid.value.getBoundingClientRect()
|
|
286
|
+
|
|
287
|
+
// Calculate relative Y position
|
|
288
|
+
const relativeY = y - gridRect.top
|
|
209
289
|
|
|
210
|
-
|
|
211
|
-
const
|
|
290
|
+
// Use the same formula as for events
|
|
291
|
+
const minutesPerSlot = slotDuration
|
|
292
|
+
const slotsFromTop = relativeY / slotHeight
|
|
293
|
+
const minutes = Math.floor(slotsFromTop * minutesPerSlot)
|
|
212
294
|
|
|
213
|
-
const date = new Date(
|
|
214
|
-
date.setHours(Math.floor(minutes / 60))
|
|
215
|
-
|
|
295
|
+
const date = new Date(day)
|
|
296
|
+
date.setHours(Math.floor(minutes / 60) - 1)
|
|
297
|
+
const roundedMinutes = Math.round((minutes % 60) / 5) * 5
|
|
298
|
+
date.setMinutes(roundedMinutes)
|
|
299
|
+
date.setSeconds(0)
|
|
300
|
+
date.setMilliseconds(0)
|
|
216
301
|
|
|
217
302
|
return date
|
|
218
303
|
}
|
|
219
304
|
|
|
220
|
-
// Update the current time indicator
|
|
305
|
+
// Update the current time indicator to use the same calculation as events
|
|
221
306
|
function updateCurrentTimeIndicator() {
|
|
222
307
|
const now = new Date()
|
|
223
308
|
|
|
@@ -227,37 +312,52 @@ function updateCurrentTimeIndicator() {
|
|
|
227
312
|
&& day.getFullYear() === now.getFullYear()
|
|
228
313
|
)
|
|
229
314
|
|
|
230
|
-
// Calculate position for the current time line
|
|
315
|
+
// Calculate position for the current time line - use same formula as events
|
|
231
316
|
const minutes = now.getHours() * 60 + now.getMinutes()
|
|
232
|
-
currentTimeTop.value = (minutes / slotDuration) *
|
|
317
|
+
currentTimeTop.value = (minutes / slotDuration) * slotHeight
|
|
233
318
|
}
|
|
234
319
|
|
|
235
|
-
//
|
|
236
|
-
function
|
|
237
|
-
|
|
238
|
-
event
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
)
|
|
320
|
+
// Update the event handling to emit the openPopover event
|
|
321
|
+
function handleEventSelection(event: CalendarEvent, domEvent?: MouseEvent) {
|
|
322
|
+
if (!slots.eventContent) {
|
|
323
|
+
emit('eventClick', event)
|
|
324
|
+
return
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Calculate position from DOM event if available
|
|
328
|
+
if (domEvent) {
|
|
329
|
+
const rect = (domEvent.currentTarget as HTMLElement).getBoundingClientRect()
|
|
330
|
+
const position = {
|
|
331
|
+
top: rect.top + window.scrollY + (rect.height / 2),
|
|
332
|
+
left: rect.left + window.scrollX + rect.width + 10
|
|
333
|
+
}
|
|
334
|
+
emit('openPopover', event, position)
|
|
335
|
+
} else {
|
|
336
|
+
emit('openPopover', event)
|
|
337
|
+
}
|
|
244
338
|
}
|
|
245
339
|
|
|
246
|
-
function
|
|
247
|
-
|
|
340
|
+
function setDayColumnRef(el: Element | ComponentPublicInstance | null | undefined, index: number) {
|
|
341
|
+
// Ensure the array is the right size
|
|
342
|
+
while (dayColumns.value.length <= index) {
|
|
343
|
+
dayColumns.value.push(null as unknown as HTMLElement)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (el) {
|
|
347
|
+
dayColumns.value[index] = el instanceof Element ? el as HTMLElement : (el.$el as HTMLElement)
|
|
348
|
+
} else {
|
|
349
|
+
// If el is undefined or null, we might still want to keep track of this slot
|
|
350
|
+
dayColumns.value[index] = null as unknown as HTMLElement
|
|
351
|
+
}
|
|
248
352
|
}
|
|
249
353
|
|
|
250
354
|
// Lifecycle hooks
|
|
251
355
|
onMounted(() => {
|
|
252
|
-
document.addEventListener('mousedown', handleMouseDown)
|
|
253
|
-
|
|
254
|
-
// Initialize current time indicator and set up interval to update it
|
|
255
356
|
updateCurrentTimeIndicator()
|
|
256
357
|
currentTimeInterval.value = setInterval(updateCurrentTimeIndicator, 60000)
|
|
257
358
|
})
|
|
258
359
|
|
|
259
360
|
onUnmounted(() => {
|
|
260
|
-
document.removeEventListener('mousedown', handleMouseDown)
|
|
261
361
|
document.removeEventListener('mousemove', handleMouseMove)
|
|
262
362
|
document.removeEventListener('mouseup', handleMouseUp)
|
|
263
363
|
|
|
@@ -269,13 +369,13 @@ onUnmounted(() => {
|
|
|
269
369
|
|
|
270
370
|
<template>
|
|
271
371
|
<div class="w-100p overflow-hidden m_overflow h-100p grid">
|
|
272
|
-
<div class="weekGrid border-bottom me-1">
|
|
372
|
+
<div ref="calendarGrid" class="weekGrid border-bottom me-1">
|
|
273
373
|
<div />
|
|
274
374
|
<div
|
|
275
375
|
v-for="day in weekDays" :key="day.toISOString()"
|
|
276
376
|
class="day-header p-05 txt-center"
|
|
277
377
|
>
|
|
278
|
-
{{
|
|
378
|
+
{{ formatDate(day, { fmt: 'DDD' }) }}
|
|
279
379
|
<span
|
|
280
380
|
class="txt-12 round p-025"
|
|
281
381
|
:class="{
|
|
@@ -283,24 +383,31 @@ onUnmounted(() => {
|
|
|
283
383
|
'bg-primary color-white': day.toDateString() === new Date().toDateString(),
|
|
284
384
|
}"
|
|
285
385
|
>
|
|
286
|
-
{{
|
|
386
|
+
{{ formatDate(day, { fmt: 'DD' }) }}
|
|
287
387
|
</span>
|
|
288
388
|
</div>
|
|
289
389
|
</div>
|
|
290
390
|
<div class="overflow h-100p pe-05">
|
|
291
|
-
<div class="weekGrid border-end relative"
|
|
292
|
-
<div>
|
|
391
|
+
<div ref="dayColumnsContainer" class="weekGrid border-end relative">
|
|
392
|
+
<div ref="timeSlotsContainer">
|
|
293
393
|
<div v-for="slot in timeSlots" :key="slot.time" class="txt-light txt-12 color-gray flex justify-content-center bg-gray-light border-start" :style="{ height: `${slotHeight}px` }">
|
|
294
394
|
{{ slot.time }}
|
|
295
395
|
</div>
|
|
296
396
|
</div>
|
|
297
397
|
|
|
298
|
-
|
|
398
|
+
<!-- Current time indicator - ensure it aligns with the time slots and events -->
|
|
399
|
+
<div v-if="isToday" class="absolute end w-100p z-2 flex pointer-events-none ps-4-5" :style="{ top: `${currentTimeTop}px` }">
|
|
299
400
|
<div class="current-time-dot h-10px aspect-ratio-1 round bg-primary" />
|
|
300
401
|
<div class="current-time-line w-100p bg-primary" />
|
|
301
402
|
</div>
|
|
302
403
|
|
|
303
|
-
<div
|
|
404
|
+
<div
|
|
405
|
+
v-for="(day, index) in weekDays"
|
|
406
|
+
:key="day.toISOString()"
|
|
407
|
+
:ref="el => setDayColumnRef(el, index)"
|
|
408
|
+
class="day-column top bottom border-start relative"
|
|
409
|
+
@mousedown="handleMouseDown($event, day)"
|
|
410
|
+
>
|
|
304
411
|
<template
|
|
305
412
|
v-for="event in processedEvents.filter(e =>
|
|
306
413
|
new Date(e.start_time).toDateString() === day.toDateString())"
|
|
@@ -315,118 +422,104 @@ onUnmounted(() => {
|
|
|
315
422
|
width: `${event.width}%`,
|
|
316
423
|
backgroundColor: event.color || 'var(--bgl-primary)',
|
|
317
424
|
}"
|
|
318
|
-
@
|
|
425
|
+
@mousedown.stop
|
|
426
|
+
@click.stop="handleEventSelection(event, $event)"
|
|
319
427
|
>
|
|
320
428
|
<div class="overflow-hidden color-white p-025 txt12 h-100p">
|
|
321
429
|
<div class="white-space ellipsis-1">
|
|
322
430
|
{{ event.title }}
|
|
323
431
|
</div>
|
|
324
432
|
<div class="txt10 opacity-8">
|
|
325
|
-
{{
|
|
433
|
+
{{ formatDate(event.start_time, { fmt: 'HH:mm' }) }} - {{ formatDate(event.end_time, { fmt: 'HH:mm' }) }}
|
|
326
434
|
</div>
|
|
327
435
|
</div>
|
|
328
436
|
</div>
|
|
329
437
|
</template>
|
|
330
438
|
</div>
|
|
331
439
|
|
|
332
|
-
<!-- Drag selection preview -->
|
|
440
|
+
<!-- Drag selection preview - ensure it aligns with time slots and events -->
|
|
333
441
|
<div
|
|
334
442
|
v-if="dragState.isDragging && dragState.start && dragState.end"
|
|
335
|
-
class="drag-preview absolute bg-primary pointer-events-none"
|
|
443
|
+
class="drag-preview absolute bg-primary-tint pointer-events-none overflow-hidden opacity-7 z-1"
|
|
336
444
|
:style="{
|
|
337
445
|
left: `${Math.min(dragState.start.x, dragState.end.x)}px`,
|
|
338
446
|
top: `${Math.min(dragState.start.y, dragState.end.y)}px`,
|
|
339
447
|
width: `${Math.abs(dragState.end.x - dragState.start.x)}px`,
|
|
340
448
|
height: `${Math.abs(dragState.end.y - dragState.start.y)}px`,
|
|
341
449
|
}"
|
|
342
|
-
|
|
450
|
+
>
|
|
451
|
+
<div class="color-primary txt-12 p-025">
|
|
452
|
+
{{ dragState.startTime ? formatDate(dragState.startTime, { fmt: 'HH:mm' }) : '' }} - {{ dragState.endTime ? formatDate(dragState.endTime, { fmt: 'HH:mm' }) : '' }}
|
|
453
|
+
</div>
|
|
454
|
+
</div>
|
|
343
455
|
</div>
|
|
344
456
|
</div>
|
|
345
|
-
|
|
346
|
-
<!-- Custom Popover -->
|
|
347
|
-
<Card
|
|
348
|
-
v-if="showPopover && activeEvent"
|
|
349
|
-
ref="popoverRef"
|
|
350
|
-
v-click-outside="closePopover"
|
|
351
|
-
thin
|
|
352
|
-
class="custom-popover fixed z-999 radius-1 bg-white "
|
|
353
|
-
:style="{
|
|
354
|
-
top: `${popoverPosition.top}px`,
|
|
355
|
-
left: `${popoverPosition.left}px`,
|
|
356
|
-
|
|
357
|
-
}"
|
|
358
|
-
>
|
|
359
|
-
<slot name="eventContent" :event="activeEvent" />
|
|
360
|
-
</Card>
|
|
361
457
|
<div class="border-bottom me-1" />
|
|
362
458
|
</div>
|
|
363
459
|
</template>
|
|
364
460
|
|
|
365
461
|
<style scoped>
|
|
366
|
-
.weekGrid{
|
|
462
|
+
.weekGrid {
|
|
367
463
|
display: grid;
|
|
368
464
|
grid-template-columns: 5rem repeat(7, 1fr);
|
|
369
465
|
}
|
|
370
466
|
|
|
371
467
|
.days-column {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
.time-slot {
|
|
378
|
-
height: 30px;
|
|
379
|
-
display: flex;
|
|
380
|
-
align-items: center;
|
|
381
|
-
justify-content: center;
|
|
382
|
-
color: var(--text-muted);
|
|
468
|
+
flex-grow: 1;
|
|
469
|
+
display: flex;
|
|
383
470
|
}
|
|
384
471
|
|
|
385
|
-
.
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
position: relative;
|
|
472
|
+
.day-column {
|
|
473
|
+
flex: 1;
|
|
474
|
+
position: relative; /* Ensure absolute positioning works properly */
|
|
475
|
+
min-height: 100%; /* Ensure column fills the full height */
|
|
390
476
|
}
|
|
391
477
|
|
|
392
|
-
|
|
393
|
-
|
|
478
|
+
/* Add consistent styling for the time slots */
|
|
479
|
+
.txt-light {
|
|
480
|
+
padding: 0.5rem 0;
|
|
481
|
+
box-sizing: border-box;
|
|
482
|
+
display: flex;
|
|
483
|
+
align-items: flex-start;
|
|
484
|
+
justify-content: center;
|
|
394
485
|
}
|
|
395
486
|
|
|
396
487
|
.event {
|
|
397
|
-
|
|
488
|
+
margin-right: 2px;
|
|
489
|
+
box-sizing: border-box;
|
|
398
490
|
}
|
|
399
491
|
|
|
400
492
|
.event:hover {
|
|
401
|
-
|
|
493
|
+
z-index: 2;
|
|
402
494
|
}
|
|
403
495
|
|
|
404
496
|
.drag-preview {
|
|
405
|
-
|
|
497
|
+
border: 1px solid var(--bgl-primary);
|
|
498
|
+
background-color: rgba(var(--bgl-primary-rgb), 0.1);
|
|
499
|
+
box-sizing: border-box; /* Ensure consistent sizing */
|
|
406
500
|
}
|
|
407
501
|
|
|
408
502
|
.current-time-line {
|
|
409
|
-
|
|
503
|
+
height: 2px;
|
|
504
|
+
background-color: var(--bgl-primary);
|
|
410
505
|
}
|
|
411
506
|
|
|
412
|
-
.
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
animation: fadeIn 0.2s ease;
|
|
416
|
-
transform-origin: center left;
|
|
507
|
+
.current-time-dot {
|
|
508
|
+
background-color: var(--bgl-primary);
|
|
509
|
+
margin-right: -5px; /* Adjust dot position */
|
|
417
510
|
}
|
|
418
511
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
transform: scale(0.95);
|
|
423
|
-
}
|
|
424
|
-
to {
|
|
425
|
-
opacity: 1;
|
|
426
|
-
transform: scale(1);
|
|
427
|
-
}
|
|
512
|
+
/* This ensures all grid content aligns properly */
|
|
513
|
+
.overflow {
|
|
514
|
+
position: relative;
|
|
428
515
|
}
|
|
429
|
-
@media screen and (max-width: 910px) {
|
|
430
516
|
|
|
517
|
+
/* Time column headers should be aligned with their content */
|
|
518
|
+
.day-header {
|
|
519
|
+
box-sizing: border-box;
|
|
520
|
+
height: 100%;
|
|
521
|
+
display: flex;
|
|
522
|
+
flex-direction: column;
|
|
523
|
+
justify-content: center;
|
|
431
524
|
}
|
|
432
525
|
</style>
|
|
@@ -205,8 +205,10 @@ onMounted(() => {
|
|
|
205
205
|
--input-font-size: 12px;
|
|
206
206
|
opacity: 0.6;
|
|
207
207
|
--input-height: 20px;
|
|
208
|
+
width: 75px;
|
|
208
209
|
}
|
|
209
|
-
.date-picker-container .
|
|
210
|
+
.date-picker-container .txtInputIconStart input{
|
|
210
211
|
padding: 0 !important;
|
|
212
|
+
padding-inline-start: 1.25rem !important;
|
|
211
213
|
}
|
|
212
214
|
</style>
|
|
@@ -437,6 +437,13 @@ function selectDate(date: Date | null) {
|
|
|
437
437
|
|
|
438
438
|
.day:hover:not(.disabled) {
|
|
439
439
|
background-color: var(--input-bg);
|
|
440
|
+
color: var(--bgl-text-color);
|
|
441
|
+
outline: 1px solid var(--border-color);
|
|
442
|
+
}
|
|
443
|
+
.day:hover:not(.disabled).selected {
|
|
444
|
+
filter: var(--bgl-hover-filter);
|
|
445
|
+
background-color: var(--bgl-primary);
|
|
446
|
+
color: var(--bgl-white);
|
|
440
447
|
}
|
|
441
448
|
|
|
442
449
|
.day.selected {
|
|
@@ -1,24 +1,35 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { onMounted, onUnmounted, ref } from 'vue'
|
|
2
2
|
|
|
3
3
|
export function useDevice() {
|
|
4
4
|
const innerWidth = ref(window.innerWidth)
|
|
5
5
|
const isMobile = ref(window.innerWidth < 768)
|
|
6
|
+
const scrollY = ref(window.scrollY)
|
|
7
|
+
const scrollX = ref(window.scrollX)
|
|
8
|
+
const innerHeight = ref(window.innerHeight)
|
|
6
9
|
|
|
7
10
|
function updateDeviceInfo() {
|
|
8
11
|
innerWidth.value = window.innerWidth
|
|
9
12
|
isMobile.value = window.innerWidth < 768
|
|
13
|
+
scrollY.value = window.scrollY
|
|
14
|
+
scrollX.value = window.scrollX
|
|
15
|
+
innerHeight.value = window.innerHeight
|
|
10
16
|
}
|
|
11
17
|
|
|
12
18
|
onMounted(() => {
|
|
13
19
|
window.addEventListener('resize', updateDeviceInfo)
|
|
20
|
+
window.addEventListener('scroll', updateDeviceInfo)
|
|
14
21
|
})
|
|
15
22
|
|
|
16
23
|
onUnmounted(() => {
|
|
17
24
|
window.removeEventListener('resize', updateDeviceInfo)
|
|
25
|
+
window.removeEventListener('scroll', updateDeviceInfo)
|
|
18
26
|
})
|
|
19
27
|
|
|
20
28
|
return {
|
|
21
29
|
innerWidth,
|
|
22
|
-
isMobile
|
|
30
|
+
isMobile,
|
|
31
|
+
scrollY,
|
|
32
|
+
scrollX,
|
|
33
|
+
innerHeight,
|
|
23
34
|
}
|
|
24
35
|
}
|
package/src/styles/layout.css
CHANGED
|
@@ -986,6 +986,20 @@
|
|
|
986
986
|
min-height: 100%;
|
|
987
987
|
}
|
|
988
988
|
|
|
989
|
+
|
|
990
|
+
.vh-min-100,
|
|
991
|
+
.min100vh,
|
|
992
|
+
.min-100vh,
|
|
993
|
+
.h-min100vh {
|
|
994
|
+
min-height: 100vh !important;
|
|
995
|
+
}
|
|
996
|
+
.h-min-unset,
|
|
997
|
+
.min-h-unset {
|
|
998
|
+
min-height: 100%;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
|
|
989
1003
|
.min-0,
|
|
990
1004
|
.min0,
|
|
991
1005
|
.wmin0p,
|
|
@@ -277,6 +277,18 @@
|
|
|
277
277
|
min-height: 100%;
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
+
.m_h-min-unset,
|
|
281
|
+
.m_min-h-unset {
|
|
282
|
+
min-height: 100%;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.m_vh-min-100,
|
|
286
|
+
.m_min100vh,
|
|
287
|
+
.m_min-100vh,
|
|
288
|
+
.m_h-min100vh {
|
|
289
|
+
min-height: 100vh !important;
|
|
290
|
+
}
|
|
291
|
+
|
|
280
292
|
.m_min-0,
|
|
281
293
|
.m_min0,
|
|
282
294
|
.m_wmin0p,
|