calendarkit-pro 1.3.0 → 1.4.0
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/README.md +26 -3
- package/dist/index.d.mts +45 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +1235 -559
- package/dist/index.mjs +1201 -525
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -35,8 +35,8 @@ __export(index_exports, {
|
|
|
35
35
|
cn: () => cn
|
|
36
36
|
});
|
|
37
37
|
module.exports = __toCommonJS(index_exports);
|
|
38
|
-
var
|
|
39
|
-
var
|
|
38
|
+
var import_react22 = __toESM(require("react"));
|
|
39
|
+
var import_core5 = require("@dnd-kit/core");
|
|
40
40
|
var import_modifiers = require("@dnd-kit/modifiers");
|
|
41
41
|
var import_framer_motion4 = require("framer-motion");
|
|
42
42
|
|
|
@@ -128,7 +128,8 @@ var CalendarHeader = ({
|
|
|
128
128
|
variant: "ghost",
|
|
129
129
|
size: "icon",
|
|
130
130
|
className: "text-muted-foreground hover:text-foreground hover:bg-accent/80 rounded-xl h-10 w-10 hidden md:inline-flex transition-all duration-200",
|
|
131
|
-
onClick: onMenuClick
|
|
131
|
+
onClick: onMenuClick,
|
|
132
|
+
"aria-label": translations.toggleSidebar
|
|
132
133
|
},
|
|
133
134
|
/* @__PURE__ */ import_react.default.createElement(import_lucide_react.Menu, { className: "h-5 w-5" })
|
|
134
135
|
), /* @__PURE__ */ import_react.default.createElement(
|
|
@@ -145,7 +146,8 @@ var CalendarHeader = ({
|
|
|
145
146
|
variant: "ghost",
|
|
146
147
|
size: "icon",
|
|
147
148
|
onClick: onPrev,
|
|
148
|
-
className: "rounded-lg h-8 w-8 hover:bg-background/80 transition-all duration-200"
|
|
149
|
+
className: "rounded-lg h-8 w-8 hover:bg-background/80 transition-all duration-200",
|
|
150
|
+
"aria-label": translations.previous
|
|
149
151
|
},
|
|
150
152
|
/* @__PURE__ */ import_react.default.createElement(import_lucide_react.ChevronLeft, { className: "h-4 w-4 text-muted-foreground" })
|
|
151
153
|
), /* @__PURE__ */ import_react.default.createElement(
|
|
@@ -154,7 +156,8 @@ var CalendarHeader = ({
|
|
|
154
156
|
variant: "ghost",
|
|
155
157
|
size: "icon",
|
|
156
158
|
onClick: onNext,
|
|
157
|
-
className: "rounded-lg h-8 w-8 hover:bg-background/80 transition-all duration-200"
|
|
159
|
+
className: "rounded-lg h-8 w-8 hover:bg-background/80 transition-all duration-200",
|
|
160
|
+
"aria-label": translations.next
|
|
158
161
|
},
|
|
159
162
|
/* @__PURE__ */ import_react.default.createElement(import_lucide_react.ChevronRight, { className: "h-4 w-4 text-muted-foreground" })
|
|
160
163
|
)), /* @__PURE__ */ import_react.default.createElement("div", { className: "ml-2 md:ml-4" }, /* @__PURE__ */ import_react.default.createElement("h2", { className: "text-lg md:text-xl font-semibold text-foreground whitespace-nowrap capitalize tracking-tight" }, (0, import_date_fns.format)(currentDate, "MMMM yyyy", { locale }))))), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2 md:gap-3 w-full md:w-auto justify-end" }, onLanguageChange && language && /* @__PURE__ */ import_react.default.createElement(
|
|
@@ -163,6 +166,7 @@ var CalendarHeader = ({
|
|
|
163
166
|
variant: "ghost",
|
|
164
167
|
size: "sm",
|
|
165
168
|
onClick: () => onLanguageChange(language === "en" ? "fr" : "en"),
|
|
169
|
+
"aria-label": translations.switchLanguage,
|
|
166
170
|
className: "h-9 px-3 rounded-xl text-xs font-semibold text-muted-foreground hover:text-foreground hover:bg-accent/80 transition-all duration-200 uppercase tracking-wider"
|
|
167
171
|
},
|
|
168
172
|
language
|
|
@@ -172,7 +176,8 @@ var CalendarHeader = ({
|
|
|
172
176
|
variant: "ghost",
|
|
173
177
|
size: "icon",
|
|
174
178
|
className: "rounded-xl h-9 w-9 hover:bg-accent/80 transition-all duration-200",
|
|
175
|
-
onClick: onThemeToggle
|
|
179
|
+
onClick: onThemeToggle,
|
|
180
|
+
"aria-label": translations.toggleTheme
|
|
176
181
|
},
|
|
177
182
|
isDarkMode ? /* @__PURE__ */ import_react.default.createElement(import_lucide_react.Sun, { className: "h-4 w-4 text-amber-500" }) : /* @__PURE__ */ import_react.default.createElement(import_lucide_react.Moon, { className: "h-4 w-4 text-muted-foreground" })
|
|
178
183
|
), !hideViewSwitcher && /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center bg-muted/50 backdrop-blur-sm rounded-xl p-1" }, viewConfig.map(({ key, icon: Icon }) => /* @__PURE__ */ import_react.default.createElement(
|
|
@@ -182,6 +187,8 @@ var CalendarHeader = ({
|
|
|
182
187
|
variant: "ghost",
|
|
183
188
|
size: "sm",
|
|
184
189
|
onClick: () => onViewChange(key),
|
|
190
|
+
"aria-pressed": view === key,
|
|
191
|
+
"aria-label": translations[key],
|
|
185
192
|
className: cn(
|
|
186
193
|
"h-8 px-3 text-xs rounded-lg transition-all duration-200 gap-1.5",
|
|
187
194
|
view === key ? "bg-background shadow-sm text-foreground font-medium border-[0.5px] border-border/50" : "text-muted-foreground hover:text-foreground hover:bg-background/50"
|
|
@@ -226,7 +233,8 @@ var MiniCalendar = ({
|
|
|
226
233
|
onDateChange,
|
|
227
234
|
onViewChange,
|
|
228
235
|
className,
|
|
229
|
-
locale
|
|
236
|
+
locale,
|
|
237
|
+
labels
|
|
230
238
|
}) => {
|
|
231
239
|
const [viewDate, setViewDate] = import_react2.default.useState(currentDate);
|
|
232
240
|
import_react2.default.useEffect(() => {
|
|
@@ -264,7 +272,7 @@ var MiniCalendar = ({
|
|
|
264
272
|
size: "icon",
|
|
265
273
|
className: "h-7 w-7 rounded-md hover:bg-background/80 transition-all",
|
|
266
274
|
onClick: handlePrev,
|
|
267
|
-
"aria-label": "Previous month"
|
|
275
|
+
"aria-label": labels?.previousMonth || "Previous month"
|
|
268
276
|
},
|
|
269
277
|
/* @__PURE__ */ import_react2.default.createElement(import_lucide_react2.ChevronLeft, { className: "h-4 w-4" })
|
|
270
278
|
), /* @__PURE__ */ import_react2.default.createElement(
|
|
@@ -274,7 +282,7 @@ var MiniCalendar = ({
|
|
|
274
282
|
size: "icon",
|
|
275
283
|
className: "h-7 w-7 rounded-md hover:bg-background/80 transition-all",
|
|
276
284
|
onClick: handleNext,
|
|
277
|
-
"aria-label": "Next month"
|
|
285
|
+
"aria-label": labels?.nextMonth || "Next month"
|
|
278
286
|
},
|
|
279
287
|
/* @__PURE__ */ import_react2.default.createElement(import_lucide_react2.ChevronRight, { className: "h-4 w-4" })
|
|
280
288
|
))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "grid grid-cols-7 gap-y-2 text-center mb-2" }, weekDays.map((day, i) => /* @__PURE__ */ import_react2.default.createElement("div", { key: `${day}-${i}`, className: "text-[10px] text-muted-foreground/70 font-semibold uppercase" }, day))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "grid grid-cols-7 gap-y-1 text-center" }, days.map((day) => {
|
|
@@ -374,7 +382,50 @@ var en = {
|
|
|
374
382
|
allCaughtUp: "All caught up!",
|
|
375
383
|
noEventsScheduled: "No events scheduled",
|
|
376
384
|
noUpcoming: "Your schedule is clear",
|
|
377
|
-
noUpcomingHint: "No upcoming events to show. Create a new event to start planning."
|
|
385
|
+
noUpcomingHint: "No upcoming events to show. Create a new event to start planning.",
|
|
386
|
+
newEvent: "New Event",
|
|
387
|
+
saveChanges: "Save Changes",
|
|
388
|
+
close: "Close",
|
|
389
|
+
noTitle: "(No title)",
|
|
390
|
+
openInMaps: "Open in maps",
|
|
391
|
+
notesLabel: "Notes",
|
|
392
|
+
addNotes: "Add description or notes...",
|
|
393
|
+
attachments: "Attachments",
|
|
394
|
+
reminders: "Reminders",
|
|
395
|
+
add: "Add",
|
|
396
|
+
calendar: "Calendar",
|
|
397
|
+
select: "Select",
|
|
398
|
+
addLocation: "Add location",
|
|
399
|
+
guestSingular: "Guest",
|
|
400
|
+
addGuestPlaceholder: "Add a guest email and press Enter",
|
|
401
|
+
invalidEmail: "Enter a valid email address",
|
|
402
|
+
removeGuest: "Remove {email}",
|
|
403
|
+
reminderAtTime: "At time of event",
|
|
404
|
+
reminderMinutes: "{n} minutes before",
|
|
405
|
+
reminderHour: "1 hour before",
|
|
406
|
+
reminderHours: "{n} hours before",
|
|
407
|
+
reminderDay: "1 day before",
|
|
408
|
+
reminderDays: "{n} days before",
|
|
409
|
+
reminderWeek: "1 week before",
|
|
410
|
+
removeReminder: "Remove reminder",
|
|
411
|
+
durationMinutes: "{n} min",
|
|
412
|
+
durationHours: "{n} hr",
|
|
413
|
+
durationHoursMinutes: "{h} hr {m} min",
|
|
414
|
+
moreEvents: "+{n} more",
|
|
415
|
+
idLabel: "ID: {id}",
|
|
416
|
+
previous: "Previous",
|
|
417
|
+
next: "Next",
|
|
418
|
+
previousMonth: "Previous month",
|
|
419
|
+
nextMonth: "Next month",
|
|
420
|
+
toggleSidebar: "Toggle sidebar",
|
|
421
|
+
toggleTheme: "Toggle dark mode",
|
|
422
|
+
switchLanguage: "Switch language",
|
|
423
|
+
eventColor: "Event color",
|
|
424
|
+
showLess: "Show less",
|
|
425
|
+
continuesBefore: "Started earlier",
|
|
426
|
+
continuesAfter: "Continues later",
|
|
427
|
+
durationDay: "1 day",
|
|
428
|
+
durationDays: "{n} days"
|
|
378
429
|
};
|
|
379
430
|
var fr = {
|
|
380
431
|
today: "Aujourd'hui",
|
|
@@ -443,7 +494,50 @@ var fr = {
|
|
|
443
494
|
allCaughtUp: "Tout est \xE0 jour !",
|
|
444
495
|
noEventsScheduled: "Aucun \xE9v\xE9nement pr\xE9vu",
|
|
445
496
|
noUpcoming: "Votre planning est libre",
|
|
446
|
-
noUpcomingHint: "Aucun \xE9v\xE9nement \xE0 venir. Cr\xE9ez un nouvel \xE9v\xE9nement pour commencer \xE0 planifier."
|
|
497
|
+
noUpcomingHint: "Aucun \xE9v\xE9nement \xE0 venir. Cr\xE9ez un nouvel \xE9v\xE9nement pour commencer \xE0 planifier.",
|
|
498
|
+
newEvent: "Nouvel \xE9v\xE9nement",
|
|
499
|
+
saveChanges: "Enregistrer",
|
|
500
|
+
close: "Fermer",
|
|
501
|
+
noTitle: "(Sans titre)",
|
|
502
|
+
openInMaps: "Ouvrir dans Maps",
|
|
503
|
+
notesLabel: "Notes",
|
|
504
|
+
addNotes: "Ajouter une description ou des notes\u2026",
|
|
505
|
+
attachments: "Pi\xE8ces jointes",
|
|
506
|
+
reminders: "Rappels",
|
|
507
|
+
add: "Ajouter",
|
|
508
|
+
calendar: "Calendrier",
|
|
509
|
+
select: "Choisir",
|
|
510
|
+
addLocation: "Ajouter un lieu",
|
|
511
|
+
guestSingular: "Invit\xE9",
|
|
512
|
+
addGuestPlaceholder: "Ajoutez l'e-mail d'un invit\xE9 puis Entr\xE9e",
|
|
513
|
+
invalidEmail: "Saisissez une adresse e-mail valide",
|
|
514
|
+
removeGuest: "Retirer {email}",
|
|
515
|
+
reminderAtTime: "Au moment de l'\xE9v\xE9nement",
|
|
516
|
+
reminderMinutes: "{n} minutes avant",
|
|
517
|
+
reminderHour: "1 heure avant",
|
|
518
|
+
reminderHours: "{n} heures avant",
|
|
519
|
+
reminderDay: "1 jour avant",
|
|
520
|
+
reminderDays: "{n} jours avant",
|
|
521
|
+
reminderWeek: "1 semaine avant",
|
|
522
|
+
removeReminder: "Supprimer le rappel",
|
|
523
|
+
durationMinutes: "{n} min",
|
|
524
|
+
durationHours: "{n} h",
|
|
525
|
+
durationHoursMinutes: "{h} h {m} min",
|
|
526
|
+
moreEvents: "+{n} de plus",
|
|
527
|
+
idLabel: "ID : {id}",
|
|
528
|
+
previous: "Pr\xE9c\xE9dent",
|
|
529
|
+
next: "Suivant",
|
|
530
|
+
previousMonth: "Mois pr\xE9c\xE9dent",
|
|
531
|
+
nextMonth: "Mois suivant",
|
|
532
|
+
toggleSidebar: "Afficher ou masquer la barre lat\xE9rale",
|
|
533
|
+
toggleTheme: "Basculer le th\xE8me sombre",
|
|
534
|
+
switchLanguage: "Changer de langue",
|
|
535
|
+
eventColor: "Couleur de l'\xE9v\xE9nement",
|
|
536
|
+
showLess: "R\xE9duire",
|
|
537
|
+
continuesBefore: "A commenc\xE9 avant",
|
|
538
|
+
continuesAfter: "Continue apr\xE8s",
|
|
539
|
+
durationDay: "1 jour",
|
|
540
|
+
durationDays: "{n} jours"
|
|
447
541
|
};
|
|
448
542
|
|
|
449
543
|
// src/core/format.ts
|
|
@@ -486,7 +580,18 @@ function timeZoneAbbreviation(date, timeZone) {
|
|
|
486
580
|
}
|
|
487
581
|
}
|
|
488
582
|
function resolveTranslations(language, overrides) {
|
|
489
|
-
|
|
583
|
+
const defined = Object.fromEntries(Object.entries(overrides ?? {}).filter(([, value]) => value !== void 0));
|
|
584
|
+
return { ...language === "fr" ? fr : en, ...defined };
|
|
585
|
+
}
|
|
586
|
+
function interpolate(template, values) {
|
|
587
|
+
return template.replace(/\{(\w+)\}/g, (match, key) => key in values ? String(values[key]) : match);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// src/core/color.ts
|
|
591
|
+
var SAFE_COLOR = /^[#\w\s%.,/()+-]+$/;
|
|
592
|
+
var FORBIDDEN = /url\(|expression\(/i;
|
|
593
|
+
function safeColor(value, fallback) {
|
|
594
|
+
return value && SAFE_COLOR.test(value.trim()) && !FORBIDDEN.test(value) ? value.trim() : fallback;
|
|
490
595
|
}
|
|
491
596
|
|
|
492
597
|
// src/components/Sidebar.tsx
|
|
@@ -514,12 +619,6 @@ var Sidebar = ({
|
|
|
514
619
|
const timer = setInterval(() => setNow(/* @__PURE__ */ new Date()), 6e4);
|
|
515
620
|
return () => clearInterval(timer);
|
|
516
621
|
}, []);
|
|
517
|
-
const defaultCalendars = [
|
|
518
|
-
{ id: "1", label: "My Calendar", color: "#3b82f6", active: true },
|
|
519
|
-
{ id: "2", label: "Birthdays", color: "#10b981", active: true },
|
|
520
|
-
{ id: "3", label: "Tasks", color: "#6366f1", active: true }
|
|
521
|
-
];
|
|
522
|
-
const displayCalendars = calendars || defaultCalendars;
|
|
523
622
|
const getAcronym = (tz) => !tz || !now ? "LOC" : timeZoneAbbreviation(now, tz);
|
|
524
623
|
const timezones = [
|
|
525
624
|
{ value: "", label: translations?.localTime || "Local Time", acronym: "LOC" },
|
|
@@ -569,7 +668,16 @@ var Sidebar = ({
|
|
|
569
668
|
},
|
|
570
669
|
/* @__PURE__ */ import_react3.default.createElement(import_lucide_react3.Plus, { className: "w-5 h-5" }),
|
|
571
670
|
/* @__PURE__ */ import_react3.default.createElement("span", { className: "text-sm" }, translations?.create || "Create")
|
|
572
|
-
)), /* @__PURE__ */ import_react3.default.createElement(
|
|
671
|
+
)), /* @__PURE__ */ import_react3.default.createElement(
|
|
672
|
+
MiniCalendar,
|
|
673
|
+
{
|
|
674
|
+
currentDate,
|
|
675
|
+
onDateChange,
|
|
676
|
+
onViewChange,
|
|
677
|
+
locale,
|
|
678
|
+
labels: { previousMonth: translations?.previousMonth, nextMonth: translations?.nextMonth }
|
|
679
|
+
}
|
|
680
|
+
), /* @__PURE__ */ import_react3.default.createElement("div", { className: "flex-1 px-4 space-y-5 mt-5" }, calendars && calendars.length > 0 && /* @__PURE__ */ import_react3.default.createElement("div", { className: "bg-muted/20 rounded-2xl p-3 border-[0px] border-border/30" }, /* @__PURE__ */ import_react3.default.createElement(
|
|
573
681
|
"div",
|
|
574
682
|
{
|
|
575
683
|
className: "flex items-center justify-between cursor-pointer hover:bg-accent/50 p-2 -m-1 rounded-xl mb-2 transition-all duration-200",
|
|
@@ -577,41 +685,40 @@ var Sidebar = ({
|
|
|
577
685
|
},
|
|
578
686
|
/* @__PURE__ */ import_react3.default.createElement("span", { className: "text-sm font-semibold text-foreground" }, translations?.calendars || "Calendars"),
|
|
579
687
|
/* @__PURE__ */ import_react3.default.createElement(import_lucide_react3.ChevronDown, { className: cn("w-4 h-4 text-muted-foreground transition-transform duration-200", calendarsOpen && "rotate-180") })
|
|
580
|
-
), calendarsOpen && /* @__PURE__ */ import_react3.default.createElement("div", { className: "space-y-1" },
|
|
688
|
+
), calendarsOpen && /* @__PURE__ */ import_react3.default.createElement("div", { className: "space-y-1" }, calendars.map((cal) => /* @__PURE__ */ import_react3.default.createElement(
|
|
581
689
|
"div",
|
|
582
690
|
{
|
|
583
691
|
key: cal.id,
|
|
584
692
|
className: "flex items-center gap-3 py-2 px-2 hover:bg-accent/60 rounded-xl cursor-pointer group transition-all duration-200",
|
|
585
693
|
onClick: () => onCalendarToggle?.(cal.id, !(cal.active ?? true))
|
|
586
694
|
},
|
|
587
|
-
/* @__PURE__ */ import_react3.default.createElement(
|
|
588
|
-
"
|
|
695
|
+
/* @__PURE__ */ import_react3.default.createElement(
|
|
696
|
+
"div",
|
|
589
697
|
{
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
`)),
|
|
698
|
+
className: "relative flex items-center justify-center",
|
|
699
|
+
style: { "--cal-color": safeColor(cal.color, "hsl(var(--primary))") }
|
|
700
|
+
},
|
|
701
|
+
/* @__PURE__ */ import_react3.default.createElement(
|
|
702
|
+
"input",
|
|
703
|
+
{
|
|
704
|
+
type: "checkbox",
|
|
705
|
+
checked: cal.active ?? true,
|
|
706
|
+
onChange: (e) => {
|
|
707
|
+
e.stopPropagation();
|
|
708
|
+
onCalendarToggle?.(cal.id, e.target.checked);
|
|
709
|
+
},
|
|
710
|
+
"aria-label": cal.label,
|
|
711
|
+
className: "peer h-5 w-5 rounded-md border-2 border-border/60 cursor-pointer appearance-none checked:border-transparent checked:bg-[var(--cal-color)] focus:ring-2 focus:ring-[var(--cal-color)] transition-all duration-200"
|
|
712
|
+
}
|
|
713
|
+
),
|
|
714
|
+
/* @__PURE__ */ import_react3.default.createElement("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none opacity-0 peer-checked:opacity-100 transition-opacity" }, /* @__PURE__ */ import_react3.default.createElement("svg", { className: "w-3.5 h-3.5 text-white", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3 }, /* @__PURE__ */ import_react3.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" })))
|
|
715
|
+
),
|
|
609
716
|
/* @__PURE__ */ import_react3.default.createElement("div", { className: "flex items-center gap-2 flex-1 min-w-0" }, /* @__PURE__ */ import_react3.default.createElement("span", { className: "text-sm text-foreground/90 truncate font-medium" }, cal.label)),
|
|
610
717
|
/* @__PURE__ */ import_react3.default.createElement(
|
|
611
718
|
"div",
|
|
612
719
|
{
|
|
613
720
|
className: "w-2 h-2 rounded-full opacity-60 group-hover:opacity-100 transition-opacity",
|
|
614
|
-
style: { backgroundColor: cal.color }
|
|
721
|
+
style: { backgroundColor: safeColor(cal.color, "hsl(var(--primary))") }
|
|
615
722
|
}
|
|
616
723
|
)
|
|
617
724
|
))))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mt-auto px-4 pt-5" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "bg-muted/20 rounded-2xl p-3" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "flex items-center gap-2 mb-3" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "p-1.5 bg-primary/10 rounded-lg" }, /* @__PURE__ */ import_react3.default.createElement(import_lucide_react3.Globe, { className: "w-4 h-4 text-primary" })), /* @__PURE__ */ import_react3.default.createElement("span", { className: "text-sm font-semibold text-foreground" }, translations?.timezone || "Timezone")), /* @__PURE__ */ import_react3.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react3.default.createElement(
|
|
@@ -640,10 +747,13 @@ var Sidebar = ({
|
|
|
640
747
|
};
|
|
641
748
|
|
|
642
749
|
// src/views/MonthView.tsx
|
|
643
|
-
var
|
|
644
|
-
var
|
|
750
|
+
var import_react7 = __toESM(require("react"));
|
|
751
|
+
var import_date_fns10 = require("date-fns");
|
|
645
752
|
|
|
646
753
|
// src/core/events.ts
|
|
754
|
+
var import_date_fns8 = require("date-fns");
|
|
755
|
+
|
|
756
|
+
// src/core/allDay.ts
|
|
647
757
|
var import_date_fns7 = require("date-fns");
|
|
648
758
|
|
|
649
759
|
// src/core/timezone.ts
|
|
@@ -704,6 +814,91 @@ function displayToday(tz, now = /* @__PURE__ */ new Date()) {
|
|
|
704
814
|
return (0, import_date_fns6.startOfDay)(toDisplay(now, tz));
|
|
705
815
|
}
|
|
706
816
|
|
|
817
|
+
// src/core/allDay.ts
|
|
818
|
+
var DAY_EVENT_MIN_MS = 24 * 60 * 60 * 1e3;
|
|
819
|
+
function isDayEvent(event) {
|
|
820
|
+
return event.allDay === true || event.end.getTime() - event.start.getTime() >= DAY_EVENT_MIN_MS;
|
|
821
|
+
}
|
|
822
|
+
var isMidnight = (date) => date.getHours() === 0 && date.getMinutes() === 0 && date.getSeconds() === 0 && date.getMilliseconds() === 0;
|
|
823
|
+
var isUtcMidnight = (date) => date.getUTCHours() === 0 && date.getUTCMinutes() === 0 && date.getUTCSeconds() === 0 && date.getUTCMilliseconds() === 0;
|
|
824
|
+
function toCalendarMidnight(date) {
|
|
825
|
+
return !isMidnight(date) && isUtcMidnight(date) ? new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()) : date;
|
|
826
|
+
}
|
|
827
|
+
function calendarDay(date) {
|
|
828
|
+
if (isMidnight(date)) return { day: (0, import_date_fns7.startOfDay)(date), midnight: true };
|
|
829
|
+
if (isUtcMidnight(date)) return { day: new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()), midnight: true };
|
|
830
|
+
return { day: (0, import_date_fns7.startOfDay)(date), midnight: false };
|
|
831
|
+
}
|
|
832
|
+
function dayEventSpan(event, tz) {
|
|
833
|
+
if (event.allDay) {
|
|
834
|
+
const firstDay2 = calendarDay(event.start).day;
|
|
835
|
+
if (event.end.getTime() <= event.start.getTime()) return { firstDay: firstDay2, lastDay: firstDay2 };
|
|
836
|
+
const end = calendarDay(event.end);
|
|
837
|
+
const lastDay2 = end.midnight ? (0, import_date_fns7.addDays)(end.day, -1) : end.day;
|
|
838
|
+
return { firstDay: firstDay2, lastDay: lastDay2 < firstDay2 ? firstDay2 : lastDay2 };
|
|
839
|
+
}
|
|
840
|
+
const firstDay = (0, import_date_fns7.startOfDay)(toDisplay(event.start, tz));
|
|
841
|
+
const lastDay = (0, import_date_fns7.startOfDay)(toDisplay(new Date(event.end.getTime() - 1), tz));
|
|
842
|
+
return { firstDay, lastDay: lastDay < firstDay ? firstDay : lastDay };
|
|
843
|
+
}
|
|
844
|
+
var partitionCache = /* @__PURE__ */ new WeakMap();
|
|
845
|
+
function partitionDayEvents(events, tz) {
|
|
846
|
+
let byZone = partitionCache.get(events);
|
|
847
|
+
if (!byZone) {
|
|
848
|
+
byZone = /* @__PURE__ */ new Map();
|
|
849
|
+
partitionCache.set(events, byZone);
|
|
850
|
+
}
|
|
851
|
+
const key = tz ?? "";
|
|
852
|
+
let result = byZone.get(key);
|
|
853
|
+
if (!result) {
|
|
854
|
+
const dayEvents = [];
|
|
855
|
+
const timedEvents = [];
|
|
856
|
+
for (const event of events) (isDayEvent(event) ? dayEvents : timedEvents).push(event);
|
|
857
|
+
result = { dayEvents, timedEvents };
|
|
858
|
+
byZone.set(key, result);
|
|
859
|
+
}
|
|
860
|
+
return result;
|
|
861
|
+
}
|
|
862
|
+
var rowCache = /* @__PURE__ */ new WeakMap();
|
|
863
|
+
function layoutDayRow(days, dayEvents, tz) {
|
|
864
|
+
if (days.length === 0) return { segments: [], laneCount: 0 };
|
|
865
|
+
const rowStart = (0, import_date_fns7.startOfDay)(days[0]);
|
|
866
|
+
const columns = days.length;
|
|
867
|
+
const key = `${tz ?? ""}|${rowStart.getTime()}|${columns}`;
|
|
868
|
+
let cache = rowCache.get(dayEvents);
|
|
869
|
+
if (!cache) {
|
|
870
|
+
cache = /* @__PURE__ */ new Map();
|
|
871
|
+
rowCache.set(dayEvents, cache);
|
|
872
|
+
}
|
|
873
|
+
const cached = cache.get(key);
|
|
874
|
+
if (cached) return cached;
|
|
875
|
+
const unplaced = [];
|
|
876
|
+
for (const event of dayEvents) {
|
|
877
|
+
const { firstDay, lastDay } = dayEventSpan(event, tz);
|
|
878
|
+
const first = (0, import_date_fns7.differenceInCalendarDays)(firstDay, rowStart);
|
|
879
|
+
const last = (0, import_date_fns7.differenceInCalendarDays)(lastDay, rowStart);
|
|
880
|
+
if (last < 0 || first >= columns) continue;
|
|
881
|
+
const startCol = Math.max(first, 0);
|
|
882
|
+
const endCol = Math.min(last, columns - 1);
|
|
883
|
+
unplaced.push({ event, startCol, span: endCol - startCol + 1, continuesBefore: first < 0, continuesAfter: last >= columns });
|
|
884
|
+
}
|
|
885
|
+
unplaced.sort((a, b) => a.startCol - b.startCol || b.span - a.span || (a.event.id < b.event.id ? -1 : a.event.id > b.event.id ? 1 : 0));
|
|
886
|
+
const occupied = [];
|
|
887
|
+
const segments = [];
|
|
888
|
+
for (const segment of unplaced) {
|
|
889
|
+
let lane = occupied.findIndex((row) => row.slice(segment.startCol, segment.startCol + segment.span).every((taken) => !taken));
|
|
890
|
+
if (lane === -1) {
|
|
891
|
+
lane = occupied.length;
|
|
892
|
+
occupied.push(new Array(columns).fill(false));
|
|
893
|
+
}
|
|
894
|
+
for (let c = segment.startCol; c < segment.startCol + segment.span; c++) occupied[lane][c] = true;
|
|
895
|
+
segments.push({ ...segment, lane });
|
|
896
|
+
}
|
|
897
|
+
const layout = { segments, laneCount: occupied.length };
|
|
898
|
+
cache.set(key, layout);
|
|
899
|
+
return layout;
|
|
900
|
+
}
|
|
901
|
+
|
|
707
902
|
// src/core/events.ts
|
|
708
903
|
var toDate = (value) => value === void 0 || value === null ? void 0 : value instanceof Date ? value : new Date(value);
|
|
709
904
|
var isValidDate = (date) => !!date && !Number.isNaN(date.getTime());
|
|
@@ -712,29 +907,35 @@ var normalizedList = /* @__PURE__ */ new WeakMap();
|
|
|
712
907
|
function normalizeEvent(event) {
|
|
713
908
|
const cached = normalizedEvent.get(event);
|
|
714
909
|
if (cached !== void 0) return cached;
|
|
715
|
-
const
|
|
716
|
-
const
|
|
910
|
+
const day = (value) => event.allDay && value ? toCalendarMidnight(value) : value;
|
|
911
|
+
const start = day(toDate(event.start));
|
|
912
|
+
const end = day(toDate(event.end));
|
|
717
913
|
let result = null;
|
|
718
914
|
if (!isValidDate(start) || !isValidDate(end)) {
|
|
719
915
|
warnOnce(`invalid-date:${event.id}`, `Event "${event.id}" has an invalid start or end date and was skipped.`);
|
|
720
916
|
} else if (end.getTime() < start.getTime()) {
|
|
721
917
|
warnOnce(`end-before-start:${event.id}`, `Event "${event.id}" ends before it starts and was skipped.`);
|
|
722
918
|
} else {
|
|
723
|
-
const needsCopy = start !== event.start || end !== event.end || needsRecurrenceCopy(event);
|
|
919
|
+
const needsCopy = start !== event.start || end !== event.end || needsRecurrenceCopy(event) || !!event.allDay && dateOnlyRecurrence(event);
|
|
724
920
|
result = needsCopy ? {
|
|
725
921
|
...event,
|
|
726
922
|
start,
|
|
727
923
|
end,
|
|
728
924
|
recurrence: event.recurrence && {
|
|
729
925
|
...event.recurrence,
|
|
730
|
-
until: toDate(event.recurrence.until),
|
|
731
|
-
exdates: event.recurrence.exdates?.map((d) => toDate(d))
|
|
926
|
+
until: day(toDate(event.recurrence.until)),
|
|
927
|
+
exdates: event.recurrence.exdates?.map((d) => day(toDate(d)))
|
|
732
928
|
}
|
|
733
929
|
} : event;
|
|
734
930
|
}
|
|
735
931
|
normalizedEvent.set(event, result);
|
|
736
932
|
return result;
|
|
737
933
|
}
|
|
934
|
+
function dateOnlyRecurrence(event) {
|
|
935
|
+
const r = event.recurrence;
|
|
936
|
+
const changes = (d) => d instanceof Date && toCalendarMidnight(d) !== d;
|
|
937
|
+
return !!r && (changes(r.until) || !!r.exdates?.some(changes));
|
|
938
|
+
}
|
|
738
939
|
function needsRecurrenceCopy(event) {
|
|
739
940
|
const r = event.recurrence;
|
|
740
941
|
if (!r) return false;
|
|
@@ -757,7 +958,7 @@ function normalizeEvents(events) {
|
|
|
757
958
|
normalizedList.set(events, result);
|
|
758
959
|
return result;
|
|
759
960
|
}
|
|
760
|
-
var dayKey = (wall) => (0,
|
|
961
|
+
var dayKey = (wall) => (0, import_date_fns8.format)(wall, "yyyy-MM-dd");
|
|
761
962
|
function memoByZone(cache, events, tz, compute) {
|
|
762
963
|
let byZone = cache.get(events);
|
|
763
964
|
if (!byZone) {
|
|
@@ -795,10 +996,10 @@ function segmentsByDisplayDay(events, tz, range) {
|
|
|
795
996
|
const rawEnd = toDisplay(event.end, tz);
|
|
796
997
|
const wallEnd = rawEnd < wallStart ? wallStart : rawEnd;
|
|
797
998
|
if (range && (wallEnd < range.start || wallStart >= range.end)) continue;
|
|
798
|
-
let day = (0,
|
|
999
|
+
let day = (0, import_date_fns8.startOfDay)(range && wallStart < range.start ? range.start : wallStart);
|
|
799
1000
|
const stop = range && wallEnd > range.end ? range.end : wallEnd;
|
|
800
1001
|
do {
|
|
801
|
-
const next = (0,
|
|
1002
|
+
const next = (0, import_date_fns8.addDays)(day, 1);
|
|
802
1003
|
const start = wallStart > day ? wallStart : day;
|
|
803
1004
|
const end = wallEnd < next ? wallEnd : next;
|
|
804
1005
|
if (end > start || wallStart.getTime() === wallEnd.getTime()) {
|
|
@@ -815,25 +1016,153 @@ function segmentsByDisplayDay(events, tz, range) {
|
|
|
815
1016
|
});
|
|
816
1017
|
}
|
|
817
1018
|
|
|
818
|
-
// src/components/
|
|
1019
|
+
// src/components/AllDayBar.tsx
|
|
819
1020
|
var import_react4 = __toESM(require("react"));
|
|
820
1021
|
var import_core = require("@dnd-kit/core");
|
|
821
1022
|
var import_utilities = require("@dnd-kit/utilities");
|
|
1023
|
+
var import_date_fns9 = require("date-fns");
|
|
1024
|
+
var AllDayBarImpl = ({
|
|
1025
|
+
segment,
|
|
1026
|
+
rowDays,
|
|
1027
|
+
laneHeight,
|
|
1028
|
+
timezone,
|
|
1029
|
+
locale,
|
|
1030
|
+
translations,
|
|
1031
|
+
readonly,
|
|
1032
|
+
onEventClick,
|
|
1033
|
+
onEventContextMenu,
|
|
1034
|
+
onDayEventResize
|
|
1035
|
+
}) => {
|
|
1036
|
+
const { event, startCol, span, lane, continuesBefore, continuesAfter } = segment;
|
|
1037
|
+
const columns = rowDays.length;
|
|
1038
|
+
const { firstDay, lastDay } = dayEventSpan(event, timezone);
|
|
1039
|
+
const segmentOffset = (0, import_date_fns9.differenceInCalendarDays)(rowDays[startCol], firstDay);
|
|
1040
|
+
const dragData = (0, import_react4.useRef)({ event, grabDayOffset: segmentOffset });
|
|
1041
|
+
dragData.current.event = event;
|
|
1042
|
+
const dragDisabled = readonly || isEventDragDisabled(event);
|
|
1043
|
+
const { attributes, listeners, setNodeRef, transform, isDragging } = (0, import_core.useDraggable)({
|
|
1044
|
+
id: `${event.id}@day@${(0, import_date_fns9.format)(rowDays[0], "yyyy-MM-dd")}`,
|
|
1045
|
+
data: dragData.current,
|
|
1046
|
+
disabled: dragDisabled
|
|
1047
|
+
});
|
|
1048
|
+
const [resizeCols, setResizeCols] = (0, import_react4.useState)(0);
|
|
1049
|
+
const ignoreClick = (0, import_react4.useRef)(false);
|
|
1050
|
+
const canResize = !readonly && !continuesAfter && !isEventResizeDisabled(event) && !!onDayEventResize;
|
|
1051
|
+
const shownSpan = Math.max(1, Math.min(span + resizeCols, columns - startCol));
|
|
1052
|
+
const handlePointerDownCapture = (e) => {
|
|
1053
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
1054
|
+
const dayWithin = rect.width > 0 ? Math.floor((e.clientX - rect.left) / rect.width * span) : 0;
|
|
1055
|
+
dragData.current.grabDayOffset = segmentOffset + Math.min(Math.max(dayWithin, 0), span - 1);
|
|
1056
|
+
};
|
|
1057
|
+
const handleResizeStart = (e) => {
|
|
1058
|
+
e.stopPropagation();
|
|
1059
|
+
e.preventDefault();
|
|
1060
|
+
const bar = e.currentTarget.parentElement;
|
|
1061
|
+
const columnWidth = bar.getBoundingClientRect().width / span || 1;
|
|
1062
|
+
const startX = e.clientX;
|
|
1063
|
+
let delta = 0;
|
|
1064
|
+
const onMove = (moveEvent) => {
|
|
1065
|
+
delta = Math.round((moveEvent.clientX - startX) / columnWidth);
|
|
1066
|
+
setResizeCols(delta);
|
|
1067
|
+
};
|
|
1068
|
+
const stop = () => {
|
|
1069
|
+
document.removeEventListener("pointermove", onMove);
|
|
1070
|
+
document.removeEventListener("pointerup", onUp);
|
|
1071
|
+
document.removeEventListener("pointercancel", stop);
|
|
1072
|
+
setResizeCols(0);
|
|
1073
|
+
};
|
|
1074
|
+
const onUp = () => {
|
|
1075
|
+
stop();
|
|
1076
|
+
ignoreClick.current = true;
|
|
1077
|
+
setTimeout(() => {
|
|
1078
|
+
ignoreClick.current = false;
|
|
1079
|
+
}, 0);
|
|
1080
|
+
if (delta !== 0) onDayEventResize?.(event, (0, import_date_fns9.addDays)(rowDays[startCol + span - 1], delta));
|
|
1081
|
+
};
|
|
1082
|
+
document.addEventListener("pointermove", onMove);
|
|
1083
|
+
document.addEventListener("pointerup", onUp);
|
|
1084
|
+
document.addEventListener("pointercancel", stop);
|
|
1085
|
+
};
|
|
1086
|
+
const color = event.color || "hsl(var(--primary))";
|
|
1087
|
+
const dateFormat = "d MMM";
|
|
1088
|
+
const label = `${event.title}, ${(0, import_date_fns9.format)(firstDay, dateFormat, { locale })}${lastDay > firstDay ? ` \u2013 ${(0, import_date_fns9.format)(lastDay, dateFormat, { locale })}` : ""}`;
|
|
1089
|
+
return /* @__PURE__ */ import_react4.default.createElement(
|
|
1090
|
+
"div",
|
|
1091
|
+
{
|
|
1092
|
+
ref: setNodeRef,
|
|
1093
|
+
...listeners,
|
|
1094
|
+
...attributes,
|
|
1095
|
+
onPointerDownCapture: handlePointerDownCapture,
|
|
1096
|
+
role: "button",
|
|
1097
|
+
"aria-label": label,
|
|
1098
|
+
className: cn(
|
|
1099
|
+
"group absolute px-[2px] select-none",
|
|
1100
|
+
dragDisabled ? "cursor-pointer" : "cursor-grab active:cursor-grabbing touch-none"
|
|
1101
|
+
),
|
|
1102
|
+
style: {
|
|
1103
|
+
left: `${startCol / columns * 100}%`,
|
|
1104
|
+
width: `${shownSpan / columns * 100}%`,
|
|
1105
|
+
top: lane * laneHeight,
|
|
1106
|
+
height: laneHeight,
|
|
1107
|
+
transform: import_utilities.CSS.Translate.toString(transform),
|
|
1108
|
+
opacity: isDragging ? 0 : void 0,
|
|
1109
|
+
zIndex: isDragging ? 100 : 1
|
|
1110
|
+
},
|
|
1111
|
+
onClick: (e) => {
|
|
1112
|
+
e.stopPropagation();
|
|
1113
|
+
if (ignoreClick.current) {
|
|
1114
|
+
ignoreClick.current = false;
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
onEventClick?.(event);
|
|
1118
|
+
},
|
|
1119
|
+
onContextMenu: onEventContextMenu ? (e) => onEventContextMenu(event, e) : void 0
|
|
1120
|
+
},
|
|
1121
|
+
/* @__PURE__ */ import_react4.default.createElement(
|
|
1122
|
+
"div",
|
|
1123
|
+
{
|
|
1124
|
+
className: cn(
|
|
1125
|
+
"relative h-[calc(100%-4px)] mt-[2px] flex items-center gap-1 px-1.5 text-[11px] font-semibold text-white overflow-hidden shadow-sm",
|
|
1126
|
+
continuesBefore ? "rounded-l-none" : "rounded-l-md",
|
|
1127
|
+
continuesAfter ? "rounded-r-none" : "rounded-r-md"
|
|
1128
|
+
),
|
|
1129
|
+
style: { backgroundColor: color }
|
|
1130
|
+
},
|
|
1131
|
+
continuesBefore && /* @__PURE__ */ import_react4.default.createElement("span", { "aria-label": translations?.continuesBefore }, "\u2039"),
|
|
1132
|
+
/* @__PURE__ */ import_react4.default.createElement("span", { className: "truncate" }, event.title),
|
|
1133
|
+
continuesAfter && /* @__PURE__ */ import_react4.default.createElement("span", { className: "ml-auto", "aria-label": translations?.continuesAfter }, "\u203A"),
|
|
1134
|
+
canResize && /* @__PURE__ */ import_react4.default.createElement(
|
|
1135
|
+
"div",
|
|
1136
|
+
{
|
|
1137
|
+
"data-testid": "all-day-resize",
|
|
1138
|
+
className: "absolute right-0 top-0 bottom-0 w-1.5 cursor-ew-resize opacity-0 group-hover:opacity-100 bg-black/20",
|
|
1139
|
+
onPointerDown: handleResizeStart
|
|
1140
|
+
}
|
|
1141
|
+
)
|
|
1142
|
+
)
|
|
1143
|
+
);
|
|
1144
|
+
};
|
|
1145
|
+
var AllDayBar = import_react4.default.memo(AllDayBarImpl);
|
|
1146
|
+
|
|
1147
|
+
// src/components/dnd/DraggableEvent.tsx
|
|
1148
|
+
var import_react5 = __toESM(require("react"));
|
|
1149
|
+
var import_core2 = require("@dnd-kit/core");
|
|
1150
|
+
var import_utilities2 = require("@dnd-kit/utilities");
|
|
822
1151
|
var DraggableEventImpl = ({ event, dragId, grabOffsetMs, children, className, style: propStyle, ...props }) => {
|
|
823
1152
|
const dragDisabled = isEventDragDisabled(event);
|
|
824
|
-
const { attributes, listeners, setNodeRef, transform, isDragging } = (0,
|
|
1153
|
+
const { attributes, listeners, setNodeRef, transform, isDragging } = (0, import_core2.useDraggable)({
|
|
825
1154
|
id: dragId ?? event.id,
|
|
826
1155
|
data: { event, grabOffsetMs },
|
|
827
1156
|
disabled: dragDisabled
|
|
828
1157
|
});
|
|
829
1158
|
const style = {
|
|
830
1159
|
...propStyle,
|
|
831
|
-
transform:
|
|
1160
|
+
transform: import_utilities2.CSS.Translate.toString(transform),
|
|
832
1161
|
zIndex: isDragging ? 100 : propStyle?.zIndex,
|
|
833
1162
|
// Hide the original while dragging: the DragOverlay ghost is what the user follows.
|
|
834
1163
|
opacity: isDragging ? 0 : propStyle?.opacity
|
|
835
1164
|
};
|
|
836
|
-
return /* @__PURE__ */
|
|
1165
|
+
return /* @__PURE__ */ import_react5.default.createElement(
|
|
837
1166
|
"div",
|
|
838
1167
|
{
|
|
839
1168
|
ref: setNodeRef,
|
|
@@ -846,11 +1175,11 @@ var DraggableEventImpl = ({ event, dragId, grabOffsetMs, children, className, st
|
|
|
846
1175
|
children
|
|
847
1176
|
);
|
|
848
1177
|
};
|
|
849
|
-
var DraggableEvent =
|
|
1178
|
+
var DraggableEvent = import_react5.default.memo(DraggableEventImpl);
|
|
850
1179
|
|
|
851
1180
|
// src/components/dnd/DroppableCell.tsx
|
|
852
|
-
var
|
|
853
|
-
var
|
|
1181
|
+
var import_react6 = __toESM(require("react"));
|
|
1182
|
+
var import_core3 = require("@dnd-kit/core");
|
|
854
1183
|
var QUARTER_HOVER = [
|
|
855
1184
|
"hover:bg-blue-50/50 dark:hover:bg-blue-900/10",
|
|
856
1185
|
"hover:bg-blue-50/80 dark:hover:bg-blue-900/20",
|
|
@@ -864,13 +1193,13 @@ var QUARTER_ACTIVE = [
|
|
|
864
1193
|
"bg-blue-100/80 dark:bg-blue-900/40 ring-2 ring-primary ring-inset"
|
|
865
1194
|
];
|
|
866
1195
|
var quarterOf = (date) => Math.min(3, Math.floor(date.getMinutes() / 15));
|
|
867
|
-
var DroppableCellImpl = ({ id, date, resourceId, children, className, style, onClick, onSlotClick }) => {
|
|
868
|
-
const { isOver, setNodeRef } = (0,
|
|
1196
|
+
var DroppableCellImpl = ({ id, date, resourceId, allDayRow, children, className, style, onClick, onSlotClick }) => {
|
|
1197
|
+
const { isOver, setNodeRef } = (0, import_core3.useDroppable)({
|
|
869
1198
|
id,
|
|
870
|
-
data: { date, resourceId }
|
|
1199
|
+
data: { date, resourceId, allDayRow }
|
|
871
1200
|
});
|
|
872
1201
|
const quarter = quarterOf(date);
|
|
873
|
-
return /* @__PURE__ */
|
|
1202
|
+
return /* @__PURE__ */ import_react6.default.createElement(
|
|
874
1203
|
"div",
|
|
875
1204
|
{
|
|
876
1205
|
ref: setNodeRef,
|
|
@@ -892,13 +1221,13 @@ var shallowEqualStyle = (a, b) => {
|
|
|
892
1221
|
const keys = Object.keys(a);
|
|
893
1222
|
return keys.length === Object.keys(b).length && keys.every((key) => a[key] === b[key]);
|
|
894
1223
|
};
|
|
895
|
-
var DroppableCell =
|
|
1224
|
+
var DroppableCell = import_react6.default.memo(
|
|
896
1225
|
DroppableCellImpl,
|
|
897
|
-
(prev, next) => prev.id === next.id && prev.date.getTime() === next.date.getTime() && prev.resourceId === next.resourceId && prev.children === next.children && prev.className === next.className && prev.onClick === next.onClick && prev.onSlotClick === next.onSlotClick && shallowEqualStyle(prev.style, next.style)
|
|
1226
|
+
(prev, next) => prev.id === next.id && prev.date.getTime() === next.date.getTime() && prev.resourceId === next.resourceId && prev.allDayRow === next.allDayRow && prev.children === next.children && prev.className === next.className && prev.onClick === next.onClick && prev.onSlotClick === next.onSlotClick && shallowEqualStyle(prev.style, next.style)
|
|
898
1227
|
);
|
|
899
1228
|
|
|
900
1229
|
// src/views/MonthView.tsx
|
|
901
|
-
var EventItem =
|
|
1230
|
+
var EventItem = import_react7.default.memo(({ event, onEventClick, onEventContextMenu }) => /* @__PURE__ */ import_react7.default.createElement(DraggableEvent, { event }, /* @__PURE__ */ import_react7.default.createElement(
|
|
902
1231
|
"div",
|
|
903
1232
|
{
|
|
904
1233
|
className: cn(
|
|
@@ -914,61 +1243,183 @@ var EventItem = import_react6.default.memo(({ event, onEventClick }) => /* @__PU
|
|
|
914
1243
|
onClick: (e) => {
|
|
915
1244
|
e.stopPropagation();
|
|
916
1245
|
onEventClick?.(event);
|
|
917
|
-
}
|
|
1246
|
+
},
|
|
1247
|
+
onContextMenu: onEventContextMenu ? (e) => onEventContextMenu(event, e) : void 0
|
|
918
1248
|
},
|
|
919
|
-
/* @__PURE__ */
|
|
1249
|
+
/* @__PURE__ */ import_react7.default.createElement("span", { className: "font-medium" }, event.title)
|
|
920
1250
|
)));
|
|
921
1251
|
EventItem.displayName = "EventItem";
|
|
1252
|
+
var ROW_HEIGHT = 130;
|
|
1253
|
+
var LANE_HEIGHT = 20;
|
|
1254
|
+
var MAX_LANES = 3;
|
|
1255
|
+
var MAX_ITEMS = 4;
|
|
1256
|
+
var BARS_TOP = 38;
|
|
1257
|
+
var CELL_CHROME = 16 + 28 + 6;
|
|
1258
|
+
var ITEM_STEP = 29 + 4;
|
|
1259
|
+
var MORE_HEIGHT = 20;
|
|
1260
|
+
function timedSlots(visibleLanes, timedCount, hiddenBars) {
|
|
1261
|
+
if (visibleLanes === 0) return Math.min(timedCount, MAX_ITEMS);
|
|
1262
|
+
const room = ROW_HEIGHT - CELL_CHROME - visibleLanes * LANE_HEIGHT;
|
|
1263
|
+
if (hiddenBars === 0 && timedCount * ITEM_STEP - 4 <= room) return timedCount;
|
|
1264
|
+
return Math.max(0, Math.floor((room - MORE_HEIGHT) / ITEM_STEP));
|
|
1265
|
+
}
|
|
922
1266
|
var MonthView = ({
|
|
923
1267
|
currentDate,
|
|
924
1268
|
events,
|
|
925
1269
|
onEventClick,
|
|
926
1270
|
onDateClick,
|
|
927
1271
|
timezone,
|
|
928
|
-
locale
|
|
1272
|
+
locale,
|
|
1273
|
+
translations,
|
|
1274
|
+
onEventContextMenu,
|
|
1275
|
+
onDayEventResize,
|
|
1276
|
+
readonly
|
|
929
1277
|
}) => {
|
|
930
1278
|
const weekStartsOn = resolveWeekStartsOn(locale, 1);
|
|
931
|
-
const days = (0,
|
|
932
|
-
const weekDays = (0,
|
|
933
|
-
const
|
|
1279
|
+
const days = (0, import_react7.useMemo)(() => getMonthGrid(currentDate, weekStartsOn), [currentDate, weekStartsOn]);
|
|
1280
|
+
const weekDays = (0, import_react7.useMemo)(() => getWeekDays(currentDate, weekStartsOn), [currentDate, weekStartsOn]);
|
|
1281
|
+
const weeks = (0, import_react7.useMemo)(
|
|
1282
|
+
() => Array.from({ length: Math.ceil(days.length / 7) }, (_, i) => days.slice(i * 7, i * 7 + 7)),
|
|
1283
|
+
[days]
|
|
1284
|
+
);
|
|
1285
|
+
const { dayEvents, timedEvents } = partitionDayEvents(events, timezone);
|
|
1286
|
+
const eventsByDay = eventsByStartDay(timedEvents, timezone);
|
|
934
1287
|
const today = displayToday(timezone);
|
|
935
|
-
return /* @__PURE__ */
|
|
1288
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex flex-col h-full bg-background border-[0.5px] scrollbar-hide border-border/50 rounded-2xl overflow-hidden min-w-[800px] md:min-w-0 shadow-sm" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "overflow-y-auto flex-1 relative" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "grid grid-cols-7 border-b-[0.5px] border-border/50 bg-gradient-to-r from-muted/30 via-muted/40 to-muted/30 sticky top-0 z-20 backdrop-blur-sm" }, weekDays.map((day) => /* @__PURE__ */ import_react7.default.createElement(
|
|
936
1289
|
"div",
|
|
937
1290
|
{
|
|
938
1291
|
key: day.toISOString(),
|
|
939
1292
|
className: "py-3 text-center text-xs font-semibold text-muted-foreground border-r-[0.5px] border-border/30 last:border-r-0 uppercase tracking-wider"
|
|
940
1293
|
},
|
|
941
|
-
(0,
|
|
942
|
-
))),
|
|
943
|
-
const
|
|
944
|
-
const
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1294
|
+
(0, import_date_fns10.format)(day, "EEE", { locale })
|
|
1295
|
+
))), weeks.map((week) => {
|
|
1296
|
+
const { segments, laneCount } = layoutDayRow(week, dayEvents, timezone);
|
|
1297
|
+
const visibleLanes = Math.min(laneCount, MAX_LANES);
|
|
1298
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { key: week[0].toISOString(), className: "relative grid grid-cols-7", style: { height: ROW_HEIGHT } }, week.map((day, column) => {
|
|
1299
|
+
const dayKey2 = (0, import_date_fns10.format)(day, "yyyy-MM-dd");
|
|
1300
|
+
const dayTimed = eventsByDay.get(dayKey2) || [];
|
|
1301
|
+
const barsOnDay = segments.filter((s) => column >= s.startCol && column < s.startCol + s.span);
|
|
1302
|
+
const hiddenBars = barsOnDay.filter((s) => s.lane >= MAX_LANES).length;
|
|
1303
|
+
const shown = timedSlots(visibleLanes, dayTimed.length, hiddenBars);
|
|
1304
|
+
const hidden = hiddenBars + dayTimed.length - shown;
|
|
1305
|
+
const total = barsOnDay.length + dayTimed.length;
|
|
1306
|
+
const isCurrentMonth = (0, import_date_fns10.isSameMonth)(day, currentDate);
|
|
1307
|
+
const cellId = day.toISOString();
|
|
1308
|
+
return /* @__PURE__ */ import_react7.default.createElement(
|
|
1309
|
+
DroppableCell,
|
|
1310
|
+
{
|
|
1311
|
+
key: cellId,
|
|
1312
|
+
id: cellId,
|
|
1313
|
+
date: day,
|
|
1314
|
+
className: cn(
|
|
1315
|
+
"h-full p-2 border-b-[0.5px] border-r-[0.5px] border-border/30 last:border-r-0 relative transition-all duration-200 hover:bg-accent/5 flex flex-col gap-1.5 overflow-hidden group",
|
|
1316
|
+
!isCurrentMonth && "bg-muted/5 text-muted-foreground/60",
|
|
1317
|
+
(0, import_date_fns10.isSameDay)(day, today) && "bg-primary/5 ring-1 ring-inset ring-primary/20"
|
|
1318
|
+
),
|
|
1319
|
+
onClick: () => onDateClick?.(day)
|
|
1320
|
+
},
|
|
1321
|
+
/* @__PURE__ */ import_react7.default.createElement("div", { className: "flex justify-between items-start" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: cn(
|
|
1322
|
+
"text-sm font-semibold w-7 h-7 flex items-center justify-center rounded-full transition-all duration-200",
|
|
1323
|
+
(0, import_date_fns10.isSameDay)(day, today) ? "bg-primary text-primary-foreground shadow-md shadow-primary/30" : "group-hover:bg-accent"
|
|
1324
|
+
) }, (0, import_date_fns10.format)(day, "d", { locale })), total > 0 && /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-[10px] font-medium text-muted-foreground/60 bg-muted/50 px-1.5 py-0.5 rounded-full" }, total)),
|
|
1325
|
+
visibleLanes > 0 && /* @__PURE__ */ import_react7.default.createElement("div", { className: "shrink-0", style: { height: visibleLanes * LANE_HEIGHT - 6 } }),
|
|
1326
|
+
/* @__PURE__ */ import_react7.default.createElement("div", { className: "flex-1 flex flex-col gap-1 scrollbar-hide overflow-y-auto overflow-x-hidden" }, dayTimed.slice(0, shown).map((event) => /* @__PURE__ */ import_react7.default.createElement(EventItem, { key: `${event.id}-${dayKey2}`, event, onEventClick, onEventContextMenu })), hidden > 0 && // "+N more" counts hidden bars and hidden timed events, and opens the day.
|
|
1327
|
+
/* @__PURE__ */ import_react7.default.createElement(
|
|
1328
|
+
"button",
|
|
1329
|
+
{
|
|
1330
|
+
type: "button",
|
|
1331
|
+
className: "shrink-0 text-[10px] leading-4 text-primary font-semibold text-center py-0.5 px-2 rounded-md bg-primary/5 hover:bg-primary/10 cursor-pointer transition-colors",
|
|
1332
|
+
onClick: (e) => {
|
|
1333
|
+
e.stopPropagation();
|
|
1334
|
+
onDateClick?.(day);
|
|
1335
|
+
}
|
|
1336
|
+
},
|
|
1337
|
+
interpolate(translations?.moreEvents || "+{n} more", { n: hidden })
|
|
1338
|
+
))
|
|
1339
|
+
);
|
|
1340
|
+
}), /* @__PURE__ */ import_react7.default.createElement("div", { className: "absolute inset-x-0 pointer-events-none", style: { top: BARS_TOP, height: visibleLanes * LANE_HEIGHT } }, segments.filter((s) => s.lane < MAX_LANES).map((segment) => /* @__PURE__ */ import_react7.default.createElement("div", { key: `${segment.event.id}-${week[0].toISOString()}`, className: "pointer-events-auto" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
1341
|
+
AllDayBar,
|
|
949
1342
|
{
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
) }, (0, import_date_fns8.format)(day, "d", { locale })), dayEvents.length > 0 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "text-[10px] font-medium text-muted-foreground/60 bg-muted/50 px-1.5 py-0.5 rounded-full" }, dayEvents.length)),
|
|
964
|
-
/* @__PURE__ */ import_react6.default.createElement("div", { className: "flex-1 flex flex-col gap-1 scrollbar-hide overflow-y-auto overflow-x-hidden" }, dayEvents.slice(0, 4).map((event) => /* @__PURE__ */ import_react6.default.createElement(EventItem, { key: `${event.id}-${dayKey2}`, event, onEventClick })), dayEvents.length > 4 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "text-[10px] text-primary font-semibold text-center py-1 px-2 rounded-md bg-primary/5 hover:bg-primary/10 cursor-pointer transition-colors" }, "+", dayEvents.length - 4, " more"))
|
|
965
|
-
);
|
|
966
|
-
}))));
|
|
1343
|
+
segment,
|
|
1344
|
+
rowDays: week,
|
|
1345
|
+
laneHeight: LANE_HEIGHT,
|
|
1346
|
+
timezone,
|
|
1347
|
+
locale,
|
|
1348
|
+
translations,
|
|
1349
|
+
readonly,
|
|
1350
|
+
onEventClick,
|
|
1351
|
+
onEventContextMenu,
|
|
1352
|
+
onDayEventResize
|
|
1353
|
+
}
|
|
1354
|
+
)))));
|
|
1355
|
+
})));
|
|
967
1356
|
};
|
|
968
1357
|
|
|
969
1358
|
// src/views/WeekView.tsx
|
|
1359
|
+
var import_react10 = __toESM(require("react"));
|
|
1360
|
+
var import_date_fns13 = require("date-fns");
|
|
1361
|
+
|
|
1362
|
+
// src/components/AllDayRow.tsx
|
|
970
1363
|
var import_react8 = __toESM(require("react"));
|
|
971
|
-
var
|
|
1364
|
+
var import_date_fns11 = require("date-fns");
|
|
1365
|
+
var LANE_HEIGHT2 = 22;
|
|
1366
|
+
var AllDayRowImpl = ({
|
|
1367
|
+
days,
|
|
1368
|
+
dayEvents,
|
|
1369
|
+
timezone,
|
|
1370
|
+
locale,
|
|
1371
|
+
translations,
|
|
1372
|
+
readonly,
|
|
1373
|
+
gutterClassName,
|
|
1374
|
+
maxLanes = 2,
|
|
1375
|
+
onEventClick,
|
|
1376
|
+
onEventContextMenu,
|
|
1377
|
+
onDayEventResize,
|
|
1378
|
+
onSlotClick
|
|
1379
|
+
}) => {
|
|
1380
|
+
const [expanded, setExpanded] = (0, import_react8.useState)(false);
|
|
1381
|
+
const rowKey = days.length ? (0, import_date_fns11.format)(days[0], "yyyy-MM-dd") : "";
|
|
1382
|
+
(0, import_react8.useEffect)(() => setExpanded(false), [rowKey]);
|
|
1383
|
+
const handleSlotClick = (0, import_react8.useCallback)((day) => onSlotClick?.(day), [onSlotClick]);
|
|
1384
|
+
const { segments, laneCount } = layoutDayRow(days, dayEvents, timezone);
|
|
1385
|
+
const visibleLanes = expanded ? laneCount : Math.min(laneCount, maxLanes);
|
|
1386
|
+
const hidden = segments.filter((segment) => segment.lane >= visibleLanes).length;
|
|
1387
|
+
const height = Math.max(visibleLanes, 1) * LANE_HEIGHT2 + 4;
|
|
1388
|
+
return /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex border-b-[0.5px] border-border/50 bg-background", "data-all-day-row": true }, /* @__PURE__ */ import_react8.default.createElement("div", { className: cn("flex-none flex flex-col items-end justify-start gap-0.5 pr-2 pt-1 text-[10px] text-muted-foreground border-r-[0.5px] border-border/30", gutterClassName) }, /* @__PURE__ */ import_react8.default.createElement("span", null, translations?.allDay || "All Day"), laneCount > maxLanes && /* @__PURE__ */ import_react8.default.createElement(
|
|
1389
|
+
"button",
|
|
1390
|
+
{
|
|
1391
|
+
type: "button",
|
|
1392
|
+
className: "text-primary font-semibold hover:underline",
|
|
1393
|
+
onClick: () => setExpanded(!expanded)
|
|
1394
|
+
},
|
|
1395
|
+
expanded ? translations?.showLess || "Show less" : interpolate(translations?.moreEvents || "+{n} more", { n: hidden })
|
|
1396
|
+
)), /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex-1 relative", style: { height } }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "absolute inset-0 grid", style: { gridTemplateColumns: `repeat(${days.length}, minmax(0, 1fr))` } }, days.map((day, index) => /* @__PURE__ */ import_react8.default.createElement(
|
|
1397
|
+
DroppableCell,
|
|
1398
|
+
{
|
|
1399
|
+
key: day.toISOString(),
|
|
1400
|
+
id: `all-day-${day.toISOString()}`,
|
|
1401
|
+
date: day,
|
|
1402
|
+
allDayRow: true,
|
|
1403
|
+
className: cn("h-full", index > 0 && "border-l-[0.5px] border-border/30"),
|
|
1404
|
+
onSlotClick: readonly || !onSlotClick ? void 0 : handleSlotClick
|
|
1405
|
+
}
|
|
1406
|
+
))), /* @__PURE__ */ import_react8.default.createElement("div", { className: "absolute inset-x-0 top-0 pointer-events-none", style: { height } }, segments.filter((segment) => segment.lane < visibleLanes).map((segment) => /* @__PURE__ */ import_react8.default.createElement("div", { key: `${segment.event.id}-${rowKey}`, className: "pointer-events-auto" }, /* @__PURE__ */ import_react8.default.createElement(
|
|
1407
|
+
AllDayBar,
|
|
1408
|
+
{
|
|
1409
|
+
segment,
|
|
1410
|
+
rowDays: days,
|
|
1411
|
+
laneHeight: LANE_HEIGHT2,
|
|
1412
|
+
timezone,
|
|
1413
|
+
locale,
|
|
1414
|
+
translations,
|
|
1415
|
+
readonly,
|
|
1416
|
+
onEventClick,
|
|
1417
|
+
onEventContextMenu,
|
|
1418
|
+
onDayEventResize
|
|
1419
|
+
}
|
|
1420
|
+
))))));
|
|
1421
|
+
};
|
|
1422
|
+
var AllDayRow = import_react8.default.memo(AllDayRowImpl);
|
|
972
1423
|
|
|
973
1424
|
// src/core/layout.ts
|
|
974
1425
|
var layoutCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -1009,9 +1460,10 @@ function layoutDayEvents(segments) {
|
|
|
1009
1460
|
}
|
|
1010
1461
|
|
|
1011
1462
|
// src/components/dnd/ResizableEvent.tsx
|
|
1012
|
-
var
|
|
1463
|
+
var import_react9 = __toESM(require("react"));
|
|
1013
1464
|
|
|
1014
1465
|
// src/core/dnd.ts
|
|
1466
|
+
var import_date_fns12 = require("date-fns");
|
|
1015
1467
|
function computeDrop({ event, overDate, overResourceId, grabOffsetMs = 0, view, tz }) {
|
|
1016
1468
|
let wallStart;
|
|
1017
1469
|
if (view === "month") {
|
|
@@ -1032,6 +1484,23 @@ function computeResizeEnd(event, deltaMinutes, minDuration = 15) {
|
|
|
1032
1484
|
const minEnd = event.start.getTime() + minDuration * 6e4;
|
|
1033
1485
|
return new Date(Math.max(event.end.getTime() + deltaMinutes * 6e4, minEnd));
|
|
1034
1486
|
}
|
|
1487
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
1488
|
+
var shiftDays = (date, days, event, tz) => event.allDay ? (0, import_date_fns12.addDays)(date, days) : fromDisplay((0, import_date_fns12.addDays)(toDisplay(date, tz), days), tz);
|
|
1489
|
+
function computeDayMove(event, overDay, grabDayOffset, tz) {
|
|
1490
|
+
const { firstDay } = dayEventSpan(event, tz);
|
|
1491
|
+
const days = (0, import_date_fns12.differenceInCalendarDays)((0, import_date_fns12.addDays)((0, import_date_fns12.startOfDay)(overDay), -grabDayOffset), firstDay);
|
|
1492
|
+
if (days === 0) return null;
|
|
1493
|
+
return { start: shiftDays(event.start, days, event, tz), end: shiftDays(event.end, days, event, tz) };
|
|
1494
|
+
}
|
|
1495
|
+
function computeDayResize(event, newLastDay, tz) {
|
|
1496
|
+
const { firstDay, lastDay } = dayEventSpan(event, tz);
|
|
1497
|
+
const target = (0, import_date_fns12.startOfDay)(newLastDay) < firstDay ? firstDay : (0, import_date_fns12.startOfDay)(newLastDay);
|
|
1498
|
+
const days = (0, import_date_fns12.differenceInCalendarDays)(target, lastDay);
|
|
1499
|
+
if (days === 0) return null;
|
|
1500
|
+
if (event.allDay) return (0, import_date_fns12.addDays)(target, 1);
|
|
1501
|
+
const end = new Date(Math.max(shiftDays(event.end, days, event, tz).getTime(), event.start.getTime() + DAY_MS));
|
|
1502
|
+
return end.getTime() === event.end.getTime() ? null : end;
|
|
1503
|
+
}
|
|
1035
1504
|
|
|
1036
1505
|
// src/components/dnd/ResizableEvent.tsx
|
|
1037
1506
|
var ResizableEvent = ({
|
|
@@ -1045,13 +1514,13 @@ var ResizableEvent = ({
|
|
|
1045
1514
|
readonly
|
|
1046
1515
|
}) => {
|
|
1047
1516
|
const resizeLocked = readonly || isEventResizeDisabled(event);
|
|
1048
|
-
const [isResizing, setIsResizing] = (0,
|
|
1049
|
-
const [resizeHeight, setResizeHeight] = (0,
|
|
1050
|
-
const containerRef = (0,
|
|
1051
|
-
const startYRef = (0,
|
|
1052
|
-
const startHeightRef = (0,
|
|
1053
|
-
const resizeHeightRef = (0,
|
|
1054
|
-
const handleResizeStart = (0,
|
|
1517
|
+
const [isResizing, setIsResizing] = (0, import_react9.useState)(false);
|
|
1518
|
+
const [resizeHeight, setResizeHeight] = (0, import_react9.useState)(null);
|
|
1519
|
+
const containerRef = (0, import_react9.useRef)(null);
|
|
1520
|
+
const startYRef = (0, import_react9.useRef)(0);
|
|
1521
|
+
const startHeightRef = (0, import_react9.useRef)(0);
|
|
1522
|
+
const resizeHeightRef = (0, import_react9.useRef)(null);
|
|
1523
|
+
const handleResizeStart = (0, import_react9.useCallback)((e) => {
|
|
1055
1524
|
e.preventDefault();
|
|
1056
1525
|
e.stopPropagation();
|
|
1057
1526
|
const clientY = "touches" in e ? e.touches[0].clientY : e.clientY;
|
|
@@ -1090,10 +1559,10 @@ var ResizableEvent = ({
|
|
|
1090
1559
|
document.addEventListener("touchmove", handleMove, { passive: false });
|
|
1091
1560
|
document.addEventListener("touchend", handleEnd);
|
|
1092
1561
|
}, [event, hourHeight, minDuration, onResize]);
|
|
1093
|
-
const handlePointerDown = (0,
|
|
1562
|
+
const handlePointerDown = (0, import_react9.useCallback)((e) => {
|
|
1094
1563
|
e.stopPropagation();
|
|
1095
1564
|
}, []);
|
|
1096
|
-
return /* @__PURE__ */
|
|
1565
|
+
return /* @__PURE__ */ import_react9.default.createElement(
|
|
1097
1566
|
"div",
|
|
1098
1567
|
{
|
|
1099
1568
|
ref: containerRef,
|
|
@@ -1104,7 +1573,7 @@ var ResizableEvent = ({
|
|
|
1104
1573
|
}
|
|
1105
1574
|
},
|
|
1106
1575
|
children,
|
|
1107
|
-
/* @__PURE__ */
|
|
1576
|
+
/* @__PURE__ */ import_react9.default.createElement(
|
|
1108
1577
|
"div",
|
|
1109
1578
|
{
|
|
1110
1579
|
className: cn(
|
|
@@ -1117,12 +1586,12 @@ var ResizableEvent = ({
|
|
|
1117
1586
|
onMouseDown: resizeLocked ? void 0 : handleResizeStart,
|
|
1118
1587
|
onTouchStart: resizeLocked ? void 0 : handleResizeStart
|
|
1119
1588
|
},
|
|
1120
|
-
/* @__PURE__ */
|
|
1589
|
+
/* @__PURE__ */ import_react9.default.createElement("div", { className: cn(
|
|
1121
1590
|
"w-8 h-1 rounded-full transition-all",
|
|
1122
1591
|
isResizing ? "bg-primary" : "bg-muted-foreground/30 group-hover:bg-primary/50"
|
|
1123
1592
|
) })
|
|
1124
1593
|
),
|
|
1125
|
-
isResizing && /* @__PURE__ */
|
|
1594
|
+
isResizing && /* @__PURE__ */ import_react9.default.createElement("div", { className: "absolute inset-0 border-2 border-primary border-dashed rounded-md pointer-events-none bg-primary/5" })
|
|
1126
1595
|
);
|
|
1127
1596
|
};
|
|
1128
1597
|
|
|
@@ -1144,72 +1613,92 @@ var WeekViewImpl = ({
|
|
|
1144
1613
|
onEventResize,
|
|
1145
1614
|
timezone,
|
|
1146
1615
|
locale,
|
|
1147
|
-
readonly
|
|
1616
|
+
readonly,
|
|
1617
|
+
onEventContextMenu,
|
|
1618
|
+
onDayEventResize,
|
|
1619
|
+
onAllDaySlotClick,
|
|
1620
|
+
translations
|
|
1148
1621
|
}) => {
|
|
1149
|
-
const weekDays =
|
|
1622
|
+
const weekDays = import_react10.default.useMemo(
|
|
1150
1623
|
() => getWeekDays(currentDate, resolveWeekStartsOn(locale, 1)),
|
|
1151
1624
|
[currentDate, locale]
|
|
1152
1625
|
);
|
|
1153
|
-
const visibleRange =
|
|
1154
|
-
() => ({ start: weekDays[0], end: (0,
|
|
1626
|
+
const visibleRange = import_react10.default.useMemo(
|
|
1627
|
+
() => ({ start: weekDays[0], end: (0, import_date_fns13.addDays)(weekDays[weekDays.length - 1], 1) }),
|
|
1155
1628
|
[weekDays]
|
|
1156
1629
|
);
|
|
1157
|
-
const scrollContainerRef =
|
|
1158
|
-
const [now, setNow] =
|
|
1159
|
-
|
|
1630
|
+
const scrollContainerRef = import_react10.default.useRef(null);
|
|
1631
|
+
const [now, setNow] = import_react10.default.useState(() => /* @__PURE__ */ new Date());
|
|
1632
|
+
import_react10.default.useEffect(() => {
|
|
1160
1633
|
const interval = setInterval(() => setNow(/* @__PURE__ */ new Date()), 6e4);
|
|
1161
1634
|
return () => clearInterval(interval);
|
|
1162
1635
|
}, []);
|
|
1163
|
-
|
|
1636
|
+
import_react10.default.useEffect(() => {
|
|
1164
1637
|
if (scrollContainerRef.current) {
|
|
1165
1638
|
const offsetHour = 4;
|
|
1166
1639
|
scrollContainerRef.current.scrollTop = (toDisplay(/* @__PURE__ */ new Date(), timezone).getHours() - offsetHour) * HOUR_HEIGHT;
|
|
1167
1640
|
}
|
|
1168
1641
|
}, [timezone]);
|
|
1169
|
-
const
|
|
1642
|
+
const { dayEvents, timedEvents } = partitionDayEvents(events, timezone);
|
|
1643
|
+
const segmentsByDay = segmentsByDisplayDay(timedEvents, timezone, visibleRange);
|
|
1170
1644
|
const today = displayToday(timezone, now);
|
|
1171
1645
|
const zonedNow = toDisplay(now, timezone);
|
|
1172
1646
|
const nowTop = minutesSinceDisplayMidnight(now, timezone) / 60 * HOUR_HEIGHT;
|
|
1173
|
-
const showsToday = weekDays.some((day) => (0,
|
|
1647
|
+
const showsToday = weekDays.some((day) => (0, import_date_fns13.isSameDay)(day, today));
|
|
1174
1648
|
const zone = resolveTimeZone(timezone);
|
|
1175
1649
|
const zoneLabel = timeZoneAbbreviation(now, zone) || zone || "LOC";
|
|
1176
1650
|
const formats = timeFormats(locale);
|
|
1177
|
-
return /* @__PURE__ */
|
|
1651
|
+
return /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex flex-col h-full bg-background border-[0.5px] border-border/50 rounded-2xl overflow-hidden min-w-[800px] md:min-w-0 shadow-sm" }, /* @__PURE__ */ import_react10.default.createElement(
|
|
1178
1652
|
"div",
|
|
1179
1653
|
{
|
|
1180
1654
|
ref: scrollContainerRef,
|
|
1181
1655
|
className: "flex-1 overflow-y-auto scrollbar-hide relative bg-background scroll-smooth"
|
|
1182
1656
|
},
|
|
1183
|
-
/* @__PURE__ */
|
|
1657
|
+
/* @__PURE__ */ import_react10.default.createElement("div", { className: "sticky top-0 z-20" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex border-b-[0.5px] border-border/50 bg-gradient-to-r from-muted/20 via-background to-muted/20 backdrop-blur-sm" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex-none p-3 text-center text-xs font-semibold text-muted-foreground w-16 flex items-center justify-center border-r-[0.5px] border-border/30 bg-muted/10" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex flex-col items-center justify-center leading-tight" }, /* @__PURE__ */ import_react10.default.createElement("span", null, (0, import_date_fns13.format)(zonedNow, "HH:mm")), /* @__PURE__ */ import_react10.default.createElement("span", { className: "text-[10px] opacity-75" }, "(", zoneLabel, ")"))), /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex-1 grid grid-cols-7" }, weekDays.map((day, index) => /* @__PURE__ */ import_react10.default.createElement("div", { key: day.toISOString(), className: cn("py-3 px-2 text-center", index > 0 && "border-l-[0.5px] border-border/30") }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "text-[10px] font-semibold text-muted-foreground uppercase tracking-wider mb-1.5" }, (0, import_date_fns13.format)(day, "EEE", { locale })), /* @__PURE__ */ import_react10.default.createElement("div", { className: cn(
|
|
1184
1658
|
"w-9 h-9 flex items-center justify-center rounded-xl mx-auto text-sm font-semibold transition-all duration-200",
|
|
1185
|
-
(0,
|
|
1186
|
-
) }, (0,
|
|
1187
|
-
|
|
1659
|
+
(0, import_date_fns13.isSameDay)(day, today) ? "bg-primary text-primary-foreground shadow-lg shadow-primary/30 scale-110" : "text-foreground hover:bg-accent/80"
|
|
1660
|
+
) }, (0, import_date_fns13.format)(day, "d", { locale })))))), /* @__PURE__ */ import_react10.default.createElement(
|
|
1661
|
+
AllDayRow,
|
|
1662
|
+
{
|
|
1663
|
+
days: weekDays,
|
|
1664
|
+
dayEvents,
|
|
1665
|
+
timezone,
|
|
1666
|
+
locale,
|
|
1667
|
+
translations,
|
|
1668
|
+
readonly,
|
|
1669
|
+
gutterClassName: "w-16",
|
|
1670
|
+
onEventClick,
|
|
1671
|
+
onEventContextMenu,
|
|
1672
|
+
onDayEventResize,
|
|
1673
|
+
onSlotClick: onAllDaySlotClick
|
|
1674
|
+
}
|
|
1675
|
+
)),
|
|
1676
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
1188
1677
|
"div",
|
|
1189
1678
|
{
|
|
1190
1679
|
className: "flex min-w-full relative",
|
|
1191
1680
|
style: { height: HOURS.length * HOUR_HEIGHT }
|
|
1192
1681
|
},
|
|
1193
|
-
/* @__PURE__ */
|
|
1682
|
+
/* @__PURE__ */ import_react10.default.createElement("div", { className: "flex-none w-16 border-r-[0.5px] border-border/30 relative bg-muted/5" }, HOURS.map((hour) => /* @__PURE__ */ import_react10.default.createElement(
|
|
1194
1683
|
"div",
|
|
1195
1684
|
{
|
|
1196
1685
|
key: hour,
|
|
1197
1686
|
className: "relative w-full text-[11px] text-muted-foreground/80 text-right pr-3 font-medium tabular-nums box-border",
|
|
1198
1687
|
style: { height: HOUR_HEIGHT }
|
|
1199
1688
|
},
|
|
1200
|
-
/* @__PURE__ */
|
|
1201
|
-
)), showsToday && /* @__PURE__ */
|
|
1689
|
+
/* @__PURE__ */ import_react10.default.createElement("span", { className: "block -translate-y-1/2" }, hour !== 0 && (0, import_date_fns13.format)(slotDate(currentDate, hour, 0), formats.hour, { locale }))
|
|
1690
|
+
)), showsToday && /* @__PURE__ */ import_react10.default.createElement(
|
|
1202
1691
|
"div",
|
|
1203
1692
|
{
|
|
1204
1693
|
className: "absolute left-0 w-full pointer-events-none z-30 flex justify-end pr-2",
|
|
1205
1694
|
style: { top: `${nowTop}px` }
|
|
1206
1695
|
},
|
|
1207
|
-
/* @__PURE__ */
|
|
1696
|
+
/* @__PURE__ */ import_react10.default.createElement("span", { className: "text-[10px] font-bold text-primary-foreground bg-primary px-1.5 py-0.5 rounded-md shadow-md -translate-y-1/2 backdrop-blur-none" }, (0, import_date_fns13.format)(zonedNow, formats.compact, { locale }))
|
|
1208
1697
|
)),
|
|
1209
|
-
/* @__PURE__ */
|
|
1210
|
-
const dayKey2 = (0,
|
|
1698
|
+
/* @__PURE__ */ import_react10.default.createElement("div", { className: "flex-1 grid grid-cols-7 relative" }, weekDays.map((day, dayIndex) => {
|
|
1699
|
+
const dayKey2 = (0, import_date_fns13.format)(day, "yyyy-MM-dd");
|
|
1211
1700
|
const positioned = layoutDayEvents(segmentsByDay.get(dayKey2) ?? NO_SEGMENTS);
|
|
1212
|
-
return /* @__PURE__ */
|
|
1701
|
+
return /* @__PURE__ */ import_react10.default.createElement("div", { key: dayKey2, className: cn("relative h-full", dayIndex > 0 && "border-l-[0.5px] border-border/30") }, HOURS.map((hour) => /* @__PURE__ */ import_react10.default.createElement(
|
|
1213
1702
|
"div",
|
|
1214
1703
|
{
|
|
1215
1704
|
key: hour,
|
|
@@ -1218,7 +1707,7 @@ var WeekViewImpl = ({
|
|
|
1218
1707
|
},
|
|
1219
1708
|
QUARTERS.map((minute) => {
|
|
1220
1709
|
const cellDate = slotDate(day, hour, minute);
|
|
1221
|
-
return /* @__PURE__ */
|
|
1710
|
+
return /* @__PURE__ */ import_react10.default.createElement(
|
|
1222
1711
|
DroppableCell,
|
|
1223
1712
|
{
|
|
1224
1713
|
key: minute,
|
|
@@ -1239,12 +1728,12 @@ var WeekViewImpl = ({
|
|
|
1239
1728
|
const zonedEventStart = toDisplay(event.start, timezone);
|
|
1240
1729
|
const zonedEventEnd = toDisplay(event.end, timezone);
|
|
1241
1730
|
const startMinutes = start.getHours() * 60 + start.getMinutes();
|
|
1242
|
-
const durationMinutes = (0,
|
|
1731
|
+
const durationMinutes = (0, import_date_fns13.differenceInMinutes)(end, start);
|
|
1243
1732
|
const top = startMinutes / 60 * HOUR_HEIGHT;
|
|
1244
1733
|
const height = durationMinutes / 60 * HOUR_HEIGHT;
|
|
1245
1734
|
const isShortEvent = durationMinutes < 60;
|
|
1246
1735
|
const isLastSegment = end.getTime() === zonedEventEnd.getTime();
|
|
1247
|
-
return /* @__PURE__ */
|
|
1736
|
+
return /* @__PURE__ */ import_react10.default.createElement(
|
|
1248
1737
|
DraggableEvent,
|
|
1249
1738
|
{
|
|
1250
1739
|
key: `${event.id}-${dayKey2}`,
|
|
@@ -1261,7 +1750,7 @@ var WeekViewImpl = ({
|
|
|
1261
1750
|
paddingRight: columns > 1 ? "2px" : "0"
|
|
1262
1751
|
}
|
|
1263
1752
|
},
|
|
1264
|
-
/* @__PURE__ */
|
|
1753
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
1265
1754
|
ResizableEvent,
|
|
1266
1755
|
{
|
|
1267
1756
|
readonly: readonly || !isLastSegment,
|
|
@@ -1271,7 +1760,7 @@ var WeekViewImpl = ({
|
|
|
1271
1760
|
className: "h-full",
|
|
1272
1761
|
style: { height: "100%" }
|
|
1273
1762
|
},
|
|
1274
|
-
/* @__PURE__ */
|
|
1763
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
1275
1764
|
"div",
|
|
1276
1765
|
{
|
|
1277
1766
|
className: cn(
|
|
@@ -1294,33 +1783,34 @@ var WeekViewImpl = ({
|
|
|
1294
1783
|
e.stopPropagation();
|
|
1295
1784
|
onEventClick?.(event);
|
|
1296
1785
|
},
|
|
1786
|
+
onContextMenu: onEventContextMenu ? (e) => onEventContextMenu(event, e) : void 0,
|
|
1297
1787
|
title: columns > 1 ? `${event.title} (${column + 1}/${columns})` : void 0
|
|
1298
1788
|
},
|
|
1299
|
-
/* @__PURE__ */
|
|
1789
|
+
/* @__PURE__ */ import_react10.default.createElement("div", { className: "flex flex-col h-full overflow-hidden w-full" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: cn(
|
|
1300
1790
|
"font-semibold truncate text-foreground/90 leading-tight",
|
|
1301
1791
|
isShortEvent ? "text-xs text-center" : "text-xs"
|
|
1302
|
-
) }, event.title), !isShortEvent && /* @__PURE__ */
|
|
1792
|
+
) }, event.title), !isShortEvent && /* @__PURE__ */ import_react10.default.createElement(import_react10.default.Fragment, null, /* @__PURE__ */ import_react10.default.createElement("div", { className: "text-[10px] text-muted-foreground truncate mt-0.5 font-medium leading-tight" }, (0, import_date_fns13.format)(zonedEventStart, formats.time, { locale }), " - ", (0, import_date_fns13.format)(zonedEventEnd, formats.time, { locale })), event.description && height > 50 && /* @__PURE__ */ import_react10.default.createElement("div", { className: "text-[10px] text-muted-foreground/80 truncate mt-1 leading-tight opacity-80" }, event.description)), columns > 1 && !isShortEvent && /* @__PURE__ */ import_react10.default.createElement("div", { className: "absolute top-1 right-1 bg-background/80 backdrop-blur-sm rounded-full w-4 h-4 flex items-center justify-center text-[9px] font-bold text-muted-foreground border border-border shadow-sm" }, columns))
|
|
1303
1793
|
)
|
|
1304
1794
|
)
|
|
1305
1795
|
);
|
|
1306
|
-
}), (0,
|
|
1796
|
+
}), (0, import_date_fns13.isSameDay)(day, today) && /* @__PURE__ */ import_react10.default.createElement(
|
|
1307
1797
|
"div",
|
|
1308
1798
|
{
|
|
1309
1799
|
className: "absolute left-0 right-0 z-20 pointer-events-none flex items-center",
|
|
1310
1800
|
style: { top: `${nowTop}px` }
|
|
1311
1801
|
},
|
|
1312
|
-
/* @__PURE__ */
|
|
1313
|
-
/* @__PURE__ */
|
|
1802
|
+
/* @__PURE__ */ import_react10.default.createElement("div", { className: "h-[2px] w-full bg-gradient-to-r from-primary via-primary to-primary/50" }),
|
|
1803
|
+
/* @__PURE__ */ import_react10.default.createElement("div", { className: "absolute -left-1.5 w-3 h-3 bg-primary rounded-full shadow-lg shadow-primary/40 ring-2 ring-background animate-pulse" })
|
|
1314
1804
|
));
|
|
1315
1805
|
}))
|
|
1316
1806
|
)
|
|
1317
1807
|
));
|
|
1318
1808
|
};
|
|
1319
|
-
var WeekView =
|
|
1809
|
+
var WeekView = import_react10.default.memo(WeekViewImpl);
|
|
1320
1810
|
|
|
1321
1811
|
// src/views/DayView.tsx
|
|
1322
|
-
var
|
|
1323
|
-
var
|
|
1812
|
+
var import_react11 = __toESM(require("react"));
|
|
1813
|
+
var import_date_fns14 = require("date-fns");
|
|
1324
1814
|
var HOUR_HEIGHT2 = 80;
|
|
1325
1815
|
var HOURS2 = Array.from({ length: 24 }, (_, i) => i);
|
|
1326
1816
|
var QUARTERS2 = [0, 15, 30, 45];
|
|
@@ -1338,46 +1828,67 @@ var DayViewImpl = ({
|
|
|
1338
1828
|
onEventResize,
|
|
1339
1829
|
timezone,
|
|
1340
1830
|
locale,
|
|
1341
|
-
readonly
|
|
1831
|
+
readonly,
|
|
1832
|
+
onEventContextMenu,
|
|
1833
|
+
translations,
|
|
1834
|
+
onDayEventResize,
|
|
1835
|
+
onAllDaySlotClick
|
|
1342
1836
|
}) => {
|
|
1343
|
-
const visibleRange =
|
|
1344
|
-
const start = (0,
|
|
1345
|
-
return { start, end: (0,
|
|
1837
|
+
const visibleRange = import_react11.default.useMemo(() => {
|
|
1838
|
+
const start = (0, import_date_fns14.startOfDay)(currentDate);
|
|
1839
|
+
return { start, end: (0, import_date_fns14.addDays)(start, 1) };
|
|
1346
1840
|
}, [currentDate]);
|
|
1347
|
-
const scrollContainerRef =
|
|
1348
|
-
const [now, setNow] =
|
|
1349
|
-
|
|
1841
|
+
const scrollContainerRef = import_react11.default.useRef(null);
|
|
1842
|
+
const [now, setNow] = import_react11.default.useState(() => /* @__PURE__ */ new Date());
|
|
1843
|
+
import_react11.default.useEffect(() => {
|
|
1350
1844
|
const interval = setInterval(() => setNow(/* @__PURE__ */ new Date()), 6e4);
|
|
1351
1845
|
return () => clearInterval(interval);
|
|
1352
1846
|
}, []);
|
|
1353
|
-
|
|
1847
|
+
import_react11.default.useEffect(() => {
|
|
1354
1848
|
if (scrollContainerRef.current) {
|
|
1355
1849
|
const offsetHour = 3;
|
|
1356
1850
|
scrollContainerRef.current.scrollTop = (toDisplay(/* @__PURE__ */ new Date(), timezone).getHours() - offsetHour) * HOUR_HEIGHT2;
|
|
1357
1851
|
}
|
|
1358
1852
|
}, [timezone]);
|
|
1359
|
-
const dayKey2 = (0,
|
|
1360
|
-
const
|
|
1361
|
-
const
|
|
1853
|
+
const dayKey2 = (0, import_date_fns14.format)(currentDate, "yyyy-MM-dd");
|
|
1854
|
+
const { dayEvents, timedEvents } = partitionDayEvents(events, timezone);
|
|
1855
|
+
const rowDays = import_react11.default.useMemo(() => [visibleRange.start], [visibleRange]);
|
|
1856
|
+
const positioned = layoutDayEvents(segmentsByDisplayDay(timedEvents, timezone, visibleRange).get(dayKey2) ?? NO_SEGMENTS2);
|
|
1857
|
+
const isToday2 = (0, import_date_fns14.isSameDay)(currentDate, displayToday(timezone, now));
|
|
1362
1858
|
const zonedNow = toDisplay(now, timezone);
|
|
1363
1859
|
const nowTop = minutesSinceDisplayMidnight(now, timezone) / 60 * HOUR_HEIGHT2;
|
|
1364
1860
|
const formats = timeFormats(locale);
|
|
1365
|
-
return /* @__PURE__ */
|
|
1861
|
+
return /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex flex-col h-full bg-background border-[0.5px] border-border/50 rounded-2xl overflow-hidden shadow-sm" }, /* @__PURE__ */ import_react11.default.createElement("div", { className: "px-6 py-4 border-b-[0.5px] border-border/50 bg-gradient-to-r from-muted/20 via-background to-muted/20 text-center shrink-0" }, /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex items-center justify-center gap-3" }, /* @__PURE__ */ import_react11.default.createElement("h2", { className: "text-xl font-semibold capitalize text-foreground" }, (0, import_date_fns14.format)(currentDate, "EEEE, MMMM d, yyyy", { locale })), isToday2 && /* @__PURE__ */ import_react11.default.createElement("span", { className: "text-xs font-semibold bg-primary text-primary-foreground px-3 py-1 rounded-full shadow-md shadow-primary/20" }, translations?.today || "Today"))), /* @__PURE__ */ import_react11.default.createElement(
|
|
1862
|
+
AllDayRow,
|
|
1863
|
+
{
|
|
1864
|
+
days: rowDays,
|
|
1865
|
+
dayEvents,
|
|
1866
|
+
timezone,
|
|
1867
|
+
locale,
|
|
1868
|
+
translations,
|
|
1869
|
+
readonly,
|
|
1870
|
+
gutterClassName: "w-20",
|
|
1871
|
+
onEventClick,
|
|
1872
|
+
onEventContextMenu,
|
|
1873
|
+
onDayEventResize,
|
|
1874
|
+
onSlotClick: onAllDaySlotClick
|
|
1875
|
+
}
|
|
1876
|
+
), /* @__PURE__ */ import_react11.default.createElement("div", { ref: scrollContainerRef, className: "flex-1 overflow-y-auto relative" }, /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex relative", style: { height: HOURS2.length * HOUR_HEIGHT2 } }, /* @__PURE__ */ import_react11.default.createElement("div", { className: "w-20 bg-muted/5 border-r-[0.5px] border-border/30 relative" }, HOURS2.map((hour) => /* @__PURE__ */ import_react11.default.createElement(
|
|
1366
1877
|
"div",
|
|
1367
1878
|
{
|
|
1368
1879
|
key: hour,
|
|
1369
1880
|
className: "relative w-full",
|
|
1370
1881
|
style: { height: HOUR_HEIGHT2 }
|
|
1371
1882
|
},
|
|
1372
|
-
hour !== 0 && /* @__PURE__ */
|
|
1373
|
-
)), isToday2 && /* @__PURE__ */
|
|
1883
|
+
hour !== 0 && /* @__PURE__ */ import_react11.default.createElement("span", { className: "absolute w-full text-center -top-3 left-1/2 -translate-x-1/2 text-[11px] text-muted-foreground/80 font-medium tabular-nums bg-background px-1.5 py-0.5 rounded-md" }, (0, import_date_fns14.format)(slotDate2(currentDate, hour, 0), formats.hour, { locale }))
|
|
1884
|
+
)), isToday2 && /* @__PURE__ */ import_react11.default.createElement(
|
|
1374
1885
|
"div",
|
|
1375
1886
|
{
|
|
1376
1887
|
className: "absolute left-0 w-full pointer-events-none z-30 flex justify-end pr-2",
|
|
1377
1888
|
style: { top: `${nowTop}px` }
|
|
1378
1889
|
},
|
|
1379
|
-
/* @__PURE__ */
|
|
1380
|
-
)), /* @__PURE__ */
|
|
1890
|
+
/* @__PURE__ */ import_react11.default.createElement("span", { className: "text-[10px] font-bold text-white bg-primary px-2 py-1 rounded-lg shadow-md shadow-primary/30 -translate-y-1/2" }, (0, import_date_fns14.format)(zonedNow, formats.time, { locale }))
|
|
1891
|
+
)), /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex-1 relative" }, HOURS2.map((hour) => /* @__PURE__ */ import_react11.default.createElement(
|
|
1381
1892
|
"div",
|
|
1382
1893
|
{
|
|
1383
1894
|
key: hour,
|
|
@@ -1386,7 +1897,7 @@ var DayViewImpl = ({
|
|
|
1386
1897
|
},
|
|
1387
1898
|
QUARTERS2.map((minute) => {
|
|
1388
1899
|
const cellDate = slotDate2(currentDate, hour, minute);
|
|
1389
|
-
return /* @__PURE__ */
|
|
1900
|
+
return /* @__PURE__ */ import_react11.default.createElement(
|
|
1390
1901
|
DroppableCell,
|
|
1391
1902
|
{
|
|
1392
1903
|
key: minute,
|
|
@@ -1407,12 +1918,12 @@ var DayViewImpl = ({
|
|
|
1407
1918
|
const zonedStart = toDisplay(event.start, timezone);
|
|
1408
1919
|
const zonedEnd = toDisplay(event.end, timezone);
|
|
1409
1920
|
const startMinutes = start.getHours() * 60 + start.getMinutes();
|
|
1410
|
-
const durationMinutes = (0,
|
|
1921
|
+
const durationMinutes = (0, import_date_fns14.differenceInMinutes)(end, start);
|
|
1411
1922
|
const top = startMinutes / 60 * HOUR_HEIGHT2;
|
|
1412
1923
|
const height = durationMinutes / 60 * HOUR_HEIGHT2;
|
|
1413
1924
|
const isShortEvent = durationMinutes < 45;
|
|
1414
1925
|
const isLastSegment = end.getTime() === zonedEnd.getTime();
|
|
1415
|
-
return /* @__PURE__ */
|
|
1926
|
+
return /* @__PURE__ */ import_react11.default.createElement(
|
|
1416
1927
|
DraggableEvent,
|
|
1417
1928
|
{
|
|
1418
1929
|
key: `${event.id}-${dayKey2}`,
|
|
@@ -1428,7 +1939,7 @@ var DayViewImpl = ({
|
|
|
1428
1939
|
paddingRight: columns > 1 ? "2px" : "0"
|
|
1429
1940
|
}
|
|
1430
1941
|
},
|
|
1431
|
-
/* @__PURE__ */
|
|
1942
|
+
/* @__PURE__ */ import_react11.default.createElement(
|
|
1432
1943
|
ResizableEvent,
|
|
1433
1944
|
{
|
|
1434
1945
|
readonly: readonly || !isLastSegment,
|
|
@@ -1438,7 +1949,7 @@ var DayViewImpl = ({
|
|
|
1438
1949
|
className: "h-full",
|
|
1439
1950
|
style: { height: "100%" }
|
|
1440
1951
|
},
|
|
1441
|
-
/* @__PURE__ */
|
|
1952
|
+
/* @__PURE__ */ import_react11.default.createElement(
|
|
1442
1953
|
"div",
|
|
1443
1954
|
{
|
|
1444
1955
|
className: cn(
|
|
@@ -1459,42 +1970,43 @@ var DayViewImpl = ({
|
|
|
1459
1970
|
e.stopPropagation();
|
|
1460
1971
|
onEventClick?.(event);
|
|
1461
1972
|
},
|
|
1973
|
+
onContextMenu: onEventContextMenu ? (e) => onEventContextMenu(event, e) : void 0,
|
|
1462
1974
|
title: columns > 1 ? `${event.title} (${column + 1}/${columns})` : void 0
|
|
1463
1975
|
},
|
|
1464
|
-
/* @__PURE__ */
|
|
1976
|
+
/* @__PURE__ */ import_react11.default.createElement("div", { className: "flex flex-col h-full overflow-hidden w-full" }, /* @__PURE__ */ import_react11.default.createElement("div", { className: cn(
|
|
1465
1977
|
"font-semibold truncate leading-tight",
|
|
1466
1978
|
isShortEvent ? "text-xs" : "text-sm",
|
|
1467
1979
|
event.color ? "text-foreground" : "text-foreground/90"
|
|
1468
|
-
) }, event.title), !isShortEvent && /* @__PURE__ */
|
|
1980
|
+
) }, event.title), !isShortEvent && /* @__PURE__ */ import_react11.default.createElement(import_react11.default.Fragment, null, /* @__PURE__ */ import_react11.default.createElement("div", { className: "text-xs text-muted-foreground mt-0.5 font-medium" }, (0, import_date_fns14.format)(zonedStart, formats.time, { locale }), " - ", (0, import_date_fns14.format)(zonedEnd, formats.time, { locale })), event.description && height > 60 && /* @__PURE__ */ import_react11.default.createElement("div", { className: "text-xs text-muted-foreground/80 mt-1 line-clamp-2" }, event.description)), columns > 1 && !isShortEvent && /* @__PURE__ */ import_react11.default.createElement("div", { className: "absolute top-1.5 right-1.5 bg-background/90 backdrop-blur-sm rounded-full w-5 h-5 flex items-center justify-center text-[10px] font-bold text-muted-foreground border border-border shadow-sm" }, columns))
|
|
1469
1981
|
)
|
|
1470
1982
|
)
|
|
1471
1983
|
);
|
|
1472
|
-
}), isToday2 && /* @__PURE__ */
|
|
1984
|
+
}), isToday2 && /* @__PURE__ */ import_react11.default.createElement(
|
|
1473
1985
|
"div",
|
|
1474
1986
|
{
|
|
1475
1987
|
className: "absolute left-0 right-0 z-20 pointer-events-none flex items-center",
|
|
1476
1988
|
style: { top: `${nowTop}px` }
|
|
1477
1989
|
},
|
|
1478
|
-
/* @__PURE__ */
|
|
1479
|
-
/* @__PURE__ */
|
|
1990
|
+
/* @__PURE__ */ import_react11.default.createElement("div", { className: "h-[2px] w-full bg-gradient-to-r from-primary via-primary to-primary/50" }),
|
|
1991
|
+
/* @__PURE__ */ import_react11.default.createElement("div", { className: "absolute -left-1.5 w-3 h-3 bg-primary rounded-full shadow-lg shadow-primary/40 ring-2 ring-background animate-pulse" })
|
|
1480
1992
|
)))));
|
|
1481
1993
|
};
|
|
1482
|
-
var DayView =
|
|
1994
|
+
var DayView = import_react11.default.memo(DayViewImpl);
|
|
1483
1995
|
|
|
1484
1996
|
// src/views/AgendaView.tsx
|
|
1485
|
-
var
|
|
1486
|
-
var
|
|
1997
|
+
var import_react13 = __toESM(require("react"));
|
|
1998
|
+
var import_date_fns15 = require("date-fns");
|
|
1487
1999
|
|
|
1488
2000
|
// src/components/EmptyState.tsx
|
|
1489
|
-
var
|
|
2001
|
+
var import_react12 = __toESM(require("react"));
|
|
1490
2002
|
var import_lucide_react4 = require("lucide-react");
|
|
1491
|
-
var AgendaEmptyState = ({ onCreateEvent, translations }) => /* @__PURE__ */
|
|
2003
|
+
var AgendaEmptyState = ({ onCreateEvent, translations }) => /* @__PURE__ */ import_react12.default.createElement("div", { className: "flex flex-col items-center justify-center h-full min-h-[400px] py-12" }, /* @__PURE__ */ import_react12.default.createElement("div", { className: "relative mb-8" }, /* @__PURE__ */ import_react12.default.createElement("div", { className: "p-8 bg-gradient-to-br from-green-50 to-blue-50 dark:from-green-900/10 dark:to-blue-900/10 rounded-3xl border border-border/30" }, /* @__PURE__ */ import_react12.default.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ import_react12.default.createElement("div", { className: "w-12 h-12 rounded-2xl bg-green-100 dark:bg-green-900/30 flex items-center justify-center" }, /* @__PURE__ */ import_react12.default.createElement("svg", { className: "w-6 h-6 text-green-600 dark:text-green-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2 }, /* @__PURE__ */ import_react12.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }))), /* @__PURE__ */ import_react12.default.createElement("div", { className: "text-left" }, /* @__PURE__ */ import_react12.default.createElement("div", { className: "font-medium text-foreground" }, translations?.allCaughtUp || "All caught up!"), /* @__PURE__ */ import_react12.default.createElement("div", { className: "text-sm text-muted-foreground" }, translations?.noEventsScheduled || "No events scheduled"))))), /* @__PURE__ */ import_react12.default.createElement("div", { className: "text-center max-w-sm" }, /* @__PURE__ */ import_react12.default.createElement("h3", { className: "text-lg font-semibold text-foreground mb-2" }, translations?.noUpcoming || "Your schedule is clear"), /* @__PURE__ */ import_react12.default.createElement("p", { className: "text-sm text-muted-foreground mb-6" }, translations?.noUpcomingHint || "No upcoming events to show. Create a new event to start planning."), onCreateEvent && /* @__PURE__ */ import_react12.default.createElement(
|
|
1492
2004
|
"button",
|
|
1493
2005
|
{
|
|
1494
2006
|
onClick: onCreateEvent,
|
|
1495
2007
|
className: "inline-flex items-center gap-2 px-5 py-2.5 bg-primary text-primary-foreground rounded-xl font-medium text-sm shadow-lg shadow-primary/20 hover:shadow-xl hover:shadow-primary/30 hover:scale-105 active:scale-95 transition-all duration-200"
|
|
1496
2008
|
},
|
|
1497
|
-
/* @__PURE__ */
|
|
2009
|
+
/* @__PURE__ */ import_react12.default.createElement(import_lucide_react4.Plus, { className: "w-4 h-4" }),
|
|
1498
2010
|
translations?.createEvent || "Create Event"
|
|
1499
2011
|
)));
|
|
1500
2012
|
|
|
@@ -1502,7 +2014,7 @@ var AgendaEmptyState = ({ onCreateEvent, translations }) => /* @__PURE__ */ impo
|
|
|
1502
2014
|
var import_framer_motion = require("framer-motion");
|
|
1503
2015
|
var import_lucide_react5 = require("lucide-react");
|
|
1504
2016
|
var formatDuration = (start, end) => {
|
|
1505
|
-
const minutes = (0,
|
|
2017
|
+
const minutes = (0, import_date_fns15.differenceInMinutes)(end, start);
|
|
1506
2018
|
if (minutes < 60) return `${minutes}m`;
|
|
1507
2019
|
const hours = Math.floor(minutes / 60);
|
|
1508
2020
|
const remainingMinutes = minutes % 60;
|
|
@@ -1510,9 +2022,9 @@ var formatDuration = (start, end) => {
|
|
|
1510
2022
|
return `${hours}h ${remainingMinutes}m`;
|
|
1511
2023
|
};
|
|
1512
2024
|
var getDateLabel = (date, today, locale, translations) => {
|
|
1513
|
-
if ((0,
|
|
1514
|
-
if ((0,
|
|
1515
|
-
return (0,
|
|
2025
|
+
if ((0, import_date_fns15.isSameDay)(date, today)) return translations?.today || "Today";
|
|
2026
|
+
if ((0, import_date_fns15.isSameDay)(date, (0, import_date_fns15.addDays)(today, 1))) return translations?.tomorrow || "Tomorrow";
|
|
2027
|
+
return (0, import_date_fns15.format)(date, "EEEE", { locale });
|
|
1516
2028
|
};
|
|
1517
2029
|
var AgendaView = ({
|
|
1518
2030
|
currentDate,
|
|
@@ -1521,17 +2033,18 @@ var AgendaView = ({
|
|
|
1521
2033
|
onCreateEvent,
|
|
1522
2034
|
locale,
|
|
1523
2035
|
translations,
|
|
1524
|
-
timezone
|
|
2036
|
+
timezone,
|
|
2037
|
+
onEventContextMenu
|
|
1525
2038
|
}) => {
|
|
1526
2039
|
const is24h = uses24HourClock(locale);
|
|
1527
2040
|
const { time: timePattern, compact: compactTimePattern } = timeFormats(locale);
|
|
1528
2041
|
const today = displayToday(timezone);
|
|
1529
|
-
const groupedEvents = (0,
|
|
2042
|
+
const groupedEvents = (0, import_react13.useMemo)(() => {
|
|
1530
2043
|
const byDay = eventsByStartDay(events, timezone);
|
|
1531
2044
|
const groups = [];
|
|
1532
2045
|
for (let i = 0; i < 30; i++) {
|
|
1533
|
-
const day = (0,
|
|
1534
|
-
const dayEvents = byDay.get((0,
|
|
2046
|
+
const day = (0, import_date_fns15.addDays)((0, import_date_fns15.startOfDay)(currentDate), i);
|
|
2047
|
+
const dayEvents = byDay.get((0, import_date_fns15.format)(day, "yyyy-MM-dd"));
|
|
1535
2048
|
if (dayEvents?.length) {
|
|
1536
2049
|
groups.push({ date: day, events: [...dayEvents].sort((a, b) => a.start.getTime() - b.start.getTime()) });
|
|
1537
2050
|
}
|
|
@@ -1551,7 +2064,7 @@ var AgendaView = ({
|
|
|
1551
2064
|
hidden: { opacity: 0, x: -20 },
|
|
1552
2065
|
show: { opacity: 1, x: 0 }
|
|
1553
2066
|
};
|
|
1554
|
-
return /* @__PURE__ */
|
|
2067
|
+
return /* @__PURE__ */ import_react13.default.createElement("div", { className: "flex flex-col h-full bg-background overflow-y-auto" }, groupedEvents.length === 0 ? /* @__PURE__ */ import_react13.default.createElement(AgendaEmptyState, { onCreateEvent, translations }) : /* @__PURE__ */ import_react13.default.createElement(
|
|
1555
2068
|
import_framer_motion.motion.div,
|
|
1556
2069
|
{
|
|
1557
2070
|
className: "max-w-3xl mx-auto w-full pb-10 px-4 md:px-6",
|
|
@@ -1559,25 +2072,26 @@ var AgendaView = ({
|
|
|
1559
2072
|
initial: "hidden",
|
|
1560
2073
|
animate: "show"
|
|
1561
2074
|
},
|
|
1562
|
-
groupedEvents.map((group) => /* @__PURE__ */
|
|
2075
|
+
groupedEvents.map((group) => /* @__PURE__ */ import_react13.default.createElement(
|
|
1563
2076
|
import_framer_motion.motion.div,
|
|
1564
2077
|
{
|
|
1565
2078
|
key: group.date.toISOString(),
|
|
1566
2079
|
className: "relative",
|
|
1567
2080
|
variants: item
|
|
1568
2081
|
},
|
|
1569
|
-
/* @__PURE__ */
|
|
2082
|
+
/* @__PURE__ */ import_react13.default.createElement("div", { className: "sticky top-0 bg-background/95 backdrop-blur-md py-4 z-10 border-b border-border/50" }, /* @__PURE__ */ import_react13.default.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ import_react13.default.createElement("div", { className: cn(
|
|
1570
2083
|
"flex flex-col items-center justify-center w-16 h-16 rounded-2xl transition-all",
|
|
1571
|
-
(0,
|
|
1572
|
-
) }, /* @__PURE__ */
|
|
2084
|
+
(0, import_date_fns15.isSameDay)(group.date, today) ? "bg-primary text-primary-foreground shadow-lg shadow-primary/30" : "bg-muted/50 text-foreground"
|
|
2085
|
+
) }, /* @__PURE__ */ import_react13.default.createElement("span", { className: "text-2xl font-bold leading-none" }, (0, import_date_fns15.format)(group.date, "d")), /* @__PURE__ */ import_react13.default.createElement("span", { className: "text-xs font-medium uppercase tracking-wide opacity-80" }, (0, import_date_fns15.format)(group.date, "MMM", { locale }))), /* @__PURE__ */ import_react13.default.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ import_react13.default.createElement("span", { className: cn(
|
|
1573
2086
|
"text-lg font-semibold",
|
|
1574
|
-
(0,
|
|
1575
|
-
) }, getDateLabel(group.date, today, locale, translations)), /* @__PURE__ */
|
|
1576
|
-
/* @__PURE__ */
|
|
2087
|
+
(0, import_date_fns15.isSameDay)(group.date, today) && "text-primary"
|
|
2088
|
+
) }, getDateLabel(group.date, today, locale, translations)), /* @__PURE__ */ import_react13.default.createElement("span", { className: "text-sm text-muted-foreground" }, group.events.length, " ", group.events.length !== 1 ? translations?.eventPlural || "events" : translations?.eventSingular || "event")))),
|
|
2089
|
+
/* @__PURE__ */ import_react13.default.createElement("div", { className: "py-4 space-y-3" }, group.events.map((event) => /* @__PURE__ */ import_react13.default.createElement(
|
|
1577
2090
|
import_framer_motion.motion.div,
|
|
1578
2091
|
{
|
|
1579
2092
|
key: event.id,
|
|
1580
2093
|
onClick: () => onEventClick?.(event),
|
|
2094
|
+
onContextMenu: onEventContextMenu ? (e) => onEventContextMenu(event, e) : void 0,
|
|
1581
2095
|
className: cn(
|
|
1582
2096
|
"group relative flex gap-4 p-4 rounded-2xl border border-border/40",
|
|
1583
2097
|
"hover:border-primary/40 hover:shadow-lg hover:shadow-primary/5",
|
|
@@ -1587,30 +2101,30 @@ var AgendaView = ({
|
|
|
1587
2101
|
whileHover: { scale: 1.01, y: -2 },
|
|
1588
2102
|
transition: { duration: 0.2 }
|
|
1589
2103
|
},
|
|
1590
|
-
/* @__PURE__ */
|
|
2104
|
+
/* @__PURE__ */ import_react13.default.createElement(
|
|
1591
2105
|
"div",
|
|
1592
2106
|
{
|
|
1593
2107
|
className: "absolute left-0 top-3 bottom-3 w-1 rounded-full",
|
|
1594
2108
|
style: { backgroundColor: event.color || "var(--primary)" }
|
|
1595
2109
|
}
|
|
1596
2110
|
),
|
|
1597
|
-
/* @__PURE__ */
|
|
1598
|
-
/* @__PURE__ */
|
|
2111
|
+
/* @__PURE__ */ import_react13.default.createElement("div", { className: "flex flex-col items-center min-w-[70px] pl-2" }, event.allDay ? /* @__PURE__ */ import_react13.default.createElement("div", { className: "flex flex-col items-center" }, /* @__PURE__ */ import_react13.default.createElement("span", { className: "text-xs font-semibold text-muted-foreground bg-muted/80 px-2.5 py-1 rounded-full" }, translations?.allDay || "All Day")) : /* @__PURE__ */ import_react13.default.createElement("div", { className: "flex flex-col items-center" }, /* @__PURE__ */ import_react13.default.createElement("span", { className: "text-base font-semibold text-foreground" }, (0, import_date_fns15.format)(toDisplay(event.start, timezone), compactTimePattern, { locale })), !is24h && /* @__PURE__ */ import_react13.default.createElement("span", { className: "text-xs text-muted-foreground uppercase" }, (0, import_date_fns15.format)(toDisplay(event.start, timezone), "a")), /* @__PURE__ */ import_react13.default.createElement("div", { className: "w-px h-3 bg-border my-1" }), /* @__PURE__ */ import_react13.default.createElement("span", { className: "text-xs text-muted-foreground/70 font-medium" }, formatDuration(event.start, event.end)))),
|
|
2112
|
+
/* @__PURE__ */ import_react13.default.createElement("div", { className: "flex-1 min-w-0 space-y-2" }, /* @__PURE__ */ import_react13.default.createElement("div", { className: "flex items-start justify-between gap-2" }, /* @__PURE__ */ import_react13.default.createElement("h4", { className: "text-base font-semibold text-foreground group-hover:text-primary transition-colors line-clamp-1" }, event.title), /* @__PURE__ */ import_react13.default.createElement(
|
|
1599
2113
|
"div",
|
|
1600
2114
|
{
|
|
1601
2115
|
className: "w-3 h-3 rounded-full shrink-0 mt-1.5",
|
|
1602
2116
|
style: { backgroundColor: event.color || "var(--primary)" }
|
|
1603
2117
|
}
|
|
1604
|
-
)), event.description && /* @__PURE__ */
|
|
1605
|
-
/* @__PURE__ */
|
|
2118
|
+
)), event.description && /* @__PURE__ */ import_react13.default.createElement("p", { className: "text-sm text-muted-foreground line-clamp-2 leading-relaxed" }, event.description), /* @__PURE__ */ import_react13.default.createElement("div", { className: "flex flex-wrap items-center gap-3 pt-1" }, !event.allDay && /* @__PURE__ */ import_react13.default.createElement("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground" }, /* @__PURE__ */ import_react13.default.createElement(import_lucide_react5.Clock, { className: "w-3.5 h-3.5" }), /* @__PURE__ */ import_react13.default.createElement("span", null, (0, import_date_fns15.format)(toDisplay(event.start, timezone), timePattern, { locale }), " - ", (0, import_date_fns15.format)(toDisplay(event.end, timezone), timePattern, { locale }))), event.guests && event.guests.length > 0 && /* @__PURE__ */ import_react13.default.createElement("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground" }, /* @__PURE__ */ import_react13.default.createElement(import_lucide_react5.Users, { className: "w-3.5 h-3.5" }), /* @__PURE__ */ import_react13.default.createElement("span", null, event.guests.length, " ", event.guests.length !== 1 ? translations?.guestsCount || "guests" : translations?.guestCount || "guest")), event.attachments && event.attachments.length > 0 && /* @__PURE__ */ import_react13.default.createElement("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground" }, /* @__PURE__ */ import_react13.default.createElement(import_lucide_react5.Paperclip, { className: "w-3.5 h-3.5" }), /* @__PURE__ */ import_react13.default.createElement("span", null, event.attachments.length)), event.reminders && event.reminders.length > 0 && /* @__PURE__ */ import_react13.default.createElement("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground" }, /* @__PURE__ */ import_react13.default.createElement(import_lucide_react5.Bell, { className: "w-3.5 h-3.5" }), /* @__PURE__ */ import_react13.default.createElement("span", null, event.reminders.length)))),
|
|
2119
|
+
/* @__PURE__ */ import_react13.default.createElement("div", { className: "absolute right-4 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 transition-opacity" }, /* @__PURE__ */ import_react13.default.createElement("svg", { className: "w-5 h-5 text-muted-foreground", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" }, /* @__PURE__ */ import_react13.default.createElement("path", { d: "M9 18l6-6-6-6" })))
|
|
1606
2120
|
)))
|
|
1607
2121
|
))
|
|
1608
2122
|
));
|
|
1609
2123
|
};
|
|
1610
2124
|
|
|
1611
2125
|
// src/views/ResourceView.tsx
|
|
1612
|
-
var
|
|
1613
|
-
var
|
|
2126
|
+
var import_react14 = __toESM(require("react"));
|
|
2127
|
+
var import_date_fns16 = require("date-fns");
|
|
1614
2128
|
var ResourceView = ({
|
|
1615
2129
|
currentDate,
|
|
1616
2130
|
events,
|
|
@@ -1618,18 +2132,20 @@ var ResourceView = ({
|
|
|
1618
2132
|
onEventClick,
|
|
1619
2133
|
onTimeSlotClick,
|
|
1620
2134
|
locale,
|
|
1621
|
-
timezone
|
|
2135
|
+
timezone,
|
|
2136
|
+
translations,
|
|
2137
|
+
onEventContextMenu
|
|
1622
2138
|
}) => {
|
|
1623
|
-
const containerRef = (0,
|
|
2139
|
+
const containerRef = (0, import_react14.useRef)(null);
|
|
1624
2140
|
const hours = Array.from({ length: 24 }, (_, i) => i);
|
|
1625
2141
|
const hourWidth = 100;
|
|
1626
2142
|
const timeFormat = timeFormats(locale).hour;
|
|
1627
2143
|
const getEventStyle = (event) => {
|
|
1628
2144
|
const start = toDisplay(event.start, timezone);
|
|
1629
2145
|
const end = toDisplay(event.end, timezone);
|
|
1630
|
-
const dayStart = (0,
|
|
1631
|
-
const startMinutes = (0,
|
|
1632
|
-
const durationMinutes = (0,
|
|
2146
|
+
const dayStart = (0, import_date_fns16.startOfDay)(currentDate);
|
|
2147
|
+
const startMinutes = (0, import_date_fns16.differenceInMinutes)(start, dayStart);
|
|
2148
|
+
const durationMinutes = (0, import_date_fns16.differenceInMinutes)(end, start);
|
|
1633
2149
|
const left = startMinutes / 60 * hourWidth;
|
|
1634
2150
|
const width = durationMinutes / 60 * hourWidth;
|
|
1635
2151
|
return {
|
|
@@ -1638,19 +2154,19 @@ var ResourceView = ({
|
|
|
1638
2154
|
// Min width for visibility
|
|
1639
2155
|
};
|
|
1640
2156
|
};
|
|
1641
|
-
return /* @__PURE__ */
|
|
2157
|
+
return /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex flex-col h-full bg-background overflow-hidden" }, /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex border-b border-border bg-muted/20" }, /* @__PURE__ */ import_react14.default.createElement("div", { className: "w-48 shrink-0 border-r border-border p-4 font-semibold text-sm bg-background sticky left-0 z-20" }, translations?.resource || "Resources"), /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex overflow-hidden" }, /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex relative", style: { width: hours.length * hourWidth } }, hours.map((hour) => /* @__PURE__ */ import_react14.default.createElement(
|
|
1642
2158
|
"div",
|
|
1643
2159
|
{
|
|
1644
2160
|
key: hour,
|
|
1645
2161
|
className: "border-r border-border/50 text-xs text-muted-foreground p-2 font-medium shrink-0",
|
|
1646
2162
|
style: { width: hourWidth }
|
|
1647
2163
|
},
|
|
1648
|
-
(0,
|
|
1649
|
-
))))), /* @__PURE__ */
|
|
2164
|
+
(0, import_date_fns16.format)((/* @__PURE__ */ new Date()).setHours(hour, 0, 0, 0), timeFormat, { locale })
|
|
2165
|
+
))))), /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex-1 overflow-auto relative", ref: containerRef }, /* @__PURE__ */ import_react14.default.createElement("div", { className: "min-w-fit" }, resources.map((resource) => {
|
|
1650
2166
|
const resourceEvents = events.filter(
|
|
1651
2167
|
(e) => e.resourceId === resource.id && isSameDisplayDay(e.start, currentDate, timezone)
|
|
1652
2168
|
);
|
|
1653
|
-
return /* @__PURE__ */
|
|
2169
|
+
return /* @__PURE__ */ import_react14.default.createElement("div", { key: resource.id, className: "flex border-b border-border min-h-[100px]" }, /* @__PURE__ */ import_react14.default.createElement("div", { className: "w-48 shrink-0 border-r border-border p-4 bg-background sticky left-0 z-10 flex items-center gap-3" }, resource.avatar ? /* @__PURE__ */ import_react14.default.createElement("img", { src: resource.avatar, alt: resource.label, className: "w-8 h-8 rounded-full object-cover" }) : /* @__PURE__ */ import_react14.default.createElement("div", { className: "w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center text-xs font-bold text-primary" }, resource.label.substring(0, 2).toUpperCase()), /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ import_react14.default.createElement("span", { className: "text-sm font-medium" }, resource.label), /* @__PURE__ */ import_react14.default.createElement("span", { className: "text-xs text-muted-foreground" }, interpolate(translations?.idLabel || "ID: {id}", { id: resource.id })))), /* @__PURE__ */ import_react14.default.createElement("div", { className: "relative flex", style: { width: hours.length * hourWidth } }, hours.map((hour) => /* @__PURE__ */ import_react14.default.createElement(
|
|
1654
2170
|
"div",
|
|
1655
2171
|
{
|
|
1656
2172
|
key: hour,
|
|
@@ -1661,7 +2177,7 @@ var ResourceView = ({
|
|
|
1661
2177
|
const slotDate3 = new Date(currentDate);
|
|
1662
2178
|
slotDate3.setHours(hour, minute, 0, 0);
|
|
1663
2179
|
const slotId = `${resource.id}-${slotDate3.toISOString()}`;
|
|
1664
|
-
return /* @__PURE__ */
|
|
2180
|
+
return /* @__PURE__ */ import_react14.default.createElement(
|
|
1665
2181
|
DroppableCell,
|
|
1666
2182
|
{
|
|
1667
2183
|
key: minute,
|
|
@@ -1673,7 +2189,7 @@ var ResourceView = ({
|
|
|
1673
2189
|
}
|
|
1674
2190
|
);
|
|
1675
2191
|
})
|
|
1676
|
-
)), resourceEvents.map((event) => /* @__PURE__ */
|
|
2192
|
+
)), resourceEvents.map((event) => /* @__PURE__ */ import_react14.default.createElement(
|
|
1677
2193
|
DraggableEvent,
|
|
1678
2194
|
{
|
|
1679
2195
|
key: event.id,
|
|
@@ -1682,6 +2198,7 @@ var ResourceView = ({
|
|
|
1682
2198
|
e.stopPropagation();
|
|
1683
2199
|
onEventClick?.(event);
|
|
1684
2200
|
},
|
|
2201
|
+
onContextMenu: onEventContextMenu ? (e) => onEventContextMenu(event, e) : void 0,
|
|
1685
2202
|
className: "absolute top-2 bottom-2 rounded-md px-2 py-1 text-xs font-medium border shadow-sm cursor-pointer overflow-hidden hover:brightness-95 transition-all z-10",
|
|
1686
2203
|
style: {
|
|
1687
2204
|
...getEventStyle(event),
|
|
@@ -1690,16 +2207,16 @@ var ResourceView = ({
|
|
|
1690
2207
|
color: "#fff"
|
|
1691
2208
|
}
|
|
1692
2209
|
},
|
|
1693
|
-
/* @__PURE__ */
|
|
2210
|
+
/* @__PURE__ */ import_react14.default.createElement("div", { className: "truncate" }, event.title)
|
|
1694
2211
|
))));
|
|
1695
2212
|
}))));
|
|
1696
2213
|
};
|
|
1697
2214
|
|
|
1698
2215
|
// src/components/EventModal.tsx
|
|
1699
|
-
var
|
|
2216
|
+
var import_react16 = __toESM(require("react"));
|
|
1700
2217
|
|
|
1701
2218
|
// src/components/ui/Modal.tsx
|
|
1702
|
-
var
|
|
2219
|
+
var import_react15 = __toESM(require("react"));
|
|
1703
2220
|
var import_lucide_react6 = require("lucide-react");
|
|
1704
2221
|
var Modal = ({
|
|
1705
2222
|
isOpen,
|
|
@@ -1707,10 +2224,11 @@ var Modal = ({
|
|
|
1707
2224
|
title,
|
|
1708
2225
|
children,
|
|
1709
2226
|
className,
|
|
1710
|
-
hideHeader = false
|
|
2227
|
+
hideHeader = false,
|
|
2228
|
+
closeLabel = "Close"
|
|
1711
2229
|
}) => {
|
|
1712
|
-
const overlayRef = (0,
|
|
1713
|
-
(0,
|
|
2230
|
+
const overlayRef = (0, import_react15.useRef)(null);
|
|
2231
|
+
(0, import_react15.useEffect)(() => {
|
|
1714
2232
|
const handleEscape = (e) => {
|
|
1715
2233
|
if (e.key === "Escape") {
|
|
1716
2234
|
onClose();
|
|
@@ -1724,14 +2242,14 @@ var Modal = ({
|
|
|
1724
2242
|
};
|
|
1725
2243
|
}, [isOpen, onClose]);
|
|
1726
2244
|
if (!isOpen) return null;
|
|
1727
|
-
return /* @__PURE__ */
|
|
2245
|
+
return /* @__PURE__ */ import_react15.default.createElement("div", { className: "absolute inset-0 z-50 flex items-center justify-center p-4 bg-black/40 backdrop-blur-md animate-in fade-in duration-300" }, /* @__PURE__ */ import_react15.default.createElement(
|
|
1728
2246
|
"div",
|
|
1729
2247
|
{
|
|
1730
2248
|
ref: overlayRef,
|
|
1731
2249
|
className: "absolute inset-0",
|
|
1732
2250
|
onClick: onClose
|
|
1733
2251
|
}
|
|
1734
|
-
), /* @__PURE__ */
|
|
2252
|
+
), /* @__PURE__ */ import_react15.default.createElement(
|
|
1735
2253
|
"div",
|
|
1736
2254
|
{
|
|
1737
2255
|
className: cn(
|
|
@@ -1739,7 +2257,7 @@ var Modal = ({
|
|
|
1739
2257
|
className
|
|
1740
2258
|
)
|
|
1741
2259
|
},
|
|
1742
|
-
!hideHeader && /* @__PURE__ */
|
|
2260
|
+
!hideHeader && /* @__PURE__ */ import_react15.default.createElement("div", { className: "flex items-center justify-between px-6 py-4 border-b border-border/50 shrink-0 bg-gradient-to-r from-muted/20 to-background" }, /* @__PURE__ */ import_react15.default.createElement("h3", { className: "text-lg font-semibold text-foreground" }, title), /* @__PURE__ */ import_react15.default.createElement(
|
|
1743
2261
|
Button,
|
|
1744
2262
|
{
|
|
1745
2263
|
variant: "ghost",
|
|
@@ -1747,29 +2265,18 @@ var Modal = ({
|
|
|
1747
2265
|
onClick: onClose,
|
|
1748
2266
|
className: "h-9 w-9 p-0 rounded-xl hover:bg-accent/80 transition-all duration-200"
|
|
1749
2267
|
},
|
|
1750
|
-
/* @__PURE__ */
|
|
1751
|
-
/* @__PURE__ */
|
|
2268
|
+
/* @__PURE__ */ import_react15.default.createElement(import_lucide_react6.X, { className: "h-4 w-4" }),
|
|
2269
|
+
/* @__PURE__ */ import_react15.default.createElement("span", { className: "sr-only" }, closeLabel)
|
|
1752
2270
|
)),
|
|
1753
|
-
/* @__PURE__ */
|
|
2271
|
+
/* @__PURE__ */ import_react15.default.createElement("div", { className: cn("overflow-y-auto flex-1", !hideHeader && "p-6") }, children)
|
|
1754
2272
|
));
|
|
1755
2273
|
};
|
|
1756
2274
|
|
|
1757
2275
|
// src/components/EventModal.tsx
|
|
1758
|
-
var
|
|
2276
|
+
var import_date_fns17 = require("date-fns");
|
|
1759
2277
|
var import_framer_motion2 = require("framer-motion");
|
|
1760
2278
|
var import_lucide_react7 = require("lucide-react");
|
|
1761
|
-
var REMINDER_OPTIONS = [
|
|
1762
|
-
{ value: 0, label: "At time of event" },
|
|
1763
|
-
{ value: 5, label: "5 minutes before" },
|
|
1764
|
-
{ value: 10, label: "10 minutes before" },
|
|
1765
|
-
{ value: 15, label: "15 minutes before" },
|
|
1766
|
-
{ value: 30, label: "30 minutes before" },
|
|
1767
|
-
{ value: 60, label: "1 hour before" },
|
|
1768
|
-
{ value: 120, label: "2 hours before" },
|
|
1769
|
-
{ value: 1440, label: "1 day before" },
|
|
1770
|
-
{ value: 2880, label: "2 days before" },
|
|
1771
|
-
{ value: 10080, label: "1 week before" }
|
|
1772
|
-
];
|
|
2279
|
+
var REMINDER_OPTIONS = [0, 5, 10, 15, 30, 60, 120, 1440, 2880, 10080];
|
|
1773
2280
|
var COLOR_PALETTE = [
|
|
1774
2281
|
"#3b82f6",
|
|
1775
2282
|
// Blue
|
|
@@ -1792,6 +2299,30 @@ var COLOR_PALETTE = [
|
|
|
1792
2299
|
"#6366f1"
|
|
1793
2300
|
// Indigo
|
|
1794
2301
|
];
|
|
2302
|
+
var EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2303
|
+
var mergeGuests = (current, added) => {
|
|
2304
|
+
const seen = new Set(current.map((email) => email.toLowerCase()));
|
|
2305
|
+
const merged = [...current];
|
|
2306
|
+
for (const email of added) {
|
|
2307
|
+
if (!seen.has(email.toLowerCase())) {
|
|
2308
|
+
seen.add(email.toLowerCase());
|
|
2309
|
+
merged.push(email);
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
return merged;
|
|
2313
|
+
};
|
|
2314
|
+
var reminderLabel = (minutes, t) => {
|
|
2315
|
+
if (minutes === 0) return t.reminderAtTime;
|
|
2316
|
+
if (minutes === 10080) return t.reminderWeek;
|
|
2317
|
+
if (minutes === 1440) return t.reminderDay;
|
|
2318
|
+
if (minutes % 1440 === 0) return interpolate(t.reminderDays, { n: minutes / 1440 });
|
|
2319
|
+
if (minutes === 60) return t.reminderHour;
|
|
2320
|
+
if (minutes % 60 === 0) return interpolate(t.reminderHours, { n: minutes / 60 });
|
|
2321
|
+
return interpolate(t.reminderMinutes, { n: minutes });
|
|
2322
|
+
};
|
|
2323
|
+
var avatarHue = (email) => [...email].reduce((hash, char) => (hash * 31 + char.charCodeAt(0)) % 360, 7);
|
|
2324
|
+
var mapsUrl = (location) => `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(location)}`;
|
|
2325
|
+
var isSafeUrl = (url) => /^(https?:|mailto:|blob:|\/|\.\/|\.\.\/|[^:]*$)/i.test(url.trim());
|
|
1795
2326
|
var EventModal = ({
|
|
1796
2327
|
isOpen,
|
|
1797
2328
|
onClose,
|
|
@@ -1799,10 +2330,17 @@ var EventModal = ({
|
|
|
1799
2330
|
initialDate,
|
|
1800
2331
|
onSave,
|
|
1801
2332
|
onDelete,
|
|
1802
|
-
calendars
|
|
2333
|
+
calendars,
|
|
2334
|
+
translations: t,
|
|
2335
|
+
locale,
|
|
2336
|
+
initialAllDay
|
|
1803
2337
|
}) => {
|
|
1804
|
-
const [mode, setMode] = (0,
|
|
1805
|
-
const
|
|
2338
|
+
const [mode, setMode] = (0, import_react16.useState)("create");
|
|
2339
|
+
const translationsRef = (0, import_react16.useRef)(t);
|
|
2340
|
+
(0, import_react16.useInsertionEffect)(() => {
|
|
2341
|
+
translationsRef.current = t;
|
|
2342
|
+
});
|
|
2343
|
+
const [formData, setFormData] = (0, import_react16.useState)({
|
|
1806
2344
|
title: "",
|
|
1807
2345
|
description: "",
|
|
1808
2346
|
location: "",
|
|
@@ -1814,22 +2352,18 @@ var EventModal = ({
|
|
|
1814
2352
|
type: void 0,
|
|
1815
2353
|
recurrence: void 0,
|
|
1816
2354
|
attachments: [],
|
|
1817
|
-
reminders: [
|
|
2355
|
+
reminders: []
|
|
1818
2356
|
});
|
|
1819
|
-
const [isCalendarDropdownOpen, setIsCalendarDropdownOpen] = (0,
|
|
1820
|
-
const [isColorPickerOpen, setIsColorPickerOpen] = (0,
|
|
1821
|
-
const [isReminderDropdownOpen, setIsReminderDropdownOpen] = (0,
|
|
1822
|
-
const [
|
|
1823
|
-
const
|
|
1824
|
-
|
|
1825
|
-
"
|
|
1826
|
-
"charlie@example.com",
|
|
1827
|
-
"diana@example.com",
|
|
1828
|
-
"evan@example.com"
|
|
1829
|
-
];
|
|
1830
|
-
const [selectedGuests, setSelectedGuests] = (0, import_react14.useState)([]);
|
|
1831
|
-
(0, import_react14.useEffect)(() => {
|
|
2357
|
+
const [isCalendarDropdownOpen, setIsCalendarDropdownOpen] = (0, import_react16.useState)(false);
|
|
2358
|
+
const [isColorPickerOpen, setIsColorPickerOpen] = (0, import_react16.useState)(false);
|
|
2359
|
+
const [isReminderDropdownOpen, setIsReminderDropdownOpen] = (0, import_react16.useState)(false);
|
|
2360
|
+
const [guestInput, setGuestInput] = (0, import_react16.useState)("");
|
|
2361
|
+
const [guestError, setGuestError] = (0, import_react16.useState)(false);
|
|
2362
|
+
(0, import_react16.useEffect)(() => {
|
|
2363
|
+
const defaultReminders = () => [{ id: "1", type: "notification", time: 30, label: reminderLabel(30, translationsRef.current) }];
|
|
1832
2364
|
if (isOpen) {
|
|
2365
|
+
setGuestInput("");
|
|
2366
|
+
setGuestError(false);
|
|
1833
2367
|
if (event) {
|
|
1834
2368
|
setMode("view");
|
|
1835
2369
|
setFormData({
|
|
@@ -1837,39 +2371,52 @@ var EventModal = ({
|
|
|
1837
2371
|
start: new Date(event.start),
|
|
1838
2372
|
end: new Date(event.end),
|
|
1839
2373
|
attachments: event.attachments || [],
|
|
1840
|
-
reminders: event.reminders ||
|
|
2374
|
+
reminders: event.reminders || defaultReminders(),
|
|
2375
|
+
guests: event.guests || []
|
|
1841
2376
|
});
|
|
1842
|
-
setSelectedGuests(event.guests || []);
|
|
1843
2377
|
} else {
|
|
1844
2378
|
setMode("create");
|
|
1845
|
-
const
|
|
1846
|
-
const
|
|
1847
|
-
end.
|
|
2379
|
+
const base = initialDate || /* @__PURE__ */ new Date();
|
|
2380
|
+
const start = initialAllDay ? (0, import_date_fns17.startOfDay)(base) : base;
|
|
2381
|
+
const end = initialAllDay ? (0, import_date_fns17.addDays)(start, 1) : new Date(base.getTime() + 60 * 60 * 1e3);
|
|
1848
2382
|
setFormData({
|
|
1849
2383
|
title: "",
|
|
1850
2384
|
description: "",
|
|
1851
2385
|
location: "",
|
|
1852
2386
|
start,
|
|
1853
2387
|
end,
|
|
1854
|
-
allDay:
|
|
2388
|
+
allDay: !!initialAllDay,
|
|
1855
2389
|
color: "#3b82f6",
|
|
1856
2390
|
calendarId: calendars?.[0]?.id,
|
|
1857
2391
|
attachments: [],
|
|
1858
|
-
reminders:
|
|
2392
|
+
reminders: defaultReminders(),
|
|
2393
|
+
guests: []
|
|
1859
2394
|
});
|
|
1860
|
-
setSelectedGuests([]);
|
|
1861
2395
|
}
|
|
1862
2396
|
}
|
|
1863
|
-
}, [isOpen, event, initialDate, calendars]);
|
|
1864
|
-
const
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
2397
|
+
}, [isOpen, event, initialDate, calendars, initialAllDay]);
|
|
2398
|
+
const guests = formData.guests || [];
|
|
2399
|
+
const addGuests = (raw) => {
|
|
2400
|
+
const entries = raw.split(/[\s,;]+/).filter(Boolean);
|
|
2401
|
+
const valid = entries.filter((entry) => EMAIL.test(entry));
|
|
2402
|
+
const invalid = entries.filter((entry) => !EMAIL.test(entry));
|
|
2403
|
+
if (valid.length > 0) {
|
|
2404
|
+
setFormData((prev) => ({ ...prev, guests: mergeGuests(prev.guests || [], valid) }));
|
|
2405
|
+
}
|
|
2406
|
+
setGuestInput(invalid.join(", "));
|
|
2407
|
+
setGuestError(invalid.length > 0);
|
|
2408
|
+
return invalid.length === 0;
|
|
2409
|
+
};
|
|
2410
|
+
const removeGuest = (email) => {
|
|
2411
|
+
setFormData((prev) => ({ ...prev, guests: (prev.guests || []).filter((g) => g !== email) }));
|
|
1870
2412
|
};
|
|
1871
2413
|
const handleSubmit = (e) => {
|
|
1872
2414
|
e.preventDefault();
|
|
2415
|
+
const pending = guestInput.split(/[\s,;]+/).filter(Boolean);
|
|
2416
|
+
if (pending.some((entry) => !EMAIL.test(entry))) {
|
|
2417
|
+
addGuests(guestInput);
|
|
2418
|
+
return;
|
|
2419
|
+
}
|
|
1873
2420
|
let eventColor = formData.color;
|
|
1874
2421
|
if (formData.calendarId && calendars) {
|
|
1875
2422
|
const selectedCal = calendars.find((c) => c.id === formData.calendarId);
|
|
@@ -1877,8 +2424,10 @@ var EventModal = ({
|
|
|
1877
2424
|
eventColor = selectedCal.color;
|
|
1878
2425
|
}
|
|
1879
2426
|
}
|
|
2427
|
+
const finalGuests = mergeGuests(guests, pending);
|
|
1880
2428
|
onSave({
|
|
1881
2429
|
...formData,
|
|
2430
|
+
guests: finalGuests,
|
|
1882
2431
|
color: eventColor,
|
|
1883
2432
|
id: event?.id
|
|
1884
2433
|
});
|
|
@@ -1892,9 +2441,38 @@ var EventModal = ({
|
|
|
1892
2441
|
};
|
|
1893
2442
|
const formatDateForInput = (date) => {
|
|
1894
2443
|
if (!date) return "";
|
|
1895
|
-
return (0,
|
|
2444
|
+
return (0, import_date_fns17.format)(date, "yyyy-MM-dd'T'HH:mm");
|
|
2445
|
+
};
|
|
2446
|
+
const allDaySpan = formData.allDay && formData.start && formData.end ? dayEventSpan({ ...formData, allDay: true }) : null;
|
|
2447
|
+
const handleAllDayToggle = () => {
|
|
2448
|
+
if (!formData.start || !formData.end) return;
|
|
2449
|
+
if (!formData.allDay) {
|
|
2450
|
+
const firstDay = (0, import_date_fns17.startOfDay)(formData.start);
|
|
2451
|
+
const lastDay = (0, import_date_fns17.startOfDay)(new Date(Math.max(formData.end.getTime() - 1, formData.start.getTime())));
|
|
2452
|
+
setFormData((prev) => ({ ...prev, allDay: true, start: firstDay, end: (0, import_date_fns17.addDays)(lastDay, 1) }));
|
|
2453
|
+
} else {
|
|
2454
|
+
const start = new Date(formData.start);
|
|
2455
|
+
start.setHours(9, 0, 0, 0);
|
|
2456
|
+
setFormData((prev) => ({ ...prev, allDay: false, start, end: new Date(start.getTime() + 60 * 60 * 1e3) }));
|
|
2457
|
+
}
|
|
2458
|
+
};
|
|
2459
|
+
const handleAllDayDateChange = (field, value) => {
|
|
2460
|
+
const [y, m, d] = value.split("-").map(Number);
|
|
2461
|
+
if (!y || !m || !d || !allDaySpan) return;
|
|
2462
|
+
const day = new Date(y, m - 1, d);
|
|
2463
|
+
if (field === "start") {
|
|
2464
|
+
const days = (0, import_date_fns17.differenceInCalendarDays)(allDaySpan.lastDay, allDaySpan.firstDay);
|
|
2465
|
+
setFormData((prev) => ({ ...prev, start: day, end: (0, import_date_fns17.addDays)(day, days + 1) }));
|
|
2466
|
+
} else {
|
|
2467
|
+
const firstDay = day < allDaySpan.firstDay ? day : allDaySpan.firstDay;
|
|
2468
|
+
setFormData((prev) => ({ ...prev, start: firstDay, end: (0, import_date_fns17.addDays)(day, 1) }));
|
|
2469
|
+
}
|
|
1896
2470
|
};
|
|
1897
2471
|
const handleDateChange = (field, value) => {
|
|
2472
|
+
if (formData.allDay) {
|
|
2473
|
+
handleAllDayDateChange(field, value);
|
|
2474
|
+
return;
|
|
2475
|
+
}
|
|
1898
2476
|
const date = new Date(value);
|
|
1899
2477
|
if (isNaN(date.getTime())) return;
|
|
1900
2478
|
if (field === "start") {
|
|
@@ -1912,12 +2490,12 @@ var EventModal = ({
|
|
|
1912
2490
|
}
|
|
1913
2491
|
}
|
|
1914
2492
|
};
|
|
1915
|
-
const addReminder = (minutes
|
|
2493
|
+
const addReminder = (minutes) => {
|
|
1916
2494
|
const newReminder = {
|
|
1917
|
-
id: Math.random().toString(36).
|
|
2495
|
+
id: Math.random().toString(36).slice(2, 11),
|
|
1918
2496
|
type: "notification",
|
|
1919
2497
|
time: minutes,
|
|
1920
|
-
label
|
|
2498
|
+
label: reminderLabel(minutes, t)
|
|
1921
2499
|
};
|
|
1922
2500
|
setFormData((prev) => ({
|
|
1923
2501
|
...prev,
|
|
@@ -1931,25 +2509,28 @@ var EventModal = ({
|
|
|
1931
2509
|
reminders: prev.reminders?.filter((r) => r.id !== id)
|
|
1932
2510
|
}));
|
|
1933
2511
|
};
|
|
1934
|
-
const handleDownload = (attachment) => {
|
|
1935
|
-
const element = document.createElement("a");
|
|
1936
|
-
const file = new Blob(["Dummy content for " + attachment.name], { type: "text/plain" });
|
|
1937
|
-
element.href = URL.createObjectURL(file);
|
|
1938
|
-
element.download = attachment.name;
|
|
1939
|
-
document.body.appendChild(element);
|
|
1940
|
-
element.click();
|
|
1941
|
-
document.body.removeChild(element);
|
|
1942
|
-
};
|
|
1943
2512
|
const getDurationText = () => {
|
|
1944
2513
|
if (!formData.start || !formData.end) return "";
|
|
1945
|
-
|
|
1946
|
-
|
|
2514
|
+
if (allDaySpan) {
|
|
2515
|
+
const days = (0, import_date_fns17.differenceInCalendarDays)(allDaySpan.lastDay, allDaySpan.firstDay) + 1;
|
|
2516
|
+
return days === 1 ? t.durationDay : interpolate(t.durationDays, { n: days });
|
|
2517
|
+
}
|
|
2518
|
+
const mins = (0, import_date_fns17.differenceInMinutes)(formData.end, formData.start);
|
|
2519
|
+
if (mins < 60) return interpolate(t.durationMinutes, { n: mins });
|
|
1947
2520
|
const hours = Math.floor(mins / 60);
|
|
1948
2521
|
const remainingMins = mins % 60;
|
|
1949
|
-
if (remainingMins === 0) return
|
|
1950
|
-
return
|
|
2522
|
+
if (remainingMins === 0) return interpolate(t.durationHours, { n: hours });
|
|
2523
|
+
return interpolate(t.durationHoursMinutes, { h: hours, m: remainingMins });
|
|
1951
2524
|
};
|
|
1952
|
-
const
|
|
2525
|
+
const { time: timeFormat } = timeFormats(locale);
|
|
2526
|
+
const viewEvent = event && { ...event, start: new Date(event.start), end: new Date(event.end) };
|
|
2527
|
+
const viewSpan = viewEvent && isDayEvent(viewEvent) ? dayEventSpan(viewEvent) : null;
|
|
2528
|
+
const renderAttachment = (att) => {
|
|
2529
|
+
const content = /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement("div", { className: "p-2 bg-primary/10 rounded-lg" }, /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.File, { className: "w-4 h-4 text-primary" })), /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ import_react16.default.createElement("p", { className: "text-sm font-medium text-foreground truncate" }, att.name), /* @__PURE__ */ import_react16.default.createElement("p", { className: "text-xs text-muted-foreground" }, att.size)), att.url && /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.Download, { className: "w-4 h-4 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity" }));
|
|
2530
|
+
const className = "flex items-center gap-3 p-3 rounded-xl border border-border/30 bg-muted/20 transition-all group";
|
|
2531
|
+
return att.url && isSafeUrl(att.url) ? /* @__PURE__ */ import_react16.default.createElement("a", { key: att.id, href: att.url, target: "_blank", rel: "noopener noreferrer", download: att.name, className: cn(className, "hover:bg-muted/40 cursor-pointer") }, content) : /* @__PURE__ */ import_react16.default.createElement("div", { key: att.id, className }, content);
|
|
2532
|
+
};
|
|
2533
|
+
const renderViewMode = () => /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex flex-col bg-background overflow-hidden w-full max-h-[90vh]" }, /* @__PURE__ */ import_react16.default.createElement(
|
|
1953
2534
|
"div",
|
|
1954
2535
|
{
|
|
1955
2536
|
className: "relative px-6 pt-6 pb-8",
|
|
@@ -1957,50 +2538,56 @@ var EventModal = ({
|
|
|
1957
2538
|
background: `linear-gradient(135deg, ${event?.color || "#3b82f6"}15 0%, transparent 100%)`
|
|
1958
2539
|
}
|
|
1959
2540
|
},
|
|
1960
|
-
/* @__PURE__ */
|
|
2541
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center justify-between mb-6" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react16.default.createElement(
|
|
1961
2542
|
"div",
|
|
1962
2543
|
{
|
|
1963
2544
|
className: "w-3 h-3 rounded-full",
|
|
1964
2545
|
style: { backgroundColor: event?.color || "#3b82f6" }
|
|
1965
2546
|
}
|
|
1966
|
-
), /* @__PURE__ */
|
|
2547
|
+
), /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wider" }, calendars?.find((c) => c.id === event?.calendarId)?.label || t.event)), /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react16.default.createElement(
|
|
1967
2548
|
"button",
|
|
1968
2549
|
{
|
|
1969
2550
|
onClick: () => setMode("edit"),
|
|
1970
2551
|
className: "p-2 hover:bg-background/80 rounded-lg transition-all text-muted-foreground hover:text-foreground",
|
|
1971
|
-
title:
|
|
2552
|
+
title: t.edit,
|
|
2553
|
+
"aria-label": t.edit
|
|
1972
2554
|
},
|
|
1973
|
-
/* @__PURE__ */
|
|
1974
|
-
), /* @__PURE__ */
|
|
2555
|
+
/* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.Edit2, { className: "w-4 h-4" })
|
|
2556
|
+
), /* @__PURE__ */ import_react16.default.createElement(
|
|
1975
2557
|
"button",
|
|
1976
2558
|
{
|
|
1977
2559
|
onClick: handleDelete,
|
|
1978
2560
|
className: "p-2 hover:bg-destructive/10 rounded-lg transition-all text-muted-foreground hover:text-destructive",
|
|
1979
|
-
title:
|
|
2561
|
+
title: t.delete,
|
|
2562
|
+
"aria-label": t.delete
|
|
1980
2563
|
},
|
|
1981
|
-
/* @__PURE__ */
|
|
1982
|
-
), /* @__PURE__ */
|
|
2564
|
+
/* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.Trash2, { className: "w-4 h-4" })
|
|
2565
|
+
), /* @__PURE__ */ import_react16.default.createElement(
|
|
1983
2566
|
"button",
|
|
1984
2567
|
{
|
|
1985
2568
|
onClick: onClose,
|
|
1986
2569
|
className: "p-2 hover:bg-background/80 rounded-lg transition-all text-muted-foreground hover:text-foreground",
|
|
1987
|
-
title:
|
|
2570
|
+
title: t.close,
|
|
2571
|
+
"aria-label": t.close
|
|
1988
2572
|
},
|
|
1989
|
-
/* @__PURE__ */
|
|
2573
|
+
/* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.X, { className: "w-4 h-4" })
|
|
1990
2574
|
))),
|
|
1991
|
-
/* @__PURE__ */
|
|
1992
|
-
/* @__PURE__ */
|
|
1993
|
-
), /* @__PURE__ */
|
|
1994
|
-
import_framer_motion2.motion.
|
|
2575
|
+
/* @__PURE__ */ import_react16.default.createElement("h1", { className: "text-2xl font-bold text-foreground mb-3 leading-tight" }, event?.title || t.noTitle),
|
|
2576
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-3 text-sm" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2 px-3 py-1.5 bg-background/60 backdrop-blur-sm rounded-lg border border-border/30" }, /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.Calendar, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ import_react16.default.createElement("span", { className: "font-medium" }, viewSpan && viewSpan.lastDay > viewSpan.firstDay ? `${(0, import_date_fns17.format)(viewSpan.firstDay, "EEE d MMM", { locale })} \u2013 ${(0, import_date_fns17.format)(viewSpan.lastDay, "EEE d MMM", { locale })}` : event?.start && (0, import_date_fns17.format)(new Date(event.start), "EEE, MMM d", { locale }))), event?.allDay ? /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2 px-3 py-1.5 bg-primary/10 rounded-lg border border-primary/20" }, /* @__PURE__ */ import_react16.default.createElement("span", { className: "font-medium text-primary" }, t.allDay)) : /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2 px-3 py-1.5 bg-background/60 backdrop-blur-sm rounded-lg border border-border/30" }, /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.Clock, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ import_react16.default.createElement("span", { className: "font-medium" }, event?.start && (0, import_date_fns17.format)(new Date(event.start), timeFormat, { locale }), " \u2013 ", event?.end && (0, import_date_fns17.format)(new Date(event.end), timeFormat, { locale }))))
|
|
2577
|
+
), /* @__PURE__ */ import_react16.default.createElement("div", { className: "px-6 pb-6 space-y-4 overflow-y-auto flex-1" }, event?.location && /* @__PURE__ */ import_react16.default.createElement(
|
|
2578
|
+
import_framer_motion2.motion.a,
|
|
1995
2579
|
{
|
|
2580
|
+
href: mapsUrl(event.location),
|
|
2581
|
+
target: "_blank",
|
|
2582
|
+
rel: "noopener noreferrer",
|
|
1996
2583
|
initial: { opacity: 0, y: 10 },
|
|
1997
2584
|
animate: { opacity: 1, y: 0 },
|
|
1998
2585
|
className: "flex items-start gap-3 p-4 rounded-2xl bg-muted/30 border border-border/30 group hover:bg-muted/50 transition-all cursor-pointer"
|
|
1999
2586
|
},
|
|
2000
|
-
/* @__PURE__ */
|
|
2001
|
-
/* @__PURE__ */
|
|
2002
|
-
/* @__PURE__ */
|
|
2003
|
-
), event?.guests && event.guests.length > 0 && /* @__PURE__ */
|
|
2587
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "p-2 bg-primary/10 rounded-xl" }, /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.MapPin, { className: "w-5 h-5 text-primary" })),
|
|
2588
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "flex-1" }, /* @__PURE__ */ import_react16.default.createElement("p", { className: "text-sm font-medium text-foreground" }, event.location), /* @__PURE__ */ import_react16.default.createElement("p", { className: "text-xs text-muted-foreground mt-0.5" }, t.openInMaps)),
|
|
2589
|
+
/* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.ExternalLink, { className: "w-4 h-4 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity" })
|
|
2590
|
+
), event?.guests && event.guests.length > 0 && /* @__PURE__ */ import_react16.default.createElement(
|
|
2004
2591
|
import_framer_motion2.motion.div,
|
|
2005
2592
|
{
|
|
2006
2593
|
initial: { opacity: 0, y: 10 },
|
|
@@ -2008,24 +2595,24 @@ var EventModal = ({
|
|
|
2008
2595
|
transition: { delay: 0.05 },
|
|
2009
2596
|
className: "space-y-3"
|
|
2010
2597
|
},
|
|
2011
|
-
/* @__PURE__ */
|
|
2012
|
-
/* @__PURE__ */
|
|
2598
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.Users, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-sm font-medium text-foreground" }, event.guests.length, " ", event.guests.length > 1 ? t.guests : t.guestSingular))),
|
|
2599
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "flex flex-wrap gap-2" }, event.guests.map((email) => /* @__PURE__ */ import_react16.default.createElement(
|
|
2013
2600
|
"div",
|
|
2014
2601
|
{
|
|
2015
|
-
key:
|
|
2016
|
-
className: "flex items-center gap-2 px-3 py-2 rounded-xl bg-muted/30 border border-border/30
|
|
2602
|
+
key: email,
|
|
2603
|
+
className: "flex items-center gap-2 px-3 py-2 rounded-xl bg-muted/30 border border-border/30"
|
|
2017
2604
|
},
|
|
2018
|
-
/* @__PURE__ */
|
|
2605
|
+
/* @__PURE__ */ import_react16.default.createElement(
|
|
2019
2606
|
"div",
|
|
2020
2607
|
{
|
|
2021
2608
|
className: "w-8 h-8 rounded-full flex items-center justify-center text-sm font-semibold text-white",
|
|
2022
|
-
style: { backgroundColor: `hsl(${
|
|
2609
|
+
style: { backgroundColor: `hsl(${avatarHue(email)}, 70%, 50%)` }
|
|
2023
2610
|
},
|
|
2024
2611
|
email[0].toUpperCase()
|
|
2025
2612
|
),
|
|
2026
|
-
/* @__PURE__ */
|
|
2613
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ import_react16.default.createElement("p", { className: "text-sm font-medium text-foreground" }, email.split("@")[0]), /* @__PURE__ */ import_react16.default.createElement("p", { className: "text-xs text-muted-foreground truncate" }, email))
|
|
2027
2614
|
)))
|
|
2028
|
-
), event?.reminders && event.reminders.length > 0 && /* @__PURE__ */
|
|
2615
|
+
), event?.reminders && event.reminders.length > 0 && /* @__PURE__ */ import_react16.default.createElement(
|
|
2029
2616
|
import_framer_motion2.motion.div,
|
|
2030
2617
|
{
|
|
2031
2618
|
initial: { opacity: 0, y: 10 },
|
|
@@ -2033,16 +2620,16 @@ var EventModal = ({
|
|
|
2033
2620
|
transition: { delay: 0.1 },
|
|
2034
2621
|
className: "flex items-center gap-3"
|
|
2035
2622
|
},
|
|
2036
|
-
/* @__PURE__ */
|
|
2037
|
-
/* @__PURE__ */
|
|
2623
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "p-2 bg-amber-500/10 rounded-xl" }, /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.Bell, { className: "w-4 h-4 text-amber-500" })),
|
|
2624
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "flex flex-wrap gap-2" }, event.reminders.map((reminder) => /* @__PURE__ */ import_react16.default.createElement(
|
|
2038
2625
|
"span",
|
|
2039
2626
|
{
|
|
2040
2627
|
key: reminder.id,
|
|
2041
2628
|
className: "text-xs font-medium px-2.5 py-1 rounded-full bg-amber-500/10 text-amber-600 dark:text-amber-400"
|
|
2042
2629
|
},
|
|
2043
|
-
reminder.label ||
|
|
2630
|
+
reminder.label || reminderLabel(reminder.time, t)
|
|
2044
2631
|
)))
|
|
2045
|
-
), event?.description && /* @__PURE__ */
|
|
2632
|
+
), event?.description && /* @__PURE__ */ import_react16.default.createElement(
|
|
2046
2633
|
import_framer_motion2.motion.div,
|
|
2047
2634
|
{
|
|
2048
2635
|
initial: { opacity: 0, y: 10 },
|
|
@@ -2050,9 +2637,9 @@ var EventModal = ({
|
|
|
2050
2637
|
transition: { delay: 0.15 },
|
|
2051
2638
|
className: "space-y-2"
|
|
2052
2639
|
},
|
|
2053
|
-
/* @__PURE__ */
|
|
2054
|
-
/* @__PURE__ */
|
|
2055
|
-
), event?.attachments && event.attachments.length > 0 && /* @__PURE__ */
|
|
2640
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.AlignLeft, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-sm font-medium text-foreground" }, t.notesLabel)),
|
|
2641
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "text-sm text-foreground/80 whitespace-pre-wrap leading-relaxed pl-6 p-3 rounded-xl bg-muted/20 border border-border/30" }, event.description)
|
|
2642
|
+
), event?.attachments && event.attachments.length > 0 && /* @__PURE__ */ import_react16.default.createElement(
|
|
2056
2643
|
import_framer_motion2.motion.div,
|
|
2057
2644
|
{
|
|
2058
2645
|
initial: { opacity: 0, y: 10 },
|
|
@@ -2060,27 +2647,18 @@ var EventModal = ({
|
|
|
2060
2647
|
transition: { delay: 0.2 },
|
|
2061
2648
|
className: "space-y-2"
|
|
2062
2649
|
},
|
|
2063
|
-
/* @__PURE__ */
|
|
2064
|
-
/* @__PURE__ */
|
|
2065
|
-
"div",
|
|
2066
|
-
{
|
|
2067
|
-
key: att.id,
|
|
2068
|
-
onClick: () => handleDownload(att),
|
|
2069
|
-
className: "flex items-center gap-3 p-3 rounded-xl border border-border/30 bg-muted/20 hover:bg-muted/40 transition-all cursor-pointer group"
|
|
2070
|
-
},
|
|
2071
|
-
/* @__PURE__ */ import_react14.default.createElement("div", { className: "p-2 bg-primary/10 rounded-lg" }, /* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.File, { className: "w-4 h-4 text-primary" })),
|
|
2072
|
-
/* @__PURE__ */ import_react14.default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ import_react14.default.createElement("p", { className: "text-sm font-medium text-foreground truncate" }, att.name), /* @__PURE__ */ import_react14.default.createElement("p", { className: "text-xs text-muted-foreground" }, att.size)),
|
|
2073
|
-
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Download, { className: "w-4 h-4 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity" })
|
|
2074
|
-
)))
|
|
2650
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.Paperclip, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-sm font-medium text-foreground" }, t.attachments)),
|
|
2651
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "grid gap-2" }, event.attachments.map(renderAttachment))
|
|
2075
2652
|
)));
|
|
2076
|
-
const renderEditMode = () => /* @__PURE__ */
|
|
2653
|
+
const renderEditMode = () => /* @__PURE__ */ import_react16.default.createElement("form", { onSubmit: handleSubmit, className: "flex flex-col bg-background overflow-hidden w-full max-h-[85vh]" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center justify-between px-5 py-4 border-b border-border/50 shrink-0" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ import_react16.default.createElement(
|
|
2077
2654
|
"button",
|
|
2078
2655
|
{
|
|
2079
2656
|
type: "button",
|
|
2080
2657
|
onClick: () => setIsColorPickerOpen(!isColorPickerOpen),
|
|
2081
|
-
className: "relative p-1"
|
|
2658
|
+
className: "relative p-1",
|
|
2659
|
+
"aria-label": t.eventColor
|
|
2082
2660
|
},
|
|
2083
|
-
/* @__PURE__ */
|
|
2661
|
+
/* @__PURE__ */ import_react16.default.createElement(
|
|
2084
2662
|
"div",
|
|
2085
2663
|
{
|
|
2086
2664
|
className: "w-5 h-5 rounded-full cursor-pointer hover:scale-110 transition-transform",
|
|
@@ -2090,11 +2668,12 @@ var EventModal = ({
|
|
|
2090
2668
|
}
|
|
2091
2669
|
}
|
|
2092
2670
|
),
|
|
2093
|
-
isColorPickerOpen && /* @__PURE__ */
|
|
2671
|
+
isColorPickerOpen && /* @__PURE__ */ import_react16.default.createElement("div", { className: "absolute top-full left-0 mt-2 p-2 bg-background border border-border rounded-xl shadow-xl z-50 flex flex-wrap gap-1.5 w-[180px]" }, COLOR_PALETTE.map((color) => /* @__PURE__ */ import_react16.default.createElement(
|
|
2094
2672
|
"button",
|
|
2095
2673
|
{
|
|
2096
2674
|
key: color,
|
|
2097
2675
|
type: "button",
|
|
2676
|
+
"aria-label": color,
|
|
2098
2677
|
onClick: () => {
|
|
2099
2678
|
setFormData((prev) => ({ ...prev, color }));
|
|
2100
2679
|
setIsColorPickerOpen(false);
|
|
@@ -2106,15 +2685,16 @@ var EventModal = ({
|
|
|
2106
2685
|
style: { backgroundColor: color, color }
|
|
2107
2686
|
}
|
|
2108
2687
|
)))
|
|
2109
|
-
), /* @__PURE__ */
|
|
2688
|
+
), /* @__PURE__ */ import_react16.default.createElement("h2", { className: "text-lg font-semibold text-foreground" }, mode === "edit" ? t.editEvent : t.newEvent)), /* @__PURE__ */ import_react16.default.createElement(
|
|
2110
2689
|
"button",
|
|
2111
2690
|
{
|
|
2112
2691
|
type: "button",
|
|
2113
2692
|
onClick: onClose,
|
|
2114
|
-
className: "p-2 hover:bg-accent rounded-xl transition-all text-muted-foreground hover:text-foreground"
|
|
2693
|
+
className: "p-2 hover:bg-accent rounded-xl transition-all text-muted-foreground hover:text-foreground",
|
|
2694
|
+
"aria-label": t.close
|
|
2115
2695
|
},
|
|
2116
|
-
/* @__PURE__ */
|
|
2117
|
-
)), /* @__PURE__ */
|
|
2696
|
+
/* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.X, { className: "w-4 h-4" })
|
|
2697
|
+
)), /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex-1 overflow-y-auto" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "px-5 py-4 space-y-5" }, /* @__PURE__ */ import_react16.default.createElement("div", null, /* @__PURE__ */ import_react16.default.createElement(
|
|
2118
2698
|
"input",
|
|
2119
2699
|
{
|
|
2120
2700
|
type: "text",
|
|
@@ -2123,132 +2703,160 @@ var EventModal = ({
|
|
|
2123
2703
|
className: "w-full text-xl font-semibold border-0 border-b-2 border-transparent focus:border-primary bg-transparent px-0 py-2 placeholder-muted-foreground/50 transition-all text-foreground focus:outline-none",
|
|
2124
2704
|
value: formData.title,
|
|
2125
2705
|
onChange: (e) => setFormData({ ...formData, title: e.target.value }),
|
|
2126
|
-
placeholder:
|
|
2706
|
+
placeholder: t.title,
|
|
2707
|
+
"aria-label": t.title
|
|
2127
2708
|
}
|
|
2128
|
-
)), /* @__PURE__ */
|
|
2709
|
+
)), /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center justify-between px-1" }, /* @__PURE__ */ import_react16.default.createElement("span", { id: "calendarkit-all-day-label", className: "text-sm font-medium text-foreground" }, t.allDay), /* @__PURE__ */ import_react16.default.createElement(
|
|
2710
|
+
"button",
|
|
2711
|
+
{
|
|
2712
|
+
type: "button",
|
|
2713
|
+
role: "switch",
|
|
2714
|
+
"aria-checked": !!formData.allDay,
|
|
2715
|
+
"aria-labelledby": "calendarkit-all-day-label",
|
|
2716
|
+
onClick: handleAllDayToggle,
|
|
2717
|
+
className: cn(
|
|
2718
|
+
"relative inline-flex h-6 w-11 shrink-0 rounded-full border-2 border-transparent transition-colors cursor-pointer",
|
|
2719
|
+
formData.allDay ? "bg-primary" : "bg-muted"
|
|
2720
|
+
)
|
|
2721
|
+
},
|
|
2722
|
+
/* @__PURE__ */ import_react16.default.createElement(
|
|
2723
|
+
"span",
|
|
2724
|
+
{
|
|
2725
|
+
className: cn(
|
|
2726
|
+
"pointer-events-none inline-block h-5 w-5 rounded-full bg-background shadow transition-transform",
|
|
2727
|
+
formData.allDay ? "translate-x-5" : "translate-x-0"
|
|
2728
|
+
)
|
|
2729
|
+
}
|
|
2730
|
+
)
|
|
2731
|
+
)), /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-3 p-4 rounded-2xl bg-muted/20 border border-border/30" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "p-2 bg-primary/10 rounded-xl shrink-0" }, /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.Clock, { className: "w-5 h-5 text-primary" })), /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex-1 grid grid-cols-2 gap-3" }, /* @__PURE__ */ import_react16.default.createElement("div", null, /* @__PURE__ */ import_react16.default.createElement("label", { htmlFor: "calendarkit-event-start", className: "text-[10px] font-semibold text-muted-foreground uppercase tracking-wider mb-1 block" }, t.start), /* @__PURE__ */ import_react16.default.createElement(
|
|
2129
2732
|
"input",
|
|
2130
2733
|
{
|
|
2131
|
-
|
|
2734
|
+
id: "calendarkit-event-start",
|
|
2735
|
+
type: allDaySpan ? "date" : "datetime-local",
|
|
2132
2736
|
className: "w-full bg-background border border-border/50 rounded-xl px-3 py-2 text-sm font-medium text-foreground focus:border-primary focus:ring-2 focus:ring-primary/20 transition-all",
|
|
2133
|
-
value: formatDateForInput(formData.start),
|
|
2737
|
+
value: allDaySpan ? (0, import_date_fns17.format)(allDaySpan.firstDay, "yyyy-MM-dd") : formatDateForInput(formData.start),
|
|
2134
2738
|
onChange: (e) => handleDateChange("start", e.target.value)
|
|
2135
2739
|
}
|
|
2136
|
-
)), /* @__PURE__ */
|
|
2740
|
+
)), /* @__PURE__ */ import_react16.default.createElement("div", null, /* @__PURE__ */ import_react16.default.createElement("label", { htmlFor: "calendarkit-event-end", className: "text-[10px] font-semibold text-muted-foreground uppercase tracking-wider mb-1 block" }, t.end), /* @__PURE__ */ import_react16.default.createElement(
|
|
2137
2741
|
"input",
|
|
2138
2742
|
{
|
|
2139
|
-
|
|
2743
|
+
id: "calendarkit-event-end",
|
|
2744
|
+
type: allDaySpan ? "date" : "datetime-local",
|
|
2140
2745
|
className: "w-full bg-background border border-border/50 rounded-xl px-3 py-2 text-sm font-medium text-foreground focus:border-primary focus:ring-2 focus:ring-primary/20 transition-all",
|
|
2141
|
-
value: formatDateForInput(formData.end),
|
|
2746
|
+
value: allDaySpan ? (0, import_date_fns17.format)(allDaySpan.lastDay, "yyyy-MM-dd") : formatDateForInput(formData.end),
|
|
2142
2747
|
onChange: (e) => handleDateChange("end", e.target.value)
|
|
2143
2748
|
}
|
|
2144
|
-
)))), getDurationText() && /* @__PURE__ */
|
|
2749
|
+
)))), getDurationText() && /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex justify-center" }, /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-xs font-medium px-3 py-1 rounded-full bg-primary/10 text-primary" }, getDurationText())), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.Bell, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-sm font-medium text-foreground" }, t.reminders)), /* @__PURE__ */ import_react16.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react16.default.createElement(
|
|
2145
2750
|
"button",
|
|
2146
2751
|
{
|
|
2147
2752
|
type: "button",
|
|
2148
2753
|
onClick: () => setIsReminderDropdownOpen(!isReminderDropdownOpen),
|
|
2149
2754
|
className: "flex items-center gap-1 text-xs font-medium text-primary hover:text-primary/80 transition-colors"
|
|
2150
2755
|
},
|
|
2151
|
-
/* @__PURE__ */
|
|
2152
|
-
|
|
2153
|
-
), isReminderDropdownOpen && /* @__PURE__ */
|
|
2756
|
+
/* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.Plus, { className: "w-3.5 h-3.5" }),
|
|
2757
|
+
t.add
|
|
2758
|
+
), isReminderDropdownOpen && /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsReminderDropdownOpen(false) }), /* @__PURE__ */ import_react16.default.createElement("div", { className: "absolute right-0 top-full mt-1 w-48 bg-background border border-border rounded-xl shadow-xl z-50 py-1 max-h-60 overflow-y-auto" }, REMINDER_OPTIONS.map((minutes) => /* @__PURE__ */ import_react16.default.createElement(
|
|
2154
2759
|
"button",
|
|
2155
2760
|
{
|
|
2156
|
-
key:
|
|
2761
|
+
key: minutes,
|
|
2157
2762
|
type: "button",
|
|
2158
|
-
onClick: () => addReminder(
|
|
2763
|
+
onClick: () => addReminder(minutes),
|
|
2159
2764
|
className: "w-full px-3 py-2 text-left text-sm hover:bg-accent transition-colors"
|
|
2160
2765
|
},
|
|
2161
|
-
|
|
2162
|
-
)))))), formData.reminders && formData.reminders.length > 0 && /* @__PURE__ */
|
|
2766
|
+
reminderLabel(minutes, t)
|
|
2767
|
+
)))))), formData.reminders && formData.reminders.length > 0 && /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex flex-wrap gap-2" }, formData.reminders.map((reminder) => /* @__PURE__ */ import_react16.default.createElement(
|
|
2163
2768
|
"div",
|
|
2164
2769
|
{
|
|
2165
2770
|
key: reminder.id,
|
|
2166
2771
|
className: "flex items-center gap-2 px-3 py-1.5 rounded-full bg-amber-500/10 border border-amber-500/20"
|
|
2167
2772
|
},
|
|
2168
|
-
/* @__PURE__ */
|
|
2169
|
-
/* @__PURE__ */
|
|
2170
|
-
/* @__PURE__ */
|
|
2773
|
+
/* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.BellRing, { className: "w-3.5 h-3.5 text-amber-500" }),
|
|
2774
|
+
/* @__PURE__ */ import_react16.default.createElement("span", { className: "text-xs font-medium text-amber-600 dark:text-amber-400" }, reminder.label || reminderLabel(reminder.time, t)),
|
|
2775
|
+
/* @__PURE__ */ import_react16.default.createElement(
|
|
2171
2776
|
"button",
|
|
2172
2777
|
{
|
|
2173
2778
|
type: "button",
|
|
2174
2779
|
onClick: () => removeReminder(reminder.id),
|
|
2175
|
-
className: "p-0.5 hover:bg-amber-500/20 rounded-full transition-colors"
|
|
2780
|
+
className: "p-0.5 hover:bg-amber-500/20 rounded-full transition-colors",
|
|
2781
|
+
"aria-label": t.removeReminder
|
|
2176
2782
|
},
|
|
2177
|
-
/* @__PURE__ */
|
|
2783
|
+
/* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.X, { className: "w-3 h-3 text-amber-500" })
|
|
2178
2784
|
)
|
|
2179
|
-
)))), /* @__PURE__ */
|
|
2180
|
-
"
|
|
2181
|
-
{
|
|
2182
|
-
type: "button",
|
|
2183
|
-
onClick: () => setIsGuestsDropdownOpen(!isGuestsDropdownOpen),
|
|
2184
|
-
className: "w-full flex items-center justify-between px-4 py-3 bg-muted/20 border border-border/30 rounded-xl text-sm text-left hover:bg-muted/30 transition-all"
|
|
2185
|
-
},
|
|
2186
|
-
/* @__PURE__ */ import_react14.default.createElement("span", { className: selectedGuests.length > 0 ? "text-foreground font-medium" : "text-muted-foreground" }, selectedGuests.length > 0 ? `${selectedGuests.length} guest${selectedGuests.length > 1 ? "s" : ""} added` : "Add guests"),
|
|
2187
|
-
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.ChevronDown, { className: cn("w-4 h-4 text-muted-foreground transition-transform", isGuestsDropdownOpen && "rotate-180") })
|
|
2188
|
-
), isGuestsDropdownOpen && /* @__PURE__ */ import_react14.default.createElement(import_react14.default.Fragment, null, /* @__PURE__ */ import_react14.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsGuestsDropdownOpen(false) }), /* @__PURE__ */ import_react14.default.createElement("div", { className: "absolute z-50 w-full mt-2 bg-background border border-border rounded-xl shadow-xl max-h-48 overflow-y-auto" }, fakeGuests.map((email) => /* @__PURE__ */ import_react14.default.createElement(
|
|
2189
|
-
"div",
|
|
2785
|
+
)))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.Users, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ import_react16.default.createElement("label", { htmlFor: "calendarkit-event-guest", className: "text-sm font-medium text-foreground" }, t.guests)), /* @__PURE__ */ import_react16.default.createElement(
|
|
2786
|
+
"input",
|
|
2190
2787
|
{
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
/* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react14.default.createElement(
|
|
2200
|
-
"div",
|
|
2201
|
-
{
|
|
2202
|
-
className: "w-7 h-7 rounded-full flex items-center justify-center text-xs font-semibold text-white",
|
|
2203
|
-
style: { backgroundColor: `hsl(${fakeGuests.indexOf(email) * 60}, 70%, 50%)` }
|
|
2788
|
+
id: "calendarkit-event-guest",
|
|
2789
|
+
type: "text",
|
|
2790
|
+
inputMode: "email",
|
|
2791
|
+
autoComplete: "email",
|
|
2792
|
+
value: guestInput,
|
|
2793
|
+
onChange: (e) => {
|
|
2794
|
+
setGuestInput(e.target.value);
|
|
2795
|
+
setGuestError(false);
|
|
2204
2796
|
},
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2797
|
+
onKeyDown: (e) => {
|
|
2798
|
+
if (e.key === "Enter" || e.key === ",") {
|
|
2799
|
+
e.preventDefault();
|
|
2800
|
+
addGuests(guestInput);
|
|
2801
|
+
}
|
|
2802
|
+
},
|
|
2803
|
+
onBlur: () => guestInput.trim() && addGuests(guestInput),
|
|
2804
|
+
placeholder: t.addGuestPlaceholder,
|
|
2805
|
+
"aria-invalid": guestError,
|
|
2806
|
+
className: cn(
|
|
2807
|
+
"w-full px-4 py-3 bg-muted/20 border rounded-xl text-sm text-foreground placeholder-muted-foreground focus:outline-none focus:border-primary transition-all",
|
|
2808
|
+
guestError ? "border-destructive" : "border-border/30"
|
|
2809
|
+
)
|
|
2810
|
+
}
|
|
2811
|
+
), guestError && /* @__PURE__ */ import_react16.default.createElement("p", { role: "alert", className: "text-xs text-destructive" }, t.invalidEmail), guests.length > 0 && /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex flex-wrap gap-2 mt-2" }, guests.map((email) => /* @__PURE__ */ import_react16.default.createElement(
|
|
2208
2812
|
"div",
|
|
2209
2813
|
{
|
|
2210
2814
|
key: email,
|
|
2211
2815
|
className: "flex items-center gap-2 pl-1 pr-2 py-1 bg-muted/30 border border-border/30 rounded-full"
|
|
2212
2816
|
},
|
|
2213
|
-
/* @__PURE__ */
|
|
2817
|
+
/* @__PURE__ */ import_react16.default.createElement(
|
|
2214
2818
|
"div",
|
|
2215
2819
|
{
|
|
2216
2820
|
className: "w-6 h-6 rounded-full flex items-center justify-center text-xs font-semibold text-white",
|
|
2217
|
-
style: { backgroundColor: `hsl(${
|
|
2821
|
+
style: { backgroundColor: `hsl(${avatarHue(email)}, 70%, 50%)` }
|
|
2218
2822
|
},
|
|
2219
2823
|
email[0].toUpperCase()
|
|
2220
2824
|
),
|
|
2221
|
-
/* @__PURE__ */
|
|
2222
|
-
/* @__PURE__ */
|
|
2825
|
+
/* @__PURE__ */ import_react16.default.createElement("span", { className: "text-xs font-medium text-foreground" }, email),
|
|
2826
|
+
/* @__PURE__ */ import_react16.default.createElement(
|
|
2223
2827
|
"button",
|
|
2224
2828
|
{
|
|
2225
2829
|
type: "button",
|
|
2226
|
-
onClick: () =>
|
|
2227
|
-
className: "p-0.5 hover:bg-destructive/10 rounded-full transition-colors"
|
|
2830
|
+
onClick: () => removeGuest(email),
|
|
2831
|
+
className: "p-0.5 hover:bg-destructive/10 rounded-full transition-colors",
|
|
2832
|
+
"aria-label": interpolate(t.removeGuest, { email })
|
|
2228
2833
|
},
|
|
2229
|
-
/* @__PURE__ */
|
|
2834
|
+
/* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.X, { className: "w-3 h-3 text-muted-foreground" })
|
|
2230
2835
|
)
|
|
2231
|
-
)))), /* @__PURE__ */
|
|
2836
|
+
)))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-3 p-3 rounded-xl bg-muted/20 border border-border/30" }, /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.MapPin, { className: "w-5 h-5 text-muted-foreground shrink-0" }), /* @__PURE__ */ import_react16.default.createElement(
|
|
2232
2837
|
"input",
|
|
2233
2838
|
{
|
|
2234
2839
|
type: "text",
|
|
2235
2840
|
className: "flex-1 bg-transparent text-sm text-foreground placeholder-muted-foreground focus:outline-none",
|
|
2236
|
-
placeholder:
|
|
2841
|
+
placeholder: t.addLocation,
|
|
2842
|
+
"aria-label": t.addLocation,
|
|
2237
2843
|
value: formData.location || "",
|
|
2238
2844
|
onChange: (e) => setFormData({ ...formData, location: e.target.value })
|
|
2239
2845
|
}
|
|
2240
|
-
)), /* @__PURE__ */
|
|
2846
|
+
)), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.AlignLeft, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-sm font-medium text-foreground" }, t.notesLabel)), /* @__PURE__ */ import_react16.default.createElement(
|
|
2241
2847
|
"textarea",
|
|
2242
2848
|
{
|
|
2243
2849
|
className: "w-full bg-muted/20 border border-border/30 rounded-xl px-4 py-3 text-sm min-h-[100px] resize-none text-foreground placeholder-muted-foreground focus:border-primary focus:ring-2 focus:ring-primary/20 transition-all",
|
|
2244
|
-
placeholder:
|
|
2850
|
+
placeholder: t.addNotes,
|
|
2851
|
+
"aria-label": t.notesLabel,
|
|
2245
2852
|
value: formData.description || "",
|
|
2246
2853
|
onChange: (e) => setFormData({ ...formData, description: e.target.value })
|
|
2247
2854
|
}
|
|
2248
|
-
)), /* @__PURE__ */
|
|
2855
|
+
)), /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-3 p-3 rounded-xl bg-muted/20 border border-border/30" }, /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.Repeat, { className: "w-5 h-5 text-muted-foreground shrink-0" }), /* @__PURE__ */ import_react16.default.createElement(
|
|
2249
2856
|
"select",
|
|
2250
2857
|
{
|
|
2251
2858
|
className: "flex-1 bg-transparent text-sm text-foreground focus:outline-none cursor-pointer",
|
|
2859
|
+
"aria-label": t.repeat,
|
|
2252
2860
|
value: formData.recurrence?.freq || "",
|
|
2253
2861
|
onChange: (e) => {
|
|
2254
2862
|
if (e.target.value === "") {
|
|
@@ -2264,28 +2872,28 @@ var EventModal = ({
|
|
|
2264
2872
|
}
|
|
2265
2873
|
}
|
|
2266
2874
|
},
|
|
2267
|
-
/* @__PURE__ */
|
|
2268
|
-
/* @__PURE__ */
|
|
2269
|
-
/* @__PURE__ */
|
|
2270
|
-
/* @__PURE__ */
|
|
2271
|
-
/* @__PURE__ */
|
|
2272
|
-
)), /* @__PURE__ */
|
|
2875
|
+
/* @__PURE__ */ import_react16.default.createElement("option", { value: "" }, t.doesNotRepeat),
|
|
2876
|
+
/* @__PURE__ */ import_react16.default.createElement("option", { value: "DAILY" }, t.daily),
|
|
2877
|
+
/* @__PURE__ */ import_react16.default.createElement("option", { value: "WEEKLY" }, t.weekly),
|
|
2878
|
+
/* @__PURE__ */ import_react16.default.createElement("option", { value: "MONTHLY" }, t.monthly),
|
|
2879
|
+
/* @__PURE__ */ import_react16.default.createElement("option", { value: "YEARLY" }, t.yearly)
|
|
2880
|
+
)), calendars && calendars.length > 0 && /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center justify-between p-3 rounded-xl bg-muted/20 border border-border/30" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.Tag, { className: "w-5 h-5 text-muted-foreground" }), /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-sm text-foreground" }, t.calendar)), /* @__PURE__ */ import_react16.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react16.default.createElement(
|
|
2273
2881
|
"button",
|
|
2274
2882
|
{
|
|
2275
2883
|
type: "button",
|
|
2276
2884
|
onClick: () => setIsCalendarDropdownOpen(!isCalendarDropdownOpen),
|
|
2277
2885
|
className: "flex items-center gap-2 px-3 py-1.5 bg-background border border-border/50 rounded-lg text-sm hover:bg-accent/50 transition-all"
|
|
2278
2886
|
},
|
|
2279
|
-
/* @__PURE__ */
|
|
2887
|
+
/* @__PURE__ */ import_react16.default.createElement(
|
|
2280
2888
|
"div",
|
|
2281
2889
|
{
|
|
2282
2890
|
className: "w-3 h-3 rounded-full",
|
|
2283
|
-
style: { backgroundColor: calendars
|
|
2891
|
+
style: { backgroundColor: calendars.find((c) => c.id === formData.calendarId)?.color || "#3b82f6" }
|
|
2284
2892
|
}
|
|
2285
2893
|
),
|
|
2286
|
-
/* @__PURE__ */
|
|
2287
|
-
/* @__PURE__ */
|
|
2288
|
-
), isCalendarDropdownOpen && /* @__PURE__ */
|
|
2894
|
+
/* @__PURE__ */ import_react16.default.createElement("span", { className: "font-medium" }, calendars.find((c) => c.id === formData.calendarId)?.label || t.select),
|
|
2895
|
+
/* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.ChevronDown, { className: "w-3.5 h-3.5 text-muted-foreground" })
|
|
2896
|
+
), isCalendarDropdownOpen && /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsCalendarDropdownOpen(false) }), /* @__PURE__ */ import_react16.default.createElement("div", { className: "absolute right-0 bottom-full mb-2 w-48 bg-background border border-border rounded-xl shadow-xl z-50 py-1" }, calendars.map((cal) => /* @__PURE__ */ import_react16.default.createElement(
|
|
2289
2897
|
"button",
|
|
2290
2898
|
{
|
|
2291
2899
|
key: cal.id,
|
|
@@ -2300,35 +2908,35 @@ var EventModal = ({
|
|
|
2300
2908
|
setIsCalendarDropdownOpen(false);
|
|
2301
2909
|
}
|
|
2302
2910
|
},
|
|
2303
|
-
/* @__PURE__ */
|
|
2304
|
-
/* @__PURE__ */
|
|
2305
|
-
formData.calendarId === cal.id && /* @__PURE__ */
|
|
2306
|
-
)))))))), /* @__PURE__ */
|
|
2911
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "w-3 h-3 rounded-full", style: { backgroundColor: cal.color } }),
|
|
2912
|
+
/* @__PURE__ */ import_react16.default.createElement("span", { className: "flex-1 text-sm" }, cal.label),
|
|
2913
|
+
formData.calendarId === cal.id && /* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.Check, { className: "w-4 h-4 text-primary" })
|
|
2914
|
+
)))))))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "px-5 py-4 border-t border-border/50 flex items-center justify-between bg-muted/10 shrink-0" }, mode === "edit" && /* @__PURE__ */ import_react16.default.createElement(
|
|
2307
2915
|
"button",
|
|
2308
2916
|
{
|
|
2309
2917
|
type: "button",
|
|
2310
2918
|
onClick: handleDelete,
|
|
2311
2919
|
className: "flex items-center gap-2 px-4 py-2 text-destructive hover:bg-destructive/10 rounded-xl transition-all text-sm font-medium"
|
|
2312
2920
|
},
|
|
2313
|
-
/* @__PURE__ */
|
|
2314
|
-
|
|
2315
|
-
), mode === "create" && /* @__PURE__ */
|
|
2921
|
+
/* @__PURE__ */ import_react16.default.createElement(import_lucide_react7.Trash2, { className: "w-4 h-4" }),
|
|
2922
|
+
t.delete
|
|
2923
|
+
), mode === "create" && /* @__PURE__ */ import_react16.default.createElement("div", null), /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react16.default.createElement(
|
|
2316
2924
|
"button",
|
|
2317
2925
|
{
|
|
2318
2926
|
type: "button",
|
|
2319
2927
|
onClick: onClose,
|
|
2320
2928
|
className: "px-4 py-2.5 text-muted-foreground hover:text-foreground font-medium text-sm rounded-xl transition-all hover:bg-accent"
|
|
2321
2929
|
},
|
|
2322
|
-
|
|
2323
|
-
), /* @__PURE__ */
|
|
2930
|
+
t.cancel
|
|
2931
|
+
), /* @__PURE__ */ import_react16.default.createElement(
|
|
2324
2932
|
"button",
|
|
2325
2933
|
{
|
|
2326
2934
|
type: "submit",
|
|
2327
2935
|
className: "px-6 py-2.5 bg-primary hover:bg-primary/90 text-primary-foreground font-semibold text-sm rounded-xl shadow-md transition-all hover:shadow-lg hover:shadow-primary/20 active:scale-95"
|
|
2328
2936
|
},
|
|
2329
|
-
mode === "edit" ?
|
|
2937
|
+
mode === "edit" ? t.saveChanges : t.createEvent
|
|
2330
2938
|
))));
|
|
2331
|
-
return /* @__PURE__ */
|
|
2939
|
+
return /* @__PURE__ */ import_react16.default.createElement(Modal, { isOpen, onClose, hideHeader: true, className: "p-0 overflow-hidden max-w-lg rounded-2xl shadow-2xl" }, /* @__PURE__ */ import_react16.default.createElement(import_framer_motion2.AnimatePresence, { mode: "wait" }, mode === "view" && event ? /* @__PURE__ */ import_react16.default.createElement(
|
|
2332
2940
|
import_framer_motion2.motion.div,
|
|
2333
2941
|
{
|
|
2334
2942
|
key: "view",
|
|
@@ -2338,7 +2946,7 @@ var EventModal = ({
|
|
|
2338
2946
|
transition: { duration: 0.15 }
|
|
2339
2947
|
},
|
|
2340
2948
|
renderViewMode()
|
|
2341
|
-
) : /* @__PURE__ */
|
|
2949
|
+
) : /* @__PURE__ */ import_react16.default.createElement(
|
|
2342
2950
|
import_framer_motion2.motion.div,
|
|
2343
2951
|
{
|
|
2344
2952
|
key: "edit",
|
|
@@ -2352,10 +2960,10 @@ var EventModal = ({
|
|
|
2352
2960
|
};
|
|
2353
2961
|
|
|
2354
2962
|
// src/components/Skeleton.tsx
|
|
2355
|
-
var
|
|
2356
|
-
var Skeleton = ({ className, style }) => /* @__PURE__ */
|
|
2357
|
-
var MonthViewSkeleton = () => /* @__PURE__ */
|
|
2358
|
-
var WeekViewSkeleton = () => /* @__PURE__ */
|
|
2963
|
+
var import_react17 = __toESM(require("react"));
|
|
2964
|
+
var Skeleton = ({ className, style }) => /* @__PURE__ */ import_react17.default.createElement("div", { className: cn("animate-pulse bg-muted/40 rounded", className), style });
|
|
2965
|
+
var MonthViewSkeleton = () => /* @__PURE__ */ import_react17.default.createElement("div", { className: "h-full bg-background border border-border/50 rounded-2xl overflow-hidden" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "grid grid-cols-7 border-b border-border/50 bg-muted/10" }, Array.from({ length: 7 }).map((_, i) => /* @__PURE__ */ import_react17.default.createElement("div", { key: i, className: "py-3 px-2 text-center border-r border-border/30 last:border-r-0" }, /* @__PURE__ */ import_react17.default.createElement(Skeleton, { className: "h-4 w-8 mx-auto" })))), /* @__PURE__ */ import_react17.default.createElement("div", { className: "grid grid-cols-7 flex-1" }, Array.from({ length: 35 }).map((_, i) => /* @__PURE__ */ import_react17.default.createElement("div", { key: i, className: "min-h-[120px] border-r border-b border-border/30 p-2" }, /* @__PURE__ */ import_react17.default.createElement(Skeleton, { className: "h-4 w-6 mb-2" }), /* @__PURE__ */ import_react17.default.createElement("div", { className: "space-y-1" }, i * 7 % 10 > 4 && /* @__PURE__ */ import_react17.default.createElement(Skeleton, { className: "h-5 w-full rounded-md" }), i * 3 % 10 > 6 && /* @__PURE__ */ import_react17.default.createElement(Skeleton, { className: "h-5 w-3/4 rounded-md" }))))));
|
|
2966
|
+
var WeekViewSkeleton = () => /* @__PURE__ */ import_react17.default.createElement("div", { className: "h-full bg-background border border-border/50 rounded-2xl overflow-hidden" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex border-b border-border/50 bg-muted/10" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "w-16 p-3 border-r border-border/30" }, /* @__PURE__ */ import_react17.default.createElement(Skeleton, { className: "h-8 w-10 mx-auto" })), /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex-1 grid grid-cols-7" }, Array.from({ length: 7 }).map((_, i) => /* @__PURE__ */ import_react17.default.createElement("div", { key: i, className: "py-3 px-2 text-center border-r border-border/30 last:border-r-0" }, /* @__PURE__ */ import_react17.default.createElement(Skeleton, { className: "h-3 w-8 mx-auto mb-1" }), /* @__PURE__ */ import_react17.default.createElement(Skeleton, { className: "h-8 w-8 mx-auto rounded-xl" }))))), /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex flex-1", style: { height: "600px" } }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "w-16 border-r border-border/30" }, Array.from({ length: 10 }).map((_, i) => /* @__PURE__ */ import_react17.default.createElement("div", { key: i, className: "h-[60px] relative" }, /* @__PURE__ */ import_react17.default.createElement(Skeleton, { className: "h-4 w-10 absolute right-2 -translate-y-1/2" })))), /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex-1 grid grid-cols-7 relative" }, Array.from({ length: 7 }).map((_, colIdx) => /* @__PURE__ */ import_react17.default.createElement("div", { key: colIdx, className: "relative border-r border-border/30 last:border-r-0" }, Array.from({ length: 10 }).map((_2, rowIdx) => /* @__PURE__ */ import_react17.default.createElement("div", { key: rowIdx, className: "h-[60px] border-b border-dashed border-border/20" })), Math.random() > 0.3 && /* @__PURE__ */ import_react17.default.createElement(
|
|
2359
2967
|
Skeleton,
|
|
2360
2968
|
{
|
|
2361
2969
|
className: "absolute rounded-md",
|
|
@@ -2367,23 +2975,23 @@ var WeekViewSkeleton = () => /* @__PURE__ */ import_react15.default.createElemen
|
|
|
2367
2975
|
}
|
|
2368
2976
|
}
|
|
2369
2977
|
))))));
|
|
2370
|
-
var DayViewSkeleton = () => /* @__PURE__ */
|
|
2978
|
+
var DayViewSkeleton = () => /* @__PURE__ */ import_react17.default.createElement("div", { className: "h-full bg-background border border-border/50 rounded-2xl overflow-hidden" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "px-6 py-4 border-b border-border/50 bg-muted/10 text-center" }, /* @__PURE__ */ import_react17.default.createElement(Skeleton, { className: "h-7 w-64 mx-auto" })), /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex flex-1", style: { height: "600px" } }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "w-20 border-r border-border/30 bg-muted/5" }, Array.from({ length: 10 }).map((_, i) => /* @__PURE__ */ import_react17.default.createElement("div", { key: i, className: "h-[80px] relative" }, /* @__PURE__ */ import_react17.default.createElement(Skeleton, { className: "h-4 w-12 absolute left-1/2 -translate-x-1/2 -translate-y-1/2" })))), /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex-1 relative" }, Array.from({ length: 10 }).map((_, i) => /* @__PURE__ */ import_react17.default.createElement("div", { key: i, className: "h-[80px] border-b border-dashed border-border/20" })), /* @__PURE__ */ import_react17.default.createElement(
|
|
2371
2979
|
Skeleton,
|
|
2372
2980
|
{
|
|
2373
2981
|
className: "absolute rounded-lg left-4 right-4",
|
|
2374
2982
|
style: { top: "160px", height: "120px" }
|
|
2375
2983
|
}
|
|
2376
|
-
), /* @__PURE__ */
|
|
2984
|
+
), /* @__PURE__ */ import_react17.default.createElement(
|
|
2377
2985
|
Skeleton,
|
|
2378
2986
|
{
|
|
2379
2987
|
className: "absolute rounded-lg left-4 right-4",
|
|
2380
2988
|
style: { top: "400px", height: "80px" }
|
|
2381
2989
|
}
|
|
2382
2990
|
))));
|
|
2383
|
-
var AgendaViewSkeleton = () => /* @__PURE__ */
|
|
2991
|
+
var AgendaViewSkeleton = () => /* @__PURE__ */ import_react17.default.createElement("div", { className: "h-full bg-background border border-border/50 rounded-2xl overflow-hidden p-6" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "space-y-6" }, Array.from({ length: 4 }).map((_, dayIdx) => /* @__PURE__ */ import_react17.default.createElement("div", { key: dayIdx }, /* @__PURE__ */ import_react17.default.createElement(Skeleton, { className: "h-5 w-40 mb-4" }), /* @__PURE__ */ import_react17.default.createElement("div", { className: "space-y-3" }, Array.from({ length: 2 + Math.floor(Math.random() * 3) }).map((_2, eventIdx) => /* @__PURE__ */ import_react17.default.createElement("div", { key: eventIdx, className: "flex items-center gap-4 p-3 rounded-xl bg-muted/10" }, /* @__PURE__ */ import_react17.default.createElement(Skeleton, { className: "h-10 w-10 rounded-lg" }), /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex-1 space-y-2" }, /* @__PURE__ */ import_react17.default.createElement(Skeleton, { className: "h-4 w-3/4" }), /* @__PURE__ */ import_react17.default.createElement(Skeleton, { className: "h-3 w-1/2" })))))))));
|
|
2384
2992
|
|
|
2385
2993
|
// src/components/ContextMenu.tsx
|
|
2386
|
-
var
|
|
2994
|
+
var import_react18 = __toESM(require("react"));
|
|
2387
2995
|
var import_lucide_react8 = require("lucide-react");
|
|
2388
2996
|
var import_framer_motion3 = require("framer-motion");
|
|
2389
2997
|
var EventContextMenu = ({
|
|
@@ -2396,8 +3004,8 @@ var EventContextMenu = ({
|
|
|
2396
3004
|
customActions = [],
|
|
2397
3005
|
translations
|
|
2398
3006
|
}) => {
|
|
2399
|
-
const menuRef = (0,
|
|
2400
|
-
(0,
|
|
3007
|
+
const menuRef = (0, import_react18.useRef)(null);
|
|
3008
|
+
(0, import_react18.useEffect)(() => {
|
|
2401
3009
|
const handleKeyDown = (e) => {
|
|
2402
3010
|
if (e.key === "Escape") {
|
|
2403
3011
|
onClose();
|
|
@@ -2408,7 +3016,7 @@ var EventContextMenu = ({
|
|
|
2408
3016
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
2409
3017
|
}
|
|
2410
3018
|
}, [position, onClose]);
|
|
2411
|
-
(0,
|
|
3019
|
+
(0, import_react18.useEffect)(() => {
|
|
2412
3020
|
const handleClickOutside = (e) => {
|
|
2413
3021
|
if (menuRef.current && !menuRef.current.contains(e.target)) {
|
|
2414
3022
|
onClose();
|
|
@@ -2426,7 +3034,7 @@ var EventContextMenu = ({
|
|
|
2426
3034
|
...onEdit ? [{
|
|
2427
3035
|
id: "edit",
|
|
2428
3036
|
label: translations?.edit || "Edit",
|
|
2429
|
-
icon: /* @__PURE__ */
|
|
3037
|
+
icon: /* @__PURE__ */ import_react18.default.createElement(import_lucide_react8.Edit3, { className: "w-4 h-4" }),
|
|
2430
3038
|
onClick: () => {
|
|
2431
3039
|
onEdit(event);
|
|
2432
3040
|
onClose();
|
|
@@ -2435,7 +3043,7 @@ var EventContextMenu = ({
|
|
|
2435
3043
|
...onDuplicate ? [{
|
|
2436
3044
|
id: "duplicate",
|
|
2437
3045
|
label: translations?.duplicate || "Duplicate",
|
|
2438
|
-
icon: /* @__PURE__ */
|
|
3046
|
+
icon: /* @__PURE__ */ import_react18.default.createElement(import_lucide_react8.Copy, { className: "w-4 h-4" }),
|
|
2439
3047
|
onClick: () => {
|
|
2440
3048
|
onDuplicate(event);
|
|
2441
3049
|
onClose();
|
|
@@ -2445,7 +3053,7 @@ var EventContextMenu = ({
|
|
|
2445
3053
|
...onDelete ? [{
|
|
2446
3054
|
id: "delete",
|
|
2447
3055
|
label: translations?.delete || "Delete",
|
|
2448
|
-
icon: /* @__PURE__ */
|
|
3056
|
+
icon: /* @__PURE__ */ import_react18.default.createElement(import_lucide_react8.Trash2, { className: "w-4 h-4" }),
|
|
2449
3057
|
onClick: () => {
|
|
2450
3058
|
onDelete(event.id);
|
|
2451
3059
|
onClose();
|
|
@@ -2457,7 +3065,7 @@ var EventContextMenu = ({
|
|
|
2457
3065
|
x: Math.min(position.x, window.innerWidth - 200),
|
|
2458
3066
|
y: Math.min(position.y, window.innerHeight - (actions.length * 44 + 80))
|
|
2459
3067
|
};
|
|
2460
|
-
return /* @__PURE__ */
|
|
3068
|
+
return /* @__PURE__ */ import_react18.default.createElement(import_framer_motion3.AnimatePresence, null, /* @__PURE__ */ import_react18.default.createElement(
|
|
2461
3069
|
import_framer_motion3.motion.div,
|
|
2462
3070
|
{
|
|
2463
3071
|
ref: menuRef,
|
|
@@ -2471,14 +3079,14 @@ var EventContextMenu = ({
|
|
|
2471
3079
|
top: adjustedPosition.y
|
|
2472
3080
|
}
|
|
2473
3081
|
},
|
|
2474
|
-
/* @__PURE__ */
|
|
3082
|
+
/* @__PURE__ */ import_react18.default.createElement("div", { className: "px-3 py-2 border-b-[0.5px] border-border bg-muted/30" }, /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react18.default.createElement(
|
|
2475
3083
|
"div",
|
|
2476
3084
|
{
|
|
2477
3085
|
className: "w-2.5 h-2.5 rounded-full shrink-0",
|
|
2478
3086
|
style: { backgroundColor: event.color || "var(--primary)" }
|
|
2479
3087
|
}
|
|
2480
|
-
), /* @__PURE__ */
|
|
2481
|
-
/* @__PURE__ */
|
|
3088
|
+
), /* @__PURE__ */ import_react18.default.createElement("span", { className: "text-sm font-medium truncate text-foreground" }, event.title))),
|
|
3089
|
+
/* @__PURE__ */ import_react18.default.createElement("div", { className: "py-1" }, actions.map((action, index) => /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, { key: action.id }, index > 0 && action.variant === "danger" && /* @__PURE__ */ import_react18.default.createElement("div", { className: "h-px bg-border my-1" }), /* @__PURE__ */ import_react18.default.createElement(
|
|
2482
3090
|
"button",
|
|
2483
3091
|
{
|
|
2484
3092
|
onClick: action.onClick,
|
|
@@ -2490,13 +3098,13 @@ var EventContextMenu = ({
|
|
|
2490
3098
|
)
|
|
2491
3099
|
},
|
|
2492
3100
|
action.icon,
|
|
2493
|
-
/* @__PURE__ */
|
|
3101
|
+
/* @__PURE__ */ import_react18.default.createElement("span", null, action.label)
|
|
2494
3102
|
))))
|
|
2495
3103
|
));
|
|
2496
3104
|
};
|
|
2497
3105
|
var useEventContextMenu = () => {
|
|
2498
|
-
const [contextMenu, setContextMenu] = (0,
|
|
2499
|
-
const openContextMenu = (0,
|
|
3106
|
+
const [contextMenu, setContextMenu] = (0, import_react18.useState)({ event: null, position: null });
|
|
3107
|
+
const openContextMenu = (0, import_react18.useCallback)((event, e) => {
|
|
2500
3108
|
e.preventDefault();
|
|
2501
3109
|
e.stopPropagation();
|
|
2502
3110
|
setContextMenu({
|
|
@@ -2504,7 +3112,7 @@ var useEventContextMenu = () => {
|
|
|
2504
3112
|
position: { x: e.clientX, y: e.clientY }
|
|
2505
3113
|
});
|
|
2506
3114
|
}, []);
|
|
2507
|
-
const closeContextMenu = (0,
|
|
3115
|
+
const closeContextMenu = (0, import_react18.useCallback)(() => {
|
|
2508
3116
|
setContextMenu({ event: null, position: null });
|
|
2509
3117
|
}, []);
|
|
2510
3118
|
return {
|
|
@@ -2595,11 +3203,11 @@ function getThemeStyles(theme) {
|
|
|
2595
3203
|
}
|
|
2596
3204
|
|
|
2597
3205
|
// src/hooks/useCalendarLogic.ts
|
|
2598
|
-
var
|
|
2599
|
-
var
|
|
3206
|
+
var import_react20 = require("react");
|
|
3207
|
+
var import_date_fns19 = require("date-fns");
|
|
2600
3208
|
|
|
2601
3209
|
// src/core/recurrence.ts
|
|
2602
|
-
var
|
|
3210
|
+
var import_date_fns18 = require("date-fns");
|
|
2603
3211
|
var import_rrule = require("rrule");
|
|
2604
3212
|
var WEEKDAYS = [import_rrule.RRule.MO, import_rrule.RRule.TU, import_rrule.RRule.WE, import_rrule.RRule.TH, import_rrule.RRule.FR, import_rrule.RRule.SA, import_rrule.RRule.SU];
|
|
2605
3213
|
var toFloating = (instant, tz) => {
|
|
@@ -2638,7 +3246,7 @@ function occurrencesInMonth(event, monthStart, tz) {
|
|
|
2638
3246
|
const excluded = new Set((event.recurrence.exdates ?? []).map(minuteKey));
|
|
2639
3247
|
const duration = event.end.getTime() - event.start.getTime();
|
|
2640
3248
|
const from = toFloating(monthStart, tz);
|
|
2641
|
-
const to = toFloating((0,
|
|
3249
|
+
const to = toFloating((0, import_date_fns18.addMonths)(monthStart, 1), tz);
|
|
2642
3250
|
const result = [];
|
|
2643
3251
|
for (const floating of rule.between(from, to, true)) {
|
|
2644
3252
|
if (floating.getTime() === to.getTime()) continue;
|
|
@@ -2676,16 +3284,18 @@ function cachedMonth(event, monthStart, tz) {
|
|
|
2676
3284
|
}
|
|
2677
3285
|
function expandRecurrences(events, range, anchorTz) {
|
|
2678
3286
|
const result = [];
|
|
2679
|
-
const firstMonth = (0, import_date_fns14.startOfMonth)(toDisplay(range.start, anchorTz));
|
|
2680
|
-
const lastMonth = (0, import_date_fns14.startOfMonth)(toDisplay(range.end, anchorTz));
|
|
2681
3287
|
for (const event of events) {
|
|
2682
3288
|
if (!event.recurrence) {
|
|
2683
3289
|
result.push(event);
|
|
2684
3290
|
continue;
|
|
2685
3291
|
}
|
|
3292
|
+
const tz = event.allDay ? void 0 : anchorTz;
|
|
3293
|
+
const lastMonth = (0, import_date_fns18.startOfMonth)(toDisplay(range.end, tz));
|
|
3294
|
+
const duration = event.end.getTime() - event.start.getTime();
|
|
3295
|
+
const firstMonth = (0, import_date_fns18.startOfMonth)(toDisplay(new Date(range.start.getTime() - duration), tz));
|
|
2686
3296
|
try {
|
|
2687
|
-
for (let month = firstMonth; month <= lastMonth; month = (0,
|
|
2688
|
-
for (const occurrence of cachedMonth(event, fromDisplay(month,
|
|
3297
|
+
for (let month = firstMonth; month <= lastMonth; month = (0, import_date_fns18.addMonths)(month, 1)) {
|
|
3298
|
+
for (const occurrence of cachedMonth(event, fromDisplay(month, tz), tz)) {
|
|
2689
3299
|
if (occurrence.end >= range.start && occurrence.start <= range.end) result.push(occurrence);
|
|
2690
3300
|
}
|
|
2691
3301
|
}
|
|
@@ -2701,8 +3311,8 @@ function stripOccurrenceFields(event) {
|
|
|
2701
3311
|
return rest;
|
|
2702
3312
|
}
|
|
2703
3313
|
var shiftFloating = (instant, deltaMs, tz) => fromFloating(new Date(toFloating(instant, tz).getTime() + deltaMs), tz);
|
|
2704
|
-
var
|
|
2705
|
-
var floatingDay = (floating) => Math.floor(floating.getTime() /
|
|
3314
|
+
var DAY_MS2 = 24 * 60 * 60 * 1e3;
|
|
3315
|
+
var floatingDay = (floating) => Math.floor(floating.getTime() / DAY_MS2);
|
|
2706
3316
|
function shiftSeries(master, occurrence, newStart, newEnd, anchorTz) {
|
|
2707
3317
|
const fromFloat = toFloating(occurrence.start, anchorTz);
|
|
2708
3318
|
const toFloat = toFloating(newStart, anchorTz);
|
|
@@ -2713,6 +3323,7 @@ function shiftSeries(master, occurrence, newStart, newEnd, anchorTz) {
|
|
|
2713
3323
|
const recurrence = master.recurrence && {
|
|
2714
3324
|
...master.recurrence,
|
|
2715
3325
|
byweekday: master.recurrence.byweekday && dayDelta % 7 !== 0 ? master.recurrence.byweekday.map((d) => ((d + dayDelta) % 7 + 7) % 7) : master.recurrence.byweekday,
|
|
3326
|
+
until: master.recurrence.until && shiftFloating(master.recurrence.until, deltaMs, anchorTz),
|
|
2716
3327
|
exdates: master.recurrence.exdates?.map((d) => shiftFloating(d, deltaMs, anchorTz))
|
|
2717
3328
|
};
|
|
2718
3329
|
return stripOccurrenceFields({ ...master, start, end, recurrence });
|
|
@@ -2723,21 +3334,23 @@ function excludeOccurrence(master, occurrenceStart) {
|
|
|
2723
3334
|
}
|
|
2724
3335
|
|
|
2725
3336
|
// src/hooks/useStableCallback.ts
|
|
2726
|
-
var
|
|
3337
|
+
var import_react19 = require("react");
|
|
2727
3338
|
function useStableCallback(fn) {
|
|
2728
|
-
const ref = (0,
|
|
2729
|
-
|
|
2730
|
-
|
|
3339
|
+
const ref = (0, import_react19.useRef)(fn);
|
|
3340
|
+
(0, import_react19.useInsertionEffect)(() => {
|
|
3341
|
+
ref.current = fn;
|
|
3342
|
+
});
|
|
3343
|
+
return (0, import_react19.useCallback)((...args) => ref.current(...args), []);
|
|
2731
3344
|
}
|
|
2732
3345
|
|
|
2733
3346
|
// src/hooks/useCalendarLogic.ts
|
|
2734
3347
|
function expansionRange(monthStart) {
|
|
2735
3348
|
return {
|
|
2736
|
-
start: (0,
|
|
2737
|
-
end: (0,
|
|
3349
|
+
start: (0, import_date_fns19.startOfWeek)((0, import_date_fns19.startOfMonth)((0, import_date_fns19.subMonths)(monthStart, 1))),
|
|
3350
|
+
end: (0, import_date_fns19.addDays)((0, import_date_fns19.endOfMonth)((0, import_date_fns19.addMonths)(monthStart, 1)), 37)
|
|
2738
3351
|
};
|
|
2739
3352
|
}
|
|
2740
|
-
var
|
|
3353
|
+
var DAY_MS3 = 24 * 60 * 60 * 1e3;
|
|
2741
3354
|
var useCalendarLogic = ({
|
|
2742
3355
|
events,
|
|
2743
3356
|
view: controlledView,
|
|
@@ -2754,19 +3367,20 @@ var useCalendarLogic = ({
|
|
|
2754
3367
|
readOnly,
|
|
2755
3368
|
timezone
|
|
2756
3369
|
}) => {
|
|
2757
|
-
const [internalView, setInternalView] = (0,
|
|
2758
|
-
const [internalDate, setInternalDate] = (0,
|
|
2759
|
-
const [isSidebarOpen, setIsSidebarOpen] = (0,
|
|
2760
|
-
const [isModalOpen, setIsModalOpen] = (0,
|
|
2761
|
-
const [selectedEvent, setSelectedEvent] = (0,
|
|
2762
|
-
const [modalInitialDate, setModalInitialDate] = (0,
|
|
2763
|
-
const [modalInitialResourceId, setModalInitialResourceId] = (0,
|
|
3370
|
+
const [internalView, setInternalView] = (0, import_react20.useState)("week");
|
|
3371
|
+
const [internalDate, setInternalDate] = (0, import_react20.useState)(() => /* @__PURE__ */ new Date());
|
|
3372
|
+
const [isSidebarOpen, setIsSidebarOpen] = (0, import_react20.useState)(true);
|
|
3373
|
+
const [isModalOpen, setIsModalOpen] = (0, import_react20.useState)(false);
|
|
3374
|
+
const [selectedEvent, setSelectedEvent] = (0, import_react20.useState)(null);
|
|
3375
|
+
const [modalInitialDate, setModalInitialDate] = (0, import_react20.useState)(void 0);
|
|
3376
|
+
const [modalInitialResourceId, setModalInitialResourceId] = (0, import_react20.useState)(void 0);
|
|
3377
|
+
const [modalInitialAllDay, setModalInitialAllDay] = (0, import_react20.useState)(false);
|
|
2764
3378
|
const view = controlledView ?? internalView;
|
|
2765
3379
|
const currentDate = controlledDate ?? internalDate;
|
|
2766
|
-
const normalizedEvents = (0,
|
|
2767
|
-
const monthKey = (0,
|
|
2768
|
-
const range = (0,
|
|
2769
|
-
const expandedEvents = (0,
|
|
3380
|
+
const normalizedEvents = (0, import_react20.useMemo)(() => normalizeEvents(events), [events]);
|
|
3381
|
+
const monthKey = (0, import_date_fns19.format)(currentDate, "yyyy-MM");
|
|
3382
|
+
const range = (0, import_react20.useMemo)(() => expansionRange(/* @__PURE__ */ new Date(`${monthKey}-01T00:00:00`)), [monthKey]);
|
|
3383
|
+
const expandedEvents = (0, import_react20.useMemo)(
|
|
2770
3384
|
() => expandRecurrences(normalizedEvents, range, timezone),
|
|
2771
3385
|
[normalizedEvents, range, timezone]
|
|
2772
3386
|
);
|
|
@@ -2788,34 +3402,34 @@ var useCalendarLogic = ({
|
|
|
2788
3402
|
const handlePrev = useStableCallback(() => {
|
|
2789
3403
|
switch (view) {
|
|
2790
3404
|
case "month":
|
|
2791
|
-
handleDateChange((0,
|
|
3405
|
+
handleDateChange((0, import_date_fns19.subMonths)(currentDate, 1));
|
|
2792
3406
|
break;
|
|
2793
3407
|
case "week":
|
|
2794
|
-
handleDateChange((0,
|
|
3408
|
+
handleDateChange((0, import_date_fns19.subWeeks)(currentDate, 1));
|
|
2795
3409
|
break;
|
|
2796
3410
|
case "day":
|
|
2797
3411
|
case "resource":
|
|
2798
|
-
handleDateChange((0,
|
|
3412
|
+
handleDateChange((0, import_date_fns19.subDays)(currentDate, 1));
|
|
2799
3413
|
break;
|
|
2800
3414
|
case "agenda":
|
|
2801
|
-
handleDateChange((0,
|
|
3415
|
+
handleDateChange((0, import_date_fns19.subDays)(currentDate, 7));
|
|
2802
3416
|
break;
|
|
2803
3417
|
}
|
|
2804
3418
|
});
|
|
2805
3419
|
const handleNext = useStableCallback(() => {
|
|
2806
3420
|
switch (view) {
|
|
2807
3421
|
case "month":
|
|
2808
|
-
handleDateChange((0,
|
|
3422
|
+
handleDateChange((0, import_date_fns19.addMonths)(currentDate, 1));
|
|
2809
3423
|
break;
|
|
2810
3424
|
case "week":
|
|
2811
|
-
handleDateChange((0,
|
|
3425
|
+
handleDateChange((0, import_date_fns19.addWeeks)(currentDate, 1));
|
|
2812
3426
|
break;
|
|
2813
3427
|
case "day":
|
|
2814
3428
|
case "resource":
|
|
2815
|
-
handleDateChange((0,
|
|
3429
|
+
handleDateChange((0, import_date_fns19.addDays)(currentDate, 1));
|
|
2816
3430
|
break;
|
|
2817
3431
|
case "agenda":
|
|
2818
|
-
handleDateChange((0,
|
|
3432
|
+
handleDateChange((0, import_date_fns19.addDays)(currentDate, 7));
|
|
2819
3433
|
break;
|
|
2820
3434
|
}
|
|
2821
3435
|
});
|
|
@@ -2831,6 +3445,15 @@ var useCalendarLogic = ({
|
|
|
2831
3445
|
setSelectedEvent(null);
|
|
2832
3446
|
setModalInitialDate(date);
|
|
2833
3447
|
setModalInitialResourceId(resourceId);
|
|
3448
|
+
setModalInitialAllDay(false);
|
|
3449
|
+
setIsModalOpen(true);
|
|
3450
|
+
});
|
|
3451
|
+
const handleAllDaySlotClick = useStableCallback((day) => {
|
|
3452
|
+
if (readOnly) return;
|
|
3453
|
+
setSelectedEvent(null);
|
|
3454
|
+
setModalInitialDate(day);
|
|
3455
|
+
setModalInitialResourceId(void 0);
|
|
3456
|
+
setModalInitialAllDay(true);
|
|
2834
3457
|
setIsModalOpen(true);
|
|
2835
3458
|
});
|
|
2836
3459
|
const handleEventClickInternal = useStableCallback((event) => {
|
|
@@ -2839,6 +3462,7 @@ var useCalendarLogic = ({
|
|
|
2839
3462
|
setSelectedEvent(event);
|
|
2840
3463
|
setModalInitialDate(void 0);
|
|
2841
3464
|
setModalInitialResourceId(void 0);
|
|
3465
|
+
setModalInitialAllDay(false);
|
|
2842
3466
|
setIsModalOpen(true);
|
|
2843
3467
|
}
|
|
2844
3468
|
});
|
|
@@ -2847,6 +3471,7 @@ var useCalendarLogic = ({
|
|
|
2847
3471
|
setSelectedEvent(null);
|
|
2848
3472
|
setModalInitialDate(/* @__PURE__ */ new Date());
|
|
2849
3473
|
setModalInitialResourceId(void 0);
|
|
3474
|
+
setModalInitialAllDay(false);
|
|
2850
3475
|
setIsModalOpen(true);
|
|
2851
3476
|
});
|
|
2852
3477
|
const handleModalSave = useStableCallback((eventData) => {
|
|
@@ -2861,7 +3486,7 @@ var useCalendarLogic = ({
|
|
|
2861
3486
|
end: master.end
|
|
2862
3487
|
};
|
|
2863
3488
|
onEventUpdate?.(
|
|
2864
|
-
shiftSeries(edited, selectedEvent, eventData.start ?? selectedEvent.start, eventData.end ?? selectedEvent.end, timezone)
|
|
3489
|
+
shiftSeries(edited, selectedEvent, eventData.start ?? selectedEvent.start, eventData.end ?? selectedEvent.end, edited.allDay ? void 0 : timezone)
|
|
2865
3490
|
);
|
|
2866
3491
|
} else if (selectedEvent) {
|
|
2867
3492
|
onEventUpdate?.({ ...eventData, id: selectedEvent.id });
|
|
@@ -2896,28 +3521,39 @@ var useCalendarLogic = ({
|
|
|
2896
3521
|
...copy,
|
|
2897
3522
|
id: `${event.originalEventId ?? event.id}-copy-${Date.now()}`,
|
|
2898
3523
|
title: `${event.title} (Copy)`,
|
|
2899
|
-
start: new Date(event.start.getTime() +
|
|
2900
|
-
end: new Date(event.end.getTime() +
|
|
3524
|
+
start: new Date(event.start.getTime() + DAY_MS3),
|
|
3525
|
+
end: new Date(event.end.getTime() + DAY_MS3)
|
|
2901
3526
|
});
|
|
2902
3527
|
});
|
|
2903
3528
|
const applyChange = (event, start, end) => {
|
|
2904
3529
|
if (!event.originalEventId) return { original: event, updated: { ...event, start, end } };
|
|
2905
3530
|
const master = masterOf(event);
|
|
2906
3531
|
if (!master) return null;
|
|
2907
|
-
return { original: master, updated: shiftSeries(master, event, start, end, timezone) };
|
|
3532
|
+
return { original: master, updated: shiftSeries(master, event, start, end, event.allDay ? void 0 : timezone) };
|
|
2908
3533
|
};
|
|
2909
3534
|
const handleDragEnd = useStableCallback((dragEvent) => {
|
|
3535
|
+
if (readOnly) return;
|
|
2910
3536
|
const { active, over } = dragEvent;
|
|
2911
3537
|
if (!over) return;
|
|
2912
3538
|
const dragged = active.data.current?.event;
|
|
2913
3539
|
const overDate = over.data.current?.date;
|
|
2914
3540
|
if (!dragged || !overDate) return;
|
|
3541
|
+
const grabDayOffset = active.data.current?.grabDayOffset;
|
|
3542
|
+
if (grabDayOffset !== void 0) {
|
|
3543
|
+
const move = computeDayMove(dragged, overDate, grabDayOffset, timezone);
|
|
3544
|
+
const dayChange = move && applyChange(dragged, move.start, move.end);
|
|
3545
|
+
if (!dayChange) return;
|
|
3546
|
+
onEventDrop?.(dayChange.original, dayChange.updated.start, dayChange.updated.end);
|
|
3547
|
+
onEventUpdate?.(dayChange.updated);
|
|
3548
|
+
return;
|
|
3549
|
+
}
|
|
2915
3550
|
const drop = computeDrop({
|
|
2916
3551
|
event: dragged,
|
|
2917
3552
|
overDate,
|
|
2918
3553
|
overResourceId: over.data.current?.resourceId,
|
|
2919
3554
|
grabOffsetMs: active.data.current?.grabOffsetMs,
|
|
2920
|
-
view
|
|
3555
|
+
// A timed event dropped in the all-day row only changes day (keeps its time), like in month view.
|
|
3556
|
+
view: over.data.current?.allDayRow ? "month" : view,
|
|
2921
3557
|
tz: timezone
|
|
2922
3558
|
});
|
|
2923
3559
|
if (!drop) return;
|
|
@@ -2927,6 +3563,14 @@ var useCalendarLogic = ({
|
|
|
2927
3563
|
onEventDrop?.(change.original, updated.start, updated.end);
|
|
2928
3564
|
onEventUpdate?.(updated);
|
|
2929
3565
|
});
|
|
3566
|
+
const handleDayEventResize = useStableCallback((event, newLastDay) => {
|
|
3567
|
+
if (readOnly) return;
|
|
3568
|
+
const end = computeDayResize(event, newLastDay, timezone);
|
|
3569
|
+
const change = end && applyChange(event, event.start, end);
|
|
3570
|
+
if (!change) return;
|
|
3571
|
+
onEventResize?.(change.original, change.updated.start, change.updated.end);
|
|
3572
|
+
onEventUpdate?.(change.updated);
|
|
3573
|
+
});
|
|
2930
3574
|
const handleEventResize = useStableCallback((event, newEnd) => {
|
|
2931
3575
|
if (readOnly) return;
|
|
2932
3576
|
const change = applyChange(event, event.start, newEnd);
|
|
@@ -2943,6 +3587,7 @@ var useCalendarLogic = ({
|
|
|
2943
3587
|
setIsModalOpen,
|
|
2944
3588
|
selectedEvent,
|
|
2945
3589
|
modalInitialDate,
|
|
3590
|
+
modalInitialAllDay,
|
|
2946
3591
|
expandedEvents,
|
|
2947
3592
|
handleViewChange,
|
|
2948
3593
|
handleDateChange,
|
|
@@ -2951,6 +3596,7 @@ var useCalendarLogic = ({
|
|
|
2951
3596
|
handleToday,
|
|
2952
3597
|
handleDateClick,
|
|
2953
3598
|
handleTimeSlotClick,
|
|
3599
|
+
handleAllDaySlotClick,
|
|
2954
3600
|
handleEventClickInternal,
|
|
2955
3601
|
handleCreateEvent,
|
|
2956
3602
|
handleModalSave,
|
|
@@ -2958,15 +3604,16 @@ var useCalendarLogic = ({
|
|
|
2958
3604
|
handleEventDelete,
|
|
2959
3605
|
handleEventDuplicate,
|
|
2960
3606
|
handleEventResize,
|
|
3607
|
+
handleDayEventResize,
|
|
2961
3608
|
handleDragEnd
|
|
2962
3609
|
};
|
|
2963
3610
|
};
|
|
2964
3611
|
|
|
2965
3612
|
// src/index.tsx
|
|
2966
|
-
var
|
|
3613
|
+
var import_date_fns21 = require("date-fns");
|
|
2967
3614
|
|
|
2968
3615
|
// src/hooks/useSwipeGesture.ts
|
|
2969
|
-
var
|
|
3616
|
+
var import_react21 = require("react");
|
|
2970
3617
|
var useSwipeGesture = (options) => {
|
|
2971
3618
|
const {
|
|
2972
3619
|
onSwipeLeft,
|
|
@@ -2978,9 +3625,9 @@ var useSwipeGesture = (options) => {
|
|
|
2978
3625
|
allowedTime = 500,
|
|
2979
3626
|
enabled = true
|
|
2980
3627
|
} = options;
|
|
2981
|
-
const touchInfoRef = (0,
|
|
2982
|
-
const elementRef = (0,
|
|
2983
|
-
const handleTouchStart = (0,
|
|
3628
|
+
const touchInfoRef = (0, import_react21.useRef)(null);
|
|
3629
|
+
const elementRef = (0, import_react21.useRef)(null);
|
|
3630
|
+
const handleTouchStart = (0, import_react21.useCallback)((e) => {
|
|
2984
3631
|
if (!enabled) return;
|
|
2985
3632
|
const touch = e.touches[0];
|
|
2986
3633
|
touchInfoRef.current = {
|
|
@@ -2989,7 +3636,7 @@ var useSwipeGesture = (options) => {
|
|
|
2989
3636
|
startTime: Date.now()
|
|
2990
3637
|
};
|
|
2991
3638
|
}, [enabled]);
|
|
2992
|
-
const handleTouchEnd = (0,
|
|
3639
|
+
const handleTouchEnd = (0, import_react21.useCallback)((e) => {
|
|
2993
3640
|
if (!enabled || !touchInfoRef.current) return;
|
|
2994
3641
|
const touch = e.changedTouches[0];
|
|
2995
3642
|
const { startX, startY, startTime } = touchInfoRef.current;
|
|
@@ -3013,7 +3660,7 @@ var useSwipeGesture = (options) => {
|
|
|
3013
3660
|
}
|
|
3014
3661
|
touchInfoRef.current = null;
|
|
3015
3662
|
}, [enabled, threshold, restraint, allowedTime, onSwipeLeft, onSwipeRight, onSwipeUp, onSwipeDown]);
|
|
3016
|
-
(0,
|
|
3663
|
+
(0, import_react21.useEffect)(() => {
|
|
3017
3664
|
const element = elementRef.current;
|
|
3018
3665
|
if (!element) return;
|
|
3019
3666
|
element.addEventListener("touchstart", handleTouchStart, { passive: true });
|
|
@@ -3036,6 +3683,25 @@ var useViewSwipe = (onPrev, onNext, enabled = true) => {
|
|
|
3036
3683
|
});
|
|
3037
3684
|
};
|
|
3038
3685
|
|
|
3686
|
+
// src/components/dnd/dragOverlay.ts
|
|
3687
|
+
var import_core4 = require("@dnd-kit/core");
|
|
3688
|
+
var import_date_fns20 = require("date-fns");
|
|
3689
|
+
var dayAwareCollision = (args) => {
|
|
3690
|
+
if (args.active.data.current?.grabDayOffset !== void 0) {
|
|
3691
|
+
const underPointer = (0, import_core4.pointerWithin)(args);
|
|
3692
|
+
if (underPointer.length > 0) return underPointer;
|
|
3693
|
+
}
|
|
3694
|
+
return (0, import_core4.rectIntersection)(args);
|
|
3695
|
+
};
|
|
3696
|
+
function dragOverlaySize(view, event, isDayDrag) {
|
|
3697
|
+
if (isDayDrag) return {};
|
|
3698
|
+
const minutes = (0, import_date_fns20.differenceInMinutes)(event.end, event.start);
|
|
3699
|
+
if (view === "month") return { width: "100%" };
|
|
3700
|
+
if (view === "resource") return { width: `${Math.max(minutes / 60 * 100, 4)}px`, height: 80 };
|
|
3701
|
+
if (view === "week" || view === "day") return { width: "150px", height: minutes / 60 * (view === "day" ? 80 : 60) };
|
|
3702
|
+
return { width: "150px" };
|
|
3703
|
+
}
|
|
3704
|
+
|
|
3039
3705
|
// src/index.tsx
|
|
3040
3706
|
var Scheduler = ({
|
|
3041
3707
|
events = [],
|
|
@@ -3071,10 +3737,12 @@ var Scheduler = ({
|
|
|
3071
3737
|
locale
|
|
3072
3738
|
// Date-fns locale
|
|
3073
3739
|
}) => {
|
|
3074
|
-
const [activeDragEvent, setActiveDragEvent] = (0,
|
|
3740
|
+
const [activeDragEvent, setActiveDragEvent] = (0, import_react22.useState)(null);
|
|
3741
|
+
const [activeDayDrag, setActiveDayDrag] = (0, import_react22.useState)(false);
|
|
3075
3742
|
const {
|
|
3076
3743
|
contextMenuEvent,
|
|
3077
3744
|
contextMenuPosition,
|
|
3745
|
+
openContextMenu,
|
|
3078
3746
|
closeContextMenu
|
|
3079
3747
|
} = useEventContextMenu();
|
|
3080
3748
|
const {
|
|
@@ -3086,6 +3754,7 @@ var Scheduler = ({
|
|
|
3086
3754
|
setIsModalOpen,
|
|
3087
3755
|
selectedEvent,
|
|
3088
3756
|
modalInitialDate,
|
|
3757
|
+
modalInitialAllDay,
|
|
3089
3758
|
handleViewChange,
|
|
3090
3759
|
handleDateChange,
|
|
3091
3760
|
handlePrev,
|
|
@@ -3093,6 +3762,7 @@ var Scheduler = ({
|
|
|
3093
3762
|
handleToday,
|
|
3094
3763
|
handleDateClick,
|
|
3095
3764
|
handleTimeSlotClick,
|
|
3765
|
+
handleAllDaySlotClick,
|
|
3096
3766
|
handleEventClickInternal,
|
|
3097
3767
|
handleCreateEvent,
|
|
3098
3768
|
handleModalSave,
|
|
@@ -3100,6 +3770,7 @@ var Scheduler = ({
|
|
|
3100
3770
|
handleEventDelete,
|
|
3101
3771
|
handleEventDuplicate,
|
|
3102
3772
|
handleEventResize,
|
|
3773
|
+
handleDayEventResize,
|
|
3103
3774
|
handleDragEnd,
|
|
3104
3775
|
expandedEvents
|
|
3105
3776
|
} = useCalendarLogic({
|
|
@@ -3118,8 +3789,8 @@ var Scheduler = ({
|
|
|
3118
3789
|
readOnly,
|
|
3119
3790
|
timezone
|
|
3120
3791
|
});
|
|
3121
|
-
const sensors = (0,
|
|
3122
|
-
(0,
|
|
3792
|
+
const sensors = (0, import_core5.useSensors)(
|
|
3793
|
+
(0, import_core5.useSensor)(import_core5.PointerSensor, {
|
|
3123
3794
|
activationConstraint: {
|
|
3124
3795
|
distance: 8
|
|
3125
3796
|
}
|
|
@@ -3129,63 +3800,49 @@ var Scheduler = ({
|
|
|
3129
3800
|
const snapToGrid = (0, import_modifiers.createSnapModifier)(gridSize);
|
|
3130
3801
|
const modifiers = [snapToGrid, import_modifiers.restrictToWindowEdges];
|
|
3131
3802
|
const dndSensors = readOnly ? [] : sensors;
|
|
3132
|
-
const id = (0,
|
|
3803
|
+
const id = (0, import_react22.useId)();
|
|
3133
3804
|
const swipeRef = useViewSwipe(handlePrev, handleNext, true);
|
|
3134
|
-
const t = (0,
|
|
3805
|
+
const t = (0, import_react22.useMemo)(() => resolveTranslations(language, translations), [language, translations]);
|
|
3135
3806
|
const overlayTimeFormat = timeFormats(locale).time;
|
|
3136
|
-
const handleDragStart = (0,
|
|
3807
|
+
const handleDragStart = (0, import_react22.useCallback)((event) => {
|
|
3137
3808
|
const draggedEvent = event.active.data.current?.event;
|
|
3138
3809
|
if (draggedEvent) {
|
|
3139
3810
|
setActiveDragEvent(draggedEvent);
|
|
3811
|
+
setActiveDayDrag(event.active.data.current?.grabDayOffset !== void 0);
|
|
3140
3812
|
}
|
|
3141
3813
|
}, []);
|
|
3142
|
-
const onDragEndWrapper = (0,
|
|
3814
|
+
const onDragEndWrapper = (0, import_react22.useCallback)((event) => {
|
|
3143
3815
|
setActiveDragEvent(null);
|
|
3144
3816
|
handleDragEnd(event);
|
|
3145
3817
|
}, [handleDragEnd]);
|
|
3146
|
-
const
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
const
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
const duration = (0, import_date_fns16.differenceInMinutes)(activeDragEvent.end, activeDragEvent.start);
|
|
3160
|
-
const width = duration / 60 * 100;
|
|
3161
|
-
return `${Math.max(width, 4)}px`;
|
|
3162
|
-
}
|
|
3163
|
-
return "150px";
|
|
3164
|
-
};
|
|
3165
|
-
const filteredEvents = (0, import_react20.useMemo)(() => {
|
|
3166
|
-
if (!calendars) return expandedEvents;
|
|
3167
|
-
const activeCalendarIds = calendars.filter((c) => c.active !== false).map((c) => c.id);
|
|
3168
|
-
return expandedEvents.filter((e) => {
|
|
3169
|
-
if (!e.calendarId) return true;
|
|
3170
|
-
return activeCalendarIds.includes(e.calendarId);
|
|
3171
|
-
});
|
|
3172
|
-
}, [expandedEvents, calendars]);
|
|
3173
|
-
return /* @__PURE__ */ import_react20.default.createElement(
|
|
3174
|
-
import_core3.DndContext,
|
|
3818
|
+
const dragSize = activeDragEvent ? dragOverlaySize(view, activeDragEvent, activeDayDrag) : {};
|
|
3819
|
+
const activeCalendarKey = calendars ? calendars.filter((c) => c.active !== false).map((c) => c.id).join("\0") : null;
|
|
3820
|
+
const filteredEvents = (0, import_react22.useMemo)(() => {
|
|
3821
|
+
if (activeCalendarKey === null) return expandedEvents;
|
|
3822
|
+
const activeCalendarIds = new Set(activeCalendarKey.split("\0"));
|
|
3823
|
+
return expandedEvents.filter((e) => !e.calendarId || activeCalendarIds.has(String(e.calendarId)));
|
|
3824
|
+
}, [expandedEvents, activeCalendarKey]);
|
|
3825
|
+
const periodKey = view === "month" ? (0, import_date_fns21.format)(currentDate, "yyyy-MM") : view === "week" ? (0, import_date_fns21.format)((0, import_date_fns21.startOfWeek)(currentDate, { weekStartsOn: resolveWeekStartsOn(locale, 1) }), "yyyy-MM-dd") : (0, import_date_fns21.format)(currentDate, "yyyy-MM-dd");
|
|
3826
|
+
const slotClickHandler = readOnly ? void 0 : handleTimeSlotClick;
|
|
3827
|
+
const allDaySlotClickHandler = readOnly ? void 0 : handleAllDaySlotClick;
|
|
3828
|
+
const contextMenuHandler = readOnly ? void 0 : openContextMenu;
|
|
3829
|
+
return /* @__PURE__ */ import_react22.default.createElement(
|
|
3830
|
+
import_core5.DndContext,
|
|
3175
3831
|
{
|
|
3176
3832
|
id,
|
|
3177
3833
|
sensors: dndSensors,
|
|
3178
3834
|
onDragStart: handleDragStart,
|
|
3179
3835
|
onDragEnd: onDragEndWrapper,
|
|
3180
|
-
modifiers
|
|
3836
|
+
modifiers,
|
|
3837
|
+
collisionDetection: dayAwareCollision
|
|
3181
3838
|
},
|
|
3182
|
-
/* @__PURE__ */
|
|
3839
|
+
/* @__PURE__ */ import_react22.default.createElement(
|
|
3183
3840
|
"div",
|
|
3184
3841
|
{
|
|
3185
3842
|
className: cn("flex flex-col h-full bg-background text-foreground relative", className),
|
|
3186
3843
|
style: getThemeStyles(theme)
|
|
3187
3844
|
},
|
|
3188
|
-
/* @__PURE__ */
|
|
3845
|
+
/* @__PURE__ */ import_react22.default.createElement(
|
|
3189
3846
|
CalendarHeader,
|
|
3190
3847
|
{
|
|
3191
3848
|
currentDate,
|
|
@@ -3204,7 +3861,7 @@ var Scheduler = ({
|
|
|
3204
3861
|
locale
|
|
3205
3862
|
}
|
|
3206
3863
|
),
|
|
3207
|
-
/* @__PURE__ */
|
|
3864
|
+
/* @__PURE__ */ import_react22.default.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ import_react22.default.createElement(
|
|
3208
3865
|
import_framer_motion4.motion.div,
|
|
3209
3866
|
{
|
|
3210
3867
|
className: cn(
|
|
@@ -3220,7 +3877,7 @@ var Scheduler = ({
|
|
|
3220
3877
|
ease: [0.4, 0, 0.2, 1]
|
|
3221
3878
|
}
|
|
3222
3879
|
},
|
|
3223
|
-
/* @__PURE__ */
|
|
3880
|
+
/* @__PURE__ */ import_react22.default.createElement(
|
|
3224
3881
|
Sidebar,
|
|
3225
3882
|
{
|
|
3226
3883
|
currentDate,
|
|
@@ -3237,10 +3894,10 @@ var Scheduler = ({
|
|
|
3237
3894
|
locale
|
|
3238
3895
|
}
|
|
3239
3896
|
)
|
|
3240
|
-
), /* @__PURE__ */
|
|
3897
|
+
), /* @__PURE__ */ import_react22.default.createElement("div", { className: "flex-1 flex flex-col overflow-hidden relative" }, isLoading ? /* @__PURE__ */ import_react22.default.createElement("div", { className: "flex-1 overflow-auto p-0 md:p-4" }, /* @__PURE__ */ import_react22.default.createElement("div", { className: "h-full min-w-full" }, view === "month" && /* @__PURE__ */ import_react22.default.createElement(MonthViewSkeleton, null), view === "week" && /* @__PURE__ */ import_react22.default.createElement(WeekViewSkeleton, null), view === "day" && /* @__PURE__ */ import_react22.default.createElement(DayViewSkeleton, null), view === "agenda" && /* @__PURE__ */ import_react22.default.createElement(AgendaViewSkeleton, null), view === "resource" && /* @__PURE__ */ import_react22.default.createElement(WeekViewSkeleton, null))) : /* @__PURE__ */ import_react22.default.createElement("div", { ref: swipeRef, className: "flex-1 overflow-auto p-0 md:p-4 touch-pan-y" }, /* @__PURE__ */ import_react22.default.createElement("div", { className: "h-full min-w-full" }, /* @__PURE__ */ import_react22.default.createElement(import_framer_motion4.AnimatePresence, { mode: "wait", initial: false }, /* @__PURE__ */ import_react22.default.createElement(
|
|
3241
3898
|
import_framer_motion4.motion.div,
|
|
3242
3899
|
{
|
|
3243
|
-
key: `${view}-${
|
|
3900
|
+
key: `${view}-${periodKey}-${timezone || "local"}`,
|
|
3244
3901
|
initial: { opacity: 0, scale: 0.98, y: 15 },
|
|
3245
3902
|
animate: {
|
|
3246
3903
|
opacity: 1,
|
|
@@ -3262,7 +3919,7 @@ var Scheduler = ({
|
|
|
3262
3919
|
},
|
|
3263
3920
|
className: "h-full"
|
|
3264
3921
|
},
|
|
3265
|
-
view === "month" && /* @__PURE__ */
|
|
3922
|
+
view === "month" && /* @__PURE__ */ import_react22.default.createElement(
|
|
3266
3923
|
MonthView,
|
|
3267
3924
|
{
|
|
3268
3925
|
currentDate,
|
|
@@ -3270,36 +3927,48 @@ var Scheduler = ({
|
|
|
3270
3927
|
onEventClick: handleEventClickInternal,
|
|
3271
3928
|
onDateClick: handleDateClick,
|
|
3272
3929
|
timezone,
|
|
3273
|
-
locale
|
|
3930
|
+
locale,
|
|
3931
|
+
translations: t,
|
|
3932
|
+
onEventContextMenu: contextMenuHandler,
|
|
3933
|
+
onDayEventResize: handleDayEventResize,
|
|
3934
|
+
readonly: readOnly
|
|
3274
3935
|
}
|
|
3275
3936
|
),
|
|
3276
|
-
view === "week" && /* @__PURE__ */
|
|
3937
|
+
view === "week" && /* @__PURE__ */ import_react22.default.createElement(
|
|
3277
3938
|
WeekView,
|
|
3278
3939
|
{
|
|
3279
3940
|
currentDate,
|
|
3280
3941
|
events: filteredEvents,
|
|
3281
3942
|
onEventClick: handleEventClickInternal,
|
|
3282
|
-
onTimeSlotClick:
|
|
3943
|
+
onTimeSlotClick: slotClickHandler,
|
|
3283
3944
|
onEventResize: handleEventResize,
|
|
3284
3945
|
timezone,
|
|
3285
3946
|
locale,
|
|
3286
|
-
readonly: readOnly
|
|
3947
|
+
readonly: readOnly,
|
|
3948
|
+
onEventContextMenu: contextMenuHandler,
|
|
3949
|
+
onDayEventResize: handleDayEventResize,
|
|
3950
|
+
onAllDaySlotClick: allDaySlotClickHandler,
|
|
3951
|
+
translations: t
|
|
3287
3952
|
}
|
|
3288
3953
|
),
|
|
3289
|
-
view === "day" && /* @__PURE__ */
|
|
3954
|
+
view === "day" && /* @__PURE__ */ import_react22.default.createElement(
|
|
3290
3955
|
DayView,
|
|
3291
3956
|
{
|
|
3292
3957
|
currentDate,
|
|
3293
3958
|
events: filteredEvents,
|
|
3294
3959
|
onEventClick: handleEventClickInternal,
|
|
3295
|
-
onTimeSlotClick:
|
|
3960
|
+
onTimeSlotClick: slotClickHandler,
|
|
3296
3961
|
onEventResize: handleEventResize,
|
|
3297
3962
|
timezone,
|
|
3298
3963
|
locale,
|
|
3299
|
-
readonly: readOnly
|
|
3964
|
+
readonly: readOnly,
|
|
3965
|
+
translations: t,
|
|
3966
|
+
onEventContextMenu: contextMenuHandler,
|
|
3967
|
+
onDayEventResize: handleDayEventResize,
|
|
3968
|
+
onAllDaySlotClick: allDaySlotClickHandler
|
|
3300
3969
|
}
|
|
3301
3970
|
),
|
|
3302
|
-
view === "agenda" && /* @__PURE__ */
|
|
3971
|
+
view === "agenda" && /* @__PURE__ */ import_react22.default.createElement(
|
|
3303
3972
|
AgendaView,
|
|
3304
3973
|
{
|
|
3305
3974
|
currentDate,
|
|
@@ -3308,37 +3977,42 @@ var Scheduler = ({
|
|
|
3308
3977
|
onCreateEvent: handleCreateEvent,
|
|
3309
3978
|
locale,
|
|
3310
3979
|
translations: t,
|
|
3311
|
-
timezone
|
|
3980
|
+
timezone,
|
|
3981
|
+
onEventContextMenu: contextMenuHandler
|
|
3312
3982
|
}
|
|
3313
3983
|
),
|
|
3314
|
-
view === "resource" && resources && /* @__PURE__ */
|
|
3984
|
+
view === "resource" && resources && /* @__PURE__ */ import_react22.default.createElement(
|
|
3315
3985
|
ResourceView,
|
|
3316
3986
|
{
|
|
3317
3987
|
currentDate,
|
|
3318
3988
|
events: filteredEvents,
|
|
3319
3989
|
resources,
|
|
3320
3990
|
onEventClick: handleEventClickInternal,
|
|
3321
|
-
onTimeSlotClick:
|
|
3991
|
+
onTimeSlotClick: slotClickHandler,
|
|
3322
3992
|
locale,
|
|
3323
|
-
timezone
|
|
3993
|
+
timezone,
|
|
3994
|
+
translations: t,
|
|
3995
|
+
onEventContextMenu: contextMenuHandler
|
|
3324
3996
|
}
|
|
3325
3997
|
)
|
|
3326
|
-
)))), /* @__PURE__ */
|
|
3998
|
+
)))), !readOnly && /* @__PURE__ */ import_react22.default.createElement("div", { className: "md:hidden absolute bottom-6 right-6 z-50" }, /* @__PURE__ */ import_react22.default.createElement(
|
|
3327
3999
|
"button",
|
|
3328
4000
|
{
|
|
3329
4001
|
onClick: handleCreateEvent,
|
|
4002
|
+
"aria-label": t.createEvent,
|
|
3330
4003
|
className: "w-14 h-14 bg-blue-600 rounded-full shadow-lg flex items-center justify-center text-white active:scale-90 transition-transform"
|
|
3331
4004
|
},
|
|
3332
|
-
/* @__PURE__ */
|
|
4005
|
+
/* @__PURE__ */ import_react22.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react22.default.createElement("path", { d: "M5 12h14" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M12 5v14" }))
|
|
3333
4006
|
)))),
|
|
3334
4007
|
renderEventForm ? renderEventForm({
|
|
3335
4008
|
isOpen: isModalOpen,
|
|
3336
4009
|
onClose: () => setIsModalOpen(false),
|
|
3337
4010
|
event: selectedEvent,
|
|
3338
4011
|
initialDate: modalInitialDate,
|
|
4012
|
+
initialAllDay: modalInitialAllDay,
|
|
3339
4013
|
onSave: handleModalSave,
|
|
3340
4014
|
onDelete: handleModalDelete
|
|
3341
|
-
}) : /* @__PURE__ */
|
|
4015
|
+
}) : /* @__PURE__ */ import_react22.default.createElement(
|
|
3342
4016
|
EventModal,
|
|
3343
4017
|
{
|
|
3344
4018
|
isOpen: isModalOpen,
|
|
@@ -3349,10 +4023,12 @@ var Scheduler = ({
|
|
|
3349
4023
|
onDelete: handleModalDelete,
|
|
3350
4024
|
calendars,
|
|
3351
4025
|
eventTypes,
|
|
3352
|
-
translations: t
|
|
4026
|
+
translations: t,
|
|
4027
|
+
locale,
|
|
4028
|
+
initialAllDay: modalInitialAllDay
|
|
3353
4029
|
}
|
|
3354
4030
|
),
|
|
3355
|
-
/* @__PURE__ */
|
|
4031
|
+
/* @__PURE__ */ import_react22.default.createElement(
|
|
3356
4032
|
EventContextMenu,
|
|
3357
4033
|
{
|
|
3358
4034
|
event: contextMenuEvent,
|
|
@@ -3377,7 +4053,7 @@ var Scheduler = ({
|
|
|
3377
4053
|
}
|
|
3378
4054
|
}
|
|
3379
4055
|
),
|
|
3380
|
-
/* @__PURE__ */
|
|
4056
|
+
/* @__PURE__ */ import_react22.default.createElement(import_core5.DragOverlay, { dropAnimation: null }, activeDragEvent ? /* @__PURE__ */ import_react22.default.createElement(
|
|
3381
4057
|
"div",
|
|
3382
4058
|
{
|
|
3383
4059
|
className: cn(
|
|
@@ -3389,19 +4065,19 @@ var Scheduler = ({
|
|
|
3389
4065
|
backgroundColor: activeDragEvent.color ? `${activeDragEvent.color}e0` : void 0,
|
|
3390
4066
|
borderColor: activeDragEvent.color ? `${activeDragEvent.color}80` : void 0,
|
|
3391
4067
|
color: activeDragEvent.color ? "#fff" : void 0,
|
|
3392
|
-
width:
|
|
3393
|
-
height:
|
|
4068
|
+
width: dragSize.width,
|
|
4069
|
+
height: dragSize.height ? `${dragSize.height}px` : void 0,
|
|
3394
4070
|
boxShadow: `0 20px 40px -15px ${activeDragEvent.color || "var(--primary)"}40, 0 10px 20px -10px rgba(0,0,0,0.2)`,
|
|
3395
4071
|
transform: "rotate(-2deg) scale(1.02)"
|
|
3396
4072
|
}
|
|
3397
4073
|
},
|
|
3398
|
-
/* @__PURE__ */
|
|
4074
|
+
/* @__PURE__ */ import_react22.default.createElement("div", { className: "p-2.5 h-full flex flex-col" }, /* @__PURE__ */ import_react22.default.createElement(
|
|
3399
4075
|
"div",
|
|
3400
4076
|
{
|
|
3401
4077
|
className: "absolute left-0 top-0 bottom-0 w-1 rounded-l-lg",
|
|
3402
4078
|
style: { backgroundColor: activeDragEvent.color || "var(--primary)" }
|
|
3403
4079
|
}
|
|
3404
|
-
), /* @__PURE__ */
|
|
4080
|
+
), /* @__PURE__ */ import_react22.default.createElement("div", { className: "pl-2" }, /* @__PURE__ */ import_react22.default.createElement("div", { className: "font-semibold truncate text-sm" }, activeDragEvent.title), (view === "week" || view === "day") && dragSize.height !== void 0 && dragSize.height > 40 && /* @__PURE__ */ import_react22.default.createElement("div", { className: "text-xs opacity-80 mt-0.5 flex items-center gap-1" }, /* @__PURE__ */ import_react22.default.createElement("svg", { className: "w-3 h-3", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" }, /* @__PURE__ */ import_react22.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M12 6v6l4 2" })), (0, import_date_fns21.format)(toDisplay(activeDragEvent.start, timezone), overlayTimeFormat, { locale }), " - ", (0, import_date_fns21.format)(toDisplay(activeDragEvent.end, timezone), overlayTimeFormat, { locale }))), /* @__PURE__ */ import_react22.default.createElement("div", { className: "absolute bottom-1.5 right-1.5 opacity-60" }, /* @__PURE__ */ import_react22.default.createElement("svg", { className: "w-4 h-4", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ import_react22.default.createElement("circle", { cx: "9", cy: "5", r: "1.5" }), /* @__PURE__ */ import_react22.default.createElement("circle", { cx: "15", cy: "5", r: "1.5" }), /* @__PURE__ */ import_react22.default.createElement("circle", { cx: "9", cy: "12", r: "1.5" }), /* @__PURE__ */ import_react22.default.createElement("circle", { cx: "15", cy: "12", r: "1.5" }), /* @__PURE__ */ import_react22.default.createElement("circle", { cx: "9", cy: "19", r: "1.5" }), /* @__PURE__ */ import_react22.default.createElement("circle", { cx: "15", cy: "19", r: "1.5" }))))
|
|
3405
4081
|
) : null)
|
|
3406
4082
|
)
|
|
3407
4083
|
);
|