@dayflow/plugin-sidebar 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -13
- package/dist/index.esm.js +106 -86
- package/dist/index.js +106 -86
- package/dist/types/DefaultCalendarSidebar.d.ts +2 -1
- package/dist/types/components/CalendarList.d.ts +3 -2
- package/package.json +24 -22
package/README.md
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**English** | [中文](README.zh.md) | [日本語](README.ja.md) | [Getting Started & Contributing](CONTRIBUTING.md)
|
|
4
4
|
|
|
5
|
-
A flexible and feature-rich calendar component library for React
|
|
6
|
-
views, and plugin architecture.
|
|
5
|
+
A flexible and feature-rich calendar component library for **React, Vue, Angular, and Svelte** with drag-and-drop support, multiple views, and plugin architecture.
|
|
7
6
|
|
|
8
7
|
[](https://www.npmjs.com/package/@dayflow/core)
|
|
9
8
|
[](https://github.com/dayflow-js/dayflow/pulls)
|
|
@@ -12,21 +11,51 @@ views, and plugin architecture.
|
|
|
12
11
|
|
|
13
12
|
## Features
|
|
14
13
|
|
|
15
|
-
###
|
|
14
|
+
### Daily, Weekly, Monthly and Yearly View Types
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
| --------------------------------------- | -------------------------------------- |
|
|
19
|
-
|  |  |
|
|
16
|
+
#### Day View
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
| ------------------------------------- | ---------------------------------------- |
|
|
23
|
-
|  |  |
|
|
18
|
+

|
|
24
19
|
|
|
25
|
-
|
|
20
|
+
#### Week View
|
|
26
21
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+

|
|
23
|
+
|
|
24
|
+
#### Month View
|
|
25
|
+
|
|
26
|
+

|
|
27
|
+
|
|
28
|
+
#### Year View(Fixed-Week)
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
#### Year View(Year-Canvas)
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+
|
|
36
|
+
### Mobile View Support
|
|
37
|
+
|
|
38
|
+
#### Mobile Day & Year View
|
|
39
|
+
|
|
40
|
+

|
|
41
|
+
|
|
42
|
+
#### Mobile Week & Month View
|
|
43
|
+
|
|
44
|
+

|
|
45
|
+
|
|
46
|
+
### Multiple Event Detail Panel options
|
|
47
|
+
|
|
48
|
+
#### Detail Popup
|
|
49
|
+
|
|
50
|
+

|
|
51
|
+
|
|
52
|
+
#### Detail Dialog
|
|
53
|
+
|
|
54
|
+

|
|
55
|
+
|
|
56
|
+
### Dark Mode Support
|
|
57
|
+
|
|
58
|
+

|
|
30
59
|
|
|
31
60
|
### Easy to resize and drag
|
|
32
61
|
|
package/dist/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { useLocale, createPortal, cancelButton, ChevronsUpDown, Check, ChevronRight, sidebarHeader, sidebarHeaderToggle, PanelRightClose, PanelRightOpen, sidebarHeaderTitle, getCalendarColorsForHex, generateUniKey, downloadICS, MiniCalendar, ContextMenu, ContentSlot, ContextMenuLabel, ContextMenuItem, ContextMenuSeparator, ContextMenuColorPicker, BlossomColorPicker, DefaultColorPicker, importICSFile, sidebarContainer, normalizeCssWidth, registerSidebarImplementation, CreateCalendarDialog } from '@dayflow/core';
|
|
1
2
|
import { options, Fragment, h } from 'preact';
|
|
2
3
|
import { useState, useRef, useCallback, useEffect, useMemo } from 'preact/hooks';
|
|
3
|
-
import { useLocale, sidebarHeader, sidebarHeaderToggle, PanelRightClose, PanelRightOpen, sidebarHeaderTitle, ChevronRight, createPortal, cancelButton, ChevronsUpDown, Check, getCalendarColorsForHex, generateUniKey, downloadICS, MiniCalendar, ContextMenu, ContentSlot, ContextMenuLabel, ContextMenuItem, ContextMenuSeparator, ContextMenuColorPicker, BlossomColorPicker, DefaultColorPicker, importICSFile, sidebarContainer, normalizeCssWidth, registerSidebarImplementation, CreateCalendarDialog } from '@dayflow/core';
|
|
4
4
|
import { hexToHsl, lightnessToSliderValue } from '@dayflow/blossom-color-picker';
|
|
5
5
|
|
|
6
6
|
/******************************************************************************
|
|
@@ -37,11 +37,6 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
37
37
|
|
|
38
38
|
var f=0;function u(e,t,n,o,i,u){t||(t={});var a,c,p=t;if("ref"in p)for(c in p={},t)"ref"==c?a=t[c]:p[c]=t[c];var l={type:e,props:p,key:n,ref:a,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--f,__i:-1,__u:0,__source:i,__self:u};if("function"==typeof e&&(a=e.defaultProps))for(c in a) void 0===p[c]&&(p[c]=a[c]);return options.vnode&&options.vnode(l),l}
|
|
39
39
|
|
|
40
|
-
const SidebarHeader = ({ isCollapsed, onCollapseToggle, }) => {
|
|
41
|
-
const { t } = useLocale();
|
|
42
|
-
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: "flex flex-1 justify-between items-center ml-3", children: u("span", { className: sidebarHeaderTitle, children: t('calendars') }) }))] }));
|
|
43
|
-
};
|
|
44
|
-
|
|
45
40
|
const getCalendarInitials = (calendar) => {
|
|
46
41
|
if (calendar.icon) {
|
|
47
42
|
return calendar.icon;
|
|
@@ -70,9 +65,11 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
|
|
|
70
65
|
calendarColors: calendar.colors,
|
|
71
66
|
calendarIcon: calendar.icon,
|
|
72
67
|
};
|
|
73
|
-
e.dataTransfer
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
if (e.dataTransfer) {
|
|
69
|
+
e.dataTransfer.setData('application/x-dayflow-calendar', JSON.stringify(dragData));
|
|
70
|
+
e.dataTransfer.effectAllowed = 'copy';
|
|
71
|
+
}
|
|
72
|
+
}, [editingId, isDraggable]);
|
|
76
73
|
const handleDragEnd = useCallback(() => {
|
|
77
74
|
setDraggedCalendarId(null);
|
|
78
75
|
setDropTarget(null);
|
|
@@ -172,7 +169,7 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
|
|
|
172
169
|
}
|
|
173
170
|
}
|
|
174
171
|
}, [editingId, calendars]);
|
|
175
|
-
return (u("div", { className:
|
|
172
|
+
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 => {
|
|
176
173
|
var _a;
|
|
177
174
|
const isVisible = calendar.isVisible !== false;
|
|
178
175
|
const calendarColor = ((_a = calendar.colors) === null || _a === void 0 ? void 0 : _a.lineColor) || '#3b82f6';
|
|
@@ -180,69 +177,23 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
|
|
|
180
177
|
const isDropTarget = (dropTarget === null || dropTarget === void 0 ? void 0 : dropTarget.id) === calendar.id;
|
|
181
178
|
const isActive = activeContextMenuCalendarId === calendar.id ||
|
|
182
179
|
editingId === calendar.id;
|
|
183
|
-
return (u("li", { className:
|
|
180
|
+
return (u("li", { className: 'df-calendar-list-item relative', onDragOver: e => handleDragOver(e, calendar.id), onDragLeave: handleDragLeave, onDrop: () => handleDrop(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-primary' })), u("div", { draggable: isDraggable && !editingId, onDragStart: e => handleDragStart(calendar, e), onDragEnd: handleDragEnd, 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: 'calendar-checkbox shrink-0 cursor-pointer', style: {
|
|
184
181
|
'--checkbox-color': calendarColor,
|
|
185
|
-
}, checked: isVisible, onChange: event => onToggleVisibility(calendar.id, event.target.checked) }), showIcon && (u("span", { className:
|
|
182
|
+
}, 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: handleRenameSave, onKeyDown: handleRenameKeyDown, 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("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: () => handleRenameStart(calendar), children: calendar.name || calendar.id }))] }) }), isDropTarget && dropTarget.position === 'bottom' && (u("div", { className: 'pointer-events-none absolute right-0 bottom-0 left-0 z-10 h-0.5 bg-primary' }))] }, calendar.id));
|
|
186
183
|
}) }) }));
|
|
187
184
|
};
|
|
188
185
|
|
|
189
|
-
const MergeMenuItem = ({ calendars, currentCalendarId, onMergeSelect, }) => {
|
|
190
|
-
const { t } = useLocale();
|
|
191
|
-
const [isHovered, setIsHovered] = useState(false);
|
|
192
|
-
const itemRef = useRef(null);
|
|
193
|
-
const submenuRef = useRef(null);
|
|
194
|
-
const [position, setPosition] = useState({ x: 0, y: 0 });
|
|
195
|
-
const timeoutRef = useRef();
|
|
196
|
-
const handleMouseEnter = () => {
|
|
197
|
-
if (timeoutRef.current)
|
|
198
|
-
clearTimeout(timeoutRef.current);
|
|
199
|
-
if (itemRef.current) {
|
|
200
|
-
const rect = itemRef.current.getBoundingClientRect();
|
|
201
|
-
setPosition({ x: rect.right, y: rect.top });
|
|
202
|
-
}
|
|
203
|
-
setIsHovered(true);
|
|
204
|
-
};
|
|
205
|
-
const handleMouseLeave = () => {
|
|
206
|
-
timeoutRef.current = setTimeout(() => {
|
|
207
|
-
setIsHovered(false);
|
|
208
|
-
}, 100);
|
|
209
|
-
};
|
|
210
|
-
useEffect(() => {
|
|
211
|
-
const el = submenuRef.current;
|
|
212
|
-
if (el) {
|
|
213
|
-
const stopPropagation = (e) => e.stopPropagation();
|
|
214
|
-
el.addEventListener('mousedown', stopPropagation);
|
|
215
|
-
return () => {
|
|
216
|
-
el.removeEventListener('mousedown', stopPropagation);
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
}, [isHovered]);
|
|
220
|
-
const availableCalendars = calendars.filter(c => c.id !== currentCalendarId);
|
|
221
|
-
if (availableCalendars.length === 0)
|
|
222
|
-
return null;
|
|
223
|
-
return (u(Fragment, { children: [u("div", { ref: itemRef, className: "relative flex cursor-default select-none items-center justify-between rounded-sm px-3 py-0.5 text-[12px] outline-none hover:bg-primary hover:text-white dark:text-slate-200 dark:hover:bg-primary dark:hover:text-white transition-colors", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [u("span", { children: t('merge') }), u(ChevronRight, { className: "h-4 w-4" })] }), isHovered &&
|
|
224
|
-
createPortal(u("div", { ref: submenuRef, "data-submenu-content": "true", className: "fixed z-60 min-w-48 overflow-hidden rounded-md border border-slate-200 bg-white p-1 shadow-md dark:border-slate-800 dark:bg-slate-950 animate-in fade-in-0 zoom-in-95 duration-100", style: { top: position.y, left: position.x }, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseDown: e => e.stopPropagation(), children: availableCalendars.map(calendar => (u("div", { className: "flex items-center cursor-pointer rounded-sm px-3 py-1 text-[12px] text-slate-900 hover:bg-primary hover:text-white dark:text-slate-50 dark:hover:bg-primary dark:hover:text-white transition-colors", onClick: e => {
|
|
225
|
-
e.stopPropagation();
|
|
226
|
-
onMergeSelect(calendar.id);
|
|
227
|
-
}, children: [u("div", { className: "mr-2 h-3 w-3 rounded-sm shrink-0", style: { backgroundColor: calendar.colors.lineColor } }), u("span", { className: "truncate", children: calendar.name || calendar.id })] }, calendar.id))) }), document.body)] }));
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
const MergeCalendarDialog = ({ sourceName, targetName, onConfirm, onCancel, }) => {
|
|
231
|
-
const { t } = useLocale();
|
|
232
|
-
return (u("div", { className: "fixed inset-0 z-100 flex items-center justify-center bg-black/50", children: u("div", { className: "w-full max-w-md rounded-lg p-6 shadow-xl bg-background", children: [u("h2", { className: "text-lg font-semibold text-gray-900 dark:text-white", children: t('mergeConfirmTitle', { sourceName, targetName }) }), u("p", { className: "mt-3 text-sm text-gray-600 dark:text-gray-300", children: t('mergeConfirmMessage', { sourceName, targetName }) }), 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') })] })] }) }));
|
|
233
|
-
};
|
|
234
|
-
|
|
235
186
|
const DeleteCalendarDialog = ({ calendarId, calendarName, calendars, step, onStepChange, onConfirmDelete, onCancel, onMergeSelect, }) => {
|
|
236
187
|
const [showMergeDropdown, setShowMergeDropdown] = useState(false);
|
|
237
188
|
const { t } = useLocale();
|
|
238
|
-
return createPortal(u("div", { className:
|
|
189
|
+
return createPortal(u("div", { className: '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-background p-6 shadow-xl', 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 text-sm text-gray-600 dark:text-gray-300', children: t('deleteCalendarMessage', { calendarName }) }), 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-background shadow-lg dark:border-slate-700', children: calendars
|
|
239
190
|
.filter(c => c.id !== calendarId)
|
|
240
|
-
.map(calendar => (u("div", { className:
|
|
191
|
+
.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: () => {
|
|
241
192
|
onMergeSelect(calendar.id);
|
|
242
193
|
setShowMergeDropdown(false);
|
|
243
|
-
}, children: [u("div", { className:
|
|
194
|
+
}, children: [u("div", { className: 'mr-2 h-3 w-3 shrink-0 rounded-sm', style: {
|
|
244
195
|
backgroundColor: calendar.colors.lineColor,
|
|
245
|
-
} }), u("span", { className:
|
|
196
|
+
} }), u("span", { className: 'whitespace-nowrap', children: calendar.name || calendar.id })] }, calendar.id))) }))] }), u("div", { className: 'flex gap-3', children: [u("button", { type: 'button', onClick: onCancel, className: cancelButton, children: t('cancel') }), u("button", { type: 'button', onClick: () => onStepChange('confirm_delete'), className: 'rounded-md bg-destructive px-4 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90', children: t('delete') })] })] })] })) : (u(Fragment, { children: [u("h2", { className: 'text-lg font-semibold text-gray-900 dark:text-white', children: t('confirmDeleteTitle', { calendarName }) }), u("p", { className: 'mt-3 text-sm text-gray-600 dark:text-gray-300', children: t('confirmDeleteMessage') }), u("div", { className: 'mt-6 flex justify-end gap-3', children: [u("button", { type: 'button', onClick: onCancel, className: 'rounded-md border border-border bg-background px-3 py-2 text-xs font-medium text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-slate-700', children: t('cancel') }), u("button", { type: 'button', onClick: onConfirmDelete, className: 'rounded-md bg-destructive px-3 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90', children: t('delete') })] })] })) }) }), document.body);
|
|
246
197
|
};
|
|
247
198
|
|
|
248
199
|
const NEW_CALENDAR_ID = 'new-calendar';
|
|
@@ -288,25 +239,76 @@ const ImportCalendarDialog = ({ calendars, filename, onConfirm, onCancel, }) =>
|
|
|
288
239
|
const rect = (_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
|
|
289
240
|
if (!rect)
|
|
290
241
|
return null;
|
|
291
|
-
return createPortal(u("div", { ref: dropdownRef, className: `fixed z-110 mt-1 max-h-60 overflow-y-auto rounded-md bg-white shadow-lg
|
|
242
|
+
return createPortal(u("div", { ref: dropdownRef, className: `fixed z-110 mt-1 max-h-60 origin-top overflow-y-auto rounded-md border border-gray-200 bg-white shadow-lg transition-all duration-200 dark:border-slate-700 dark:bg-slate-800 ${isOpen ? 'scale-100 opacity-100' : 'scale-95 opacity-0'}`, style: {
|
|
292
243
|
top: rect.bottom,
|
|
293
244
|
left: rect.left,
|
|
294
245
|
width: rect.width,
|
|
295
|
-
}, children: u("div", { className:
|
|
246
|
+
}, 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);
|
|
296
247
|
};
|
|
297
|
-
return (u("div", { className:
|
|
298
|
-
'This calendar contains new events. Please select a target calendar.' }), u("div", { className:
|
|
248
|
+
return (u("div", { className: '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-slate-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') ||
|
|
249
|
+
'This calendar contains new events. Please select a target calendar.' }), u("div", { className: 'relative', children: [u("button", { ref: triggerRef, type: 'button', className: 'flex w-full items-center rounded-md border border-gray-300 px-3 py-2 shadow-sm transition-colors hover:bg-gray-50 dark:border-gray-600 dark:hover:bg-gray-800', onClick: () => setIsOpen(!isOpen), children: [!isNewSelected && selectedCalendar && (u("div", { className: 'mr-3 h-3 w-3 shrink-0 rounded-sm', style: { backgroundColor: selectedCalendar.colors.lineColor } })), u("span", { className: `flex-1 truncate text-left text-sm font-medium text-gray-700 dark:text-gray-200 ${isNewSelected ? 'pl-0' : ''}`, children: isNewSelected
|
|
299
250
|
? `${t('newCalendar')}: ${filename}`
|
|
300
|
-
: (selectedCalendar === null || selectedCalendar === void 0 ? void 0 : selectedCalendar.name) || (selectedCalendar === null || selectedCalendar === void 0 ? void 0 : selectedCalendar.id) }), u(ChevronsUpDown, { className:
|
|
251
|
+
: (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
|
+
};
|
|
253
|
+
|
|
254
|
+
const MergeCalendarDialog = ({ sourceName, targetName, onConfirm, onCancel, }) => {
|
|
255
|
+
const { t } = useLocale();
|
|
256
|
+
return (u("div", { className: '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-background p-6 shadow-xl', children: [u("h2", { className: 'text-lg font-semibold text-gray-900 dark:text-white', children: t('mergeConfirmTitle', { sourceName, targetName }) }), u("p", { className: 'mt-3 text-sm text-gray-600 dark:text-gray-300', children: t('mergeConfirmMessage', { sourceName, targetName }) }), 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
|
+
};
|
|
258
|
+
|
|
259
|
+
const stopPropagation = (e) => e.stopPropagation();
|
|
260
|
+
const MergeMenuItem = ({ calendars, currentCalendarId, onMergeSelect, }) => {
|
|
261
|
+
const { t } = useLocale();
|
|
262
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
263
|
+
const itemRef = useRef(null);
|
|
264
|
+
const submenuRef = useRef(null);
|
|
265
|
+
const [position, setPosition] = useState({ x: 0, y: 0 });
|
|
266
|
+
const timeoutRef = useRef();
|
|
267
|
+
const handleMouseEnter = () => {
|
|
268
|
+
if (timeoutRef.current)
|
|
269
|
+
clearTimeout(timeoutRef.current);
|
|
270
|
+
if (itemRef.current) {
|
|
271
|
+
const rect = itemRef.current.getBoundingClientRect();
|
|
272
|
+
setPosition({ x: rect.right, y: rect.top });
|
|
273
|
+
}
|
|
274
|
+
setIsHovered(true);
|
|
275
|
+
};
|
|
276
|
+
const handleMouseLeave = () => {
|
|
277
|
+
timeoutRef.current = setTimeout(() => {
|
|
278
|
+
setIsHovered(false);
|
|
279
|
+
}, 100);
|
|
280
|
+
};
|
|
281
|
+
useEffect(() => {
|
|
282
|
+
const el = submenuRef.current;
|
|
283
|
+
if (el) {
|
|
284
|
+
el.addEventListener('mousedown', stopPropagation);
|
|
285
|
+
return () => {
|
|
286
|
+
el.removeEventListener('mousedown', stopPropagation);
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
}, [isHovered]);
|
|
290
|
+
const availableCalendars = calendars.filter(c => c.id !== currentCalendarId);
|
|
291
|
+
if (availableCalendars.length === 0)
|
|
292
|
+
return null;
|
|
293
|
+
return (u(Fragment, { children: [u("div", { ref: itemRef, className: 'relative flex cursor-default items-center justify-between rounded-sm px-3 py-0.5 text-[12px] transition-colors outline-none select-none hover:bg-primary hover:text-white dark:text-slate-200 dark:hover:bg-primary dark:hover:text-white', onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [u("span", { children: t('merge') }), u(ChevronRight, { className: 'h-4 w-4' })] }), isHovered &&
|
|
294
|
+
createPortal(u("div", { ref: submenuRef, "data-submenu-content": 'true', className: 'animate-in fade-in-0 zoom-in-95 fixed z-60 min-w-48 overflow-hidden rounded-md border border-slate-200 bg-white p-1 shadow-md duration-100 dark:border-slate-800 dark:bg-slate-950', style: { top: position.y, left: position.x }, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseDown: e => e.stopPropagation(), children: availableCalendars.map(calendar => (u("div", { className: 'flex cursor-pointer items-center rounded-sm px-3 py-1 text-[12px] text-slate-900 transition-colors hover:bg-primary hover:text-white dark:text-slate-50 dark:hover:bg-primary dark:hover:text-white', onClick: e => {
|
|
295
|
+
e.stopPropagation();
|
|
296
|
+
onMergeSelect(calendar.id);
|
|
297
|
+
}, children: [u("div", { className: 'mr-2 h-3 w-3 shrink-0 rounded-sm', style: { backgroundColor: calendar.colors.lineColor } }), u("span", { className: 'truncate', children: calendar.name || calendar.id })] }, calendar.id))) }), document.body)] }));
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const SidebarHeader = ({ isCollapsed, onCollapseToggle, }) => {
|
|
301
|
+
const { t } = useLocale();
|
|
302
|
+
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') }) }))] }));
|
|
301
303
|
};
|
|
302
304
|
|
|
303
305
|
const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, colorPickerMode = 'default', }) => {
|
|
304
306
|
var _a, _b, _c, _d;
|
|
305
307
|
const { t } = useLocale();
|
|
306
308
|
const [localEditingCalendarId, setLocalEditingCalendarId] = useState(null);
|
|
307
|
-
const editingCalendarId = propEditingCalendarId
|
|
308
|
-
?
|
|
309
|
-
:
|
|
309
|
+
const editingCalendarId = propEditingCalendarId === undefined
|
|
310
|
+
? localEditingCalendarId
|
|
311
|
+
: propEditingCalendarId;
|
|
310
312
|
const setEditingCalendarId = propSetEditingCalendarId || setLocalEditingCalendarId;
|
|
311
313
|
// File input ref for import
|
|
312
314
|
const fileInputRef = useRef(null);
|
|
@@ -443,7 +445,7 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
443
445
|
}, [handleCloseSidebarContextMenu]);
|
|
444
446
|
const handleFileChange = useCallback((e) => __awaiter(void 0, void 0, void 0, function* () {
|
|
445
447
|
var _a;
|
|
446
|
-
const file = (_a = e.
|
|
448
|
+
const file = (_a = e.currentTarget.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
447
449
|
if (!file)
|
|
448
450
|
return;
|
|
449
451
|
const result = yield importICSFile(file);
|
|
@@ -522,28 +524,48 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
522
524
|
const readOnlyConfig = app.getReadOnlyConfig();
|
|
523
525
|
const isEditable = !app.state.readOnly;
|
|
524
526
|
const isDraggable = readOnlyConfig.draggable !== false;
|
|
525
|
-
return (u("div", { className: sidebarContainer, onContextMenu: isEditable ? handleSidebarContextMenu : undefined, children: [u(SidebarHeader, { isCollapsed: isCollapsed, onCollapseToggle: () => setCollapsed(!isCollapsed) }),
|
|
526
|
-
|
|
527
|
-
|
|
527
|
+
return (u("div", { className: sidebarContainer, onContextMenu: isEditable ? handleSidebarContextMenu : undefined, children: [u(SidebarHeader, { isCollapsed: isCollapsed, onCollapseToggle: () => setCollapsed(!isCollapsed) }), isCollapsed ? (u(CalendarList, { calendars: calendars, onToggleVisibility: toggleCalendarVisibility, onReorder: isDraggable
|
|
528
|
+
? app.reorderCalendars
|
|
529
|
+
: () => {
|
|
530
|
+
/* noop */
|
|
531
|
+
}, onRename: isEditable
|
|
528
532
|
? (id, newName) => app.updateCalendar(id, { name: newName })
|
|
529
|
-
: () => {
|
|
533
|
+
: () => {
|
|
534
|
+
/* noop */
|
|
535
|
+
}, onContextMenu: isEditable
|
|
536
|
+
? handleContextMenu
|
|
537
|
+
: () => {
|
|
538
|
+
/* noop */
|
|
539
|
+
}, editingId: editingCalendarId, setEditingId: setEditingCalendarId, activeContextMenuCalendarId: contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.calendarId, isDraggable: isDraggable, isEditable: isEditable })) : (u(Fragment, { children: [u(CalendarList, { calendars: calendars, onToggleVisibility: toggleCalendarVisibility, onReorder: isDraggable
|
|
540
|
+
? app.reorderCalendars
|
|
541
|
+
: () => {
|
|
542
|
+
/* noop */
|
|
543
|
+
}, onRename: isEditable
|
|
544
|
+
? (id, newName) => app.updateCalendar(id, { name: newName })
|
|
545
|
+
: () => {
|
|
546
|
+
/* noop */
|
|
547
|
+
}, onContextMenu: isEditable
|
|
548
|
+
? handleContextMenu
|
|
549
|
+
: () => {
|
|
550
|
+
/* noop */
|
|
551
|
+
}, 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: {
|
|
530
552
|
calendar: calendars.find(c => c.id === contextMenu.calendarId),
|
|
531
553
|
onClose: handleCloseContextMenu,
|
|
532
554
|
}, 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: (_d = calendars.find(c => c.id === contextMenu.calendarId)) === null || _d === void 0 ? void 0 : _d.colors.lineColor, onSelect: handleColorSelect, onCustomColor: handleCustomColor })] })) }) })), sidebarContextMenu &&
|
|
533
|
-
createPortal(u(ContextMenu, { x: sidebarContextMenu.x, y: sidebarContextMenu.y, onClose: handleCloseSidebarContextMenu, className:
|
|
555
|
+
createPortal(u(ContextMenu, { x: sidebarContextMenu.x, y: sidebarContextMenu.y, onClose: handleCloseSidebarContextMenu, className: 'w-max p-2', children: [u(ContextMenuItem, { onClick: () => {
|
|
534
556
|
onCreateCalendar === null || onCreateCalendar === void 0 ? void 0 : onCreateCalendar();
|
|
535
557
|
handleCloseSidebarContextMenu();
|
|
536
558
|
}, children: t('newCalendar') || 'New Calendar' }), u(ContextMenuItem, { onClick: handleImportClick, children: t('importCalendar') || 'Import Calendar' }), u(ContextMenuItem, { onClick: () => {
|
|
537
559
|
app.triggerRender();
|
|
538
560
|
handleCloseSidebarContextMenu();
|
|
539
|
-
}, children: t('refreshAll') || 'Refresh All' })] }), document.body), u("input", { ref: fileInputRef, type:
|
|
561
|
+
}, children: t('refreshAll') || 'Refresh All' })] }), document.body), u("input", { ref: fileInputRef, type: 'file', accept: '.ics', style: { display: 'none' }, onChange: handleFileChange }), importState &&
|
|
540
562
|
createPortal(u(ImportCalendarDialog, { calendars: calendars, filename: importState.filename, onConfirm: handleImportConfirm, onCancel: () => setImportState(null) }), document.body), mergeState &&
|
|
541
563
|
createPortal(u(MergeCalendarDialog, { sourceName: sourceCalendarName, targetName: targetCalendarName, onConfirm: handleMergeConfirm, onCancel: () => setMergeState(null) }), document.body), deleteState &&
|
|
542
564
|
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 &&
|
|
543
|
-
createPortal(u("div", { className:
|
|
565
|
+
createPortal(u("div", { className: 'fixed inset-0 z-50', onMouseDown: () => {
|
|
544
566
|
app.updateCalendar(customColorPicker.calendarId, {});
|
|
545
567
|
setCustomColorPicker(null);
|
|
546
|
-
}, children: u("div", { className:
|
|
568
|
+
}, children: u("div", { className: 'absolute flex items-center justify-center', style: {
|
|
547
569
|
top: customColorPicker.y,
|
|
548
570
|
left: customColorPicker.x,
|
|
549
571
|
transform: 'translate(280%, -50%)',
|
|
@@ -556,8 +578,8 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
556
578
|
}, onCollapse: () => {
|
|
557
579
|
app.updateCalendar(customColorPicker.calendarId, {});
|
|
558
580
|
setCustomColorPicker(null);
|
|
559
|
-
} })) : (u(ContentSlot, { generatorName:
|
|
560
|
-
variant: 'sketch', //
|
|
581
|
+
} })) : (u(ContentSlot, { generatorName: 'colorPicker', generatorArgs: {
|
|
582
|
+
variant: 'sketch', // Pending: change name
|
|
561
583
|
color: customColorPicker.currentColor,
|
|
562
584
|
onChange: (color) => {
|
|
563
585
|
setCustomColorPicker(prev => prev ? Object.assign(Object.assign({}, prev), { currentColor: color.hex }) : null);
|
|
@@ -613,11 +635,9 @@ function createSidebarPlugin(config = {}) {
|
|
|
613
635
|
const refreshSidebar = useCallback(() => {
|
|
614
636
|
setSidebarVersion(prev => prev + 1);
|
|
615
637
|
}, []);
|
|
616
|
-
useEffect(() => {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
});
|
|
620
|
-
}, [app, refreshSidebar]);
|
|
638
|
+
useEffect(() => app.subscribe(() => {
|
|
639
|
+
refreshSidebar();
|
|
640
|
+
}), [app, refreshSidebar]);
|
|
621
641
|
const calendars = useMemo(() => app.getCalendars(), [app, sidebarVersion]);
|
|
622
642
|
const handleToggleCalendarVisibility = useCallback((calendarId, visible) => {
|
|
623
643
|
app.setCalendarVisibility(calendarId, visible);
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var core = require('@dayflow/core');
|
|
3
4
|
var preact = require('preact');
|
|
4
5
|
var hooks = require('preact/hooks');
|
|
5
|
-
var core = require('@dayflow/core');
|
|
6
6
|
var blossomColorPicker = require('@dayflow/blossom-color-picker');
|
|
7
7
|
|
|
8
8
|
/******************************************************************************
|
|
@@ -39,11 +39,6 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
39
39
|
|
|
40
40
|
var f=0;function u(e,t,n,o,i,u){t||(t={});var a,c,p=t;if("ref"in p)for(c in p={},t)"ref"==c?a=t[c]:p[c]=t[c];var l={type:e,props:p,key:n,ref:a,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--f,__i:-1,__u:0,__source:i,__self:u};if("function"==typeof e&&(a=e.defaultProps))for(c in a) void 0===p[c]&&(p[c]=a[c]);return preact.options.vnode&&preact.options.vnode(l),l}
|
|
41
41
|
|
|
42
|
-
const SidebarHeader = ({ isCollapsed, onCollapseToggle, }) => {
|
|
43
|
-
const { t } = core.useLocale();
|
|
44
|
-
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: "flex flex-1 justify-between items-center ml-3", children: u("span", { className: core.sidebarHeaderTitle, children: t('calendars') }) }))] }));
|
|
45
|
-
};
|
|
46
|
-
|
|
47
42
|
const getCalendarInitials = (calendar) => {
|
|
48
43
|
if (calendar.icon) {
|
|
49
44
|
return calendar.icon;
|
|
@@ -72,9 +67,11 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
|
|
|
72
67
|
calendarColors: calendar.colors,
|
|
73
68
|
calendarIcon: calendar.icon,
|
|
74
69
|
};
|
|
75
|
-
e.dataTransfer
|
|
76
|
-
|
|
77
|
-
|
|
70
|
+
if (e.dataTransfer) {
|
|
71
|
+
e.dataTransfer.setData('application/x-dayflow-calendar', JSON.stringify(dragData));
|
|
72
|
+
e.dataTransfer.effectAllowed = 'copy';
|
|
73
|
+
}
|
|
74
|
+
}, [editingId, isDraggable]);
|
|
78
75
|
const handleDragEnd = hooks.useCallback(() => {
|
|
79
76
|
setDraggedCalendarId(null);
|
|
80
77
|
setDropTarget(null);
|
|
@@ -174,7 +171,7 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
|
|
|
174
171
|
}
|
|
175
172
|
}
|
|
176
173
|
}, [editingId, calendars]);
|
|
177
|
-
return (u("div", { className:
|
|
174
|
+
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 => {
|
|
178
175
|
var _a;
|
|
179
176
|
const isVisible = calendar.isVisible !== false;
|
|
180
177
|
const calendarColor = ((_a = calendar.colors) === null || _a === void 0 ? void 0 : _a.lineColor) || '#3b82f6';
|
|
@@ -182,69 +179,23 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
|
|
|
182
179
|
const isDropTarget = (dropTarget === null || dropTarget === void 0 ? void 0 : dropTarget.id) === calendar.id;
|
|
183
180
|
const isActive = activeContextMenuCalendarId === calendar.id ||
|
|
184
181
|
editingId === calendar.id;
|
|
185
|
-
return (u("li", { className:
|
|
182
|
+
return (u("li", { className: 'df-calendar-list-item relative', onDragOver: e => handleDragOver(e, calendar.id), onDragLeave: handleDragLeave, onDrop: () => handleDrop(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-primary' })), u("div", { draggable: isDraggable && !editingId, onDragStart: e => handleDragStart(calendar, e), onDragEnd: handleDragEnd, 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: 'calendar-checkbox shrink-0 cursor-pointer', style: {
|
|
186
183
|
'--checkbox-color': calendarColor,
|
|
187
|
-
}, checked: isVisible, onChange: event => onToggleVisibility(calendar.id, event.target.checked) }), showIcon && (u("span", { className:
|
|
184
|
+
}, 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: handleRenameSave, onKeyDown: handleRenameKeyDown, 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("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: () => handleRenameStart(calendar), children: calendar.name || calendar.id }))] }) }), isDropTarget && dropTarget.position === 'bottom' && (u("div", { className: 'pointer-events-none absolute right-0 bottom-0 left-0 z-10 h-0.5 bg-primary' }))] }, calendar.id));
|
|
188
185
|
}) }) }));
|
|
189
186
|
};
|
|
190
187
|
|
|
191
|
-
const MergeMenuItem = ({ calendars, currentCalendarId, onMergeSelect, }) => {
|
|
192
|
-
const { t } = core.useLocale();
|
|
193
|
-
const [isHovered, setIsHovered] = hooks.useState(false);
|
|
194
|
-
const itemRef = hooks.useRef(null);
|
|
195
|
-
const submenuRef = hooks.useRef(null);
|
|
196
|
-
const [position, setPosition] = hooks.useState({ x: 0, y: 0 });
|
|
197
|
-
const timeoutRef = hooks.useRef();
|
|
198
|
-
const handleMouseEnter = () => {
|
|
199
|
-
if (timeoutRef.current)
|
|
200
|
-
clearTimeout(timeoutRef.current);
|
|
201
|
-
if (itemRef.current) {
|
|
202
|
-
const rect = itemRef.current.getBoundingClientRect();
|
|
203
|
-
setPosition({ x: rect.right, y: rect.top });
|
|
204
|
-
}
|
|
205
|
-
setIsHovered(true);
|
|
206
|
-
};
|
|
207
|
-
const handleMouseLeave = () => {
|
|
208
|
-
timeoutRef.current = setTimeout(() => {
|
|
209
|
-
setIsHovered(false);
|
|
210
|
-
}, 100);
|
|
211
|
-
};
|
|
212
|
-
hooks.useEffect(() => {
|
|
213
|
-
const el = submenuRef.current;
|
|
214
|
-
if (el) {
|
|
215
|
-
const stopPropagation = (e) => e.stopPropagation();
|
|
216
|
-
el.addEventListener('mousedown', stopPropagation);
|
|
217
|
-
return () => {
|
|
218
|
-
el.removeEventListener('mousedown', stopPropagation);
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
}, [isHovered]);
|
|
222
|
-
const availableCalendars = calendars.filter(c => c.id !== currentCalendarId);
|
|
223
|
-
if (availableCalendars.length === 0)
|
|
224
|
-
return null;
|
|
225
|
-
return (u(preact.Fragment, { children: [u("div", { ref: itemRef, className: "relative flex cursor-default select-none items-center justify-between rounded-sm px-3 py-0.5 text-[12px] outline-none hover:bg-primary hover:text-white dark:text-slate-200 dark:hover:bg-primary dark:hover:text-white transition-colors", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [u("span", { children: t('merge') }), u(core.ChevronRight, { className: "h-4 w-4" })] }), isHovered &&
|
|
226
|
-
core.createPortal(u("div", { ref: submenuRef, "data-submenu-content": "true", className: "fixed z-60 min-w-48 overflow-hidden rounded-md border border-slate-200 bg-white p-1 shadow-md dark:border-slate-800 dark:bg-slate-950 animate-in fade-in-0 zoom-in-95 duration-100", style: { top: position.y, left: position.x }, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseDown: e => e.stopPropagation(), children: availableCalendars.map(calendar => (u("div", { className: "flex items-center cursor-pointer rounded-sm px-3 py-1 text-[12px] text-slate-900 hover:bg-primary hover:text-white dark:text-slate-50 dark:hover:bg-primary dark:hover:text-white transition-colors", onClick: e => {
|
|
227
|
-
e.stopPropagation();
|
|
228
|
-
onMergeSelect(calendar.id);
|
|
229
|
-
}, children: [u("div", { className: "mr-2 h-3 w-3 rounded-sm shrink-0", style: { backgroundColor: calendar.colors.lineColor } }), u("span", { className: "truncate", children: calendar.name || calendar.id })] }, calendar.id))) }), document.body)] }));
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
const MergeCalendarDialog = ({ sourceName, targetName, onConfirm, onCancel, }) => {
|
|
233
|
-
const { t } = core.useLocale();
|
|
234
|
-
return (u("div", { className: "fixed inset-0 z-100 flex items-center justify-center bg-black/50", children: u("div", { className: "w-full max-w-md rounded-lg p-6 shadow-xl bg-background", children: [u("h2", { className: "text-lg font-semibold text-gray-900 dark:text-white", children: t('mergeConfirmTitle', { sourceName, targetName }) }), u("p", { className: "mt-3 text-sm text-gray-600 dark:text-gray-300", children: t('mergeConfirmMessage', { sourceName, targetName }) }), 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') })] })] }) }));
|
|
235
|
-
};
|
|
236
|
-
|
|
237
188
|
const DeleteCalendarDialog = ({ calendarId, calendarName, calendars, step, onStepChange, onConfirmDelete, onCancel, onMergeSelect, }) => {
|
|
238
189
|
const [showMergeDropdown, setShowMergeDropdown] = hooks.useState(false);
|
|
239
190
|
const { t } = core.useLocale();
|
|
240
|
-
return core.createPortal(u("div", { className:
|
|
191
|
+
return core.createPortal(u("div", { className: '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-background p-6 shadow-xl', 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 text-sm text-gray-600 dark:text-gray-300', children: t('deleteCalendarMessage', { calendarName }) }), 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-background shadow-lg dark:border-slate-700', children: calendars
|
|
241
192
|
.filter(c => c.id !== calendarId)
|
|
242
|
-
.map(calendar => (u("div", { className:
|
|
193
|
+
.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: () => {
|
|
243
194
|
onMergeSelect(calendar.id);
|
|
244
195
|
setShowMergeDropdown(false);
|
|
245
|
-
}, children: [u("div", { className:
|
|
196
|
+
}, children: [u("div", { className: 'mr-2 h-3 w-3 shrink-0 rounded-sm', style: {
|
|
246
197
|
backgroundColor: calendar.colors.lineColor,
|
|
247
|
-
} }), u("span", { className:
|
|
198
|
+
} }), u("span", { className: 'whitespace-nowrap', children: calendar.name || calendar.id })] }, calendar.id))) }))] }), u("div", { className: 'flex gap-3', children: [u("button", { type: 'button', onClick: onCancel, className: core.cancelButton, children: t('cancel') }), u("button", { type: 'button', onClick: () => onStepChange('confirm_delete'), className: 'rounded-md bg-destructive px-4 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90', children: t('delete') })] })] })] })) : (u(preact.Fragment, { children: [u("h2", { className: 'text-lg font-semibold text-gray-900 dark:text-white', children: t('confirmDeleteTitle', { calendarName }) }), u("p", { className: 'mt-3 text-sm text-gray-600 dark:text-gray-300', children: t('confirmDeleteMessage') }), u("div", { className: 'mt-6 flex justify-end gap-3', children: [u("button", { type: 'button', onClick: onCancel, className: 'rounded-md border border-border bg-background px-3 py-2 text-xs font-medium text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-slate-700', children: t('cancel') }), u("button", { type: 'button', onClick: onConfirmDelete, className: 'rounded-md bg-destructive px-3 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90', children: t('delete') })] })] })) }) }), document.body);
|
|
248
199
|
};
|
|
249
200
|
|
|
250
201
|
const NEW_CALENDAR_ID = 'new-calendar';
|
|
@@ -290,25 +241,76 @@ const ImportCalendarDialog = ({ calendars, filename, onConfirm, onCancel, }) =>
|
|
|
290
241
|
const rect = (_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
|
|
291
242
|
if (!rect)
|
|
292
243
|
return null;
|
|
293
|
-
return core.createPortal(u("div", { ref: dropdownRef, className: `fixed z-110 mt-1 max-h-60 overflow-y-auto rounded-md bg-white shadow-lg
|
|
244
|
+
return core.createPortal(u("div", { ref: dropdownRef, className: `fixed z-110 mt-1 max-h-60 origin-top overflow-y-auto rounded-md border border-gray-200 bg-white shadow-lg transition-all duration-200 dark:border-slate-700 dark:bg-slate-800 ${isOpen ? 'scale-100 opacity-100' : 'scale-95 opacity-0'}`, style: {
|
|
294
245
|
top: rect.bottom,
|
|
295
246
|
left: rect.left,
|
|
296
247
|
width: rect.width,
|
|
297
|
-
}, children: u("div", { className:
|
|
248
|
+
}, 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);
|
|
298
249
|
};
|
|
299
|
-
return (u("div", { className:
|
|
300
|
-
'This calendar contains new events. Please select a target calendar.' }), u("div", { className:
|
|
250
|
+
return (u("div", { className: '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-slate-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
|
+
'This calendar contains new events. Please select a target calendar.' }), u("div", { className: 'relative', children: [u("button", { ref: triggerRef, type: 'button', className: 'flex w-full items-center rounded-md border border-gray-300 px-3 py-2 shadow-sm transition-colors hover:bg-gray-50 dark:border-gray-600 dark:hover:bg-gray-800', onClick: () => setIsOpen(!isOpen), children: [!isNewSelected && selectedCalendar && (u("div", { className: 'mr-3 h-3 w-3 shrink-0 rounded-sm', style: { backgroundColor: selectedCalendar.colors.lineColor } })), u("span", { className: `flex-1 truncate text-left text-sm font-medium text-gray-700 dark:text-gray-200 ${isNewSelected ? 'pl-0' : ''}`, children: isNewSelected
|
|
301
252
|
? `${t('newCalendar')}: ${filename}`
|
|
302
|
-
: (selectedCalendar === null || selectedCalendar === void 0 ? void 0 : selectedCalendar.name) || (selectedCalendar === null || selectedCalendar === void 0 ? void 0 : selectedCalendar.id) }), u(core.ChevronsUpDown, { className:
|
|
253
|
+
: (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
|
+
};
|
|
255
|
+
|
|
256
|
+
const MergeCalendarDialog = ({ sourceName, targetName, onConfirm, onCancel, }) => {
|
|
257
|
+
const { t } = core.useLocale();
|
|
258
|
+
return (u("div", { className: '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-background p-6 shadow-xl', children: [u("h2", { className: 'text-lg font-semibold text-gray-900 dark:text-white', children: t('mergeConfirmTitle', { sourceName, targetName }) }), u("p", { className: 'mt-3 text-sm text-gray-600 dark:text-gray-300', children: t('mergeConfirmMessage', { sourceName, targetName }) }), 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
|
+
};
|
|
260
|
+
|
|
261
|
+
const stopPropagation = (e) => e.stopPropagation();
|
|
262
|
+
const MergeMenuItem = ({ calendars, currentCalendarId, onMergeSelect, }) => {
|
|
263
|
+
const { t } = core.useLocale();
|
|
264
|
+
const [isHovered, setIsHovered] = hooks.useState(false);
|
|
265
|
+
const itemRef = hooks.useRef(null);
|
|
266
|
+
const submenuRef = hooks.useRef(null);
|
|
267
|
+
const [position, setPosition] = hooks.useState({ x: 0, y: 0 });
|
|
268
|
+
const timeoutRef = hooks.useRef();
|
|
269
|
+
const handleMouseEnter = () => {
|
|
270
|
+
if (timeoutRef.current)
|
|
271
|
+
clearTimeout(timeoutRef.current);
|
|
272
|
+
if (itemRef.current) {
|
|
273
|
+
const rect = itemRef.current.getBoundingClientRect();
|
|
274
|
+
setPosition({ x: rect.right, y: rect.top });
|
|
275
|
+
}
|
|
276
|
+
setIsHovered(true);
|
|
277
|
+
};
|
|
278
|
+
const handleMouseLeave = () => {
|
|
279
|
+
timeoutRef.current = setTimeout(() => {
|
|
280
|
+
setIsHovered(false);
|
|
281
|
+
}, 100);
|
|
282
|
+
};
|
|
283
|
+
hooks.useEffect(() => {
|
|
284
|
+
const el = submenuRef.current;
|
|
285
|
+
if (el) {
|
|
286
|
+
el.addEventListener('mousedown', stopPropagation);
|
|
287
|
+
return () => {
|
|
288
|
+
el.removeEventListener('mousedown', stopPropagation);
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}, [isHovered]);
|
|
292
|
+
const availableCalendars = calendars.filter(c => c.id !== currentCalendarId);
|
|
293
|
+
if (availableCalendars.length === 0)
|
|
294
|
+
return null;
|
|
295
|
+
return (u(preact.Fragment, { children: [u("div", { ref: itemRef, className: 'relative flex cursor-default items-center justify-between rounded-sm px-3 py-0.5 text-[12px] transition-colors outline-none select-none hover:bg-primary hover:text-white dark:text-slate-200 dark:hover:bg-primary dark:hover:text-white', onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [u("span", { children: t('merge') }), u(core.ChevronRight, { className: 'h-4 w-4' })] }), isHovered &&
|
|
296
|
+
core.createPortal(u("div", { ref: submenuRef, "data-submenu-content": 'true', className: 'animate-in fade-in-0 zoom-in-95 fixed z-60 min-w-48 overflow-hidden rounded-md border border-slate-200 bg-white p-1 shadow-md duration-100 dark:border-slate-800 dark:bg-slate-950', style: { top: position.y, left: position.x }, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseDown: e => e.stopPropagation(), children: availableCalendars.map(calendar => (u("div", { className: 'flex cursor-pointer items-center rounded-sm px-3 py-1 text-[12px] text-slate-900 transition-colors hover:bg-primary hover:text-white dark:text-slate-50 dark:hover:bg-primary dark:hover:text-white', onClick: e => {
|
|
297
|
+
e.stopPropagation();
|
|
298
|
+
onMergeSelect(calendar.id);
|
|
299
|
+
}, children: [u("div", { className: 'mr-2 h-3 w-3 shrink-0 rounded-sm', style: { backgroundColor: calendar.colors.lineColor } }), u("span", { className: 'truncate', children: calendar.name || calendar.id })] }, calendar.id))) }), document.body)] }));
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
const SidebarHeader = ({ isCollapsed, onCollapseToggle, }) => {
|
|
303
|
+
const { t } = core.useLocale();
|
|
304
|
+
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') }) }))] }));
|
|
303
305
|
};
|
|
304
306
|
|
|
305
307
|
const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, colorPickerMode = 'default', }) => {
|
|
306
308
|
var _a, _b, _c, _d;
|
|
307
309
|
const { t } = core.useLocale();
|
|
308
310
|
const [localEditingCalendarId, setLocalEditingCalendarId] = hooks.useState(null);
|
|
309
|
-
const editingCalendarId = propEditingCalendarId
|
|
310
|
-
?
|
|
311
|
-
:
|
|
311
|
+
const editingCalendarId = propEditingCalendarId === undefined
|
|
312
|
+
? localEditingCalendarId
|
|
313
|
+
: propEditingCalendarId;
|
|
312
314
|
const setEditingCalendarId = propSetEditingCalendarId || setLocalEditingCalendarId;
|
|
313
315
|
// File input ref for import
|
|
314
316
|
const fileInputRef = hooks.useRef(null);
|
|
@@ -445,7 +447,7 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
445
447
|
}, [handleCloseSidebarContextMenu]);
|
|
446
448
|
const handleFileChange = hooks.useCallback((e) => __awaiter(void 0, void 0, void 0, function* () {
|
|
447
449
|
var _a;
|
|
448
|
-
const file = (_a = e.
|
|
450
|
+
const file = (_a = e.currentTarget.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
449
451
|
if (!file)
|
|
450
452
|
return;
|
|
451
453
|
const result = yield core.importICSFile(file);
|
|
@@ -524,28 +526,48 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
524
526
|
const readOnlyConfig = app.getReadOnlyConfig();
|
|
525
527
|
const isEditable = !app.state.readOnly;
|
|
526
528
|
const isDraggable = readOnlyConfig.draggable !== false;
|
|
527
|
-
return (u("div", { className: core.sidebarContainer, onContextMenu: isEditable ? handleSidebarContextMenu : undefined, children: [u(SidebarHeader, { isCollapsed: isCollapsed, onCollapseToggle: () => setCollapsed(!isCollapsed) }),
|
|
528
|
-
|
|
529
|
-
|
|
529
|
+
return (u("div", { className: core.sidebarContainer, onContextMenu: isEditable ? handleSidebarContextMenu : undefined, children: [u(SidebarHeader, { isCollapsed: isCollapsed, onCollapseToggle: () => setCollapsed(!isCollapsed) }), isCollapsed ? (u(CalendarList, { calendars: calendars, onToggleVisibility: toggleCalendarVisibility, onReorder: isDraggable
|
|
530
|
+
? app.reorderCalendars
|
|
531
|
+
: () => {
|
|
532
|
+
/* noop */
|
|
533
|
+
}, onRename: isEditable
|
|
530
534
|
? (id, newName) => app.updateCalendar(id, { name: newName })
|
|
531
|
-
: () => {
|
|
535
|
+
: () => {
|
|
536
|
+
/* noop */
|
|
537
|
+
}, onContextMenu: isEditable
|
|
538
|
+
? handleContextMenu
|
|
539
|
+
: () => {
|
|
540
|
+
/* noop */
|
|
541
|
+
}, editingId: editingCalendarId, setEditingId: setEditingCalendarId, activeContextMenuCalendarId: contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.calendarId, isDraggable: isDraggable, isEditable: isEditable })) : (u(preact.Fragment, { children: [u(CalendarList, { calendars: calendars, onToggleVisibility: toggleCalendarVisibility, onReorder: isDraggable
|
|
542
|
+
? app.reorderCalendars
|
|
543
|
+
: () => {
|
|
544
|
+
/* noop */
|
|
545
|
+
}, onRename: isEditable
|
|
546
|
+
? (id, newName) => app.updateCalendar(id, { name: newName })
|
|
547
|
+
: () => {
|
|
548
|
+
/* noop */
|
|
549
|
+
}, onContextMenu: isEditable
|
|
550
|
+
? handleContextMenu
|
|
551
|
+
: () => {
|
|
552
|
+
/* noop */
|
|
553
|
+
}, 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: {
|
|
532
554
|
calendar: calendars.find(c => c.id === contextMenu.calendarId),
|
|
533
555
|
onClose: handleCloseContextMenu,
|
|
534
556
|
}, 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: (_d = calendars.find(c => c.id === contextMenu.calendarId)) === null || _d === void 0 ? void 0 : _d.colors.lineColor, onSelect: handleColorSelect, onCustomColor: handleCustomColor })] })) }) })), sidebarContextMenu &&
|
|
535
|
-
core.createPortal(u(core.ContextMenu, { x: sidebarContextMenu.x, y: sidebarContextMenu.y, onClose: handleCloseSidebarContextMenu, className:
|
|
557
|
+
core.createPortal(u(core.ContextMenu, { x: sidebarContextMenu.x, y: sidebarContextMenu.y, onClose: handleCloseSidebarContextMenu, className: 'w-max p-2', children: [u(core.ContextMenuItem, { onClick: () => {
|
|
536
558
|
onCreateCalendar === null || onCreateCalendar === void 0 ? void 0 : onCreateCalendar();
|
|
537
559
|
handleCloseSidebarContextMenu();
|
|
538
560
|
}, children: t('newCalendar') || 'New Calendar' }), u(core.ContextMenuItem, { onClick: handleImportClick, children: t('importCalendar') || 'Import Calendar' }), u(core.ContextMenuItem, { onClick: () => {
|
|
539
561
|
app.triggerRender();
|
|
540
562
|
handleCloseSidebarContextMenu();
|
|
541
|
-
}, children: t('refreshAll') || 'Refresh All' })] }), document.body), u("input", { ref: fileInputRef, type:
|
|
563
|
+
}, children: t('refreshAll') || 'Refresh All' })] }), document.body), u("input", { ref: fileInputRef, type: 'file', accept: '.ics', style: { display: 'none' }, onChange: handleFileChange }), importState &&
|
|
542
564
|
core.createPortal(u(ImportCalendarDialog, { calendars: calendars, filename: importState.filename, onConfirm: handleImportConfirm, onCancel: () => setImportState(null) }), document.body), mergeState &&
|
|
543
565
|
core.createPortal(u(MergeCalendarDialog, { sourceName: sourceCalendarName, targetName: targetCalendarName, onConfirm: handleMergeConfirm, onCancel: () => setMergeState(null) }), document.body), deleteState &&
|
|
544
566
|
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 &&
|
|
545
|
-
core.createPortal(u("div", { className:
|
|
567
|
+
core.createPortal(u("div", { className: 'fixed inset-0 z-50', onMouseDown: () => {
|
|
546
568
|
app.updateCalendar(customColorPicker.calendarId, {});
|
|
547
569
|
setCustomColorPicker(null);
|
|
548
|
-
}, children: u("div", { className:
|
|
570
|
+
}, children: u("div", { className: 'absolute flex items-center justify-center', style: {
|
|
549
571
|
top: customColorPicker.y,
|
|
550
572
|
left: customColorPicker.x,
|
|
551
573
|
transform: 'translate(280%, -50%)',
|
|
@@ -558,8 +580,8 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
558
580
|
}, onCollapse: () => {
|
|
559
581
|
app.updateCalendar(customColorPicker.calendarId, {});
|
|
560
582
|
setCustomColorPicker(null);
|
|
561
|
-
} })) : (u(core.ContentSlot, { generatorName:
|
|
562
|
-
variant: 'sketch', //
|
|
583
|
+
} })) : (u(core.ContentSlot, { generatorName: 'colorPicker', generatorArgs: {
|
|
584
|
+
variant: 'sketch', // Pending: change name
|
|
563
585
|
color: customColorPicker.currentColor,
|
|
564
586
|
onChange: (color) => {
|
|
565
587
|
setCustomColorPicker(prev => prev ? Object.assign(Object.assign({}, prev), { currentColor: color.hex }) : null);
|
|
@@ -615,11 +637,9 @@ function createSidebarPlugin(config = {}) {
|
|
|
615
637
|
const refreshSidebar = hooks.useCallback(() => {
|
|
616
638
|
setSidebarVersion(prev => prev + 1);
|
|
617
639
|
}, []);
|
|
618
|
-
hooks.useEffect(() => {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
});
|
|
622
|
-
}, [app, refreshSidebar]);
|
|
640
|
+
hooks.useEffect(() => app.subscribe(() => {
|
|
641
|
+
refreshSidebar();
|
|
642
|
+
}), [app, refreshSidebar]);
|
|
623
643
|
const calendars = hooks.useMemo(() => app.getCalendars(), [app, sidebarVersion]);
|
|
624
644
|
const handleToggleCalendarVisibility = hooks.useCallback((calendarId, visible) => {
|
|
625
645
|
app.setCalendarVisibility(calendarId, visible);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { JSX } from 'preact';
|
|
1
2
|
import type { CalendarSidebarRenderProps } from './plugin';
|
|
2
|
-
declare const DefaultCalendarSidebar: ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, colorPickerMode, }: CalendarSidebarRenderProps) =>
|
|
3
|
+
declare const DefaultCalendarSidebar: ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, colorPickerMode, }: CalendarSidebarRenderProps) => JSX.Element;
|
|
3
4
|
export default DefaultCalendarSidebar;
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { CalendarType } from '@dayflow/core';
|
|
2
|
+
import { JSX } from 'preact';
|
|
2
3
|
interface CalendarListProps {
|
|
3
4
|
calendars: CalendarType[];
|
|
4
5
|
onToggleVisibility: (id: string, visible: boolean) => void;
|
|
5
6
|
onReorder: (fromIndex: number, toIndex: number) => void;
|
|
6
7
|
onRename: (id: string, newName: string) => void;
|
|
7
|
-
onContextMenu: (e:
|
|
8
|
+
onContextMenu: (e: JSX.TargetedMouseEvent<HTMLElement>, id: string) => void;
|
|
8
9
|
editingId: string | null;
|
|
9
10
|
setEditingId: (id: string | null) => void;
|
|
10
11
|
activeContextMenuCalendarId?: string | null;
|
|
11
12
|
isDraggable?: boolean;
|
|
12
13
|
isEditable?: boolean;
|
|
13
14
|
}
|
|
14
|
-
export declare const CalendarList: ({ calendars, onToggleVisibility, onReorder, onRename, onContextMenu, editingId, setEditingId, activeContextMenuCalendarId, isDraggable, isEditable, }: CalendarListProps) =>
|
|
15
|
+
export declare const CalendarList: ({ calendars, onToggleVisibility, onReorder, onRename, onContextMenu, editingId, setEditingId, activeContextMenuCalendarId, isDraggable, isEditable, }: CalendarListProps) => JSX.Element;
|
|
15
16
|
export {};
|
package/package.json
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dayflow/plugin-sidebar",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"type": "module",
|
|
3
|
+
"version": "1.1.0",
|
|
5
4
|
"description": "Sidebar plugin for DayFlow calendar",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"calendar",
|
|
7
|
+
"dayflow",
|
|
8
|
+
"plugin",
|
|
9
|
+
"sidebar"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"author": "Jayce Li",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"type": "module",
|
|
6
19
|
"main": "dist/index.js",
|
|
7
20
|
"module": "dist/index.esm.js",
|
|
8
21
|
"types": "dist/index.d.ts",
|
|
@@ -13,36 +26,25 @@
|
|
|
13
26
|
"require": "./dist/index.js"
|
|
14
27
|
}
|
|
15
28
|
},
|
|
16
|
-
"files": [
|
|
17
|
-
"dist",
|
|
18
|
-
"README.md",
|
|
19
|
-
"LICENSE"
|
|
20
|
-
],
|
|
21
|
-
"keywords": [
|
|
22
|
-
"calendar",
|
|
23
|
-
"sidebar",
|
|
24
|
-
"dayflow",
|
|
25
|
-
"plugin"
|
|
26
|
-
],
|
|
27
|
-
"author": "Jayce Li",
|
|
28
|
-
"license": "MIT",
|
|
29
|
-
"peerDependencies": {
|
|
30
|
-
"@dayflow/core": "3.1.1"
|
|
31
|
-
},
|
|
32
29
|
"devDependencies": {
|
|
33
30
|
"@dayflow/blossom-color-picker": "^2.0.1",
|
|
34
31
|
"@rollup/plugin-commonjs": "^28.0.2",
|
|
35
32
|
"@rollup/plugin-node-resolve": "^16.0.0",
|
|
36
33
|
"@rollup/plugin-typescript": "^12.1.2",
|
|
34
|
+
"preact": "^10.28.3",
|
|
35
|
+
"rimraf": "^6.1.2",
|
|
37
36
|
"rollup": "^4.29.1",
|
|
38
37
|
"rollup-plugin-dts": "^6.3.0",
|
|
39
|
-
"preact": "^10.25.4",
|
|
40
38
|
"temporal-polyfill": "^0.3.0",
|
|
41
|
-
"typescript": "^5.
|
|
42
|
-
"@dayflow/core": "3.
|
|
39
|
+
"typescript": "^5.9.3",
|
|
40
|
+
"@dayflow/core": "3.2.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"@dayflow/core": "3.2.0"
|
|
43
44
|
},
|
|
44
45
|
"scripts": {
|
|
45
|
-
"build": "tsc -p tsconfig.build.json && rollup -c",
|
|
46
|
+
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && rollup -c",
|
|
47
|
+
"clean": "rimraf dist node_modules",
|
|
46
48
|
"typecheck": "tsc --noEmit"
|
|
47
49
|
}
|
|
48
50
|
}
|