@anymux/ui-kit 0.1.0 → 0.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.
Files changed (94) hide show
  1. package/dist/{calendar-DSlrbHoj.js → calendar-DQKfYSQS.js} +48 -45
  2. package/dist/calendar-DQKfYSQS.js.map +1 -0
  3. package/dist/calendar.d.ts +1 -1
  4. package/dist/calendar.js +1 -1
  5. package/dist/{contacts-DQXTZzHc.js → contacts-By9Wg3kn.js} +35 -33
  6. package/dist/contacts-By9Wg3kn.js.map +1 -0
  7. package/dist/contacts.d.ts +1 -1
  8. package/dist/contacts.js +1 -1
  9. package/dist/{file-browser-m5atC3kF.js → file-browser-CkhNwADU.js} +61 -133
  10. package/dist/file-browser-CkhNwADU.js.map +1 -0
  11. package/dist/file-browser.d.ts +6 -6
  12. package/dist/file-browser.js +4 -4
  13. package/dist/{git-B55e6LL-.js → git-m4lboTfx.js} +29 -29
  14. package/dist/git-m4lboTfx.js.map +1 -0
  15. package/dist/git.js +1 -1
  16. package/dist/{iconMap-V4B8P-Uh.js → iconMap-DDpe35ek.js} +5 -5
  17. package/dist/iconMap-DDpe35ek.js.map +1 -0
  18. package/dist/icons.js +1 -1
  19. package/dist/{index-Bryv_GCG.d.ts → index-BP4IYXiF.d.ts} +46 -53
  20. package/dist/index-BP4IYXiF.d.ts.map +1 -0
  21. package/dist/{index-kHr9udZD.d.ts → index-BkIh8oov.d.ts} +17 -17
  22. package/dist/{index-kHr9udZD.d.ts.map → index-BkIh8oov.d.ts.map} +1 -1
  23. package/dist/{index-DSu19mq0.d.ts → index-D3Ob3aXg.d.ts} +9 -9
  24. package/dist/{index-DSu19mq0.d.ts.map → index-D3Ob3aXg.d.ts.map} +1 -1
  25. package/dist/{index-Ml_SgiKa.d.ts → index-DGoLQBX6.d.ts} +18 -42
  26. package/dist/index-DGoLQBX6.d.ts.map +1 -0
  27. package/dist/index-DnJaZr08.d.ts +67 -0
  28. package/dist/index-DnJaZr08.d.ts.map +1 -0
  29. package/dist/{index-DmsyeHFr.d.ts → index-Pty-N7-g.d.ts} +5 -5
  30. package/dist/{index-DmsyeHFr.d.ts.map → index-Pty-N7-g.d.ts.map} +1 -1
  31. package/dist/index.d.ts +7 -7
  32. package/dist/index.js +10 -10
  33. package/dist/layout-BYsc16hD.js +183 -0
  34. package/dist/layout-BYsc16hD.js.map +1 -0
  35. package/dist/layout.d.ts +2 -2
  36. package/dist/layout.js +2 -2
  37. package/dist/{list-CxfT6hix.js → list-DAq-b6RR.js} +49 -63
  38. package/dist/list-DAq-b6RR.js.map +1 -0
  39. package/dist/list.d.ts +2 -2
  40. package/dist/list.js +4 -3
  41. package/dist/{media-DZ292aKK.js → media-DuczOGsk.js} +32 -31
  42. package/dist/media-DuczOGsk.js.map +1 -0
  43. package/dist/media.js +1 -1
  44. package/dist/{tree-Dd9Z0Aso.js → tree-B9VQcKBp.js} +2 -2
  45. package/dist/{tree-Dd9Z0Aso.js.map → tree-B9VQcKBp.js.map} +1 -1
  46. package/dist/tree.d.ts +1 -1
  47. package/dist/tree.js +2 -2
  48. package/package.json +2 -2
  49. package/src/calendar/AgendaView.tsx +2 -2
  50. package/src/calendar/CalendarBrowser.tsx +11 -11
  51. package/src/calendar/CalendarSidebar.tsx +10 -10
  52. package/src/calendar/DayView.tsx +5 -5
  53. package/src/calendar/EventCard.tsx +3 -3
  54. package/src/calendar/MonthView.tsx +6 -6
  55. package/src/calendar/WeekView.tsx +10 -10
  56. package/src/contacts/ContactBrowser.tsx +8 -8
  57. package/src/contacts/ContactCard.tsx +4 -4
  58. package/src/contacts/ContactDetail.tsx +10 -10
  59. package/src/contacts/ContactGroupSidebar.tsx +6 -6
  60. package/src/contacts/ContactList.tsx +3 -3
  61. package/src/file-browser/components/FileBrowser.tsx +3 -2
  62. package/src/file-browser/components/FileBrowserContent.tsx +1 -1
  63. package/src/file-browser/examples/BasicUsage.tsx +2 -2
  64. package/src/file-browser/index.ts +1 -1
  65. package/src/file-browser/providers/FileSystemProvider.ts +1 -1
  66. package/src/git/BranchList.tsx +12 -12
  67. package/src/git/CommitList.tsx +11 -11
  68. package/src/git/DiffViewer.tsx +11 -11
  69. package/src/icons/iconMap.ts +4 -4
  70. package/src/layout/index.ts +6 -2
  71. package/src/layout/models/ResponsiveLayoutModel.ts +116 -0
  72. package/src/list/components/ListItem.tsx +1 -1
  73. package/src/list/index.ts +1 -1
  74. package/src/media/AlbumSidebar.tsx +4 -4
  75. package/src/media/MediaBrowser.tsx +11 -11
  76. package/src/media/MediaGrid.tsx +3 -3
  77. package/src/media/MediaList.tsx +6 -6
  78. package/src/media/MediaPreview.tsx +2 -2
  79. package/src/media/MediaTimeline.tsx +3 -3
  80. package/src/{file-browser/components/shared → shared}/ErrorBoundary.tsx +3 -3
  81. package/dist/calendar-DSlrbHoj.js.map +0 -1
  82. package/dist/contacts-DQXTZzHc.js.map +0 -1
  83. package/dist/file-browser-m5atC3kF.js.map +0 -1
  84. package/dist/git-B55e6LL-.js.map +0 -1
  85. package/dist/iconMap-V4B8P-Uh.js.map +0 -1
  86. package/dist/index-Bryv_GCG.d.ts.map +0 -1
  87. package/dist/index-DzfY1Tok.d.ts +0 -32
  88. package/dist/index-DzfY1Tok.d.ts.map +0 -1
  89. package/dist/index-Ml_SgiKa.d.ts.map +0 -1
  90. package/dist/layout-Ca_4r8ka.js +0 -89
  91. package/dist/layout-Ca_4r8ka.js.map +0 -1
  92. package/dist/list-CxfT6hix.js.map +0 -1
  93. package/dist/media-DZ292aKK.js.map +0 -1
  94. package/src/list/components/shared/ErrorBoundary.tsx +0 -123
