@bagelink/vue 1.12.19 → 1.12.25

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 (43) hide show
  1. package/dist/components/calendar/CalendarTypes.d.ts.map +1 -1
  2. package/dist/components/calendar/Index.vue.d.ts.map +1 -1
  3. package/dist/components/calendar/views/WeekView.vue.d.ts.map +1 -1
  4. package/dist/components/dataTable/DataTable.vue.d.ts.map +1 -1
  5. package/dist/components/form/inputs/ArrayInput.vue.d.ts.map +1 -1
  6. package/dist/components/layout/AppLayout.vue.d.ts.map +1 -1
  7. package/dist/components/layout/AppSidebar.vue.d.ts.map +1 -1
  8. package/dist/dialog/DialogForm.vue.d.ts.map +1 -1
  9. package/dist/form-flow/FormFlow.vue.d.ts.map +1 -1
  10. package/dist/form-flow/form-flow.d.ts.map +1 -1
  11. package/dist/i18n/index.d.ts.map +1 -1
  12. package/dist/index.cjs +124 -124
  13. package/dist/index.mjs +13282 -13011
  14. package/dist/plugins/bagel.d.ts.map +1 -1
  15. package/dist/style.css +1 -1
  16. package/dist/types/index.d.ts.map +1 -1
  17. package/package.json +2 -2
  18. package/src/components/Pagination.vue +1 -1
  19. package/src/components/calendar/CalendarTypes.ts +11 -0
  20. package/src/components/calendar/Index.vue +25 -4
  21. package/src/components/calendar/views/WeekView.vue +260 -16
  22. package/src/components/dataTable/DataTable.vue +10 -0
  23. package/src/components/form/inputs/ArrayInput.vue +4 -3
  24. package/src/components/layout/AppLayout.vue +4 -2
  25. package/src/components/layout/AppSidebar.vue +21 -8
  26. package/src/dialog/DialogForm.vue +7 -9
  27. package/src/form-flow/FormFlow.vue +14 -1
  28. package/src/form-flow/MultiStepForm.vue +1 -1
  29. package/src/form-flow/form-flow.ts +2 -2
  30. package/src/i18n/locales/en.json +48 -0
  31. package/src/i18n/locales/es.json +1 -0
  32. package/src/i18n/locales/fr.json +1 -0
  33. package/src/i18n/locales/he.json +48 -0
  34. package/src/i18n/locales/it.json +1 -0
  35. package/src/i18n/locales/ru.json +1 -0
  36. package/src/plugins/bagel.ts +2 -0
  37. package/src/plugins/useModal.ts +2 -2
  38. package/src/styles/buttons.css +6 -4
  39. package/src/styles/layout.css +48 -2
  40. package/src/styles/mobilLayout.css +41 -0
  41. package/src/styles/text.css +1759 -1755
  42. package/src/types/index.ts +4 -3
  43. package/src/utils/elementUtils.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/vue",
3
3
  "type": "module",
4
- "version": "1.12.19",
4
+ "version": "1.12.25",
5
5
  "description": "Bagel core sdk packages",
6
6
  "author": {
7
7
  "name": "Bagel Studio",
@@ -90,7 +90,7 @@
90
90
  "signature_pad": "^5.0.9",
91
91
  "vue-i18n": "^11.2.8",
92
92
  "vue-toastification": "^2.0.0-rc.5",
93
- "@bagelink/utils": "1.12.19"
93
+ "@bagelink/utils": "1.12.25"
94
94
  },
