@dayflow/plugin-sidebar 1.1.3 → 1.2.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/dist/index.d.ts +4 -1
- package/dist/index.esm.js +17 -10
- package/dist/index.js +16 -9
- package/dist/types/DefaultCalendarSidebar.d.ts +1 -1
- package/dist/types/plugin.d.ts +4 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { ICalendarApp, CalendarType, TNode, CreateCalendarDialogProps, CalendarPlugin } from '@dayflow/core';
|
|
1
|
+
import { ICalendarApp, CalendarType, TNode, SidebarHeaderSlotArgs, CreateCalendarDialogProps, CalendarPlugin } from '@dayflow/core';
|
|
2
|
+
export { SidebarHeaderSlotArgs } from '@dayflow/core';
|
|
2
3
|
|
|
3
4
|
interface CalendarSidebarRenderProps {
|
|
4
5
|
app: ICalendarApp;
|
|
@@ -8,6 +9,7 @@ interface CalendarSidebarRenderProps {
|
|
|
8
9
|
isCollapsed: boolean;
|
|
9
10
|
setCollapsed: (collapsed: boolean) => void;
|
|
10
11
|
renderCalendarContextMenu?: (calendar: CalendarType, onClose: () => void) => TNode;
|
|
12
|
+
renderSidebarHeader?: (args: SidebarHeaderSlotArgs) => TNode;
|
|
11
13
|
createCalendarMode?: 'inline' | 'modal';
|
|
12
14
|
renderCreateCalendarDialog?: (props: CreateCalendarDialogProps) => TNode;
|
|
13
15
|
editingCalendarId?: string | null;
|
|
@@ -21,6 +23,7 @@ interface SidebarPluginConfig {
|
|
|
21
23
|
createCalendarMode?: 'inline' | 'modal';
|
|
22
24
|
render?: (props: CalendarSidebarRenderProps) => TNode;
|
|
23
25
|
renderCalendarContextMenu?: (calendar: CalendarType, onClose: () => void) => TNode;
|
|
26
|
+
renderSidebarHeader?: (args: SidebarHeaderSlotArgs) => TNode;
|
|
24
27
|
renderCreateCalendarDialog?: (props: CreateCalendarDialogProps) => TNode;
|
|
25
28
|
[key: string]: unknown;
|
|
26
29
|
}
|
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, MiniCalendar, ContextMenu,
|
|
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';
|
|
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';
|
|
@@ -177,16 +177,16 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
|
|
|
177
177
|
const isDropTarget = (dropTarget === null || dropTarget === void 0 ? void 0 : dropTarget.id) === calendar.id;
|
|
178
178
|
const isActive = activeContextMenuCalendarId === calendar.id ||
|
|
179
179
|
editingId === calendar.id;
|
|
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: {
|
|
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-[var(--df-color-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: 'df-calendar-checkbox shrink-0 cursor-pointer', style: {
|
|
181
181
|
'--checkbox-color': calendarColor,
|
|
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));
|
|
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-[var(--df-color-primary)]' }))] }, calendar.id));
|
|
183
183
|
}) }) }));
|
|
184
184
|
};
|
|
185
185
|
|
|
186
186
|
const DeleteCalendarDialog = ({ calendarId, calendarName, calendars, step, onStepChange, onConfirmDelete, onCancel, onMergeSelect, }) => {
|
|
187
187
|
const [showMergeDropdown, setShowMergeDropdown] = useState(false);
|
|
188
188
|
const { t } = useLocale();
|
|
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
|
|
189
|
+
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-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
|
|
190
190
|
.filter(c => c.id !== calendarId)
|
|
191
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: () => {
|
|
192
192
|
onMergeSelect(calendar.id);
|
|
@@ -245,7 +245,7 @@ const ImportCalendarDialog = ({ calendars, filename, onConfirm, onCancel, }) =>
|
|
|
245
245
|
width: rect.width,
|
|
246
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);
|
|
247
247
|
};
|
|
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-
|
|
248
|
+
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') ||
|
|
249
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
|
|
250
250
|
? `${t('newCalendar')}: ${filename}`
|
|
251
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' })] })] }) }));
|
|
@@ -290,8 +290,8 @@ const MergeMenuItem = ({ calendars, currentCalendarId, onMergeSelect, }) => {
|
|
|
290
290
|
const availableCalendars = calendars.filter(c => c.id !== currentCalendarId);
|
|
291
291
|
if (availableCalendars.length === 0)
|
|
292
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-
|
|
294
|
-
createPortal(u("div", { ref: submenuRef, "data-submenu-content": 'true', className: 'animate-in fade-in-
|
|
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] text-[var(--df-color-foreground)] transition-colors outline-none select-none hover:bg-[var(--df-color-primary)] hover:text-[var(--df-color-primary-foreground)]', 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: 'df-portal df-animate-in df-fade-in df-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-[var(--df-color-foreground)] transition-colors hover:bg-[var(--df-color-primary)] hover:text-[var(--df-color-primary-foreground)]', onClick: e => {
|
|
295
295
|
e.stopPropagation();
|
|
296
296
|
onMergeSelect(calendar.id);
|
|
297
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)] }));
|
|
@@ -302,7 +302,7 @@ const SidebarHeader = ({ isCollapsed, onCollapseToggle, }) => {
|
|
|
302
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') }) }))] }));
|
|
303
303
|
};
|
|
304
304
|
|
|
305
|
-
const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, }) => {
|
|
305
|
+
const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, renderSidebarHeader, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, }) => {
|
|
306
306
|
var _a, _b, _c, _d;
|
|
307
307
|
const { t } = useLocale();
|
|
308
308
|
// Detect if custom color picker slot is provided
|
|
@@ -526,7 +526,13 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
526
526
|
const readOnlyConfig = app.getReadOnlyConfig();
|
|
527
527
|
const isEditable = !app.state.readOnly;
|
|
528
528
|
const isDraggable = readOnlyConfig.draggable !== false;
|
|
529
|
-
return (u("div", { className: sidebarContainer, onContextMenu: isEditable ? handleSidebarContextMenu : undefined, children: [u(
|
|
529
|
+
return (u("div", { className: sidebarContainer, onContextMenu: isEditable ? handleSidebarContextMenu : undefined, children: [u(ContentSlot, { generatorName: 'sidebarHeader', generatorArgs: {
|
|
530
|
+
isCollapsed,
|
|
531
|
+
onCollapseToggle: () => setCollapsed(!isCollapsed),
|
|
532
|
+
}, defaultContent: renderSidebarHeader ? (renderSidebarHeader({
|
|
533
|
+
isCollapsed,
|
|
534
|
+
onCollapseToggle: () => setCollapsed(!isCollapsed),
|
|
535
|
+
})) : (u(SidebarHeader, { isCollapsed: isCollapsed, onCollapseToggle: () => setCollapsed(!isCollapsed) })) }), isCollapsed ? (u(CalendarList, { calendars: calendars, onToggleVisibility: toggleCalendarVisibility, onReorder: isDraggable
|
|
530
536
|
? app.reorderCalendars
|
|
531
537
|
: () => {
|
|
532
538
|
/* noop */
|
|
@@ -589,7 +595,7 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
589
595
|
darkColors,
|
|
590
596
|
});
|
|
591
597
|
},
|
|
592
|
-
}, defaultContent: u("div", { className: 'rounded-lg border border-gray-200 bg-white p-3 shadow-xl dark:border-gray-700 dark:bg-
|
|
598
|
+
}, defaultContent: u("div", { className: 'rounded-lg border border-gray-200 bg-white p-3 shadow-xl dark:border-gray-700 dark:bg-gray-900', children: u(DefaultColorPicker, { color: customColorPicker.currentColor, onChange: (color, isPending) => {
|
|
593
599
|
setCustomColorPicker(prev => prev ? Object.assign(Object.assign({}, prev), { currentColor: color.hex }) : null);
|
|
594
600
|
const { colors, darkColors } = getCalendarColorsForHex(color.hex);
|
|
595
601
|
app.updateCalendar(customColorPicker.calendarId, {
|
|
@@ -678,6 +684,7 @@ function createSidebarPlugin(config = {}) {
|
|
|
678
684
|
isCollapsed,
|
|
679
685
|
setCollapsed: setIsCollapsed,
|
|
680
686
|
renderCalendarContextMenu: config.renderCalendarContextMenu,
|
|
687
|
+
renderSidebarHeader: config.renderSidebarHeader,
|
|
681
688
|
createCalendarMode: config.createCalendarMode,
|
|
682
689
|
renderCreateCalendarDialog: config.renderCreateCalendarDialog,
|
|
683
690
|
editingCalendarId,
|
package/dist/index.js
CHANGED
|
@@ -179,16 +179,16 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
|
|
|
179
179
|
const isDropTarget = (dropTarget === null || dropTarget === void 0 ? void 0 : dropTarget.id) === calendar.id;
|
|
180
180
|
const isActive = activeContextMenuCalendarId === calendar.id ||
|
|
181
181
|
editingId === calendar.id;
|
|
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: {
|
|
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-[var(--df-color-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: 'df-calendar-checkbox shrink-0 cursor-pointer', style: {
|
|
183
183
|
'--checkbox-color': calendarColor,
|
|
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));
|
|
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-[var(--df-color-primary)]' }))] }, calendar.id));
|
|
185
185
|
}) }) }));
|
|
186
186
|
};
|
|
187
187
|
|
|
188
188
|
const DeleteCalendarDialog = ({ calendarId, calendarName, calendars, step, onStepChange, onConfirmDelete, onCancel, onMergeSelect, }) => {
|
|
189
189
|
const [showMergeDropdown, setShowMergeDropdown] = hooks.useState(false);
|
|
190
190
|
const { t } = core.useLocale();
|
|
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
|
|
191
|
+
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-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
|
|
192
192
|
.filter(c => c.id !== calendarId)
|
|
193
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: () => {
|
|
194
194
|
onMergeSelect(calendar.id);
|
|
@@ -247,7 +247,7 @@ const ImportCalendarDialog = ({ calendars, filename, onConfirm, onCancel, }) =>
|
|
|
247
247
|
width: rect.width,
|
|
248
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);
|
|
249
249
|
};
|
|
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-
|
|
250
|
+
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
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
|
|
252
252
|
? `${t('newCalendar')}: ${filename}`
|
|
253
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' })] })] }) }));
|
|
@@ -292,8 +292,8 @@ const MergeMenuItem = ({ calendars, currentCalendarId, onMergeSelect, }) => {
|
|
|
292
292
|
const availableCalendars = calendars.filter(c => c.id !== currentCalendarId);
|
|
293
293
|
if (availableCalendars.length === 0)
|
|
294
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-
|
|
296
|
-
core.createPortal(u("div", { ref: submenuRef, "data-submenu-content": 'true', className: 'animate-in fade-in-
|
|
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] text-[var(--df-color-foreground)] transition-colors outline-none select-none hover:bg-[var(--df-color-primary)] hover:text-[var(--df-color-primary-foreground)]', 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: 'df-portal df-animate-in df-fade-in df-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-[var(--df-color-foreground)] transition-colors hover:bg-[var(--df-color-primary)] hover:text-[var(--df-color-primary-foreground)]', onClick: e => {
|
|
297
297
|
e.stopPropagation();
|
|
298
298
|
onMergeSelect(calendar.id);
|
|
299
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)] }));
|
|
@@ -304,7 +304,7 @@ const SidebarHeader = ({ isCollapsed, onCollapseToggle, }) => {
|
|
|
304
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') }) }))] }));
|
|
305
305
|
};
|
|
306
306
|
|
|
307
|
-
const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, }) => {
|
|
307
|
+
const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, renderSidebarHeader, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, }) => {
|
|
308
308
|
var _a, _b, _c, _d;
|
|
309
309
|
const { t } = core.useLocale();
|
|
310
310
|
// Detect if custom color picker slot is provided
|
|
@@ -528,7 +528,13 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
528
528
|
const readOnlyConfig = app.getReadOnlyConfig();
|
|
529
529
|
const isEditable = !app.state.readOnly;
|
|
530
530
|
const isDraggable = readOnlyConfig.draggable !== false;
|
|
531
|
-
return (u("div", { className: core.sidebarContainer, onContextMenu: isEditable ? handleSidebarContextMenu : undefined, children: [u(
|
|
531
|
+
return (u("div", { className: core.sidebarContainer, onContextMenu: isEditable ? handleSidebarContextMenu : undefined, children: [u(core.ContentSlot, { generatorName: 'sidebarHeader', generatorArgs: {
|
|
532
|
+
isCollapsed,
|
|
533
|
+
onCollapseToggle: () => setCollapsed(!isCollapsed),
|
|
534
|
+
}, defaultContent: renderSidebarHeader ? (renderSidebarHeader({
|
|
535
|
+
isCollapsed,
|
|
536
|
+
onCollapseToggle: () => setCollapsed(!isCollapsed),
|
|
537
|
+
})) : (u(SidebarHeader, { isCollapsed: isCollapsed, onCollapseToggle: () => setCollapsed(!isCollapsed) })) }), isCollapsed ? (u(CalendarList, { calendars: calendars, onToggleVisibility: toggleCalendarVisibility, onReorder: isDraggable
|
|
532
538
|
? app.reorderCalendars
|
|
533
539
|
: () => {
|
|
534
540
|
/* noop */
|
|
@@ -591,7 +597,7 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
|
|
|
591
597
|
darkColors,
|
|
592
598
|
});
|
|
593
599
|
},
|
|
594
|
-
}, defaultContent: u("div", { className: 'rounded-lg border border-gray-200 bg-white p-3 shadow-xl dark:border-gray-700 dark:bg-
|
|
600
|
+
}, defaultContent: u("div", { className: 'rounded-lg border border-gray-200 bg-white p-3 shadow-xl dark:border-gray-700 dark:bg-gray-900', children: u(core.DefaultColorPicker, { color: customColorPicker.currentColor, onChange: (color, isPending) => {
|
|
595
601
|
setCustomColorPicker(prev => prev ? Object.assign(Object.assign({}, prev), { currentColor: color.hex }) : null);
|
|
596
602
|
const { colors, darkColors } = core.getCalendarColorsForHex(color.hex);
|
|
597
603
|
app.updateCalendar(customColorPicker.calendarId, {
|
|
@@ -680,6 +686,7 @@ function createSidebarPlugin(config = {}) {
|
|
|
680
686
|
isCollapsed,
|
|
681
687
|
setCollapsed: setIsCollapsed,
|
|
682
688
|
renderCalendarContextMenu: config.renderCalendarContextMenu,
|
|
689
|
+
renderSidebarHeader: config.renderSidebarHeader,
|
|
683
690
|
createCalendarMode: config.createCalendarMode,
|
|
684
691
|
renderCreateCalendarDialog: config.renderCreateCalendarDialog,
|
|
685
692
|
editingCalendarId,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { JSX } from 'preact';
|
|
2
2
|
import type { CalendarSidebarRenderProps } from './plugin';
|
|
3
|
-
declare const DefaultCalendarSidebar: ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, }: CalendarSidebarRenderProps) => JSX.Element;
|
|
3
|
+
declare const DefaultCalendarSidebar: ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, renderSidebarHeader, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, }: CalendarSidebarRenderProps) => JSX.Element;
|
|
4
4
|
export default DefaultCalendarSidebar;
|
package/dist/types/plugin.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { CalendarPlugin, ICalendarApp, CalendarType, TNode, CreateCalendarDialogProps } from '@dayflow/core';
|
|
1
|
+
import { CalendarPlugin, ICalendarApp, CalendarType, TNode, CreateCalendarDialogProps, SidebarHeaderSlotArgs } from '@dayflow/core';
|
|
2
|
+
export type { SidebarHeaderSlotArgs };
|
|
2
3
|
export interface CalendarSidebarRenderProps {
|
|
3
4
|
app: ICalendarApp;
|
|
4
5
|
calendars: CalendarType[];
|
|
@@ -7,6 +8,7 @@ export interface CalendarSidebarRenderProps {
|
|
|
7
8
|
isCollapsed: boolean;
|
|
8
9
|
setCollapsed: (collapsed: boolean) => void;
|
|
9
10
|
renderCalendarContextMenu?: (calendar: CalendarType, onClose: () => void) => TNode;
|
|
11
|
+
renderSidebarHeader?: (args: SidebarHeaderSlotArgs) => TNode;
|
|
10
12
|
createCalendarMode?: 'inline' | 'modal';
|
|
11
13
|
renderCreateCalendarDialog?: (props: CreateCalendarDialogProps) => TNode;
|
|
12
14
|
editingCalendarId?: string | null;
|
|
@@ -20,6 +22,7 @@ export interface SidebarPluginConfig {
|
|
|
20
22
|
createCalendarMode?: 'inline' | 'modal';
|
|
21
23
|
render?: (props: CalendarSidebarRenderProps) => TNode;
|
|
22
24
|
renderCalendarContextMenu?: (calendar: CalendarType, onClose: () => void) => TNode;
|
|
25
|
+
renderSidebarHeader?: (args: SidebarHeaderSlotArgs) => TNode;
|
|
23
26
|
renderCreateCalendarDialog?: (props: CreateCalendarDialogProps) => TNode;
|
|
24
27
|
[key: string]: unknown;
|
|
25
28
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dayflow/plugin-sidebar",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
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.
|
|
40
|
+
"@dayflow/core": "3.3.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@dayflow/core": "3.
|
|
43
|
+
"@dayflow/core": "3.3.0"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && rollup -c",
|