@dayflow/plugin-sidebar 1.2.0 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useLocale, createPortal, cancelButton, ChevronsUpDown, Check, ChevronRight, sidebarHeader, sidebarHeaderToggle, PanelRightClose, PanelRightOpen, sidebarHeaderTitle, getCalendarColorsForHex, generateUniKey, downloadICS, ContentSlot, MiniCalendar, ContextMenu, ContextMenuLabel, ContextMenuItem, ContextMenuSeparator, ContextMenuColorPicker, DefaultColorPicker, BlossomColorPicker, importICSFile, sidebarContainer, normalizeCssWidth, registerSidebarImplementation, CreateCalendarDialog } from '@dayflow/core';
|
|
1
|
+
import { ChevronDown, AudioLines, useLocale, createPortal, cancelButton, ChevronsUpDown, Check, ChevronRight, sidebarHeader, sidebarHeaderToggle, PanelRightClose, PanelRightOpen, sidebarHeaderTitle, getCalendarColorsForHex, generateUniKey, downloadICS, ContentSlot, MiniCalendar, ContextMenu, ContextMenuLabel, ContextMenuItem, ContextMenuSeparator, ContextMenuColorPicker, DefaultColorPicker, BlossomColorPicker, importICSFile, parseICS, sidebarContainer, normalizeCssWidth, registerSidebarImplementation, CreateCalendarDialog } from '@dayflow/core';
|
|
2
2
|
import { options, Fragment, h } from 'preact';
|
|
3
3
|
import { useState, useRef, useCallback, useEffect, useMemo } from 'preact/hooks';
|
|
4
4
|
import { hexToHsl, lightnessToSliderValue } from '@dayflow/blossom-color-picker';
|
|
@@ -44,21 +44,33 @@ const getCalendarInitials = (calendar) => {
|
|
|
44
44
|
const name = calendar.name || calendar.id;
|
|
45
45
|
return name.charAt(0).toUpperCase();
|
|
46
46
|
};
|
|
47
|
+
const CalendarItem = ({ calendar, isDraggable, isEditable: _isEditable, editingId, editingName, setEditingName, editInputRef, draggedCalendarId, dropTarget, activeContextMenuCalendarId, onDragStart, onDragEnd, onDragOver, onDragLeave, onDrop, onContextMenu, onToggleVisibility, onRenameStart, onRenameSave, onRenameKeyDown, }) => {
|
|
48
|
+
var _a;
|
|
49
|
+
const isVisible = calendar.isVisible !== false;
|
|
50
|
+
const calendarColor = ((_a = calendar.colors) === null || _a === void 0 ? void 0 : _a.lineColor) || '#3b82f6';
|
|
51
|
+
const showIcon = Boolean(calendar.icon);
|
|
52
|
+
const isDropTarget = (dropTarget === null || dropTarget === void 0 ? void 0 : dropTarget.id) === calendar.id;
|
|
53
|
+
const isActive = activeContextMenuCalendarId === calendar.id || editingId === calendar.id;
|
|
54
|
+
return (u("li", { className: 'df-calendar-list-item relative', onDragOver: e => onDragOver(e, calendar.id), onDragLeave: onDragLeave, onDrop: () => onDrop(calendar), onContextMenu: e => onContextMenu(e, calendar.id), children: [isDropTarget && dropTarget.position === 'top' && (u("div", { className: 'pointer-events-none absolute top-0 right-0 left-0 z-10 h-0.5 bg-[var(--df-color-primary)]' })), u("div", { draggable: isDraggable && !editingId, onDragStart: e => onDragStart(calendar, e), onDragEnd: onDragEnd, className: `rounded transition ${draggedCalendarId === calendar.id ? 'opacity-50' : ''} ${isDraggable ? 'cursor-grab' : 'cursor-default'}`, children: u("div", { className: `group flex items-center rounded px-2 py-2 transition hover:bg-gray-100 dark:hover:bg-slate-800 ${isActive ? 'bg-gray-100 dark:bg-slate-800' : ''}`, title: calendar.name, children: [u("input", { type: 'checkbox', className: 'df-calendar-checkbox shrink-0 cursor-pointer', style: {
|
|
55
|
+
'--checkbox-color': calendarColor,
|
|
56
|
+
}, checked: isVisible, onChange: event => onToggleVisibility(calendar.id, event.target.checked) }), showIcon && (u("span", { className: 'ml-2 flex h-5 w-5 shrink-0 items-center justify-center text-xs font-semibold text-white', "aria-hidden": 'true', children: getCalendarInitials(calendar) })), editingId === calendar.id ? (u("input", { ref: editInputRef, type: 'text', value: editingName, onChange: e => setEditingName(e.target.value), onBlur: onRenameSave, onKeyDown: onRenameKeyDown, className: 'ml-2 h-5 min-w-0 flex-1 rounded bg-white px-0 py-0 text-sm text-gray-900 focus:outline-none dark:bg-slate-700 dark:text-gray-100', onClick: e => e.stopPropagation() })) : (u(Fragment, { children: [u("span", { className: 'ml-2 flex-1 truncate pl-1 text-sm text-gray-700 group-hover:text-gray-900 dark:text-gray-200 dark:group-hover:text-white', onDblClick: () => onRenameStart(calendar), children: calendar.name || calendar.id }), calendar.subscribed && (u(AudioLines, { width: 13, height: 13, className: 'ml-1 shrink-0 text-gray-400 dark:text-gray-500' }))] }))] }) }), isDropTarget && dropTarget.position === 'bottom' && (u("div", { className: 'pointer-events-none absolute right-0 bottom-0 left-0 z-10 h-0.5 bg-[var(--df-color-primary)]' }))] }, calendar.id));
|
|
57
|
+
};
|
|
47
58
|
const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onContextMenu, editingId, setEditingId, activeContextMenuCalendarId, isDraggable = true, isEditable = true, }) => {
|
|
59
|
+
var _a;
|
|
48
60
|
const [editingName, setEditingName] = useState('');
|
|
49
61
|
const editInputRef = useRef(null);
|
|
50
62
|
const isProcessedRef = useRef(false);
|
|
51
63
|
// Drag state
|
|
52
64
|
const [draggedCalendarId, setDraggedCalendarId] = useState(null);
|
|
53
65
|
const [dropTarget, setDropTarget] = useState(null);
|
|
66
|
+
// Collapsed sources state
|
|
67
|
+
const [collapsedSources, setCollapsedSources] = useState({});
|
|
54
68
|
const handleDragStart = useCallback((calendar, e) => {
|
|
55
|
-
// Prevent dragging when editing or not draggable
|
|
56
69
|
if (editingId || !isDraggable) {
|
|
57
70
|
e.preventDefault();
|
|
58
71
|
return;
|
|
59
72
|
}
|
|
60
73
|
setDraggedCalendarId(calendar.id);
|
|
61
|
-
// Store calendar data for drop handling
|
|
62
74
|
const dragData = {
|
|
63
75
|
calendarId: calendar.id,
|
|
64
76
|
calendarName: calendar.name,
|
|
@@ -107,11 +119,9 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
|
|
|
107
119
|
return;
|
|
108
120
|
const fromIndex = calendars.findIndex(c => c.id === draggedCalendarId);
|
|
109
121
|
let toIndex = calendars.findIndex(c => c.id === targetCalendar.id);
|
|
110
|
-
// Adjust target index based on position
|
|
111
122
|
if (dropTarget.position === 'bottom') {
|
|
112
123
|
toIndex += 1;
|
|
113
124
|
}
|
|
114
|
-
// Adjust for removal of the item
|
|
115
125
|
if (toIndex > fromIndex) {
|
|
116
126
|
toIndex -= 1;
|
|
117
127
|
}
|
|
@@ -169,24 +179,75 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
|
|
|
169
179
|
}
|
|
170
180
|
}
|
|
171
181
|
}, [editingId, calendars]);
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
182
|
+
const toggleSource = useCallback((source) => {
|
|
183
|
+
setCollapsedSources(prev => (Object.assign(Object.assign({}, prev), { [source]: !prev[source] })));
|
|
184
|
+
}, []);
|
|
185
|
+
// Shared item props (excludes per-item fields)
|
|
186
|
+
const sharedItemProps = {
|
|
187
|
+
isDraggable,
|
|
188
|
+
isEditable,
|
|
189
|
+
editingId,
|
|
190
|
+
editingName,
|
|
191
|
+
setEditingName,
|
|
192
|
+
editInputRef,
|
|
193
|
+
isProcessedRef,
|
|
194
|
+
draggedCalendarId,
|
|
195
|
+
dropTarget,
|
|
196
|
+
activeContextMenuCalendarId,
|
|
197
|
+
onDragStart: handleDragStart,
|
|
198
|
+
onDragEnd: handleDragEnd,
|
|
199
|
+
onDragOver: handleDragOver,
|
|
200
|
+
onDragLeave: handleDragLeave,
|
|
201
|
+
onDrop: handleDrop,
|
|
202
|
+
onContextMenu,
|
|
203
|
+
onToggleVisibility,
|
|
204
|
+
onRenameStart: handleRenameStart,
|
|
205
|
+
onRenameSave: handleRenameSave,
|
|
206
|
+
onRenameKeyDown: handleRenameKeyDown,
|
|
207
|
+
setEditingId,
|
|
208
|
+
};
|
|
209
|
+
// Check if any calendar has a source
|
|
210
|
+
const hasSources = calendars.some(c => c.source);
|
|
211
|
+
if (!hasSources) {
|
|
212
|
+
// Flat list (original behaviour)
|
|
213
|
+
return (u("div", { className: 'df-calendar-list flex-1 overflow-y-auto px-2 pb-3', children: u("ul", { className: 'relative space-y-1', children: calendars.map(calendar => (u(CalendarItem, Object.assign({ calendar: calendar }, sharedItemProps), calendar.id))) }) }));
|
|
214
|
+
}
|
|
215
|
+
// Group calendars by source; calendars without a source go into a null group
|
|
216
|
+
const groups = new Map();
|
|
217
|
+
for (const calendar of calendars) {
|
|
218
|
+
const key = (_a = calendar.source) !== null && _a !== void 0 ? _a : null;
|
|
219
|
+
if (!groups.has(key))
|
|
220
|
+
groups.set(key, []);
|
|
221
|
+
groups.get(key).push(calendar);
|
|
222
|
+
}
|
|
223
|
+
return (u("div", { className: 'df-calendar-list flex-1 overflow-y-auto px-2 pb-3', children: [groups.has(null) && (u("ul", { className: 'relative space-y-1', children: groups.get(null).map(calendar => (u(CalendarItem, Object.assign({ calendar: calendar }, sharedItemProps), calendar.id))) })), Array.from(groups.entries())
|
|
224
|
+
.filter(([source]) => source !== null)
|
|
225
|
+
.map(([source, groupCalendars]) => {
|
|
226
|
+
const isCollapsed = collapsedSources[source];
|
|
227
|
+
return (u("div", { className: 'mt-1', children: [u("button", { type: 'button', className: 'flex w-full items-center justify-between rounded px-2 py-1.5 text-xs font-medium text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-slate-800', onClick: () => toggleSource(source), children: [u("span", { className: 'truncate', children: source }), u(ChevronDown, { width: 13, height: 13, className: `ml-1 shrink-0 transition-transform duration-200 ${isCollapsed ? '-rotate-90' : ''}` })] }), u("div", { style: {
|
|
228
|
+
display: 'grid',
|
|
229
|
+
gridTemplateRows: isCollapsed ? '0fr' : '1fr',
|
|
230
|
+
transition: 'grid-template-rows 200ms ease',
|
|
231
|
+
}, children: u("div", { style: { overflow: 'hidden' }, children: u("ul", { className: 'relative space-y-1', children: groupCalendars.map(calendar => (u(CalendarItem, Object.assign({ calendar: calendar }, sharedItemProps), calendar.id))) }) }) })] }, source));
|
|
232
|
+
})] }));
|
|
184
233
|
};
|
|
185
234
|
|
|
235
|
+
const CalendarChip = ({ name, color }) => (u("span", { className: 'mx-0.5 inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium', style: { backgroundColor: `${color}26`, color }, children: name }));
|
|
236
|
+
|
|
237
|
+
const CAL_SENTINEL = '\u0001C\u0001';
|
|
238
|
+
function renderWithChip(template, name, color) {
|
|
239
|
+
return template
|
|
240
|
+
.split(CAL_SENTINEL)
|
|
241
|
+
.flatMap((part, i) => i === 0
|
|
242
|
+
? [part]
|
|
243
|
+
: [u(CalendarChip, { name: name, color: color }, i), part]);
|
|
244
|
+
}
|
|
186
245
|
const DeleteCalendarDialog = ({ calendarId, calendarName, calendars, step, onStepChange, onConfirmDelete, onCancel, onMergeSelect, }) => {
|
|
246
|
+
var _a, _b;
|
|
187
247
|
const [showMergeDropdown, setShowMergeDropdown] = useState(false);
|
|
188
248
|
const { t } = useLocale();
|
|
189
|
-
|
|
249
|
+
const calendarColor = (_b = (_a = calendars.find(c => c.id === calendarId)) === null || _a === void 0 ? void 0 : _a.colors.lineColor) !== null && _b !== void 0 ? _b : '#6b7280';
|
|
250
|
+
return createPortal(u("div", { className: 'df-portal fixed inset-0 z-[9999] flex items-center justify-center bg-black/50', children: u("div", { className: 'w-full max-w-md rounded-lg bg-white p-6 shadow-xl dark:bg-gray-800', children: step === 'initial' ? (u(Fragment, { children: [u("h2", { className: 'text-lg font-semibold text-gray-900 dark:text-white', children: t('deleteCalendar', { calendarName }) }), u("p", { className: 'mt-3 flex flex-wrap items-center gap-y-0.5 text-sm text-gray-600 dark:text-gray-300', children: renderWithChip(t('deleteCalendarMessage', { calendarName: CAL_SENTINEL }), calendarName, calendarColor) }), u("div", { className: 'mt-6 flex items-center justify-between', children: [u("div", { className: 'relative', children: [u("button", { type: 'button', onClick: () => setShowMergeDropdown(!showMergeDropdown), className: 'flex items-center gap-1 rounded-md border border-gray-300 px-4 py-2 text-xs font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-200 dark:hover:bg-slate-700', children: t('merge') }), showMergeDropdown && (u("div", { className: 'absolute top-full left-0 z-10 mt-1 max-h-60 w-max min-w-full overflow-y-auto rounded-md border border-gray-200 bg-white shadow-lg dark:border-slate-700 dark:bg-gray-800', children: calendars
|
|
190
251
|
.filter(c => c.id !== calendarId)
|
|
191
252
|
.map(calendar => (u("div", { className: 'flex cursor-pointer items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-slate-700', onClick: () => {
|
|
192
253
|
onMergeSelect(calendar.id);
|
|
@@ -243,6 +304,7 @@ const ImportCalendarDialog = ({ calendars, filename, onConfirm, onCancel, }) =>
|
|
|
243
304
|
top: rect.bottom,
|
|
244
305
|
left: rect.left,
|
|
245
306
|
width: rect.width,
|
|
307
|
+
overscrollBehavior: 'none',
|
|
246
308
|
}, children: u("div", { className: 'py-1', children: [calendars.map(calendar => (u("div", { className: `flex cursor-pointer items-center px-3 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 ${selectedCalendarId === calendar.id ? 'bg-primary/10' : ''}`, onClick: () => handleSelect(calendar.id), children: [u("div", { className: 'mr-3 h-3 w-3 shrink-0 rounded-sm', style: { backgroundColor: calendar.colors.lineColor } }), u("span", { className: `flex-1 truncate text-sm ${selectedCalendarId === calendar.id ? 'font-medium text-primary' : 'text-gray-700 dark:text-gray-200'}`, children: calendar.name || calendar.id }), selectedCalendarId === calendar.id && (u(Check, { className: 'ml-2 h-4 w-4 shrink-0 text-primary' }))] }, calendar.id))), u("div", { className: 'my-1 border-t border-gray-100 dark:border-slate-700' }), u("div", { className: `flex cursor-pointer items-center px-3 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 ${isNewSelected ? 'bg-primary/10' : ''}`, onClick: () => handleSelect(NEW_CALENDAR_ID), children: [u("span", { className: `flex-1 truncate text-sm ${isNewSelected ? 'font-medium text-primary' : 'pl-6 text-gray-700 dark:text-gray-200'}`, children: [t('newCalendar') || 'New Calendar', ": ", filename] }), isNewSelected && (u(Check, { className: 'ml-2 h-4 w-4 shrink-0 text-primary' }))] })] }) }), document.body);
|
|
247
309
|
};
|
|
248
310
|
return (u("div", { className: 'df-portal fixed inset-0 z-100 flex items-center justify-center bg-black/50', children: u("div", { className: 'w-full max-w-md rounded-lg bg-white p-6 shadow-xl dark:bg-gray-900', children: [u("h2", { className: 'mb-4 text-lg font-semibold text-gray-900 dark:text-white', children: t('addSchedule') || 'Add Schedule' }), u("p", { className: 'mb-4 text-sm text-gray-600 dark:text-gray-300', children: t('importCalendarMessage') ||
|
|
@@ -251,9 +313,29 @@ const ImportCalendarDialog = ({ calendars, filename, onConfirm, onCancel, }) =>
|
|
|
251
313
|
: (selectedCalendar === null || selectedCalendar === void 0 ? void 0 : selectedCalendar.name) || (selectedCalendar === null || selectedCalendar === void 0 ? void 0 : selectedCalendar.id) }), u(ChevronsUpDown, { className: 'ml-2 h-4 w-4 shrink-0 text-gray-400' })] }), renderDropdown()] }), u("div", { className: 'mt-8 flex justify-end gap-3', children: [u("button", { type: 'button', onClick: onCancel, className: cancelButton, children: t('cancel') || 'Cancel' }), u("button", { type: 'button', onClick: () => onConfirm(selectedCalendarId), className: 'rounded-md bg-primary px-6 py-2 text-sm font-medium text-primary-foreground shadow-sm transition-colors hover:bg-primary/90', children: t('ok') || 'OK' })] })] }) }));
|
|
252
314
|
};
|
|
253
315
|
|
|
254
|
-
const
|
|
316
|
+
const SOURCE_SENTINEL = '\u0001S\u0001';
|
|
317
|
+
const TARGET_SENTINEL = '\u0001T\u0001';
|
|
318
|
+
function renderLine(line, source, target) {
|
|
319
|
+
return line
|
|
320
|
+
.split(new RegExp(`(${SOURCE_SENTINEL}|${TARGET_SENTINEL})`))
|
|
321
|
+
.map((part, i) => {
|
|
322
|
+
if (part === SOURCE_SENTINEL)
|
|
323
|
+
return u(CalendarChip, { name: source.name, color: source.color }, i);
|
|
324
|
+
if (part === TARGET_SENTINEL)
|
|
325
|
+
return u(CalendarChip, { name: target.name, color: target.color }, i);
|
|
326
|
+
return part;
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
const MergeCalendarDialog = ({ sourceName, sourceColor, targetName, targetColor, onConfirm, onCancel, }) => {
|
|
255
330
|
const { t } = useLocale();
|
|
256
|
-
|
|
331
|
+
const source = { name: sourceName, color: sourceColor };
|
|
332
|
+
const target = { name: targetName, color: targetColor };
|
|
333
|
+
const messageTemplate = t('mergeConfirmMessage', {
|
|
334
|
+
sourceName: SOURCE_SENTINEL,
|
|
335
|
+
targetName: TARGET_SENTINEL,
|
|
336
|
+
});
|
|
337
|
+
const messageLines = messageTemplate.split('\n');
|
|
338
|
+
return (u("div", { className: 'df-portal fixed inset-0 z-[9999] flex items-center justify-center bg-black/50', children: u("div", { className: 'rounded-lg bg-white p-6 shadow-xl dark:bg-gray-800', children: [u("h2", { className: 'text-lg font-semibold text-gray-900 dark:text-white', children: t('mergeConfirmTitle', { sourceName, targetName }) }), u("div", { className: 'mt-3 space-y-1 text-sm text-gray-600 dark:text-gray-300', children: messageLines.map((line, i) => (u("p", { className: 'flex flex-wrap items-center gap-y-0.5', children: renderLine(line, source, target) }, i))) }), u("div", { className: 'mt-6 flex justify-end gap-3', children: [u("button", { type: 'button', onClick: onCancel, className: cancelButton, children: t('cancel') }), u("button", { type: 'button', onClick: onConfirm, className: 'rounded-md bg-destructive px-3 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90', children: t('merge') })] })] }) }));
|
|
257
339
|
};
|
|
258
340
|
|
|
259
341
|
const stopPropagation = (e) => e.stopPropagation();
|
|
@@ -302,8 +384,38 @@ const SidebarHeader = ({ isCollapsed, onCollapseToggle, }) => {
|
|
|
302
384
|
return (u("div", { className: sidebarHeader, children: [u("button", { type: 'button', "aria-label": isCollapsed ? t('expandSidebar') : t('collapseSidebar'), className: sidebarHeaderToggle, onClick: onCollapseToggle, children: isCollapsed ? (u(PanelRightClose, { className: 'h-4 w-4 text-gray-500 dark:text-gray-400' })) : (u(PanelRightOpen, { className: 'h-4 w-4 text-gray-500 dark:text-gray-400' })) }), !isCollapsed && (u("div", { className: 'ml-3 flex flex-1 items-center justify-between', children: u("span", { className: sidebarHeaderTitle, children: t('calendars') }) }))] }));
|
|
303
385
|
};
|
|
304
386
|
|
|
387
|
+
const SubscribeCalendarDialog = ({ onSubscribe, onCancel, }) => {
|
|
388
|
+
const { t } = useLocale();
|
|
389
|
+
const [url, setUrl] = useState('');
|
|
390
|
+
const [loading, setLoading] = useState(false);
|
|
391
|
+
const [error, setError] = useState(null);
|
|
392
|
+
const handleSubmit = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
393
|
+
const trimmed = url.trim();
|
|
394
|
+
if (!trimmed)
|
|
395
|
+
return;
|
|
396
|
+
setError(null);
|
|
397
|
+
setLoading(true);
|
|
398
|
+
try {
|
|
399
|
+
yield onSubscribe(trimmed);
|
|
400
|
+
}
|
|
401
|
+
catch (_a) {
|
|
402
|
+
setError(t('subscribeError'));
|
|
403
|
+
}
|
|
404
|
+
finally {
|
|
405
|
+
setLoading(false);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
const handleKeyDown = (e) => {
|
|
409
|
+
if (e.key === 'Enter')
|
|
410
|
+
handleSubmit();
|
|
411
|
+
if (e.key === 'Escape')
|
|
412
|
+
onCancel();
|
|
413
|
+
};
|
|
414
|
+
return (u("div", { className: 'df-portal fixed inset-0 z-[9999] flex items-center justify-center bg-black/50', children: u("div", { className: 'w-full max-w-xl rounded-lg bg-white p-6 shadow-xl dark:bg-gray-800', children: [u("h2", { className: 'text-lg font-semibold text-gray-900 dark:text-white', children: t('subscribeCalendarTitle') }), u("div", { className: 'mt-4', children: [u("div", { className: 'flex items-center gap-3', children: [u("label", { className: 'shrink-0 text-sm font-medium text-gray-700 dark:text-gray-300', children: t('calendarUrl') }), u("input", { type: 'url', value: url, onInput: e => setUrl(e.target.value), onKeyDown: handleKeyDown, placeholder: t('calendarUrlPlaceholder'), disabled: loading, autoFocus: true, className: 'flex-1 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 placeholder-gray-400 focus:border-primary focus:ring-1 focus:ring-primary focus:outline-none disabled:opacity-50 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400' })] }), error && (u("p", { className: 'mt-2 text-xs text-red-500 dark:text-red-400', children: error }))] }), u("div", { className: 'mt-6 flex justify-end gap-3', children: [u("button", { type: 'button', onClick: onCancel, disabled: loading, className: cancelButton, children: t('cancel') }), u("button", { type: 'button', onClick: handleSubmit, disabled: loading || !url.trim(), className: 'rounded-md bg-primary px-4 py-2 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-50', children: loading ? t('fetchingCalendar') : t('subscribe') })] })] }) }));
|
|
415
|
+
};
|
|
416
|
+
|
|
305
417
|
const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, renderSidebarHeader, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, }) => {
|
|
306
|
-
var _a, _b
|
|
418
|
+
var _a, _b;
|
|
307
419
|
const { t } = useLocale();
|
|
308
420
|
// Detect if custom color picker slot is provided
|
|
309
421
|
const hasCustomPicker = app.state.overrides.includes('colorPicker');
|
|
@@ -331,6 +443,8 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
331
443
|
const [deleteState, setDeleteState] = useState(null);
|
|
332
444
|
// Import Calendar State
|
|
333
445
|
const [importState, setImportState] = useState(null);
|
|
446
|
+
// Subscribe Calendar State
|
|
447
|
+
const [subscribeDialogOpen, setSubscribeDialogOpen] = useState(false);
|
|
334
448
|
const handleContextMenu = useCallback((e, calendarId) => {
|
|
335
449
|
e.preventDefault();
|
|
336
450
|
e.stopPropagation(); // Stop propagation to prevent sidebar context menu
|
|
@@ -445,6 +559,51 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
445
559
|
(_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
|
|
446
560
|
handleCloseSidebarContextMenu();
|
|
447
561
|
}, [handleCloseSidebarContextMenu]);
|
|
562
|
+
// Subscribe Calendar handler
|
|
563
|
+
const handleSubscribeClick = useCallback(() => {
|
|
564
|
+
setSubscribeDialogOpen(true);
|
|
565
|
+
handleCloseSidebarContextMenu();
|
|
566
|
+
}, [handleCloseSidebarContextMenu]);
|
|
567
|
+
const handleSubscribeConfirm = useCallback((url) => __awaiter(void 0, void 0, void 0, function* () {
|
|
568
|
+
const response = yield fetch(url);
|
|
569
|
+
if (!response.ok)
|
|
570
|
+
throw new Error(`HTTP ${response.status}`);
|
|
571
|
+
const icsContent = yield response.text();
|
|
572
|
+
const result = parseICS(icsContent);
|
|
573
|
+
// Extract calendar name from X-WR-CALNAME if present
|
|
574
|
+
const nameMatch = icsContent.match(/X-WR-CALNAME[^:]*:([^\r\n]+)/);
|
|
575
|
+
const calendarName = nameMatch
|
|
576
|
+
? nameMatch[1].trim()
|
|
577
|
+
: new URL(url).hostname;
|
|
578
|
+
const presetColors = [
|
|
579
|
+
'#3b82f6',
|
|
580
|
+
'#10b981',
|
|
581
|
+
'#8b5cf6',
|
|
582
|
+
'#f59e0b',
|
|
583
|
+
'#ef4444',
|
|
584
|
+
'#f97316',
|
|
585
|
+
'#ec4899',
|
|
586
|
+
'#14b8a6',
|
|
587
|
+
'#6366f1',
|
|
588
|
+
'#6b7280',
|
|
589
|
+
];
|
|
590
|
+
const randomColor = presetColors[Math.floor(Math.random() * presetColors.length)];
|
|
591
|
+
const { colors: calendarColors, darkColors } = getCalendarColorsForHex(randomColor);
|
|
592
|
+
const calendarId = generateUniKey();
|
|
593
|
+
app.createCalendar({
|
|
594
|
+
id: calendarId,
|
|
595
|
+
name: calendarName,
|
|
596
|
+
isDefault: false,
|
|
597
|
+
colors: calendarColors,
|
|
598
|
+
darkColors,
|
|
599
|
+
isVisible: true,
|
|
600
|
+
subscribed: true,
|
|
601
|
+
});
|
|
602
|
+
result.events.forEach(event => {
|
|
603
|
+
app.addEvent(Object.assign(Object.assign({}, event), { calendarId }));
|
|
604
|
+
});
|
|
605
|
+
setSubscribeDialogOpen(false);
|
|
606
|
+
}), [app]);
|
|
448
607
|
const handleFileChange = useCallback((e) => __awaiter(void 0, void 0, void 0, function* () {
|
|
449
608
|
var _a;
|
|
450
609
|
const file = (_a = e.currentTarget.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
@@ -514,14 +673,18 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
514
673
|
handleCloseContextMenu();
|
|
515
674
|
}
|
|
516
675
|
}, [contextMenu, calendars, app, handleCloseContextMenu]);
|
|
517
|
-
const
|
|
518
|
-
?
|
|
519
|
-
:
|
|
520
|
-
const
|
|
521
|
-
?
|
|
522
|
-
:
|
|
676
|
+
const sourceCalendar = mergeState
|
|
677
|
+
? calendars.find(c => c.id === mergeState.sourceId)
|
|
678
|
+
: null;
|
|
679
|
+
const targetCalendar = mergeState
|
|
680
|
+
? calendars.find(c => c.id === mergeState.targetId)
|
|
681
|
+
: null;
|
|
682
|
+
const sourceCalendarName = (sourceCalendar === null || sourceCalendar === void 0 ? void 0 : sourceCalendar.name) || 'Unknown';
|
|
683
|
+
const targetCalendarName = (targetCalendar === null || targetCalendar === void 0 ? void 0 : targetCalendar.name) || 'Unknown';
|
|
684
|
+
const sourceCalendarColor = (sourceCalendar === null || sourceCalendar === void 0 ? void 0 : sourceCalendar.colors.lineColor) || '#6b7280';
|
|
685
|
+
const targetCalendarColor = (targetCalendar === null || targetCalendar === void 0 ? void 0 : targetCalendar.colors.lineColor) || '#6b7280';
|
|
523
686
|
const deleteCalendarName = deleteState
|
|
524
|
-
? ((
|
|
687
|
+
? ((_a = calendars.find(c => c.id === deleteState.calendarId)) === null || _a === void 0 ? void 0 : _a.name) || 'Unknown'
|
|
525
688
|
: '';
|
|
526
689
|
const readOnlyConfig = app.getReadOnlyConfig();
|
|
527
690
|
const isEditable = !app.state.readOnly;
|
|
@@ -559,16 +722,17 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
559
722
|
}, editingId: editingCalendarId, setEditingId: setEditingCalendarId, activeContextMenuCalendarId: contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.calendarId, isDraggable: isDraggable, isEditable: isEditable }), u("div", { className: 'border-t border-gray-200 dark:border-slate-800', children: u(MiniCalendar, { visibleMonth: app.getVisibleMonth(), currentDate: app.getCurrentDate(), showHeader: true, onMonthChange: handleMonthChange, onDateSelect: date => app.setCurrentDate(date) }) })] })), contextMenu && (u(ContextMenu, { ref: contextMenuRef, x: contextMenu.x, y: contextMenu.y, onClose: handleCloseContextMenu, className: 'w-64 p-2', children: u(ContentSlot, { generatorName: 'calendarContextMenu', generatorArgs: {
|
|
560
723
|
calendar: calendars.find(c => c.id === contextMenu.calendarId),
|
|
561
724
|
onClose: handleCloseContextMenu,
|
|
562
|
-
}, defaultContent: renderCalendarContextMenu ? (renderCalendarContextMenu(calendars.find(c => c.id === contextMenu.calendarId), handleCloseContextMenu)) : (u(Fragment, { children: [u(ContextMenuLabel, { children: t('calendarOptions') }), u(MergeMenuItem, { calendars: calendars, currentCalendarId: contextMenu.calendarId, onMergeSelect: handleMergeSelect }), u(ContextMenuItem, { onClick: handleDeleteCalendar, children: t('delete') }), u(ContextMenuItem, { onClick: handleExportCalendar, children: t('exportCalendar') || 'Export Calendar' }), u(ContextMenuSeparator, {}), u(ContextMenuColorPicker, { selectedColor: (
|
|
725
|
+
}, defaultContent: renderCalendarContextMenu ? (renderCalendarContextMenu(calendars.find(c => c.id === contextMenu.calendarId), handleCloseContextMenu)) : (u(Fragment, { children: [u(ContextMenuLabel, { children: t('calendarOptions') }), u(MergeMenuItem, { calendars: calendars, currentCalendarId: contextMenu.calendarId, onMergeSelect: handleMergeSelect }), u(ContextMenuItem, { onClick: handleDeleteCalendar, children: t('delete') }), u(ContextMenuItem, { onClick: handleExportCalendar, children: t('exportCalendar') || 'Export Calendar' }), u(ContextMenuSeparator, {}), u(ContextMenuColorPicker, { selectedColor: (_b = calendars.find(c => c.id === contextMenu.calendarId)) === null || _b === void 0 ? void 0 : _b.colors.lineColor, onSelect: handleColorSelect, onCustomColor: handleCustomColor })] })) }) })), sidebarContextMenu &&
|
|
563
726
|
createPortal(u(ContextMenu, { x: sidebarContextMenu.x, y: sidebarContextMenu.y, onClose: handleCloseSidebarContextMenu, className: 'w-max p-2', children: [u(ContextMenuItem, { onClick: () => {
|
|
564
727
|
onCreateCalendar === null || onCreateCalendar === void 0 ? void 0 : onCreateCalendar();
|
|
565
728
|
handleCloseSidebarContextMenu();
|
|
566
|
-
}, children: t('newCalendar') || 'New Calendar' }), u(ContextMenuItem, { onClick: handleImportClick, children: t('importCalendar') || 'Import Calendar' }), u(ContextMenuItem, { onClick: () => {
|
|
729
|
+
}, children: t('newCalendar') || 'New Calendar' }), u(ContextMenuItem, { onClick: handleImportClick, children: t('importCalendar') || 'Import Calendar' }), u(ContextMenuItem, { onClick: handleSubscribeClick, children: t('subscribeCalendar') || 'Subscribe to Calendar' }), u(ContextMenuItem, { onClick: () => {
|
|
567
730
|
app.triggerRender();
|
|
568
731
|
handleCloseSidebarContextMenu();
|
|
569
732
|
}, children: t('refreshAll') || 'Refresh All' })] }), document.body), u("input", { ref: fileInputRef, type: 'file', accept: '.ics', style: { display: 'none' }, onChange: handleFileChange }), importState &&
|
|
570
|
-
createPortal(u(ImportCalendarDialog, { calendars: calendars, filename: importState.filename, onConfirm: handleImportConfirm, onCancel: () => setImportState(null) }), document.body),
|
|
571
|
-
createPortal(u(
|
|
733
|
+
createPortal(u(ImportCalendarDialog, { calendars: calendars, filename: importState.filename, onConfirm: handleImportConfirm, onCancel: () => setImportState(null) }), document.body), subscribeDialogOpen &&
|
|
734
|
+
createPortal(u(SubscribeCalendarDialog, { onSubscribe: handleSubscribeConfirm, onCancel: () => setSubscribeDialogOpen(false) }), document.body), mergeState &&
|
|
735
|
+
createPortal(u(MergeCalendarDialog, { sourceName: sourceCalendarName, sourceColor: sourceCalendarColor, targetName: targetCalendarName, targetColor: targetCalendarColor, onConfirm: handleMergeConfirm, onCancel: () => setMergeState(null) }), document.body), deleteState &&
|
|
572
736
|
createPortal(u(DeleteCalendarDialog, { calendarId: deleteState.calendarId, calendarName: deleteCalendarName, calendars: calendars, step: deleteState.step, onStepChange: step => setDeleteState(prev => (prev ? Object.assign(Object.assign({}, prev), { step }) : null)), onConfirmDelete: handleConfirmDelete, onCancel: () => setDeleteState(null), onMergeSelect: handleDeleteMergeSelect }), document.body), customColorPicker &&
|
|
573
737
|
createPortal(u("div", { className: 'fixed inset-0 z-50', onMouseDown: () => {
|
|
574
738
|
app.updateCalendar(customColorPicker.calendarId, {});
|
package/dist/index.js
CHANGED
|
@@ -46,21 +46,33 @@ const getCalendarInitials = (calendar) => {
|
|
|
46
46
|
const name = calendar.name || calendar.id;
|
|
47
47
|
return name.charAt(0).toUpperCase();
|
|
48
48
|
};
|
|
49
|
+
const CalendarItem = ({ calendar, isDraggable, isEditable: _isEditable, editingId, editingName, setEditingName, editInputRef, draggedCalendarId, dropTarget, activeContextMenuCalendarId, onDragStart, onDragEnd, onDragOver, onDragLeave, onDrop, onContextMenu, onToggleVisibility, onRenameStart, onRenameSave, onRenameKeyDown, }) => {
|
|
50
|
+
var _a;
|
|
51
|
+
const isVisible = calendar.isVisible !== false;
|
|
52
|
+
const calendarColor = ((_a = calendar.colors) === null || _a === void 0 ? void 0 : _a.lineColor) || '#3b82f6';
|
|
53
|
+
const showIcon = Boolean(calendar.icon);
|
|
54
|
+
const isDropTarget = (dropTarget === null || dropTarget === void 0 ? void 0 : dropTarget.id) === calendar.id;
|
|
55
|
+
const isActive = activeContextMenuCalendarId === calendar.id || editingId === calendar.id;
|
|
56
|
+
return (u("li", { className: 'df-calendar-list-item relative', onDragOver: e => onDragOver(e, calendar.id), onDragLeave: onDragLeave, onDrop: () => onDrop(calendar), onContextMenu: e => onContextMenu(e, calendar.id), children: [isDropTarget && dropTarget.position === 'top' && (u("div", { className: 'pointer-events-none absolute top-0 right-0 left-0 z-10 h-0.5 bg-[var(--df-color-primary)]' })), u("div", { draggable: isDraggable && !editingId, onDragStart: e => onDragStart(calendar, e), onDragEnd: onDragEnd, className: `rounded transition ${draggedCalendarId === calendar.id ? 'opacity-50' : ''} ${isDraggable ? 'cursor-grab' : 'cursor-default'}`, children: u("div", { className: `group flex items-center rounded px-2 py-2 transition hover:bg-gray-100 dark:hover:bg-slate-800 ${isActive ? 'bg-gray-100 dark:bg-slate-800' : ''}`, title: calendar.name, children: [u("input", { type: 'checkbox', className: 'df-calendar-checkbox shrink-0 cursor-pointer', style: {
|
|
57
|
+
'--checkbox-color': calendarColor,
|
|
58
|
+
}, checked: isVisible, onChange: event => onToggleVisibility(calendar.id, event.target.checked) }), showIcon && (u("span", { className: 'ml-2 flex h-5 w-5 shrink-0 items-center justify-center text-xs font-semibold text-white', "aria-hidden": 'true', children: getCalendarInitials(calendar) })), editingId === calendar.id ? (u("input", { ref: editInputRef, type: 'text', value: editingName, onChange: e => setEditingName(e.target.value), onBlur: onRenameSave, onKeyDown: onRenameKeyDown, className: 'ml-2 h-5 min-w-0 flex-1 rounded bg-white px-0 py-0 text-sm text-gray-900 focus:outline-none dark:bg-slate-700 dark:text-gray-100', onClick: e => e.stopPropagation() })) : (u(preact.Fragment, { children: [u("span", { className: 'ml-2 flex-1 truncate pl-1 text-sm text-gray-700 group-hover:text-gray-900 dark:text-gray-200 dark:group-hover:text-white', onDblClick: () => onRenameStart(calendar), children: calendar.name || calendar.id }), calendar.subscribed && (u(core.AudioLines, { width: 13, height: 13, className: 'ml-1 shrink-0 text-gray-400 dark:text-gray-500' }))] }))] }) }), isDropTarget && dropTarget.position === 'bottom' && (u("div", { className: 'pointer-events-none absolute right-0 bottom-0 left-0 z-10 h-0.5 bg-[var(--df-color-primary)]' }))] }, calendar.id));
|
|
59
|
+
};
|
|
49
60
|
const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onContextMenu, editingId, setEditingId, activeContextMenuCalendarId, isDraggable = true, isEditable = true, }) => {
|
|
61
|
+
var _a;
|
|
50
62
|
const [editingName, setEditingName] = hooks.useState('');
|
|
51
63
|
const editInputRef = hooks.useRef(null);
|
|
52
64
|
const isProcessedRef = hooks.useRef(false);
|
|
53
65
|
// Drag state
|
|
54
66
|
const [draggedCalendarId, setDraggedCalendarId] = hooks.useState(null);
|
|
55
67
|
const [dropTarget, setDropTarget] = hooks.useState(null);
|
|
68
|
+
// Collapsed sources state
|
|
69
|
+
const [collapsedSources, setCollapsedSources] = hooks.useState({});
|
|
56
70
|
const handleDragStart = hooks.useCallback((calendar, e) => {
|
|
57
|
-
// Prevent dragging when editing or not draggable
|
|
58
71
|
if (editingId || !isDraggable) {
|
|
59
72
|
e.preventDefault();
|
|
60
73
|
return;
|
|
61
74
|
}
|
|
62
75
|
setDraggedCalendarId(calendar.id);
|
|
63
|
-
// Store calendar data for drop handling
|
|
64
76
|
const dragData = {
|
|
65
77
|
calendarId: calendar.id,
|
|
66
78
|
calendarName: calendar.name,
|
|
@@ -109,11 +121,9 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
|
|
|
109
121
|
return;
|
|
110
122
|
const fromIndex = calendars.findIndex(c => c.id === draggedCalendarId);
|
|
111
123
|
let toIndex = calendars.findIndex(c => c.id === targetCalendar.id);
|
|
112
|
-
// Adjust target index based on position
|
|
113
124
|
if (dropTarget.position === 'bottom') {
|
|
114
125
|
toIndex += 1;
|
|
115
126
|
}
|
|
116
|
-
// Adjust for removal of the item
|
|
117
127
|
if (toIndex > fromIndex) {
|
|
118
128
|
toIndex -= 1;
|
|
119
129
|
}
|
|
@@ -171,24 +181,75 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
|
|
|
171
181
|
}
|
|
172
182
|
}
|
|
173
183
|
}, [editingId, calendars]);
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
184
|
+
const toggleSource = hooks.useCallback((source) => {
|
|
185
|
+
setCollapsedSources(prev => (Object.assign(Object.assign({}, prev), { [source]: !prev[source] })));
|
|
186
|
+
}, []);
|
|
187
|
+
// Shared item props (excludes per-item fields)
|
|
188
|
+
const sharedItemProps = {
|
|
189
|
+
isDraggable,
|
|
190
|
+
isEditable,
|
|
191
|
+
editingId,
|
|
192
|
+
editingName,
|
|
193
|
+
setEditingName,
|
|
194
|
+
editInputRef,
|
|
195
|
+
isProcessedRef,
|
|
196
|
+
draggedCalendarId,
|
|
197
|
+
dropTarget,
|
|
198
|
+
activeContextMenuCalendarId,
|
|
199
|
+
onDragStart: handleDragStart,
|
|
200
|
+
onDragEnd: handleDragEnd,
|
|
201
|
+
onDragOver: handleDragOver,
|
|
202
|
+
onDragLeave: handleDragLeave,
|
|
203
|
+
onDrop: handleDrop,
|
|
204
|
+
onContextMenu,
|
|
205
|
+
onToggleVisibility,
|
|
206
|
+
onRenameStart: handleRenameStart,
|
|
207
|
+
onRenameSave: handleRenameSave,
|
|
208
|
+
onRenameKeyDown: handleRenameKeyDown,
|
|
209
|
+
setEditingId,
|
|
210
|
+
};
|
|
211
|
+
// Check if any calendar has a source
|
|
212
|
+
const hasSources = calendars.some(c => c.source);
|
|
213
|
+
if (!hasSources) {
|
|
214
|
+
// Flat list (original behaviour)
|
|
215
|
+
return (u("div", { className: 'df-calendar-list flex-1 overflow-y-auto px-2 pb-3', children: u("ul", { className: 'relative space-y-1', children: calendars.map(calendar => (u(CalendarItem, Object.assign({ calendar: calendar }, sharedItemProps), calendar.id))) }) }));
|
|
216
|
+
}
|
|
217
|
+
// Group calendars by source; calendars without a source go into a null group
|
|
218
|
+
const groups = new Map();
|
|
219
|
+
for (const calendar of calendars) {
|
|
220
|
+
const key = (_a = calendar.source) !== null && _a !== void 0 ? _a : null;
|
|
221
|
+
if (!groups.has(key))
|
|
222
|
+
groups.set(key, []);
|
|
223
|
+
groups.get(key).push(calendar);
|
|
224
|
+
}
|
|
225
|
+
return (u("div", { className: 'df-calendar-list flex-1 overflow-y-auto px-2 pb-3', children: [groups.has(null) && (u("ul", { className: 'relative space-y-1', children: groups.get(null).map(calendar => (u(CalendarItem, Object.assign({ calendar: calendar }, sharedItemProps), calendar.id))) })), Array.from(groups.entries())
|
|
226
|
+
.filter(([source]) => source !== null)
|
|
227
|
+
.map(([source, groupCalendars]) => {
|
|
228
|
+
const isCollapsed = collapsedSources[source];
|
|
229
|
+
return (u("div", { className: 'mt-1', children: [u("button", { type: 'button', className: 'flex w-full items-center justify-between rounded px-2 py-1.5 text-xs font-medium text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-slate-800', onClick: () => toggleSource(source), children: [u("span", { className: 'truncate', children: source }), u(core.ChevronDown, { width: 13, height: 13, className: `ml-1 shrink-0 transition-transform duration-200 ${isCollapsed ? '-rotate-90' : ''}` })] }), u("div", { style: {
|
|
230
|
+
display: 'grid',
|
|
231
|
+
gridTemplateRows: isCollapsed ? '0fr' : '1fr',
|
|
232
|
+
transition: 'grid-template-rows 200ms ease',
|
|
233
|
+
}, children: u("div", { style: { overflow: 'hidden' }, children: u("ul", { className: 'relative space-y-1', children: groupCalendars.map(calendar => (u(CalendarItem, Object.assign({ calendar: calendar }, sharedItemProps), calendar.id))) }) }) })] }, source));
|
|
234
|
+
})] }));
|
|
186
235
|
};
|
|
187
236
|
|
|
237
|
+
const CalendarChip = ({ name, color }) => (u("span", { className: 'mx-0.5 inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium', style: { backgroundColor: `${color}26`, color }, children: name }));
|
|
238
|
+
|
|
239
|
+
const CAL_SENTINEL = '\u0001C\u0001';
|
|
240
|
+
function renderWithChip(template, name, color) {
|
|
241
|
+
return template
|
|
242
|
+
.split(CAL_SENTINEL)
|
|
243
|
+
.flatMap((part, i) => i === 0
|
|
244
|
+
? [part]
|
|
245
|
+
: [u(CalendarChip, { name: name, color: color }, i), part]);
|
|
246
|
+
}
|
|
188
247
|
const DeleteCalendarDialog = ({ calendarId, calendarName, calendars, step, onStepChange, onConfirmDelete, onCancel, onMergeSelect, }) => {
|
|
248
|
+
var _a, _b;
|
|
189
249
|
const [showMergeDropdown, setShowMergeDropdown] = hooks.useState(false);
|
|
190
250
|
const { t } = core.useLocale();
|
|
191
|
-
|
|
251
|
+
const calendarColor = (_b = (_a = calendars.find(c => c.id === calendarId)) === null || _a === void 0 ? void 0 : _a.colors.lineColor) !== null && _b !== void 0 ? _b : '#6b7280';
|
|
252
|
+
return core.createPortal(u("div", { className: 'df-portal fixed inset-0 z-[9999] flex items-center justify-center bg-black/50', children: u("div", { className: 'w-full max-w-md rounded-lg bg-white p-6 shadow-xl dark:bg-gray-800', children: step === 'initial' ? (u(preact.Fragment, { children: [u("h2", { className: 'text-lg font-semibold text-gray-900 dark:text-white', children: t('deleteCalendar', { calendarName }) }), u("p", { className: 'mt-3 flex flex-wrap items-center gap-y-0.5 text-sm text-gray-600 dark:text-gray-300', children: renderWithChip(t('deleteCalendarMessage', { calendarName: CAL_SENTINEL }), calendarName, calendarColor) }), u("div", { className: 'mt-6 flex items-center justify-between', children: [u("div", { className: 'relative', children: [u("button", { type: 'button', onClick: () => setShowMergeDropdown(!showMergeDropdown), className: 'flex items-center gap-1 rounded-md border border-gray-300 px-4 py-2 text-xs font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-200 dark:hover:bg-slate-700', children: t('merge') }), showMergeDropdown && (u("div", { className: 'absolute top-full left-0 z-10 mt-1 max-h-60 w-max min-w-full overflow-y-auto rounded-md border border-gray-200 bg-white shadow-lg dark:border-slate-700 dark:bg-gray-800', children: calendars
|
|
192
253
|
.filter(c => c.id !== calendarId)
|
|
193
254
|
.map(calendar => (u("div", { className: 'flex cursor-pointer items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-slate-700', onClick: () => {
|
|
194
255
|
onMergeSelect(calendar.id);
|
|
@@ -245,6 +306,7 @@ const ImportCalendarDialog = ({ calendars, filename, onConfirm, onCancel, }) =>
|
|
|
245
306
|
top: rect.bottom,
|
|
246
307
|
left: rect.left,
|
|
247
308
|
width: rect.width,
|
|
309
|
+
overscrollBehavior: 'none',
|
|
248
310
|
}, children: u("div", { className: 'py-1', children: [calendars.map(calendar => (u("div", { className: `flex cursor-pointer items-center px-3 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 ${selectedCalendarId === calendar.id ? 'bg-primary/10' : ''}`, onClick: () => handleSelect(calendar.id), children: [u("div", { className: 'mr-3 h-3 w-3 shrink-0 rounded-sm', style: { backgroundColor: calendar.colors.lineColor } }), u("span", { className: `flex-1 truncate text-sm ${selectedCalendarId === calendar.id ? 'font-medium text-primary' : 'text-gray-700 dark:text-gray-200'}`, children: calendar.name || calendar.id }), selectedCalendarId === calendar.id && (u(core.Check, { className: 'ml-2 h-4 w-4 shrink-0 text-primary' }))] }, calendar.id))), u("div", { className: 'my-1 border-t border-gray-100 dark:border-slate-700' }), u("div", { className: `flex cursor-pointer items-center px-3 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 ${isNewSelected ? 'bg-primary/10' : ''}`, onClick: () => handleSelect(NEW_CALENDAR_ID), children: [u("span", { className: `flex-1 truncate text-sm ${isNewSelected ? 'font-medium text-primary' : 'pl-6 text-gray-700 dark:text-gray-200'}`, children: [t('newCalendar') || 'New Calendar', ": ", filename] }), isNewSelected && (u(core.Check, { className: 'ml-2 h-4 w-4 shrink-0 text-primary' }))] })] }) }), document.body);
|
|
249
311
|
};
|
|
250
312
|
return (u("div", { className: 'df-portal fixed inset-0 z-100 flex items-center justify-center bg-black/50', children: u("div", { className: 'w-full max-w-md rounded-lg bg-white p-6 shadow-xl dark:bg-gray-900', children: [u("h2", { className: 'mb-4 text-lg font-semibold text-gray-900 dark:text-white', children: t('addSchedule') || 'Add Schedule' }), u("p", { className: 'mb-4 text-sm text-gray-600 dark:text-gray-300', children: t('importCalendarMessage') ||
|
|
@@ -253,9 +315,29 @@ const ImportCalendarDialog = ({ calendars, filename, onConfirm, onCancel, }) =>
|
|
|
253
315
|
: (selectedCalendar === null || selectedCalendar === void 0 ? void 0 : selectedCalendar.name) || (selectedCalendar === null || selectedCalendar === void 0 ? void 0 : selectedCalendar.id) }), u(core.ChevronsUpDown, { className: 'ml-2 h-4 w-4 shrink-0 text-gray-400' })] }), renderDropdown()] }), u("div", { className: 'mt-8 flex justify-end gap-3', children: [u("button", { type: 'button', onClick: onCancel, className: core.cancelButton, children: t('cancel') || 'Cancel' }), u("button", { type: 'button', onClick: () => onConfirm(selectedCalendarId), className: 'rounded-md bg-primary px-6 py-2 text-sm font-medium text-primary-foreground shadow-sm transition-colors hover:bg-primary/90', children: t('ok') || 'OK' })] })] }) }));
|
|
254
316
|
};
|
|
255
317
|
|
|
256
|
-
const
|
|
318
|
+
const SOURCE_SENTINEL = '\u0001S\u0001';
|
|
319
|
+
const TARGET_SENTINEL = '\u0001T\u0001';
|
|
320
|
+
function renderLine(line, source, target) {
|
|
321
|
+
return line
|
|
322
|
+
.split(new RegExp(`(${SOURCE_SENTINEL}|${TARGET_SENTINEL})`))
|
|
323
|
+
.map((part, i) => {
|
|
324
|
+
if (part === SOURCE_SENTINEL)
|
|
325
|
+
return u(CalendarChip, { name: source.name, color: source.color }, i);
|
|
326
|
+
if (part === TARGET_SENTINEL)
|
|
327
|
+
return u(CalendarChip, { name: target.name, color: target.color }, i);
|
|
328
|
+
return part;
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
const MergeCalendarDialog = ({ sourceName, sourceColor, targetName, targetColor, onConfirm, onCancel, }) => {
|
|
257
332
|
const { t } = core.useLocale();
|
|
258
|
-
|
|
333
|
+
const source = { name: sourceName, color: sourceColor };
|
|
334
|
+
const target = { name: targetName, color: targetColor };
|
|
335
|
+
const messageTemplate = t('mergeConfirmMessage', {
|
|
336
|
+
sourceName: SOURCE_SENTINEL,
|
|
337
|
+
targetName: TARGET_SENTINEL,
|
|
338
|
+
});
|
|
339
|
+
const messageLines = messageTemplate.split('\n');
|
|
340
|
+
return (u("div", { className: 'df-portal fixed inset-0 z-[9999] flex items-center justify-center bg-black/50', children: u("div", { className: 'rounded-lg bg-white p-6 shadow-xl dark:bg-gray-800', children: [u("h2", { className: 'text-lg font-semibold text-gray-900 dark:text-white', children: t('mergeConfirmTitle', { sourceName, targetName }) }), u("div", { className: 'mt-3 space-y-1 text-sm text-gray-600 dark:text-gray-300', children: messageLines.map((line, i) => (u("p", { className: 'flex flex-wrap items-center gap-y-0.5', children: renderLine(line, source, target) }, i))) }), u("div", { className: 'mt-6 flex justify-end gap-3', children: [u("button", { type: 'button', onClick: onCancel, className: core.cancelButton, children: t('cancel') }), u("button", { type: 'button', onClick: onConfirm, className: 'rounded-md bg-destructive px-3 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90', children: t('merge') })] })] }) }));
|
|
259
341
|
};
|
|
260
342
|
|
|
261
343
|
const stopPropagation = (e) => e.stopPropagation();
|
|
@@ -304,8 +386,38 @@ const SidebarHeader = ({ isCollapsed, onCollapseToggle, }) => {
|
|
|
304
386
|
return (u("div", { className: core.sidebarHeader, children: [u("button", { type: 'button', "aria-label": isCollapsed ? t('expandSidebar') : t('collapseSidebar'), className: core.sidebarHeaderToggle, onClick: onCollapseToggle, children: isCollapsed ? (u(core.PanelRightClose, { className: 'h-4 w-4 text-gray-500 dark:text-gray-400' })) : (u(core.PanelRightOpen, { className: 'h-4 w-4 text-gray-500 dark:text-gray-400' })) }), !isCollapsed && (u("div", { className: 'ml-3 flex flex-1 items-center justify-between', children: u("span", { className: core.sidebarHeaderTitle, children: t('calendars') }) }))] }));
|
|
305
387
|
};
|
|
306
388
|
|
|
389
|
+
const SubscribeCalendarDialog = ({ onSubscribe, onCancel, }) => {
|
|
390
|
+
const { t } = core.useLocale();
|
|
391
|
+
const [url, setUrl] = hooks.useState('');
|
|
392
|
+
const [loading, setLoading] = hooks.useState(false);
|
|
393
|
+
const [error, setError] = hooks.useState(null);
|
|
394
|
+
const handleSubmit = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
395
|
+
const trimmed = url.trim();
|
|
396
|
+
if (!trimmed)
|
|
397
|
+
return;
|
|
398
|
+
setError(null);
|
|
399
|
+
setLoading(true);
|
|
400
|
+
try {
|
|
401
|
+
yield onSubscribe(trimmed);
|
|
402
|
+
}
|
|
403
|
+
catch (_a) {
|
|
404
|
+
setError(t('subscribeError'));
|
|
405
|
+
}
|
|
406
|
+
finally {
|
|
407
|
+
setLoading(false);
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
const handleKeyDown = (e) => {
|
|
411
|
+
if (e.key === 'Enter')
|
|
412
|
+
handleSubmit();
|
|
413
|
+
if (e.key === 'Escape')
|
|
414
|
+
onCancel();
|
|
415
|
+
};
|
|
416
|
+
return (u("div", { className: 'df-portal fixed inset-0 z-[9999] flex items-center justify-center bg-black/50', children: u("div", { className: 'w-full max-w-xl rounded-lg bg-white p-6 shadow-xl dark:bg-gray-800', children: [u("h2", { className: 'text-lg font-semibold text-gray-900 dark:text-white', children: t('subscribeCalendarTitle') }), u("div", { className: 'mt-4', children: [u("div", { className: 'flex items-center gap-3', children: [u("label", { className: 'shrink-0 text-sm font-medium text-gray-700 dark:text-gray-300', children: t('calendarUrl') }), u("input", { type: 'url', value: url, onInput: e => setUrl(e.target.value), onKeyDown: handleKeyDown, placeholder: t('calendarUrlPlaceholder'), disabled: loading, autoFocus: true, className: 'flex-1 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 placeholder-gray-400 focus:border-primary focus:ring-1 focus:ring-primary focus:outline-none disabled:opacity-50 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400' })] }), error && (u("p", { className: 'mt-2 text-xs text-red-500 dark:text-red-400', children: error }))] }), u("div", { className: 'mt-6 flex justify-end gap-3', children: [u("button", { type: 'button', onClick: onCancel, disabled: loading, className: core.cancelButton, children: t('cancel') }), u("button", { type: 'button', onClick: handleSubmit, disabled: loading || !url.trim(), className: 'rounded-md bg-primary px-4 py-2 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-50', children: loading ? t('fetchingCalendar') : t('subscribe') })] })] }) }));
|
|
417
|
+
};
|
|
418
|
+
|
|
307
419
|
const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, renderSidebarHeader, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, }) => {
|
|
308
|
-
var _a, _b
|
|
420
|
+
var _a, _b;
|
|
309
421
|
const { t } = core.useLocale();
|
|
310
422
|
// Detect if custom color picker slot is provided
|
|
311
423
|
const hasCustomPicker = app.state.overrides.includes('colorPicker');
|
|
@@ -333,6 +445,8 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
333
445
|
const [deleteState, setDeleteState] = hooks.useState(null);
|
|
334
446
|
// Import Calendar State
|
|
335
447
|
const [importState, setImportState] = hooks.useState(null);
|
|
448
|
+
// Subscribe Calendar State
|
|
449
|
+
const [subscribeDialogOpen, setSubscribeDialogOpen] = hooks.useState(false);
|
|
336
450
|
const handleContextMenu = hooks.useCallback((e, calendarId) => {
|
|
337
451
|
e.preventDefault();
|
|
338
452
|
e.stopPropagation(); // Stop propagation to prevent sidebar context menu
|
|
@@ -447,6 +561,51 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
447
561
|
(_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
|
|
448
562
|
handleCloseSidebarContextMenu();
|
|
449
563
|
}, [handleCloseSidebarContextMenu]);
|
|
564
|
+
// Subscribe Calendar handler
|
|
565
|
+
const handleSubscribeClick = hooks.useCallback(() => {
|
|
566
|
+
setSubscribeDialogOpen(true);
|
|
567
|
+
handleCloseSidebarContextMenu();
|
|
568
|
+
}, [handleCloseSidebarContextMenu]);
|
|
569
|
+
const handleSubscribeConfirm = hooks.useCallback((url) => __awaiter(void 0, void 0, void 0, function* () {
|
|
570
|
+
const response = yield fetch(url);
|
|
571
|
+
if (!response.ok)
|
|
572
|
+
throw new Error(`HTTP ${response.status}`);
|
|
573
|
+
const icsContent = yield response.text();
|
|
574
|
+
const result = core.parseICS(icsContent);
|
|
575
|
+
// Extract calendar name from X-WR-CALNAME if present
|
|
576
|
+
const nameMatch = icsContent.match(/X-WR-CALNAME[^:]*:([^\r\n]+)/);
|
|
577
|
+
const calendarName = nameMatch
|
|
578
|
+
? nameMatch[1].trim()
|
|
579
|
+
: new URL(url).hostname;
|
|
580
|
+
const presetColors = [
|
|
581
|
+
'#3b82f6',
|
|
582
|
+
'#10b981',
|
|
583
|
+
'#8b5cf6',
|
|
584
|
+
'#f59e0b',
|
|
585
|
+
'#ef4444',
|
|
586
|
+
'#f97316',
|
|
587
|
+
'#ec4899',
|
|
588
|
+
'#14b8a6',
|
|
589
|
+
'#6366f1',
|
|
590
|
+
'#6b7280',
|
|
591
|
+
];
|
|
592
|
+
const randomColor = presetColors[Math.floor(Math.random() * presetColors.length)];
|
|
593
|
+
const { colors: calendarColors, darkColors } = core.getCalendarColorsForHex(randomColor);
|
|
594
|
+
const calendarId = core.generateUniKey();
|
|
595
|
+
app.createCalendar({
|
|
596
|
+
id: calendarId,
|
|
597
|
+
name: calendarName,
|
|
598
|
+
isDefault: false,
|
|
599
|
+
colors: calendarColors,
|
|
600
|
+
darkColors,
|
|
601
|
+
isVisible: true,
|
|
602
|
+
subscribed: true,
|
|
603
|
+
});
|
|
604
|
+
result.events.forEach(event => {
|
|
605
|
+
app.addEvent(Object.assign(Object.assign({}, event), { calendarId }));
|
|
606
|
+
});
|
|
607
|
+
setSubscribeDialogOpen(false);
|
|
608
|
+
}), [app]);
|
|
450
609
|
const handleFileChange = hooks.useCallback((e) => __awaiter(void 0, void 0, void 0, function* () {
|
|
451
610
|
var _a;
|
|
452
611
|
const file = (_a = e.currentTarget.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
@@ -516,14 +675,18 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
516
675
|
handleCloseContextMenu();
|
|
517
676
|
}
|
|
518
677
|
}, [contextMenu, calendars, app, handleCloseContextMenu]);
|
|
519
|
-
const
|
|
520
|
-
?
|
|
521
|
-
:
|
|
522
|
-
const
|
|
523
|
-
?
|
|
524
|
-
:
|
|
678
|
+
const sourceCalendar = mergeState
|
|
679
|
+
? calendars.find(c => c.id === mergeState.sourceId)
|
|
680
|
+
: null;
|
|
681
|
+
const targetCalendar = mergeState
|
|
682
|
+
? calendars.find(c => c.id === mergeState.targetId)
|
|
683
|
+
: null;
|
|
684
|
+
const sourceCalendarName = (sourceCalendar === null || sourceCalendar === void 0 ? void 0 : sourceCalendar.name) || 'Unknown';
|
|
685
|
+
const targetCalendarName = (targetCalendar === null || targetCalendar === void 0 ? void 0 : targetCalendar.name) || 'Unknown';
|
|
686
|
+
const sourceCalendarColor = (sourceCalendar === null || sourceCalendar === void 0 ? void 0 : sourceCalendar.colors.lineColor) || '#6b7280';
|
|
687
|
+
const targetCalendarColor = (targetCalendar === null || targetCalendar === void 0 ? void 0 : targetCalendar.colors.lineColor) || '#6b7280';
|
|
525
688
|
const deleteCalendarName = deleteState
|
|
526
|
-
? ((
|
|
689
|
+
? ((_a = calendars.find(c => c.id === deleteState.calendarId)) === null || _a === void 0 ? void 0 : _a.name) || 'Unknown'
|
|
527
690
|
: '';
|
|
528
691
|
const readOnlyConfig = app.getReadOnlyConfig();
|
|
529
692
|
const isEditable = !app.state.readOnly;
|
|
@@ -561,16 +724,17 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
561
724
|
}, editingId: editingCalendarId, setEditingId: setEditingCalendarId, activeContextMenuCalendarId: contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.calendarId, isDraggable: isDraggable, isEditable: isEditable }), u("div", { className: 'border-t border-gray-200 dark:border-slate-800', children: u(core.MiniCalendar, { visibleMonth: app.getVisibleMonth(), currentDate: app.getCurrentDate(), showHeader: true, onMonthChange: handleMonthChange, onDateSelect: date => app.setCurrentDate(date) }) })] })), contextMenu && (u(core.ContextMenu, { ref: contextMenuRef, x: contextMenu.x, y: contextMenu.y, onClose: handleCloseContextMenu, className: 'w-64 p-2', children: u(core.ContentSlot, { generatorName: 'calendarContextMenu', generatorArgs: {
|
|
562
725
|
calendar: calendars.find(c => c.id === contextMenu.calendarId),
|
|
563
726
|
onClose: handleCloseContextMenu,
|
|
564
|
-
}, defaultContent: renderCalendarContextMenu ? (renderCalendarContextMenu(calendars.find(c => c.id === contextMenu.calendarId), handleCloseContextMenu)) : (u(preact.Fragment, { children: [u(core.ContextMenuLabel, { children: t('calendarOptions') }), u(MergeMenuItem, { calendars: calendars, currentCalendarId: contextMenu.calendarId, onMergeSelect: handleMergeSelect }), u(core.ContextMenuItem, { onClick: handleDeleteCalendar, children: t('delete') }), u(core.ContextMenuItem, { onClick: handleExportCalendar, children: t('exportCalendar') || 'Export Calendar' }), u(core.ContextMenuSeparator, {}), u(core.ContextMenuColorPicker, { selectedColor: (
|
|
727
|
+
}, defaultContent: renderCalendarContextMenu ? (renderCalendarContextMenu(calendars.find(c => c.id === contextMenu.calendarId), handleCloseContextMenu)) : (u(preact.Fragment, { children: [u(core.ContextMenuLabel, { children: t('calendarOptions') }), u(MergeMenuItem, { calendars: calendars, currentCalendarId: contextMenu.calendarId, onMergeSelect: handleMergeSelect }), u(core.ContextMenuItem, { onClick: handleDeleteCalendar, children: t('delete') }), u(core.ContextMenuItem, { onClick: handleExportCalendar, children: t('exportCalendar') || 'Export Calendar' }), u(core.ContextMenuSeparator, {}), u(core.ContextMenuColorPicker, { selectedColor: (_b = calendars.find(c => c.id === contextMenu.calendarId)) === null || _b === void 0 ? void 0 : _b.colors.lineColor, onSelect: handleColorSelect, onCustomColor: handleCustomColor })] })) }) })), sidebarContextMenu &&
|
|
565
728
|
core.createPortal(u(core.ContextMenu, { x: sidebarContextMenu.x, y: sidebarContextMenu.y, onClose: handleCloseSidebarContextMenu, className: 'w-max p-2', children: [u(core.ContextMenuItem, { onClick: () => {
|
|
566
729
|
onCreateCalendar === null || onCreateCalendar === void 0 ? void 0 : onCreateCalendar();
|
|
567
730
|
handleCloseSidebarContextMenu();
|
|
568
|
-
}, children: t('newCalendar') || 'New Calendar' }), u(core.ContextMenuItem, { onClick: handleImportClick, children: t('importCalendar') || 'Import Calendar' }), u(core.ContextMenuItem, { onClick: () => {
|
|
731
|
+
}, children: t('newCalendar') || 'New Calendar' }), u(core.ContextMenuItem, { onClick: handleImportClick, children: t('importCalendar') || 'Import Calendar' }), u(core.ContextMenuItem, { onClick: handleSubscribeClick, children: t('subscribeCalendar') || 'Subscribe to Calendar' }), u(core.ContextMenuItem, { onClick: () => {
|
|
569
732
|
app.triggerRender();
|
|
570
733
|
handleCloseSidebarContextMenu();
|
|
571
734
|
}, children: t('refreshAll') || 'Refresh All' })] }), document.body), u("input", { ref: fileInputRef, type: 'file', accept: '.ics', style: { display: 'none' }, onChange: handleFileChange }), importState &&
|
|
572
|
-
core.createPortal(u(ImportCalendarDialog, { calendars: calendars, filename: importState.filename, onConfirm: handleImportConfirm, onCancel: () => setImportState(null) }), document.body),
|
|
573
|
-
core.createPortal(u(
|
|
735
|
+
core.createPortal(u(ImportCalendarDialog, { calendars: calendars, filename: importState.filename, onConfirm: handleImportConfirm, onCancel: () => setImportState(null) }), document.body), subscribeDialogOpen &&
|
|
736
|
+
core.createPortal(u(SubscribeCalendarDialog, { onSubscribe: handleSubscribeConfirm, onCancel: () => setSubscribeDialogOpen(false) }), document.body), mergeState &&
|
|
737
|
+
core.createPortal(u(MergeCalendarDialog, { sourceName: sourceCalendarName, sourceColor: sourceCalendarColor, targetName: targetCalendarName, targetColor: targetCalendarColor, onConfirm: handleMergeConfirm, onCancel: () => setMergeState(null) }), document.body), deleteState &&
|
|
574
738
|
core.createPortal(u(DeleteCalendarDialog, { calendarId: deleteState.calendarId, calendarName: deleteCalendarName, calendars: calendars, step: deleteState.step, onStepChange: step => setDeleteState(prev => (prev ? Object.assign(Object.assign({}, prev), { step }) : null)), onConfirmDelete: handleConfirmDelete, onCancel: () => setDeleteState(null), onMergeSelect: handleDeleteMergeSelect }), document.body), customColorPicker &&
|
|
575
739
|
core.createPortal(u("div", { className: 'fixed inset-0 z-50', onMouseDown: () => {
|
|
576
740
|
app.updateCalendar(customColorPicker.calendarId, {});
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
interface MergeCalendarDialogProps {
|
|
2
2
|
sourceName: string;
|
|
3
|
+
sourceColor: string;
|
|
3
4
|
targetName: string;
|
|
5
|
+
targetColor: string;
|
|
4
6
|
onConfirm: () => void;
|
|
5
7
|
onCancel: () => void;
|
|
6
8
|
}
|
|
7
|
-
export declare const MergeCalendarDialog: ({ sourceName, targetName, onConfirm, onCancel, }: MergeCalendarDialogProps) => import("preact").JSX.Element;
|
|
9
|
+
export declare const MergeCalendarDialog: ({ sourceName, sourceColor, targetName, targetColor, onConfirm, onCancel, }: MergeCalendarDialogProps) => import("preact").JSX.Element;
|
|
8
10
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dayflow/plugin-sidebar",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "Sidebar plugin for DayFlow calendar",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"calendar",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"rollup-plugin-dts": "^6.3.0",
|
|
38
38
|
"temporal-polyfill": "^0.3.0",
|
|
39
39
|
"typescript": "^5.9.3",
|
|
40
|
-
"@dayflow/core": "3.3.
|
|
40
|
+
"@dayflow/core": "3.3.2"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@dayflow/core": "3.3.
|
|
43
|
+
"@dayflow/core": "3.3.2"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && rollup -c",
|