@goweekdays/layer-common 1.0.5 → 1.0.7

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @goweekdays/layer-common
2
2
 
3
+ ## 1.0.7
4
+
5
+ ### Patch Changes
6
+
7
+ - 341cbeb: Add confirmation dialog component
8
+
9
+ ## 1.0.6
10
+
11
+ ### Patch Changes
12
+
13
+ - b76337c: use session id instead of access & refresh token
14
+
3
15
  ## 1.0.5
4
16
 
5
17
  ### Patch Changes
@@ -0,0 +1,367 @@
1
+ <template>
2
+ <v-card variant="outlined" border="thin" rounded="xl">
3
+ <!-- Calendar Header -->
4
+ <v-card-title
5
+ class="d-flex align-center justify-space-between flex-wrap ga-4 flex-column flex-md-row"
6
+ >
7
+ <div class="d-flex align-center ga-2 justify-center justify-md-start">
8
+ <v-btn
9
+ icon="mdi-chevron-left"
10
+ variant="tonal"
11
+ size="small"
12
+ @click="previousMonth"
13
+ />
14
+ <v-chip
15
+ variant="text"
16
+ size="large"
17
+ label
18
+ class="text-h6 font-weight-medium text-center"
19
+ style="min-width: 180px"
20
+ >
21
+ {{ currentMonth }} {{ currentYear }}
22
+ </v-chip>
23
+ <v-btn
24
+ icon="mdi-chevron-right"
25
+ variant="tonal"
26
+ size="small"
27
+ @click="nextMonth"
28
+ />
29
+ </div>
30
+
31
+ <!-- Today Button -->
32
+ <v-btn
33
+ v-if="props.hideTodayButton"
34
+ variant="outlined"
35
+ size="small"
36
+ prepend-icon="mdi-calendar-today"
37
+ @click="goToToday"
38
+ >
39
+ Today
40
+ </v-btn>
41
+ </v-card-title>
42
+
43
+ <v-divider />
44
+
45
+ <!-- Month View -->
46
+ <v-card-text class="pa-0">
47
+ <!-- Days of Week Header -->
48
+ <v-sheet color="surface-bright" class="calendar-weekdays pa-0">
49
+ <v-sheet
50
+ v-for="day in daysOfWeek"
51
+ :key="day"
52
+ color="transparent"
53
+ class="d-flex align-center justify-center pa-3 weekday-cell"
54
+ style="min-height: 48px"
55
+ >
56
+ <v-chip variant="text" size="small" label>{{ day }}</v-chip>
57
+ </v-sheet>
58
+ </v-sheet>
59
+
60
+ <!-- Calendar Grid -->
61
+ <div
62
+ class="calendar-grid pa-0"
63
+ :style="{
64
+ 'grid-auto-rows': $vuetify.display.xs
65
+ ? '80px'
66
+ : $vuetify.display.sm
67
+ ? '100px'
68
+ : '120px',
69
+ }"
70
+ >
71
+ <v-hover
72
+ v-for="date in calendarDates"
73
+ :key="`${date.year}-${date.month}-${date.day}`"
74
+ v-slot="{ isHovering, props }"
75
+ >
76
+ <v-sheet
77
+ v-bind="props"
78
+ :color="getDateColor(date, isHovering || false)"
79
+ :variant="getDateVariant(date)"
80
+ class="cursor-pointer d-flex flex-column transition-all-ease calendar-day-cell"
81
+ :class="[
82
+ !date.isCurrentMonth ? 'opacity-50' : '',
83
+ $vuetify.display.xs
84
+ ? 'pa-1'
85
+ : $vuetify.display.sm
86
+ ? 'pa-2'
87
+ : 'pa-2',
88
+ ]"
89
+ :style="{
90
+ height: $vuetify.display.xs
91
+ ? '80px'
92
+ : $vuetify.display.sm
93
+ ? '100px'
94
+ : '120px',
95
+ }"
96
+ @click="selectDate(date)"
97
+ >
98
+ <!-- Day Number -->
99
+ <v-chip
100
+ v-if="date.isToday"
101
+ :color="date.isSelected ? 'secondary' : 'primary'"
102
+ variant="flat"
103
+ size="small"
104
+ class="align-self-start mb-1"
105
+ >
106
+ {{ date.day }}
107
+ </v-chip>
108
+ <span
109
+ v-else
110
+ class="font-weight-semibold text-body-2 mb-1 align-self-start"
111
+ >{{ date.day }}</span
112
+ >
113
+
114
+ <!-- Events -->
115
+ <div
116
+ class="d-flex flex-column flex-1-1 ga-1"
117
+ style="overflow: hidden"
118
+ >
119
+ <v-chip
120
+ v-for="event in date.events.slice(0, 3)"
121
+ :key="event.id"
122
+ :color="event.color || 'primary'"
123
+ variant="flat"
124
+ size="x-small"
125
+ class="align-self-stretch text-truncate"
126
+ style="height: auto !important; font-size: 0.625rem !important"
127
+ @click.stop="openEvent(event)"
128
+ >
129
+ {{ event.title }}
130
+ </v-chip>
131
+
132
+ <v-chip
133
+ v-if="date.events.length > 3"
134
+ variant="outlined"
135
+ size="x-small"
136
+ class="align-self-start"
137
+ style="font-size: 0.625rem !important"
138
+ @click.stop="showMoreEvents(date)"
139
+ >
140
+ +{{ date.events.length - 3 }} more
141
+ </v-chip>
142
+ </div>
143
+ </v-sheet>
144
+ </v-hover>
145
+ </div>
146
+ </v-card-text>
147
+ </v-card>
148
+ </template>
149
+
150
+ <script setup lang="ts">
151
+ interface CalendarEvent {
152
+ id: string;
153
+ title: string;
154
+ start: Date;
155
+ end: Date;
156
+ color: string;
157
+ description?: string;
158
+ }
159
+
160
+ interface CalendarDate {
161
+ day: number;
162
+ month: number;
163
+ year: number;
164
+ date: Date;
165
+ dateString: string;
166
+ isCurrentMonth: boolean;
167
+ isToday: boolean;
168
+ isSelected: boolean;
169
+ events: CalendarEvent[];
170
+ }
171
+
172
+ // Props
173
+ interface Props {
174
+ events?: CalendarEvent[];
175
+ selectedDate?: Date;
176
+ minDate?: Date;
177
+ maxDate?: Date;
178
+ hideTodayButton?: boolean;
179
+ }
180
+
181
+ const props = withDefaults(defineProps<Props>(), {
182
+ events: () => [],
183
+ selectedDate: () => new Date(),
184
+ minDate: undefined,
185
+ maxDate: undefined,
186
+ hideTodayButton: false,
187
+ });
188
+
189
+ // Emits
190
+ const emit = defineEmits<{
191
+ "date-selected": [date: Date];
192
+ "event-selected": [event: CalendarEvent];
193
+ "month-changed": [month: number, year: number];
194
+ }>();
195
+
196
+ // Reactive data
197
+ const currentDate = ref(new Date(props.selectedDate));
198
+ const selectedDate = ref(new Date(props.selectedDate));
199
+
200
+ // Computed properties
201
+ const currentMonth = computed(() => {
202
+ return currentDate.value.toLocaleString("default", { month: "long" });
203
+ });
204
+
205
+ const currentYear = computed(() => {
206
+ return currentDate.value.getFullYear();
207
+ });
208
+
209
+ const daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
210
+
211
+ const calendarDates = computed(() => {
212
+ const dates: CalendarDate[] = [];
213
+ const year = currentDate.value.getFullYear();
214
+ const month = currentDate.value.getMonth();
215
+
216
+ // First day of the month
217
+ const firstDay = new Date(year, month, 1);
218
+ const lastDay = new Date(year, month + 1, 0);
219
+
220
+ // Start from Sunday of the week containing the first day
221
+ const startDate = new Date(firstDay);
222
+ startDate.setDate(startDate.getDate() - startDate.getDay());
223
+
224
+ // End at Saturday of the week containing the last day
225
+ const endDate = new Date(lastDay);
226
+ endDate.setDate(endDate.getDate() + (6 - endDate.getDay()));
227
+
228
+ const today = new Date();
229
+
230
+ for (let d = new Date(startDate); d <= endDate; d.setDate(d.getDate() + 1)) {
231
+ const dateObj = new Date(d);
232
+ const dateString = dateObj.toISOString().split("T")[0];
233
+
234
+ dates.push({
235
+ day: dateObj.getDate(),
236
+ month: dateObj.getMonth(),
237
+ year: dateObj.getFullYear(),
238
+ date: dateObj,
239
+ dateString,
240
+ isCurrentMonth: dateObj.getMonth() === month,
241
+ isToday: dateObj.toDateString() === today.toDateString(),
242
+ isSelected: dateObj.toDateString() === selectedDate.value.toDateString(),
243
+ events: props.events.filter(
244
+ (event) => event.start.toDateString() === dateObj.toDateString()
245
+ ),
246
+ });
247
+ }
248
+
249
+ return dates;
250
+ });
251
+
252
+ const selectedDay = computed(() => {
253
+ const today = new Date();
254
+ return {
255
+ day: selectedDate.value.getDate(),
256
+ dayName: selectedDate.value.toLocaleDateString("default", {
257
+ weekday: "long",
258
+ }),
259
+ fullDate: selectedDate.value.toLocaleDateString("default", {
260
+ year: "numeric",
261
+ month: "long",
262
+ day: "numeric",
263
+ }),
264
+ dateString: selectedDate.value.toISOString().split("T")[0],
265
+ isToday: selectedDate.value.toDateString() === today.toDateString(),
266
+ date: selectedDate.value,
267
+ };
268
+ });
269
+
270
+ // Methods
271
+ const previousMonth = () => {
272
+ const newDate = new Date(currentDate.value);
273
+ newDate.setMonth(newDate.getMonth() - 1);
274
+ currentDate.value = newDate;
275
+ emit("month-changed", newDate.getMonth(), newDate.getFullYear());
276
+ };
277
+
278
+ const nextMonth = () => {
279
+ const newDate = new Date(currentDate.value);
280
+ newDate.setMonth(newDate.getMonth() + 1);
281
+ currentDate.value = newDate;
282
+ emit("month-changed", newDate.getMonth(), newDate.getFullYear());
283
+ };
284
+
285
+ const goToToday = () => {
286
+ const today = new Date();
287
+ currentDate.value = today;
288
+ selectedDate.value = today;
289
+ emit("date-selected", today);
290
+ emit("month-changed", today.getMonth(), today.getFullYear());
291
+ };
292
+
293
+ const selectDate = (date: CalendarDate) => {
294
+ selectedDate.value = date.date;
295
+ emit("date-selected", date.date);
296
+ };
297
+
298
+ const openEvent = (event: CalendarEvent) => {
299
+ emit("event-selected", event);
300
+ };
301
+
302
+ const showMoreEvents = (date: CalendarDate) => {
303
+ // Handle showing more events in a modal or expanded view
304
+ console.log("Show more events for", date.dateString, date.events);
305
+ };
306
+
307
+ // Helper methods for Vuetify components
308
+ const getDateColor = (date: CalendarDate, isHovering: boolean) => {
309
+ if (date.isSelected) return "secondary";
310
+ if (date.isToday) return "primary-container";
311
+ if (isHovering && date.isCurrentMonth) return "primary";
312
+ return "transparent";
313
+ };
314
+
315
+ const getDateVariant = (date: CalendarDate) => {
316
+ if (date.isSelected) return "tonal";
317
+ if (date.isToday) return "flat";
318
+ return "flat";
319
+ };
320
+
321
+ // Watch for prop changes
322
+ watch(
323
+ () => props.selectedDate,
324
+ (newDate) => {
325
+ if (newDate) {
326
+ selectedDate.value = new Date(newDate);
327
+ currentDate.value = new Date(newDate);
328
+ }
329
+ }
330
+ );
331
+ </script>
332
+
333
+ <style scoped>
334
+ /* CSS Grid layout for calendar */
335
+ .calendar-weekdays {
336
+ display: grid;
337
+ grid-template-columns: repeat(7, 1fr);
338
+ }
339
+
340
+ .calendar-grid {
341
+ display: grid;
342
+ grid-template-columns: repeat(7, 1fr);
343
+ }
344
+
345
+ .weekday-cell {
346
+ border-right: 1px solid rgba(var(--v-theme-on-surface), 0.12);
347
+ border-bottom: 1px solid rgba(var(--v-theme-on-surface), 0.12);
348
+ }
349
+
350
+ .weekday-cell:nth-child(7n) {
351
+ border-right: none; /* Remove right border on last column */
352
+ }
353
+
354
+ .calendar-day-cell {
355
+ border-right: 1px solid rgba(var(--v-theme-on-surface), 0.12);
356
+ border-bottom: 1px solid rgba(var(--v-theme-on-surface), 0.12);
357
+ }
358
+
359
+ .calendar-day-cell:nth-child(7n) {
360
+ border-right: none; /* Remove right border on last column */
361
+ }
362
+
363
+ /* Remove bottom border on last row of calendar days */
364
+ .calendar-day-cell:nth-last-child(-n + 7) {
365
+ border-bottom: none;
366
+ }
367
+ </style>
@@ -0,0 +1,67 @@
1
+ <template>
2
+ <v-card width="100%">
3
+ <v-toolbar density="compact" class="pl-4">
4
+ <span class="font-weight-medium text-h5 text-capitalize"
5
+ >Delete {{ localProps.title }}</span
6
+ >
7
+ </v-toolbar>
8
+
9
+ <v-card-text>
10
+ <p class="text-subtitle-2 text-center">
11
+ Are you sure you want to delete this
12
+ {{ localProps.title.toLowerCase() }}? This action cannot be undone.
13
+ </p>
14
+
15
+ <v-row v-if="message" no-gutters justify="center" class="mt-4">
16
+ <span class="text-caption text-error text-center">
17
+ {{ message }}
18
+ </span>
19
+ </v-row>
20
+ </v-card-text>
21
+
22
+ <v-toolbar density="compact">
23
+ <v-row no-gutters>
24
+ <v-col cols="6">
25
+ <v-btn
26
+ tile
27
+ block
28
+ size="48"
29
+ variant="text"
30
+ class="text-none"
31
+ @click="emits('cancel')"
32
+ >
33
+ Cancel
34
+ </v-btn>
35
+ </v-col>
36
+ <v-col cols="6">
37
+ <v-btn
38
+ tile
39
+ block
40
+ size="48"
41
+ color="black"
42
+ variant="flat"
43
+ class="text-none"
44
+ @click="emits('confirm')"
45
+ >
46
+ Delete {{ localProps.title }}
47
+ </v-btn>
48
+ </v-col>
49
+ </v-row>
50
+ </v-toolbar>
51
+ </v-card>
52
+ </template>
53
+
54
+ <script setup lang="ts">
55
+ const localProps = defineProps({
56
+ title: {
57
+ type: String,
58
+ default: "Title",
59
+ },
60
+ message: {
61
+ type: String,
62
+ default: "",
63
+ },
64
+ });
65
+
66
+ const emits = defineEmits(["cancel", "confirm"]);
67
+ </script>