@anymux/ui-kit 0.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/dist/ExplorerLayout-CSIJd7N4.js +105 -0
- package/dist/ExplorerLayout-CSIJd7N4.js.map +1 -0
- package/dist/FileBrowserContext-B6jixa2j.js +11 -0
- package/dist/FileBrowserContext-B6jixa2j.js.map +1 -0
- package/dist/calendar-DSlrbHoj.js +761 -0
- package/dist/calendar-DSlrbHoj.js.map +1 -0
- package/dist/calendar.d.ts +3 -0
- package/dist/calendar.js +3 -0
- package/dist/contacts-DQXTZzHc.js +539 -0
- package/dist/contacts-DQXTZzHc.js.map +1 -0
- package/dist/contacts.d.ts +3 -0
- package/dist/contacts.js +3 -0
- package/dist/file-browser-m5atC3kF.js +6755 -0
- package/dist/file-browser-m5atC3kF.js.map +1 -0
- package/dist/file-browser.d.ts +11 -0
- package/dist/file-browser.js +9 -0
- package/dist/git-B55e6LL-.js +561 -0
- package/dist/git-B55e6LL-.js.map +1 -0
- package/dist/git.d.ts +2 -0
- package/dist/git.js +3 -0
- package/dist/iconMap-V4B8P-Uh.js +206 -0
- package/dist/iconMap-V4B8P-Uh.js.map +1 -0
- package/dist/icons-CIsIOZXR.js +0 -0
- package/dist/icons.d.ts +2 -0
- package/dist/icons.js +4 -0
- package/dist/index-BNmNIWBL.d.ts +71 -0
- package/dist/index-BNmNIWBL.d.ts.map +1 -0
- package/dist/index-Bryv_GCG.d.ts +1481 -0
- package/dist/index-Bryv_GCG.d.ts.map +1 -0
- package/dist/index-CuQIjSXs.d.ts +134 -0
- package/dist/index-CuQIjSXs.d.ts.map +1 -0
- package/dist/index-DSu19mq0.d.ts +153 -0
- package/dist/index-DSu19mq0.d.ts.map +1 -0
- package/dist/index-DmsyeHFr.d.ts +149 -0
- package/dist/index-DmsyeHFr.d.ts.map +1 -0
- package/dist/index-DxnJ8FYM.d.ts +17 -0
- package/dist/index-DxnJ8FYM.d.ts.map +1 -0
- package/dist/index-DzfY1Tok.d.ts +32 -0
- package/dist/index-DzfY1Tok.d.ts.map +1 -0
- package/dist/index-Ml_SgiKa.d.ts +1847 -0
- package/dist/index-Ml_SgiKa.d.ts.map +1 -0
- package/dist/index-kHr9udZD.d.ts +1025 -0
- package/dist/index-kHr9udZD.d.ts.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +15 -0
- package/dist/layout-Ca_4r8ka.js +89 -0
- package/dist/layout-Ca_4r8ka.js.map +1 -0
- package/dist/layout.d.ts +2 -0
- package/dist/layout.js +5 -0
- package/dist/list-CxfT6hix.js +6831 -0
- package/dist/list-CxfT6hix.js.map +1 -0
- package/dist/list.d.ts +2 -0
- package/dist/list.js +5 -0
- package/dist/media-DZ292aKK.js +557 -0
- package/dist/media-DZ292aKK.js.map +1 -0
- package/dist/media.d.ts +3 -0
- package/dist/media.js +3 -0
- package/dist/tree-Dd9Z0Aso.js +3351 -0
- package/dist/tree-Dd9Z0Aso.js.map +1 -0
- package/dist/tree.d.ts +2 -0
- package/dist/tree.js +6 -0
- package/dist/types-common-CB3kRek8.d.ts +26 -0
- package/dist/types-common-CB3kRek8.d.ts.map +1 -0
- package/dist/utils-B4fdKKsy.js +3 -0
- package/package.json +109 -0
- package/src/calendar/AgendaView.tsx +37 -0
- package/src/calendar/CalendarBrowser.tsx +90 -0
- package/src/calendar/CalendarModel.ts +142 -0
- package/src/calendar/CalendarSidebar.tsx +81 -0
- package/src/calendar/DayView.tsx +76 -0
- package/src/calendar/EventCard.tsx +51 -0
- package/src/calendar/MockCalendarProvider.ts +98 -0
- package/src/calendar/MonthView.tsx +77 -0
- package/src/calendar/WeekView.tsx +129 -0
- package/src/calendar/index.ts +18 -0
- package/src/calendar/types.ts +25 -0
- package/src/contacts/ContactAvatar.tsx +35 -0
- package/src/contacts/ContactBrowser.tsx +56 -0
- package/src/contacts/ContactCard.tsx +37 -0
- package/src/contacts/ContactDetail.tsx +63 -0
- package/src/contacts/ContactGroupSidebar.tsx +40 -0
- package/src/contacts/ContactList.tsx +32 -0
- package/src/contacts/ContactListModel.ts +120 -0
- package/src/contacts/MockContactProvider.ts +77 -0
- package/src/contacts/index.ts +17 -0
- package/src/contacts/types.ts +26 -0
- package/src/demos/CalendarBrowserDemo.tsx +15 -0
- package/src/demos/ContactBrowserDemo.tsx +15 -0
- package/src/demos/MediaBrowserDemo.tsx +15 -0
- package/src/file-browser/adapters/DocumentViewerAdapter.ts +371 -0
- package/src/file-browser/adapters/FileSystemBridge.ts +168 -0
- package/src/file-browser/adapters/GitBrowserAdapter.ts +546 -0
- package/src/file-browser/adapters/README.md +504 -0
- package/src/file-browser/adapters/index.ts +27 -0
- package/src/file-browser/adapters/types.ts +70 -0
- package/src/file-browser/architecture.md +645 -0
- package/src/file-browser/components/CreateItemDialog.tsx +71 -0
- package/src/file-browser/components/DeleteConfirmDialog.tsx +58 -0
- package/src/file-browser/components/FileBrowser.tsx +473 -0
- package/src/file-browser/components/FileBrowserContent.tsx +209 -0
- package/src/file-browser/components/FileBrowserHeader.tsx +151 -0
- package/src/file-browser/components/FileBrowserToolbar.tsx +145 -0
- package/src/file-browser/components/LeftPanel/LeftPanel.tsx +103 -0
- package/src/file-browser/components/LeftPanel/LeftPanelTabs.tsx +70 -0
- package/src/file-browser/components/LeftPanel/TreeNavigationView.tsx +256 -0
- package/src/file-browser/components/PreviewPane.tsx +146 -0
- package/src/file-browser/components/RightPanel/FilePreview.tsx +219 -0
- package/src/file-browser/components/RightPanel/RightPanel.tsx +186 -0
- package/src/file-browser/components/RightPanel/RightPanelToolbar.tsx +113 -0
- package/src/file-browser/components/UploadProgress.tsx +123 -0
- package/src/file-browser/components/ViewerHost.tsx +208 -0
- package/src/file-browser/components/mobile/MobileNavigation.tsx +227 -0
- package/src/file-browser/components/navigation/NavigationButtons.tsx +171 -0
- package/src/file-browser/components/shared/ErrorBoundary.tsx +116 -0
- package/src/file-browser/components/shared/FileBrowserItem.tsx +195 -0
- package/src/file-browser/components/shared/FileIcon.tsx +169 -0
- package/src/file-browser/components/toolbar/ViewModeToggle.tsx +200 -0
- package/src/file-browser/components/views/ListView/ListView.tsx +484 -0
- package/src/file-browser/components/views/ThumbnailView/ThumbnailView.tsx +323 -0
- package/src/file-browser/components/views/TreeView/TreeNode.tsx +186 -0
- package/src/file-browser/components/views/TreeView/TreeNodeList.tsx +191 -0
- package/src/file-browser/components/views/TreeView/TreeView.tsx +200 -0
- package/src/file-browser/components/views/TreemapView/TreemapView.tsx +339 -0
- package/src/file-browser/context/FileBrowserContext.tsx +13 -0
- package/src/file-browser/examples/BasicUsage.tsx +20 -0
- package/src/file-browser/index.ts +98 -0
- package/src/file-browser/models/FileBrowserModel.ts +623 -0
- package/src/file-browser/models/LeftPanelManagerModel.ts +105 -0
- package/src/file-browser/models/NavigationManagerModel.ts +312 -0
- package/src/file-browser/models/ResponsiveLayoutManagerModel.ts +437 -0
- package/src/file-browser/models/RightPanelManagerModel.ts +190 -0
- package/src/file-browser/models/SelectionManagerModel.ts +252 -0
- package/src/file-browser/models/ToolbarManagerModel.ts +144 -0
- package/src/file-browser/models/UploadModel.ts +147 -0
- package/src/file-browser/models/ViewModeManagerModel.ts +185 -0
- package/src/file-browser/models/ViewerHostModel.ts +44 -0
- package/src/file-browser/models/ui/ListViewUIModel.ts +265 -0
- package/src/file-browser/models/ui/PreviewUIModel.ts +297 -0
- package/src/file-browser/models/ui/ThumbnailViewUIModel.ts +254 -0
- package/src/file-browser/models/ui/TreeViewUIModel.ts +128 -0
- package/src/file-browser/models/ui/TreemapViewUIModel.ts +350 -0
- package/src/file-browser/providers/FileSystemListProvider.ts +552 -0
- package/src/file-browser/providers/FileSystemProvider.ts +401 -0
- package/src/file-browser/providers/FileSystemTreeProvider.ts +231 -0
- package/src/file-browser/providers/GitProvider.ts +337 -0
- package/src/file-browser/providers/GitRepositoryProvider.ts +376 -0
- package/src/file-browser/providers/IFileBrowserProvider.ts +56 -0
- package/src/file-browser/providers/MemoryProvider.ts +303 -0
- package/src/file-browser/providers/index.ts +4 -0
- package/src/file-browser/registry/ViewerRegistry.ts +551 -0
- package/src/file-browser/registry/types.ts +144 -0
- package/src/file-browser/scripts/performanceBenchmark.ts +553 -0
- package/src/file-browser/services/ThumbnailCacheService.ts +128 -0
- package/src/file-browser/tasks.md +537 -0
- package/src/file-browser/types/FileBrowserTypes.ts +126 -0
- package/src/file-browser/types/ProviderTypes.ts +155 -0
- package/src/file-browser/types/UITypes.ts +235 -0
- package/src/file-browser/types/ViewModeTypes.ts +150 -0
- package/src/file-browser/utils/gestures.ts +327 -0
- package/src/file-browser/utils/performance.ts +563 -0
- package/src/file-browser/viewers/ImageViewer.tsx +163 -0
- package/src/file-browser/viewers/ImageViewerModel.ts +79 -0
- package/src/file-browser/viewers/TextViewer.tsx +95 -0
- package/src/file-browser/viewers/UnsupportedFileViewer.tsx +57 -0
- package/src/file-browser/viewers/index.ts +61 -0
- package/src/git/BranchList.tsx +128 -0
- package/src/git/CommitGraph.tsx +239 -0
- package/src/git/CommitList.tsx +258 -0
- package/src/git/DiffViewer.tsx +219 -0
- package/src/git/index.ts +4 -0
- package/src/icons/iconMap.ts +146 -0
- package/src/icons/index.ts +9 -0
- package/src/index.ts +13 -0
- package/src/layout/README.md +307 -0
- package/src/layout/components/ExplorerLayout/ExplorerLayout.tsx +178 -0
- package/src/layout/examples/SimpleExample.tsx +60 -0
- package/src/layout/index.ts +6 -0
- package/src/lib/utils.ts +1 -0
- package/src/list/README.md +303 -0
- package/src/list/architecture.md +807 -0
- package/src/list/components/CalculatedGridView.tsx +252 -0
- package/src/list/components/DragPreview.tsx +102 -0
- package/src/list/components/ListContextMenu.tsx +274 -0
- package/src/list/components/ListItem.tsx +761 -0
- package/src/list/components/ListItems.tsx +919 -0
- package/src/list/components/MasonryView.tsx +241 -0
- package/src/list/components/SearchFilter.tsx +44 -0
- package/src/list/components/TreemapView.tsx +709 -0
- package/src/list/components/ViewSizeControls.tsx +205 -0
- package/src/list/components/ViewTypeSelector.tsx +312 -0
- package/src/list/components/VirtualizedDetailsView.tsx +231 -0
- package/src/list/components/VirtualizedGrid.tsx +164 -0
- package/src/list/components/VirtualizedList.tsx +154 -0
- package/src/list/components/VirtualizedMasonryView.tsx +344 -0
- package/src/list/components/shared/EmptyState.tsx +103 -0
- package/src/list/components/shared/ErrorBoundary.tsx +123 -0
- package/src/list/components/shared/ErrorDisplay.tsx +100 -0
- package/src/list/components/shared/ListLoader.tsx +146 -0
- package/src/list/components/shared/LoadingIndicator.tsx +80 -0
- package/src/list/index.ts +92 -0
- package/src/list/models/ListItemsModel.ts +1301 -0
- package/src/list/models/TreemapModel.ts +204 -0
- package/src/list/providers/ListItemsProvider.ts +313 -0
- package/src/list/providers/TestListProvider.ts +604 -0
- package/src/list/tasks.md +937 -0
- package/src/list/types/ListTypes.ts +178 -0
- package/src/list/utils/BenchmarkLogger.ts +243 -0
- package/src/list/utils/DragDropManager.ts +320 -0
- package/src/list/utils/GridLayoutCalculator.ts +290 -0
- package/src/list/utils/ListAccessibility.ts +367 -0
- package/src/list/utils/ListKeyboard.ts +414 -0
- package/src/list/utils/MasonryLayoutCalculator.ts +302 -0
- package/src/list/utils/MasonryLayoutEngine.ts +401 -0
- package/src/list/utils/__tests__/MasonryLayoutEngine.test.ts +157 -0
- package/src/list/utils/__tests__/VirtualizedMasonryView.test.tsx +251 -0
- package/src/media/AlbumSidebar.tsx +48 -0
- package/src/media/MediaBrowser.tsx +92 -0
- package/src/media/MediaBrowserModel.ts +138 -0
- package/src/media/MediaGrid.tsx +50 -0
- package/src/media/MediaList.tsx +49 -0
- package/src/media/MediaPreview.tsx +63 -0
- package/src/media/MediaTimeline.tsx +38 -0
- package/src/media/MockMediaProvider.ts +70 -0
- package/src/media/index.ts +18 -0
- package/src/media/types.ts +21 -0
- package/src/styles/variables.css +60 -0
- package/src/tree/DEVELOPMENT_SUMMARY.md +170 -0
- package/src/tree/__tests__/TreeModel.test.ts +16 -0
- package/src/tree/architecture.md +530 -0
- package/src/tree/components/Tree.tsx +283 -0
- package/src/tree/components/TreeCheckbox.tsx +147 -0
- package/src/tree/components/TreeContextMenu.tsx +139 -0
- package/src/tree/components/TreeNodeList.tsx +329 -0
- package/src/tree/components/TreeTable.tsx +382 -0
- package/src/tree/index.ts +58 -0
- package/src/tree/models/TreeModel.ts +839 -0
- package/src/tree/providers/SimpleTreeProvider.ts +463 -0
- package/src/tree/providers/TestTreeProvider.ts +946 -0
- package/src/tree/providers/TreeProvider.ts +308 -0
- package/src/tree/tasks.md +2046 -0
- package/src/tree/types/TreeTypes.ts +279 -0
- package/src/tree/utils/SelectionTheme.ts +150 -0
- package/src/tree/utils/logger.ts +203 -0
- package/src/types-common.ts +21 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar-DSlrbHoj.js","names":["provider: ICalendarProvider","err: any","event: Omit<CalendarEvent, 'id' | 'createdAt' | 'updatedAt'>","id: string","event: CalendarEvent | null","date: Date","mode: CalendarViewMode","d: Date","weeks: (number | null)[][]","week: (number | null)[]","day: number","d: Date","cells: (number | null)[]","day: number","VIEW_LABELS: Record<CalendarViewMode, string>","CALENDARS: CalendarInfo[]","events: CalendarEvent[]","id: string","item: Omit<CalendarEvent, 'id' | 'createdAt' | 'updatedAt'>","created: CalendarEvent","updates: Partial<CalendarEvent>","query: string","start: Date","end: Date","calendarId: string"],"sources":["../src/calendar/CalendarModel.ts","../src/calendar/EventCard.tsx","../src/calendar/MonthView.tsx","../src/calendar/WeekView.tsx","../src/calendar/DayView.tsx","../src/calendar/AgendaView.tsx","../src/calendar/CalendarSidebar.tsx","../src/calendar/CalendarBrowser.tsx","../src/calendar/MockCalendarProvider.ts"],"sourcesContent":["import { makeAutoObservable, flow } from 'mobx';\nimport type { ICalendarProvider, CalendarEvent, CalendarInfo } from './types';\n\nexport type CalendarViewMode = 'month' | 'week' | 'day' | 'agenda';\n\nexport class CalendarModel {\n events: CalendarEvent[] = [];\n calendars: CalendarInfo[] = [];\n currentDate: Date = new Date();\n viewMode: CalendarViewMode = 'month';\n selectedEvent: CalendarEvent | null = null;\n loading = false;\n error: string | null = null;\n\n constructor(private provider: ICalendarProvider) {\n makeAutoObservable(this);\n }\n\n get visibleDateRange(): { start: Date; end: Date } {\n const d = this.currentDate;\n switch (this.viewMode) {\n case 'month': {\n const start = new Date(d.getFullYear(), d.getMonth(), 1);\n start.setDate(start.getDate() - start.getDay());\n const end = new Date(d.getFullYear(), d.getMonth() + 1, 0);\n end.setDate(end.getDate() + (6 - end.getDay()));\n return { start, end };\n }\n case 'week': {\n const start = new Date(d);\n start.setDate(d.getDate() - d.getDay());\n start.setHours(0, 0, 0, 0);\n const end = new Date(start);\n end.setDate(start.getDate() + 6);\n end.setHours(23, 59, 59, 999);\n return { start, end };\n }\n case 'day': {\n const start = new Date(d);\n start.setHours(0, 0, 0, 0);\n const end = new Date(d);\n end.setHours(23, 59, 59, 999);\n return { start, end };\n }\n case 'agenda': {\n const start = new Date(d);\n start.setHours(0, 0, 0, 0);\n const end = new Date(d);\n end.setDate(end.getDate() + 30);\n return { start, end };\n }\n }\n }\n\n get eventsForCurrentView(): CalendarEvent[] {\n const { start, end } = this.visibleDateRange;\n return this.events.filter(e =>\n e.endDate >= start && e.startDate <= end\n );\n }\n\n get eventsByDay(): Map<string, CalendarEvent[]> {\n const map = new Map<string, CalendarEvent[]>();\n for (const event of this.eventsForCurrentView) {\n const key = event.startDate.toISOString().slice(0, 10);\n const list = map.get(key) ?? [];\n list.push(event);\n map.set(key, list);\n }\n return map;\n }\n\n loadEvents = flow(function* (this: CalendarModel) {\n this.loading = true;\n this.error = null;\n try {\n const { start, end } = this.visibleDateRange;\n const [events, calendars] = yield Promise.all([\n this.provider.getEventsByRange(start, end),\n this.provider.getCalendars()\n ]);\n this.events = events;\n this.calendars = calendars;\n } catch (err: any) {\n this.error = err?.message || 'Failed to load calendar events';\n } finally {\n this.loading = false;\n }\n });\n\n selectEvent(event: CalendarEvent | null) {\n this.selectedEvent = event;\n }\n\n setDate(date: Date) {\n this.currentDate = date;\n this.loadEvents();\n }\n\n setViewMode(mode: CalendarViewMode) {\n this.viewMode = mode;\n this.loadEvents();\n }\n\n navigateForward() {\n const d = new Date(this.currentDate);\n switch (this.viewMode) {\n case 'month': d.setMonth(d.getMonth() + 1); break;\n case 'week': d.setDate(d.getDate() + 7); break;\n case 'day': d.setDate(d.getDate() + 1); break;\n case 'agenda': d.setDate(d.getDate() + 30); break;\n }\n this.setDate(d);\n }\n\n navigateBack() {\n const d = new Date(this.currentDate);\n switch (this.viewMode) {\n case 'month': d.setMonth(d.getMonth() - 1); break;\n case 'week': d.setDate(d.getDate() - 7); break;\n case 'day': d.setDate(d.getDate() - 1); break;\n case 'agenda': d.setDate(d.getDate() - 30); break;\n }\n this.setDate(d);\n }\n\n today() {\n this.setDate(new Date());\n }\n\n createEvent = flow(function* (this: CalendarModel, event: Omit<CalendarEvent, 'id' | 'createdAt' | 'updatedAt'>) {\n const created = yield this.provider.createItem(event);\n this.events.push(created);\n return created;\n });\n\n deleteEvent = flow(function* (this: CalendarModel, id: string) {\n yield this.provider.deleteItem(id);\n this.events = this.events.filter(e => e.id !== id);\n if (this.selectedEvent?.id === id) this.selectedEvent = null;\n });\n}\n","import React from 'react';\nimport { Clock, MapPin } from 'lucide-react';\nimport type { CalendarEvent } from './types';\n\nexport interface EventCardProps {\n event: CalendarEvent;\n compact?: boolean;\n onClick?: () => void;\n className?: string;\n}\n\nconst formatTime = (d: Date) => d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n\nexport const EventCard = ({ event, compact = false, onClick, className = '' }: EventCardProps) => {\n const color = event.color ?? '#3b82f6';\n\n if (compact) {\n return (\n <button\n onClick={onClick}\n className={`text-left text-xs px-1.5 py-0.5 rounded truncate w-full hover:opacity-80 transition-opacity ${className}`}\n style={{ backgroundColor: `${color}20`, color, borderLeft: `2px solid ${color}` }}\n title={event.title}\n >\n {event.title}\n </button>\n );\n }\n\n return (\n <button\n onClick={onClick}\n className={`text-left w-full p-3 rounded-lg border border-gray-200 hover:shadow-sm transition-shadow ${className}`}\n style={{ borderLeftWidth: '3px', borderLeftColor: color }}\n >\n <p className=\"text-sm font-medium text-gray-900 truncate\" title={event.title}>{event.title}</p>\n <div className=\"mt-1 flex items-center gap-3 text-xs text-gray-500\">\n <span className=\"flex items-center gap-1\">\n <Clock size={12} />\n {event.allDay ? 'All day' : `${formatTime(event.startDate)} - ${formatTime(event.endDate)}`}\n </span>\n {event.location && (\n <span className=\"flex items-center gap-1\">\n <MapPin size={12} />\n {event.location}\n </span>\n )}\n </div>\n </button>\n );\n};\n","import React from 'react';\nimport { observer } from 'mobx-react-lite';\nimport type { CalendarModel } from './CalendarModel';\nimport { EventCard } from './EventCard';\n\nexport interface MonthViewProps {\n model: CalendarModel;\n className?: string;\n}\n\nconst DAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\n\nexport const MonthView = observer<MonthViewProps>(({ model, className = '' }) => {\n const d = model.currentDate;\n const year = d.getFullYear();\n const month = d.getMonth();\n const today = new Date();\n\n const firstDay = new Date(year, month, 1).getDay();\n const daysInMonth = new Date(year, month + 1, 0).getDate();\n\n const weeks: (number | null)[][] = [];\n let week: (number | null)[] = [];\n for (let i = 0; i < firstDay; i++) week.push(null);\n for (let day = 1; day <= daysInMonth; day++) {\n week.push(day);\n if (week.length === 7) { weeks.push(week); week = []; }\n }\n if (week.length > 0) {\n while (week.length < 7) week.push(null);\n weeks.push(week);\n }\n\n const isToday = (day: number) =>\n day === today.getDate() && month === today.getMonth() && year === today.getFullYear();\n\n return (\n <div className={`flex flex-col h-full ${className}`}>\n <div className=\"grid grid-cols-7 border-b border-gray-200\">\n {DAYS.map(day => (\n <div key={day} className=\"px-2 py-2 text-xs font-medium text-gray-500 text-center\">{day.slice(0, 3)}</div>\n ))}\n </div>\n <div className=\"flex-1 grid grid-rows-[repeat(auto-fill,1fr)]\">\n {weeks.map((week, wi) => (\n <div key={wi} className=\"grid grid-cols-7 border-b border-gray-100 min-h-[80px]\">\n {week.map((day, di) => {\n const dateKey = day ? `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}` : null;\n const events = dateKey ? (model.eventsByDay.get(dateKey) ?? []) : [];\n return (\n <div key={di} className={`border-r border-gray-100 p-1 ${day === null ? 'bg-gray-50' : ''}`}>\n {day !== null && (\n <>\n <div className={`text-xs mb-0.5 w-6 h-6 flex items-center justify-center rounded-full ${\n isToday(day) ? 'bg-blue-500 text-white font-bold' : 'text-gray-700'\n }`}>\n {day}\n </div>\n <div className=\"space-y-0.5\">\n {events.slice(0, 3).map(ev => (\n <EventCard key={ev.id} event={ev} compact onClick={() => model.selectEvent(ev)} />\n ))}\n {events.length > 3 && (\n <p className=\"text-[10px] text-gray-400 pl-1\">+{events.length - 3} more</p>\n )}\n </div>\n </>\n )}\n </div>\n );\n })}\n </div>\n ))}\n </div>\n </div>\n );\n});\n","import React from 'react';\nimport { observer } from 'mobx-react-lite';\nimport type { CalendarModel } from './CalendarModel';\n\nexport interface WeekViewProps {\n model: CalendarModel;\n className?: string;\n}\n\nconst HOURS = Array.from({ length: 24 }, (_, i) => i);\n\nexport const WeekView = observer<WeekViewProps>(({ model, className = '' }) => {\n const { start } = model.visibleDateRange;\n const days = Array.from({ length: 7 }, (_, i) => {\n const d = new Date(start);\n d.setDate(start.getDate() + i);\n return d;\n });\n\n const now = new Date();\n const isToday = (d: Date) => d.toDateString() === now.toDateString();\n const currentHour = now.getHours();\n const currentMinute = now.getMinutes();\n\n // Collect all-day events for the visible week\n const allDayEventsByDay = days.map(d => {\n const dateKey = d.toISOString().slice(0, 10);\n return (model.eventsByDay.get(dateKey) ?? []).filter(e => e.allDay);\n });\n const hasAllDay = allDayEventsByDay.some(events => events.length > 0);\n\n return (\n <div className={`flex flex-col h-full overflow-auto ${className}`}>\n {/* Day headers */}\n <div className=\"sticky top-0 bg-white z-10 border-b border-gray-200\">\n <div className=\"grid\" style={{ gridTemplateColumns: '60px repeat(7, 1fr)' }}>\n <div />\n {days.map((d, i) => (\n <div key={i} className={`text-center py-2 border-l border-gray-100 ${isToday(d) ? 'bg-blue-50' : ''}`}>\n <div className=\"text-xs text-gray-500\">{d.toLocaleDateString(undefined, { weekday: 'short' })}</div>\n <div className={`text-lg font-medium ${isToday(d) ? 'text-blue-600' : 'text-gray-900'}`}>{d.getDate()}</div>\n </div>\n ))}\n </div>\n\n {/* All-day events row */}\n {hasAllDay && (\n <div className=\"grid border-t border-gray-100\" style={{ gridTemplateColumns: '60px repeat(7, 1fr)' }}>\n <div className=\"text-[10px] text-gray-400 text-right pr-2 py-1\">all-day</div>\n {allDayEventsByDay.map((events, i) => (\n <div key={i} className=\"border-l border-gray-100 px-0.5 py-0.5 space-y-0.5\">\n {events.map(ev => (\n <button\n key={ev.id}\n onClick={() => model.selectEvent(ev)}\n className=\"w-full text-left text-[10px] px-1 py-0.5 rounded truncate\"\n style={{\n backgroundColor: `${ev.color ?? '#3b82f6'}20`,\n color: ev.color ?? '#3b82f6',\n borderLeft: `2px solid ${ev.color ?? '#3b82f6'}`,\n }}\n title={ev.title}\n >\n {ev.title}\n </button>\n ))}\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Time grid */}\n <div className=\"flex-1 relative\">\n {HOURS.map(hour => (\n <div key={hour} className=\"grid border-b border-gray-50\" style={{ gridTemplateColumns: '60px repeat(7, 1fr)', height: '48px' }}>\n <div className=\"text-[10px] text-gray-400 text-right pr-2 -mt-2\">\n {hour === 0 ? '' : `${hour % 12 || 12} ${hour < 12 ? 'AM' : 'PM'}`}\n </div>\n {days.map((d, i) => {\n const dateKey = d.toISOString().slice(0, 10);\n const events = (model.eventsByDay.get(dateKey) ?? []).filter(e =>\n !e.allDay && e.startDate.getHours() === hour\n );\n const showTimeLine = isToday(d) && hour === currentHour;\n return (\n <div key={i} className=\"border-l border-gray-100 relative\">\n {/* Current time indicator */}\n {showTimeLine && (\n <div\n className=\"absolute left-0 right-0 z-10 pointer-events-none\"\n style={{ top: `${(currentMinute / 60) * 48}px` }}\n >\n <div className=\"w-2 h-2 bg-red-500 rounded-full absolute -left-1 -top-1\" />\n <div className=\"h-px bg-red-500 w-full\" />\n </div>\n )}\n {events.map((ev, ei) => {\n const durationHours = Math.max(0.5, (ev.endDate.getTime() - ev.startDate.getTime()) / 3600000);\n const topOffset = (ev.startDate.getMinutes() / 60) * 48;\n return (\n <button\n key={ev.id}\n onClick={() => model.selectEvent(ev)}\n className=\"absolute text-xs px-1 py-0.5 rounded truncate z-[1]\"\n title={ev.title}\n style={{\n backgroundColor: `${ev.color ?? '#3b82f6'}20`,\n color: ev.color ?? '#3b82f6',\n borderLeft: `2px solid ${ev.color ?? '#3b82f6'}`,\n height: `${durationHours * 48}px`,\n top: `${topOffset}px`,\n left: `${ei * 4 + 2}px`,\n right: '2px',\n }}\n >\n {ev.title}\n </button>\n );\n })}\n </div>\n );\n })}\n </div>\n ))}\n </div>\n </div>\n );\n});\n","import React from 'react';\nimport { observer } from 'mobx-react-lite';\nimport type { CalendarModel } from './CalendarModel';\n\nexport interface DayViewProps {\n model: CalendarModel;\n className?: string;\n}\n\nconst HOURS = Array.from({ length: 24 }, (_, i) => i);\n\nexport const DayView = observer<DayViewProps>(({ model, className = '' }) => {\n const d = model.currentDate;\n const dateKey = d.toISOString().slice(0, 10);\n const dayEvents = model.eventsByDay.get(dateKey) ?? [];\n const allDayEvents = dayEvents.filter(e => e.allDay);\n const timedEvents = dayEvents.filter(e => !e.allDay);\n\n return (\n <div className={`flex flex-col h-full overflow-auto ${className}`}>\n {/* Header */}\n <div className=\"border-b border-gray-200 px-4 py-2 sticky top-0 bg-white z-10\">\n <h2 className=\"text-lg font-medium text-gray-900\">\n {d.toLocaleDateString(undefined, { weekday: 'long', month: 'long', day: 'numeric' })}\n </h2>\n {allDayEvents.length > 0 && (\n <div className=\"flex gap-1 mt-1\">\n {allDayEvents.map(ev => (\n <button\n key={ev.id}\n onClick={() => model.selectEvent(ev)}\n className=\"text-xs px-2 py-0.5 rounded\"\n style={{ backgroundColor: `${ev.color ?? '#3b82f6'}20`, color: ev.color ?? '#3b82f6' }}\n >\n {ev.title}\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* Time slots */}\n <div className=\"flex-1\">\n {HOURS.map(hour => {\n const hourEvents = timedEvents.filter(e => e.startDate.getHours() === hour);\n return (\n <div key={hour} className=\"grid grid-cols-[60px_1fr] border-b border-gray-50 min-h-[48px]\">\n <div className=\"text-[10px] text-gray-400 text-right pr-2 -mt-2\">\n {hour === 0 ? '' : `${hour % 12 || 12} ${hour < 12 ? 'AM' : 'PM'}`}\n </div>\n <div className=\"border-l border-gray-100 relative pl-1\">\n {hourEvents.map(ev => (\n <button\n key={ev.id}\n onClick={() => model.selectEvent(ev)}\n className=\"w-full text-left text-xs p-1.5 rounded mb-0.5\"\n style={{\n backgroundColor: `${ev.color ?? '#3b82f6'}15`,\n color: ev.color ?? '#3b82f6',\n borderLeft: `2px solid ${ev.color ?? '#3b82f6'}`\n }}\n >\n <span className=\"font-medium\">{ev.title}</span>\n <span className=\"ml-2 opacity-70\">\n {ev.startDate.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}\n </span>\n </button>\n ))}\n </div>\n </div>\n );\n })}\n </div>\n </div>\n );\n});\n","import React from 'react';\nimport { observer } from 'mobx-react-lite';\nimport type { CalendarModel } from './CalendarModel';\nimport { EventCard } from './EventCard';\n\nexport interface AgendaViewProps {\n model: CalendarModel;\n className?: string;\n}\n\nexport const AgendaView = observer<AgendaViewProps>(({ model, className = '' }) => {\n const sortedEntries = Array.from(model.eventsByDay.entries())\n .sort(([a], [b]) => a.localeCompare(b));\n\n return (\n <div className={`overflow-y-auto p-4 space-y-4 ${className}`}>\n {sortedEntries.length === 0 && (\n <div className=\"flex items-center justify-center h-32 text-gray-400 text-sm\">No upcoming events</div>\n )}\n {sortedEntries.map(([dateKey, events]) => {\n const date = new Date(dateKey + 'T00:00:00');\n return (\n <div key={dateKey}>\n <h3 className=\"text-sm font-semibold text-gray-700 mb-2 sticky top-0 bg-white/90 backdrop-blur-sm py-1\">\n {date.toLocaleDateString(undefined, { weekday: 'long', month: 'long', day: 'numeric' })}\n </h3>\n <div className=\"space-y-1.5\">\n {events.map(ev => (\n <EventCard key={ev.id} event={ev} onClick={() => model.selectEvent(ev)} />\n ))}\n </div>\n </div>\n );\n })}\n </div>\n );\n});\n","import React from 'react';\nimport { observer } from 'mobx-react-lite';\nimport { ChevronLeft, ChevronRight } from 'lucide-react';\nimport type { CalendarModel } from './CalendarModel';\n\nexport interface CalendarSidebarProps {\n model: CalendarModel;\n className?: string;\n}\n\nconst DAYS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];\n\nexport const CalendarSidebar = observer<CalendarSidebarProps>(({ model, className = '' }) => {\n const d = model.currentDate;\n const year = d.getFullYear();\n const month = d.getMonth();\n\n const firstDay = new Date(year, month, 1).getDay();\n const daysInMonth = new Date(year, month + 1, 0).getDate();\n const today = new Date();\n\n const cells: (number | null)[] = [];\n for (let i = 0; i < firstDay; i++) cells.push(null);\n for (let i = 1; i <= daysInMonth; i++) cells.push(i);\n\n const isToday = (day: number) =>\n day === today.getDate() && month === today.getMonth() && year === today.getFullYear();\n\n const isSelected = (day: number) =>\n day === d.getDate();\n\n return (\n <div className={`w-56 border-r border-gray-200 bg-gray-50 p-3 ${className}`}>\n {/* Mini month */}\n <div className=\"mb-4\">\n <div className=\"flex items-center justify-between mb-2\">\n <button onClick={() => model.navigateBack()} className=\"p-1 hover:bg-gray-200 rounded\">\n <ChevronLeft size={14} />\n </button>\n <span className=\"text-sm font-medium\">\n {d.toLocaleDateString(undefined, { month: 'long', year: 'numeric' })}\n </span>\n <button onClick={() => model.navigateForward()} className=\"p-1 hover:bg-gray-200 rounded\">\n <ChevronRight size={14} />\n </button>\n </div>\n <div className=\"grid grid-cols-7 gap-0.5 text-center\">\n {DAYS.map(day => (\n <div key={day} className=\"text-[10px] text-gray-400 font-medium py-0.5\">{day}</div>\n ))}\n {cells.map((day, i) => (\n <button\n key={i}\n disabled={day === null}\n onClick={() => day && model.setDate(new Date(year, month, day))}\n className={`text-xs py-0.5 rounded ${\n day === null ? '' :\n isSelected(day) ? 'bg-blue-500 text-white' :\n isToday(day) ? 'bg-blue-100 text-blue-700 font-bold' :\n 'text-gray-700 hover:bg-gray-200'\n }`}\n >\n {day}\n </button>\n ))}\n </div>\n </div>\n\n {/* Calendar list */}\n <div>\n <h3 className=\"text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2\">Calendars</h3>\n {model.calendars.map(cal => (\n <div key={cal.id} className=\"flex items-center gap-2 px-2 py-1.5 text-sm text-gray-700\">\n <div className=\"w-3 h-3 rounded-full\" style={{ backgroundColor: cal.color }} />\n <span className=\"truncate\" title={cal.name}>{cal.name}</span>\n </div>\n ))}\n </div>\n </div>\n );\n});\n","import React, { useEffect } from 'react';\nimport { observer } from 'mobx-react-lite';\nimport { ChevronLeft, ChevronRight, Loader2 } from 'lucide-react';\nimport { BrowserError } from '@anymux/ui/components/browser-error';\nimport type { CalendarModel, CalendarViewMode } from './CalendarModel';\nimport { MonthView } from './MonthView';\nimport { WeekView } from './WeekView';\nimport { DayView } from './DayView';\nimport { AgendaView } from './AgendaView';\nimport { CalendarSidebar } from './CalendarSidebar';\n\nexport interface CalendarBrowserProps {\n model: CalendarModel;\n className?: string;\n showSidebar?: boolean;\n}\n\nconst VIEW_LABELS: Record<CalendarViewMode, string> = {\n month: 'Month',\n week: 'Week',\n day: 'Day',\n agenda: 'Agenda',\n};\n\nexport const CalendarBrowser = observer<CalendarBrowserProps>(({ model, className = '', showSidebar = true }) => {\n useEffect(() => { model.loadEvents(); }, [model]);\n\n return (\n <div className={`flex h-full bg-white rounded-xl border border-gray-200 overflow-hidden ${className}`}>\n {showSidebar && <CalendarSidebar model={model} />}\n\n <div className=\"flex-1 flex flex-col min-w-0\">\n {/* Toolbar */}\n <div className=\"flex items-center gap-2 px-4 py-2 border-b border-gray-200\">\n <button onClick={() => model.today()} className=\"text-sm px-3 py-1.5 border border-gray-200 rounded-lg hover:bg-gray-50\">\n Today\n </button>\n <button onClick={() => model.navigateBack()} className=\"p-1.5 hover:bg-gray-100 rounded-lg\">\n <ChevronLeft size={16} />\n </button>\n <button onClick={() => model.navigateForward()} className=\"p-1.5 hover:bg-gray-100 rounded-lg\">\n <ChevronRight size={16} />\n </button>\n <h2 className=\"text-sm font-medium text-gray-900 ml-2\">\n {model.currentDate.toLocaleDateString(undefined, {\n month: 'long',\n year: 'numeric',\n ...(model.viewMode === 'day' ? { day: 'numeric', weekday: 'long' } : {})\n })}\n </h2>\n <div className=\"ml-auto flex items-center border border-gray-200 rounded-lg overflow-hidden\">\n {(Object.keys(VIEW_LABELS) as CalendarViewMode[]).map(mode => (\n <button\n key={mode}\n onClick={() => model.setViewMode(mode)}\n className={`px-3 py-1.5 text-xs font-medium ${\n model.viewMode === mode ? 'bg-blue-50 text-blue-600' : 'text-gray-500 hover:bg-gray-50'\n }`}\n >\n {VIEW_LABELS[mode]}\n </button>\n ))}\n </div>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-hidden\">\n {model.loading ? (\n <div className=\"flex items-center justify-center h-64\">\n <Loader2 size={24} className=\"animate-spin text-gray-400\" />\n </div>\n ) : model.error ? (\n <BrowserError\n error={model.error}\n context=\"Calendar\"\n onRetry={() => model.loadEvents()}\n />\n ) : (\n <>\n {model.viewMode === 'month' && <MonthView model={model} />}\n {model.viewMode === 'week' && <WeekView model={model} />}\n {model.viewMode === 'day' && <DayView model={model} />}\n {model.viewMode === 'agenda' && <AgendaView model={model} />}\n </>\n )}\n </div>\n </div>\n </div>\n );\n});\n","import type { ICalendarProvider, CalendarEvent, CalendarInfo } from './types';\n\nconst CALENDARS: CalendarInfo[] = [\n { id: 'personal', name: 'Personal', color: '#3b82f6' },\n { id: 'work', name: 'Work', color: '#10b981' },\n { id: 'family', name: 'Family', color: '#f59e0b' },\n];\n\nconst EVENT_TITLES = [\n 'Team standup', 'Lunch with Sarah', 'Design review', 'Gym session',\n 'Doctor appointment', 'Code review', 'Sprint planning', 'Movie night',\n 'Grocery shopping', 'Piano lesson', 'Board meeting', 'Yoga class',\n 'Project deadline', 'Coffee with Alex', 'Dentist', 'Book club',\n];\n\nconst LOCATIONS = ['Office', 'Zoom', 'Conference Room A', 'Downtown Cafe', 'Home', undefined];\n\nfunction generateEvents(): CalendarEvent[] {\n const events: CalendarEvent[] = [];\n const now = new Date();\n const baseDate = new Date(now.getFullYear(), now.getMonth(), 1);\n\n for (let i = 0; i < 40; i++) {\n const day = Math.floor(Math.random() * 35) - 5;\n const hour = 8 + Math.floor(Math.random() * 10);\n const duration = 1 + Math.floor(Math.random() * 3);\n const allDay = i % 8 === 0;\n const calendar = CALENDARS[i % CALENDARS.length];\n\n const startDate = new Date(baseDate);\n startDate.setDate(startDate.getDate() + day);\n startDate.setHours(hour, 0, 0, 0);\n\n const endDate = new Date(startDate);\n if (allDay) {\n endDate.setHours(23, 59, 59, 999);\n } else {\n endDate.setHours(hour + duration);\n }\n\n events.push({\n id: `event-${i}`,\n type: 'calendar-event',\n title: EVENT_TITLES[i % EVENT_TITLES.length],\n startDate,\n endDate,\n allDay,\n location: LOCATIONS[i % LOCATIONS.length],\n attendees: i % 3 === 0 ? ['alice@example.com', 'bob@example.com'] : undefined,\n color: calendar.color,\n calendarId: calendar.id,\n createdAt: now,\n updatedAt: now,\n });\n }\n return events;\n}\n\nexport class MockCalendarProvider implements ICalendarProvider {\n private events = generateEvents();\n\n async listItems() { return this.events; }\n\n async getItem(id: string) { return this.events.find(e => e.id === id) ?? null; }\n\n async createItem(item: Omit<CalendarEvent, 'id' | 'createdAt' | 'updatedAt'>) {\n const now = new Date();\n const created: CalendarEvent = { ...item, id: `event-${Date.now()}`, createdAt: now, updatedAt: now } as CalendarEvent;\n this.events.push(created);\n return created;\n }\n\n async updateItem(id: string, updates: Partial<CalendarEvent>) {\n const idx = this.events.findIndex(e => e.id === id);\n if (idx === -1) throw new Error('Not found');\n this.events[idx] = { ...this.events[idx], ...updates, updatedAt: new Date() };\n return this.events[idx];\n }\n\n async deleteItem(id: string) {\n this.events = this.events.filter(e => e.id !== id);\n }\n\n async search(query: string) {\n const q = query.toLowerCase();\n return this.events.filter(e => e.title.toLowerCase().includes(q));\n }\n\n async getCalendars() { return CALENDARS; }\n\n async getEventsByRange(start: Date, end: Date) {\n return this.events.filter(e => e.endDate >= start && e.startDate <= end);\n }\n\n async getEventsByCalendar(calendarId: string) {\n return this.events.filter(e => e.calendarId === calendarId);\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import "./types-common-CB3kRek8.js";
|
|
2
|
+
import { AgendaView$1 as AgendaView, AgendaViewProps, CalendarBrowser$1 as CalendarBrowser, CalendarBrowserProps, CalendarEvent, CalendarInfo, CalendarModel$1 as CalendarModel, CalendarSidebar$1 as CalendarSidebar, CalendarSidebarProps, CalendarViewMode, DayView$1 as DayView, DayViewProps, EventCard$1 as EventCard, EventCardProps, ICalendarProvider, MockCalendarProvider$1 as MockCalendarProvider, MonthView$1 as MonthView, MonthViewProps, WeekView$1 as WeekView, WeekViewProps } from "./index-DSu19mq0.js";
|
|
3
|
+
export { AgendaView, AgendaViewProps, CalendarBrowser, CalendarBrowserProps, CalendarEvent, CalendarInfo, CalendarModel, CalendarSidebar, CalendarSidebarProps, CalendarViewMode, DayView, DayViewProps, EventCard, EventCardProps, ICalendarProvider, MockCalendarProvider, MonthView, MonthViewProps, WeekView, WeekViewProps };
|
package/dist/calendar.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { AgendaView, CalendarBrowser, CalendarModel, CalendarSidebar, DayView, EventCard, MockCalendarProvider, MonthView, WeekView } from "./calendar-DSlrbHoj.js";
|
|
2
|
+
|
|
3
|
+
export { AgendaView, CalendarBrowser, CalendarModel, CalendarSidebar, DayView, EventCard, MockCalendarProvider, MonthView, WeekView };
|
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { observer } from "mobx-react-lite";
|
|
3
|
+
import { Building, Calendar, Loader2, Mail, MapPin, Phone, Search, Tag, User, Users } from "lucide-react";
|
|
4
|
+
import { BrowserError } from "@anymux/ui/components/browser-error";
|
|
5
|
+
import { makeAutoObservable, runInAction } from "mobx";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
|
|
8
|
+
//#region src/contacts/ContactListModel.ts
|
|
9
|
+
var ContactListModel = class {
|
|
10
|
+
constructor(provider) {
|
|
11
|
+
this.provider = provider;
|
|
12
|
+
this.contacts = [];
|
|
13
|
+
this.selectedContact = null;
|
|
14
|
+
this.groups = [];
|
|
15
|
+
this.currentGroup = null;
|
|
16
|
+
this.searchQuery = "";
|
|
17
|
+
this.sortBy = "lastName";
|
|
18
|
+
this.loading = false;
|
|
19
|
+
this.error = null;
|
|
20
|
+
makeAutoObservable(this);
|
|
21
|
+
}
|
|
22
|
+
get filteredContacts() {
|
|
23
|
+
let result = this.contacts;
|
|
24
|
+
if (this.searchQuery) {
|
|
25
|
+
const q = this.searchQuery.toLowerCase();
|
|
26
|
+
result = result.filter((c) => c.firstName.toLowerCase().includes(q) || c.lastName.toLowerCase().includes(q) || c.email?.toLowerCase().includes(q) || c.company?.toLowerCase().includes(q));
|
|
27
|
+
}
|
|
28
|
+
return this.sortContacts(result);
|
|
29
|
+
}
|
|
30
|
+
get groupedByLetter() {
|
|
31
|
+
const groups = new Map();
|
|
32
|
+
for (const contact of this.filteredContacts) {
|
|
33
|
+
const letter = (this.sortBy === "firstName" ? contact.firstName : contact.lastName).charAt(0).toUpperCase();
|
|
34
|
+
const group = groups.get(letter) ?? [];
|
|
35
|
+
group.push(contact);
|
|
36
|
+
groups.set(letter, group);
|
|
37
|
+
}
|
|
38
|
+
return groups;
|
|
39
|
+
}
|
|
40
|
+
get groupedByGroup() {
|
|
41
|
+
const groups = new Map();
|
|
42
|
+
for (const contact of this.filteredContacts) for (const groupName of contact.groups ?? ["Ungrouped"]) {
|
|
43
|
+
const group = groups.get(groupName) ?? [];
|
|
44
|
+
group.push(contact);
|
|
45
|
+
groups.set(groupName, group);
|
|
46
|
+
}
|
|
47
|
+
return groups;
|
|
48
|
+
}
|
|
49
|
+
async loadContacts() {
|
|
50
|
+
this.loading = true;
|
|
51
|
+
this.error = null;
|
|
52
|
+
try {
|
|
53
|
+
const [contacts, groups] = await Promise.all([this.currentGroup ? this.provider.getByGroup(this.currentGroup) : this.provider.listItems(), this.provider.getGroups()]);
|
|
54
|
+
runInAction(() => {
|
|
55
|
+
this.contacts = contacts;
|
|
56
|
+
this.groups = groups;
|
|
57
|
+
});
|
|
58
|
+
} catch (err) {
|
|
59
|
+
runInAction(() => {
|
|
60
|
+
this.error = err?.message || "Failed to load contacts";
|
|
61
|
+
});
|
|
62
|
+
} finally {
|
|
63
|
+
runInAction(() => {
|
|
64
|
+
this.loading = false;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
selectContact(contact) {
|
|
69
|
+
this.selectedContact = contact;
|
|
70
|
+
}
|
|
71
|
+
setGroup(groupId) {
|
|
72
|
+
this.currentGroup = groupId;
|
|
73
|
+
this.loadContacts();
|
|
74
|
+
}
|
|
75
|
+
setSearch(query) {
|
|
76
|
+
this.searchQuery = query;
|
|
77
|
+
}
|
|
78
|
+
setSort(sortBy) {
|
|
79
|
+
this.sortBy = sortBy;
|
|
80
|
+
}
|
|
81
|
+
async addContact(contact) {
|
|
82
|
+
const created = await this.provider.createItem(contact);
|
|
83
|
+
runInAction(() => {
|
|
84
|
+
this.contacts.push(created);
|
|
85
|
+
});
|
|
86
|
+
return created;
|
|
87
|
+
}
|
|
88
|
+
async deleteContact(id) {
|
|
89
|
+
await this.provider.deleteItem(id);
|
|
90
|
+
runInAction(() => {
|
|
91
|
+
this.contacts = this.contacts.filter((c) => c.id !== id);
|
|
92
|
+
if (this.selectedContact?.id === id) this.selectedContact = null;
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
sortContacts(contacts) {
|
|
96
|
+
return [...contacts].sort((a, b) => {
|
|
97
|
+
switch (this.sortBy) {
|
|
98
|
+
case "firstName": return a.firstName.localeCompare(b.firstName);
|
|
99
|
+
case "lastName": return a.lastName.localeCompare(b.lastName);
|
|
100
|
+
case "company": return (a.company ?? "").localeCompare(b.company ?? "");
|
|
101
|
+
default: return 0;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region src/contacts/ContactAvatar.tsx
|
|
109
|
+
const sizeClasses = {
|
|
110
|
+
sm: "w-8 h-8 text-xs",
|
|
111
|
+
md: "w-10 h-10 text-sm",
|
|
112
|
+
lg: "w-16 h-16 text-xl"
|
|
113
|
+
};
|
|
114
|
+
const bgColors = [
|
|
115
|
+
"bg-blue-500",
|
|
116
|
+
"bg-green-500",
|
|
117
|
+
"bg-purple-500",
|
|
118
|
+
"bg-pink-500",
|
|
119
|
+
"bg-indigo-500",
|
|
120
|
+
"bg-teal-500",
|
|
121
|
+
"bg-orange-500",
|
|
122
|
+
"bg-red-500"
|
|
123
|
+
];
|
|
124
|
+
const ContactAvatar = ({ firstName, lastName, avatar, size = "md", className = "" }) => {
|
|
125
|
+
const initials = `${firstName.charAt(0)}${lastName.charAt(0)}`.toUpperCase();
|
|
126
|
+
const colorIdx = (firstName.charCodeAt(0) + lastName.charCodeAt(0)) % bgColors.length;
|
|
127
|
+
if (avatar) return /* @__PURE__ */ jsx("img", {
|
|
128
|
+
src: avatar,
|
|
129
|
+
alt: `${firstName} ${lastName}`,
|
|
130
|
+
className: `${sizeClasses[size]} rounded-full object-cover ${className}`
|
|
131
|
+
});
|
|
132
|
+
return /* @__PURE__ */ jsx("div", {
|
|
133
|
+
className: `${sizeClasses[size]} ${bgColors[colorIdx]} rounded-full flex items-center justify-center text-white font-medium ${className}`,
|
|
134
|
+
children: initials
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
//#endregion
|
|
139
|
+
//#region src/contacts/ContactCard.tsx
|
|
140
|
+
const ContactCard = ({ contact, selected = false, onClick, className = "" }) => /* @__PURE__ */ jsxs("button", {
|
|
141
|
+
onClick,
|
|
142
|
+
className: `flex items-center gap-3 px-4 py-3 w-full text-left transition-colors ${selected ? "bg-blue-50 border-l-2 border-blue-500" : "hover:bg-gray-50 border-l-2 border-transparent"} ${className}`,
|
|
143
|
+
children: [
|
|
144
|
+
/* @__PURE__ */ jsx(ContactAvatar, {
|
|
145
|
+
firstName: contact.firstName,
|
|
146
|
+
lastName: contact.lastName,
|
|
147
|
+
avatar: contact.avatar
|
|
148
|
+
}),
|
|
149
|
+
/* @__PURE__ */ jsxs("div", {
|
|
150
|
+
className: "flex-1 min-w-0",
|
|
151
|
+
children: [/* @__PURE__ */ jsxs("p", {
|
|
152
|
+
className: "text-sm font-medium text-gray-900 truncate",
|
|
153
|
+
title: `${contact.firstName} ${contact.lastName}`,
|
|
154
|
+
children: [
|
|
155
|
+
contact.firstName,
|
|
156
|
+
" ",
|
|
157
|
+
contact.lastName
|
|
158
|
+
]
|
|
159
|
+
}), contact.company && /* @__PURE__ */ jsxs("p", {
|
|
160
|
+
className: "text-xs text-gray-500 flex items-center gap-1 truncate",
|
|
161
|
+
title: contact.company,
|
|
162
|
+
children: [/* @__PURE__ */ jsx(Building, { size: 12 }), contact.company]
|
|
163
|
+
})]
|
|
164
|
+
}),
|
|
165
|
+
/* @__PURE__ */ jsxs("div", {
|
|
166
|
+
className: "flex items-center gap-1.5 text-gray-400",
|
|
167
|
+
children: [contact.email && /* @__PURE__ */ jsx(Mail, { size: 14 }), contact.phone && /* @__PURE__ */ jsx(Phone, { size: 14 })]
|
|
168
|
+
})
|
|
169
|
+
]
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
//#endregion
|
|
173
|
+
//#region src/contacts/ContactList.tsx
|
|
174
|
+
const ContactList = observer(({ model, className = "" }) => /* @__PURE__ */ jsxs("div", {
|
|
175
|
+
className: `overflow-y-auto ${className}`,
|
|
176
|
+
children: [Array.from(model.groupedByLetter.entries()).map(([letter, contacts]) => /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
|
|
177
|
+
className: "sticky top-0 bg-gray-50/90 backdrop-blur-sm px-4 py-1 border-b border-gray-100",
|
|
178
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
179
|
+
className: "text-xs font-semibold text-gray-500",
|
|
180
|
+
children: letter
|
|
181
|
+
})
|
|
182
|
+
}), contacts.map((contact) => /* @__PURE__ */ jsx(ContactCard, {
|
|
183
|
+
contact,
|
|
184
|
+
selected: model.selectedContact?.id === contact.id,
|
|
185
|
+
onClick: () => model.selectContact(contact)
|
|
186
|
+
}, contact.id))] }, letter)), model.filteredContacts.length === 0 && /* @__PURE__ */ jsx("div", {
|
|
187
|
+
className: "flex items-center justify-center h-32 text-gray-400 text-sm",
|
|
188
|
+
children: "No contacts found"
|
|
189
|
+
})]
|
|
190
|
+
}));
|
|
191
|
+
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/contacts/ContactDetail.tsx
|
|
194
|
+
const DetailRow = ({ icon: Icon, label, value }) => /* @__PURE__ */ jsxs("div", {
|
|
195
|
+
className: "flex items-start gap-3 py-2",
|
|
196
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
197
|
+
size: 16,
|
|
198
|
+
className: "text-gray-400 mt-0.5 flex-shrink-0"
|
|
199
|
+
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
|
|
200
|
+
className: "text-xs text-gray-500",
|
|
201
|
+
children: label
|
|
202
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
203
|
+
className: "text-sm text-gray-900",
|
|
204
|
+
children: value
|
|
205
|
+
})] })]
|
|
206
|
+
});
|
|
207
|
+
const ContactDetail = observer(({ model, className = "" }) => {
|
|
208
|
+
const contact = model.selectedContact;
|
|
209
|
+
if (!contact) return /* @__PURE__ */ jsx("div", {
|
|
210
|
+
className: `flex items-center justify-center h-full text-gray-400 text-sm ${className}`,
|
|
211
|
+
children: "Select a contact to view details"
|
|
212
|
+
});
|
|
213
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
214
|
+
className: `p-6 overflow-y-auto ${className}`,
|
|
215
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
216
|
+
className: "flex flex-col items-center mb-6",
|
|
217
|
+
children: [
|
|
218
|
+
/* @__PURE__ */ jsx(ContactAvatar, {
|
|
219
|
+
firstName: contact.firstName,
|
|
220
|
+
lastName: contact.lastName,
|
|
221
|
+
avatar: contact.avatar,
|
|
222
|
+
size: "lg"
|
|
223
|
+
}),
|
|
224
|
+
/* @__PURE__ */ jsxs("h2", {
|
|
225
|
+
className: "mt-3 text-lg font-semibold text-gray-900",
|
|
226
|
+
children: [
|
|
227
|
+
contact.firstName,
|
|
228
|
+
" ",
|
|
229
|
+
contact.lastName
|
|
230
|
+
]
|
|
231
|
+
}),
|
|
232
|
+
contact.company && /* @__PURE__ */ jsx("p", {
|
|
233
|
+
className: "text-sm text-gray-500",
|
|
234
|
+
children: contact.company
|
|
235
|
+
})
|
|
236
|
+
]
|
|
237
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
238
|
+
className: "divide-y divide-gray-100",
|
|
239
|
+
children: [
|
|
240
|
+
contact.email && /* @__PURE__ */ jsx(DetailRow, {
|
|
241
|
+
icon: Mail,
|
|
242
|
+
label: "Email",
|
|
243
|
+
value: contact.email
|
|
244
|
+
}),
|
|
245
|
+
contact.phone && /* @__PURE__ */ jsx(DetailRow, {
|
|
246
|
+
icon: Phone,
|
|
247
|
+
label: "Phone",
|
|
248
|
+
value: contact.phone
|
|
249
|
+
}),
|
|
250
|
+
contact.company && /* @__PURE__ */ jsx(DetailRow, {
|
|
251
|
+
icon: Building,
|
|
252
|
+
label: "Company",
|
|
253
|
+
value: contact.company
|
|
254
|
+
}),
|
|
255
|
+
contact.address && /* @__PURE__ */ jsx(DetailRow, {
|
|
256
|
+
icon: MapPin,
|
|
257
|
+
label: "Address",
|
|
258
|
+
value: contact.address
|
|
259
|
+
}),
|
|
260
|
+
contact.birthday && /* @__PURE__ */ jsx(DetailRow, {
|
|
261
|
+
icon: Calendar,
|
|
262
|
+
label: "Birthday",
|
|
263
|
+
value: contact.birthday.toLocaleDateString()
|
|
264
|
+
}),
|
|
265
|
+
contact.groups && contact.groups.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
266
|
+
className: "flex items-start gap-3 py-2",
|
|
267
|
+
children: [/* @__PURE__ */ jsx(Tag, {
|
|
268
|
+
size: 16,
|
|
269
|
+
className: "text-gray-400 mt-0.5 flex-shrink-0"
|
|
270
|
+
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
|
|
271
|
+
className: "text-xs text-gray-500",
|
|
272
|
+
children: "Groups"
|
|
273
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
274
|
+
className: "flex flex-wrap gap-1 mt-1",
|
|
275
|
+
children: contact.groups.map((g) => /* @__PURE__ */ jsx("span", {
|
|
276
|
+
className: "text-xs bg-gray-100 text-gray-600 px-2 py-0.5 rounded-full",
|
|
277
|
+
children: g
|
|
278
|
+
}, g))
|
|
279
|
+
})] })]
|
|
280
|
+
})
|
|
281
|
+
]
|
|
282
|
+
})]
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
//#endregion
|
|
287
|
+
//#region src/contacts/ContactGroupSidebar.tsx
|
|
288
|
+
const ContactGroupSidebar = observer(({ model, className = "" }) => /* @__PURE__ */ jsx("div", {
|
|
289
|
+
className: `w-56 border-r border-gray-200 bg-gray-50 overflow-y-auto ${className}`,
|
|
290
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
291
|
+
className: "p-3",
|
|
292
|
+
children: [
|
|
293
|
+
/* @__PURE__ */ jsx("h3", {
|
|
294
|
+
className: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2",
|
|
295
|
+
children: "Groups"
|
|
296
|
+
}),
|
|
297
|
+
/* @__PURE__ */ jsxs("button", {
|
|
298
|
+
onClick: () => model.setGroup(null),
|
|
299
|
+
className: `flex items-center gap-2 w-full px-3 py-2 rounded-lg text-sm transition-colors ${model.currentGroup === null ? "bg-blue-100 text-blue-700" : "text-gray-700 hover:bg-gray-100"}`,
|
|
300
|
+
children: [
|
|
301
|
+
/* @__PURE__ */ jsx(Users, { size: 16 }),
|
|
302
|
+
/* @__PURE__ */ jsx("span", { children: "All Contacts" }),
|
|
303
|
+
/* @__PURE__ */ jsx("span", {
|
|
304
|
+
className: "ml-auto text-xs text-gray-400",
|
|
305
|
+
children: model.contacts.length
|
|
306
|
+
})
|
|
307
|
+
]
|
|
308
|
+
}),
|
|
309
|
+
model.groups.map((group) => /* @__PURE__ */ jsxs("button", {
|
|
310
|
+
onClick: () => model.setGroup(group.id),
|
|
311
|
+
className: `flex items-center gap-2 w-full px-3 py-2 rounded-lg text-sm transition-colors ${model.currentGroup === group.id ? "bg-blue-100 text-blue-700" : "text-gray-700 hover:bg-gray-100"}`,
|
|
312
|
+
children: [
|
|
313
|
+
/* @__PURE__ */ jsx(User, { size: 16 }),
|
|
314
|
+
/* @__PURE__ */ jsx("span", {
|
|
315
|
+
className: "truncate",
|
|
316
|
+
title: group.name,
|
|
317
|
+
children: group.name
|
|
318
|
+
}),
|
|
319
|
+
/* @__PURE__ */ jsx("span", {
|
|
320
|
+
className: "ml-auto text-xs text-gray-400",
|
|
321
|
+
children: group.count
|
|
322
|
+
})
|
|
323
|
+
]
|
|
324
|
+
}, group.id))
|
|
325
|
+
]
|
|
326
|
+
})
|
|
327
|
+
}));
|
|
328
|
+
|
|
329
|
+
//#endregion
|
|
330
|
+
//#region src/contacts/ContactBrowser.tsx
|
|
331
|
+
const ContactBrowser = observer(({ model, className = "", showSidebar = true }) => {
|
|
332
|
+
useEffect(() => {
|
|
333
|
+
model.loadContacts();
|
|
334
|
+
}, [model]);
|
|
335
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
336
|
+
className: `flex h-full bg-white rounded-xl border border-gray-200 overflow-hidden ${className}`,
|
|
337
|
+
children: [
|
|
338
|
+
showSidebar && /* @__PURE__ */ jsx(ContactGroupSidebar, { model }),
|
|
339
|
+
/* @__PURE__ */ jsxs("div", {
|
|
340
|
+
className: "flex-1 flex flex-col min-w-0 border-r border-gray-200",
|
|
341
|
+
style: { maxWidth: "380px" },
|
|
342
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
343
|
+
className: "px-4 py-2 border-b border-gray-200",
|
|
344
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
345
|
+
className: "relative",
|
|
346
|
+
children: [/* @__PURE__ */ jsx(Search, {
|
|
347
|
+
size: 16,
|
|
348
|
+
className: "absolute left-3 top-1/2 -translate-y-1/2 text-gray-400"
|
|
349
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
350
|
+
type: "text",
|
|
351
|
+
placeholder: "Search contacts...",
|
|
352
|
+
value: model.searchQuery,
|
|
353
|
+
onChange: (e) => model.setSearch(e.target.value),
|
|
354
|
+
className: "w-full pl-9 pr-3 py-1.5 text-sm border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
355
|
+
})]
|
|
356
|
+
})
|
|
357
|
+
}), model.loading ? /* @__PURE__ */ jsx("div", {
|
|
358
|
+
className: "flex items-center justify-center h-64",
|
|
359
|
+
children: /* @__PURE__ */ jsx(Loader2, {
|
|
360
|
+
size: 24,
|
|
361
|
+
className: "animate-spin text-gray-400"
|
|
362
|
+
})
|
|
363
|
+
}) : model.error ? /* @__PURE__ */ jsx(BrowserError, {
|
|
364
|
+
error: model.error,
|
|
365
|
+
context: "Contacts",
|
|
366
|
+
onRetry: () => model.loadContacts()
|
|
367
|
+
}) : /* @__PURE__ */ jsx(ContactList, {
|
|
368
|
+
model,
|
|
369
|
+
className: "flex-1"
|
|
370
|
+
})]
|
|
371
|
+
}),
|
|
372
|
+
/* @__PURE__ */ jsx(ContactDetail, {
|
|
373
|
+
model,
|
|
374
|
+
className: "flex-1"
|
|
375
|
+
})
|
|
376
|
+
]
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
//#endregion
|
|
381
|
+
//#region src/contacts/MockContactProvider.ts
|
|
382
|
+
const FIRST_NAMES = [
|
|
383
|
+
"Alice",
|
|
384
|
+
"Bob",
|
|
385
|
+
"Charlie",
|
|
386
|
+
"Diana",
|
|
387
|
+
"Emma",
|
|
388
|
+
"Frank",
|
|
389
|
+
"Grace",
|
|
390
|
+
"Henry",
|
|
391
|
+
"Iris",
|
|
392
|
+
"Jack",
|
|
393
|
+
"Karen",
|
|
394
|
+
"Leo",
|
|
395
|
+
"Mia",
|
|
396
|
+
"Nathan",
|
|
397
|
+
"Olivia",
|
|
398
|
+
"Paul",
|
|
399
|
+
"Quinn",
|
|
400
|
+
"Rachel",
|
|
401
|
+
"Sam",
|
|
402
|
+
"Tina",
|
|
403
|
+
"Uma",
|
|
404
|
+
"Victor",
|
|
405
|
+
"Wendy",
|
|
406
|
+
"Xavier",
|
|
407
|
+
"Yara",
|
|
408
|
+
"Zach"
|
|
409
|
+
];
|
|
410
|
+
const LAST_NAMES = [
|
|
411
|
+
"Anderson",
|
|
412
|
+
"Baker",
|
|
413
|
+
"Chen",
|
|
414
|
+
"Davis",
|
|
415
|
+
"Evans",
|
|
416
|
+
"Fisher",
|
|
417
|
+
"Garcia",
|
|
418
|
+
"Hall",
|
|
419
|
+
"Ibrahim",
|
|
420
|
+
"Jones",
|
|
421
|
+
"Kim",
|
|
422
|
+
"Lee",
|
|
423
|
+
"Martinez",
|
|
424
|
+
"Nguyen",
|
|
425
|
+
"O'Brien",
|
|
426
|
+
"Park",
|
|
427
|
+
"Quinn",
|
|
428
|
+
"Robinson",
|
|
429
|
+
"Smith",
|
|
430
|
+
"Taylor",
|
|
431
|
+
"Ueda",
|
|
432
|
+
"Vega",
|
|
433
|
+
"Wilson",
|
|
434
|
+
"Xu",
|
|
435
|
+
"Yang",
|
|
436
|
+
"Zhang"
|
|
437
|
+
];
|
|
438
|
+
const COMPANIES = [
|
|
439
|
+
"Acme Corp",
|
|
440
|
+
"TechStart Inc",
|
|
441
|
+
"Global Systems",
|
|
442
|
+
"DataFlow",
|
|
443
|
+
"CloudNine",
|
|
444
|
+
"PixelPerfect"
|
|
445
|
+
];
|
|
446
|
+
const GROUPS_DATA = [
|
|
447
|
+
{
|
|
448
|
+
id: "family",
|
|
449
|
+
name: "Family",
|
|
450
|
+
count: 8
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
id: "work",
|
|
454
|
+
name: "Work",
|
|
455
|
+
count: 12
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
id: "friends",
|
|
459
|
+
name: "Friends",
|
|
460
|
+
count: 10
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
id: "vip",
|
|
464
|
+
name: "VIP",
|
|
465
|
+
count: 5
|
|
466
|
+
}
|
|
467
|
+
];
|
|
468
|
+
function generateContacts() {
|
|
469
|
+
const contacts = [];
|
|
470
|
+
const now = new Date();
|
|
471
|
+
for (let i = 0; i < FIRST_NAMES.length; i++) contacts.push({
|
|
472
|
+
id: `contact-${i}`,
|
|
473
|
+
type: "contact",
|
|
474
|
+
title: `${FIRST_NAMES[i]} ${LAST_NAMES[i]}`,
|
|
475
|
+
firstName: FIRST_NAMES[i],
|
|
476
|
+
lastName: LAST_NAMES[i],
|
|
477
|
+
email: `${FIRST_NAMES[i].toLowerCase()}.${LAST_NAMES[i].toLowerCase()}@example.com`,
|
|
478
|
+
phone: `+1 (555) ${String(100 + i).padStart(3, "0")}-${String(1e3 + i * 37).slice(0, 4)}`,
|
|
479
|
+
company: COMPANIES[i % COMPANIES.length],
|
|
480
|
+
address: `${100 + i} Main St, City ${i % 10}, ST ${1e4 + i}`,
|
|
481
|
+
birthday: new Date(1985 + i % 20, i % 12, 1 + i % 28),
|
|
482
|
+
groups: [GROUPS_DATA[i % GROUPS_DATA.length].id],
|
|
483
|
+
createdAt: now,
|
|
484
|
+
updatedAt: now
|
|
485
|
+
});
|
|
486
|
+
return contacts;
|
|
487
|
+
}
|
|
488
|
+
var MockContactProvider = class {
|
|
489
|
+
constructor() {
|
|
490
|
+
this.contacts = generateContacts();
|
|
491
|
+
}
|
|
492
|
+
async listItems() {
|
|
493
|
+
return this.contacts;
|
|
494
|
+
}
|
|
495
|
+
async getItem(id) {
|
|
496
|
+
return this.contacts.find((c) => c.id === id) ?? null;
|
|
497
|
+
}
|
|
498
|
+
async createItem(item) {
|
|
499
|
+
const now = new Date();
|
|
500
|
+
const created = {
|
|
501
|
+
...item,
|
|
502
|
+
id: `contact-${Date.now()}`,
|
|
503
|
+
createdAt: now,
|
|
504
|
+
updatedAt: now
|
|
505
|
+
};
|
|
506
|
+
this.contacts.push(created);
|
|
507
|
+
return created;
|
|
508
|
+
}
|
|
509
|
+
async updateItem(id, updates) {
|
|
510
|
+
const idx = this.contacts.findIndex((c) => c.id === id);
|
|
511
|
+
if (idx === -1) throw new Error("Not found");
|
|
512
|
+
this.contacts[idx] = {
|
|
513
|
+
...this.contacts[idx],
|
|
514
|
+
...updates,
|
|
515
|
+
updatedAt: new Date()
|
|
516
|
+
};
|
|
517
|
+
return this.contacts[idx];
|
|
518
|
+
}
|
|
519
|
+
async deleteItem(id) {
|
|
520
|
+
this.contacts = this.contacts.filter((c) => c.id !== id);
|
|
521
|
+
}
|
|
522
|
+
async search(query) {
|
|
523
|
+
const q = query.toLowerCase();
|
|
524
|
+
return this.contacts.filter((c) => c.firstName.toLowerCase().includes(q) || c.lastName.toLowerCase().includes(q));
|
|
525
|
+
}
|
|
526
|
+
async getGroups() {
|
|
527
|
+
return GROUPS_DATA;
|
|
528
|
+
}
|
|
529
|
+
async getByGroup(groupId) {
|
|
530
|
+
return this.contacts.filter((c) => c.groups?.includes(groupId));
|
|
531
|
+
}
|
|
532
|
+
async searchByName(name) {
|
|
533
|
+
return this.search(name);
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
//#endregion
|
|
538
|
+
export { ContactAvatar, ContactBrowser, ContactCard, ContactDetail, ContactGroupSidebar, ContactList, ContactListModel, MockContactProvider };
|
|
539
|
+
//# sourceMappingURL=contacts-DQXTZzHc.js.map
|