@unciatech/file-manager 0.0.41 → 0.0.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +303 -288
- package/dist/chunk-NOCFQCIH.js +18 -0
- package/dist/chunk-XOGHUQYC.cjs +18 -0
- package/dist/index.cjs +11 -11
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/{mock-provider-DrtiUc3h.d.cts → mock-provider-D1q21QlM.d.cts} +1 -0
- package/dist/{mock-provider-DrtiUc3h.d.ts → mock-provider-D1q21QlM.d.ts} +1 -0
- package/dist/mock.cjs +1 -1
- package/dist/mock.d.cts +1 -1
- package/dist/mock.d.ts +1 -1
- package/dist/mock.js +1 -1
- package/package.json +1 -4
- package/dist/chunk-DXJH5W7A.js +0 -18
- package/dist/chunk-SV5VFLC2.cjs +0 -18
- package/dist/cli.cjs +0 -213
- package/dist/cli.d.cts +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -213
package/README.md
CHANGED
|
@@ -1,383 +1,398 @@
|
|
|
1
1
|
# 🗂️ File Manager
|
|
2
2
|
|
|
3
|
-
A robust, production-ready file management component for
|
|
3
|
+
A robust, production-ready file management component for **React applications**.
|
|
4
4
|
|
|
5
|
-
It
|
|
5
|
+
It works with **Vite, Next.js, Remix, CRA**, and other React frameworks.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- **Dual Operating Modes**: Use it as a standalone full-page media library or instantiate it as a picker modal for form inputs.
|
|
9
|
-
- **Unified Grid View**: Beautiful, responsive layout that intelligently renders thumbnails, icons, and metadata based on the file's MIME type.
|
|
10
|
-
- **Nested Folder Structure**: Infinite folder depth with smooth virtualized/paginated fetching.
|
|
11
|
-
- **Provider Agnostic**: Built on an `IFileManagerProvider` interface. You can easily hot-swap the mock data provider for a real backend (Node.js, Supabase, Strapi, etc.).
|
|
12
|
-
- **Bulk Actions**: Select multiple files/folders at once to bulk move or bulk delete.
|
|
13
|
-
- **Optimistic UI Updates**: Instant visual feedback when renaming folders or updating file descriptions, with silent background synchronization.
|
|
14
|
-
- **Graceful Error Handling**: Resilient `<FileManagerErrorBoundary>` that captures catastrophic failures and allows users to hard-reload safely without app crashes.
|
|
7
|
+
The library supports deep folder hierarchies, drag-and-drop uploads, metadata management for multiple file types (Images, Videos, Audio, Documents), and a responsive grid interface optimized for large media libraries.
|
|
15
8
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# 🌟 Key Features
|
|
12
|
+
|
|
13
|
+
* **Dual Operating Modes** - Use as a full-page media library or as a picker modal.
|
|
14
|
+
* **Unified Grid View** - Responsive layout that intelligently renders thumbnails, icons, and metadata.
|
|
15
|
+
* **Nested Folder Structure** - Infinite folder depth with smooth paginated fetching.
|
|
16
|
+
* **Provider Agnostic** - Integrates with any backend through the `IFileManagerProvider` interface.
|
|
17
|
+
* **Bulk Actions** - Select and move/delete multiple files or folders.
|
|
18
|
+
* **Optimistic UI Updates** - Instant UI feedback with background synchronization.
|
|
19
|
+
* **Error Boundary Protection** - Built-in `<FileManagerErrorBoundary>` prevents crashes.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# 📦 Installation
|
|
24
|
+
|
|
25
|
+
Install the file manager and required utilities:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install @unciatech/file-manager class-variance-authority clsx tailwind-merge
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
> ⚠️ This library relies on **Tailwind CSS** for styling.
|
|
32
|
+
> If your project does not use Tailwind yet, install it in Step 3.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
# ⚡ Quick Start
|
|
37
|
+
|
|
38
|
+
You can instantly test the UI using the built-in `MockProvider`.
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { FileManager, MockProvider } from "@unciatech/file-manager"
|
|
42
|
+
|
|
43
|
+
const provider = new MockProvider()
|
|
44
|
+
|
|
45
|
+
export default function App() {
|
|
46
|
+
return (
|
|
47
|
+
<FileManager
|
|
48
|
+
provider={provider}
|
|
49
|
+
basePath="/"
|
|
50
|
+
viewMode="grid"
|
|
51
|
+
allowedFileTypes={["images", "videos", "files"]}
|
|
52
|
+
/>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
# 🛠 Setup & Requirements
|
|
60
|
+
|
|
61
|
+
## Step 1 - Install the Library
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npm install @unciatech/file-manager class-variance-authority clsx tailwind-merge
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Step 2 - Import Styles
|
|
70
|
+
|
|
71
|
+
Import the file manager styles in your root file.
|
|
72
|
+
|
|
73
|
+
### Vite / React
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import "@unciatech/file-manager/styles"
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Place this inside:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
main.tsx or App.tsx
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Next.js
|
|
86
|
+
|
|
87
|
+
Import inside your root layout:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import "@unciatech/file-manager/styles"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Place this in:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
app/layout.tsx
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
# Step 3 - Configure Tailwind CSS
|
|
102
|
+
|
|
103
|
+
This library relies heavily on **Tailwind CSS**.
|
|
21
104
|
|
|
22
|
-
|
|
23
|
-
|
|
105
|
+
If your project **already uses Tailwind**, follow Option A.
|
|
106
|
+
If **not**, follow Option B.
|
|
24
107
|
|
|
25
|
-
|
|
108
|
+
---
|
|
26
109
|
|
|
27
|
-
|
|
110
|
+
## Option A - Project Already Uses Tailwind
|
|
28
111
|
|
|
29
112
|
### Tailwind v4
|
|
30
|
-
|
|
113
|
+
|
|
114
|
+
Add this to your main CSS file (`globals.css` or `index.css`):
|
|
31
115
|
|
|
32
116
|
```css
|
|
33
117
|
@import "tailwindcss";
|
|
34
118
|
@import "@unciatech/file-manager/styles";
|
|
119
|
+
|
|
35
120
|
@source "../node_modules/@unciatech/file-manager";
|
|
36
121
|
```
|
|
37
122
|
|
|
123
|
+
---
|
|
124
|
+
|
|
38
125
|
### Tailwind v3
|
|
39
|
-
|
|
126
|
+
|
|
127
|
+
Update your `tailwind.config.ts`:
|
|
40
128
|
|
|
41
129
|
```ts
|
|
42
130
|
content: [
|
|
43
|
-
// ... your other paths
|
|
44
131
|
"./node_modules/@unciatech/file-manager/dist/**/*.{js,ts,jsx,tsx}",
|
|
45
|
-
]
|
|
132
|
+
]
|
|
46
133
|
```
|
|
47
134
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
If you want to integrate this File Manager into your own React application (Next.js, Vite, Remix, CRA, etc.), follow this step-by-step guide.
|
|
135
|
+
---
|
|
51
136
|
|
|
52
|
-
|
|
137
|
+
## Option B - Install Tailwind CSS
|
|
53
138
|
|
|
54
|
-
Install the library via NPM:
|
|
55
139
|
```bash
|
|
56
|
-
npm install
|
|
140
|
+
npm install -D tailwindcss postcss autoprefixer
|
|
141
|
+
npx tailwindcss init -p
|
|
57
142
|
```
|
|
58
143
|
|
|
59
|
-
|
|
60
|
-
Instead of setting everything up manually, our init script can spawn a brand new full-stack application instantly:
|
|
61
|
-
```bash
|
|
62
|
-
npx @unciatech/file-manager init my-media-app
|
|
63
|
-
```
|
|
64
|
-
*It will ask if you want Next.js or Vite (React), install Tailwind, install the package, and set everything up including styles!*
|
|
144
|
+
Update `tailwind.config.ts`:
|
|
65
145
|
|
|
66
|
-
**(CRITICAL) Import the styles:**
|
|
67
|
-
The init script includes this automatically, but if you are installing manually, add this import to your root layout / entry file:
|
|
68
146
|
```ts
|
|
69
|
-
|
|
147
|
+
content: [
|
|
148
|
+
"./index.html",
|
|
149
|
+
"./src/**/*.{js,ts,jsx,tsx}",
|
|
150
|
+
"./node_modules/@unciatech/file-manager/dist/**/*.{js,ts,jsx,tsx}",
|
|
151
|
+
]
|
|
70
152
|
```
|
|
71
153
|
|
|
72
|
-
|
|
154
|
+
Add to `index.css` or `globals.css`:
|
|
73
155
|
|
|
74
|
-
|
|
156
|
+
```css
|
|
157
|
+
@tailwind base;
|
|
158
|
+
@tailwind components;
|
|
159
|
+
@tailwind utilities;
|
|
75
160
|
|
|
76
|
-
|
|
161
|
+
@import "@unciatech/file-manager/styles";
|
|
162
|
+
```
|
|
77
163
|
|
|
78
|
-
|
|
79
|
-
// lib/my-api-provider.ts
|
|
80
|
-
import {
|
|
81
|
-
IFileManagerProvider,
|
|
82
|
-
FolderId,
|
|
83
|
-
FileUploadInput
|
|
84
|
-
} from "@/types/file-manager"; // Or "@unciatech/file-manager" for external users
|
|
164
|
+
---
|
|
85
165
|
|
|
86
|
-
|
|
87
|
-
private baseUrl = "https://api.mybackend.com/v1";
|
|
166
|
+
# Step 4 - Create Your Custom API Provider
|
|
88
167
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
// Simulate real API Call
|
|
94
|
-
const res = await fetch(`${this.baseUrl}/folders?page=${page}&limit=${limit}${parentQuery}`);
|
|
95
|
-
|
|
96
|
-
if (!res.ok) throw new Error("Failed to fetch folders");
|
|
97
|
-
|
|
98
|
-
const data = await res.json();
|
|
99
|
-
|
|
100
|
-
return {
|
|
101
|
-
folders: data.folders, // Array of Folder objects matching our interface
|
|
102
|
-
pagination: data.pagination // { currentPage, totalPages, totalFiles, filesPerPage }
|
|
103
|
-
};
|
|
104
|
-
}
|
|
168
|
+
> 💡 **Pro Tip - The Mock Provider**
|
|
169
|
+
> If you are just prototyping and don't have a backend ready yet, you can skip this step entirely.
|
|
170
|
+
>
|
|
171
|
+
> The library includes a fully functional `MockProvider` that simulates network latency and stores data in memory.
|
|
105
172
|
|
|
106
|
-
|
|
107
|
-
async uploadFiles(filesInput: FileUploadInput[], folderId?: FolderId) {
|
|
108
|
-
const formData = new FormData();
|
|
109
|
-
if (folderId) formData.append("folderId", String(folderId));
|
|
110
|
-
|
|
111
|
-
filesInput.forEach(({ file }) => {
|
|
112
|
-
formData.append("files", file);
|
|
113
|
-
});
|
|
173
|
+
Example:
|
|
114
174
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
body: formData
|
|
118
|
-
});
|
|
175
|
+
```tsx
|
|
176
|
+
import { FileManager, MockProvider } from "@unciatech/file-manager"
|
|
119
177
|
|
|
120
|
-
|
|
121
|
-
}
|
|
178
|
+
const provider = new MockProvider()
|
|
122
179
|
|
|
123
|
-
|
|
124
|
-
}
|
|
180
|
+
<FileManager provider={provider} basePath="/" viewMode="grid" />
|
|
125
181
|
```
|
|
126
182
|
|
|
127
|
-
|
|
128
|
-
> If you are just prototyping and don't have a backend ready yet, you can skip Step 2 entirely! We included a fully functional `MockProvider` that fakes network latency and stores data in memory. Just import it and use it right away to see the UI in action.
|
|
183
|
+
---
|
|
129
184
|
|
|
130
|
-
|
|
131
|
-
import { FileManager, MockProvider } from "@unciatech/file-manager";
|
|
132
|
-
import "@unciatech/file-manager/styles";
|
|
185
|
+
### Using Your Own Backend
|
|
133
186
|
|
|
134
|
-
|
|
135
|
-
// @source "../node_modules/@unciatech/file-manager";
|
|
136
|
-
// OR import your real provider
|
|
137
|
-
import { MyCustomApiProvider } from "@/lib/my-api-provider";
|
|
187
|
+
The file manager is **backend-agnostic**.
|
|
138
188
|
|
|
139
|
-
|
|
140
|
-
// Instantiate the provider (Real or Mock)
|
|
141
|
-
const apiProvider = new MockProvider();
|
|
189
|
+
Create a class implementing `IFileManagerProvider`.
|
|
142
190
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
provider={apiProvider}
|
|
150
|
-
>
|
|
151
|
-
<FileManager basePath="/media" />
|
|
152
|
-
</FileManagerProvider>
|
|
153
|
-
</div>
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
```
|
|
191
|
+
```ts
|
|
192
|
+
import {
|
|
193
|
+
IFileManagerProvider,
|
|
194
|
+
FolderId,
|
|
195
|
+
FileUploadInput,
|
|
196
|
+
} from "@unciatech/file-manager"
|
|
157
197
|
|
|
158
|
-
|
|
198
|
+
export class MyCustomApiProvider implements IFileManagerProvider {
|
|
199
|
+
private baseUrl = "https://api.mybackend.com/v1"
|
|
159
200
|
|
|
160
|
-
|
|
201
|
+
async getFolders(folderId: FolderId, page = 1, limit = 24) {
|
|
202
|
+
const parentQuery = folderId ? `&parentId=${folderId}` : "&isRoot=true"
|
|
161
203
|
|
|
162
|
-
|
|
204
|
+
const res = await fetch(
|
|
205
|
+
`${this.baseUrl}/folders?page=${page}&limit=${limit}${parentQuery}`
|
|
206
|
+
)
|
|
163
207
|
|
|
164
|
-
|
|
208
|
+
if (!res.ok) throw new Error("Failed to fetch folders")
|
|
165
209
|
|
|
166
|
-
|
|
210
|
+
const data = await res.json()
|
|
167
211
|
|
|
168
|
-
|
|
169
|
-
|
|
212
|
+
return {
|
|
213
|
+
folders: data.folders,
|
|
214
|
+
pagination: data.pagination,
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async uploadFiles(filesInput: FileUploadInput[], folderId?: FolderId) {
|
|
219
|
+
const formData = new FormData()
|
|
170
220
|
|
|
171
|
-
|
|
172
|
-
|
|
221
|
+
if (folderId) {
|
|
222
|
+
formData.append("folderId", String(folderId))
|
|
223
|
+
}
|
|
173
224
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
225
|
+
filesInput.forEach(({ file }) => {
|
|
226
|
+
formData.append("files", file)
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
const res = await fetch(`${this.baseUrl}/upload`, {
|
|
230
|
+
method: "POST",
|
|
231
|
+
body: formData,
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
return res.json()
|
|
235
|
+
}
|
|
182
236
|
}
|
|
183
237
|
```
|
|
184
238
|
|
|
185
|
-
|
|
239
|
+
---
|
|
186
240
|
|
|
187
|
-
|
|
188
|
-
'use client';
|
|
189
|
-
import { useRouter } from 'next/navigation';
|
|
241
|
+
# 🔀 Router Integration
|
|
190
242
|
|
|
191
|
-
|
|
192
|
-
const router = useRouter();
|
|
243
|
+
By default the file manager uses `history.pushState`.
|
|
193
244
|
|
|
194
|
-
|
|
195
|
-
<FileManager
|
|
196
|
-
provider={provider}
|
|
197
|
-
allowedFileTypes={['images', 'videos']}
|
|
198
|
-
onNavigate={(url) => router.push(url)}
|
|
199
|
-
basePath="/media"
|
|
200
|
-
/>
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
```
|
|
245
|
+
If your app uses a router, pass the `onNavigate` prop.
|
|
204
246
|
|
|
205
|
-
|
|
247
|
+
---
|
|
206
248
|
|
|
207
|
-
|
|
208
|
-
import { useRouter } from '@tanstack/react-router';
|
|
249
|
+
# Example - React Router
|
|
209
250
|
|
|
210
|
-
|
|
211
|
-
const router = useRouter();
|
|
251
|
+
### Install
|
|
212
252
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
provider={provider}
|
|
216
|
-
allowedFileTypes={['images', 'videos']}
|
|
217
|
-
onNavigate={(url) => router.navigate({ href: url })}
|
|
218
|
-
basePath="/media"
|
|
219
|
-
/>
|
|
220
|
-
);
|
|
221
|
-
}
|
|
253
|
+
```bash
|
|
254
|
+
npm install react-router-dom
|
|
222
255
|
```
|
|
223
256
|
|
|
257
|
+
### main.tsx
|
|
258
|
+
|
|
224
259
|
```tsx
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
260
|
+
import React from "react"
|
|
261
|
+
import ReactDOM from "react-dom/client"
|
|
262
|
+
import { BrowserRouter } from "react-router-dom"
|
|
263
|
+
import App from "./App"
|
|
264
|
+
import "./index.css"
|
|
265
|
+
|
|
266
|
+
ReactDOM.createRoot(document.getElementById("root")!).render(
|
|
267
|
+
<React.StrictMode>
|
|
268
|
+
<BrowserRouter>
|
|
269
|
+
<App />
|
|
270
|
+
</BrowserRouter>
|
|
271
|
+
</React.StrictMode>
|
|
272
|
+
)
|
|
231
273
|
```
|
|
232
274
|
|
|
233
|
-
|
|
275
|
+
---
|
|
234
276
|
|
|
235
|
-
|
|
277
|
+
# Example - TanStack Router
|
|
236
278
|
|
|
237
|
-
|
|
238
|
-
- **[TanStack Router Playground](file:///Users/avi/Developer/Uncia/file-manager/playgrounds/test-tanstack)**: Demonstrates integration with `@tanstack/react-router` using the `router` object and `href` based navigation.
|
|
279
|
+
### Install
|
|
239
280
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
- Using the `MockProvider` for rapid prototyping
|
|
244
|
-
- Configuring `FileManagerModal` v/s full-page `FileManager`
|
|
281
|
+
```bash
|
|
282
|
+
npm install @tanstack/react-router
|
|
283
|
+
```
|
|
245
284
|
|
|
246
|
-
|
|
285
|
+
### main.tsx
|
|
247
286
|
|
|
248
|
-
|
|
249
|
-
|
|
287
|
+
```tsx
|
|
288
|
+
import React from "react"
|
|
289
|
+
import ReactDOM from "react-dom/client"
|
|
290
|
+
import {
|
|
291
|
+
RouterProvider,
|
|
292
|
+
createRouter,
|
|
293
|
+
createRoute,
|
|
294
|
+
createRootRoute,
|
|
295
|
+
} from "@tanstack/react-router"
|
|
296
|
+
|
|
297
|
+
import App, { ModalPage } from "./App"
|
|
298
|
+
import "./index.css"
|
|
299
|
+
|
|
300
|
+
const rootRoute = createRootRoute()
|
|
301
|
+
|
|
302
|
+
const indexRoute = createRoute({
|
|
303
|
+
getParentRoute: () => rootRoute,
|
|
304
|
+
path: "/",
|
|
305
|
+
component: ModalPage,
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
const fullRoute = createRoute({
|
|
309
|
+
getParentRoute: () => rootRoute,
|
|
310
|
+
path: "/full",
|
|
311
|
+
component: App,
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
const catchAllRoute = createRoute({
|
|
315
|
+
getParentRoute: () => rootRoute,
|
|
316
|
+
path: "$",
|
|
317
|
+
component: App,
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
const routeTree = rootRoute.addChildren([
|
|
321
|
+
indexRoute,
|
|
322
|
+
fullRoute,
|
|
323
|
+
catchAllRoute,
|
|
324
|
+
])
|
|
325
|
+
|
|
326
|
+
const router = createRouter({ routeTree })
|
|
327
|
+
|
|
328
|
+
declare module "@tanstack/react-router" {
|
|
329
|
+
interface Register {
|
|
330
|
+
router: typeof router
|
|
331
|
+
}
|
|
332
|
+
}
|
|
250
333
|
|
|
251
|
-
|
|
334
|
+
ReactDOM.createRoot(document.getElementById("root")!).render(
|
|
335
|
+
<React.StrictMode>
|
|
336
|
+
<RouterProvider router={router} />
|
|
337
|
+
</React.StrictMode>
|
|
338
|
+
)
|
|
339
|
+
```
|
|
252
340
|
|
|
253
|
-
|
|
341
|
+
---
|
|
254
342
|
|
|
255
|
-
|
|
343
|
+
# 🗄️ Database Schema (Optional)
|
|
256
344
|
|
|
257
|
-
|
|
345
|
+
Using **PostgreSQL** with JSON support is recommended.
|
|
258
346
|
|
|
259
|
-
|
|
347
|
+
Example Prisma schema:
|
|
260
348
|
|
|
261
349
|
```prisma
|
|
262
|
-
generator client {
|
|
263
|
-
provider = "prisma-client-js"
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
datasource db {
|
|
267
|
-
provider = "postgresql" // or "mysql"
|
|
268
|
-
url = env("DATABASE_URL")
|
|
269
|
-
}
|
|
270
|
-
|
|
271
350
|
model Folder {
|
|
272
|
-
id Int
|
|
351
|
+
id Int @id @default(autoincrement())
|
|
273
352
|
name String
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
pathId Int @default(0)
|
|
286
|
-
path String? // e.g. "/1/5/12"
|
|
287
|
-
|
|
288
|
-
createdAt DateTime @default(now())
|
|
289
|
-
updatedAt DateTime @updatedAt
|
|
290
|
-
|
|
353
|
+
parentId Int?
|
|
354
|
+
|
|
355
|
+
folderCount Int @default(0)
|
|
356
|
+
fileCount Int @default(0)
|
|
357
|
+
|
|
358
|
+
pathId Int @default(0)
|
|
359
|
+
path String?
|
|
360
|
+
|
|
361
|
+
createdAt DateTime @default(now())
|
|
362
|
+
updatedAt DateTime @updatedAt
|
|
363
|
+
|
|
291
364
|
files File[]
|
|
292
365
|
|
|
293
366
|
@@index([parentId])
|
|
294
367
|
}
|
|
295
368
|
|
|
296
369
|
model File {
|
|
297
|
-
id
|
|
298
|
-
name
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
ext String?
|
|
311
|
-
hash String?
|
|
312
|
-
|
|
313
|
-
// Common Media Details
|
|
314
|
-
alternativeText String?
|
|
315
|
-
caption String?
|
|
316
|
-
width Int?
|
|
317
|
-
height Int?
|
|
318
|
-
|
|
319
|
-
// JSONB storage for flexible metadata
|
|
320
|
-
// (e.g., formats: { thumbnail: {...}, small: {...} })
|
|
321
|
-
formats Json?
|
|
322
|
-
// (e.g., metaData: { duration: 120, bitrate: 320, pageCount: 15 })
|
|
323
|
-
metaData Json?
|
|
324
|
-
|
|
325
|
-
createdAt DateTime @default(now())
|
|
326
|
-
updatedAt DateTime @updatedAt
|
|
327
|
-
|
|
328
|
-
@@index([folderId])
|
|
370
|
+
id Int @id @default(autoincrement())
|
|
371
|
+
name String
|
|
372
|
+
folderId Int?
|
|
373
|
+
|
|
374
|
+
size Int
|
|
375
|
+
url String
|
|
376
|
+
mime String
|
|
377
|
+
|
|
378
|
+
formats Json?
|
|
379
|
+
metaData Json?
|
|
380
|
+
|
|
381
|
+
createdAt DateTime @default(now())
|
|
382
|
+
updatedAt DateTime @updatedAt
|
|
329
383
|
}
|
|
330
384
|
```
|
|
331
385
|
|
|
386
|
+
---
|
|
332
387
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
// Nullable parentId allows root-level folders
|
|
345
|
-
parentId: integer("parent_id"), // Needs recursive FK setup in relations
|
|
346
|
-
|
|
347
|
-
folderCount: integer("folder_count").default(0),
|
|
348
|
-
fileCount: integer("file_count").default(0),
|
|
349
|
-
|
|
350
|
-
pathId: integer("path_id").default(0),
|
|
351
|
-
path: varchar("path", { length: 255 }),
|
|
352
|
-
|
|
353
|
-
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
354
|
-
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
export const files = pgTable("files", {
|
|
358
|
-
id: serial("id").primaryKey(),
|
|
359
|
-
name: varchar("name", { length: 255 }).notNull(),
|
|
360
|
-
|
|
361
|
-
folderId: integer("folder_id").references(() => folders.id, { onDelete: "cascade" }),
|
|
362
|
-
folderPath: varchar("folder_path", { length: 255 }),
|
|
363
|
-
|
|
364
|
-
size: integer("size").notNull(),
|
|
365
|
-
url: text("url").notNull(),
|
|
366
|
-
previewUrl: text("preview_url"),
|
|
367
|
-
mime: varchar("mime", { length: 100 }).notNull(),
|
|
368
|
-
ext: varchar("ext", { length: 20 }),
|
|
369
|
-
hash: varchar("hash", { length: 255 }),
|
|
370
|
-
|
|
371
|
-
alternativeText: text("alternative_text"),
|
|
372
|
-
caption: text("caption"),
|
|
373
|
-
width: integer("width"),
|
|
374
|
-
height: integer("height"),
|
|
375
|
-
|
|
376
|
-
// JSONB is perfect for storing our dynamic metadata & responsive formats
|
|
377
|
-
formats: jsonb("formats"),
|
|
378
|
-
metaData: jsonb("meta_data"),
|
|
379
|
-
|
|
380
|
-
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
381
|
-
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
|
382
|
-
});
|
|
383
|
-
```
|
|
388
|
+
# ⚠️ Status
|
|
389
|
+
|
|
390
|
+
> This library is currently in **BETA**.
|
|
391
|
+
|
|
392
|
+
Please report bugs or feature requests through **GitHub Issues**.
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
# License
|
|
397
|
+
|
|
398
|
+
MIT
|