@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,307 @@
|
|
|
1
|
+
# ExplorerLayout Component
|
|
2
|
+
|
|
3
|
+
A fully-typed, responsive layout component designed for editor-style interfaces like file browsers, code editors, and similar applications.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Fully Responsive**: Automatically adapts to different screen sizes with configurable breakpoints
|
|
8
|
+
- **Flexible Configuration**: Config-object API for easy customization of all sections
|
|
9
|
+
- **Smooth Transitions**: CSS transitions for sidebar width changes and responsive behavior
|
|
10
|
+
- **Mobile-First**: Mobile overlay behavior with hamburger toggle on small screens
|
|
11
|
+
- **TypeScript**: Fully typed with comprehensive type definitions
|
|
12
|
+
- **Tailwind Integration**: Uses Tailwind CSS classes with conditional styling
|
|
13
|
+
|
|
14
|
+
## API
|
|
15
|
+
|
|
16
|
+
### `ExplorerSections` Configuration Object
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
interface ExplorerSections {
|
|
20
|
+
header?: ReactNode;
|
|
21
|
+
footer?: ReactNode;
|
|
22
|
+
sidebar?: {
|
|
23
|
+
content: ReactNode;
|
|
24
|
+
toolbar?: ReactNode;
|
|
25
|
+
width?: number; // px, default 224
|
|
26
|
+
};
|
|
27
|
+
main: {
|
|
28
|
+
content: ReactNode;
|
|
29
|
+
toolbar?: ReactNode;
|
|
30
|
+
};
|
|
31
|
+
responsive?: {
|
|
32
|
+
breakpoint?: number; // px, default 768
|
|
33
|
+
sidebarCollapsed?: boolean;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### `ExplorerLayoutProps`
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
interface ExplorerLayoutProps {
|
|
42
|
+
sections: ExplorerSections;
|
|
43
|
+
className?: string;
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Layout Structure
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
┌─────────────────────────────────────┐
|
|
51
|
+
│ Header │ (optional)
|
|
52
|
+
├──────────┬──────────────────────────┤
|
|
53
|
+
│ │ Main Toolbar │ (optional)
|
|
54
|
+
│ Sidebar ├──────────────────────────┤
|
|
55
|
+
│ Toolbar │ │
|
|
56
|
+
├──────────┤ Main Content │ (required)
|
|
57
|
+
│ │ │
|
|
58
|
+
│ Sidebar │ │
|
|
59
|
+
│ Content │ │
|
|
60
|
+
│ │ │
|
|
61
|
+
├──────────┴──────────────────────────┤
|
|
62
|
+
│ Footer │ (optional)
|
|
63
|
+
└─────────────────────────────────────┘
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Responsive Behavior
|
|
67
|
+
|
|
68
|
+
- **Desktop (≥ breakpoint)**: Two-column layout with fixed sidebar
|
|
69
|
+
- **Mobile (< breakpoint)**: Single column with overlay sidebar
|
|
70
|
+
- **Mobile Toggle**: ☰ button appears in top-left corner for sidebar toggle
|
|
71
|
+
- **Backdrop**: Click outside sidebar to close on mobile
|
|
72
|
+
|
|
73
|
+
## Basic Usage
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
import { ExplorerLayout, type ExplorerSections } from '@anymux/fs-ui';
|
|
77
|
+
import { useState } from 'react';
|
|
78
|
+
|
|
79
|
+
const sections: ExplorerSections = {
|
|
80
|
+
header: <div className="p-4">My App Header</div>,
|
|
81
|
+
sidebar: {
|
|
82
|
+
content: <div className="p-4">Navigation content</div>,
|
|
83
|
+
toolbar: <div className="p-2">Sidebar toolbar</div>,
|
|
84
|
+
width: 280,
|
|
85
|
+
},
|
|
86
|
+
main: {
|
|
87
|
+
content: <div className="p-4">Main content area</div>,
|
|
88
|
+
toolbar: <div className="p-2">Main toolbar</div>,
|
|
89
|
+
},
|
|
90
|
+
footer: <div className="p-2">Status bar</div>,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// With internal collapse state (automatic)
|
|
94
|
+
export const MyApp = () => (
|
|
95
|
+
<div className="h-screen">
|
|
96
|
+
<ExplorerLayout sections={sections} />
|
|
97
|
+
</div>
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
// With external collapse state (controlled)
|
|
101
|
+
export const MyControlledApp = () => {
|
|
102
|
+
const [collapsed, setCollapsed] = useState(false);
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<div className="h-screen">
|
|
106
|
+
<ExplorerLayout
|
|
107
|
+
sections={sections}
|
|
108
|
+
isSidebarCollapsed={collapsed}
|
|
109
|
+
setSidebarCollapsed={setCollapsed}
|
|
110
|
+
/>
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Advanced Examples
|
|
117
|
+
|
|
118
|
+
### Code Editor Layout
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
const editorSections: ExplorerSections = {
|
|
122
|
+
header: (
|
|
123
|
+
<div className="p-4 flex items-center justify-between border-b">
|
|
124
|
+
<h1 className="text-lg font-semibold">Code Editor</h1>
|
|
125
|
+
<div className="flex gap-2">
|
|
126
|
+
<Button size="sm">File</Button>
|
|
127
|
+
<Button size="sm">Edit</Button>
|
|
128
|
+
<Button size="sm">View</Button>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
),
|
|
132
|
+
sidebar: {
|
|
133
|
+
content: <FileExplorer />,
|
|
134
|
+
toolbar: (
|
|
135
|
+
<div className="p-2 flex items-center justify-between">
|
|
136
|
+
<span className="text-sm font-medium">Explorer</span>
|
|
137
|
+
<Button variant="ghost" size="sm">+</Button>
|
|
138
|
+
</div>
|
|
139
|
+
),
|
|
140
|
+
width: 320,
|
|
141
|
+
},
|
|
142
|
+
main: {
|
|
143
|
+
content: <CodeEditor />,
|
|
144
|
+
toolbar: (
|
|
145
|
+
<div className="p-2 flex items-center justify-between">
|
|
146
|
+
<span className="text-sm">src/App.tsx</span>
|
|
147
|
+
<div className="flex gap-1">
|
|
148
|
+
<Button variant="ghost" size="sm">Save</Button>
|
|
149
|
+
<Button variant="ghost" size="sm">Format</Button>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
),
|
|
153
|
+
},
|
|
154
|
+
footer: (
|
|
155
|
+
<div className="p-2 flex items-center justify-between text-xs bg-muted">
|
|
156
|
+
<span>Ln 42, Col 15</span>
|
|
157
|
+
<span>TypeScript • UTF-8</span>
|
|
158
|
+
</div>
|
|
159
|
+
),
|
|
160
|
+
responsive: {
|
|
161
|
+
breakpoint: 768,
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Minimal Layout (No Header/Footer)
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
const minimalSections: ExplorerSections = {
|
|
170
|
+
sidebar: {
|
|
171
|
+
content: <NavigationMenu />,
|
|
172
|
+
width: 240,
|
|
173
|
+
},
|
|
174
|
+
main: {
|
|
175
|
+
content: <MainContent />,
|
|
176
|
+
},
|
|
177
|
+
responsive: {
|
|
178
|
+
breakpoint: 640,
|
|
179
|
+
sidebarCollapsed: false,
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### No Sidebar Layout
|
|
185
|
+
|
|
186
|
+
```tsx
|
|
187
|
+
const noSidebarSections: ExplorerSections = {
|
|
188
|
+
header: <AppHeader />,
|
|
189
|
+
main: {
|
|
190
|
+
content: <FullWidthContent />,
|
|
191
|
+
toolbar: <ContentToolbar />,
|
|
192
|
+
},
|
|
193
|
+
footer: <AppFooter />,
|
|
194
|
+
};
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Styling Guidelines
|
|
198
|
+
|
|
199
|
+
### Full Height Containers
|
|
200
|
+
|
|
201
|
+
Always ensure the parent container has full height:
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
// ✅ Correct
|
|
205
|
+
<div className="h-screen">
|
|
206
|
+
<ExplorerLayout sections={sections} />
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
// ❌ Incorrect - layout won't fill screen
|
|
210
|
+
<div>
|
|
211
|
+
<ExplorerLayout sections={sections} />
|
|
212
|
+
</div>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Content Overflow
|
|
216
|
+
|
|
217
|
+
For scrollable content areas, use `overflow-auto` or `overflow-hidden`:
|
|
218
|
+
|
|
219
|
+
```tsx
|
|
220
|
+
const sections: ExplorerSections = {
|
|
221
|
+
sidebar: {
|
|
222
|
+
content: (
|
|
223
|
+
<div className="h-full overflow-auto p-4">
|
|
224
|
+
{/* Long list of items */}
|
|
225
|
+
</div>
|
|
226
|
+
),
|
|
227
|
+
},
|
|
228
|
+
main: {
|
|
229
|
+
content: (
|
|
230
|
+
<div className="h-full overflow-auto p-4">
|
|
231
|
+
{/* Scrollable main content */}
|
|
232
|
+
</div>
|
|
233
|
+
),
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Configuration Tips
|
|
239
|
+
|
|
240
|
+
### Responsive Breakpoints
|
|
241
|
+
|
|
242
|
+
Choose breakpoints based on your content:
|
|
243
|
+
|
|
244
|
+
- **Small layouts**: 640px (mobile-first)
|
|
245
|
+
- **Standard layouts**: 768px (tablet breakpoint)
|
|
246
|
+
- **Wide layouts**: 1024px (desktop-first)
|
|
247
|
+
|
|
248
|
+
### Sidebar Widths
|
|
249
|
+
|
|
250
|
+
Recommended sidebar widths:
|
|
251
|
+
|
|
252
|
+
- **Navigation only**: 200-240px
|
|
253
|
+
- **File explorer**: 280-320px
|
|
254
|
+
- **Tool panels**: 320-400px
|
|
255
|
+
- **Wide content**: 400-500px
|
|
256
|
+
|
|
257
|
+
### Performance Considerations
|
|
258
|
+
|
|
259
|
+
- Use `React.memo()` for expensive sidebar/main content
|
|
260
|
+
- Implement virtualization for large lists
|
|
261
|
+
- Minimize re-renders by memoizing section configurations
|
|
262
|
+
|
|
263
|
+
## Testing
|
|
264
|
+
|
|
265
|
+
The component includes a comprehensive demo at:
|
|
266
|
+
`/explorer-layout-samples`
|
|
267
|
+
|
|
268
|
+
Test different:
|
|
269
|
+
- Screen sizes and responsive behavior
|
|
270
|
+
- Section combinations (with/without header, footer, sidebar)
|
|
271
|
+
- Content types and overflow scenarios
|
|
272
|
+
- Mobile overlay functionality
|
|
273
|
+
|
|
274
|
+
## Migration from FileBrowser
|
|
275
|
+
|
|
276
|
+
If migrating from the FileBrowser component:
|
|
277
|
+
|
|
278
|
+
```tsx
|
|
279
|
+
// Before (FileBrowser pattern)
|
|
280
|
+
<div className="flex h-full">
|
|
281
|
+
<div className="w-80 border-r">
|
|
282
|
+
<SidebarContent />
|
|
283
|
+
</div>
|
|
284
|
+
<div className="flex-1">
|
|
285
|
+
<MainContent />
|
|
286
|
+
</div>
|
|
287
|
+
</div>
|
|
288
|
+
|
|
289
|
+
// After (ExplorerLayout)
|
|
290
|
+
const sections: ExplorerSections = {
|
|
291
|
+
sidebar: {
|
|
292
|
+
content: <SidebarContent />,
|
|
293
|
+
width: 320,
|
|
294
|
+
},
|
|
295
|
+
main: {
|
|
296
|
+
content: <MainContent />,
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
<ExplorerLayout sections={sections} />
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## Browser Support
|
|
304
|
+
|
|
305
|
+
- Modern browsers with CSS Grid and Flexbox support
|
|
306
|
+
- Mobile browsers with touch events
|
|
307
|
+
- Responsive design works on all screen sizes
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import React, { ReactNode, useState, useEffect, useCallback } from 'react';
|
|
2
|
+
import { observer } from 'mobx-react-lite';
|
|
3
|
+
import { cn } from '../../../lib/utils';
|
|
4
|
+
import { Button } from '@anymux/ui/components/button';
|
|
5
|
+
import { ChevronLeft, ChevronRight, PanelLeftClose, PanelLeft } from 'lucide-react';
|
|
6
|
+
|
|
7
|
+
export interface ExplorerSections {
|
|
8
|
+
header?: ReactNode;
|
|
9
|
+
footer?: ReactNode;
|
|
10
|
+
sidebar?: {
|
|
11
|
+
content: ReactNode;
|
|
12
|
+
toolbar?: ReactNode;
|
|
13
|
+
width?: number; // px, default 280
|
|
14
|
+
};
|
|
15
|
+
main: {
|
|
16
|
+
content: ReactNode;
|
|
17
|
+
toolbar?: ReactNode;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ExplorerLayoutProps {
|
|
22
|
+
sections: ExplorerSections;
|
|
23
|
+
className?: string;
|
|
24
|
+
isSidebarCollapsed?: boolean;
|
|
25
|
+
setSidebarCollapsed?: (collapsed: boolean) => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const MOBILE_BREAKPOINT = 768;
|
|
29
|
+
|
|
30
|
+
export const ExplorerLayout: React.FC<ExplorerLayoutProps> = observer(({
|
|
31
|
+
sections,
|
|
32
|
+
className,
|
|
33
|
+
isSidebarCollapsed: externalCollapsed,
|
|
34
|
+
setSidebarCollapsed: externalSetCollapsed
|
|
35
|
+
}) => {
|
|
36
|
+
const [internalCollapsed, setInternalCollapsed] = useState(false);
|
|
37
|
+
const [isMobile, setIsMobile] = useState(false);
|
|
38
|
+
const [mobileOpen, setMobileOpen] = useState(false);
|
|
39
|
+
|
|
40
|
+
const isCollapsed = externalCollapsed ?? internalCollapsed;
|
|
41
|
+
const setCollapsed = externalSetCollapsed ?? setInternalCollapsed;
|
|
42
|
+
|
|
43
|
+
const sidebarWidth = sections.sidebar?.width ?? 280;
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
const checkMobile = () => {
|
|
47
|
+
const mobile = window.innerWidth < MOBILE_BREAKPOINT;
|
|
48
|
+
setIsMobile(mobile);
|
|
49
|
+
if (mobile) {
|
|
50
|
+
setMobileOpen(false);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
checkMobile();
|
|
54
|
+
window.addEventListener('resize', checkMobile);
|
|
55
|
+
return () => window.removeEventListener('resize', checkMobile);
|
|
56
|
+
}, []);
|
|
57
|
+
|
|
58
|
+
const handleOverlayClick = useCallback(() => {
|
|
59
|
+
setMobileOpen(false);
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
62
|
+
const showSidebar = sections.sidebar && (isMobile ? mobileOpen : !isCollapsed);
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<div className={cn("flex flex-col h-full w-full bg-background", className)}>
|
|
66
|
+
{/* Header Section */}
|
|
67
|
+
{sections.header && (
|
|
68
|
+
<div className="flex-shrink-0 border-b bg-background">
|
|
69
|
+
{sections.header}
|
|
70
|
+
</div>
|
|
71
|
+
)}
|
|
72
|
+
|
|
73
|
+
{/* Main content - dual panel layout */}
|
|
74
|
+
<div className="flex flex-1 min-h-0 relative">
|
|
75
|
+
{/* Mobile overlay */}
|
|
76
|
+
{isMobile && mobileOpen && (
|
|
77
|
+
<div
|
|
78
|
+
className="absolute inset-0 bg-black/30 z-30"
|
|
79
|
+
onClick={handleOverlayClick}
|
|
80
|
+
/>
|
|
81
|
+
)}
|
|
82
|
+
|
|
83
|
+
{/* Left Panel - Sidebar */}
|
|
84
|
+
{sections.sidebar && (isMobile ? mobileOpen : true) && (
|
|
85
|
+
<div
|
|
86
|
+
className={cn(
|
|
87
|
+
"bg-background flex flex-col flex-shrink-0 transition-all duration-200 ease-in-out",
|
|
88
|
+
isMobile
|
|
89
|
+
? "absolute inset-y-0 left-0 z-40 border-r shadow-lg"
|
|
90
|
+
: cn(
|
|
91
|
+
"border-r relative",
|
|
92
|
+
isCollapsed && "overflow-hidden"
|
|
93
|
+
)
|
|
94
|
+
)}
|
|
95
|
+
style={{
|
|
96
|
+
width: isMobile
|
|
97
|
+
? Math.min(sidebarWidth, 300)
|
|
98
|
+
: (isCollapsed ? 0 : sidebarWidth)
|
|
99
|
+
}}
|
|
100
|
+
>
|
|
101
|
+
{/* Sidebar Toolbar */}
|
|
102
|
+
{!isCollapsed && (
|
|
103
|
+
<div className="px-2 border-b bg-muted/10 flex-shrink-0 flex items-center h-10 gap-1">
|
|
104
|
+
<div className="flex-1 min-w-0">
|
|
105
|
+
{sections.sidebar.toolbar}
|
|
106
|
+
</div>
|
|
107
|
+
<Button
|
|
108
|
+
variant="ghost"
|
|
109
|
+
size="icon"
|
|
110
|
+
className="h-6 w-6 flex-shrink-0"
|
|
111
|
+
onClick={() => {
|
|
112
|
+
if (isMobile) {
|
|
113
|
+
setMobileOpen(false);
|
|
114
|
+
} else {
|
|
115
|
+
setCollapsed(true);
|
|
116
|
+
}
|
|
117
|
+
}}
|
|
118
|
+
title="Collapse sidebar"
|
|
119
|
+
>
|
|
120
|
+
<PanelLeftClose className="h-4 w-4" />
|
|
121
|
+
</Button>
|
|
122
|
+
</div>
|
|
123
|
+
)}
|
|
124
|
+
|
|
125
|
+
{/* Sidebar Content */}
|
|
126
|
+
<div className="flex-1 min-h-0 overflow-auto">
|
|
127
|
+
{sections.sidebar.content}
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
)}
|
|
131
|
+
|
|
132
|
+
{/* Right Panel - Main Content */}
|
|
133
|
+
<div className="flex-1 flex flex-col min-w-0">
|
|
134
|
+
{/* Main Toolbar */}
|
|
135
|
+
{sections.main.toolbar && (
|
|
136
|
+
<div className="px-2 border-b bg-muted/10 flex items-center justify-between flex-shrink-0 h-10">
|
|
137
|
+
<div className="flex items-center gap-2 flex-1 min-w-0">
|
|
138
|
+
{/* Mobile sidebar toggle + collapsed sidebar toggle */}
|
|
139
|
+
{sections.sidebar && (isMobile || isCollapsed) && !(isMobile && mobileOpen) && (
|
|
140
|
+
<Button
|
|
141
|
+
variant="ghost"
|
|
142
|
+
size="icon"
|
|
143
|
+
className="h-6 w-6 flex-shrink-0"
|
|
144
|
+
onClick={() => {
|
|
145
|
+
if (isMobile) {
|
|
146
|
+
setMobileOpen(true);
|
|
147
|
+
} else {
|
|
148
|
+
setCollapsed(false);
|
|
149
|
+
}
|
|
150
|
+
}}
|
|
151
|
+
title="Show sidebar"
|
|
152
|
+
>
|
|
153
|
+
<PanelLeft className="h-4 w-4" />
|
|
154
|
+
</Button>
|
|
155
|
+
)}
|
|
156
|
+
{sections.main.toolbar}
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
)}
|
|
160
|
+
|
|
161
|
+
{/* Main Content */}
|
|
162
|
+
<div className="flex-1 min-h-0 overflow-hidden">
|
|
163
|
+
{sections.main.content}
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
167
|
+
|
|
168
|
+
{/* Footer Section */}
|
|
169
|
+
{sections.footer && (
|
|
170
|
+
<div className="flex-shrink-0 border-t bg-background">
|
|
171
|
+
{sections.footer}
|
|
172
|
+
</div>
|
|
173
|
+
)}
|
|
174
|
+
</div>
|
|
175
|
+
);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
ExplorerLayout.displayName = 'ExplorerLayout';
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ExplorerLayout, type ExplorerSections } from '../';
|
|
3
|
+
import { Button } from '@anymux/ui/components/button';
|
|
4
|
+
|
|
5
|
+
// AICODE-NOTE: Minimal example showing ExplorerLayout basic usage
|
|
6
|
+
export const SimpleExample: React.FC = () => {
|
|
7
|
+
const sections: ExplorerSections = {
|
|
8
|
+
header: (
|
|
9
|
+
<div className="p-4 flex items-center justify-between border-b">
|
|
10
|
+
<h1 className="text-lg font-semibold">My App</h1>
|
|
11
|
+
<Button variant="outline" size="sm">Settings</Button>
|
|
12
|
+
</div>
|
|
13
|
+
),
|
|
14
|
+
sidebar: {
|
|
15
|
+
content: (
|
|
16
|
+
<div className="p-4">
|
|
17
|
+
<h3 className="font-medium mb-2">Navigation</h3>
|
|
18
|
+
<div className="space-y-1">
|
|
19
|
+
<div className="p-2 rounded hover:bg-muted cursor-pointer">📁 Files</div>
|
|
20
|
+
<div className="p-2 rounded hover:bg-muted cursor-pointer">🔍 Search</div>
|
|
21
|
+
<div className="p-2 rounded hover:bg-muted cursor-pointer">⚙️ Settings</div>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
),
|
|
25
|
+
toolbar: (
|
|
26
|
+
<div className="p-2 border-b">
|
|
27
|
+
<span className="text-sm font-medium">Explorer</span>
|
|
28
|
+
</div>
|
|
29
|
+
),
|
|
30
|
+
width: 240,
|
|
31
|
+
},
|
|
32
|
+
main: {
|
|
33
|
+
content: (
|
|
34
|
+
<div className="p-8 text-center">
|
|
35
|
+
<h2 className="text-xl font-semibold mb-4">Welcome to ExplorerLayout</h2>
|
|
36
|
+
<p className="text-muted-foreground">
|
|
37
|
+
This is the main content area. It automatically adapts to different screen sizes.
|
|
38
|
+
</p>
|
|
39
|
+
</div>
|
|
40
|
+
),
|
|
41
|
+
toolbar: (
|
|
42
|
+
<div className="p-2 border-b flex items-center justify-between">
|
|
43
|
+
<span className="text-sm font-medium">Main Content</span>
|
|
44
|
+
<Button variant="ghost" size="sm">Action</Button>
|
|
45
|
+
</div>
|
|
46
|
+
),
|
|
47
|
+
},
|
|
48
|
+
footer: (
|
|
49
|
+
<div className="p-2 border-t text-center text-sm text-muted-foreground">
|
|
50
|
+
Ready
|
|
51
|
+
</div>
|
|
52
|
+
),
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<div className="h-screen w-screen">
|
|
57
|
+
<ExplorerLayout sections={sections} />
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// AICODE-NOTE: Main exports for EditorLayout module
|
|
2
|
+
export { ExplorerLayout } from './components/ExplorerLayout/ExplorerLayout';
|
|
3
|
+
export type { ExplorerLayoutProps, ExplorerSections } from './components/ExplorerLayout/ExplorerLayout';
|
|
4
|
+
|
|
5
|
+
// Examples
|
|
6
|
+
export { SimpleExample as ExplorerLayoutSimpleExample } from './examples/SimpleExample';
|
package/src/lib/utils.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { cn } from '@anymux/ui/lib/utils';
|