package/dist/tree.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { CheckboxState, DEFAULT_SELECTION_THEME$1 as DEFAULT_SELECTION_THEME, FocusIndicatorStyle, SelectionColorScheme, SelectionIntensity, SimpleTreeProvider$1 as SimpleTreeProvider, TestTreeProvider$1 as TestTreeProvider, Tree$1 as Tree, TreeCheckbox$1 as TreeCheckbox, TreeContextMenu$1 as TreeContextMenu, TreeContextMenuEvent, TreeContextMenuItem, TreeContextMenuProps, TreeDragDropInfo, TreeLoadOptions, TreeLoadResult, TreeModel$1 as TreeModel, TreeNodeData, TreeNodeList$1 as TreeNodeList, TreeNodeListProps, TreeNodeRenderer, TreeProps, TreeProvider, TreeSelectionInfo, TreeSelectionTheme, TreeTable$1 as TreeTable, TreeTableColumn, TreeTableExportOptions, TreeTableProps, TreeTableSort, getCustomColorVariables$1 as getCustomColorVariables, getSelectionClasses$1 as getSelectionClasses, logger$1 as logger } from "./index-kHr9udZD.js";
1
+ import { CheckboxState, DEFAULT_SELECTION_THEME$1 as DEFAULT_SELECTION_THEME, FocusIndicatorStyle, SelectionColorScheme, SelectionIntensity, SimpleTreeProvider$1 as SimpleTreeProvider, TestTreeProvider$1 as TestTreeProvider, Tree$1 as Tree, TreeCheckbox$1 as TreeCheckbox, TreeContextMenu$1 as TreeContextMenu, TreeContextMenuEvent, TreeContextMenuItem, TreeContextMenuProps, TreeDragDropInfo, TreeLoadOptions, TreeLoadResult, TreeModel$1 as TreeModel, TreeNodeData, TreeNodeList$1 as TreeNodeList, TreeNodeListProps, TreeNodeRenderer, TreeProps, TreeProvider, TreeSelectionInfo, TreeSelectionTheme, TreeTable$1 as TreeTable, TreeTableColumn, TreeTableExportOptions, TreeTableProps, TreeTableSort, getCustomColorVariables$1 as getCustomColorVariables, getSelectionClasses$1 as getSelectionClasses, logger$1 as logger } from "./index-BkIh8oov.js";
2
2
  export { CheckboxState, DEFAULT_SELECTION_THEME, FocusIndicatorStyle, SelectionColorScheme, SelectionIntensity, SimpleTreeProvider, TestTreeProvider, Tree, TreeCheckbox, TreeContextMenu, TreeContextMenuEvent, TreeContextMenuItem, TreeContextMenuProps, TreeDragDropInfo, TreeLoadOptions, TreeLoadResult, TreeModel, TreeNodeData, TreeNodeList, TreeNodeListProps, TreeNodeRenderer, TreeProps, TreeProvider, TreeSelectionInfo, TreeSelectionTheme, TreeTable, TreeTableColumn, TreeTableExportOptions, TreeTableProps, TreeTableSort, getCustomColorVariables, getSelectionClasses, logger };
package/dist/tree.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import "./utils-B4fdKKsy.js";
2
- import { DEFAULT_SELECTION_THEME, SimpleTreeProvider, TestTreeProvider, Tree, TreeCheckbox, TreeContextMenu, TreeModel, TreeNodeList, TreeTable, getCustomColorVariables, getSelectionClasses, logger } from "./tree-Dd9Z0Aso.js";
3
- import "./iconMap-V4B8P-Uh.js";
2
+ import { DEFAULT_SELECTION_THEME, SimpleTreeProvider, TestTreeProvider, Tree, TreeCheckbox, TreeContextMenu, TreeModel, TreeNodeList, TreeTable, getCustomColorVariables, getSelectionClasses, logger } from "./tree-B9VQcKBp.js";
3
+ import "./iconMap-DDpe35ek.js";
4
4
  import "./FileBrowserContext-B6jixa2j.js";
5
5
 
