@vicacha-devs/strapi-plugin-calendar 0.0.0-stage → 1.0.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/LICENSE.md +21 -0
- package/README.md +163 -2
- package/dist/admin/CalendarPage-CVqowKst.cjs +1015 -0
- package/dist/admin/CalendarPage-Dq6YfSXF.js +1015 -0
- package/dist/admin/SettingsPage-7SecVQEi.js +2088 -0
- package/dist/admin/SettingsPage-D0aCDb9w.cjs +2088 -0
- package/dist/admin/ar-O6QL_nJZ.js +331 -0
- package/dist/admin/ar-yKsEpX_y.cjs +331 -0
- package/dist/admin/de-BpDxjctz.js +331 -0
- package/dist/admin/de-ryVtwWOz.cjs +331 -0
- package/dist/admin/en-BHYSUqXv.cjs +331 -0
- package/dist/admin/en-BoRq-9QD.js +331 -0
- package/dist/admin/es-BZ7WX8Ev.js +331 -0
- package/dist/admin/es-T5v93hXW.cjs +331 -0
- package/dist/admin/fr-BnDr9DC8.js +331 -0
- package/dist/admin/fr-DTdTwx7e.cjs +331 -0
- package/dist/admin/index-DO0QbnXX.cjs +3223 -0
- package/dist/admin/index-USqxqyAm.js +3216 -0
- package/dist/admin/index.cjs +9 -0
- package/dist/admin/index.js +9 -0
- package/dist/admin/index.mjs +9 -0
- package/dist/admin/it-BkJNzy27.cjs +331 -0
- package/dist/admin/it-DkdUInap.js +331 -0
- package/dist/admin/nl-C2NFORLS.js +331 -0
- package/dist/admin/nl-CjnlbeUM.cjs +331 -0
- package/dist/admin/pl-BJArPgCQ.cjs +331 -0
- package/dist/admin/pl-mv5eXA8W.js +331 -0
- package/dist/admin/pt-CSYqSGnz.cjs +331 -0
- package/dist/admin/pt-WpvZGj3b.js +331 -0
- package/dist/admin/src/components/CalendarSidePanel.d.ts +13 -0
- package/dist/admin/src/components/Initializer.d.ts +6 -0
- package/dist/admin/src/components/PluginIcon.d.ts +3 -0
- package/dist/admin/src/components/RRuleInput.d.ts +20 -0
- package/dist/admin/src/components/calendar/CalendarToolbar.d.ts +32 -0
- package/dist/admin/src/components/calendar/FullCalendarCanvas.d.ts +21 -0
- package/dist/admin/src/components/calendar/FullCalendarDayCell.d.ts +11 -0
- package/dist/admin/src/components/calendar/OccurrenceDetailDrawer.d.ts +15 -0
- package/dist/admin/src/components/calendar/QuickCreatePanel.d.ts +29 -0
- package/dist/admin/src/components/calendar/QuickCreateSubcomponents.d.ts +40 -0
- package/dist/admin/src/components/calendar/calendarPageHelpers.d.ts +52 -0
- package/dist/admin/src/components/calendar/calendarThemeStyles.d.ts +2 -0
- package/dist/admin/src/components/settings/CalendarThemeSection.d.ts +9 -0
- package/dist/admin/src/components/settings/CalendarViewsSection.d.ts +10 -0
- package/dist/admin/src/components/settings/CollectionSourcesSection.d.ts +12 -0
- package/dist/admin/src/components/settings/CompanionSuiteSettingsSection.d.ts +29 -0
- package/dist/admin/src/components/settings/SecondaryCalendarsSection.d.ts +11 -0
- package/dist/admin/src/fields/rruleField.d.ts +19 -0
- package/dist/admin/src/index.d.ts +18 -0
- package/dist/admin/src/pages/CalendarPage.d.ts +3 -0
- package/dist/admin/src/pages/SettingsPage.d.ts +3 -0
- package/dist/admin/src/pages/calendarPageSupport.d.ts +8 -0
- package/dist/admin/tr-BhZKvFoK.js +331 -0
- package/dist/admin/tr-zUVxuw9X.cjs +331 -0
- package/dist/package.json +3 -0
- package/dist/server/index.cjs +2585 -0
- package/dist/server/index.js +2585 -0
- package/dist/server/index.mjs +2585 -0
- package/dist/server/src/bootstrap.d.ts +5 -0
- package/dist/server/src/config/index.d.ts +7 -0
- package/dist/server/src/controllers/admin.d.ts +15 -0
- package/dist/server/src/controllers/content-api.d.ts +10 -0
- package/dist/server/src/controllers/index.d.ts +21 -0
- package/dist/server/src/destroy.d.ts +5 -0
- package/dist/server/src/index.d.ts +85 -0
- package/dist/server/src/register.d.ts +5 -0
- package/dist/server/src/routes/admin.d.ts +17 -0
- package/dist/server/src/routes/content-api.d.ts +10 -0
- package/dist/server/src/routes/index.d.ts +28 -0
- package/dist/server/src/services/builtinSources.d.ts +3 -0
- package/dist/server/src/services/ical.d.ts +6 -0
- package/dist/server/src/services/index.d.ts +23 -0
- package/dist/server/src/services/occurrence.d.ts +6 -0
- package/dist/server/src/services/occurrenceDates.d.ts +7 -0
- package/dist/server/src/services/quickCreateHelpers.d.ts +20 -0
- package/dist/server/src/services/registry.d.ts +19 -0
- package/dist/server/src/services/settings.d.ts +6 -0
- package/dist/server/src/types.d.ts +98 -0
- package/dist/shared/calendarSystems.d.ts +41 -0
- package/dist/shared/icalGenerator.d.ts +18 -0
- package/dist/shared/index.cjs +1612 -0
- package/dist/shared/index.d.ts +6 -0
- package/dist/shared/index.js +1612 -0
- package/dist/shared/index.mjs +1612 -0
- package/dist/shared/localization.d.ts +14 -0
- package/dist/shared/pluginId.d.ts +2 -0
- package/dist/shared/rruleEngine.d.ts +22 -0
- package/dist/shared/themePalettes.d.ts +27 -0
- package/dist/shared/themePresets.d.ts +32 -0
- package/dist/shared/types.d.ts +311 -0
- package/package.json +120 -3
|
@@ -0,0 +1,3216 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Flex, Box, Typography, Badge, Button, SingleSelect, SingleSelectOption, Field, Checkbox, DatePicker, NumberInput } from "@strapi/design-system";
|
|
3
|
+
import { NavLink } from "react-router-dom";
|
|
4
|
+
import allLocales from "@fullcalendar/core/locales-all";
|
|
5
|
+
import dayGridPlugin from "@fullcalendar/daygrid";
|
|
6
|
+
import interactionPlugin from "@fullcalendar/interaction";
|
|
7
|
+
import listPlugin from "@fullcalendar/list";
|
|
8
|
+
import multiMonthPlugin from "@fullcalendar/multimonth";
|
|
9
|
+
import FullCalendar from "@fullcalendar/react";
|
|
10
|
+
import timeGridPlugin from "@fullcalendar/timegrid";
|
|
11
|
+
import { useMemo, useCallback, useState, useEffect, useRef } from "react";
|
|
12
|
+
import { useTheme } from "styled-components";
|
|
13
|
+
import { useFetchClient } from "@strapi/strapi/admin";
|
|
14
|
+
import { useIntl } from "react-intl";
|
|
15
|
+
import { Calendar } from "@strapi/icons";
|
|
16
|
+
const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
|
|
17
|
+
const v = glob[path];
|
|
18
|
+
if (v) {
|
|
19
|
+
return typeof v === "function" ? v() : Promise.resolve(v);
|
|
20
|
+
}
|
|
21
|
+
return new Promise((_, reject) => {
|
|
22
|
+
(typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
|
|
23
|
+
reject.bind(
|
|
24
|
+
null,
|
|
25
|
+
new Error(
|
|
26
|
+
"Unknown variable dynamic import: " + path + (path.split("/").length !== segs ? ". Note that variables only represent file names one level deep." : "")
|
|
27
|
+
)
|
|
28
|
+
)
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
function freezeOptions(items) {
|
|
33
|
+
return Object.freeze(items.map((item) => Object.freeze({ ...item })));
|
|
34
|
+
}
|
|
35
|
+
freezeOptions([
|
|
36
|
+
{ value: "es", label: "es — Español (Spanish)" },
|
|
37
|
+
{ value: "en", label: "en — English" },
|
|
38
|
+
{ value: "ar", label: "ar — العربية (Arabic)" },
|
|
39
|
+
{ value: "tr", label: "tr — Türkçe (Turkish)" },
|
|
40
|
+
{ value: "fr", label: "fr — Français (French)" },
|
|
41
|
+
{ value: "de", label: "de — Deutsch (German)" },
|
|
42
|
+
{ value: "pt", label: "pt — Português (Portuguese)" },
|
|
43
|
+
{ value: "it", label: "it — Italiano (Italian)" },
|
|
44
|
+
{ value: "nl", label: "nl — Nederlands (Dutch)" },
|
|
45
|
+
{ value: "pl", label: "pl — Polski (Polish)" },
|
|
46
|
+
{ value: "ru", label: "ru — Русский (Russian)" },
|
|
47
|
+
{ value: "id", label: "id — Bahasa Indonesia" },
|
|
48
|
+
{ value: "ur", label: "ur — اردو (Urdu)" },
|
|
49
|
+
{ value: "zh", label: "zh — 中文 (Chinese)" }
|
|
50
|
+
]);
|
|
51
|
+
freezeOptions([
|
|
52
|
+
{
|
|
53
|
+
value: "islamic-umalqura",
|
|
54
|
+
label: "islamic-umalqura (Hijri Umm al-Qura)"
|
|
55
|
+
},
|
|
56
|
+
{ value: "islamic-civil", label: "islamic-civil (Tabular Islamic Civil)" },
|
|
57
|
+
{ value: "islamic-tbla", label: "islamic-tbla (Tabular Astronomical)" },
|
|
58
|
+
{ value: "hebrew", label: "hebrew (Hebrew)" },
|
|
59
|
+
{ value: "persian", label: "persian (Solar Hijri)" },
|
|
60
|
+
{ value: "none", label: "none (Gregorian Only)" }
|
|
61
|
+
]);
|
|
62
|
+
const VALID_LOCALE_RE = /^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8}){0,4}$/;
|
|
63
|
+
function isTranslationRecord(value) {
|
|
64
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
65
|
+
}
|
|
66
|
+
function extractDictionary(loaded) {
|
|
67
|
+
if (!isTranslationRecord(loaded)) {
|
|
68
|
+
return void 0;
|
|
69
|
+
}
|
|
70
|
+
if ("default" in loaded) {
|
|
71
|
+
return isTranslationRecord(loaded.default) ? loaded.default : void 0;
|
|
72
|
+
}
|
|
73
|
+
return loaded;
|
|
74
|
+
}
|
|
75
|
+
function getLookupCandidates(locale, fallbackToLanguage) {
|
|
76
|
+
const trimmed = locale.trim();
|
|
77
|
+
if (!VALID_LOCALE_RE.test(trimmed)) {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
if (!fallbackToLanguage || !trimmed.includes("-")) {
|
|
81
|
+
return [trimmed];
|
|
82
|
+
}
|
|
83
|
+
const base = trimmed.split("-")[0];
|
|
84
|
+
return base && base !== trimmed ? [trimmed, base] : [trimmed];
|
|
85
|
+
}
|
|
86
|
+
function prefixPluginTranslations(trad, pluginId, options) {
|
|
87
|
+
const normalizedPluginId = typeof pluginId === "string" ? pluginId.trim() : "";
|
|
88
|
+
if (!normalizedPluginId) {
|
|
89
|
+
throw new TypeError("pluginId can't be empty");
|
|
90
|
+
}
|
|
91
|
+
const result = {};
|
|
92
|
+
if (options?.baseTranslations) {
|
|
93
|
+
for (const [key, value] of Object.entries(options.baseTranslations)) {
|
|
94
|
+
if (typeof value === "string") {
|
|
95
|
+
result[key] = value;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const prefix = `${normalizedPluginId}.`;
|
|
100
|
+
const explicitPrefixed = [];
|
|
101
|
+
for (const [key, value] of Object.entries(trad)) {
|
|
102
|
+
if (typeof value !== "string") {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (options?.keepUnprefixed) {
|
|
106
|
+
result[key] = value;
|
|
107
|
+
}
|
|
108
|
+
if (key.startsWith(prefix)) {
|
|
109
|
+
explicitPrefixed.push([key, value]);
|
|
110
|
+
} else {
|
|
111
|
+
result[`${prefix}${key}`] = value;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const [key, value] of explicitPrefixed) {
|
|
115
|
+
result[key] = value;
|
|
116
|
+
}
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
function createRegisterTrads(options) {
|
|
120
|
+
const { pluginId, defaultLocales = ["en", "es", "ar", "tr"], supportedLocales, keepUnprefixed = true, fallbackToLanguageCode = true, loadTranslation, translations, getBaseTranslations, onLoaded } = options;
|
|
121
|
+
const normalizedPluginId = typeof pluginId === "string" ? pluginId.trim() : "";
|
|
122
|
+
if (!normalizedPluginId) {
|
|
123
|
+
throw new TypeError("pluginId can't be empty");
|
|
124
|
+
}
|
|
125
|
+
const supportedSet = supportedLocales ? new Set(supportedLocales) : void 0;
|
|
126
|
+
const effectiveDefaults = supportedSet ? defaultLocales.filter((loc) => getLookupCandidates(loc, fallbackToLanguageCode).some((candidate) => supportedSet.has(candidate))) : defaultLocales;
|
|
127
|
+
return async function registerTrads({ locales = [] } = {}) {
|
|
128
|
+
const allLocales2 = effectiveDefaults.length > 0 ? Array.from(/* @__PURE__ */ new Set([...locales, ...effectiveDefaults])) : Array.from(new Set(locales));
|
|
129
|
+
return Promise.all(allLocales2.map(async (locale) => {
|
|
130
|
+
const candidates = getLookupCandidates(locale, fallbackToLanguageCode);
|
|
131
|
+
if (candidates.length === 0) {
|
|
132
|
+
return { data: {}, locale };
|
|
133
|
+
}
|
|
134
|
+
if (supportedSet && !candidates.some((candidate) => supportedSet.has(candidate))) {
|
|
135
|
+
return { data: {}, locale };
|
|
136
|
+
}
|
|
137
|
+
let rawData;
|
|
138
|
+
for (const candidate of candidates) {
|
|
139
|
+
if (translations && Object.hasOwn(translations, candidate)) {
|
|
140
|
+
rawData = extractDictionary(translations[candidate]);
|
|
141
|
+
if (rawData) {
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (loadTranslation) {
|
|
146
|
+
try {
|
|
147
|
+
const loaded = await loadTranslation(candidate);
|
|
148
|
+
rawData = extractDictionary(loaded);
|
|
149
|
+
if (rawData) {
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
} catch {
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const baseTranslations = getBaseTranslations?.(locale);
|
|
157
|
+
const hasBase = Boolean(baseTranslations) && Object.keys(baseTranslations).length > 0;
|
|
158
|
+
if (!rawData && !hasBase) {
|
|
159
|
+
return { data: {}, locale };
|
|
160
|
+
}
|
|
161
|
+
const prefixed = prefixPluginTranslations(rawData ?? {}, normalizedPluginId, {
|
|
162
|
+
keepUnprefixed,
|
|
163
|
+
baseTranslations
|
|
164
|
+
});
|
|
165
|
+
onLoaded?.(locale, prefixed);
|
|
166
|
+
return { data: prefixed, locale };
|
|
167
|
+
}));
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
const PLUGIN_ID = "calendar";
|
|
171
|
+
const RTL_LANGUAGE_PREFIXES = /* @__PURE__ */ new Set([
|
|
172
|
+
"ar",
|
|
173
|
+
"he",
|
|
174
|
+
"iw",
|
|
175
|
+
"fa",
|
|
176
|
+
"ur",
|
|
177
|
+
"ps",
|
|
178
|
+
"sd",
|
|
179
|
+
"ug",
|
|
180
|
+
"yi"
|
|
181
|
+
]);
|
|
182
|
+
const SUPPORTED_CALENDAR_LOCALES = [
|
|
183
|
+
{
|
|
184
|
+
code: "en",
|
|
185
|
+
label: "English",
|
|
186
|
+
nativeName: "English",
|
|
187
|
+
direction: "ltr",
|
|
188
|
+
week: { dow: 0, doy: 4 },
|
|
189
|
+
buttonText: {
|
|
190
|
+
prev: "Prev",
|
|
191
|
+
next: "Next",
|
|
192
|
+
today: "Today",
|
|
193
|
+
year: "Year",
|
|
194
|
+
month: "Month",
|
|
195
|
+
week: "Week",
|
|
196
|
+
day: "Day",
|
|
197
|
+
list: "Agenda"
|
|
198
|
+
},
|
|
199
|
+
weekText: "Wk",
|
|
200
|
+
allDayText: "all-day",
|
|
201
|
+
moreLinkText: "more",
|
|
202
|
+
noEventsText: "No events to display"
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
code: "es",
|
|
206
|
+
label: "Spanish",
|
|
207
|
+
nativeName: "Español",
|
|
208
|
+
direction: "ltr",
|
|
209
|
+
week: { dow: 1, doy: 4 },
|
|
210
|
+
buttonText: {
|
|
211
|
+
prev: "Ant",
|
|
212
|
+
next: "Sig",
|
|
213
|
+
today: "Hoy",
|
|
214
|
+
year: "Año",
|
|
215
|
+
month: "Mes",
|
|
216
|
+
week: "Semana",
|
|
217
|
+
day: "Día",
|
|
218
|
+
list: "Agenda"
|
|
219
|
+
},
|
|
220
|
+
weekText: "Sm",
|
|
221
|
+
allDayText: "todo el día",
|
|
222
|
+
moreLinkText: "más",
|
|
223
|
+
noEventsText: "No hay eventos para mostrar"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
code: "fr",
|
|
227
|
+
label: "French",
|
|
228
|
+
nativeName: "Français",
|
|
229
|
+
direction: "ltr",
|
|
230
|
+
week: { dow: 1, doy: 4 },
|
|
231
|
+
buttonText: {
|
|
232
|
+
prev: "Préc",
|
|
233
|
+
next: "Suiv",
|
|
234
|
+
today: "Aujourd'hui",
|
|
235
|
+
year: "Année",
|
|
236
|
+
month: "Mois",
|
|
237
|
+
week: "Semaine",
|
|
238
|
+
day: "Jour",
|
|
239
|
+
list: "Planning"
|
|
240
|
+
},
|
|
241
|
+
weekText: "Sem.",
|
|
242
|
+
allDayText: "toute la journée",
|
|
243
|
+
moreLinkText: "en plus",
|
|
244
|
+
noEventsText: "Aucun événement à afficher"
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
code: "de",
|
|
248
|
+
label: "German",
|
|
249
|
+
nativeName: "Deutsch",
|
|
250
|
+
direction: "ltr",
|
|
251
|
+
week: { dow: 1, doy: 4 },
|
|
252
|
+
buttonText: {
|
|
253
|
+
prev: "Zurück",
|
|
254
|
+
next: "Weiter",
|
|
255
|
+
today: "Heute",
|
|
256
|
+
year: "Jahr",
|
|
257
|
+
month: "Monat",
|
|
258
|
+
week: "Woche",
|
|
259
|
+
day: "Tag",
|
|
260
|
+
list: "Terminübersicht"
|
|
261
|
+
},
|
|
262
|
+
weekText: "KW",
|
|
263
|
+
allDayText: "ganztägig",
|
|
264
|
+
moreLinkText: "weitere",
|
|
265
|
+
noEventsText: "Keine Ereignisse anzuzeigen"
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
code: "pt",
|
|
269
|
+
label: "Portuguese",
|
|
270
|
+
nativeName: "Português",
|
|
271
|
+
direction: "ltr",
|
|
272
|
+
week: { dow: 0, doy: 4 },
|
|
273
|
+
buttonText: {
|
|
274
|
+
prev: "Ant",
|
|
275
|
+
next: "Próx",
|
|
276
|
+
today: "Hoje",
|
|
277
|
+
year: "Ano",
|
|
278
|
+
month: "Mês",
|
|
279
|
+
week: "Semana",
|
|
280
|
+
day: "Dia",
|
|
281
|
+
list: "Agenda"
|
|
282
|
+
},
|
|
283
|
+
weekText: "Sem",
|
|
284
|
+
allDayText: "dia inteiro",
|
|
285
|
+
moreLinkText: "mais",
|
|
286
|
+
noEventsText: "Não há eventos para mostrar"
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
code: "it",
|
|
290
|
+
label: "Italian",
|
|
291
|
+
nativeName: "Italiano",
|
|
292
|
+
direction: "ltr",
|
|
293
|
+
week: { dow: 1, doy: 4 },
|
|
294
|
+
buttonText: {
|
|
295
|
+
prev: "Prec",
|
|
296
|
+
next: "Succ",
|
|
297
|
+
today: "Oggi",
|
|
298
|
+
year: "Anno",
|
|
299
|
+
month: "Mese",
|
|
300
|
+
week: "Settimana",
|
|
301
|
+
day: "Giorno",
|
|
302
|
+
list: "Agenda"
|
|
303
|
+
},
|
|
304
|
+
weekText: "Set",
|
|
305
|
+
allDayText: "tutto il giorno",
|
|
306
|
+
moreLinkText: "altri",
|
|
307
|
+
noEventsText: "Non ci sono eventi da visualizzare"
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
code: "nl",
|
|
311
|
+
label: "Dutch",
|
|
312
|
+
nativeName: "Nederlands",
|
|
313
|
+
direction: "ltr",
|
|
314
|
+
week: { dow: 1, doy: 4 },
|
|
315
|
+
buttonText: {
|
|
316
|
+
prev: "Vorige",
|
|
317
|
+
next: "Volgende",
|
|
318
|
+
today: "Vandaag",
|
|
319
|
+
year: "Jaar",
|
|
320
|
+
month: "Maand",
|
|
321
|
+
week: "Week",
|
|
322
|
+
day: "Dag",
|
|
323
|
+
list: "Lijst"
|
|
324
|
+
},
|
|
325
|
+
weekText: "Wk",
|
|
326
|
+
allDayText: "hele dag",
|
|
327
|
+
moreLinkText: "extra",
|
|
328
|
+
noEventsText: "Geen evenementen om te laten zien"
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
code: "pl",
|
|
332
|
+
label: "Polish",
|
|
333
|
+
nativeName: "Polski",
|
|
334
|
+
direction: "ltr",
|
|
335
|
+
week: { dow: 1, doy: 4 },
|
|
336
|
+
buttonText: {
|
|
337
|
+
prev: "Poprzedni",
|
|
338
|
+
next: "Następny",
|
|
339
|
+
today: "Dziś",
|
|
340
|
+
year: "Rok",
|
|
341
|
+
month: "Miesiąc",
|
|
342
|
+
week: "Tydzień",
|
|
343
|
+
day: "Dzień",
|
|
344
|
+
list: "Plan dnia"
|
|
345
|
+
},
|
|
346
|
+
weekText: "Tydz",
|
|
347
|
+
allDayText: "cały dzień",
|
|
348
|
+
moreLinkText: "więcej",
|
|
349
|
+
noEventsText: "Brak wydarzeń do wyświetlenia"
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
code: "tr",
|
|
353
|
+
label: "Turkish",
|
|
354
|
+
nativeName: "Türkçe",
|
|
355
|
+
direction: "ltr",
|
|
356
|
+
week: { dow: 1, doy: 7 },
|
|
357
|
+
buttonText: {
|
|
358
|
+
prev: "geri",
|
|
359
|
+
next: "ileri",
|
|
360
|
+
today: "bugün",
|
|
361
|
+
year: "Yıl",
|
|
362
|
+
month: "Ay",
|
|
363
|
+
week: "Hafta",
|
|
364
|
+
day: "Gün",
|
|
365
|
+
list: "Ajanda"
|
|
366
|
+
},
|
|
367
|
+
weekText: "Hf",
|
|
368
|
+
allDayText: "tüm gün",
|
|
369
|
+
moreLinkText: "daha fazla",
|
|
370
|
+
noEventsText: "Gösterilecek etkinlik yok"
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
code: "ar",
|
|
374
|
+
label: "Arabic",
|
|
375
|
+
nativeName: "العربية",
|
|
376
|
+
direction: "rtl",
|
|
377
|
+
week: { dow: 6, doy: 12 },
|
|
378
|
+
buttonText: {
|
|
379
|
+
prev: "السابق",
|
|
380
|
+
next: "التالي",
|
|
381
|
+
today: "اليوم",
|
|
382
|
+
year: "سنة",
|
|
383
|
+
month: "شهر",
|
|
384
|
+
week: "أسبوع",
|
|
385
|
+
day: "يوم",
|
|
386
|
+
list: "أجندة"
|
|
387
|
+
},
|
|
388
|
+
weekText: "أسبوع",
|
|
389
|
+
allDayText: "اليوم كله",
|
|
390
|
+
moreLinkText: "أخرى",
|
|
391
|
+
noEventsText: "أي أحداث لعرض"
|
|
392
|
+
}
|
|
393
|
+
];
|
|
394
|
+
function normalizeLocaleCode(locale) {
|
|
395
|
+
if (!locale || typeof locale !== "string") {
|
|
396
|
+
return "en";
|
|
397
|
+
}
|
|
398
|
+
const cleaned = locale.trim().toLowerCase().replace("_", "-");
|
|
399
|
+
if (!cleaned || cleaned === "auto") {
|
|
400
|
+
return "en";
|
|
401
|
+
}
|
|
402
|
+
const exact = SUPPORTED_CALENDAR_LOCALES.find((l) => l.code === cleaned);
|
|
403
|
+
if (exact) {
|
|
404
|
+
return exact.code;
|
|
405
|
+
}
|
|
406
|
+
const baseLang = cleaned.split("-")[0];
|
|
407
|
+
const baseMatch = SUPPORTED_CALENDAR_LOCALES.find((l) => l.code === baseLang);
|
|
408
|
+
return baseMatch ? baseMatch.code : baseLang || "en";
|
|
409
|
+
}
|
|
410
|
+
function isRtlLocale(locale) {
|
|
411
|
+
const normalized = normalizeLocaleCode(locale);
|
|
412
|
+
const baseLang = normalized.split("-")[0];
|
|
413
|
+
return RTL_LANGUAGE_PREFIXES.has(baseLang);
|
|
414
|
+
}
|
|
415
|
+
function getLocalizedCalendarBundle(locale) {
|
|
416
|
+
const code = normalizeLocaleCode(locale);
|
|
417
|
+
return SUPPORTED_CALENDAR_LOCALES.find((l) => l.code === code) ?? SUPPORTED_CALENDAR_LOCALES[0];
|
|
418
|
+
}
|
|
419
|
+
function resolveFullCalendarLocale(uiLocale, defaultLocaleSetting, runtimeOverrideLocale) {
|
|
420
|
+
if (runtimeOverrideLocale && runtimeOverrideLocale !== "auto" && runtimeOverrideLocale.trim()) {
|
|
421
|
+
return normalizeLocaleCode(runtimeOverrideLocale);
|
|
422
|
+
}
|
|
423
|
+
if (defaultLocaleSetting && defaultLocaleSetting !== "auto" && defaultLocaleSetting.trim()) {
|
|
424
|
+
return normalizeLocaleCode(defaultLocaleSetting);
|
|
425
|
+
}
|
|
426
|
+
return normalizeLocaleCode(uiLocale || "en");
|
|
427
|
+
}
|
|
428
|
+
function resolveCalendarDirection(locale, directionSetting) {
|
|
429
|
+
if (directionSetting === "ltr" || directionSetting === "rtl") {
|
|
430
|
+
return directionSetting;
|
|
431
|
+
}
|
|
432
|
+
return isRtlLocale(locale) ? "rtl" : "ltr";
|
|
433
|
+
}
|
|
434
|
+
function resolveLocaleFirstDay(locale, configuredFirstDay) {
|
|
435
|
+
if (typeof configuredFirstDay === "number" && configuredFirstDay >= 0 && configuredFirstDay <= 6) {
|
|
436
|
+
return configuredFirstDay;
|
|
437
|
+
}
|
|
438
|
+
const bundle = getLocalizedCalendarBundle(locale);
|
|
439
|
+
return bundle.week.dow;
|
|
440
|
+
}
|
|
441
|
+
function buildFullCalendarTimeFormat(timeFormat24h = true) {
|
|
442
|
+
if (timeFormat24h) {
|
|
443
|
+
return {
|
|
444
|
+
hour: "2-digit",
|
|
445
|
+
minute: "2-digit",
|
|
446
|
+
meridiem: false,
|
|
447
|
+
hour12: false
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
return {
|
|
451
|
+
hour: "numeric",
|
|
452
|
+
minute: "2-digit",
|
|
453
|
+
meridiem: "short",
|
|
454
|
+
hour12: true
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
const SUPPORTED_INTL_CALENDARS = [
|
|
458
|
+
{ id: "gregory", intlCalendar: "gregory", defaultLabel: "Gregorian" },
|
|
459
|
+
{ id: "iso8601", intlCalendar: "iso8601", defaultLabel: "ISO 8601" },
|
|
460
|
+
{
|
|
461
|
+
id: "islamic-umalqura",
|
|
462
|
+
intlCalendar: "islamic-umalqura",
|
|
463
|
+
defaultLabel: "Hijri (Umm al-Qura)"
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
id: "islamic-civil",
|
|
467
|
+
intlCalendar: "islamic-civil",
|
|
468
|
+
defaultLabel: "Hijri (Civil)"
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
id: "islamic-tbla",
|
|
472
|
+
intlCalendar: "islamic-tbla",
|
|
473
|
+
defaultLabel: "Hijri (Tabular)"
|
|
474
|
+
},
|
|
475
|
+
{ id: "hebrew", intlCalendar: "hebrew", defaultLabel: "Hebrew" },
|
|
476
|
+
{
|
|
477
|
+
id: "persian",
|
|
478
|
+
intlCalendar: "persian",
|
|
479
|
+
defaultLabel: "Persian (Solar Hijri)"
|
|
480
|
+
},
|
|
481
|
+
{ id: "buddhist", intlCalendar: "buddhist", defaultLabel: "Buddhist" },
|
|
482
|
+
{ id: "japanese", intlCalendar: "japanese", defaultLabel: "Japanese" },
|
|
483
|
+
{ id: "chinese", intlCalendar: "chinese", defaultLabel: "Chinese Lunar" },
|
|
484
|
+
{ id: "indian", intlCalendar: "indian", defaultLabel: "Indian National" },
|
|
485
|
+
{ id: "coptic", intlCalendar: "coptic", defaultLabel: "Coptic" },
|
|
486
|
+
{ id: "ethiopic", intlCalendar: "ethiopic", defaultLabel: "Ethiopic" }
|
|
487
|
+
];
|
|
488
|
+
const customFormatters = /* @__PURE__ */ new Map();
|
|
489
|
+
function applyDayOffset(date, dayOffset) {
|
|
490
|
+
if (!dayOffset || !Number.isFinite(dayOffset)) {
|
|
491
|
+
return date;
|
|
492
|
+
}
|
|
493
|
+
const offsetDays = Math.trunc(dayOffset);
|
|
494
|
+
return new Date(date.getTime() + offsetDays * 864e5);
|
|
495
|
+
}
|
|
496
|
+
const intlFormatterCache = /* @__PURE__ */ new Map();
|
|
497
|
+
function getCachedIntlFormatter(locale, options) {
|
|
498
|
+
const key = `${locale}|${options.year ?? ""}|${options.month ?? ""}|${options.day ?? ""}|${options.timeZone ?? "UTC"}`;
|
|
499
|
+
let fmt = intlFormatterCache.get(key);
|
|
500
|
+
if (!fmt) {
|
|
501
|
+
if (intlFormatterCache.size >= 200) {
|
|
502
|
+
const oldestKey = intlFormatterCache.keys().next().value;
|
|
503
|
+
if (oldestKey !== void 0) intlFormatterCache.delete(oldestKey);
|
|
504
|
+
}
|
|
505
|
+
fmt = new Intl.DateTimeFormat(locale, options);
|
|
506
|
+
intlFormatterCache.set(key, fmt);
|
|
507
|
+
}
|
|
508
|
+
return fmt;
|
|
509
|
+
}
|
|
510
|
+
function resolveCalendarLocaleTag(systemLocale, fallbackLocale) {
|
|
511
|
+
const rawLocale = systemLocale && systemLocale !== "auto" ? systemLocale : fallbackLocale && fallbackLocale !== "auto" ? fallbackLocale : "en";
|
|
512
|
+
return rawLocale.split("-u-")[0];
|
|
513
|
+
}
|
|
514
|
+
function tryFormatWithCustomFormatter(effectiveDate, system, effectiveLocale, compact) {
|
|
515
|
+
const customFn = customFormatters.get(system.id) ?? customFormatters.get(system.intlCalendar);
|
|
516
|
+
if (!customFn) return null;
|
|
517
|
+
try {
|
|
518
|
+
return customFn(effectiveDate, {
|
|
519
|
+
locale: effectiveLocale,
|
|
520
|
+
system,
|
|
521
|
+
compact
|
|
522
|
+
});
|
|
523
|
+
} catch {
|
|
524
|
+
return null;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
function formatWithIntlFallback(effectiveDate, isoOrDateKey, intlLocale, compact) {
|
|
528
|
+
try {
|
|
529
|
+
const formatter = getCachedIntlFormatter(
|
|
530
|
+
intlLocale,
|
|
531
|
+
compact ? { day: "numeric", month: "short", timeZone: "UTC" } : { day: "numeric", month: "long", year: "numeric", timeZone: "UTC" }
|
|
532
|
+
);
|
|
533
|
+
return formatter.format(effectiveDate);
|
|
534
|
+
} catch {
|
|
535
|
+
try {
|
|
536
|
+
const fallback = getCachedIntlFormatter("en-u-ca-gregory", {
|
|
537
|
+
day: "numeric",
|
|
538
|
+
month: "short",
|
|
539
|
+
year: "numeric",
|
|
540
|
+
timeZone: "UTC"
|
|
541
|
+
});
|
|
542
|
+
return fallback.format(effectiveDate);
|
|
543
|
+
} catch {
|
|
544
|
+
return isoOrDateKey.slice(0, 10);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
function formatDateInCalendarSystem(isoOrDateKey, system, locale = "en", options) {
|
|
549
|
+
const rawDate = /^\d{4}-\d{2}-\d{2}$/.test(isoOrDateKey) ? /* @__PURE__ */ new Date(`${isoOrDateKey}T12:00:00.000Z`) : new Date(isoOrDateKey);
|
|
550
|
+
if (Number.isNaN(rawDate.getTime())) {
|
|
551
|
+
return "";
|
|
552
|
+
}
|
|
553
|
+
const effectiveDate = applyDayOffset(rawDate, system.dayOffset);
|
|
554
|
+
const effectiveLocale = resolveCalendarLocaleTag(system.locale, locale);
|
|
555
|
+
const compact = Boolean(options?.compact);
|
|
556
|
+
const customResult = tryFormatWithCustomFormatter(
|
|
557
|
+
effectiveDate,
|
|
558
|
+
system,
|
|
559
|
+
effectiveLocale,
|
|
560
|
+
compact
|
|
561
|
+
);
|
|
562
|
+
if (customResult !== null) {
|
|
563
|
+
return customResult;
|
|
564
|
+
}
|
|
565
|
+
const calendarTag = (system.intlCalendar || "gregory").trim();
|
|
566
|
+
return formatWithIntlFallback(
|
|
567
|
+
effectiveDate,
|
|
568
|
+
isoOrDateKey,
|
|
569
|
+
`${effectiveLocale}-u-ca-${calendarTag}`,
|
|
570
|
+
compact
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
const FALLBACK_RECURRENCE_PRESETS = [
|
|
574
|
+
{ id: "daily", label: "Daily", rrule: "FREQ=DAILY;INTERVAL=1" },
|
|
575
|
+
{
|
|
576
|
+
id: "weekly-mon",
|
|
577
|
+
label: "Weekly on Mondays",
|
|
578
|
+
rrule: "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO"
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
id: "weekly-tue",
|
|
582
|
+
label: "Weekly on Tuesdays",
|
|
583
|
+
rrule: "FREQ=WEEKLY;INTERVAL=1;BYDAY=TU"
|
|
584
|
+
},
|
|
585
|
+
{
|
|
586
|
+
id: "weekly-wed",
|
|
587
|
+
label: "Weekly on Wednesdays",
|
|
588
|
+
rrule: "FREQ=WEEKLY;INTERVAL=1;BYDAY=WE"
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
id: "weekly-thu",
|
|
592
|
+
label: "Weekly on Thursdays",
|
|
593
|
+
rrule: "FREQ=WEEKLY;INTERVAL=1;BYDAY=TH"
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
id: "weekly-fri",
|
|
597
|
+
label: "Weekly on Fridays",
|
|
598
|
+
rrule: "FREQ=WEEKLY;INTERVAL=1;BYDAY=FR"
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
id: "weekly-sat",
|
|
602
|
+
label: "Weekly on Saturdays",
|
|
603
|
+
rrule: "FREQ=WEEKLY;INTERVAL=1;BYDAY=SA"
|
|
604
|
+
},
|
|
605
|
+
{
|
|
606
|
+
id: "weekly-sun",
|
|
607
|
+
label: "Weekly on Sundays",
|
|
608
|
+
rrule: "FREQ=WEEKLY;INTERVAL=1;BYDAY=SU"
|
|
609
|
+
},
|
|
610
|
+
{ id: "monthly", label: "Monthly", rrule: "FREQ=MONTHLY;INTERVAL=1" },
|
|
611
|
+
{ id: "yearly", label: "Yearly", rrule: "FREQ=YEARLY;INTERVAL=1" }
|
|
612
|
+
];
|
|
613
|
+
const WEEKDAYS$1 = [
|
|
614
|
+
{ code: "MO", label: "Mon", fullName: "Monday", jsDay: 1 },
|
|
615
|
+
{ code: "TU", label: "Tue", fullName: "Tuesday", jsDay: 2 },
|
|
616
|
+
{ code: "WE", label: "Wed", fullName: "Wednesday", jsDay: 3 },
|
|
617
|
+
{ code: "TH", label: "Thu", fullName: "Thursday", jsDay: 4 },
|
|
618
|
+
{ code: "FR", label: "Fri", fullName: "Friday", jsDay: 5 },
|
|
619
|
+
{ code: "SA", label: "Sat", fullName: "Saturday", jsDay: 6 },
|
|
620
|
+
{ code: "SU", label: "Sun", fullName: "Sunday", jsDay: 0 }
|
|
621
|
+
];
|
|
622
|
+
function parseOptionalStartDate(startDate) {
|
|
623
|
+
if (typeof startDate === "string" && startDate.trim()) {
|
|
624
|
+
const d = new Date(startDate);
|
|
625
|
+
return Number.isNaN(d.getTime()) ? void 0 : d;
|
|
626
|
+
}
|
|
627
|
+
if (startDate instanceof Date && !Number.isNaN(startDate.getTime())) {
|
|
628
|
+
return startDate;
|
|
629
|
+
}
|
|
630
|
+
return void 0;
|
|
631
|
+
}
|
|
632
|
+
function buildOrderedRecurrencePresets(recurrencePresets, startDate) {
|
|
633
|
+
const byRRule = /* @__PURE__ */ new Map();
|
|
634
|
+
for (const def of FALLBACK_RECURRENCE_PRESETS) {
|
|
635
|
+
byRRule.set(def.rrule, def);
|
|
636
|
+
}
|
|
637
|
+
for (const p of recurrencePresets) {
|
|
638
|
+
if (p?.rrule) byRRule.set(p.rrule, p);
|
|
639
|
+
}
|
|
640
|
+
const parsedDate = parseOptionalStartDate(startDate);
|
|
641
|
+
const activeWeekday = parsedDate ? WEEKDAYS$1.find((w) => w.jsDay === parsedDate.getDay()) : void 0;
|
|
642
|
+
const result = [];
|
|
643
|
+
if (activeWeekday) {
|
|
644
|
+
const activeWeeklyRRule = `FREQ=WEEKLY;INTERVAL=1;BYDAY=${activeWeekday.code}`;
|
|
645
|
+
result.push({
|
|
646
|
+
id: `every-${activeWeekday.code.toLowerCase()}`,
|
|
647
|
+
label: `Every ${activeWeekday.fullName}`,
|
|
648
|
+
rrule: activeWeeklyRRule
|
|
649
|
+
});
|
|
650
|
+
byRRule.delete(activeWeeklyRRule);
|
|
651
|
+
}
|
|
652
|
+
for (const coreRRule of [
|
|
653
|
+
"FREQ=DAILY;INTERVAL=1",
|
|
654
|
+
"FREQ=MONTHLY;INTERVAL=1",
|
|
655
|
+
"FREQ=YEARLY;INTERVAL=1"
|
|
656
|
+
]) {
|
|
657
|
+
const preset = byRRule.get(coreRRule);
|
|
658
|
+
if (preset) {
|
|
659
|
+
result.push(preset);
|
|
660
|
+
byRRule.delete(coreRRule);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
for (const preset of byRRule.values()) {
|
|
664
|
+
result.push(preset);
|
|
665
|
+
}
|
|
666
|
+
return result;
|
|
667
|
+
}
|
|
668
|
+
const VALID_WEEKDAY_CODES = new Set(WEEKDAYS$1.map((w) => w.code));
|
|
669
|
+
function extractByDays(rrule) {
|
|
670
|
+
const match = rrule.match(/BYDAY=([A-Z,]+)/i);
|
|
671
|
+
if (!match?.[1]) return [];
|
|
672
|
+
return match[1].toUpperCase().split(",").map((d) => d.trim()).filter((d) => VALID_WEEKDAY_CODES.has(d));
|
|
673
|
+
}
|
|
674
|
+
function formatCategoryLabel(category) {
|
|
675
|
+
const trimmed = category.trim();
|
|
676
|
+
if (!trimmed) return "";
|
|
677
|
+
return trimmed.split(/[\s_-]+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
678
|
+
}
|
|
679
|
+
function parseDateTimePickerValue(raw) {
|
|
680
|
+
if (!raw || !raw.trim()) return void 0;
|
|
681
|
+
const trimmed = raw.trim();
|
|
682
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
|
|
683
|
+
const [y, m, d] = trimmed.split("-").map(Number);
|
|
684
|
+
const localDt = new Date(y, m - 1, d, 9, 0, 0, 0);
|
|
685
|
+
return Number.isNaN(localDt.getTime()) ? void 0 : localDt;
|
|
686
|
+
}
|
|
687
|
+
const dt = new Date(trimmed);
|
|
688
|
+
return Number.isNaN(dt.getTime()) ? void 0 : dt;
|
|
689
|
+
}
|
|
690
|
+
function formatLocalYmd(date) {
|
|
691
|
+
const y = date.getFullYear();
|
|
692
|
+
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
693
|
+
const d = String(date.getDate()).padStart(2, "0");
|
|
694
|
+
return `${y}-${m}-${d}`;
|
|
695
|
+
}
|
|
696
|
+
function alignStartDateToWeekday(startStr, targetCode) {
|
|
697
|
+
if (!startStr) return startStr;
|
|
698
|
+
const target = WEEKDAYS$1.find((w) => w.code === targetCode);
|
|
699
|
+
if (!target) return startStr;
|
|
700
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(startStr)) {
|
|
701
|
+
const dt2 = /* @__PURE__ */ new Date(`${startStr}T00:00:00.000Z`);
|
|
702
|
+
if (Number.isNaN(dt2.getTime())) return startStr;
|
|
703
|
+
const currentDay2 = dt2.getUTCDay();
|
|
704
|
+
const diff2 = (target.jsDay - currentDay2 + 7) % 7;
|
|
705
|
+
if (diff2 === 0) return startStr;
|
|
706
|
+
dt2.setUTCDate(dt2.getUTCDate() + diff2);
|
|
707
|
+
return dt2.toISOString().slice(0, 10);
|
|
708
|
+
}
|
|
709
|
+
const dt = new Date(startStr);
|
|
710
|
+
if (Number.isNaN(dt.getTime())) return startStr;
|
|
711
|
+
const currentDay = dt.getDay();
|
|
712
|
+
const diff = (target.jsDay - currentDay + 7) % 7;
|
|
713
|
+
if (diff === 0) return startStr;
|
|
714
|
+
dt.setDate(dt.getDate() + diff);
|
|
715
|
+
return dt.toISOString();
|
|
716
|
+
}
|
|
717
|
+
function buildInitialDateWindow() {
|
|
718
|
+
const now = /* @__PURE__ */ new Date();
|
|
719
|
+
const y = now.getUTCFullYear();
|
|
720
|
+
return {
|
|
721
|
+
from: new Date(Date.UTC(y, 0, 1, 0, 0, 0)).toISOString(),
|
|
722
|
+
to: new Date(Date.UTC(y, 11, 31, 23, 59, 59)).toISOString()
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
function expandDateWindowToYear(currentStart, fromIso, toIso) {
|
|
726
|
+
const year = currentStart.getUTCFullYear();
|
|
727
|
+
const yearStart = new Date(Date.UTC(year, 0, 1, 0, 0, 0)).toISOString();
|
|
728
|
+
const yearEnd = new Date(Date.UTC(year, 11, 31, 23, 59, 59)).toISOString();
|
|
729
|
+
return {
|
|
730
|
+
from: fromIso < yearStart ? fromIso : yearStart,
|
|
731
|
+
to: toIso > yearEnd ? toIso : yearEnd
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
function matchLoadedSourceId(loadedSources, sourceFilter) {
|
|
735
|
+
if (!sourceFilter || sourceFilter === "all") return null;
|
|
736
|
+
if (loadedSources.some((s) => s.id === sourceFilter)) return sourceFilter;
|
|
737
|
+
const matched = loadedSources.find(
|
|
738
|
+
(s) => s.uid === sourceFilter || sourceFilter === "events" && (s.id.includes("event") || s.uid.includes("event")) || sourceFilter === "bookings" && (s.id.includes("booking") || s.uid.includes("booking"))
|
|
739
|
+
);
|
|
740
|
+
return matched ? matched.id : null;
|
|
741
|
+
}
|
|
742
|
+
function normalizeSelectedEndSlot(startStr, endStr) {
|
|
743
|
+
if (!endStr) return "";
|
|
744
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(startStr) && /^\d{4}-\d{2}-\d{2}$/.test(endStr)) {
|
|
745
|
+
const startMs = (/* @__PURE__ */ new Date(`${startStr}T00:00:00.000Z`)).getTime();
|
|
746
|
+
const endMs = (/* @__PURE__ */ new Date(`${endStr}T00:00:00.000Z`)).getTime();
|
|
747
|
+
if (!Number.isNaN(startMs) && !Number.isNaN(endMs) && endMs - startMs <= 864e5) {
|
|
748
|
+
return "";
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
return endStr;
|
|
752
|
+
}
|
|
753
|
+
function resolveActiveSecondaryCalendars(secondaryLangMode, configuredCalendars) {
|
|
754
|
+
if (secondaryLangMode === "off") {
|
|
755
|
+
return [];
|
|
756
|
+
}
|
|
757
|
+
const configured = (configuredCalendars ?? []).filter((c) => c.enabled);
|
|
758
|
+
if (configured.length > 0) {
|
|
759
|
+
return configured;
|
|
760
|
+
}
|
|
761
|
+
const hijriMatch = SUPPORTED_INTL_CALENDARS.find(
|
|
762
|
+
(c) => c.id === "islamic-umalqura"
|
|
763
|
+
);
|
|
764
|
+
return hijriMatch ? [
|
|
765
|
+
{
|
|
766
|
+
id: "hijri",
|
|
767
|
+
label: hijriMatch.defaultLabel,
|
|
768
|
+
intlCalendar: hijriMatch.intlCalendar,
|
|
769
|
+
enabled: true
|
|
770
|
+
}
|
|
771
|
+
] : [];
|
|
772
|
+
}
|
|
773
|
+
function filterVisibleOccurrences(occurrences, sourceFilter) {
|
|
774
|
+
if (sourceFilter === "all") return occurrences;
|
|
775
|
+
return occurrences.filter(
|
|
776
|
+
(occ) => occ.sourceId === sourceFilter || occ.uid === sourceFilter || sourceFilter === "events" && (occ.sourceId.includes("event") || occ.uid.includes("event")) || sourceFilter === "bookings" && (occ.sourceId.includes("booking") || occ.uid.includes("booking"))
|
|
777
|
+
);
|
|
778
|
+
}
|
|
779
|
+
function computeSourceCounts(occurrences, sources) {
|
|
780
|
+
const counts = {};
|
|
781
|
+
for (const src of sources ?? []) {
|
|
782
|
+
counts[src.id] = 0;
|
|
783
|
+
}
|
|
784
|
+
for (const occ of occurrences) {
|
|
785
|
+
counts[occ.sourceId] = (counts[occ.sourceId] ?? 0) + 1;
|
|
786
|
+
}
|
|
787
|
+
return counts;
|
|
788
|
+
}
|
|
789
|
+
function buildSecondaryHeaderLabel(activeSecondaryCalendars, anchorDate, effectiveLocale, secondaryLangMode) {
|
|
790
|
+
if (activeSecondaryCalendars.length === 0 || secondaryLangMode === "off")
|
|
791
|
+
return "";
|
|
792
|
+
const anchorIso = anchorDate.toISOString().slice(0, 10);
|
|
793
|
+
const targetLoc = secondaryLangMode === "ar" ? "ar-SA" : effectiveLocale;
|
|
794
|
+
return activeSecondaryCalendars.map((sys) => {
|
|
795
|
+
const formatted = formatDateInCalendarSystem(
|
|
796
|
+
anchorIso,
|
|
797
|
+
{ ...sys, locale: targetLoc },
|
|
798
|
+
targetLoc,
|
|
799
|
+
{ compact: false }
|
|
800
|
+
);
|
|
801
|
+
return formatted ? `${sys.label}: ${formatted}` : "";
|
|
802
|
+
}).filter(Boolean).join(" • ");
|
|
803
|
+
}
|
|
804
|
+
function buildEnabledCalendarViews(settings, effectiveLocale) {
|
|
805
|
+
const b = getLocalizedCalendarBundle(effectiveLocale).buttonText;
|
|
806
|
+
const list = [];
|
|
807
|
+
if (settings?.monthView !== false)
|
|
808
|
+
list.push({ mode: "dayGridMonth", label: b.month });
|
|
809
|
+
if (settings?.weekView !== false)
|
|
810
|
+
list.push({ mode: "timeGridWeek", label: b.week });
|
|
811
|
+
if (settings?.dayView !== false)
|
|
812
|
+
list.push({ mode: "timeGridDay", label: b.day });
|
|
813
|
+
if (settings?.agendaView !== false)
|
|
814
|
+
list.push({ mode: "listMonth", label: b.list });
|
|
815
|
+
if (settings?.yearView !== false)
|
|
816
|
+
list.push({ mode: "multiMonthYear", label: b.year });
|
|
817
|
+
return list;
|
|
818
|
+
}
|
|
819
|
+
function toExclusiveAllDayEnd(startDate, endDate) {
|
|
820
|
+
const sDay = startDate.slice(0, 10);
|
|
821
|
+
const eDay = (endDate || startDate).slice(0, 10);
|
|
822
|
+
const baseDay = eDay >= sDay ? eDay : sDay;
|
|
823
|
+
const dt = /* @__PURE__ */ new Date(`${baseDay}T00:00:00.000Z`);
|
|
824
|
+
if (Number.isNaN(dt.getTime())) return endDate || startDate;
|
|
825
|
+
dt.setUTCDate(dt.getUTCDate() + 1);
|
|
826
|
+
return dt.toISOString().slice(0, 10);
|
|
827
|
+
}
|
|
828
|
+
function mapOccurrencesToFullCalendarEvents(occurrences, primaryColor) {
|
|
829
|
+
const fallbackColor = primaryColor || "#0284C7";
|
|
830
|
+
return occurrences.map((occ) => ({
|
|
831
|
+
id: occ.occurrenceId,
|
|
832
|
+
title: occ.title,
|
|
833
|
+
start: occ.allDay ? occ.startDate.slice(0, 10) : occ.startDate,
|
|
834
|
+
end: occ.allDay ? toExclusiveAllDayEnd(occ.startDate, occ.endDate) : occ.endDate,
|
|
835
|
+
allDay: occ.allDay,
|
|
836
|
+
backgroundColor: occ.color || fallbackColor,
|
|
837
|
+
borderColor: occ.color || fallbackColor,
|
|
838
|
+
extendedProps: { occurrence: occ }
|
|
839
|
+
}));
|
|
840
|
+
}
|
|
841
|
+
function addSourceCategoryKeys(cats, src, sourceFilter) {
|
|
842
|
+
if (src.enabled === false || sourceFilter && src.id !== sourceFilter)
|
|
843
|
+
return;
|
|
844
|
+
for (const key of Object.keys(src.categoryColors ?? {})) {
|
|
845
|
+
if (key) cats.add(key);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
function collectAvailableCategories(sources, sourceFilter, visibleOccurrences) {
|
|
849
|
+
const cats = /* @__PURE__ */ new Set();
|
|
850
|
+
for (const src of sources ?? []) {
|
|
851
|
+
addSourceCategoryKeys(cats, src, sourceFilter);
|
|
852
|
+
}
|
|
853
|
+
for (const occ of visibleOccurrences) {
|
|
854
|
+
if (occ.category) cats.add(occ.category);
|
|
855
|
+
}
|
|
856
|
+
return Array.from(cats);
|
|
857
|
+
}
|
|
858
|
+
function computeStartEndIsoPair(quickStart, quickEnd) {
|
|
859
|
+
const startIso = quickStart.includes("T") ? new Date(quickStart).toISOString() : `${quickStart}T10:00:00.000Z`;
|
|
860
|
+
const hasValidEnd = Boolean(quickEnd) && !Number.isNaN(new Date(quickEnd).getTime());
|
|
861
|
+
const endIso = hasValidEnd ? new Date(quickEnd).toISOString() : new Date(new Date(startIso).getTime() + 36e5).toISOString();
|
|
862
|
+
return { startIso, endIso };
|
|
863
|
+
}
|
|
864
|
+
function buildQuickCreateRequestPayload(args) {
|
|
865
|
+
const { startIso, endIso } = computeStartEndIsoPair(
|
|
866
|
+
args.quickStart,
|
|
867
|
+
args.quickEnd
|
|
868
|
+
);
|
|
869
|
+
const targetSource = args.quickSourceId || (args.sourceFilter !== "all" ? args.sourceFilter : void 0);
|
|
870
|
+
return {
|
|
871
|
+
sourceId: targetSource,
|
|
872
|
+
title: args.quickTitle.trim(),
|
|
873
|
+
startDate: startIso,
|
|
874
|
+
endDate: endIso,
|
|
875
|
+
location: args.quickLocation.trim() || void 0,
|
|
876
|
+
category: args.quickCategory,
|
|
877
|
+
rrule: args.quickRRule || void 0,
|
|
878
|
+
customerName: args.quickCustomerName.trim() || void 0,
|
|
879
|
+
customerEmail: args.quickCustomerEmail.trim() || void 0,
|
|
880
|
+
partySize: args.quickPartySize || 1
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
function resolveActiveContentLocale(fallbackLocale) {
|
|
884
|
+
if (typeof window !== "undefined") {
|
|
885
|
+
const urlLoc = new URLSearchParams(window.location.search).get(
|
|
886
|
+
"plugins[i18n][locale]"
|
|
887
|
+
);
|
|
888
|
+
if (urlLoc) return urlLoc;
|
|
889
|
+
}
|
|
890
|
+
return fallbackLocale || "en";
|
|
891
|
+
}
|
|
892
|
+
function formatPluginMessageWithUrlLocale(pluginId, id, defaultMessage, formatMessage) {
|
|
893
|
+
const fullKey = `${pluginId}.${id}`;
|
|
894
|
+
if (typeof window !== "undefined") {
|
|
895
|
+
const urlLoc = new URLSearchParams(window.location.search).get(
|
|
896
|
+
"plugins[i18n][locale]"
|
|
897
|
+
);
|
|
898
|
+
const globalMessages = globalThis.__CM_I18N_MESSAGES__;
|
|
899
|
+
const override = urlLoc ? globalMessages?.[urlLoc]?.[fullKey] : void 0;
|
|
900
|
+
if (override) return override;
|
|
901
|
+
}
|
|
902
|
+
return formatMessage({ id: fullKey, defaultMessage });
|
|
903
|
+
}
|
|
904
|
+
const QuickCreateButtons = ({ showCreateButton, enabledSources, t, onOpenQuickCreate }) => {
|
|
905
|
+
if (!showCreateButton) return null;
|
|
906
|
+
if (enabledSources.length > 1) {
|
|
907
|
+
return /* @__PURE__ */ jsx(Fragment, { children: enabledSources.map((src, idx) => /* @__PURE__ */ jsxs(
|
|
908
|
+
Button,
|
|
909
|
+
{
|
|
910
|
+
variant: idx === 0 ? "default" : "secondary",
|
|
911
|
+
size: "S",
|
|
912
|
+
onClick: () => onOpenQuickCreate(src.id),
|
|
913
|
+
children: [
|
|
914
|
+
"+ ",
|
|
915
|
+
src.label
|
|
916
|
+
]
|
|
917
|
+
},
|
|
918
|
+
src.id
|
|
919
|
+
)) });
|
|
920
|
+
}
|
|
921
|
+
return /* @__PURE__ */ jsxs(
|
|
922
|
+
Button,
|
|
923
|
+
{
|
|
924
|
+
variant: "default",
|
|
925
|
+
size: "S",
|
|
926
|
+
onClick: () => onOpenQuickCreate(enabledSources[0]?.id),
|
|
927
|
+
children: [
|
|
928
|
+
"+ ",
|
|
929
|
+
t("calendar.quickCreate", "New Entry")
|
|
930
|
+
]
|
|
931
|
+
}
|
|
932
|
+
);
|
|
933
|
+
};
|
|
934
|
+
const CalendarToolbar = ({
|
|
935
|
+
t,
|
|
936
|
+
effectiveLocale,
|
|
937
|
+
effectiveDirection,
|
|
938
|
+
secondaryLangMode,
|
|
939
|
+
monthLabel,
|
|
940
|
+
secondaryHeaderLabel,
|
|
941
|
+
loading,
|
|
942
|
+
settings,
|
|
943
|
+
totalOccurrences,
|
|
944
|
+
sourceCounts,
|
|
945
|
+
sourceFilter,
|
|
946
|
+
onSourceFilterChange,
|
|
947
|
+
categoryFilter,
|
|
948
|
+
onCategoryFilterChange,
|
|
949
|
+
availableCategories,
|
|
950
|
+
viewMode,
|
|
951
|
+
enabledViews,
|
|
952
|
+
onViewChange,
|
|
953
|
+
onNavigate,
|
|
954
|
+
onOpenQuickCreate
|
|
955
|
+
}) => {
|
|
956
|
+
const localeBundle = getLocalizedCalendarBundle(effectiveLocale);
|
|
957
|
+
const isRtl = effectiveDirection === "rtl";
|
|
958
|
+
const enabledSources = (settings?.sources ?? []).filter(
|
|
959
|
+
(src) => src.enabled !== false
|
|
960
|
+
);
|
|
961
|
+
const showSecondaryBadge = Boolean(
|
|
962
|
+
secondaryHeaderLabel && secondaryLangMode !== "off"
|
|
963
|
+
);
|
|
964
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
|
|
965
|
+
/* @__PURE__ */ jsxs(
|
|
966
|
+
Flex,
|
|
967
|
+
{
|
|
968
|
+
justifyContent: "space-between",
|
|
969
|
+
alignItems: "center",
|
|
970
|
+
wrap: "wrap",
|
|
971
|
+
gap: 3,
|
|
972
|
+
children: [
|
|
973
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
974
|
+
/* @__PURE__ */ jsx(Typography, { variant: "alpha", fontWeight: "bold", children: t("calendar.title", "Calendar & Scheduler") }),
|
|
975
|
+
/* @__PURE__ */ jsx(Box, { paddingTop: 1, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
|
|
976
|
+
/* @__PURE__ */ jsx(
|
|
977
|
+
Typography,
|
|
978
|
+
{
|
|
979
|
+
variant: "delta",
|
|
980
|
+
fontWeight: "bold",
|
|
981
|
+
textColor: "neutral800",
|
|
982
|
+
style: { textTransform: "uppercase", letterSpacing: "0.03em" },
|
|
983
|
+
children: monthLabel.toUpperCase()
|
|
984
|
+
}
|
|
985
|
+
),
|
|
986
|
+
showSecondaryBadge && /* @__PURE__ */ jsx(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: secondaryHeaderLabel }),
|
|
987
|
+
/* @__PURE__ */ jsxs(Badge, { backgroundColor: "neutral150", textColor: "neutral700", children: [
|
|
988
|
+
localeBundle.nativeName,
|
|
989
|
+
" (",
|
|
990
|
+
effectiveDirection.toUpperCase(),
|
|
991
|
+
")"
|
|
992
|
+
] }),
|
|
993
|
+
loading && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: t("calendar.loading", "Syncing...") })
|
|
994
|
+
] }) })
|
|
995
|
+
] }),
|
|
996
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, wrap: "wrap", children: [
|
|
997
|
+
/* @__PURE__ */ jsx(
|
|
998
|
+
QuickCreateButtons,
|
|
999
|
+
{
|
|
1000
|
+
showCreateButton: settings?.showCreateButton !== false,
|
|
1001
|
+
enabledSources,
|
|
1002
|
+
t,
|
|
1003
|
+
onOpenQuickCreate
|
|
1004
|
+
}
|
|
1005
|
+
),
|
|
1006
|
+
/* @__PURE__ */ jsx(
|
|
1007
|
+
Button,
|
|
1008
|
+
{
|
|
1009
|
+
variant: "secondary",
|
|
1010
|
+
size: "S",
|
|
1011
|
+
tag: "a",
|
|
1012
|
+
href: "/api/calendar/feed.ics",
|
|
1013
|
+
target: "_blank",
|
|
1014
|
+
rel: "noopener noreferrer",
|
|
1015
|
+
children: t("calendar.downloadIcsFeed", "iCal Feed (.ics)")
|
|
1016
|
+
}
|
|
1017
|
+
),
|
|
1018
|
+
/* @__PURE__ */ jsx(
|
|
1019
|
+
Button,
|
|
1020
|
+
{
|
|
1021
|
+
variant: "tertiary",
|
|
1022
|
+
size: "S",
|
|
1023
|
+
tag: NavLink,
|
|
1024
|
+
to: `/settings/${PLUGIN_ID}`,
|
|
1025
|
+
children: t("calendar.settings", "Settings")
|
|
1026
|
+
}
|
|
1027
|
+
)
|
|
1028
|
+
] })
|
|
1029
|
+
]
|
|
1030
|
+
}
|
|
1031
|
+
),
|
|
1032
|
+
/* @__PURE__ */ jsx(Box, { padding: 3, background: "neutral0", hasRadius: true, shadow: "filterShadow", children: /* @__PURE__ */ jsxs(
|
|
1033
|
+
Flex,
|
|
1034
|
+
{
|
|
1035
|
+
justifyContent: "space-between",
|
|
1036
|
+
alignItems: "center",
|
|
1037
|
+
wrap: "wrap",
|
|
1038
|
+
gap: 3,
|
|
1039
|
+
children: [
|
|
1040
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
|
|
1041
|
+
/* @__PURE__ */ jsxs(
|
|
1042
|
+
Button,
|
|
1043
|
+
{
|
|
1044
|
+
variant: "tertiary",
|
|
1045
|
+
size: "S",
|
|
1046
|
+
onClick: () => onNavigate("prev"),
|
|
1047
|
+
children: [
|
|
1048
|
+
isRtl ? "→" : "←",
|
|
1049
|
+
" ",
|
|
1050
|
+
localeBundle.buttonText.prev
|
|
1051
|
+
]
|
|
1052
|
+
}
|
|
1053
|
+
),
|
|
1054
|
+
settings?.showTodayButton !== false && /* @__PURE__ */ jsx(
|
|
1055
|
+
Button,
|
|
1056
|
+
{
|
|
1057
|
+
variant: "secondary",
|
|
1058
|
+
size: "S",
|
|
1059
|
+
onClick: () => onNavigate("today"),
|
|
1060
|
+
children: localeBundle.buttonText.today
|
|
1061
|
+
}
|
|
1062
|
+
),
|
|
1063
|
+
/* @__PURE__ */ jsxs(
|
|
1064
|
+
Button,
|
|
1065
|
+
{
|
|
1066
|
+
variant: "tertiary",
|
|
1067
|
+
size: "S",
|
|
1068
|
+
onClick: () => onNavigate("next"),
|
|
1069
|
+
children: [
|
|
1070
|
+
localeBundle.buttonText.next,
|
|
1071
|
+
" ",
|
|
1072
|
+
isRtl ? "←" : "→"
|
|
1073
|
+
]
|
|
1074
|
+
}
|
|
1075
|
+
)
|
|
1076
|
+
] }),
|
|
1077
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, wrap: "wrap", alignItems: "center", children: [
|
|
1078
|
+
/* @__PURE__ */ jsxs(
|
|
1079
|
+
Button,
|
|
1080
|
+
{
|
|
1081
|
+
size: "S",
|
|
1082
|
+
variant: sourceFilter === "all" ? "default" : "tertiary",
|
|
1083
|
+
onClick: () => onSourceFilterChange("all"),
|
|
1084
|
+
children: [
|
|
1085
|
+
t("calendar.allSources", "All Sources"),
|
|
1086
|
+
" (",
|
|
1087
|
+
totalOccurrences,
|
|
1088
|
+
")"
|
|
1089
|
+
]
|
|
1090
|
+
}
|
|
1091
|
+
),
|
|
1092
|
+
(settings?.sources ?? []).map((src) => {
|
|
1093
|
+
const srcCount = sourceCounts?.[src.id] ?? 0;
|
|
1094
|
+
return /* @__PURE__ */ jsxs(
|
|
1095
|
+
Button,
|
|
1096
|
+
{
|
|
1097
|
+
size: "S",
|
|
1098
|
+
variant: sourceFilter === src.id ? "default" : "tertiary",
|
|
1099
|
+
onClick: () => onSourceFilterChange(src.id),
|
|
1100
|
+
children: [
|
|
1101
|
+
/* @__PURE__ */ jsx(
|
|
1102
|
+
"span",
|
|
1103
|
+
{
|
|
1104
|
+
style: {
|
|
1105
|
+
display: "inline-block",
|
|
1106
|
+
width: 8,
|
|
1107
|
+
height: 8,
|
|
1108
|
+
borderRadius: "50%",
|
|
1109
|
+
background: src.color,
|
|
1110
|
+
marginRight: 6
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
),
|
|
1114
|
+
src.label,
|
|
1115
|
+
" (",
|
|
1116
|
+
srcCount,
|
|
1117
|
+
")"
|
|
1118
|
+
]
|
|
1119
|
+
},
|
|
1120
|
+
src.id
|
|
1121
|
+
);
|
|
1122
|
+
}),
|
|
1123
|
+
/* @__PURE__ */ jsx(Box, { style: { minWidth: 175, maxWidth: 220 }, children: /* @__PURE__ */ jsxs(
|
|
1124
|
+
SingleSelect,
|
|
1125
|
+
{
|
|
1126
|
+
size: "S",
|
|
1127
|
+
"aria-label": t("calendar.toolbar.category", "Category Filter"),
|
|
1128
|
+
placeholder: t("placeholder.all_categories", "All Categories"),
|
|
1129
|
+
value: categoryFilter,
|
|
1130
|
+
onChange: (val) => onCategoryFilterChange(String(val)),
|
|
1131
|
+
children: [
|
|
1132
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "all", children: t("calendar.allCategories", "All Categories") }),
|
|
1133
|
+
availableCategories.map((cat) => /* @__PURE__ */ jsx(SingleSelectOption, { value: cat, children: formatCategoryLabel(cat) }, cat))
|
|
1134
|
+
]
|
|
1135
|
+
}
|
|
1136
|
+
) })
|
|
1137
|
+
] }),
|
|
1138
|
+
/* @__PURE__ */ jsx(Flex, { gap: 1, wrap: "wrap", children: enabledViews.map((v) => /* @__PURE__ */ jsx(
|
|
1139
|
+
Button,
|
|
1140
|
+
{
|
|
1141
|
+
size: "S",
|
|
1142
|
+
variant: viewMode === v.mode ? "default" : "tertiary",
|
|
1143
|
+
onClick: () => onViewChange(v.mode),
|
|
1144
|
+
children: v.label
|
|
1145
|
+
},
|
|
1146
|
+
v.mode
|
|
1147
|
+
)) })
|
|
1148
|
+
]
|
|
1149
|
+
}
|
|
1150
|
+
) })
|
|
1151
|
+
] });
|
|
1152
|
+
};
|
|
1153
|
+
const CALENDAR_COLOR_PALETTES = {
|
|
1154
|
+
default: {
|
|
1155
|
+
id: "default",
|
|
1156
|
+
label: "Theme Default",
|
|
1157
|
+
lightPrimary: "#0284C7",
|
|
1158
|
+
darkPrimary: "#38BDF8",
|
|
1159
|
+
lightHeaderBg: "#E0F2FE",
|
|
1160
|
+
lightHeaderText: "#0C4A6E",
|
|
1161
|
+
lightTodayBg: "#F0F9FF",
|
|
1162
|
+
lightBadgeBg: "#E0F2FE",
|
|
1163
|
+
lightBadgeText: "#0369A1",
|
|
1164
|
+
lightBadgeBorder: "#7DD3FC",
|
|
1165
|
+
darkHeaderBg: "#1E293B",
|
|
1166
|
+
darkHeaderText: "#E2E8F0",
|
|
1167
|
+
darkTodayBg: "#172554",
|
|
1168
|
+
darkBadgeBg: "#1E293B",
|
|
1169
|
+
darkBadgeText: "#7DD3FC",
|
|
1170
|
+
darkBadgeBorder: "#0369A1"
|
|
1171
|
+
},
|
|
1172
|
+
purple: {
|
|
1173
|
+
id: "purple",
|
|
1174
|
+
label: "Monarch Purple",
|
|
1175
|
+
lightPrimary: "#6750A4",
|
|
1176
|
+
darkPrimary: "#D0BCFF",
|
|
1177
|
+
lightHeaderBg: "#F3EDF7",
|
|
1178
|
+
lightHeaderText: "#381E72",
|
|
1179
|
+
lightTodayBg: "#F7F2FA",
|
|
1180
|
+
lightBadgeBg: "#EADDFF",
|
|
1181
|
+
lightBadgeText: "#4F378B",
|
|
1182
|
+
lightBadgeBorder: "#D0BCFF",
|
|
1183
|
+
darkHeaderBg: "#211F26",
|
|
1184
|
+
darkHeaderText: "#E6E0E9",
|
|
1185
|
+
darkTodayBg: "#2B223C",
|
|
1186
|
+
darkBadgeBg: "#381E72",
|
|
1187
|
+
darkBadgeText: "#EADDFF",
|
|
1188
|
+
darkBadgeBorder: "#4F378B"
|
|
1189
|
+
},
|
|
1190
|
+
blue: {
|
|
1191
|
+
id: "blue",
|
|
1192
|
+
label: "Forma / Pulse Blue",
|
|
1193
|
+
lightPrimary: "#0F6CBD",
|
|
1194
|
+
darkPrimary: "#60A5FA",
|
|
1195
|
+
lightHeaderBg: "#EFF6FC",
|
|
1196
|
+
lightHeaderText: "#0A4478",
|
|
1197
|
+
lightTodayBg: "#F0F7FF",
|
|
1198
|
+
lightBadgeBg: "#DBEAFE",
|
|
1199
|
+
lightBadgeText: "#1E40AF",
|
|
1200
|
+
lightBadgeBorder: "#93C5FD",
|
|
1201
|
+
darkHeaderBg: "#172130",
|
|
1202
|
+
darkHeaderText: "#DBEAFE",
|
|
1203
|
+
darkTodayBg: "#172554",
|
|
1204
|
+
darkBadgeBg: "#1E3A8A",
|
|
1205
|
+
darkBadgeText: "#BFDBFE",
|
|
1206
|
+
darkBadgeBorder: "#2563EB"
|
|
1207
|
+
},
|
|
1208
|
+
indigo: {
|
|
1209
|
+
id: "indigo",
|
|
1210
|
+
label: "Breezy Indigo",
|
|
1211
|
+
lightPrimary: "#4F46E5",
|
|
1212
|
+
darkPrimary: "#818CF8",
|
|
1213
|
+
lightHeaderBg: "#EEF2FF",
|
|
1214
|
+
lightHeaderText: "#312E81",
|
|
1215
|
+
lightTodayBg: "#EEF2FF",
|
|
1216
|
+
lightBadgeBg: "#E0E7FF",
|
|
1217
|
+
lightBadgeText: "#3730A3",
|
|
1218
|
+
lightBadgeBorder: "#A5B4FC",
|
|
1219
|
+
darkHeaderBg: "#1E1B4B",
|
|
1220
|
+
darkHeaderText: "#E0E7FF",
|
|
1221
|
+
darkTodayBg: "#1E1B4B",
|
|
1222
|
+
darkBadgeBg: "#312E81",
|
|
1223
|
+
darkBadgeText: "#C7D2FE",
|
|
1224
|
+
darkBadgeBorder: "#4F46E5"
|
|
1225
|
+
},
|
|
1226
|
+
emerald: {
|
|
1227
|
+
id: "emerald",
|
|
1228
|
+
label: "Emerald Green",
|
|
1229
|
+
lightPrimary: "#059669",
|
|
1230
|
+
darkPrimary: "#34D399",
|
|
1231
|
+
lightHeaderBg: "#ECFDF5",
|
|
1232
|
+
lightHeaderText: "#065F46",
|
|
1233
|
+
lightTodayBg: "#F0FDF4",
|
|
1234
|
+
lightBadgeBg: "#D1FAE5",
|
|
1235
|
+
lightBadgeText: "#065F46",
|
|
1236
|
+
lightBadgeBorder: "#6EE7B7",
|
|
1237
|
+
darkHeaderBg: "#064E3B",
|
|
1238
|
+
darkHeaderText: "#D1FAE5",
|
|
1239
|
+
darkTodayBg: "#064E3B",
|
|
1240
|
+
darkBadgeBg: "#065F46",
|
|
1241
|
+
darkBadgeText: "#A7F3D0",
|
|
1242
|
+
darkBadgeBorder: "#059669"
|
|
1243
|
+
},
|
|
1244
|
+
rose: {
|
|
1245
|
+
id: "rose",
|
|
1246
|
+
label: "Pulse Rose",
|
|
1247
|
+
lightPrimary: "#E11D48",
|
|
1248
|
+
darkPrimary: "#FB7185",
|
|
1249
|
+
lightHeaderBg: "#FFF1F2",
|
|
1250
|
+
lightHeaderText: "#881337",
|
|
1251
|
+
lightTodayBg: "#FFF1F2",
|
|
1252
|
+
lightBadgeBg: "#FFE4E6",
|
|
1253
|
+
lightBadgeText: "#9F1239",
|
|
1254
|
+
lightBadgeBorder: "#FDA4AF",
|
|
1255
|
+
darkHeaderBg: "#3B0A19",
|
|
1256
|
+
darkHeaderText: "#FFE4E6",
|
|
1257
|
+
darkTodayBg: "#4C0519",
|
|
1258
|
+
darkBadgeBg: "#881337",
|
|
1259
|
+
darkBadgeText: "#FECDD3",
|
|
1260
|
+
darkBadgeBorder: "#E11D48"
|
|
1261
|
+
},
|
|
1262
|
+
amber: {
|
|
1263
|
+
id: "amber",
|
|
1264
|
+
label: "Monarch Amber",
|
|
1265
|
+
lightPrimary: "#D97706",
|
|
1266
|
+
darkPrimary: "#FBBF24",
|
|
1267
|
+
lightHeaderBg: "#FFFBEB",
|
|
1268
|
+
lightHeaderText: "#78350F",
|
|
1269
|
+
lightTodayBg: "#FEF3C7",
|
|
1270
|
+
lightBadgeBg: "#FEF3C7",
|
|
1271
|
+
lightBadgeText: "#92400E",
|
|
1272
|
+
lightBadgeBorder: "#FCD34D",
|
|
1273
|
+
darkHeaderBg: "#3B2506",
|
|
1274
|
+
darkHeaderText: "#FEF3C7",
|
|
1275
|
+
darkTodayBg: "#451A03",
|
|
1276
|
+
darkBadgeBg: "#78350F",
|
|
1277
|
+
darkBadgeText: "#FDE68A",
|
|
1278
|
+
darkBadgeBorder: "#D97706"
|
|
1279
|
+
}
|
|
1280
|
+
};
|
|
1281
|
+
function detectFromHexLuminance(strapiNeutral0) {
|
|
1282
|
+
if (typeof strapiNeutral0 !== "string" || !strapiNeutral0.startsWith("#")) {
|
|
1283
|
+
return null;
|
|
1284
|
+
}
|
|
1285
|
+
const hex = strapiNeutral0.slice(1).trim();
|
|
1286
|
+
const r = hex.length === 3 ? Number.parseInt(hex[0] + hex[0], 16) : Number.parseInt(hex.slice(0, 2), 16);
|
|
1287
|
+
if (Number.isNaN(r)) return null;
|
|
1288
|
+
return r < 128 ? "dark" : "light";
|
|
1289
|
+
}
|
|
1290
|
+
function detectFromBrowserEnvironment() {
|
|
1291
|
+
if (typeof window === "undefined") return "light";
|
|
1292
|
+
try {
|
|
1293
|
+
const storedTheme = window.localStorage?.getItem("STRAPI_THEME");
|
|
1294
|
+
if (storedTheme === "dark" || storedTheme === "light") {
|
|
1295
|
+
return storedTheme;
|
|
1296
|
+
}
|
|
1297
|
+
} catch {
|
|
1298
|
+
}
|
|
1299
|
+
return window.matchMedia?.("(prefers-color-scheme: dark)")?.matches ? "dark" : "light";
|
|
1300
|
+
}
|
|
1301
|
+
function detectEffectiveColorScheme(colorScheme = "auto", strapiNeutral0) {
|
|
1302
|
+
if (colorScheme === "dark" || colorScheme === "light") {
|
|
1303
|
+
return colorScheme;
|
|
1304
|
+
}
|
|
1305
|
+
return detectFromHexLuminance(strapiNeutral0) ?? detectFromBrowserEnvironment();
|
|
1306
|
+
}
|
|
1307
|
+
const CALENDAR_THEME_PRESETS = {
|
|
1308
|
+
breeze: {
|
|
1309
|
+
id: "breeze",
|
|
1310
|
+
label: "Breezy (Modern Default)",
|
|
1311
|
+
description: "FullCalendar Breezy style — airy sky & slate grid, soft-tinted event pills, and rounded-lg container",
|
|
1312
|
+
category: "modern",
|
|
1313
|
+
fontFamily: "'Inter Variable', Inter, system-ui, sans-serif",
|
|
1314
|
+
containerRadius: "10px",
|
|
1315
|
+
containerShadow: "0 1px 3px rgba(15, 23, 42, 0.06)",
|
|
1316
|
+
eventRadius: "6px",
|
|
1317
|
+
eventStyle: "tinted",
|
|
1318
|
+
dayNumberAlign: "start",
|
|
1319
|
+
todayHeaderAccent: "pill",
|
|
1320
|
+
primaryColor: "#0284C7",
|
|
1321
|
+
headerBg: "#F8FAFC",
|
|
1322
|
+
headerText: "#0F172A",
|
|
1323
|
+
cellBg: "#FFFFFF",
|
|
1324
|
+
cellAltBg: "#F8FAFC",
|
|
1325
|
+
cellHoverBg: "#F0F9FF",
|
|
1326
|
+
cellText: "#111827",
|
|
1327
|
+
cellMutedText: "#6B7280",
|
|
1328
|
+
borderColor: "#E5E7EB",
|
|
1329
|
+
todayBg: "#F0F9FF",
|
|
1330
|
+
todayBorder: "#0284C7",
|
|
1331
|
+
todayNumberBg: "#0284C7",
|
|
1332
|
+
todayNumberText: "#FFFFFF",
|
|
1333
|
+
badgeBg: "#E0F2FE",
|
|
1334
|
+
badgeText: "#0369A1",
|
|
1335
|
+
badgeBorder: "#7DD3FC"
|
|
1336
|
+
},
|
|
1337
|
+
monarch: {
|
|
1338
|
+
id: "monarch",
|
|
1339
|
+
label: "Monarch (Material 3)",
|
|
1340
|
+
description: "FullCalendar Monarch style — pill-shaped headers, centered day badges, tonal surfaces & rounded-xl frame",
|
|
1341
|
+
category: "modern",
|
|
1342
|
+
fontFamily: "'Roboto Variable', Roboto, system-ui, sans-serif",
|
|
1343
|
+
containerRadius: "14px",
|
|
1344
|
+
containerShadow: "0 2px 8px rgba(103, 80, 164, 0.08)",
|
|
1345
|
+
eventRadius: "6px",
|
|
1346
|
+
eventStyle: "solid",
|
|
1347
|
+
dayNumberAlign: "center",
|
|
1348
|
+
todayHeaderAccent: "pill",
|
|
1349
|
+
primaryColor: "#6750A4",
|
|
1350
|
+
headerBg: "#F7F2FA",
|
|
1351
|
+
headerText: "#1D1B20",
|
|
1352
|
+
cellBg: "#FFFFFF",
|
|
1353
|
+
cellAltBg: "#FAF8FC",
|
|
1354
|
+
cellHoverBg: "#F3EDF7",
|
|
1355
|
+
cellText: "#0C090C",
|
|
1356
|
+
cellMutedText: "#79747E",
|
|
1357
|
+
borderColor: "#DEDCE1",
|
|
1358
|
+
todayBg: "#F7F2FA",
|
|
1359
|
+
todayBorder: "#6750A4",
|
|
1360
|
+
todayNumberBg: "#895264",
|
|
1361
|
+
todayNumberText: "#FFFFFF",
|
|
1362
|
+
badgeBg: "#EADDFF",
|
|
1363
|
+
badgeText: "#4F378B",
|
|
1364
|
+
badgeBorder: "#D0BCFF"
|
|
1365
|
+
},
|
|
1366
|
+
forma: {
|
|
1367
|
+
id: "forma",
|
|
1368
|
+
label: "Forma (Fluent Enterprise)",
|
|
1369
|
+
description: "FullCalendar Forma style — architectural 6px left-accent event bars, top-accent Today bar & crisp 4px corners",
|
|
1370
|
+
category: "modern",
|
|
1371
|
+
fontFamily: "'Noto Sans Variable', 'Noto Sans', system-ui, sans-serif",
|
|
1372
|
+
containerRadius: "4px",
|
|
1373
|
+
containerShadow: "0 1px 2px rgba(0, 0, 0, 0.06)",
|
|
1374
|
+
eventRadius: "3px",
|
|
1375
|
+
eventStyle: "accent-bar",
|
|
1376
|
+
dayNumberAlign: "start",
|
|
1377
|
+
todayHeaderAccent: "top-bar",
|
|
1378
|
+
primaryColor: "#0F6CBD",
|
|
1379
|
+
headerBg: "#FFFFFF",
|
|
1380
|
+
headerText: "#030712",
|
|
1381
|
+
cellBg: "#FFFFFF",
|
|
1382
|
+
cellAltBg: "#F9FAFB",
|
|
1383
|
+
cellHoverBg: "#EFF6FC",
|
|
1384
|
+
cellText: "#030712",
|
|
1385
|
+
cellMutedText: "#6B7280",
|
|
1386
|
+
borderColor: "#E0E0E0",
|
|
1387
|
+
todayBg: "#F5F9FF",
|
|
1388
|
+
todayBorder: "#0F6CBD",
|
|
1389
|
+
todayNumberBg: "#0F6CBD",
|
|
1390
|
+
todayNumberText: "#FFFFFF",
|
|
1391
|
+
badgeBg: "#EFF6FC",
|
|
1392
|
+
badgeText: "#0F6CBD",
|
|
1393
|
+
badgeBorder: "#B4D6FA"
|
|
1394
|
+
},
|
|
1395
|
+
pulse: {
|
|
1396
|
+
id: "pulse",
|
|
1397
|
+
label: "Pulse (Apple / macOS)",
|
|
1398
|
+
description: "FullCalendar Pulse style — right-aligned day numbers, crimson Today circle, elevated controls & dotted minor slots",
|
|
1399
|
+
category: "modern",
|
|
1400
|
+
fontFamily: "ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif",
|
|
1401
|
+
containerRadius: "8px",
|
|
1402
|
+
containerShadow: "0 1px 3px rgba(0, 0, 0, 0.12)",
|
|
1403
|
+
eventRadius: "6px",
|
|
1404
|
+
eventStyle: "solid",
|
|
1405
|
+
dayNumberAlign: "end",
|
|
1406
|
+
todayHeaderAccent: "pill",
|
|
1407
|
+
primaryColor: "#117AFF",
|
|
1408
|
+
headerBg: "#FFFFFF",
|
|
1409
|
+
headerText: "#232D3E",
|
|
1410
|
+
cellBg: "#FFFFFF",
|
|
1411
|
+
cellAltBg: "#F9FAFB",
|
|
1412
|
+
cellHoverBg: "#F0F7FF",
|
|
1413
|
+
cellText: "#232D3E",
|
|
1414
|
+
cellMutedText: "#545C6C",
|
|
1415
|
+
borderColor: "#E5E7EB",
|
|
1416
|
+
todayBg: "#FFF5F5",
|
|
1417
|
+
todayBorder: "#FD453B",
|
|
1418
|
+
todayNumberBg: "#FD453B",
|
|
1419
|
+
todayNumberText: "#FFFFFF",
|
|
1420
|
+
badgeBg: "#EFF6FF",
|
|
1421
|
+
badgeText: "#1D4ED8",
|
|
1422
|
+
badgeBorder: "#BFDBFE"
|
|
1423
|
+
},
|
|
1424
|
+
classic: {
|
|
1425
|
+
id: "classic",
|
|
1426
|
+
label: "Classic (FullCalendar Standard)",
|
|
1427
|
+
description: "Traditional FullCalendar v6/v7 studio grid with slate headers, warm yellow Today cell tint & solid events",
|
|
1428
|
+
category: "modern",
|
|
1429
|
+
fontFamily: "ui-sans-serif, system-ui, sans-serif",
|
|
1430
|
+
containerRadius: "6px",
|
|
1431
|
+
containerShadow: "none",
|
|
1432
|
+
eventRadius: "4px",
|
|
1433
|
+
eventStyle: "solid",
|
|
1434
|
+
dayNumberAlign: "end",
|
|
1435
|
+
todayHeaderAccent: "tint",
|
|
1436
|
+
primaryColor: "#3788D8",
|
|
1437
|
+
headerBg: "#F8FAFC",
|
|
1438
|
+
headerText: "#1E293B",
|
|
1439
|
+
cellBg: "#FFFFFF",
|
|
1440
|
+
cellAltBg: "#F8FAFC",
|
|
1441
|
+
cellHoverBg: "#F1F5F9",
|
|
1442
|
+
cellText: "#030712",
|
|
1443
|
+
cellMutedText: "#6B7280",
|
|
1444
|
+
borderColor: "#DDDDDD",
|
|
1445
|
+
todayBg: "#FEFCE8",
|
|
1446
|
+
todayBorder: "#EAB308",
|
|
1447
|
+
todayNumberBg: "#334155",
|
|
1448
|
+
todayNumberText: "#FFFFFF",
|
|
1449
|
+
badgeBg: "#F1F5F9",
|
|
1450
|
+
badgeText: "#334155",
|
|
1451
|
+
badgeBorder: "#CBD5E1"
|
|
1452
|
+
},
|
|
1453
|
+
shadcn: {
|
|
1454
|
+
id: "shadcn",
|
|
1455
|
+
label: "Shadcn UI (Zinc Minimal)",
|
|
1456
|
+
description: "Design-system theme matching Shadcn UI — ultra-clean 1px zinc borders, monochrome primary & tinted badges",
|
|
1457
|
+
category: "design-system",
|
|
1458
|
+
fontFamily: "'Inter Variable', Inter, system-ui, sans-serif",
|
|
1459
|
+
containerRadius: "8px",
|
|
1460
|
+
containerShadow: "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
|
|
1461
|
+
eventRadius: "5px",
|
|
1462
|
+
eventStyle: "tinted",
|
|
1463
|
+
dayNumberAlign: "start",
|
|
1464
|
+
todayHeaderAccent: "pill",
|
|
1465
|
+
primaryColor: "#18181B",
|
|
1466
|
+
headerBg: "#FAFAFA",
|
|
1467
|
+
headerText: "#09090B",
|
|
1468
|
+
cellBg: "#FFFFFF",
|
|
1469
|
+
cellAltBg: "#FAFAFA",
|
|
1470
|
+
cellHoverBg: "#F4F4F5",
|
|
1471
|
+
cellText: "#09090B",
|
|
1472
|
+
cellMutedText: "#71717A",
|
|
1473
|
+
borderColor: "#E4E4E7",
|
|
1474
|
+
todayBg: "#F4F4F5",
|
|
1475
|
+
todayBorder: "#18181B",
|
|
1476
|
+
todayNumberBg: "#18181B",
|
|
1477
|
+
todayNumberText: "#FAFAFA",
|
|
1478
|
+
badgeBg: "#F4F4F5",
|
|
1479
|
+
badgeText: "#18181B",
|
|
1480
|
+
badgeBorder: "#D4D4D8"
|
|
1481
|
+
},
|
|
1482
|
+
mui: {
|
|
1483
|
+
id: "mui",
|
|
1484
|
+
label: "Material UI (MUI Paper)",
|
|
1485
|
+
description: "Design-system theme matching Material UI — Paper surface elevation, Roboto uppercase headers & Material blue",
|
|
1486
|
+
category: "design-system",
|
|
1487
|
+
fontFamily: "'Roboto Variable', Roboto, Helvetica, Arial, sans-serif",
|
|
1488
|
+
containerRadius: "8px",
|
|
1489
|
+
containerShadow: "0px 2px 4px -1px rgba(0,0,0,0.08), 0px 4px 5px 0px rgba(0,0,0,0.05)",
|
|
1490
|
+
eventRadius: "4px",
|
|
1491
|
+
eventStyle: "solid",
|
|
1492
|
+
dayNumberAlign: "center",
|
|
1493
|
+
todayHeaderAccent: "pill",
|
|
1494
|
+
primaryColor: "#1976D2",
|
|
1495
|
+
headerBg: "#F5F7FA",
|
|
1496
|
+
headerText: "#1E293B",
|
|
1497
|
+
cellBg: "#FFFFFF",
|
|
1498
|
+
cellAltBg: "#FAFAFA",
|
|
1499
|
+
cellHoverBg: "#E3F2FD",
|
|
1500
|
+
cellText: "#212121",
|
|
1501
|
+
cellMutedText: "#757575",
|
|
1502
|
+
borderColor: "#E0E0E0",
|
|
1503
|
+
todayBg: "#E3F2FD",
|
|
1504
|
+
todayBorder: "#1976D2",
|
|
1505
|
+
todayNumberBg: "#1976D2",
|
|
1506
|
+
todayNumberText: "#FFFFFF",
|
|
1507
|
+
badgeBg: "#E3F2FD",
|
|
1508
|
+
badgeText: "#1565C0",
|
|
1509
|
+
badgeBorder: "#90CAF9"
|
|
1510
|
+
},
|
|
1511
|
+
emerald: {
|
|
1512
|
+
id: "emerald",
|
|
1513
|
+
label: "Emerald Mosque",
|
|
1514
|
+
description: "Lush emerald & teal palette inspired by traditional Islamic architecture",
|
|
1515
|
+
category: "heritage",
|
|
1516
|
+
fontFamily: "'Inter Variable', Inter, system-ui, sans-serif",
|
|
1517
|
+
containerRadius: "10px",
|
|
1518
|
+
containerShadow: "0 1px 3px rgba(13, 148, 136, 0.08)",
|
|
1519
|
+
eventRadius: "6px",
|
|
1520
|
+
eventStyle: "solid",
|
|
1521
|
+
dayNumberAlign: "start",
|
|
1522
|
+
todayHeaderAccent: "pill",
|
|
1523
|
+
primaryColor: "#0D9488",
|
|
1524
|
+
headerBg: "#CCFBF1",
|
|
1525
|
+
headerText: "#115E59",
|
|
1526
|
+
cellBg: "#FFFFFF",
|
|
1527
|
+
cellAltBg: "#F0FDFA",
|
|
1528
|
+
cellHoverBg: "#CCFBF1",
|
|
1529
|
+
cellText: "#0F172A",
|
|
1530
|
+
cellMutedText: "#475569",
|
|
1531
|
+
borderColor: "#99F6E4",
|
|
1532
|
+
todayBg: "#F0FDFA",
|
|
1533
|
+
todayBorder: "#0D9488",
|
|
1534
|
+
todayNumberBg: "#0D9488",
|
|
1535
|
+
todayNumberText: "#FFFFFF",
|
|
1536
|
+
badgeBg: "#CCFBF1",
|
|
1537
|
+
badgeText: "#0F766E",
|
|
1538
|
+
badgeBorder: "#5EEAD4"
|
|
1539
|
+
},
|
|
1540
|
+
sand: {
|
|
1541
|
+
id: "sand",
|
|
1542
|
+
label: "Warm Sand & Gold",
|
|
1543
|
+
description: "Warm parchment & amber tones for high-comfort reading",
|
|
1544
|
+
category: "heritage",
|
|
1545
|
+
fontFamily: "'Noto Sans Variable', 'Noto Sans', system-ui, sans-serif",
|
|
1546
|
+
containerRadius: "10px",
|
|
1547
|
+
containerShadow: "0 1px 3px rgba(180, 83, 9, 0.08)",
|
|
1548
|
+
eventRadius: "6px",
|
|
1549
|
+
eventStyle: "solid",
|
|
1550
|
+
dayNumberAlign: "start",
|
|
1551
|
+
todayHeaderAccent: "pill",
|
|
1552
|
+
primaryColor: "#B45309",
|
|
1553
|
+
headerBg: "#FEF3C7",
|
|
1554
|
+
headerText: "#78350F",
|
|
1555
|
+
cellBg: "#FFFBEB",
|
|
1556
|
+
cellAltBg: "#FEF9C3",
|
|
1557
|
+
cellHoverBg: "#FEF3C7",
|
|
1558
|
+
cellText: "#1C1917",
|
|
1559
|
+
cellMutedText: "#78716C",
|
|
1560
|
+
borderColor: "#FDE68A",
|
|
1561
|
+
todayBg: "#FEF3C7",
|
|
1562
|
+
todayBorder: "#D97706",
|
|
1563
|
+
todayNumberBg: "#B45309",
|
|
1564
|
+
todayNumberText: "#FFFFFF",
|
|
1565
|
+
badgeBg: "#FEF3C7",
|
|
1566
|
+
badgeText: "#92400E",
|
|
1567
|
+
badgeBorder: "#FCD34D"
|
|
1568
|
+
},
|
|
1569
|
+
midnight: {
|
|
1570
|
+
id: "midnight",
|
|
1571
|
+
label: "Midnight Slate",
|
|
1572
|
+
description: "Deep dark-mode slate grid with luminous sky accents",
|
|
1573
|
+
category: "heritage",
|
|
1574
|
+
fontFamily: "'Inter Variable', Inter, system-ui, sans-serif",
|
|
1575
|
+
containerRadius: "10px",
|
|
1576
|
+
containerShadow: "0 4px 12px rgba(2, 6, 23, 0.35)",
|
|
1577
|
+
eventRadius: "6px",
|
|
1578
|
+
eventStyle: "tinted",
|
|
1579
|
+
dayNumberAlign: "start",
|
|
1580
|
+
todayHeaderAccent: "pill",
|
|
1581
|
+
primaryColor: "#38BDF8",
|
|
1582
|
+
headerBg: "#1E293B",
|
|
1583
|
+
headerText: "#E2E8F0",
|
|
1584
|
+
cellBg: "#0F172A",
|
|
1585
|
+
cellAltBg: "#162032",
|
|
1586
|
+
cellHoverBg: "#1E293B",
|
|
1587
|
+
cellText: "#F8FAFC",
|
|
1588
|
+
cellMutedText: "#94A3B8",
|
|
1589
|
+
borderColor: "#334155",
|
|
1590
|
+
todayBg: "#172554",
|
|
1591
|
+
todayBorder: "#38BDF8",
|
|
1592
|
+
todayNumberBg: "#0284C7",
|
|
1593
|
+
todayNumberText: "#FFFFFF",
|
|
1594
|
+
badgeBg: "#1E293B",
|
|
1595
|
+
badgeText: "#7DD3FC",
|
|
1596
|
+
badgeBorder: "#0369A1"
|
|
1597
|
+
}
|
|
1598
|
+
};
|
|
1599
|
+
function applyDarkSurfaceOverride(base, themeKey) {
|
|
1600
|
+
return {
|
|
1601
|
+
...base,
|
|
1602
|
+
headerBg: themeKey === "monarch" ? "#141218" : "#111827",
|
|
1603
|
+
headerText: "#F3F4F6",
|
|
1604
|
+
cellBg: "#030712",
|
|
1605
|
+
cellAltBg: "#0B0F19",
|
|
1606
|
+
cellHoverBg: "#1F2937",
|
|
1607
|
+
cellText: "#F9FAFB",
|
|
1608
|
+
cellMutedText: "#9CA3AF",
|
|
1609
|
+
borderColor: themeKey === "forma" ? "#2A2A2A" : "#1F2937",
|
|
1610
|
+
todayBg: "#172554",
|
|
1611
|
+
todayBorder: base.primaryColor,
|
|
1612
|
+
todayNumberBg: base.primaryColor,
|
|
1613
|
+
todayNumberText: "#FFFFFF",
|
|
1614
|
+
badgeBg: "#1E293B",
|
|
1615
|
+
badgeText: "#E2E8F0",
|
|
1616
|
+
badgeBorder: "#334155"
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
function selectPaletteColors(palette, isDark) {
|
|
1620
|
+
if (isDark) {
|
|
1621
|
+
return {
|
|
1622
|
+
primary: palette.darkPrimary,
|
|
1623
|
+
headerBg: palette.darkHeaderBg,
|
|
1624
|
+
headerText: palette.darkHeaderText,
|
|
1625
|
+
todayBg: palette.darkTodayBg,
|
|
1626
|
+
badgeBg: palette.darkBadgeBg,
|
|
1627
|
+
badgeText: palette.darkBadgeText,
|
|
1628
|
+
badgeBorder: palette.darkBadgeBorder
|
|
1629
|
+
};
|
|
1630
|
+
}
|
|
1631
|
+
return {
|
|
1632
|
+
primary: palette.lightPrimary,
|
|
1633
|
+
headerBg: palette.lightHeaderBg,
|
|
1634
|
+
headerText: palette.lightHeaderText,
|
|
1635
|
+
todayBg: palette.lightTodayBg,
|
|
1636
|
+
badgeBg: palette.lightBadgeBg,
|
|
1637
|
+
badgeText: palette.lightBadgeText,
|
|
1638
|
+
badgeBorder: palette.lightBadgeBorder
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
function applyPaletteOverride(resolved, paletteKey, isDark) {
|
|
1642
|
+
const palette = CALENDAR_COLOR_PALETTES[paletteKey];
|
|
1643
|
+
if (!palette) return resolved;
|
|
1644
|
+
const c = selectPaletteColors(palette, isDark);
|
|
1645
|
+
return {
|
|
1646
|
+
...resolved,
|
|
1647
|
+
primaryColor: c.primary,
|
|
1648
|
+
headerBg: c.headerBg,
|
|
1649
|
+
headerText: c.headerText,
|
|
1650
|
+
todayBg: c.todayBg,
|
|
1651
|
+
todayBorder: c.primary,
|
|
1652
|
+
todayNumberBg: c.primary,
|
|
1653
|
+
todayNumberText: isDark && paletteKey === "purple" ? "#381E72" : "#FFFFFF",
|
|
1654
|
+
badgeBg: c.badgeBg,
|
|
1655
|
+
badgeText: c.badgeText,
|
|
1656
|
+
badgeBorder: c.badgeBorder
|
|
1657
|
+
};
|
|
1658
|
+
}
|
|
1659
|
+
function resolveCalendarTheme(themeKey = "breeze", colorScheme = "auto", paletteKey = "default", strapiNeutral0) {
|
|
1660
|
+
const base = CALENDAR_THEME_PRESETS[themeKey] ?? CALENDAR_THEME_PRESETS.breeze;
|
|
1661
|
+
const effectiveScheme = detectEffectiveColorScheme(
|
|
1662
|
+
colorScheme,
|
|
1663
|
+
strapiNeutral0
|
|
1664
|
+
);
|
|
1665
|
+
const isDark = effectiveScheme === "dark" || themeKey === "midnight";
|
|
1666
|
+
const surfaced = isDark && themeKey !== "midnight" ? applyDarkSurfaceOverride(base, themeKey) : { ...base };
|
|
1667
|
+
return paletteKey !== "default" ? applyPaletteOverride(surfaced, paletteKey, isDark) : surfaced;
|
|
1668
|
+
}
|
|
1669
|
+
function buildEventStyleCss(scope, activeTheme, evtRadius) {
|
|
1670
|
+
if (activeTheme.eventStyle === "tinted") {
|
|
1671
|
+
return `
|
|
1672
|
+
${scope} .fc-daygrid-event,
|
|
1673
|
+
${scope} .fc-timegrid-event {
|
|
1674
|
+
border-radius: ${evtRadius} !important;
|
|
1675
|
+
border-width: 1px !important;
|
|
1676
|
+
border-style: solid !important;
|
|
1677
|
+
background: color-mix(in oklab, var(--fc-event-bg-color, ${activeTheme.primaryColor}) 20%, ${activeTheme.cellBg}) !important;
|
|
1678
|
+
border-color: color-mix(in oklab, var(--fc-event-bg-color, ${activeTheme.primaryColor}) 45%, ${activeTheme.borderColor}) !important;
|
|
1679
|
+
color: color-mix(in oklab, var(--fc-event-bg-color, ${activeTheme.primaryColor}) 72%, ${activeTheme.cellText}) !important;
|
|
1680
|
+
box-shadow: none !important;
|
|
1681
|
+
}
|
|
1682
|
+
${scope} .fc-daygrid-event .fc-event-main,
|
|
1683
|
+
${scope} .fc-timegrid-event .fc-event-main,
|
|
1684
|
+
${scope} .fc-daygrid-event .vicacha-fc-event-inner,
|
|
1685
|
+
${scope} .fc-timegrid-event .vicacha-fc-event-inner {
|
|
1686
|
+
color: color-mix(in oklab, var(--fc-event-bg-color, ${activeTheme.primaryColor}) 75%, ${activeTheme.cellText}) !important;
|
|
1687
|
+
}
|
|
1688
|
+
`;
|
|
1689
|
+
}
|
|
1690
|
+
if (activeTheme.eventStyle === "accent-bar") {
|
|
1691
|
+
return `
|
|
1692
|
+
${scope} .fc-daygrid-event,
|
|
1693
|
+
${scope} .fc-timegrid-event {
|
|
1694
|
+
border-radius: ${evtRadius} !important;
|
|
1695
|
+
border-top: 1px solid color-mix(in oklab, var(--fc-event-bg-color, ${activeTheme.primaryColor}) 32%, transparent) !important;
|
|
1696
|
+
border-bottom: 1px solid color-mix(in oklab, var(--fc-event-bg-color, ${activeTheme.primaryColor}) 32%, transparent) !important;
|
|
1697
|
+
border-inline-end: 1px solid color-mix(in oklab, var(--fc-event-bg-color, ${activeTheme.primaryColor}) 32%, transparent) !important;
|
|
1698
|
+
border-inline-start: 6px solid var(--fc-event-bg-color, ${activeTheme.primaryColor}) !important;
|
|
1699
|
+
background: color-mix(in oklab, var(--fc-event-bg-color, ${activeTheme.primaryColor}) 24%, ${activeTheme.cellBg}) !important;
|
|
1700
|
+
color: ${activeTheme.cellText} !important;
|
|
1701
|
+
box-shadow: none !important;
|
|
1702
|
+
}
|
|
1703
|
+
${scope} .fc-daygrid-event .fc-event-main,
|
|
1704
|
+
${scope} .fc-timegrid-event .fc-event-main,
|
|
1705
|
+
${scope} .fc-daygrid-event .vicacha-fc-event-inner,
|
|
1706
|
+
${scope} .fc-timegrid-event .vicacha-fc-event-inner {
|
|
1707
|
+
color: ${activeTheme.cellText} !important;
|
|
1708
|
+
}
|
|
1709
|
+
`;
|
|
1710
|
+
}
|
|
1711
|
+
return `
|
|
1712
|
+
${scope} .fc-daygrid-event,
|
|
1713
|
+
${scope} .fc-timegrid-event {
|
|
1714
|
+
border-radius: ${evtRadius} !important;
|
|
1715
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08) !important;
|
|
1716
|
+
}
|
|
1717
|
+
`;
|
|
1718
|
+
}
|
|
1719
|
+
function buildTodayCellCss(scope, activeTheme) {
|
|
1720
|
+
if (activeTheme.todayHeaderAccent === "top-bar") {
|
|
1721
|
+
return `
|
|
1722
|
+
${scope} .fc-daygrid-day.fc-day-today {
|
|
1723
|
+
background: ${activeTheme.todayBg} !important;
|
|
1724
|
+
box-shadow: inset 0 4px 0 0 ${activeTheme.todayBorder} !important;
|
|
1725
|
+
}
|
|
1726
|
+
${scope} .fc-col-header-cell.fc-day-today {
|
|
1727
|
+
box-shadow: inset 0 4px 0 0 ${activeTheme.todayBorder} !important;
|
|
1728
|
+
}
|
|
1729
|
+
`;
|
|
1730
|
+
}
|
|
1731
|
+
if (activeTheme.id === "monarch" || activeTheme.id === "pulse") {
|
|
1732
|
+
return `
|
|
1733
|
+
${scope} .fc-daygrid-day.fc-day-today {
|
|
1734
|
+
background: ${activeTheme.todayBg} !important;
|
|
1735
|
+
}
|
|
1736
|
+
`;
|
|
1737
|
+
}
|
|
1738
|
+
return `
|
|
1739
|
+
${scope} .fc-daygrid-day.fc-day-today {
|
|
1740
|
+
background: ${activeTheme.todayBg} !important;
|
|
1741
|
+
box-shadow: inset 0 0 0 2px ${activeTheme.todayBorder} !important;
|
|
1742
|
+
}
|
|
1743
|
+
`;
|
|
1744
|
+
}
|
|
1745
|
+
function buildInteractiveCursorCss(scope, allowCreate) {
|
|
1746
|
+
if (!allowCreate) return "";
|
|
1747
|
+
return `
|
|
1748
|
+
${scope} .fc-daygrid-day,
|
|
1749
|
+
${scope} .fc-timegrid-slot-lane {
|
|
1750
|
+
cursor: pointer;
|
|
1751
|
+
}
|
|
1752
|
+
${scope} .vicacha-fc-day-quick-add {
|
|
1753
|
+
opacity: 0;
|
|
1754
|
+
transition: opacity 0.15s ease, transform 0.15s ease;
|
|
1755
|
+
}
|
|
1756
|
+
${scope} .fc-daygrid-day:hover .vicacha-fc-day-quick-add {
|
|
1757
|
+
opacity: 1;
|
|
1758
|
+
}
|
|
1759
|
+
`;
|
|
1760
|
+
}
|
|
1761
|
+
function resolveThemeDefaults(activeTheme) {
|
|
1762
|
+
return {
|
|
1763
|
+
radius: activeTheme.containerRadius ?? "10px",
|
|
1764
|
+
shadow: activeTheme.containerShadow ?? "none",
|
|
1765
|
+
evtRadius: activeTheme.eventRadius ?? "6px",
|
|
1766
|
+
fontFamily: activeTheme.fontFamily ?? "'Inter Variable', Inter, system-ui, sans-serif"
|
|
1767
|
+
};
|
|
1768
|
+
}
|
|
1769
|
+
function resolveThemeVariantTokens(activeTheme) {
|
|
1770
|
+
const isForma = activeTheme.id === "forma";
|
|
1771
|
+
return {
|
|
1772
|
+
nowColor: activeTheme.id === "pulse" ? "#EF4444" : activeTheme.primaryColor,
|
|
1773
|
+
headerPad: activeTheme.id === "monarch" ? "12px 4px" : "10px 4px",
|
|
1774
|
+
headerWeight: activeTheme.id === "pulse" ? 600 : 700,
|
|
1775
|
+
headerTransform: isForma ? "none" : "uppercase",
|
|
1776
|
+
headerTracking: isForma ? "0" : "0.04em",
|
|
1777
|
+
listDayBorder: isForma ? `border-inline-start: 4px solid ${activeTheme.primaryColor} !important;` : "",
|
|
1778
|
+
weekNumRadius: isForma ? "2px" : "5px"
|
|
1779
|
+
};
|
|
1780
|
+
}
|
|
1781
|
+
function buildCalendarThemeCss(rawTheme, allowCreate = true) {
|
|
1782
|
+
const safePrimary = /^#[0-9a-fA-F]{3,8}$/.test(rawTheme.primaryColor ?? "") ? rawTheme.primaryColor : "#0284C7";
|
|
1783
|
+
const activeTheme = { ...rawTheme, primaryColor: safePrimary };
|
|
1784
|
+
const scope = `.vicacha-fc-container.vicacha-fc-theme-${activeTheme.id}`;
|
|
1785
|
+
const defaults = resolveThemeDefaults(activeTheme);
|
|
1786
|
+
const variants = resolveThemeVariantTokens(activeTheme);
|
|
1787
|
+
const eventRules = buildEventStyleCss(scope, activeTheme, defaults.evtRadius);
|
|
1788
|
+
const todayCellRule = buildTodayCellCss(scope, activeTheme);
|
|
1789
|
+
const interactiveCursorRule = buildInteractiveCursorCss(scope, allowCreate);
|
|
1790
|
+
return `
|
|
1791
|
+
${scope} {
|
|
1792
|
+
--fc-border-color: ${activeTheme.borderColor};
|
|
1793
|
+
--fc-page-bg-color: ${activeTheme.cellBg};
|
|
1794
|
+
--fc-neutral-bg-color: ${activeTheme.cellAltBg};
|
|
1795
|
+
--fc-today-bg-color: ${activeTheme.todayBg};
|
|
1796
|
+
--fc-highlight-color: ${activeTheme.cellHoverBg};
|
|
1797
|
+
--fc-now-indicator-color: ${variants.nowColor};
|
|
1798
|
+
font-family: ${defaults.fontFamily};
|
|
1799
|
+
background: ${activeTheme.cellBg};
|
|
1800
|
+
color: ${activeTheme.cellText};
|
|
1801
|
+
border-radius: ${defaults.radius};
|
|
1802
|
+
border: 1px solid ${activeTheme.borderColor};
|
|
1803
|
+
box-shadow: ${defaults.shadow};
|
|
1804
|
+
overflow: hidden;
|
|
1805
|
+
}
|
|
1806
|
+
${scope} .fc-theme-standard th,
|
|
1807
|
+
${scope} .fc-col-header-cell {
|
|
1808
|
+
background: ${activeTheme.headerBg} !important;
|
|
1809
|
+
color: ${activeTheme.headerText} !important;
|
|
1810
|
+
border-color: ${activeTheme.borderColor} !important;
|
|
1811
|
+
padding: ${variants.headerPad} !important;
|
|
1812
|
+
}
|
|
1813
|
+
${scope} .fc-col-header-cell-cushion {
|
|
1814
|
+
color: ${activeTheme.headerText} !important;
|
|
1815
|
+
font-weight: ${variants.headerWeight} !important;
|
|
1816
|
+
font-size: 12px !important;
|
|
1817
|
+
text-transform: ${variants.headerTransform} !important;
|
|
1818
|
+
letter-spacing: ${variants.headerTracking} !important;
|
|
1819
|
+
text-decoration: none !important;
|
|
1820
|
+
}
|
|
1821
|
+
${scope} .fc-daygrid-day {
|
|
1822
|
+
background: ${activeTheme.cellBg} !important;
|
|
1823
|
+
color: ${activeTheme.cellText} !important;
|
|
1824
|
+
border-color: ${activeTheme.borderColor} !important;
|
|
1825
|
+
transition: background-color 0.15s ease;
|
|
1826
|
+
}
|
|
1827
|
+
${scope} .fc-daygrid-day:hover {
|
|
1828
|
+
background: ${activeTheme.cellHoverBg} !important;
|
|
1829
|
+
}
|
|
1830
|
+
${scope} .fc-daygrid-day.fc-day-other {
|
|
1831
|
+
background: ${activeTheme.cellAltBg} !important;
|
|
1832
|
+
opacity: 0.72;
|
|
1833
|
+
}
|
|
1834
|
+
${todayCellRule}
|
|
1835
|
+
${eventRules}
|
|
1836
|
+
${interactiveCursorRule}
|
|
1837
|
+
${scope} .fc-daygrid-day-top {
|
|
1838
|
+
flex-direction: row !important;
|
|
1839
|
+
width: 100% !important;
|
|
1840
|
+
padding: 4px 4px 2px !important;
|
|
1841
|
+
box-sizing: border-box !important;
|
|
1842
|
+
}
|
|
1843
|
+
${scope} .fc-daygrid-day-number {
|
|
1844
|
+
width: 100% !important;
|
|
1845
|
+
min-width: 0 !important;
|
|
1846
|
+
padding: 0 !important;
|
|
1847
|
+
color: ${activeTheme.cellText} !important;
|
|
1848
|
+
text-decoration: none !important;
|
|
1849
|
+
}
|
|
1850
|
+
${scope} .fc-daygrid-day-frame {
|
|
1851
|
+
min-height: 92px !important;
|
|
1852
|
+
padding: 2px !important;
|
|
1853
|
+
box-sizing: border-box !important;
|
|
1854
|
+
}
|
|
1855
|
+
${scope} .fc-daygrid-more-link {
|
|
1856
|
+
font-size: 11px !important;
|
|
1857
|
+
font-weight: 700 !important;
|
|
1858
|
+
color: ${activeTheme.primaryColor} !important;
|
|
1859
|
+
padding: 1px 4px !important;
|
|
1860
|
+
text-decoration: none !important;
|
|
1861
|
+
}
|
|
1862
|
+
${scope} .fc-timegrid-slot,
|
|
1863
|
+
${scope} .fc-timegrid-axis,
|
|
1864
|
+
${scope} .fc-scrollgrid {
|
|
1865
|
+
border-color: ${activeTheme.borderColor} !important;
|
|
1866
|
+
color: ${activeTheme.cellText} !important;
|
|
1867
|
+
background: ${activeTheme.cellBg} !important;
|
|
1868
|
+
}
|
|
1869
|
+
${scope} .fc-timegrid-slot-minor {
|
|
1870
|
+
border-top-style: dotted !important;
|
|
1871
|
+
}
|
|
1872
|
+
${scope} .fc-timegrid-slot-label-cushion,
|
|
1873
|
+
${scope} .fc-list-day-text,
|
|
1874
|
+
${scope} .fc-list-day-side-text {
|
|
1875
|
+
color: ${activeTheme.headerText} !important;
|
|
1876
|
+
font-weight: 600 !important;
|
|
1877
|
+
text-decoration: none !important;
|
|
1878
|
+
}
|
|
1879
|
+
${scope} .fc-list-day-cushion {
|
|
1880
|
+
background: ${activeTheme.headerBg} !important;
|
|
1881
|
+
${variants.listDayBorder}
|
|
1882
|
+
}
|
|
1883
|
+
${scope} .fc-list-event td {
|
|
1884
|
+
background: ${activeTheme.cellBg} !important;
|
|
1885
|
+
color: ${activeTheme.cellText} !important;
|
|
1886
|
+
border-color: ${activeTheme.borderColor} !important;
|
|
1887
|
+
}
|
|
1888
|
+
${scope} .fc-list-empty {
|
|
1889
|
+
background: ${activeTheme.cellAltBg} !important;
|
|
1890
|
+
color: ${activeTheme.cellMutedText} !important;
|
|
1891
|
+
}
|
|
1892
|
+
${scope} .fc-multimonth {
|
|
1893
|
+
border: none !important;
|
|
1894
|
+
padding: 12px !important;
|
|
1895
|
+
gap: 14px !important;
|
|
1896
|
+
box-sizing: border-box !important;
|
|
1897
|
+
background: ${activeTheme.cellAltBg} !important;
|
|
1898
|
+
}
|
|
1899
|
+
${scope} .fc-multimonth-month {
|
|
1900
|
+
background: ${activeTheme.cellBg} !important;
|
|
1901
|
+
color: ${activeTheme.cellText} !important;
|
|
1902
|
+
border: 1px solid ${activeTheme.borderColor} !important;
|
|
1903
|
+
border-radius: ${defaults.radius} !important;
|
|
1904
|
+
box-sizing: border-box !important;
|
|
1905
|
+
overflow: hidden !important;
|
|
1906
|
+
padding: 0 !important;
|
|
1907
|
+
}
|
|
1908
|
+
${scope} .fc-multimonth-month[style*="33.3"] {
|
|
1909
|
+
width: calc((100% - 28px) / 3) !important;
|
|
1910
|
+
flex: 0 0 calc((100% - 28px) / 3) !important;
|
|
1911
|
+
}
|
|
1912
|
+
${scope} .fc-multimonth-month[style*="50%"] {
|
|
1913
|
+
width: calc((100% - 14px) / 2) !important;
|
|
1914
|
+
flex: 0 0 calc((100% - 14px) / 2) !important;
|
|
1915
|
+
}
|
|
1916
|
+
${scope} .fc-multimonth-month[style*="25%"] {
|
|
1917
|
+
width: calc((100% - 42px) / 4) !important;
|
|
1918
|
+
flex: 0 0 calc((100% - 42px) / 4) !important;
|
|
1919
|
+
}
|
|
1920
|
+
${scope} .fc-multimonth-month[style*="100%"] {
|
|
1921
|
+
width: 100% !important;
|
|
1922
|
+
flex: 0 0 100% !important;
|
|
1923
|
+
}
|
|
1924
|
+
${scope} .fc-multimonth-header-table th,
|
|
1925
|
+
${scope} .fc-multimonth-month .fc-col-header-cell {
|
|
1926
|
+
padding: 6px 2px !important;
|
|
1927
|
+
}
|
|
1928
|
+
${scope} .fc-multimonth-month .fc-col-header-cell-cushion {
|
|
1929
|
+
font-size: 10.5px !important;
|
|
1930
|
+
letter-spacing: 0.02em !important;
|
|
1931
|
+
}
|
|
1932
|
+
${scope} .fc-multimonth-month .fc-daygrid-day-frame {
|
|
1933
|
+
min-height: 46px !important;
|
|
1934
|
+
padding: 1px !important;
|
|
1935
|
+
}
|
|
1936
|
+
${scope} .fc-multimonth-month .fc-daygrid-day-top {
|
|
1937
|
+
padding: 2px 2px 1px !important;
|
|
1938
|
+
}
|
|
1939
|
+
${scope} .fc-multimonth-title {
|
|
1940
|
+
color: ${activeTheme.headerText} !important;
|
|
1941
|
+
background: ${activeTheme.headerBg} !important;
|
|
1942
|
+
border-bottom: 1px solid ${activeTheme.borderColor} !important;
|
|
1943
|
+
font-size: 13px !important;
|
|
1944
|
+
font-weight: 700 !important;
|
|
1945
|
+
padding: 10px 12px !important;
|
|
1946
|
+
text-transform: uppercase !important;
|
|
1947
|
+
letter-spacing: 0.06em !important;
|
|
1948
|
+
}
|
|
1949
|
+
${scope} .fc-daygrid-week-number {
|
|
1950
|
+
background: ${activeTheme.badgeBg} !important;
|
|
1951
|
+
color: ${activeTheme.badgeText} !important;
|
|
1952
|
+
border-radius: ${variants.weekNumRadius} !important;
|
|
1953
|
+
font-size: 10px !important;
|
|
1954
|
+
font-weight: 600 !important;
|
|
1955
|
+
padding: 1px 5px !important;
|
|
1956
|
+
margin: 2px 4px !important;
|
|
1957
|
+
opacity: 0.85;
|
|
1958
|
+
}
|
|
1959
|
+
@media (max-width: 1100px) {
|
|
1960
|
+
${scope} .vicacha-fc-day-quick-add {
|
|
1961
|
+
display: none !important;
|
|
1962
|
+
}
|
|
1963
|
+
${scope} .vicacha-fc-secondary-badge {
|
|
1964
|
+
font-size: 9.5px !important;
|
|
1965
|
+
padding: 0 5px !important;
|
|
1966
|
+
}
|
|
1967
|
+
${scope} .fc-daygrid-day-frame {
|
|
1968
|
+
min-height: 76px !important;
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
@media (max-width: 768px) {
|
|
1972
|
+
${scope} .vicacha-fc-secondary-badge {
|
|
1973
|
+
display: none !important;
|
|
1974
|
+
}
|
|
1975
|
+
${scope} .fc-daygrid-day-frame {
|
|
1976
|
+
min-height: 58px !important;
|
|
1977
|
+
}
|
|
1978
|
+
${scope} .fc-multimonth {
|
|
1979
|
+
padding: 6px !important;
|
|
1980
|
+
gap: 10px !important;
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
`;
|
|
1984
|
+
}
|
|
1985
|
+
function computeSecondaryBadges(dateKey, effectiveSecondaryLang, localeCode, activeSecondaryCalendars) {
|
|
1986
|
+
if (effectiveSecondaryLang === "off") return [];
|
|
1987
|
+
const targetLoc = effectiveSecondaryLang === "ar" ? "ar-SA" : localeCode;
|
|
1988
|
+
return activeSecondaryCalendars.map((sys) => {
|
|
1989
|
+
const sysLocale = effectiveSecondaryLang === "ar" ? "ar-SA" : sys.locale || targetLoc;
|
|
1990
|
+
return formatDateInCalendarSystem(
|
|
1991
|
+
dateKey,
|
|
1992
|
+
{ ...sys, locale: sysLocale },
|
|
1993
|
+
targetLoc,
|
|
1994
|
+
{
|
|
1995
|
+
compact: true
|
|
1996
|
+
}
|
|
1997
|
+
);
|
|
1998
|
+
}).filter(Boolean);
|
|
1999
|
+
}
|
|
2000
|
+
function buildDayHeaderStyle(activeTheme, isCompactYear, hasSecondaryBadges, allowCreate) {
|
|
2001
|
+
const isEndAligned = activeTheme.dayNumberAlign === "end";
|
|
2002
|
+
const isCenterAligned = activeTheme.dayNumberAlign === "center";
|
|
2003
|
+
const justifyCenter = isCompactYear || isCenterAligned && !hasSecondaryBadges;
|
|
2004
|
+
return {
|
|
2005
|
+
display: "flex",
|
|
2006
|
+
flexDirection: isEndAligned ? "row-reverse" : "row",
|
|
2007
|
+
flexWrap: isCompactYear ? "nowrap" : "wrap",
|
|
2008
|
+
justifyContent: justifyCenter ? "center" : "space-between",
|
|
2009
|
+
alignItems: "center",
|
|
2010
|
+
width: "100%",
|
|
2011
|
+
minWidth: 0,
|
|
2012
|
+
overflow: "hidden",
|
|
2013
|
+
gap: isCompactYear ? 2 : 4,
|
|
2014
|
+
padding: isCompactYear ? "1px 2px" : "2px 4px",
|
|
2015
|
+
cursor: allowCreate ? "pointer" : "default"
|
|
2016
|
+
};
|
|
2017
|
+
}
|
|
2018
|
+
function buildDayNumberBadgeStyle(activeTheme, isCompactYear, isToday) {
|
|
2019
|
+
const fontSize = isCompactYear ? 12 : activeTheme.id === "monarch" ? 13.5 : 13;
|
|
2020
|
+
const size = isCompactYear ? 22 : 26;
|
|
2021
|
+
const borderRadius = activeTheme.id === "forma" && !isToday ? "3px" : "999px";
|
|
2022
|
+
return {
|
|
2023
|
+
fontWeight: 700,
|
|
2024
|
+
fontSize,
|
|
2025
|
+
lineHeight: 1.2,
|
|
2026
|
+
display: "inline-flex",
|
|
2027
|
+
alignItems: "center",
|
|
2028
|
+
justifyContent: "center",
|
|
2029
|
+
minWidth: size,
|
|
2030
|
+
height: size,
|
|
2031
|
+
flexShrink: 0,
|
|
2032
|
+
borderRadius,
|
|
2033
|
+
padding: isCompactYear ? "0 4px" : "0 6px",
|
|
2034
|
+
background: isToday ? activeTheme.todayNumberBg : "transparent",
|
|
2035
|
+
color: isToday ? activeTheme.todayNumberText : activeTheme.cellText
|
|
2036
|
+
};
|
|
2037
|
+
}
|
|
2038
|
+
const DayCellMetaBadges = ({
|
|
2039
|
+
secondarySummary,
|
|
2040
|
+
effectiveSecondaryLang,
|
|
2041
|
+
activeTheme,
|
|
2042
|
+
allowCreate
|
|
2043
|
+
}) => /* @__PURE__ */ jsxs(
|
|
2044
|
+
"span",
|
|
2045
|
+
{
|
|
2046
|
+
className: "vicacha-fc-day-meta",
|
|
2047
|
+
style: {
|
|
2048
|
+
display: "inline-flex",
|
|
2049
|
+
alignItems: "center",
|
|
2050
|
+
gap: 4,
|
|
2051
|
+
minWidth: 0,
|
|
2052
|
+
maxWidth: "100%"
|
|
2053
|
+
},
|
|
2054
|
+
children: [
|
|
2055
|
+
secondarySummary && /* @__PURE__ */ jsx(
|
|
2056
|
+
"span",
|
|
2057
|
+
{
|
|
2058
|
+
className: "vicacha-fc-secondary-badge",
|
|
2059
|
+
dir: effectiveSecondaryLang === "ar" ? "rtl" : "auto",
|
|
2060
|
+
style: {
|
|
2061
|
+
fontSize: 10.5,
|
|
2062
|
+
background: activeTheme.badgeBg,
|
|
2063
|
+
color: activeTheme.badgeText,
|
|
2064
|
+
border: `1px solid ${activeTheme.badgeBorder}`,
|
|
2065
|
+
borderRadius: activeTheme.id === "forma" ? "4px" : "999px",
|
|
2066
|
+
padding: "1px 6px",
|
|
2067
|
+
fontWeight: 600,
|
|
2068
|
+
whiteSpace: "nowrap",
|
|
2069
|
+
overflow: "hidden",
|
|
2070
|
+
textOverflow: "ellipsis",
|
|
2071
|
+
maxWidth: "100%",
|
|
2072
|
+
lineHeight: 1.3
|
|
2073
|
+
},
|
|
2074
|
+
children: secondarySummary
|
|
2075
|
+
}
|
|
2076
|
+
),
|
|
2077
|
+
allowCreate && /* @__PURE__ */ jsx(
|
|
2078
|
+
"span",
|
|
2079
|
+
{
|
|
2080
|
+
className: "vicacha-fc-day-quick-add",
|
|
2081
|
+
style: {
|
|
2082
|
+
display: "inline-flex",
|
|
2083
|
+
alignItems: "center",
|
|
2084
|
+
justifyContent: "center",
|
|
2085
|
+
width: 18,
|
|
2086
|
+
height: 18,
|
|
2087
|
+
flexShrink: 0,
|
|
2088
|
+
borderRadius: "999px",
|
|
2089
|
+
background: activeTheme.primaryColor,
|
|
2090
|
+
color: "#FFFFFF",
|
|
2091
|
+
fontSize: 12,
|
|
2092
|
+
fontWeight: 700,
|
|
2093
|
+
lineHeight: 1
|
|
2094
|
+
},
|
|
2095
|
+
children: "+"
|
|
2096
|
+
}
|
|
2097
|
+
)
|
|
2098
|
+
]
|
|
2099
|
+
}
|
|
2100
|
+
);
|
|
2101
|
+
const FULLCALENDAR_PLUGINS = [
|
|
2102
|
+
dayGridPlugin,
|
|
2103
|
+
timeGridPlugin,
|
|
2104
|
+
listPlugin,
|
|
2105
|
+
multiMonthPlugin,
|
|
2106
|
+
interactionPlugin
|
|
2107
|
+
];
|
|
2108
|
+
const VIEW_SPECIFIC_OPTIONS = {
|
|
2109
|
+
dayGridMonth: { dayMaxEventRows: 3 },
|
|
2110
|
+
listMonth: { type: "list", duration: { years: 1 } },
|
|
2111
|
+
multiMonthYear: {
|
|
2112
|
+
type: "multiMonth",
|
|
2113
|
+
duration: { years: 1 },
|
|
2114
|
+
multiMonthMaxColumns: 3,
|
|
2115
|
+
multiMonthMinWidth: 300,
|
|
2116
|
+
dayMaxEventRows: 2,
|
|
2117
|
+
weekNumbers: false
|
|
2118
|
+
},
|
|
2119
|
+
multiMonthYearStacked: {
|
|
2120
|
+
type: "multiMonth",
|
|
2121
|
+
duration: { years: 1 },
|
|
2122
|
+
multiMonthMaxColumns: 1,
|
|
2123
|
+
dayMaxEventRows: 3
|
|
2124
|
+
},
|
|
2125
|
+
dayGridYear: {
|
|
2126
|
+
type: "dayGrid",
|
|
2127
|
+
duration: { years: 1 },
|
|
2128
|
+
dayMaxEventRows: 3
|
|
2129
|
+
}
|
|
2130
|
+
};
|
|
2131
|
+
const ALL_CALENDAR_LOCALES = (() => {
|
|
2132
|
+
const builtInMap = /* @__PURE__ */ new Map();
|
|
2133
|
+
if (Array.isArray(allLocales)) {
|
|
2134
|
+
for (const loc of allLocales) {
|
|
2135
|
+
if (loc && loc.code) {
|
|
2136
|
+
builtInMap.set(loc.code.toLowerCase(), loc);
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
for (const customLoc of SUPPORTED_CALENDAR_LOCALES) {
|
|
2141
|
+
builtInMap.set(customLoc.code.toLowerCase(), customLoc);
|
|
2142
|
+
}
|
|
2143
|
+
return Array.from(builtInMap.values());
|
|
2144
|
+
})();
|
|
2145
|
+
function renderEventContent(eventArg) {
|
|
2146
|
+
const occ = eventArg.event.extendedProps?.occurrence;
|
|
2147
|
+
const isCompactYear = eventArg.view?.type === "multiMonthYear";
|
|
2148
|
+
const tooltip = [eventArg.timeText, eventArg.event.title].filter(Boolean).join(" • ");
|
|
2149
|
+
return /* @__PURE__ */ jsxs(
|
|
2150
|
+
"div",
|
|
2151
|
+
{
|
|
2152
|
+
className: "vicacha-fc-event-inner",
|
|
2153
|
+
title: tooltip,
|
|
2154
|
+
style: {
|
|
2155
|
+
overflow: "hidden",
|
|
2156
|
+
textOverflow: "ellipsis",
|
|
2157
|
+
whiteSpace: "nowrap",
|
|
2158
|
+
padding: isCompactYear ? "1px 4px" : "2px 6px",
|
|
2159
|
+
fontSize: isCompactYear ? 11 : 12,
|
|
2160
|
+
fontWeight: 600,
|
|
2161
|
+
lineHeight: 1.3
|
|
2162
|
+
},
|
|
2163
|
+
children: [
|
|
2164
|
+
occ?.isRecurring ? "↻ " : "",
|
|
2165
|
+
!isCompactYear && eventArg.timeText ? /* @__PURE__ */ jsxs("b", { className: "vicacha-fc-event-time", children: [
|
|
2166
|
+
eventArg.timeText,
|
|
2167
|
+
" "
|
|
2168
|
+
] }) : null,
|
|
2169
|
+
/* @__PURE__ */ jsx("span", { className: "vicacha-fc-event-title", children: eventArg.event.title })
|
|
2170
|
+
]
|
|
2171
|
+
}
|
|
2172
|
+
);
|
|
2173
|
+
}
|
|
2174
|
+
function resolveVisualKeys(props) {
|
|
2175
|
+
const { settings } = props;
|
|
2176
|
+
return {
|
|
2177
|
+
activeThemeKey: props.theme ?? settings?.theme ?? "breeze",
|
|
2178
|
+
configuredColorScheme: props.colorScheme ?? settings?.colorScheme ?? "auto",
|
|
2179
|
+
activePaletteKey: props.themePalette ?? settings?.themePalette ?? "default",
|
|
2180
|
+
effectiveSecondaryLang: props.secondaryCalendarLanguage ?? settings?.secondaryCalendarLanguage ?? "local",
|
|
2181
|
+
allowCreate: settings?.showCreateButton !== false
|
|
2182
|
+
};
|
|
2183
|
+
}
|
|
2184
|
+
function buildCalendarGridConfig(settings) {
|
|
2185
|
+
return {
|
|
2186
|
+
initialView: settings?.defaultView || "dayGridMonth",
|
|
2187
|
+
weekNumbers: settings?.weekNumbers ?? false,
|
|
2188
|
+
weekNumberCalculation: settings?.weekNumberCalculation ?? "ISO",
|
|
2189
|
+
weekends: settings?.showWeekends ?? true,
|
|
2190
|
+
slotMinTime: settings?.startHour || "07:00:00",
|
|
2191
|
+
slotMaxTime: settings?.endHour || "21:00:00",
|
|
2192
|
+
slotDuration: settings?.slotDuration || "00:30:00",
|
|
2193
|
+
businessHours: settings?.businessHours || true
|
|
2194
|
+
};
|
|
2195
|
+
}
|
|
2196
|
+
const FullCalendarCanvas = (props) => {
|
|
2197
|
+
const {
|
|
2198
|
+
calendarRef,
|
|
2199
|
+
locale,
|
|
2200
|
+
direction,
|
|
2201
|
+
settings,
|
|
2202
|
+
events,
|
|
2203
|
+
activeSecondaryCalendars,
|
|
2204
|
+
onDatesSet,
|
|
2205
|
+
onSelectSlot,
|
|
2206
|
+
onSelectOccurrence,
|
|
2207
|
+
onDropOrResizeOccurrence
|
|
2208
|
+
} = props;
|
|
2209
|
+
const styledTheme = useTheme();
|
|
2210
|
+
const strapiNeutral0 = styledTheme?.colors?.neutral0;
|
|
2211
|
+
const localeBundle = useMemo(
|
|
2212
|
+
() => getLocalizedCalendarBundle(locale),
|
|
2213
|
+
[locale]
|
|
2214
|
+
);
|
|
2215
|
+
const {
|
|
2216
|
+
activeThemeKey,
|
|
2217
|
+
configuredColorScheme,
|
|
2218
|
+
activePaletteKey,
|
|
2219
|
+
effectiveSecondaryLang,
|
|
2220
|
+
allowCreate
|
|
2221
|
+
} = resolveVisualKeys(props);
|
|
2222
|
+
const activeColorScheme = detectEffectiveColorScheme(
|
|
2223
|
+
configuredColorScheme,
|
|
2224
|
+
strapiNeutral0
|
|
2225
|
+
);
|
|
2226
|
+
const activeTheme = useMemo(
|
|
2227
|
+
() => resolveCalendarTheme(
|
|
2228
|
+
activeThemeKey,
|
|
2229
|
+
activeColorScheme,
|
|
2230
|
+
activePaletteKey,
|
|
2231
|
+
strapiNeutral0
|
|
2232
|
+
),
|
|
2233
|
+
[activeThemeKey, activeColorScheme, activePaletteKey, strapiNeutral0]
|
|
2234
|
+
);
|
|
2235
|
+
const effectiveDirection = useMemo(
|
|
2236
|
+
() => direction ?? resolveCalendarDirection(locale, settings?.direction),
|
|
2237
|
+
[direction, locale, settings?.direction]
|
|
2238
|
+
);
|
|
2239
|
+
const effectiveFirstDay = useMemo(
|
|
2240
|
+
() => resolveLocaleFirstDay(locale, settings?.firstDayOfWeek),
|
|
2241
|
+
[locale, settings?.firstDayOfWeek]
|
|
2242
|
+
);
|
|
2243
|
+
const timeFormat = useMemo(
|
|
2244
|
+
() => buildFullCalendarTimeFormat(settings?.timeFormat24h ?? true),
|
|
2245
|
+
[settings?.timeFormat24h]
|
|
2246
|
+
);
|
|
2247
|
+
const gridConfig = useMemo(
|
|
2248
|
+
() => buildCalendarGridConfig(settings),
|
|
2249
|
+
[settings]
|
|
2250
|
+
);
|
|
2251
|
+
const handleDatesSet = useCallback(
|
|
2252
|
+
(dateInfo) => {
|
|
2253
|
+
onDatesSet(
|
|
2254
|
+
dateInfo.view.currentStart,
|
|
2255
|
+
dateInfo.start.toISOString(),
|
|
2256
|
+
dateInfo.end.toISOString()
|
|
2257
|
+
);
|
|
2258
|
+
},
|
|
2259
|
+
[onDatesSet]
|
|
2260
|
+
);
|
|
2261
|
+
const handleDateClick = useCallback(
|
|
2262
|
+
(clickInfo) => {
|
|
2263
|
+
if (allowCreate) onSelectSlot(clickInfo.dateStr, "");
|
|
2264
|
+
},
|
|
2265
|
+
[allowCreate, onSelectSlot]
|
|
2266
|
+
);
|
|
2267
|
+
const handleSelect = useCallback(
|
|
2268
|
+
(selectInfo) => {
|
|
2269
|
+
if (allowCreate) onSelectSlot(selectInfo.startStr, selectInfo.endStr);
|
|
2270
|
+
},
|
|
2271
|
+
[allowCreate, onSelectSlot]
|
|
2272
|
+
);
|
|
2273
|
+
const handleEventClick = useCallback(
|
|
2274
|
+
(clickInfo) => {
|
|
2275
|
+
const occ = clickInfo.event.extendedProps?.occurrence;
|
|
2276
|
+
if (occ) onSelectOccurrence(occ);
|
|
2277
|
+
},
|
|
2278
|
+
[onSelectOccurrence]
|
|
2279
|
+
);
|
|
2280
|
+
const handleEventDropOrResize = useCallback(
|
|
2281
|
+
(arg) => {
|
|
2282
|
+
const occ = arg.event.extendedProps?.occurrence;
|
|
2283
|
+
if (!occ || !arg.event.start) return;
|
|
2284
|
+
const startIso = arg.event.allDay ? `${arg.event.start.toISOString().slice(0, 10)}T00:00:00.000Z` : arg.event.start.toISOString();
|
|
2285
|
+
let endIso = arg.event.end?.toISOString();
|
|
2286
|
+
if (arg.event.allDay && arg.event.end) {
|
|
2287
|
+
const inclusiveEnd = new Date(arg.event.end.getTime() - 864e5);
|
|
2288
|
+
endIso = `${inclusiveEnd.toISOString().slice(0, 10)}T23:59:59.000Z`;
|
|
2289
|
+
}
|
|
2290
|
+
onDropOrResizeOccurrence(occ, startIso, endIso);
|
|
2291
|
+
},
|
|
2292
|
+
[onDropOrResizeOccurrence]
|
|
2293
|
+
);
|
|
2294
|
+
const renderDayCellContent = useCallback(
|
|
2295
|
+
(cellArg) => {
|
|
2296
|
+
const dateKey = cellArg.date.toISOString().slice(0, 10);
|
|
2297
|
+
const secondaryBadges = computeSecondaryBadges(
|
|
2298
|
+
dateKey,
|
|
2299
|
+
effectiveSecondaryLang,
|
|
2300
|
+
localeBundle.code,
|
|
2301
|
+
activeSecondaryCalendars
|
|
2302
|
+
);
|
|
2303
|
+
const cleanDayNumber = cellArg.dayNumberText.replace(/[^\d٠-٩]/g, "") || cellArg.dayNumberText;
|
|
2304
|
+
const isCompactYear = cellArg.view?.type === "multiMonthYear";
|
|
2305
|
+
const secondarySummary = secondaryBadges.join(" · ");
|
|
2306
|
+
const tooltipParts = [
|
|
2307
|
+
dateKey,
|
|
2308
|
+
secondarySummary,
|
|
2309
|
+
allowCreate ? "+" : ""
|
|
2310
|
+
].filter(Boolean);
|
|
2311
|
+
return /* @__PURE__ */ jsxs(
|
|
2312
|
+
"div",
|
|
2313
|
+
{
|
|
2314
|
+
className: "vicacha-fc-day-header",
|
|
2315
|
+
onClick: (e) => {
|
|
2316
|
+
if (allowCreate) {
|
|
2317
|
+
e.stopPropagation();
|
|
2318
|
+
onSelectSlot(dateKey, "");
|
|
2319
|
+
}
|
|
2320
|
+
},
|
|
2321
|
+
title: tooltipParts.join(" • "),
|
|
2322
|
+
style: buildDayHeaderStyle(
|
|
2323
|
+
activeTheme,
|
|
2324
|
+
isCompactYear,
|
|
2325
|
+
secondaryBadges.length > 0,
|
|
2326
|
+
allowCreate
|
|
2327
|
+
),
|
|
2328
|
+
children: [
|
|
2329
|
+
/* @__PURE__ */ jsx(
|
|
2330
|
+
"span",
|
|
2331
|
+
{
|
|
2332
|
+
style: buildDayNumberBadgeStyle(
|
|
2333
|
+
activeTheme,
|
|
2334
|
+
isCompactYear,
|
|
2335
|
+
Boolean(cellArg.isToday)
|
|
2336
|
+
),
|
|
2337
|
+
children: cleanDayNumber
|
|
2338
|
+
}
|
|
2339
|
+
),
|
|
2340
|
+
!isCompactYear && /* @__PURE__ */ jsx(
|
|
2341
|
+
DayCellMetaBadges,
|
|
2342
|
+
{
|
|
2343
|
+
secondarySummary,
|
|
2344
|
+
effectiveSecondaryLang,
|
|
2345
|
+
activeTheme,
|
|
2346
|
+
allowCreate
|
|
2347
|
+
}
|
|
2348
|
+
)
|
|
2349
|
+
]
|
|
2350
|
+
}
|
|
2351
|
+
);
|
|
2352
|
+
},
|
|
2353
|
+
[
|
|
2354
|
+
activeSecondaryCalendars,
|
|
2355
|
+
activeTheme,
|
|
2356
|
+
allowCreate,
|
|
2357
|
+
effectiveSecondaryLang,
|
|
2358
|
+
localeBundle.code,
|
|
2359
|
+
onSelectSlot
|
|
2360
|
+
]
|
|
2361
|
+
);
|
|
2362
|
+
const themeCss = useMemo(
|
|
2363
|
+
() => buildCalendarThemeCss(activeTheme, allowCreate),
|
|
2364
|
+
[activeTheme, allowCreate]
|
|
2365
|
+
);
|
|
2366
|
+
return /* @__PURE__ */ jsxs(
|
|
2367
|
+
Box,
|
|
2368
|
+
{
|
|
2369
|
+
background: "neutral0",
|
|
2370
|
+
hasRadius: true,
|
|
2371
|
+
shadow: "tableShadow",
|
|
2372
|
+
padding: 4,
|
|
2373
|
+
style: { direction: effectiveDirection },
|
|
2374
|
+
children: [
|
|
2375
|
+
/* @__PURE__ */ jsx("style", { children: themeCss }),
|
|
2376
|
+
/* @__PURE__ */ jsx(
|
|
2377
|
+
"div",
|
|
2378
|
+
{
|
|
2379
|
+
className: `vicacha-fc-container vicacha-fc-theme-${activeTheme.id}`,
|
|
2380
|
+
"data-color-scheme": activeColorScheme,
|
|
2381
|
+
children: /* @__PURE__ */ jsx(
|
|
2382
|
+
FullCalendar,
|
|
2383
|
+
{
|
|
2384
|
+
ref: calendarRef,
|
|
2385
|
+
plugins: FULLCALENDAR_PLUGINS,
|
|
2386
|
+
views: VIEW_SPECIFIC_OPTIONS,
|
|
2387
|
+
initialView: gridConfig.initialView,
|
|
2388
|
+
headerToolbar: false,
|
|
2389
|
+
locales: ALL_CALENDAR_LOCALES,
|
|
2390
|
+
locale: localeBundle.code,
|
|
2391
|
+
direction: effectiveDirection,
|
|
2392
|
+
firstDay: effectiveFirstDay,
|
|
2393
|
+
weekNumbers: gridConfig.weekNumbers,
|
|
2394
|
+
weekNumberCalculation: gridConfig.weekNumberCalculation,
|
|
2395
|
+
weekText: localeBundle.weekText,
|
|
2396
|
+
allDayText: localeBundle.allDayText,
|
|
2397
|
+
moreLinkText: localeBundle.moreLinkText,
|
|
2398
|
+
noEventsText: localeBundle.noEventsText,
|
|
2399
|
+
buttonText: localeBundle.buttonText,
|
|
2400
|
+
eventTimeFormat: timeFormat,
|
|
2401
|
+
slotLabelFormat: timeFormat,
|
|
2402
|
+
weekends: gridConfig.weekends,
|
|
2403
|
+
slotMinTime: gridConfig.slotMinTime,
|
|
2404
|
+
slotMaxTime: gridConfig.slotMaxTime,
|
|
2405
|
+
slotDuration: gridConfig.slotDuration,
|
|
2406
|
+
businessHours: gridConfig.businessHours,
|
|
2407
|
+
nowIndicator: true,
|
|
2408
|
+
editable: true,
|
|
2409
|
+
selectable: allowCreate,
|
|
2410
|
+
selectMirror: true,
|
|
2411
|
+
dayMaxEvents: true,
|
|
2412
|
+
height: "auto",
|
|
2413
|
+
events,
|
|
2414
|
+
datesSet: handleDatesSet,
|
|
2415
|
+
dateClick: handleDateClick,
|
|
2416
|
+
select: handleSelect,
|
|
2417
|
+
eventClick: handleEventClick,
|
|
2418
|
+
eventDrop: handleEventDropOrResize,
|
|
2419
|
+
eventResize: handleEventDropOrResize,
|
|
2420
|
+
dayCellContent: renderDayCellContent,
|
|
2421
|
+
eventContent: renderEventContent
|
|
2422
|
+
}
|
|
2423
|
+
)
|
|
2424
|
+
}
|
|
2425
|
+
)
|
|
2426
|
+
]
|
|
2427
|
+
}
|
|
2428
|
+
);
|
|
2429
|
+
};
|
|
2430
|
+
function resolveSidePanelStartDate(docRecord, mappedStartField) {
|
|
2431
|
+
const candidates = [
|
|
2432
|
+
...mappedStartField ? [mappedStartField] : [],
|
|
2433
|
+
"startDate",
|
|
2434
|
+
"preferredDate",
|
|
2435
|
+
"date",
|
|
2436
|
+
"checkIn"
|
|
2437
|
+
];
|
|
2438
|
+
for (const key of candidates) {
|
|
2439
|
+
const val = docRecord[key];
|
|
2440
|
+
if (typeof val === "string" && val) return val;
|
|
2441
|
+
}
|
|
2442
|
+
return "";
|
|
2443
|
+
}
|
|
2444
|
+
const CalendarSidePanel = (props) => {
|
|
2445
|
+
const { formatMessage, locale } = useIntl();
|
|
2446
|
+
const { get } = useFetchClient();
|
|
2447
|
+
const [settings, setSettings] = useState(null);
|
|
2448
|
+
const model = props.model ?? "";
|
|
2449
|
+
const docRecord = props.document ?? {};
|
|
2450
|
+
const documentId = props.documentId ?? (typeof docRecord.documentId === "string" ? docRecord.documentId : "");
|
|
2451
|
+
const matchedSource = useMemo(
|
|
2452
|
+
() => settings?.sources?.find((s) => s.uid === model && s.enabled),
|
|
2453
|
+
[settings?.sources, model]
|
|
2454
|
+
);
|
|
2455
|
+
const rawStartDate = resolveSidePanelStartDate(
|
|
2456
|
+
docRecord,
|
|
2457
|
+
matchedSource?.fields.startDate
|
|
2458
|
+
);
|
|
2459
|
+
const activeLocale = resolveActiveContentLocale(locale);
|
|
2460
|
+
const rruleField = matchedSource?.fields.rrule || "recurrence";
|
|
2461
|
+
const hasScheduleFields = Boolean(rawStartDate || docRecord[rruleField]);
|
|
2462
|
+
useEffect(() => {
|
|
2463
|
+
if (!hasScheduleFields || !documentId) return;
|
|
2464
|
+
let mounted = true;
|
|
2465
|
+
get(`/${PLUGIN_ID}/settings`).then((res) => {
|
|
2466
|
+
if (mounted && res?.data?.data) {
|
|
2467
|
+
setSettings(res.data.data);
|
|
2468
|
+
}
|
|
2469
|
+
}).catch(() => {
|
|
2470
|
+
});
|
|
2471
|
+
return () => {
|
|
2472
|
+
mounted = false;
|
|
2473
|
+
};
|
|
2474
|
+
}, [model, get, hasScheduleFields, documentId]);
|
|
2475
|
+
const computedAlternateDates = useMemo(() => {
|
|
2476
|
+
if (!rawStartDate || !settings?.secondaryCalendars) {
|
|
2477
|
+
return [];
|
|
2478
|
+
}
|
|
2479
|
+
return settings.secondaryCalendars.filter((sys) => sys.enabled).map((sys) => {
|
|
2480
|
+
const rawFieldVal = sys.overrideField ? docRecord[sys.overrideField] : void 0;
|
|
2481
|
+
const overrideVal = typeof rawFieldVal === "string" ? rawFieldVal.trim() : "";
|
|
2482
|
+
const formatted = overrideVal || formatDateInCalendarSystem(rawStartDate, sys, activeLocale, {
|
|
2483
|
+
compact: false
|
|
2484
|
+
});
|
|
2485
|
+
return {
|
|
2486
|
+
id: sys.id,
|
|
2487
|
+
label: sys.label,
|
|
2488
|
+
formatted,
|
|
2489
|
+
isOverridden: Boolean(overrideVal)
|
|
2490
|
+
};
|
|
2491
|
+
}).filter((item) => Boolean(item.formatted));
|
|
2492
|
+
}, [rawStartDate, settings?.secondaryCalendars, docRecord, activeLocale]);
|
|
2493
|
+
if (!hasScheduleFields || !documentId) {
|
|
2494
|
+
return null;
|
|
2495
|
+
}
|
|
2496
|
+
const t = (id, defaultMessage) => formatPluginMessageWithUrlLocale(
|
|
2497
|
+
PLUGIN_ID,
|
|
2498
|
+
id,
|
|
2499
|
+
defaultMessage,
|
|
2500
|
+
formatMessage
|
|
2501
|
+
);
|
|
2502
|
+
const icsUrl = `/api/calendar/${encodeURIComponent(documentId)}/invite.ics`;
|
|
2503
|
+
return {
|
|
2504
|
+
title: t("sidePanel.title", "Calendar & Schedule"),
|
|
2505
|
+
content: /* @__PURE__ */ jsx(Box, { paddingTop: 2, paddingBottom: 2, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
|
|
2506
|
+
computedAlternateDates.length > 0 && /* @__PURE__ */ jsxs(Box, { padding: 3, background: "neutral100", hasRadius: true, children: [
|
|
2507
|
+
/* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: t(
|
|
2508
|
+
"sidePanel.secondaryCalendars",
|
|
2509
|
+
"Alternative Calendar Dates"
|
|
2510
|
+
) }),
|
|
2511
|
+
/* @__PURE__ */ jsx(
|
|
2512
|
+
Flex,
|
|
2513
|
+
{
|
|
2514
|
+
direction: "column",
|
|
2515
|
+
alignItems: "stretch",
|
|
2516
|
+
gap: 1,
|
|
2517
|
+
paddingTop: 2,
|
|
2518
|
+
children: computedAlternateDates.map((alt) => /* @__PURE__ */ jsxs(
|
|
2519
|
+
Flex,
|
|
2520
|
+
{
|
|
2521
|
+
justifyContent: "space-between",
|
|
2522
|
+
alignItems: "center",
|
|
2523
|
+
children: [
|
|
2524
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
|
|
2525
|
+
alt.label,
|
|
2526
|
+
":"
|
|
2527
|
+
] }),
|
|
2528
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: alt.formatted })
|
|
2529
|
+
]
|
|
2530
|
+
},
|
|
2531
|
+
alt.id
|
|
2532
|
+
))
|
|
2533
|
+
}
|
|
2534
|
+
)
|
|
2535
|
+
] }),
|
|
2536
|
+
/* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
|
2537
|
+
/* @__PURE__ */ jsx(
|
|
2538
|
+
Button,
|
|
2539
|
+
{
|
|
2540
|
+
variant: "secondary",
|
|
2541
|
+
size: "S",
|
|
2542
|
+
tag: "a",
|
|
2543
|
+
href: icsUrl,
|
|
2544
|
+
target: "_blank",
|
|
2545
|
+
rel: "noopener noreferrer",
|
|
2546
|
+
children: t("sidePanel.downloadIcs", "Download .ics Invite")
|
|
2547
|
+
}
|
|
2548
|
+
),
|
|
2549
|
+
/* @__PURE__ */ jsx(
|
|
2550
|
+
Button,
|
|
2551
|
+
{
|
|
2552
|
+
variant: "tertiary",
|
|
2553
|
+
size: "S",
|
|
2554
|
+
tag: NavLink,
|
|
2555
|
+
to: `/plugins/${PLUGIN_ID}?documentId=${encodeURIComponent(documentId)}`,
|
|
2556
|
+
children: t("sidePanel.openCalendar", "Open in Calendar View")
|
|
2557
|
+
}
|
|
2558
|
+
)
|
|
2559
|
+
] })
|
|
2560
|
+
] }) })
|
|
2561
|
+
};
|
|
2562
|
+
};
|
|
2563
|
+
const Initializer = ({ setPlugin }) => {
|
|
2564
|
+
const ref = useRef(setPlugin);
|
|
2565
|
+
useEffect(() => {
|
|
2566
|
+
ref.current?.(PLUGIN_ID);
|
|
2567
|
+
}, []);
|
|
2568
|
+
return null;
|
|
2569
|
+
};
|
|
2570
|
+
const PluginIcon = () => /* @__PURE__ */ jsx(Calendar, {});
|
|
2571
|
+
const VALID_FREQUENCIES = [
|
|
2572
|
+
"NONE",
|
|
2573
|
+
"DAILY",
|
|
2574
|
+
"WEEKLY",
|
|
2575
|
+
"MONTHLY",
|
|
2576
|
+
"YEARLY"
|
|
2577
|
+
];
|
|
2578
|
+
const JS_DAY_TO_RRULE_DAY = [
|
|
2579
|
+
"SU",
|
|
2580
|
+
"MO",
|
|
2581
|
+
"TU",
|
|
2582
|
+
"WE",
|
|
2583
|
+
"TH",
|
|
2584
|
+
"FR",
|
|
2585
|
+
"SA"
|
|
2586
|
+
];
|
|
2587
|
+
const DAY_LABELS = {
|
|
2588
|
+
MO: "Mon",
|
|
2589
|
+
TU: "Tue",
|
|
2590
|
+
WE: "Wed",
|
|
2591
|
+
TH: "Thu",
|
|
2592
|
+
FR: "Fri",
|
|
2593
|
+
SA: "Sat",
|
|
2594
|
+
SU: "Sun"
|
|
2595
|
+
};
|
|
2596
|
+
const FREQ_UNITS = {
|
|
2597
|
+
NONE: ["", "days"],
|
|
2598
|
+
DAILY: ["Every day", "days"],
|
|
2599
|
+
WEEKLY: ["Every week", "weeks"],
|
|
2600
|
+
MONTHLY: ["Every month", "months"],
|
|
2601
|
+
YEARLY: ["Every year", "years"]
|
|
2602
|
+
};
|
|
2603
|
+
function parseBoundedInt(val, min, max) {
|
|
2604
|
+
const n = Number.parseInt(val, 10);
|
|
2605
|
+
return Number.isFinite(n) && n >= min && n <= max ? n : void 0;
|
|
2606
|
+
}
|
|
2607
|
+
function parseUntilDate(val) {
|
|
2608
|
+
if (/^\d{8}(?:T\d{6}Z?)?$/.test(val)) {
|
|
2609
|
+
return `${val.slice(0, 4)}-${val.slice(4, 6)}-${val.slice(6, 8)}`;
|
|
2610
|
+
}
|
|
2611
|
+
return /^\d{4}-\d{2}-\d{2}/.test(val) ? val.slice(0, 10) : void 0;
|
|
2612
|
+
}
|
|
2613
|
+
function parseByDayList(val) {
|
|
2614
|
+
return val.split(",").map((d) => d.trim().slice(-2)).filter((d) => JS_DAY_TO_RRULE_DAY.includes(d));
|
|
2615
|
+
}
|
|
2616
|
+
const intAssigner = (key, min, max) => (p, v) => {
|
|
2617
|
+
const n = parseBoundedInt(v, min, max);
|
|
2618
|
+
if (n !== void 0) p[key] = n;
|
|
2619
|
+
};
|
|
2620
|
+
const RRULE_PART_ASSIGNERS = {
|
|
2621
|
+
RSCALE: (p, v) => {
|
|
2622
|
+
if (v) p.rscale = v.toLowerCase();
|
|
2623
|
+
},
|
|
2624
|
+
FREQ: (p, v) => {
|
|
2625
|
+
if (VALID_FREQUENCIES.includes(v)) {
|
|
2626
|
+
p.freq = v;
|
|
2627
|
+
}
|
|
2628
|
+
},
|
|
2629
|
+
INTERVAL: intAssigner("interval", 1, 365),
|
|
2630
|
+
BYDAY: (p, v) => {
|
|
2631
|
+
p.byDay = parseByDayList(v);
|
|
2632
|
+
},
|
|
2633
|
+
BYMONTH: intAssigner("byMonth", 1, 13),
|
|
2634
|
+
BYMONTHDAY: intAssigner("byMonthDay", 1, 31),
|
|
2635
|
+
COUNT: intAssigner("count", 1, 1e3),
|
|
2636
|
+
UNTIL: (p, v) => {
|
|
2637
|
+
const u = parseUntilDate(v);
|
|
2638
|
+
if (u !== void 0) p.until = u;
|
|
2639
|
+
}
|
|
2640
|
+
};
|
|
2641
|
+
function parseRRule(rawRule) {
|
|
2642
|
+
const defaultParsed = { freq: "NONE", interval: 1, byDay: [] };
|
|
2643
|
+
if (!rawRule || typeof rawRule !== "string") return defaultParsed;
|
|
2644
|
+
const cleaned = rawRule.trim().replace(/^RRULE:/i, "");
|
|
2645
|
+
if (!cleaned) return defaultParsed;
|
|
2646
|
+
const parsed = { ...defaultParsed };
|
|
2647
|
+
for (const part of cleaned.split(";")) {
|
|
2648
|
+
const [rawKey, rawVal] = part.split("=");
|
|
2649
|
+
if (!rawKey || !rawVal) continue;
|
|
2650
|
+
RRULE_PART_ASSIGNERS[rawKey.trim().toUpperCase()]?.(
|
|
2651
|
+
parsed,
|
|
2652
|
+
rawVal.trim().toUpperCase()
|
|
2653
|
+
);
|
|
2654
|
+
}
|
|
2655
|
+
return parsed;
|
|
2656
|
+
}
|
|
2657
|
+
function buildRRule(parsed) {
|
|
2658
|
+
if (!parsed || parsed.freq === "NONE") return "";
|
|
2659
|
+
const rscale = parsed.rscale;
|
|
2660
|
+
const segments = [];
|
|
2661
|
+
if (rscale && rscale !== "gregory" && rscale !== "iso8601") {
|
|
2662
|
+
segments.push(`RSCALE=${rscale.toUpperCase()}`);
|
|
2663
|
+
}
|
|
2664
|
+
segments.push(
|
|
2665
|
+
`FREQ=${parsed.freq}`,
|
|
2666
|
+
`INTERVAL=${Math.max(1, Math.floor(parsed.interval || 1))}`
|
|
2667
|
+
);
|
|
2668
|
+
if (parsed.freq === "WEEKLY" && Array.isArray(parsed.byDay)) {
|
|
2669
|
+
const validDays = parsed.byDay.filter(
|
|
2670
|
+
(d) => JS_DAY_TO_RRULE_DAY.includes(d)
|
|
2671
|
+
);
|
|
2672
|
+
if (validDays.length > 0) segments.push(`BYDAY=${validDays.join(",")}`);
|
|
2673
|
+
}
|
|
2674
|
+
if (parsed.freq === "YEARLY" && typeof parsed.byMonth === "number" && parsed.byMonth >= 1 && parsed.byMonth <= 13) {
|
|
2675
|
+
segments.push(`BYMONTH=${Math.floor(parsed.byMonth)}`);
|
|
2676
|
+
}
|
|
2677
|
+
if ((parsed.freq === "MONTHLY" || parsed.freq === "YEARLY") && typeof parsed.byMonthDay === "number" && parsed.byMonthDay >= 1 && parsed.byMonthDay <= 31) {
|
|
2678
|
+
segments.push(`BYMONTHDAY=${Math.floor(parsed.byMonthDay)}`);
|
|
2679
|
+
}
|
|
2680
|
+
if (typeof parsed.count === "number" && parsed.count >= 1) {
|
|
2681
|
+
segments.push(`COUNT=${Math.floor(parsed.count)}`);
|
|
2682
|
+
} else if (parsed.until && /^\d{4}-\d{2}-\d{2}$/.test(parsed.until)) {
|
|
2683
|
+
segments.push(`UNTIL=${parsed.until.replace(/-/g, "")}T235959Z`);
|
|
2684
|
+
}
|
|
2685
|
+
return segments.join(";");
|
|
2686
|
+
}
|
|
2687
|
+
function formatRRuleSuffix(parsed) {
|
|
2688
|
+
if (parsed.freq === "WEEKLY" && parsed.byDay.length > 0) {
|
|
2689
|
+
return ` on ${parsed.byDay.map((d) => DAY_LABELS[d]).join(", ")}`;
|
|
2690
|
+
}
|
|
2691
|
+
if (parsed.freq === "YEARLY" && parsed.byMonth && parsed.byMonthDay) {
|
|
2692
|
+
return ` on month ${parsed.byMonth}, day ${parsed.byMonthDay}`;
|
|
2693
|
+
}
|
|
2694
|
+
if (parsed.freq === "MONTHLY" && parsed.byMonthDay) {
|
|
2695
|
+
return ` on day ${parsed.byMonthDay}`;
|
|
2696
|
+
}
|
|
2697
|
+
return "";
|
|
2698
|
+
}
|
|
2699
|
+
function describeRRule(rawRule) {
|
|
2700
|
+
const parsed = parseRRule(rawRule);
|
|
2701
|
+
if (parsed.freq === "NONE") return "Does not repeat (Single occurrence)";
|
|
2702
|
+
const rscalePrefix = parsed.rscale && parsed.rscale !== "gregory" ? `[${parsed.rscale.toUpperCase()}] ` : "";
|
|
2703
|
+
const [singular, plural] = FREQ_UNITS[parsed.freq] || ["Every year", "years"];
|
|
2704
|
+
const intervalText = parsed.interval === 1 ? singular : `Every ${parsed.interval} ${plural}`;
|
|
2705
|
+
const limit = parsed.count ? `, ${parsed.count} times` : parsed.until ? `, until ${parsed.until}` : "";
|
|
2706
|
+
return `${rscalePrefix}${intervalText}${formatRRuleSuffix(parsed)}${limit}`;
|
|
2707
|
+
}
|
|
2708
|
+
function normalizeRRuleObject(obj, defaultTimezone) {
|
|
2709
|
+
const rrule = typeof obj.rrule === "string" ? obj.rrule : "";
|
|
2710
|
+
const parsed = parseRRule(rrule);
|
|
2711
|
+
const timezone = typeof obj.timezone === "string" && obj.timezone ? obj.timezone : defaultTimezone;
|
|
2712
|
+
const rscale = typeof obj.rscale === "string" ? obj.rscale : parsed.rscale;
|
|
2713
|
+
const exdates = Array.isArray(obj.exdates) ? obj.exdates.filter((d) => typeof d === "string") : [];
|
|
2714
|
+
const overrides = obj.overrides && typeof obj.overrides === "object" ? obj.overrides : {};
|
|
2715
|
+
return {
|
|
2716
|
+
rrule,
|
|
2717
|
+
timezone,
|
|
2718
|
+
rscale,
|
|
2719
|
+
allDay: Boolean(obj.allDay),
|
|
2720
|
+
exdates,
|
|
2721
|
+
overrides
|
|
2722
|
+
};
|
|
2723
|
+
}
|
|
2724
|
+
function parseRRuleFieldValue(raw, defaultTimezone = "UTC") {
|
|
2725
|
+
const fallback = normalizeRRuleObject({}, defaultTimezone);
|
|
2726
|
+
if (!raw) return fallback;
|
|
2727
|
+
if (typeof raw === "string") {
|
|
2728
|
+
const trimmed = raw.trim();
|
|
2729
|
+
if (trimmed.startsWith("{")) {
|
|
2730
|
+
try {
|
|
2731
|
+
const obj = JSON.parse(trimmed);
|
|
2732
|
+
return normalizeRRuleObject(obj, defaultTimezone);
|
|
2733
|
+
} catch {
|
|
2734
|
+
return fallback;
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
const parsed = parseRRule(trimmed);
|
|
2738
|
+
return { ...fallback, rrule: trimmed, rscale: parsed.rscale };
|
|
2739
|
+
}
|
|
2740
|
+
return typeof raw === "object" ? normalizeRRuleObject(raw, defaultTimezone) : fallback;
|
|
2741
|
+
}
|
|
2742
|
+
const WEEKDAYS = [
|
|
2743
|
+
{ code: "MO", label: "Mon" },
|
|
2744
|
+
{ code: "TU", label: "Tue" },
|
|
2745
|
+
{ code: "WE", label: "Wed" },
|
|
2746
|
+
{ code: "TH", label: "Thu" },
|
|
2747
|
+
{ code: "FR", label: "Fri" },
|
|
2748
|
+
{ code: "SA", label: "Sat" },
|
|
2749
|
+
{ code: "SU", label: "Sun" }
|
|
2750
|
+
];
|
|
2751
|
+
const COMMON_TIMEZONES = "UTC,America/Bogota,America/New_York,America/Mexico_City,America/Sao_Paulo,Europe/Madrid,Europe/London,Europe/Paris,Europe/Berlin,Europe/Amsterdam,Europe/Istanbul,Asia/Riyadh,Asia/Dubai".split(
|
|
2752
|
+
","
|
|
2753
|
+
);
|
|
2754
|
+
const FREQ_OPTIONS = [
|
|
2755
|
+
["NONE", "rrule.freq.none", "Does not repeat (Single Entry)"],
|
|
2756
|
+
["DAILY", "rrule.freq.daily", "Daily"],
|
|
2757
|
+
["WEEKLY", "rrule.freq.weekly", "Weekly"],
|
|
2758
|
+
["MONTHLY", "rrule.freq.monthly", "Monthly"],
|
|
2759
|
+
["YEARLY", "rrule.freq.yearly", "Yearly"]
|
|
2760
|
+
];
|
|
2761
|
+
const END_OPTIONS = [
|
|
2762
|
+
["never", "rrule.ends.never", "Never (Ongoing)"],
|
|
2763
|
+
["until", "rrule.ends.until", "On Specific Date (UNTIL)"],
|
|
2764
|
+
["count", "rrule.ends.count", "After N Occurrences (COUNT)"]
|
|
2765
|
+
];
|
|
2766
|
+
const REMOVE_BTN_STYLE = {
|
|
2767
|
+
border: "none",
|
|
2768
|
+
background: "transparent",
|
|
2769
|
+
cursor: "pointer"
|
|
2770
|
+
};
|
|
2771
|
+
function applyEndModeChange(mode, updateRule) {
|
|
2772
|
+
if (mode === "never") {
|
|
2773
|
+
updateRule({ count: void 0, until: void 0 });
|
|
2774
|
+
} else if (mode === "count") {
|
|
2775
|
+
updateRule({ count: 10, until: void 0 });
|
|
2776
|
+
} else if (mode === "until") {
|
|
2777
|
+
const nextYear = /* @__PURE__ */ new Date();
|
|
2778
|
+
nextYear.setUTCFullYear(nextYear.getUTCFullYear() + 1);
|
|
2779
|
+
updateRule({
|
|
2780
|
+
until: nextYear.toISOString().slice(0, 10),
|
|
2781
|
+
count: void 0
|
|
2782
|
+
});
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
const RRuleInput = ({
|
|
2786
|
+
name,
|
|
2787
|
+
value,
|
|
2788
|
+
onChange,
|
|
2789
|
+
disabled = false,
|
|
2790
|
+
error,
|
|
2791
|
+
label,
|
|
2792
|
+
required = false,
|
|
2793
|
+
hint
|
|
2794
|
+
}) => {
|
|
2795
|
+
const { formatMessage } = useIntl();
|
|
2796
|
+
const t = (id, defaultMessage) => formatPluginMessageWithUrlLocale(
|
|
2797
|
+
PLUGIN_ID,
|
|
2798
|
+
id,
|
|
2799
|
+
defaultMessage,
|
|
2800
|
+
formatMessage
|
|
2801
|
+
);
|
|
2802
|
+
const fieldValue = useMemo(() => parseRRuleFieldValue(value, "UTC"), [value]);
|
|
2803
|
+
const parsedRule = useMemo(
|
|
2804
|
+
() => parseRRule(fieldValue.rrule),
|
|
2805
|
+
[fieldValue.rrule]
|
|
2806
|
+
);
|
|
2807
|
+
const [newExdate, setNewExdate] = useState("");
|
|
2808
|
+
const isRepeating = parsedRule.freq !== "NONE";
|
|
2809
|
+
const endMode = parsedRule.until ? "until" : parsedRule.count ? "count" : "never";
|
|
2810
|
+
const emitChange = (next) => {
|
|
2811
|
+
onChange({ target: { name, value: next, type: "json" } });
|
|
2812
|
+
};
|
|
2813
|
+
const updateRule = (patch) => {
|
|
2814
|
+
const merged = { ...parsedRule, ...patch };
|
|
2815
|
+
emitChange({
|
|
2816
|
+
...fieldValue,
|
|
2817
|
+
rrule: buildRRule(merged),
|
|
2818
|
+
rscale: merged.rscale
|
|
2819
|
+
});
|
|
2820
|
+
};
|
|
2821
|
+
const toggleWeekday = (day) => {
|
|
2822
|
+
const nextDays = parsedRule.byDay.includes(day) ? parsedRule.byDay.filter((d) => d !== day) : [...parsedRule.byDay, day];
|
|
2823
|
+
updateRule({ byDay: nextDays });
|
|
2824
|
+
};
|
|
2825
|
+
const handleAddExdate = () => {
|
|
2826
|
+
const clean = newExdate.trim();
|
|
2827
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(clean)) return;
|
|
2828
|
+
const current = fieldValue.exdates ?? [];
|
|
2829
|
+
if (!current.includes(clean)) {
|
|
2830
|
+
emitChange({ ...fieldValue, exdates: [...current, clean].sort() });
|
|
2831
|
+
}
|
|
2832
|
+
setNewExdate("");
|
|
2833
|
+
};
|
|
2834
|
+
const handleRemoveExdate = (dateToRemove) => {
|
|
2835
|
+
emitChange({
|
|
2836
|
+
...fieldValue,
|
|
2837
|
+
exdates: (fieldValue.exdates ?? []).filter((d) => d !== dateToRemove)
|
|
2838
|
+
});
|
|
2839
|
+
};
|
|
2840
|
+
const renderSelect = (style, labelText, placeholderText, val, options, onSelect) => /* @__PURE__ */ jsx(Box, { style, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
|
|
2841
|
+
/* @__PURE__ */ jsx(Field.Label, { children: labelText }),
|
|
2842
|
+
/* @__PURE__ */ jsx(
|
|
2843
|
+
SingleSelect,
|
|
2844
|
+
{
|
|
2845
|
+
disabled,
|
|
2846
|
+
placeholder: placeholderText,
|
|
2847
|
+
value: val,
|
|
2848
|
+
onChange: onSelect,
|
|
2849
|
+
children: options.map(([optVal, optLabel]) => /* @__PURE__ */ jsx(SingleSelectOption, { value: optVal, children: optLabel }, optVal))
|
|
2850
|
+
}
|
|
2851
|
+
)
|
|
2852
|
+
] }) });
|
|
2853
|
+
const renderNumber = (width, labelText, placeholderText, val, onValChange) => /* @__PURE__ */ jsx(Box, { style: { width }, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
|
|
2854
|
+
/* @__PURE__ */ jsx(Field.Label, { children: labelText }),
|
|
2855
|
+
/* @__PURE__ */ jsx(
|
|
2856
|
+
NumberInput,
|
|
2857
|
+
{
|
|
2858
|
+
disabled,
|
|
2859
|
+
placeholder: placeholderText,
|
|
2860
|
+
value: val,
|
|
2861
|
+
onValueChange: onValChange
|
|
2862
|
+
}
|
|
2863
|
+
)
|
|
2864
|
+
] }) });
|
|
2865
|
+
const exdatesList = fieldValue.exdates ?? [];
|
|
2866
|
+
const summaryText = !isRepeating ? t("rrule.freq.none", "Does not repeat (Single Entry)") : describeRRule(fieldValue.rrule);
|
|
2867
|
+
return /* @__PURE__ */ jsx(Field.Root, { name, error, hint, required, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
|
|
2868
|
+
label && /* @__PURE__ */ jsx(Field.Label, { children: label }),
|
|
2869
|
+
/* @__PURE__ */ jsx(
|
|
2870
|
+
Box,
|
|
2871
|
+
{
|
|
2872
|
+
padding: 4,
|
|
2873
|
+
background: "neutral100",
|
|
2874
|
+
borderColor: "neutral200",
|
|
2875
|
+
hasRadius: true,
|
|
2876
|
+
children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
|
|
2877
|
+
/* @__PURE__ */ jsxs(
|
|
2878
|
+
Flex,
|
|
2879
|
+
{
|
|
2880
|
+
justifyContent: "space-between",
|
|
2881
|
+
alignItems: "center",
|
|
2882
|
+
wrap: "wrap",
|
|
2883
|
+
gap: 2,
|
|
2884
|
+
children: [
|
|
2885
|
+
/* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: t("rrule.summaryLabel", "Recurrence Summary") }),
|
|
2886
|
+
/* @__PURE__ */ jsx(Badge, { backgroundColor: "primary100", textColor: "primary700", children: summaryText })
|
|
2887
|
+
]
|
|
2888
|
+
}
|
|
2889
|
+
),
|
|
2890
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 3, wrap: "wrap", children: [
|
|
2891
|
+
renderSelect(
|
|
2892
|
+
{ flex: 1, minWidth: 170 },
|
|
2893
|
+
t("rrule.frequency", "Repeat Frequency"),
|
|
2894
|
+
t(
|
|
2895
|
+
"placeholder.select_repeat_frequency",
|
|
2896
|
+
"Select repeat frequency"
|
|
2897
|
+
),
|
|
2898
|
+
parsedRule.freq,
|
|
2899
|
+
FREQ_OPTIONS.map(([v, id, def]) => [v, t(id, def)]),
|
|
2900
|
+
(val) => updateRule({
|
|
2901
|
+
freq: val,
|
|
2902
|
+
byDay: val === "WEEKLY" ? ["FR"] : []
|
|
2903
|
+
})
|
|
2904
|
+
),
|
|
2905
|
+
isRepeating && renderNumber(
|
|
2906
|
+
130,
|
|
2907
|
+
t("rrule.interval", "Every (Interval)"),
|
|
2908
|
+
t("placeholder.1", "1"),
|
|
2909
|
+
parsedRule.interval,
|
|
2910
|
+
(val) => updateRule({ interval: val && val >= 1 ? val : 1 })
|
|
2911
|
+
),
|
|
2912
|
+
isRepeating && renderSelect(
|
|
2913
|
+
{ flex: 1, minWidth: 190 },
|
|
2914
|
+
t("rrule.rscale", "Calendar Scale (RSCALE)"),
|
|
2915
|
+
t(
|
|
2916
|
+
"placeholder.select_calendar_scale",
|
|
2917
|
+
"Select calendar scale"
|
|
2918
|
+
),
|
|
2919
|
+
parsedRule.rscale || "gregory",
|
|
2920
|
+
SUPPORTED_INTL_CALENDARS.map((c) => [
|
|
2921
|
+
c.intlCalendar,
|
|
2922
|
+
c.defaultLabel
|
|
2923
|
+
]),
|
|
2924
|
+
(val) => updateRule({ rscale: val === "gregory" ? void 0 : val })
|
|
2925
|
+
),
|
|
2926
|
+
renderSelect(
|
|
2927
|
+
{ flex: 1, minWidth: 180 },
|
|
2928
|
+
t("rrule.timezone", "Timezone"),
|
|
2929
|
+
t("placeholder.select_timezone", "Select timezone"),
|
|
2930
|
+
fieldValue.timezone || "UTC",
|
|
2931
|
+
COMMON_TIMEZONES.map((tz) => [tz, tz]),
|
|
2932
|
+
(tz) => emitChange({ ...fieldValue, timezone: String(tz) })
|
|
2933
|
+
)
|
|
2934
|
+
] }),
|
|
2935
|
+
/* @__PURE__ */ jsx(
|
|
2936
|
+
Checkbox,
|
|
2937
|
+
{
|
|
2938
|
+
disabled,
|
|
2939
|
+
checked: Boolean(fieldValue.allDay),
|
|
2940
|
+
onCheckedChange: (checked) => emitChange({ ...fieldValue, allDay: Boolean(checked) }),
|
|
2941
|
+
children: t("rrule.allDay", "All-day entry")
|
|
2942
|
+
}
|
|
2943
|
+
),
|
|
2944
|
+
parsedRule.freq === "WEEKLY" && /* @__PURE__ */ jsxs(Box, { children: [
|
|
2945
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: t("rrule.byDay", "Repeat on Weekdays") }),
|
|
2946
|
+
/* @__PURE__ */ jsx(Flex, { gap: 2, paddingTop: 2, wrap: "wrap", children: WEEKDAYS.map((day) => {
|
|
2947
|
+
const active = parsedRule.byDay.includes(day.code);
|
|
2948
|
+
return /* @__PURE__ */ jsx(
|
|
2949
|
+
Button,
|
|
2950
|
+
{
|
|
2951
|
+
size: "S",
|
|
2952
|
+
variant: active ? "default" : "tertiary",
|
|
2953
|
+
disabled,
|
|
2954
|
+
onClick: () => toggleWeekday(day.code),
|
|
2955
|
+
children: t(`weekday.${day.code.toLowerCase()}`, day.label)
|
|
2956
|
+
},
|
|
2957
|
+
day.code
|
|
2958
|
+
);
|
|
2959
|
+
}) })
|
|
2960
|
+
] }),
|
|
2961
|
+
(parsedRule.freq === "MONTHLY" || parsedRule.freq === "YEARLY") && /* @__PURE__ */ jsxs(Flex, { gap: 3, wrap: "wrap", children: [
|
|
2962
|
+
parsedRule.freq === "YEARLY" && renderNumber(
|
|
2963
|
+
160,
|
|
2964
|
+
t("rrule.byMonth", "Month (1-12)"),
|
|
2965
|
+
t("placeholder.1", "1"),
|
|
2966
|
+
parsedRule.byMonth ?? 1,
|
|
2967
|
+
(val) => {
|
|
2968
|
+
const maxMonth = parsedRule.rscale && parsedRule.rscale !== "gregory" && parsedRule.rscale !== "iso8601" ? 13 : 12;
|
|
2969
|
+
updateRule({
|
|
2970
|
+
byMonth: val && val >= 1 && val <= maxMonth ? Math.floor(val) : void 0
|
|
2971
|
+
});
|
|
2972
|
+
}
|
|
2973
|
+
),
|
|
2974
|
+
renderNumber(
|
|
2975
|
+
160,
|
|
2976
|
+
t("rrule.byMonthDay", "Day of Month (1-31)"),
|
|
2977
|
+
t("placeholder.1", "1"),
|
|
2978
|
+
parsedRule.byMonthDay ?? 1,
|
|
2979
|
+
(val) => updateRule({
|
|
2980
|
+
byMonthDay: val && val >= 1 && val <= 31 ? Math.floor(val) : void 0
|
|
2981
|
+
})
|
|
2982
|
+
)
|
|
2983
|
+
] }),
|
|
2984
|
+
isRepeating && /* @__PURE__ */ jsxs(Flex, { gap: 3, wrap: "wrap", alignItems: "flex-end", children: [
|
|
2985
|
+
renderSelect(
|
|
2986
|
+
{ width: 180 },
|
|
2987
|
+
t("rrule.ends", "Series Ends"),
|
|
2988
|
+
t(
|
|
2989
|
+
"placeholder.select_series_end_mode",
|
|
2990
|
+
"Select series end mode"
|
|
2991
|
+
),
|
|
2992
|
+
endMode,
|
|
2993
|
+
END_OPTIONS.map(([v, id, def]) => [v, t(id, def)]),
|
|
2994
|
+
(mode) => applyEndModeChange(mode, updateRule)
|
|
2995
|
+
),
|
|
2996
|
+
endMode === "until" && /* @__PURE__ */ jsx(Box, { style: { width: 200 }, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
|
|
2997
|
+
/* @__PURE__ */ jsx(Field.Label, { children: t("rrule.untilDate", "Until Date (YYYY-MM-DD)") }),
|
|
2998
|
+
/* @__PURE__ */ jsx(
|
|
2999
|
+
DatePicker,
|
|
3000
|
+
{
|
|
3001
|
+
disabled,
|
|
3002
|
+
value: parseDateTimePickerValue(parsedRule.until),
|
|
3003
|
+
clearLabel: t("common.clear", "Clear"),
|
|
3004
|
+
onChange: (d) => updateRule({
|
|
3005
|
+
until: d ? formatLocalYmd(d) : void 0
|
|
3006
|
+
}),
|
|
3007
|
+
onClear: () => updateRule({ until: void 0 })
|
|
3008
|
+
}
|
|
3009
|
+
)
|
|
3010
|
+
] }) }),
|
|
3011
|
+
endMode === "count" && renderNumber(
|
|
3012
|
+
180,
|
|
3013
|
+
t("rrule.occurrenceCount", "Max Occurrences"),
|
|
3014
|
+
t("placeholder.10", "10"),
|
|
3015
|
+
parsedRule.count ?? 10,
|
|
3016
|
+
(val) => updateRule({
|
|
3017
|
+
count: val && val >= 1 ? Math.floor(val) : 1
|
|
3018
|
+
})
|
|
3019
|
+
)
|
|
3020
|
+
] }),
|
|
3021
|
+
isRepeating && /* @__PURE__ */ jsxs(Box, { children: [
|
|
3022
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, paddingTop: 1, wrap: "wrap", alignItems: "flex-end", children: [
|
|
3023
|
+
/* @__PURE__ */ jsx(Box, { style: { width: 240 }, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
|
|
3024
|
+
/* @__PURE__ */ jsx(Field.Label, { children: t(
|
|
3025
|
+
"rrule.exdates",
|
|
3026
|
+
"Excluded Dates (Holiday / Exception Dates)"
|
|
3027
|
+
) }),
|
|
3028
|
+
/* @__PURE__ */ jsx(
|
|
3029
|
+
DatePicker,
|
|
3030
|
+
{
|
|
3031
|
+
disabled,
|
|
3032
|
+
value: parseDateTimePickerValue(newExdate),
|
|
3033
|
+
clearLabel: t("common.clear", "Clear"),
|
|
3034
|
+
onChange: (d) => setNewExdate(d ? formatLocalYmd(d) : ""),
|
|
3035
|
+
onClear: () => setNewExdate("")
|
|
3036
|
+
}
|
|
3037
|
+
)
|
|
3038
|
+
] }) }),
|
|
3039
|
+
/* @__PURE__ */ jsx(
|
|
3040
|
+
Button,
|
|
3041
|
+
{
|
|
3042
|
+
variant: "secondary",
|
|
3043
|
+
size: "S",
|
|
3044
|
+
disabled,
|
|
3045
|
+
onClick: handleAddExdate,
|
|
3046
|
+
children: t("rrule.addExdate", "Add Excluded Date")
|
|
3047
|
+
}
|
|
3048
|
+
)
|
|
3049
|
+
] }),
|
|
3050
|
+
exdatesList.length > 0 && /* @__PURE__ */ jsx(Flex, { gap: 2, paddingTop: 2, wrap: "wrap", children: exdatesList.map((dt) => /* @__PURE__ */ jsxs(
|
|
3051
|
+
Badge,
|
|
3052
|
+
{
|
|
3053
|
+
backgroundColor: "neutral200",
|
|
3054
|
+
textColor: "neutral800",
|
|
3055
|
+
children: [
|
|
3056
|
+
dt,
|
|
3057
|
+
" ",
|
|
3058
|
+
/* @__PURE__ */ jsx(
|
|
3059
|
+
"button",
|
|
3060
|
+
{
|
|
3061
|
+
type: "button",
|
|
3062
|
+
onClick: () => handleRemoveExdate(dt),
|
|
3063
|
+
style: REMOVE_BTN_STYLE,
|
|
3064
|
+
"aria-label": `Remove ${dt}`,
|
|
3065
|
+
children: "×"
|
|
3066
|
+
}
|
|
3067
|
+
)
|
|
3068
|
+
]
|
|
3069
|
+
},
|
|
3070
|
+
dt
|
|
3071
|
+
)) })
|
|
3072
|
+
] })
|
|
3073
|
+
] })
|
|
3074
|
+
}
|
|
3075
|
+
),
|
|
3076
|
+
/* @__PURE__ */ jsx(Field.Error, {}),
|
|
3077
|
+
/* @__PURE__ */ jsx(Field.Hint, {})
|
|
3078
|
+
] }) });
|
|
3079
|
+
};
|
|
3080
|
+
const RRuleInput$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
3081
|
+
__proto__: null,
|
|
3082
|
+
RRuleInput
|
|
3083
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
3084
|
+
const rruleCustomField = {
|
|
3085
|
+
name: "rrule",
|
|
3086
|
+
pluginId: PLUGIN_ID,
|
|
3087
|
+
type: "json",
|
|
3088
|
+
intlLabel: {
|
|
3089
|
+
id: `${PLUGIN_ID}.rrule.field.label`,
|
|
3090
|
+
defaultMessage: "Recurrence Schedule (RRULE / RSCALE)"
|
|
3091
|
+
},
|
|
3092
|
+
intlDescription: {
|
|
3093
|
+
id: `${PLUGIN_ID}.rrule.field.description`,
|
|
3094
|
+
defaultMessage: "Configure RFC 5545 & RFC 7529 recurring schedules, non-Gregorian calendar recurrence, excluded dates, and per-occurrence overrides."
|
|
3095
|
+
},
|
|
3096
|
+
icon: PluginIcon,
|
|
3097
|
+
components: {
|
|
3098
|
+
Input: async () => Promise.resolve().then(() => RRuleInput$1).then((module) => ({
|
|
3099
|
+
default: module.RRuleInput
|
|
3100
|
+
}))
|
|
3101
|
+
}
|
|
3102
|
+
};
|
|
3103
|
+
const SUPPORTED_LOCALES = [
|
|
3104
|
+
"en",
|
|
3105
|
+
"es",
|
|
3106
|
+
"fr",
|
|
3107
|
+
"de",
|
|
3108
|
+
"pt",
|
|
3109
|
+
"it",
|
|
3110
|
+
"nl",
|
|
3111
|
+
"pl",
|
|
3112
|
+
"tr",
|
|
3113
|
+
"ar"
|
|
3114
|
+
];
|
|
3115
|
+
const index = {
|
|
3116
|
+
register(app) {
|
|
3117
|
+
app.customFields.register(rruleCustomField);
|
|
3118
|
+
app.addMenuLink({
|
|
3119
|
+
to: `plugins/${PLUGIN_ID}`,
|
|
3120
|
+
icon: PluginIcon,
|
|
3121
|
+
intlLabel: {
|
|
3122
|
+
id: `${PLUGIN_ID}.plugin.name`,
|
|
3123
|
+
defaultMessage: "Calendar"
|
|
3124
|
+
},
|
|
3125
|
+
permissions: [],
|
|
3126
|
+
Component: () => import("./CalendarPage-Dq6YfSXF.js").then((mod) => ({
|
|
3127
|
+
default: mod.CalendarPage
|
|
3128
|
+
}))
|
|
3129
|
+
});
|
|
3130
|
+
const calendarSettingsSection = {
|
|
3131
|
+
id: PLUGIN_ID,
|
|
3132
|
+
intlLabel: {
|
|
3133
|
+
id: `${PLUGIN_ID}.settings.section`,
|
|
3134
|
+
defaultMessage: "Calendar, Events & Bookings"
|
|
3135
|
+
}
|
|
3136
|
+
};
|
|
3137
|
+
const calendarSettingsLink = {
|
|
3138
|
+
intlLabel: {
|
|
3139
|
+
id: `${PLUGIN_ID}.settings.general`,
|
|
3140
|
+
defaultMessage: "Calendar & Scheduler"
|
|
3141
|
+
},
|
|
3142
|
+
id: `${PLUGIN_ID}-settings`,
|
|
3143
|
+
to: `${PLUGIN_ID}`,
|
|
3144
|
+
Component: () => import("./SettingsPage-7SecVQEi.js").then((mod) => ({
|
|
3145
|
+
default: mod.SettingsPage
|
|
3146
|
+
})),
|
|
3147
|
+
permissions: []
|
|
3148
|
+
};
|
|
3149
|
+
try {
|
|
3150
|
+
if (typeof app.addSettingsLink === "function") {
|
|
3151
|
+
app.addSettingsLink(calendarSettingsSection.id, calendarSettingsLink);
|
|
3152
|
+
} else {
|
|
3153
|
+
app.createSettingSection(calendarSettingsSection, [
|
|
3154
|
+
calendarSettingsLink
|
|
3155
|
+
]);
|
|
3156
|
+
}
|
|
3157
|
+
} catch {
|
|
3158
|
+
app.createSettingSection(calendarSettingsSection, [calendarSettingsLink]);
|
|
3159
|
+
}
|
|
3160
|
+
app.registerPlugin({
|
|
3161
|
+
id: PLUGIN_ID,
|
|
3162
|
+
initializer: Initializer,
|
|
3163
|
+
isReady: false,
|
|
3164
|
+
name: PLUGIN_ID
|
|
3165
|
+
});
|
|
3166
|
+
},
|
|
3167
|
+
bootstrap(app) {
|
|
3168
|
+
const cmPlugin = app.getPlugin("content-manager");
|
|
3169
|
+
if (cmPlugin?.apis?.addEditViewSidePanel) {
|
|
3170
|
+
cmPlugin.apis.addEditViewSidePanel([CalendarSidePanel]);
|
|
3171
|
+
}
|
|
3172
|
+
},
|
|
3173
|
+
registerTrads: createRegisterTrads({
|
|
3174
|
+
pluginId: PLUGIN_ID,
|
|
3175
|
+
defaultLocales: SUPPORTED_LOCALES,
|
|
3176
|
+
loadTranslation: (locale) => __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-O6QL_nJZ.js"), "./translations/de.json": () => import("./de-BpDxjctz.js"), "./translations/en.json": () => import("./en-BoRq-9QD.js"), "./translations/es.json": () => import("./es-BZ7WX8Ev.js"), "./translations/fr.json": () => import("./fr-BnDr9DC8.js"), "./translations/it.json": () => import("./it-DkdUInap.js"), "./translations/nl.json": () => import("./nl-C2NFORLS.js"), "./translations/pl.json": () => import("./pl-mv5eXA8W.js"), "./translations/pt.json": () => import("./pt-WpvZGj3b.js"), "./translations/tr.json": () => import("./tr-BhZKvFoK.js") }), `./translations/${locale}.json`, 3)
|
|
3177
|
+
})
|
|
3178
|
+
};
|
|
3179
|
+
export {
|
|
3180
|
+
SUPPORTED_INTL_CALENDARS as A,
|
|
3181
|
+
CalendarSidePanel as B,
|
|
3182
|
+
CalendarToolbar as C,
|
|
3183
|
+
SUPPORTED_LOCALES as D,
|
|
3184
|
+
index as E,
|
|
3185
|
+
FALLBACK_RECURRENCE_PRESETS as F,
|
|
3186
|
+
PLUGIN_ID as P,
|
|
3187
|
+
RRuleInput as R,
|
|
3188
|
+
SUPPORTED_CALENDAR_LOCALES as S,
|
|
3189
|
+
WEEKDAYS$1 as W,
|
|
3190
|
+
formatLocalYmd as a,
|
|
3191
|
+
buildOrderedRecurrencePresets as b,
|
|
3192
|
+
alignStartDateToWeekday as c,
|
|
3193
|
+
describeRRule as d,
|
|
3194
|
+
extractByDays as e,
|
|
3195
|
+
formatCategoryLabel as f,
|
|
3196
|
+
buildInitialDateWindow as g,
|
|
3197
|
+
resolveCalendarDirection as h,
|
|
3198
|
+
computeSourceCounts as i,
|
|
3199
|
+
filterVisibleOccurrences as j,
|
|
3200
|
+
collectAvailableCategories as k,
|
|
3201
|
+
resolveActiveSecondaryCalendars as l,
|
|
3202
|
+
matchLoadedSourceId as m,
|
|
3203
|
+
mapOccurrencesToFullCalendarEvents as n,
|
|
3204
|
+
buildSecondaryHeaderLabel as o,
|
|
3205
|
+
parseDateTimePickerValue as p,
|
|
3206
|
+
buildEnabledCalendarViews as q,
|
|
3207
|
+
resolveFullCalendarLocale as r,
|
|
3208
|
+
FullCalendarCanvas as s,
|
|
3209
|
+
buildQuickCreateRequestPayload as t,
|
|
3210
|
+
normalizeSelectedEndSlot as u,
|
|
3211
|
+
expandDateWindowToYear as v,
|
|
3212
|
+
detectEffectiveColorScheme as w,
|
|
3213
|
+
CALENDAR_COLOR_PALETTES as x,
|
|
3214
|
+
CALENDAR_THEME_PRESETS as y,
|
|
3215
|
+
resolveCalendarTheme as z
|
|
3216
|
+
};
|