95
95
  "scripts": {
96
96
  "dev": "tsx watch src/index.ts",
@@ -231,7 +231,7 @@ const renderPageButtons = computed(() => {
231
231
  height: 30px;
232
232
  background-color: var(--bgl-primary);
233
233
  transition: all 0.3s ease;
234
- z-index: -1;
234
+ /* z-index: -1; */
235
235
  }
236
236
 
237
237
  .selected {
@@ -14,11 +14,22 @@ export type CalendarView = 'Week' | 'Month' | 'Day' | 'Agenda'
14
14
 
15
15
  export type WeekStart = 'Sunday' | 'Monday'
16
16
 
17
+ export interface AvailabilitySlot {
18
+ start_time: Date
19
+ end_time: Date
20
+ }
21
+
17
22
  export interface CalendarProps {
18
23
  events?: CalendarEvent[]
19
24
  startDate?: Date
20
25
  view?: CalendarView
21
26
  weekStart?: WeekStart
27
+ /** When true, renders availability blocks on the week grid */
28
+ availabilityMode?: boolean
29
+ /** When true, allows drag-to-paint editing of availability (requires availabilityMode) */
30
+ availabilityEditable?: boolean
31
+ /** Existing availability slots to display as painted blocks */
32
+ availabilitySlots?: AvailabilitySlot[]
22
33
  }
23
34
 
24
35
  export interface CalendarViewState {
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { Component } from 'vue'
3
- import type { CalendarEvent, CalendarProps, CalendarView, CalendarViewState } from './CalendarTypes'
3
+ import type { AvailabilitySlot, CalendarEvent, CalendarView, CalendarViewState, WeekStart } from './CalendarTypes'
4
4
  import { timeDelta, Btn, ListItem, Dropdown, formatDate } from '@bagelink/vue'
5
5
  import { ref, computed, onMounted } from 'vue'
6
6
  import CalendarPopover from './CalendarPopover.vue'
@@ -9,11 +9,22 @@ import DayView from './views/DayView.vue'
9
9
  import MonthView from './views/MonthView.vue'
10
10
  import WeekView from './views/WeekView.vue'
11
11
 
12
- const props = withDefaults(defineProps<CalendarProps>(), {
12
+ const props = withDefaults(defineProps<{
13
+ events?: CalendarEvent[]
14
+ startDate?: Date
15
+ view?: CalendarView
16
+ weekStart?: WeekStart
17
+ availabilityMode?: boolean
18
+ availabilityEditable?: boolean
19
+ availabilitySlots?: AvailabilitySlot[]
20
+ }>(), {
13
21
  startDate: () => new Date(),
14
22
  view: 'Week',
15
23
  weekStart: 'Sunday',
16
- events: () => []
24
+ events: () => [],
25
+ availabilityMode: false,
26
+ availabilityEditable: false,
27
+ availabilitySlots: () => []
17
28
  })
18
29
 
19
30
  const emit = defineEmits<{
@@ -24,6 +35,7 @@ const emit = defineEmits<{
24
35
  (e: 'dateChange', changeEvent: CalendarViewState): void
25
36
  (e: 'viewChange', changeEvent: CalendarViewState): void
26
37
  (e: 'ready', changeEvent: CalendarViewState): void
38
+ (e: 'availabilityChange', slots: AvailabilitySlot[]): void
27
39
  }>()
28
40
 
29
41
  const currentDate = ref(new Date(props.startDate))
@@ -117,7 +129,14 @@ defineExpose({
117
129
  closePopover
118
130
  })
119
131
 
120
- onMounted(() => { emit('ready', state.value) })
132
+ onMounted(() => {
133
+ console.log('[Calendar] props:', {
134
+ availabilityMode: props.availabilityMode,
135
+ availabilityEditable: props.availabilityEditable,
136
+ availabilitySlots: props.availabilitySlots?.length
137
+ })
138
+ emit('ready', state.value)
139
+ })
121
140
  </script>
122
141
 
123
142
  <template>
@@ -144,8 +163,10 @@ onMounted(() => { emit('ready', state.value) })
144
163
  </div>
145
164
  <component
146
165
  :is="views[currentView]" :events="events" :start-date="currentDate" :week-start="weekStart"
166
+ :availability-mode="props.availabilityMode" :availability-editable="props.availabilityEditable" :availability-slots="props.availabilitySlots"
147
167
  @event-click="handleEventClick" @event-create="handleEventCreate" @event-update="handleEventUpdate"
148
168
  @event-delete="handleEventDelete" @date-change="handleDateChange" @open-popover="openPopover"
169
+ @availability-change="(slots: AvailabilitySlot[]) => emit('availabilityChange', slots)"
149
170
  >
150
171
  <template #eventContent="{ event, close }">
151
172
  <slot name="eventContent" :event="event" :close="close" />
@@ -1,8 +1,8 @@
1
1
  <script setup lang="ts">
2
2
  import type { SetupContext, ComponentPublicInstance } from 'vue'
3
- import type { CalendarEvent, WeekStart } from '../CalendarTypes'
3
+ import type { AvailabilitySlot, CalendarEvent, WeekStart } from '../CalendarTypes'
4
4
  import { formatDate } from '@bagelink/vue'
5
- import { ref, computed, onMounted, onUnmounted, useSlots, nextTick } from 'vue'
5
+ import { ref, computed, onMounted, onUnmounted, useSlots, nextTick, watch } from 'vue'
6
6
 
7
7
  interface WeekViewEvent extends CalendarEvent {
8
8
  top: number
@@ -17,16 +17,23 @@ const props = withDefaults(defineProps<{
17
17
  events?: CalendarEvent[]
18
18
  startDate?: Date
19
19
  weekStart?: WeekStart
20
+ availabilityMode?: boolean
21
+ availabilityEditable?: boolean
22
+ availabilitySlots?: AvailabilitySlot[]
20
23
  }>(), {
21
24
  startDate: () => new Date(),
22
25
  weekStart: 'Sunday',
23
- events: () => []
26
+ events: () => [],
27
+ availabilityMode: false,
28
+ availabilityEditable: false,
29
+ availabilitySlots: () => []
24
30
  })
25
31
 
26
32
  const emit = defineEmits<{
27
33
  (e: 'eventClick', event: CalendarEvent): void
28
34
  (e: 'eventCreate', event: { start_time: Date, end_time: Date }): void
29
35
  (e: 'openPopover', event: CalendarEvent, position?: { top: number, left: number }): void
36
+ (e: 'availabilityChange', slots: AvailabilitySlot[]): void
30
37
  }>()
31
38
 
32
39
  const slots: SetupContext['slots'] = useSlots()
@@ -52,16 +59,24 @@ const dragState = ref({
52
59
  endTime: undefined as Date | undefined
53
60
  })
54
61
 
55
- // Time indicators
56
- const currentTimeTop = ref(0)
57
- const isToday = ref(false)
58
- const currentTimeInterval = ref<any>()
62
+ // ===== AVAILABILITY MODE =====
63
+ const AVAILABILITY_SNAP_MINUTES = 30
64
+ const localAvailability = ref<AvailabilitySlot[]>([])
65
+ const availDragState = ref({
66
+ isDragging: false,
67
+ mode: 'add' as 'add' | 'remove',
68
+ dayIndex: -1,
69
+ startMinute: 0,
70
+ currentMinute: 0
71
+ })
59
72
 
60
- const timeSlotsContainer = ref<HTMLElement>()
61
- const calendarGrid = ref<HTMLElement>()
62
- const dayColumns = ref<HTMLElement[]>([])
63
- const dayColumnsContainer = ref<HTMLElement>()
64
- const scrollableContainer = ref<HTMLElement>()
73
+ // Sync external availability slots to local state
74
+ watch(() => props.availabilitySlots, (slots) => {
75
+ localAvailability.value = slots.map(s => ({
76
+ start_time: new Date(s.start_time),
77
+ end_time: new Date(s.end_time)
78
+ }))
79
+ }, { immediate: true })
65
80
 
66
81
  // Calculate week days based on start date and week start preference
67
82
  const weekDays = computed(() => {
@@ -83,19 +98,197 @@ const weekDays = computed(() => {
83
98
  return days
84
99
  })
85
100
 
101
+ function snapMinutes(minutes: number): number {
102
+ return Math.round(minutes / AVAILABILITY_SNAP_MINUTES) * AVAILABILITY_SNAP_MINUTES
103
+ }
104
+
105
+ function getAvailabilitySlotsForDay(day: Date) {
106
+ return localAvailability.value.filter((slot) => {
107
+ const slotDate = new Date(slot.start_time)
108
+ return slotDate.getFullYear() === day.getFullYear()
109
+ && slotDate.getMonth() === day.getMonth()
110
+ && slotDate.getDate() === day.getDate()
111
+ }).map((slot) => {
112
+ const startMinutes = new Date(slot.start_time).getHours() * 60 + new Date(slot.start_time).getMinutes()
113
+ const endMinutes = new Date(slot.end_time).getHours() * 60 + new Date(slot.end_time).getMinutes()
114
+ return {
115
+ top: (startMinutes / slotDuration) * slotHeight,
116
+ height: ((endMinutes - startMinutes) / slotDuration) * slotHeight,
117
+ slot
118
+ }
119
+ })
120
+ }
121
+
122
+ function availabilityPreviewForDay(dayIndex: number) {
123
+ if (!availDragState.value.isDragging || availDragState.value.dayIndex !== dayIndex) return null
124
+ const minM = Math.min(availDragState.value.startMinute, availDragState.value.currentMinute)
125
+ const maxM = Math.max(availDragState.value.startMinute, availDragState.value.currentMinute)
126
+ return {
127
+ top: (minM / slotDuration) * slotHeight,
128
+ height: ((maxM - minM) / slotDuration) * slotHeight,
129
+ mode: availDragState.value.mode
130
+ }
131
+ }
132
+
133
+ function isMinuteInAvailability(day: Date, minute: number): boolean {
134
+ return localAvailability.value.some((slot) => {
135
+ const slotDate = new Date(slot.start_time)
136
+ if (slotDate.getFullYear() !== day.getFullYear()
137
+ || slotDate.getMonth() !== day.getMonth()
138
+ || slotDate.getDate() !== day.getDate()) { return false
139
+ }
140
+ const startM = slotDate.getHours() * 60 + slotDate.getMinutes()
141
+ const endM = new Date(slot.end_time).getHours() * 60 + new Date(slot.end_time).getMinutes()
142
+ return minute >= startM && minute < endM
143
+ })
144
+ }
145
+
146
+ function handleAvailMouseDown(e: MouseEvent, dayIndex: number) {
147
+ if (!props.availabilityEditable) return
148
+ e.preventDefault()
149
+ e.stopPropagation()
150
+ const day = weekDays.value[dayIndex]
151
+ const minutes = snapMinutes(getMinutesFromY(e.clientY))
152
+ const isExisting = isMinuteInAvailability(day, minutes)
153
+
154
+ availDragState.value = {
155
+ isDragging: true,
156
+ mode: isExisting ? 'remove' : 'add',
157
+ dayIndex,
158
+ startMinute: minutes,
159
+ currentMinute: minutes + AVAILABILITY_SNAP_MINUTES
160
+ }
161
+
162
+ document.addEventListener('mousemove', handleAvailMouseMove)
163
+ document.addEventListener('mouseup', handleAvailMouseUp)
164
+ }
165
+
166
+ function handleAvailMouseMove(e: MouseEvent) {
167
+ if (!availDragState.value.isDragging) return
168
+ const minutes = snapMinutes(getMinutesFromY(e.clientY))
169
+ availDragState.value.currentMinute = minutes
170
+ }
171
+
172
+ function handleAvailMouseUp() {
173
+ if (!availDragState.value.isDragging) return
174
+ const { dayIndex, startMinute, currentMinute, mode } = availDragState.value
175
+ const day = weekDays.value[dayIndex]
176
+ const minM = Math.min(startMinute, currentMinute)
177
+ const maxM = Math.max(startMinute, currentMinute)
178
+
179
+ if (maxM - minM < AVAILABILITY_SNAP_MINUTES) {
180
+ availDragState.value.isDragging = false
181
+ document.removeEventListener('mousemove', handleAvailMouseMove)
182
+ document.removeEventListener('mouseup', handleAvailMouseUp)
183
+ return
184
+ }
185
+
186
+ const newStart = new Date(day)
187
+ newStart.setHours(Math.floor(minM / 60), minM % 60, 0, 0)
188
+ const newEnd = new Date(day)
189
+ newEnd.setHours(Math.floor(maxM / 60), maxM % 60, 0, 0)
190
+
191
+ if (mode === 'add') {
192
+ // Add and merge overlapping
193
+ const otherDays = localAvailability.value.filter((s) => {
194
+ const d = new Date(s.start_time)
195
+ return d.getFullYear() !== day.getFullYear()
196
+ || d.getMonth() !== day.getMonth()
197
+ || d.getDate() !== day.getDate()
198
+ })
199
+ const sameDaySlots = localAvailability.value.filter((s) => {
200
+ const d = new Date(s.start_time)
201
+ return d.getFullYear() === day.getFullYear()
202
+ && d.getMonth() === day.getMonth()
203
+ && d.getDate() === day.getDate()
204
+ })
205
+ sameDaySlots.push({ start_time: newStart, end_time: newEnd })
206
+ // Sort and merge
207
+ sameDaySlots.sort((a, b) => new Date(a.start_time).getTime() - new Date(b.start_time).getTime())
208
+ const merged: AvailabilitySlot[] = []
209
+ for (const s of sameDaySlots) {
210
+ if (merged.length === 0) {
211
+ merged.push({ start_time: new Date(s.start_time), end_time: new Date(s.end_time) })
212
+ } else {
213
+ const last = merged[merged.length - 1]
214
+ if (new Date(s.start_time).getTime() <= new Date(last.end_time).getTime()) {
215
+ last.end_time = new Date(Math.max(new Date(last.end_time).getTime(), new Date(s.end_time).getTime()))
216
+ } else {
217
+ merged.push({ start_time: new Date(s.start_time), end_time: new Date(s.end_time) })
218
+ }
219
+ }
220
+ }
221
+ localAvailability.value = [...otherDays, ...merged]
222
+ } else {
223
+ // Remove: subtract the range from existing slots
224
+ const result: AvailabilitySlot[] = []
225
+ for (const s of localAvailability.value) {
226
+ const d = new Date(s.start_time)
227
+ if (d.getFullYear() !== day.getFullYear()
228
+ || d.getMonth() !== day.getMonth()
229
+ || d.getDate() !== day.getDate()) {
230
+ result.push(s)
231
+ continue
232
+ }
233
+ const sStart = new Date(s.start_time).getTime()
234
+ const sEnd = new Date(s.end_time).getTime()
235
+ const rStart = newStart.getTime()
236
+ const rEnd = newEnd.getTime()
237
+
238
+ // No overlap
239
+ if (sEnd <= rStart || sStart >= rEnd) {
240
+ result.push(s)
241
+ continue
242
+ }
243
+ // Left remainder
244
+ if (sStart < rStart) {
245
+ result.push({ start_time: new Date(sStart), end_time: new Date(rStart) })
246
+ }
247
+ // Right remainder
248
+ if (sEnd > rEnd) {
249
+ result.push({ start_time: new Date(rEnd), end_time: new Date(sEnd) })
250
+ }
251
+ }
252
+ localAvailability.value = result
253
+ }
254
+
255
+ emit('availabilityChange', localAvailability.value)
256
+ availDragState.value.isDragging = false
257
+ document.removeEventListener('mousemove', handleAvailMouseMove)
258
+ document.removeEventListener('mouseup', handleAvailMouseUp)
259
+ }
260
+
261
+ // Time indicators
262
+ const currentTimeTop = ref(0)
263
+ const isToday = ref(false)
264
+ const currentTimeInterval = ref<any>()
265
+
266
+ const timeSlotsContainer = ref<HTMLElement>()
267
+ const calendarGrid = ref<HTMLElement>()
268
+ const dayColumns = ref<HTMLElement[]>([])
269
+ const dayColumnsContainer = ref<HTMLElement>()
270
+ const scrollableContainer = ref<HTMLElement>()
271
+
272
+ function getMinutesFromY(clientY: number): number {
273
+ if (!dayColumnsContainer.value) return 0
274
+ const rect = dayColumnsContainer.value.getBoundingClientRect()
275
+ const relativeY = clientY - rect.top
276
+ return Math.max(0, Math.min((relativeY / slotHeight) * slotDuration, 24 * 60))
277
+ }
278
+
86
279
  // Generate hourly time slots
87
280
  const timeSlots = computed(() => {
88
- const slots = []
281
+ const items = []
89
282
  for (let hour = timeRange.start; hour < timeRange.end; hour++) {
90
283
  for (let minute = 0; minute < 60; minute += slotDuration) {
91
- slots.push({
284
+ items.push({
92
285
  hour,
93
286
  minute,
94
287
  time: `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`
95
288
  })
96
289
  }
97
290
  }
98
- return slots
291
+ return items
99
292
  })
100
293
 
101
294
  // Calculate drag preview positioning using the same formula as events
@@ -410,6 +603,11 @@ function scrollToTime(time: number) {
410
603
 
411
604
  // Lifecycle hooks
412
605
  onMounted(() => {
606
+ console.log('[WeekView] mounted with props:', {
607
+ availabilityMode: props.availabilityMode,
608
+ availabilityEditable: props.availabilityEditable,
609
+ availabilitySlotsCount: props.availabilitySlots?.length
610
+ })
413
611
  updateCurrentTimeIndicator()
414
612
  currentTimeInterval.value = setInterval(updateCurrentTimeIndicator, 60000)
415
613
 
@@ -420,6 +618,8 @@ onMounted(() => {
420
618
  onUnmounted(() => {
421
619
  document.removeEventListener('mousemove', handleMouseMove)
422
620
  document.removeEventListener('mouseup', handleMouseUp)
621
+ document.removeEventListener('mousemove', handleAvailMouseMove)
622
+ document.removeEventListener('mouseup', handleAvailMouseUp)
423
623
 
424
624
  if (currentTimeInterval.value) {
425
625
  clearInterval(currentTimeInterval.value)
@@ -466,8 +666,29 @@ onUnmounted(() => {
466
666
 
467
667
  <div
468
668
  v-for="(day, index) in weekDays" :key="day.toISOString()" :ref="el => setDayColumnRef(el, index)"
469
- class="day-column top bottom border-start relative" @mousedown="handleMouseDown($event, day)"
669
+ class="day-column top bottom border-start relative"
670
+ @mousedown="props.availabilityEditable ? handleAvailMouseDown($event, index) : handleMouseDown($event, day)"
470
671
  >
672
+ <!-- Availability painted blocks (behind events) -->
673
+ <template v-if="props.availabilityMode">
674
+ <div
675
+ v-for="(block, bi) in getAvailabilitySlotsForDay(day)" :key="`avail-${bi}`"
676
+ class="availability-block absolute start end"
677
+ :class="{ 'availability-editable': props.availabilityEditable }"
678
+ :style="{ top: `${block.top}px`, height: `${block.height}px` }"
679
+ />
680
+ <!-- Availability drag preview -->
681
+ <div
682
+ v-if="availabilityPreviewForDay(index)"
683
+ class="availability-preview absolute start end pointer-events-none"
684
+ :class="{ 'avail-remove': availabilityPreviewForDay(index)!.mode === 'remove' }"
685
+ :style="{
686
+ top: `${availabilityPreviewForDay(index)!.top}px`,
687
+ height: `${availabilityPreviewForDay(index)!.height}px`,
688
+ }"
689
+ />
690
+ </template>
691
+
471
692
  <template
472
693
  v-for="event in processedEvents.filter(e =>
473
694
  new Date(e.start_time).toDateString() === day.toDateString())" :key="event.id"
@@ -587,6 +808,29 @@ onUnmounted(() => {
587
808
  justify-content: center; */
588
809
  }
589
810
 
811
+ .availability-block {
812
+ background-color: rgba(76, 175, 80, 0.18);
813
+ border-inline-start: 3px solid rgba(76, 175, 80, 0.5);
814
+ z-index: 0;
815
+ pointer-events: none;
816
+ }
817
+
818
+ .availability-block.availability-editable {
819
+ background-color: rgba(33, 150, 243, 0.18);
820
+ border-inline-start: 3px solid rgba(33, 150, 243, 0.5);
821
+ }
822
+
823
+ .availability-preview {
824
+ background-color: rgba(76, 175, 80, 0.25);
825
+ border: 1px dashed rgba(76, 175, 80, 0.6);
826
+ z-index: 0;
827
+ }
828
+
829
+ .availability-preview.avail-remove {
830
+ background-color: rgba(244, 67, 54, 0.15);
831
+ border-color: rgba(244, 67, 54, 0.5);
832
+ }
833
+
590
834
  @media (max-width: 910px) {
591
835
  .weekGrid {
592
836
  display: grid;
@@ -412,4 +412,14 @@ tbody tr {
412
412
  tbody tr:hover {
413
413
  background: var(--bgl-gray-light);
414
414
  }
415
+
416
+ @media (max-width: 910px) {
417
+ .col {
418
+ max-width: 60vw !important;
419
+ }
420
+ .max-col-width {
421
+ max-width: 60vw !important;
422
+ }
423
+ }
424
+
415
425
  </style>
@@ -136,7 +136,7 @@ function getItemRef(i: number) {
136
136
  {{ helpText }}
137
137
  </p>
138
138
  <template v-if="!collapsible">
139
- <div v-for="(_, i) in items" :key="i" class="array-input-row grid align-items-center">
139
+ <div v-for="(_, i) in items" :key="i" class="array-input-row grid align-items-center pb-1">
140
140
  <slot :item="getItemRef(i)" :index="i" />
141
141
  <div v-if="allowDelete" class="ms-075 my-1 border-start h-100p ps-025">
142
142
  <Btn
@@ -149,13 +149,14 @@ function getItemRef(i: number) {
149
149
  <Draggable v-if="collapsible" :model-value="items" handle=".grab" :disabled="!allowReorder" class="grid gap-05 mb-05" @end="onDraggableEnd">
150
150
  <template #default="{ index: i }">
151
151
  <div class="border radius-1 overflow-hidden">
152
- <div class="grid gap-05 grid-array-line align-items-center pe-025 hover">
152
+ <div class="grid gap-0 grid-array-line align-items-center pe-025 hover">
153
153
  <Btn
154
154
  v-if="allowReorder" v-tooltip="resolveI18n('Drag to reorder')" flat thin icon="drag_indicator"
155
155
  class="grab"
156
156
  />
157
+ <div v-else />
157
158
  <Btn
158
- full-width align-txt="start" class="px-05 bg-transparent color-inherit" :ripple="false"
159
+ full-width align-txt="start" class="px-025 bg-transparent color-inherit" :ripple="false"
159
160
  :icon="minimizedItems[i] ? 'expand_more' : 'expand_less'" @click="toggleItem(i)"
160
161
  >
161
162
  <p class="ellipsis-1">
@@ -4,15 +4,17 @@ import { ref, provide, onMounted, onUnmounted, computed } from 'vue'
4
4
  interface Props {
5
5
  sidebarWidth?: string
6
6
  sidebarCardStyle?: boolean
7
+ defaultOpen?: boolean
7
8
  }
8
9
 
9
10
  const props = withDefaults(defineProps<Props>(), {
10
11
  sidebarWidth: '260px',
11
- sidebarCardStyle: false
12
+ sidebarCardStyle: false,
13
+ defaultOpen: true,
12
14
  })
13
15
 
14
16
  // Menu state
15
- const isOpen = ref(true)
17
+ const isOpen = ref(props.defaultOpen)
16
18
  const isMobile = ref(false)
17
19
 
18
20
  // Check if mobile
@@ -7,7 +7,7 @@ import { resolveI18n } from '../../i18n'
7
7
 
8
8
  // Extended interface for links with active route tracking
9
9
  interface LinkWithAction extends NavLink {
10
- activeRoutes?: string[] // נתיבים שצריכים להיות מסומנים כאקטיביים עבור הלינק הזה
10
+ activeRoutes?: string[] // Routes that should be marked as active for this link
11
11
  }
12
12
 
13
13
  interface Props {
@@ -23,10 +23,14 @@ interface Props {
23
23
  name?: string
24
24
  frame?: boolean
25
25
  activeRoutes?: string[]
26
+ centerlinks?: boolean
27
+ defaultOpen?: boolean
26
28
  }
27
29
 
28
30
  const props = withDefaults(defineProps<Props>(), {
29
31
  card: true,
32
+ centerlinks: false,
33
+ defaultOpen: true,
30
34
  bgColor: 'var(--bgl-white)',
31
35
  textColor: 'var(--bgl-black)',
32
36
  activeColor: 'var(--bgl-black)',
@@ -40,9 +44,12 @@ const route = useRoute()
40
44
  const isTransitioning = ref(false)
41
45
 
42
46
  // Inject menu state from parent
47
+ const _fallbackIsOpen = ref(props.defaultOpen)
48
+ const _fallbackIsMobile = ref(false)
49
+
43
50
  const menuState = inject('menuState', {
44
- isOpen: { value: true },
45
- isMobile: { value: false },
51
+ isOpen: _fallbackIsOpen,
52
+ isMobile: _fallbackIsMobile,
46
53
  closeOnMobile: () => void 0,
47
54
  sidebarWidth: '260px',
48
55
  sidebarCollapsedWidth: '66px',
@@ -160,7 +167,7 @@ const sidebarStyles = computed(() => {
160
167
  >
161
168
  <!-- Logo/Brand -->
162
169
  <router-link
163
- to="/" class="decoration-none flex px-05" :class="{
170
+ to="/" class="decoration-none flex siderbarLogoWrap" :class="{
164
171
  'gap-05': menuState.isOpen.value,
165
172
  'gap-0': !menuState.isOpen.value,
166
173
  }"
@@ -175,7 +182,7 @@ const sidebarStyles = computed(() => {
175
182
  </router-link>
176
183
 
177
184
  <!-- Navigation Links -->
178
- <nav class="sidebar-nav flex column flex-stretch gap-025 align-items-start scrollbar-gutter-stable">
185
+ <nav class="sidebar-nav flex column flex-stretch gap-025 align-items-start scrollbar-gutter-stable" :class="{ 'justify-content-center': props.centerlinks }">
179
186
  <Btn
180
187
  v-for="link in props.navLinks" :key="link.to"
181
188
  :title="!menuState.isOpen.value && !menuState.isMobile.value ? resolveI18n(link.label) : ''" fullWidth
@@ -183,7 +190,8 @@ const sidebarStyles = computed(() => {
183
190
  :style="{
184
191
  backgroundColor: isActiveRoute(link) ? props.activeColor : props.bgColor,
185
192
  color: isActiveRoute(link) ? 'white' : props.textColor,
186
- }" :to="link.to || '/'" @click="link.action"
193
+ }"
194
+ :to="link.to || '/'" @click="link.action"
187
195
  >
188
196
  <Icon :name="link.icon" size="1.2" />
189
197
  <span class="nav-text">
@@ -196,8 +204,13 @@ const sidebarStyles = computed(() => {
196
204
  <!-- Footer Links -->
197
205
  <Btn
198
206
  v-for="link in props.footerLinks" :key="link.to || link.label"
199
- :title="!menuState.isOpen.value && !menuState.isMobile.value ? resolveI18n(link.label) : ''" alignTxt="start"
200
- fullWidth flat :icon="link.icon" class="flex-shrink-0 px-1" :to="link.to" @click="link.action"
207
+ :title="!menuState.isOpen.value && !menuState.isMobile.value ? resolveI18n(link.label) : ''"
208
+ :style="{
209
+ color: isActiveRoute(link) ? 'white' : props.textColor,
210
+ }"
211
+ fullWidth
212
+ alignTxt="start"
213
+ flat :icon="link.icon" class="flex-shrink-0 px-1" :to="link.to" @click="link.action"
201
214
  >
202
215
  <span class="nav-text">
203
216
  {{ resolveI18n(link.label) }}
@@ -108,15 +108,13 @@ function handleClose() {
108
108
  :open="open" :title="title" :width="width" :position="position" :dismissable="dismissable"
109
109
  @update:open="$emit('update:open', $event)" @close="handleClose"
110
110
  >
111
- <form @submit.prevent="handleSubmit">
112
- <!-- Error message -->
113
- <div v-if="error" class="dialog-form-error bg-red-30 color-red radius-1 mb-1 txt14 px-1 py-075">
114
- {{ error }}
115
- </div>
116
-
117
- <!-- Form fields -->
118
- <FormFlow ref="formFlowRef" v-model="formData" :schema="schema" />
119
- </form>
111
+ <!-- Error message -->
112
+ <div v-if="error" class="dialog-form-error bg-red-30 color-red radius-1 mb-1 txt14 px-1 py-075">
113
+ {{ error }}
114
+ </div>
115
+
116
+ <!-- Form fields -->
117
+ <FormFlow ref="formFlowRef" v-model="formData" :schema="schema" @submit="handleSubmit" />
120
118
 
121
119
  <template #footer>
122
120
  <!-- Delete button (left side) -->