6
6
  export { DEFAULT_SELECTION_THEME, SimpleTreeProvider, TestTreeProvider, Tree, TreeCheckbox, TreeContextMenu, TreeModel, TreeNodeList, TreeTable, getCustomColorVariables, getSelectionClasses, logger };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anymux/ui-kit",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Composite UI components for AnyMux — file browser, media, calendar, contacts, git",
@@ -84,10 +84,10 @@
84
84
  "squarify": "^1.1.0",
85
85
  "tailwind-merge": "^2.2.1",
86
86
  "transformation-matrix": "^3.1.0",
87
- "@anymux/file-system": "0.1.0",
88
87
  "@anymux/ui": "0.1.0"
89
88
  },
90
89
  "peerDependencies": {
90
+ "@anymux/file-system": ">=0.1.0",
91
91
  "mobx": "^6.13.5",
92
92
  "mobx-react-lite": "^4.0.7",
93
93
  "react": "^19.0.0",
@@ -15,13 +15,13 @@ export const AgendaView = observer<AgendaViewProps>(({ model, className = '' })
15
15
  return (
16
16
  <div className={`overflow-y-auto p-4 space-y-4 ${className}`}>
17
17
  {sortedEntries.length === 0 && (
18
- <div className="flex items-center justify-center h-32 text-gray-400 text-sm">No upcoming events</div>
18
+ <div className="flex items-center justify-center h-32 text-muted-foreground text-sm">No upcoming events</div>
19
19
  )}
20
20
  {sortedEntries.map(([dateKey, events]) => {
21
21
  const date = new Date(dateKey + 'T00:00:00');
22
22
  return (
23
23
  <div key={dateKey}>
24
- <h3 className="text-sm font-semibold text-gray-700 mb-2 sticky top-0 bg-white/90 backdrop-blur-sm py-1">
24
+ <h3 className="text-sm font-semibold text-foreground mb-2 sticky top-0 bg-background/90 backdrop-blur-sm py-1">
25
25
  {date.toLocaleDateString(undefined, { weekday: 'long', month: 'long', day: 'numeric' })}
26
26
  </h3>
27
27
  <div className="space-y-1.5">
@@ -26,35 +26,35 @@ export const CalendarBrowser = observer<CalendarBrowserProps>(({ model, classNam
26
26
  useEffect(() => { model.loadEvents(); }, [model]);
27
27
 
28
28
  return (
29
- <div className={`flex h-full bg-white rounded-xl border border-gray-200 overflow-hidden ${className}`}>
30
- {showSidebar && <CalendarSidebar model={model} />}
29
+ <div className={`flex h-full bg-background rounded-xl border border-border overflow-hidden ${className}`}>
30
+ {showSidebar && <CalendarSidebar model={model} className="hidden md:block" />}
31
31
 
32
32
  <div className="flex-1 flex flex-col min-w-0">
33
33
  {/* Toolbar */}
34
- <div className="flex items-center gap-2 px-4 py-2 border-b border-gray-200">
35
- <button onClick={() => model.today()} className="text-sm px-3 py-1.5 border border-gray-200 rounded-lg hover:bg-gray-50">
34
+ <div className="flex items-center gap-1.5 sm:gap-2 px-3 py-2 border-b border-border flex-wrap sm:flex-nowrap">
35
+ <button onClick={() => model.today()} className="text-sm px-3 py-1.5 border border-border rounded-lg hover:bg-muted">
36
36
  Today
37
37
  </button>
38
- <button onClick={() => model.navigateBack()} className="p-1.5 hover:bg-gray-100 rounded-lg">
38
+ <button onClick={() => model.navigateBack()} className="p-1.5 hover:bg-muted rounded-lg">
39
39
  <ChevronLeft size={16} />
40
40
  </button>
41
- <button onClick={() => model.navigateForward()} className="p-1.5 hover:bg-gray-100 rounded-lg">
41
+ <button onClick={() => model.navigateForward()} className="p-1.5 hover:bg-muted rounded-lg">
42
42
  <ChevronRight size={16} />
43
43
  </button>
44
- <h2 className="text-sm font-medium text-gray-900 ml-2">
44
+ <h2 className="text-sm font-medium text-foreground ml-2 truncate">
45
45
  {model.currentDate.toLocaleDateString(undefined, {
46
46
  month: 'long',
47
47
  year: 'numeric',
48
48
  ...(model.viewMode === 'day' ? { day: 'numeric', weekday: 'long' } : {})
49
49
  })}
50
50
  </h2>
51
- <div className="ml-auto flex items-center border border-gray-200 rounded-lg overflow-hidden">
51
+ <div className="ml-auto flex items-center border border-border rounded-lg overflow-hidden">
52
52
  {(Object.keys(VIEW_LABELS) as CalendarViewMode[]).map(mode => (
53
53
  <button
54
54
  key={mode}
55
55
  onClick={() => model.setViewMode(mode)}
56
- className={`px-3 py-1.5 text-xs font-medium ${
57
- model.viewMode === mode ? 'bg-blue-50 text-blue-600' : 'text-gray-500 hover:bg-gray-50'
56
+ className={`px-2 sm:px-3 py-1.5 text-xs font-medium ${
57
+ model.viewMode === mode ? 'bg-primary/10 text-primary' : 'text-muted-foreground hover:bg-muted'
58
58
  }`}
59
59
  >
60
60
  {VIEW_LABELS[mode]}
@@ -67,7 +67,7 @@ export const CalendarBrowser = observer<CalendarBrowserProps>(({ model, classNam
67
67
  <div className="flex-1 overflow-hidden">
68
68
  {model.loading ? (
69
69
  <div className="flex items-center justify-center h-64">
70
- <Loader2 size={24} className="animate-spin text-gray-400" />
70
+ <Loader2 size={24} className="animate-spin text-muted-foreground" />
71
71
  </div>
72
72
  ) : model.error ? (
73
73
  <BrowserError
@@ -30,23 +30,23 @@ export const CalendarSidebar = observer<CalendarSidebarProps>(({ model, classNam
30
30
  day === d.getDate();
31
31
 
32
32
  return (
33
- <div className={`w-56 border-r border-gray-200 bg-gray-50 p-3 ${className}`}>
33
+ <div className={`w-56 border-r border-border bg-muted/30 p-3 ${className}`}>
34
34
  {/* Mini month */}
35
35
  <div className="mb-4">
36
36
  <div className="flex items-center justify-between mb-2">
37
- <button onClick={() => model.navigateBack()} className="p-1 hover:bg-gray-200 rounded">
37
+ <button onClick={() => model.navigateBack()} className="p-1 hover:bg-muted rounded">
38
38
  <ChevronLeft size={14} />
39
39
  </button>
40
- <span className="text-sm font-medium">
40
+ <span className="text-sm font-medium text-foreground">
41
41
  {d.toLocaleDateString(undefined, { month: 'long', year: 'numeric' })}
42
42
  </span>
43
- <button onClick={() => model.navigateForward()} className="p-1 hover:bg-gray-200 rounded">
43
+ <button onClick={() => model.navigateForward()} className="p-1 hover:bg-muted rounded">
44
44
  <ChevronRight size={14} />
45
45
  </button>
46
46
  </div>
47
47
  <div className="grid grid-cols-7 gap-0.5 text-center">
48
48
  {DAYS.map(day => (
49
- <div key={day} className="text-[10px] text-gray-400 font-medium py-0.5">{day}</div>
49
+ <div key={day} className="text-[10px] text-muted-foreground font-medium py-0.5">{day}</div>
50
50
  ))}
51
51
  {cells.map((day, i) => (
52
52
  <button
@@ -55,9 +55,9 @@ export const CalendarSidebar = observer<CalendarSidebarProps>(({ model, classNam
55
55
  onClick={() => day && model.setDate(new Date(year, month, day))}
56
56
  className={`text-xs py-0.5 rounded ${
57
57
  day === null ? '' :
58
- isSelected(day) ? 'bg-blue-500 text-white' :
59
- isToday(day) ? 'bg-blue-100 text-blue-700 font-bold' :
60
- 'text-gray-700 hover:bg-gray-200'
58
+ isSelected(day) ? 'bg-primary text-primary-foreground' :
59
+ isToday(day) ? 'bg-primary/10 text-primary font-bold' :
60
+ 'text-foreground hover:bg-muted'
61
61
  }`}
62
62
  >
63
63
  {day}
@@ -68,9 +68,9 @@ export const CalendarSidebar = observer<CalendarSidebarProps>(({ model, classNam
68
68
 
69
69
  {/* Calendar list */}
70
70
  <div>
71
- <h3 className="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2">Calendars</h3>
71
+ <h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">Calendars</h3>
72
72
  {model.calendars.map(cal => (
73
- <div key={cal.id} className="flex items-center gap-2 px-2 py-1.5 text-sm text-gray-700">
73
+ <div key={cal.id} className="flex items-center gap-2 px-2 py-1.5 text-sm text-foreground">
74
74
  <div className="w-3 h-3 rounded-full" style={{ backgroundColor: cal.color }} />
75
75
  <span className="truncate" title={cal.name}>{cal.name}</span>
76
76
  </div>
@@ -19,8 +19,8 @@ export const DayView = observer<DayViewProps>(({ model, className = '' }) => {
19
19
  return (
20
20
  <div className={`flex flex-col h-full overflow-auto ${className}`}>
21
21
  {/* Header */}
22
- <div className="border-b border-gray-200 px-4 py-2 sticky top-0 bg-white z-10">
23
- <h2 className="text-lg font-medium text-gray-900">
22
+ <div className="border-b border-border px-4 py-2 sticky top-0 bg-background z-10">
23
+ <h2 className="text-lg font-medium text-foreground">
24
24
  {d.toLocaleDateString(undefined, { weekday: 'long', month: 'long', day: 'numeric' })}
25
25
  </h2>
26
26
  {allDayEvents.length > 0 && (
@@ -44,11 +44,11 @@ export const DayView = observer<DayViewProps>(({ model, className = '' }) => {
44
44
  {HOURS.map(hour => {
45
45
  const hourEvents = timedEvents.filter(e => e.startDate.getHours() === hour);
46
46
  return (
47
- <div key={hour} className="grid grid-cols-[60px_1fr] border-b border-gray-50 min-h-[48px]">
48
- <div className="text-[10px] text-gray-400 text-right pr-2 -mt-2">
47
+ <div key={hour} className="grid grid-cols-[60px_1fr] border-b border-border/50 min-h-[48px]">
48
+ <div className="text-[10px] text-muted-foreground text-right pr-2 -mt-2">
49
49
  {hour === 0 ? '' : `${hour % 12 || 12} ${hour < 12 ? 'AM' : 'PM'}`}
50
50
  </div>
51
- <div className="border-l border-gray-100 relative pl-1">
51
+ <div className="border-l border-border relative pl-1">
52
52
  {hourEvents.map(ev => (
53
53
  <button
54
54
  key={ev.id}
@@ -30,11 +30,11 @@ export const EventCard = ({ event, compact = false, onClick, className = '' }: E
30
30
  return (
31
31
  <button
32
32
  onClick={onClick}
33
- className={`text-left w-full p-3 rounded-lg border border-gray-200 hover:shadow-sm transition-shadow ${className}`}
33
+ className={`text-left w-full p-3 rounded-lg border border-border hover:shadow-sm transition-shadow ${className}`}
34
34
  style={{ borderLeftWidth: '3px', borderLeftColor: color }}
35
35
  >
36
- <p className="text-sm font-medium text-gray-900 truncate" title={event.title}>{event.title}</p>
37
- <div className="mt-1 flex items-center gap-3 text-xs text-gray-500">
36
+ <p className="text-sm font-medium text-foreground truncate" title={event.title}>{event.title}</p>
37
+ <div className="mt-1 flex items-center gap-3 text-xs text-muted-foreground">
38
38
  <span className="flex items-center gap-1">
39
39
  <Clock size={12} />
40
40
  {event.allDay ? 'All day' : `${formatTime(event.startDate)} - ${formatTime(event.endDate)}`}
@@ -36,23 +36,23 @@ export const MonthView = observer<MonthViewProps>(({ model, className = '' }) =>
36
36
 
37
37
  return (
38
38
  <div className={`flex flex-col h-full ${className}`}>
39
- <div className="grid grid-cols-7 border-b border-gray-200">
39
+ <div className="grid grid-cols-7 border-b border-border">
40
40
  {DAYS.map(day => (
41
- <div key={day} className="px-2 py-2 text-xs font-medium text-gray-500 text-center">{day.slice(0, 3)}</div>
41
+ <div key={day} className="px-2 py-2 text-xs font-medium text-muted-foreground text-center">{day.slice(0, 3)}</div>
42
42
  ))}
43
43
  </div>
44
44
  <div className="flex-1 grid grid-rows-[repeat(auto-fill,1fr)]">
45
45
  {weeks.map((week, wi) => (
46
- <div key={wi} className="grid grid-cols-7 border-b border-gray-100 min-h-[80px]">
46
+ <div key={wi} className="grid grid-cols-7 border-b border-border min-h-[80px]">
47
47
  {week.map((day, di) => {
48
48
  const dateKey = day ? `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}` : null;
49
49
  const events = dateKey ? (model.eventsByDay.get(dateKey) ?? []) : [];
50
50
  return (
51
- <div key={di} className={`border-r border-gray-100 p-1 ${day === null ? 'bg-gray-50' : ''}`}>
51
+ <div key={di} className={`border-r border-border p-1 ${day === null ? 'bg-muted/50' : ''}`}>
52
52
  {day !== null && (
53
53
  <>
54
54
  <div className={`text-xs mb-0.5 w-6 h-6 flex items-center justify-center rounded-full ${
55
- isToday(day) ? 'bg-blue-500 text-white font-bold' : 'text-gray-700'
55
+ isToday(day) ? 'bg-primary text-white font-bold' : 'text-foreground'
56
56
  }`}>
57
57
  {day}
58
58
  </div>
@@ -61,7 +61,7 @@ export const MonthView = observer<MonthViewProps>(({ model, className = '' }) =>
61
61
  <EventCard key={ev.id} event={ev} compact onClick={() => model.selectEvent(ev)} />
62
62
  ))}
63
63
  {events.length > 3 && (
64
- <p className="text-[10px] text-gray-400 pl-1">+{events.length - 3} more</p>
64
+ <p className="text-[10px] text-muted-foreground pl-1">+{events.length - 3} more</p>
65
65
  )}
66
66
  </div>
67
67
  </>
@@ -32,23 +32,23 @@ export const WeekView = observer<WeekViewProps>(({ model, className = '' }) => {
32
32
  return (
33
33
  <div className={`flex flex-col h-full overflow-auto ${className}`}>
34
34
  {/* Day headers */}
35
- <div className="sticky top-0 bg-white z-10 border-b border-gray-200">
35
+ <div className="sticky top-0 bg-background z-10 border-b border-border">
36
36
  <div className="grid" style={{ gridTemplateColumns: '60px repeat(7, 1fr)' }}>
37
37
  <div />
38
38
  {days.map((d, i) => (
39
- <div key={i} className={`text-center py-2 border-l border-gray-100 ${isToday(d) ? 'bg-blue-50' : ''}`}>
40
- <div className="text-xs text-gray-500">{d.toLocaleDateString(undefined, { weekday: 'short' })}</div>
41
- <div className={`text-lg font-medium ${isToday(d) ? 'text-blue-600' : 'text-gray-900'}`}>{d.getDate()}</div>
39
+ <div key={i} className={`text-center py-2 border-l border-border ${isToday(d) ? 'bg-primary/10' : ''}`}>
40
+ <div className="text-xs text-muted-foreground">{d.toLocaleDateString(undefined, { weekday: 'short' })}</div>
41
+ <div className={`text-lg font-medium ${isToday(d) ? 'text-primary' : 'text-foreground'}`}>{d.getDate()}</div>
42
42
  </div>
43
43
  ))}
44
44
  </div>
45
45
 
46
46
  {/* All-day events row */}
47
47
  {hasAllDay && (
48
- <div className="grid border-t border-gray-100" style={{ gridTemplateColumns: '60px repeat(7, 1fr)' }}>
49
- <div className="text-[10px] text-gray-400 text-right pr-2 py-1">all-day</div>
48
+ <div className="grid border-t border-border" style={{ gridTemplateColumns: '60px repeat(7, 1fr)' }}>
49
+ <div className="text-[10px] text-muted-foreground text-right pr-2 py-1">all-day</div>
50
50
  {allDayEventsByDay.map((events, i) => (
51
- <div key={i} className="border-l border-gray-100 px-0.5 py-0.5 space-y-0.5">
51
+ <div key={i} className="border-l border-border px-0.5 py-0.5 space-y-0.5">
52
52
  {events.map(ev => (
53
53
  <button
54
54
  key={ev.id}
@@ -73,8 +73,8 @@ export const WeekView = observer<WeekViewProps>(({ model, className = '' }) => {
73
73
  {/* Time grid */}
74
74
  <div className="flex-1 relative">
75
75
  {HOURS.map(hour => (
76
- <div key={hour} className="grid border-b border-gray-50" style={{ gridTemplateColumns: '60px repeat(7, 1fr)', height: '48px' }}>
77
- <div className="text-[10px] text-gray-400 text-right pr-2 -mt-2">
76
+ <div key={hour} className="grid border-b border-border/50" style={{ gridTemplateColumns: '60px repeat(7, 1fr)', height: '48px' }}>
77
+ <div className="text-[10px] text-muted-foreground text-right pr-2 -mt-2">
78
78
  {hour === 0 ? '' : `${hour % 12 || 12} ${hour < 12 ? 'AM' : 'PM'}`}
79
79
  </div>
80
80
  {days.map((d, i) => {
@@ -84,7 +84,7 @@ export const WeekView = observer<WeekViewProps>(({ model, className = '' }) => {
84
84
  );
85
85
  const showTimeLine = isToday(d) && hour === currentHour;
86
86
  return (
87
- <div key={i} className="border-l border-gray-100 relative">
87
+ <div key={i} className="border-l border-border relative">
88
88
  {/* Current time indicator */}
89
89
  {showTimeLine && (
90
90
  <div
@@ -17,27 +17,27 @@ export const ContactBrowser = observer<ContactBrowserProps>(({ model, className
17
17
  useEffect(() => { model.loadContacts(); }, [model]);
18
18
 
19
19
  return (
20
- <div className={`flex h-full bg-white rounded-xl border border-gray-200 overflow-hidden ${className}`}>
21
- {showSidebar && <ContactGroupSidebar model={model} />}
20
+ <div className={`flex h-full bg-background rounded-xl border border-border overflow-hidden ${className}`}>
21
+ {showSidebar && <ContactGroupSidebar model={model} className="hidden lg:block" />}
22
22
 
23
- <div className="flex-1 flex flex-col min-w-0 border-r border-gray-200" style={{ maxWidth: '380px' }}>
23
+ <div className="flex-1 flex flex-col min-w-0 border-r border-border sm:max-w-[380px]">
24
24
  {/* Search */}
25
- <div className="px-4 py-2 border-b border-gray-200">
25
+ <div className="px-3 py-2 border-b border-border">
26
26
  <div className="relative">
27
- <Search size={16} className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
27
+ <Search size={16} className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground" />
28
28
  <input
29
29
  type="text"
30
30
  placeholder="Search contacts..."
31
31
  value={model.searchQuery}
32
32
  onChange={e => model.setSearch(e.target.value)}
33
- 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"
33
+ className="w-full pl-9 pr-3 py-1.5 text-sm border border-border rounded-lg bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-ring"
34
34
  />
35
35
  </div>
36
36
  </div>
37
37
 
38
38
  {model.loading ? (
39
39
  <div className="flex items-center justify-center h-64">
40
- <Loader2 size={24} className="animate-spin text-gray-400" />
40
+ <Loader2 size={24} className="animate-spin text-muted-foreground" />
41
41
  </div>
42
42
  ) : model.error ? (
43
43
  <BrowserError
@@ -50,7 +50,7 @@ export const ContactBrowser = observer<ContactBrowserProps>(({ model, className
50
50
  )}
51
51
  </div>
52
52
 
53
- <ContactDetail model={model} className="flex-1" />
53
+ <ContactDetail model={model} className="flex-1 hidden sm:block" />
54
54
  </div>
55
55
  );
56
56
  });
@@ -14,22 +14,22 @@ export const ContactCard = ({ contact, selected = false, onClick, className = ''
14
14
  <button
15
15
  onClick={onClick}
16
16
  className={`flex items-center gap-3 px-4 py-3 w-full text-left transition-colors ${
17
- selected ? 'bg-blue-50 border-l-2 border-blue-500' : 'hover:bg-gray-50 border-l-2 border-transparent'
17
+ selected ? 'bg-primary/10 border-l-2 border-primary' : 'hover:bg-muted/50 border-l-2 border-transparent'
18
18
  } ${className}`}
19
19
  >
20
20
  <ContactAvatar firstName={contact.firstName} lastName={contact.lastName} avatar={contact.avatar} />
21
21
  <div className="flex-1 min-w-0">
22
- <p className="text-sm font-medium text-gray-900 truncate" title={`${contact.firstName} ${contact.lastName}`}>
22
+ <p className="text-sm font-medium text-foreground truncate" title={`${contact.firstName} ${contact.lastName}`}>
23
23
  {contact.firstName} {contact.lastName}
24
24
  </p>
25
25
  {contact.company && (
26
- <p className="text-xs text-gray-500 flex items-center gap-1 truncate" title={contact.company}>
26
+ <p className="text-xs text-muted-foreground flex items-center gap-1 truncate" title={contact.company}>
27
27
  <Building size={12} />
28
28
  {contact.company}
29
29
  </p>
30
30
  )}
31
31
  </div>
32
- <div className="flex items-center gap-1.5 text-gray-400">
32
+ <div className="flex items-center gap-1.5 text-muted-foreground">
33
33
  {contact.email && <Mail size={14} />}
34
34
  {contact.phone && <Phone size={14} />}
35
35
  </div>
@@ -11,10 +11,10 @@ export interface ContactDetailProps {
11
11
 
12
12
  const DetailRow = ({ icon: Icon, label, value }: { icon: React.ElementType; label: string; value: string }) => (
13
13
  <div className="flex items-start gap-3 py-2">
14
- <Icon size={16} className="text-gray-400 mt-0.5 flex-shrink-0" />
14
+ <Icon size={16} className="text-muted-foreground mt-0.5 flex-shrink-0" />
15
15
  <div>
16
- <p className="text-xs text-gray-500">{label}</p>
17
- <p className="text-sm text-gray-900">{value}</p>
16
+ <p className="text-xs text-muted-foreground">{label}</p>
17
+ <p className="text-sm text-foreground">{value}</p>
18
18
  </div>
19
19
  </div>
20
20
  );
@@ -24,7 +24,7 @@ export const ContactDetail = observer<ContactDetailProps>(({ model, className =
24
24
 
25
25
  if (!contact) {
26
26
  return (
27
- <div className={`flex items-center justify-center h-full text-gray-400 text-sm ${className}`}>
27
+ <div className={`flex items-center justify-center h-full text-muted-foreground text-sm ${className}`}>
28
28
  Select a contact to view details
29
29
  </div>
30
30
  );
@@ -34,11 +34,11 @@ export const ContactDetail = observer<ContactDetailProps>(({ model, className =
34
34
  <div className={`p-6 overflow-y-auto ${className}`}>
35
35
  <div className="flex flex-col items-center mb-6">
36
36
  <ContactAvatar firstName={contact.firstName} lastName={contact.lastName} avatar={contact.avatar} size="lg" />
37
- <h2 className="mt-3 text-lg font-semibold text-gray-900">{contact.firstName} {contact.lastName}</h2>
38
- {contact.company && <p className="text-sm text-gray-500">{contact.company}</p>}
37
+ <h2 className="mt-3 text-lg font-semibold text-foreground">{contact.firstName} {contact.lastName}</h2>
38
+ {contact.company && <p className="text-sm text-muted-foreground">{contact.company}</p>}
39
39
  </div>
40
40
 
41
- <div className="divide-y divide-gray-100">
41
+ <div className="divide-y divide-border">
42
42
  {contact.email && <DetailRow icon={Mail} label="Email" value={contact.email} />}
43
43
  {contact.phone && <DetailRow icon={Phone} label="Phone" value={contact.phone} />}
44
44
  {contact.company && <DetailRow icon={Building} label="Company" value={contact.company} />}
@@ -46,12 +46,12 @@ export const ContactDetail = observer<ContactDetailProps>(({ model, className =
46
46
  {contact.birthday && <DetailRow icon={Calendar} label="Birthday" value={contact.birthday.toLocaleDateString()} />}
47
47
  {contact.groups && contact.groups.length > 0 && (
48
48
  <div className="flex items-start gap-3 py-2">
49
- <Tag size={16} className="text-gray-400 mt-0.5 flex-shrink-0" />
49
+ <Tag size={16} className="text-muted-foreground mt-0.5 flex-shrink-0" />
50
50
  <div>
51
- <p className="text-xs text-gray-500">Groups</p>
51
+ <p className="text-xs text-muted-foreground">Groups</p>
52
52
  <div className="flex flex-wrap gap-1 mt-1">
53
53
  {contact.groups.map(g => (
54
- <span key={g} className="text-xs bg-gray-100 text-gray-600 px-2 py-0.5 rounded-full">{g}</span>
54
+ <span key={g} className="text-xs bg-muted text-muted-foreground px-2 py-0.5 rounded-full">{g}</span>
55
55
  ))}
56
56
  </div>
57
57
  </div>
@@ -9,30 +9,30 @@ export interface ContactGroupSidebarProps {
9
9
  }
10
10
 
11
11
  export const ContactGroupSidebar = observer<ContactGroupSidebarProps>(({ model, className = '' }) => (
12
- <div className={`w-56 border-r border-gray-200 bg-gray-50 overflow-y-auto ${className}`}>
12
+ <div className={`w-56 border-r border-border bg-muted/30 overflow-y-auto ${className}`}>
13
13
  <div className="p-3">
14
- <h3 className="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2">Groups</h3>
14
+ <h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">Groups</h3>
15
15
  <button
16
16
  onClick={() => model.setGroup(null)}
17
17
  className={`flex items-center gap-2 w-full px-3 py-2 rounded-lg text-sm transition-colors ${
18
- model.currentGroup === null ? 'bg-blue-100 text-blue-700' : 'text-gray-700 hover:bg-gray-100'
18
+ model.currentGroup === null ? 'bg-primary/10 text-primary' : 'text-foreground hover:bg-muted'
19
19
  }`}
20
20
  >
21
21
  <Users size={16} />
22
22
  <span>All Contacts</span>
23
- <span className="ml-auto text-xs text-gray-400">{model.contacts.length}</span>
23
+ <span className="ml-auto text-xs text-muted-foreground">{model.contacts.length}</span>
24
24
  </button>
25
25
  {model.groups.map(group => (
26
26
  <button
27
27
  key={group.id}
28
28
  onClick={() => model.setGroup(group.id)}
29
29
  className={`flex items-center gap-2 w-full px-3 py-2 rounded-lg text-sm transition-colors ${
30
- model.currentGroup === group.id ? 'bg-blue-100 text-blue-700' : 'text-gray-700 hover:bg-gray-100'
30
+ model.currentGroup === group.id ? 'bg-primary/10 text-primary' : 'text-foreground hover:bg-muted'
31
31
  }`}
32
32
  >
33
33
  <User size={16} />
34
34
  <span className="truncate" title={group.name}>{group.name}</span>
35
- <span className="ml-auto text-xs text-gray-400">{group.count}</span>
35
+ <span className="ml-auto text-xs text-muted-foreground">{group.count}</span>
36
36
  </button>
37
37
  ))}
38
38
  </div>
@@ -12,8 +12,8 @@ export const ContactList = observer<ContactListProps>(({ model, className = '' }
12
12
  <div className={`overflow-y-auto ${className}`}>
13
13
  {Array.from(model.groupedByLetter.entries()).map(([letter, contacts]) => (
14
14
  <div key={letter}>
15
- <div className="sticky top-0 bg-gray-50/90 backdrop-blur-sm px-4 py-1 border-b border-gray-100">
16
- <span className="text-xs font-semibold text-gray-500">{letter}</span>
15
+ <div className="sticky top-0 bg-muted/50 backdrop-blur-sm px-4 py-1 border-b border-border">
16
+ <span className="text-xs font-semibold text-muted-foreground">{letter}</span>
17
17
  </div>
18
18
  {contacts.map(contact => (
19
19
  <ContactCard
@@ -26,7 +26,7 @@ export const ContactList = observer<ContactListProps>(({ model, className = '' }
26
26
  </div>
27
27
  ))}
28
28
  {model.filteredContacts.length === 0 && (
29
- <div className="flex items-center justify-center h-32 text-gray-400 text-sm">No contacts found</div>
29
+ <div className="flex items-center justify-center h-32 text-muted-foreground text-sm">No contacts found</div>
30
30
  )}
31
31
  </div>
32
32
  ));
@@ -177,6 +177,7 @@ export const FileBrowser: React.FC<FileBrowserProps> = observer(({
177
177
  onClick={() => model.navigateToPrevFile()}
178
178
  disabled={!model.canNavigatePrev}
179
179
  title="Previous file (left arrow)"
180
+ aria-label="Previous file"
180
181
  >
181
182
  <ChevronLeft className="w-4 h-4" />
182
183
  </Button>
@@ -412,8 +413,8 @@ export const FileBrowser: React.FC<FileBrowserProps> = observer(({
412
413
  >
413
414
  {/* Native file drop overlay */}
414
415
  {isDragOver && (
415
- <div className="absolute inset-0 z-50 bg-blue-500/10 border-2 border-dashed border-blue-500 rounded-lg flex items-center justify-center pointer-events-none">
416
- <div className="flex flex-col items-center gap-2 text-blue-600 dark:text-blue-400">
416
+ <div className="absolute inset-0 z-50 bg-primary/10 border-2 border-dashed border-primary rounded-lg flex items-center justify-center pointer-events-none">
417
+ <div className="flex flex-col items-center gap-2 text-primary">
417
418
  <Upload className="w-8 h-8" />
418
419
  <p className="text-sm font-medium">Drop files here to upload</p>
419
420
  <p className="text-xs text-muted-foreground">Files will be added to {model.currentPath}</p>
@@ -4,7 +4,7 @@ import { AlertCircle, FolderOpen } from 'lucide-react';
4
4
  import { cn } from '../../lib/utils';
5
5
  import { FileBrowserModel } from '../models/FileBrowserModel';
6
6
  import { LoadingSpinner } from '@anymux/ui/components/loading-spinner';
7
- import { ErrorBoundary } from './shared/ErrorBoundary';
7
+ import { ErrorBoundary } from '../../shared/ErrorBoundary';
8
8
 
9
9
  export interface FileBrowserContentProps {
10
10
  model: FileBrowserModel;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { FileBrowser } from '../components/FileBrowser';
3
- import { IFileSystem } from '@anymux/file-system';
3
+ import type { IFileSystem } from '@anymux/file-system';
4
4
 
5
5
  interface BasicUsageProps {
6
6
  fileSystem: IFileSystem;
@@ -8,7 +8,7 @@ interface BasicUsageProps {
8
8
 
9
9
  export const BasicUsage: React.FC<BasicUsageProps> = ({ fileSystem }) => {
10
10
  return (
11
- <div className="w-full h-96 border border-gray-300 rounded-lg">
11
+ <div className="w-full h-96 border border-border rounded-lg">
12
12
  <FileBrowser
13
13
  fileSystem={fileSystem}
14
14
  initialPath="/"
@@ -3,7 +3,7 @@ export { FileBrowser } from './components/FileBrowser';
3
3
 
4
4
  // Shared components
5
5
  export { default as FileBrowserItemComponent } from './components/shared/FileBrowserItem';
6
- export { ErrorBoundary, type ErrorBoundaryProps } from './components/shared/ErrorBoundary';
6
+ export { ErrorBoundary, type ErrorBoundaryProps } from '../shared/ErrorBoundary';
7
7
  export { default as FileIcon } from './components/shared/FileIcon';
8
8
 
9
9
  // Types
@@ -1,4 +1,4 @@
1
- import { IFileSystem } from '@anymux/file-system';
1
+ import type { IFileSystem } from '@anymux/file-system';
2
2
  import { IFileBrowserProvider } from './IFileBrowserProvider';
3
3
  import { FileBrowserItem, IconDefinition, PreviewData } from '../types/FileBrowserTypes';
4
4
  import { LeftPanelMode } from '../models/LeftPanelManagerModel';