@unciatech/file-manager 0.0.31 → 0.0.33
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 +125 -32
- package/dist/cli.cjs +68 -51
- package/dist/cli.js +68 -51
- package/dist/index.cjs +257 -170
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +243 -156
- package/dist/{mock-provider-nCBvw7nl.d.cts → mock-provider-DrtiUc3h.d.cts} +32 -4
- package/dist/{mock-provider-nCBvw7nl.d.ts → mock-provider-DrtiUc3h.d.ts} +32 -4
- package/dist/mock.d.cts +1 -1
- package/dist/mock.d.ts +1 -1
- package/dist/styles.css +75 -56
- package/dist/styles.d.ts +1 -0
- package/package.json +8 -5
- package/styles.css +75 -56
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 🗂️ File Manager
|
|
2
2
|
|
|
3
|
-
A robust, production-ready
|
|
3
|
+
A robust, production-ready file management component for any **React** application — works with Vite, Next.js, Remix, CRA, and more.
|
|
4
4
|
|
|
5
5
|
It supports deep folder nesting, drag-and-drop file uploads, metadata management for various file types (Images, Videos, Audio, Documents), unified grid layouts, and fully optimized loading states.
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ It supports deep folder nesting, drag-and-drop file uploads, metadata management
|
|
|
14
14
|
- **Graceful Error Handling**: Resilient `<FileManagerErrorBoundary>` that captures catastrophic failures and allows users to hard-reload safely without app crashes.
|
|
15
15
|
|
|
16
16
|
## 🛠️ Tech Stack
|
|
17
|
-
- **Framework**: Next.js
|
|
17
|
+
- **Framework**: React (any — Vite, Next.js, Remix, CRA)
|
|
18
18
|
- **Styling**: Tailwind CSS
|
|
19
19
|
- **Icons**: Custom SVG Icons
|
|
20
20
|
- **Notifications**: Sonner
|
|
@@ -22,9 +22,32 @@ It supports deep folder nesting, drag-and-drop file uploads, metadata management
|
|
|
22
22
|
> [!WARNING]
|
|
23
23
|
> This library is currently in **BETA**. Please report any bugs or feature requests on the GitHub issues page.
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## Setup & Requirements
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
Because this library relies heavily on Tailwind CSS for minimal zero-config styling, ensure your app is configured to scan the library's components for Tailwind utility classes.
|
|
28
|
+
|
|
29
|
+
### Tailwind v4
|
|
30
|
+
If you are using **Tailwind CSS v4** (like in newer Next.js or Vite projects), add this to your main CSS file (`globals.css` or `index.css`). This pulls in the required theme configuration and ensures the library is scanned:
|
|
31
|
+
|
|
32
|
+
```css
|
|
33
|
+
@import "tailwindcss";
|
|
34
|
+
@import "@unciatech/file-manager/styles";
|
|
35
|
+
@source "../node_modules/@unciatech/file-manager";
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Tailwind v3
|
|
39
|
+
If you are still on **Tailwind v3**, add the library path to your `tailwind.config.ts`:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
content: [
|
|
43
|
+
// ... your other paths
|
|
44
|
+
"./node_modules/@unciatech/file-manager/dist/**/*.{js,ts,jsx,tsx}",
|
|
45
|
+
],
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Basic Usage in Your Project
|
|
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.
|
|
28
51
|
|
|
29
52
|
### Step 1: Install the Package
|
|
30
53
|
|
|
@@ -46,30 +69,6 @@ The init script includes this automatically, but if you are installing manually,
|
|
|
46
69
|
import '@unciatech/file-manager/styles';
|
|
47
70
|
```
|
|
48
71
|
|
|
49
|
-
**(CRITICAL) Configure Tailwind CSS:**
|
|
50
|
-
Because this library uses Tailwind CSS, you MUST tell your Tailwind compiler to scan the library components for utility classes, otherwise it will render with zero styles!
|
|
51
|
-
|
|
52
|
-
**For Tailwind v3 (`tailwind.config.ts`):**
|
|
53
|
-
```typescript
|
|
54
|
-
import type { Config } from "tailwindcss";
|
|
55
|
-
|
|
56
|
-
const config: Config = {
|
|
57
|
-
content: [
|
|
58
|
-
// Your existing paths...
|
|
59
|
-
"./node_modules/@unciatech/file-manager/dist/**/*.js",
|
|
60
|
-
"./node_modules/@unciatech/file-manager/dist/**/*.mjs",
|
|
61
|
-
],
|
|
62
|
-
// ...
|
|
63
|
-
};
|
|
64
|
-
export default config;
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**For Tailwind v4 (`globals.css`):**
|
|
68
|
-
```css
|
|
69
|
-
@import "tailwindcss";
|
|
70
|
-
@source "../node_modules/@unciatech/file-manager/dist";
|
|
71
|
-
```
|
|
72
|
-
|
|
73
72
|
### Step 2: Create your Custom API Provider
|
|
74
73
|
|
|
75
74
|
The file manager is completely agnostic to your backend database. You simply need to create a class that implements the `IFileManagerProvider` interface.
|
|
@@ -129,10 +128,11 @@ export class MyCustomApiProvider implements IFileManagerProvider {
|
|
|
129
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.
|
|
130
129
|
|
|
131
130
|
// app/media/page.tsx
|
|
132
|
-
import {
|
|
133
|
-
import
|
|
134
|
-
import { MockProvider } from "@/providers/mock-provider";
|
|
131
|
+
import { FileManager, MockProvider } from "@unciatech/file-manager";
|
|
132
|
+
import "@unciatech/file-manager/styles";
|
|
135
133
|
|
|
134
|
+
// **Tailwind v4 Users:** Make sure your `globals.css` or `index.css` includes:
|
|
135
|
+
// @source "../node_modules/@unciatech/file-manager";
|
|
136
136
|
// OR import your real provider
|
|
137
137
|
import { MyCustomApiProvider } from "@/lib/my-api-provider";
|
|
138
138
|
|
|
@@ -148,7 +148,7 @@ export default function MediaLibraryPage() {
|
|
|
148
148
|
allowedFileTypes={["images", "videos", "audios", "files"]}
|
|
149
149
|
provider={apiProvider}
|
|
150
150
|
>
|
|
151
|
-
<FileManager />
|
|
151
|
+
<FileManager basePath="/media" />
|
|
152
152
|
</FileManagerProvider>
|
|
153
153
|
</div>
|
|
154
154
|
);
|
|
@@ -157,6 +157,99 @@ export default function MediaLibraryPage() {
|
|
|
157
157
|
|
|
158
158
|
---
|
|
159
159
|
|
|
160
|
+
## 🔀 Framework Router Integration
|
|
161
|
+
|
|
162
|
+
By default, the file manager uses the browser's native `history.pushState` API for navigation — no full page reloads, no dependencies. This works out of the box in any bare React app (Vite, CRA, etc.).
|
|
163
|
+
|
|
164
|
+
However, if your app already has its own router (React Router, Next.js, TanStack Router), you should pass the `onNavigate` prop so the file manager delegates all navigation to your router instead of calling `history.pushState` directly. This keeps your router's internal state in sync.
|
|
165
|
+
|
|
166
|
+
### React Router v6
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
import { useNavigate } from 'react-router-dom';
|
|
170
|
+
|
|
171
|
+
function MyPage() {
|
|
172
|
+
const navigate = useNavigate();
|
|
173
|
+
|
|
174
|
+
return (
|
|
175
|
+
<FileManager
|
|
176
|
+
provider={provider}
|
|
177
|
+
allowedFileTypes={['images', 'videos']}
|
|
178
|
+
onNavigate={(url) => navigate(url)}
|
|
179
|
+
basePath="/media"
|
|
180
|
+
/>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Next.js (App Router)
|
|
186
|
+
|
|
187
|
+
```tsx
|
|
188
|
+
'use client';
|
|
189
|
+
import { useRouter } from 'next/navigation';
|
|
190
|
+
|
|
191
|
+
export default function MediaPage() {
|
|
192
|
+
const router = useRouter();
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<FileManager
|
|
196
|
+
provider={provider}
|
|
197
|
+
allowedFileTypes={['images', 'videos']}
|
|
198
|
+
onNavigate={(url) => router.push(url)}
|
|
199
|
+
basePath="/media"
|
|
200
|
+
/>
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### TanStack Router
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
import { useRouter } from '@tanstack/react-router';
|
|
209
|
+
|
|
210
|
+
function MyPage() {
|
|
211
|
+
const router = useRouter();
|
|
212
|
+
|
|
213
|
+
return (
|
|
214
|
+
<FileManager
|
|
215
|
+
provider={provider}
|
|
216
|
+
allowedFileTypes={['images', 'videos']}
|
|
217
|
+
onNavigate={(url) => router.navigate({ href: url })}
|
|
218
|
+
basePath="/media"
|
|
219
|
+
/>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
<FileManager
|
|
226
|
+
provider={provider}
|
|
227
|
+
allowedFileTypes={['images', 'videos']}
|
|
228
|
+
basePath="/media"
|
|
229
|
+
// no onNavigate needed
|
|
230
|
+
/>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## 🎮 Playgrounds & Reference Implementations
|
|
234
|
+
|
|
235
|
+
For complete, working examples of how to integrate the File Manager into different application architectures, check out the [playgrounds](file:///Users/avi/Developer/Uncia/file-manager/playgrounds) directory. These are fully functional Vite-based projects that demonstrate real-world integration patterns.
|
|
236
|
+
|
|
237
|
+
- **[React Router v7 Playground](file:///Users/avi/Developer/Uncia/file-manager/playgrounds/test-react-router)**: Demonstrates integration with `react-router-dom` using `useNavigate` and route-based navigation.
|
|
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.
|
|
239
|
+
|
|
240
|
+
These playgrounds are a great starting point for seeing how to handle:
|
|
241
|
+
- Styling with Tailwind CSS v4
|
|
242
|
+
- Mapping `onNavigate` to your framework's router
|
|
243
|
+
- Using the `MockProvider` for rapid prototyping
|
|
244
|
+
- Configuring `FileManagerModal` v/s full-page `FileManager`
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
> [!NOTE]
|
|
249
|
+
> The `onNavigate` prop is also available on `<FileManagerModal>` for modal mode.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
160
253
|
## 💾 Database Schema Design
|
|
161
254
|
|
|
162
255
|
Because this application relies heavily on tree structures (Folders inside Folders) and varied JSON metadata (Video durations vs Document page counts), using a relational database with JSONB support (like PostgreSQL) is highly recommended.
|
package/dist/cli.cjs
CHANGED
|
@@ -38,13 +38,13 @@ var rl = import_readline.default.createInterface({
|
|
|
38
38
|
var askQuestion = (query) => {
|
|
39
39
|
return new Promise((resolve) => rl.question(query, resolve));
|
|
40
40
|
};
|
|
41
|
-
var
|
|
41
|
+
var getTemplate = (basePath = "/media") => `"use client";
|
|
42
42
|
|
|
43
|
-
import React, { Suspense
|
|
43
|
+
import React, { Suspense } from "react";
|
|
44
44
|
import { FileManager, MockProvider } from "@unciatech/file-manager";
|
|
45
45
|
|
|
46
46
|
export default function FileManagerDemo() {
|
|
47
|
-
const
|
|
47
|
+
const mockProvider = new MockProvider();
|
|
48
48
|
|
|
49
49
|
return (
|
|
50
50
|
<div className="h-screen w-full">
|
|
@@ -52,7 +52,8 @@ export default function FileManagerDemo() {
|
|
|
52
52
|
<FileManager
|
|
53
53
|
allowedFileTypes={["audios", "videos", "images", "files"]}
|
|
54
54
|
viewMode="grid"
|
|
55
|
-
provider={
|
|
55
|
+
provider={mockProvider}
|
|
56
|
+
basePath="${basePath}"
|
|
56
57
|
/>
|
|
57
58
|
</Suspense>
|
|
58
59
|
</div>
|
|
@@ -77,8 +78,11 @@ async function main() {
|
|
|
77
78
|
console.error(`\u274C Error: ${targetFile} already exists.`);
|
|
78
79
|
process.exit(1);
|
|
79
80
|
}
|
|
80
|
-
import_fs.default.writeFileSync(targetFile,
|
|
81
|
+
import_fs.default.writeFileSync(targetFile, getTemplate("/"), "utf-8");
|
|
81
82
|
console.log(`\u2705 Success! Created ${targetFile}`);
|
|
83
|
+
console.log("");
|
|
84
|
+
console.log("You can now import and render <FileManagerDemo /> anywhere in your application.");
|
|
85
|
+
console.log("Don't forget to configure your Tailwind CSS content to scan the library for styles!");
|
|
82
86
|
process.exit(0);
|
|
83
87
|
}
|
|
84
88
|
console.log(`
|
|
@@ -89,11 +93,12 @@ async function main() {
|
|
|
89
93
|
console.log(" 2) Vite (React, Tailwind v4)");
|
|
90
94
|
console.log(" 3) Cancel");
|
|
91
95
|
const choice = await askQuestion("\nSelect an option (1-3): ");
|
|
92
|
-
rl.close();
|
|
93
96
|
const targetDir = import_path.default.join(process.cwd(), projectName);
|
|
94
97
|
if (import_fs.default.existsSync(targetDir)) {
|
|
95
98
|
console.error(`
|
|
96
|
-
\u274C Error: Directory "${projectName}" already exists.`);
|
|
99
|
+
\u274C Error: Directory "${projectName}" already exists in ${process.cwd()}.`);
|
|
100
|
+
console.error(` Please choose a different project name or delete the existing directory first.`);
|
|
101
|
+
rl.close();
|
|
97
102
|
process.exit(1);
|
|
98
103
|
}
|
|
99
104
|
try {
|
|
@@ -112,13 +117,13 @@ async function main() {
|
|
|
112
117
|
process.exit(0);
|
|
113
118
|
}
|
|
114
119
|
async function scaffoldNextjs(projectName2, targetDir) {
|
|
115
|
-
console.log("\n\u{1F4E6} Creating Next.js application...");
|
|
120
|
+
console.log("\n\u{1F4E6} Creating Next.js application (this may take a minute)...");
|
|
116
121
|
(0, import_child_process.execSync)(`npx create-next-app@latest ${projectName2} --ts --tailwind --eslint --app --src-dir --import-alias "@/*" --use-npm`, { stdio: "inherit" });
|
|
117
|
-
console.log("\n\u{1F4E6} Installing dependencies...");
|
|
122
|
+
console.log("\n\u{1F4E6} Installing dependencies (@unciatech/file-manager, tailwindcss-animate)...");
|
|
118
123
|
(0, import_child_process.execSync)("npm install @unciatech/file-manager tailwindcss-animate", { cwd: targetDir, stdio: "inherit" });
|
|
119
124
|
const componentsDir = import_path.default.join(targetDir, "src", "components");
|
|
120
125
|
if (!import_fs.default.existsSync(componentsDir)) import_fs.default.mkdirSync(componentsDir, { recursive: true });
|
|
121
|
-
import_fs.default.writeFileSync(import_path.default.join(componentsDir, "FileManagerDemo.tsx"),
|
|
126
|
+
import_fs.default.writeFileSync(import_path.default.join(componentsDir, "FileManagerDemo.tsx"), getTemplate("/media"), "utf-8");
|
|
122
127
|
const pagePath = import_path.default.join(targetDir, "src", "app", "page.tsx");
|
|
123
128
|
import_fs.default.writeFileSync(pagePath, `import FileManagerDemo from "@/components/FileManagerDemo";
|
|
124
129
|
|
|
@@ -129,22 +134,56 @@ export default function Home() {
|
|
|
129
134
|
</main>
|
|
130
135
|
);
|
|
131
136
|
}
|
|
137
|
+
`);
|
|
138
|
+
const mediaRouteDir = import_path.default.join(targetDir, "src", "app", "media", "[[...path]]");
|
|
139
|
+
import_fs.default.mkdirSync(mediaRouteDir, { recursive: true });
|
|
140
|
+
import_fs.default.writeFileSync(
|
|
141
|
+
import_path.default.join(mediaRouteDir, "page.tsx"),
|
|
142
|
+
`import FileManagerDemo from "@/components/FileManagerDemo";
|
|
143
|
+
|
|
144
|
+
export default function MediaPage() {
|
|
145
|
+
return (
|
|
146
|
+
<main className="min-h-screen bg-neutral-50">
|
|
147
|
+
<FileManagerDemo />
|
|
148
|
+
</main>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
`
|
|
152
|
+
);
|
|
153
|
+
const layoutPath = import_path.default.join(targetDir, "src", "app", "layout.tsx");
|
|
154
|
+
if (import_fs.default.existsSync(layoutPath)) {
|
|
155
|
+
let layoutContent = import_fs.default.readFileSync(layoutPath, "utf8");
|
|
156
|
+
if (!layoutContent.includes("@unciatech/file-manager/styles")) {
|
|
157
|
+
layoutContent = layoutContent.replace(
|
|
158
|
+
/^(import type)/m,
|
|
159
|
+
`import '@unciatech/file-manager/styles';
|
|
160
|
+
$1`
|
|
161
|
+
);
|
|
162
|
+
import_fs.default.writeFileSync(layoutPath, layoutContent);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const cssPath = import_path.default.join(targetDir, "src", "app", "globals.css");
|
|
166
|
+
import_fs.default.writeFileSync(cssPath, `@import "tailwindcss";
|
|
167
|
+
@import "@unciatech/file-manager/styles";
|
|
168
|
+
@import "tw-animate-css";
|
|
169
|
+
|
|
170
|
+
@source "../../node_modules/@unciatech/file-manager";
|
|
171
|
+
|
|
172
|
+
@theme {
|
|
173
|
+
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
|
|
174
|
+
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
175
|
+
}
|
|
132
176
|
`);
|
|
133
177
|
printSuccess(projectName2);
|
|
134
178
|
}
|
|
135
179
|
async function scaffoldVite(projectName2, targetDir) {
|
|
136
180
|
console.log("\n\u{1F4E6} Creating Vite React application...");
|
|
137
181
|
(0, import_child_process.execSync)(`npm create vite@latest ${projectName2} -- --template react-ts`, { stdio: "inherit" });
|
|
138
|
-
console.log("\n\u{1F4E6} Installing dependencies...");
|
|
182
|
+
console.log("\n\u{1F4E6} Installing dependencies (Tailwind + File Manager)...");
|
|
139
183
|
(0, import_child_process.execSync)("npm install", { cwd: targetDir, stdio: "inherit" });
|
|
140
|
-
(0, import_child_process.execSync)(
|
|
141
|
-
"npm install tailwindcss @tailwindcss/vite @unciatech/file-manager tw-animate-css",
|
|
142
|
-
{ cwd: targetDir, stdio: "inherit" }
|
|
143
|
-
);
|
|
184
|
+
(0, import_child_process.execSync)("npm install tailwindcss @tailwindcss/vite @unciatech/file-manager", { cwd: targetDir, stdio: "inherit" });
|
|
144
185
|
const viteConfigPath = import_path.default.join(targetDir, "vite.config.ts");
|
|
145
|
-
|
|
146
|
-
viteConfigPath,
|
|
147
|
-
`import { defineConfig } from 'vite'
|
|
186
|
+
const viteConfig = `import { defineConfig } from 'vite'
|
|
148
187
|
import react from '@vitejs/plugin-react'
|
|
149
188
|
import tailwindcss from '@tailwindcss/vite'
|
|
150
189
|
|
|
@@ -154,39 +193,18 @@ export default defineConfig({
|
|
|
154
193
|
tailwindcss(),
|
|
155
194
|
],
|
|
156
195
|
})
|
|
157
|
-
|
|
158
|
-
);
|
|
196
|
+
`;
|
|
197
|
+
import_fs.default.writeFileSync(viteConfigPath, viteConfig);
|
|
159
198
|
const cssPath = import_path.default.join(targetDir, "src", "index.css");
|
|
160
|
-
import_fs.default.writeFileSync(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
@source "../node_modules/@unciatech/file-manager/dist/**/*.{js,ts,jsx,tsx}";
|
|
166
|
-
`
|
|
167
|
-
);
|
|
168
|
-
const mainPath = import_path.default.join(targetDir, "src", "main.tsx");
|
|
169
|
-
if (import_fs.default.existsSync(mainPath)) {
|
|
170
|
-
let mainContent = import_fs.default.readFileSync(mainPath, "utf8");
|
|
171
|
-
if (!mainContent.includes("@unciatech/file-manager/styles")) {
|
|
172
|
-
mainContent = `import "@unciatech/file-manager/styles";
|
|
173
|
-
` + mainContent;
|
|
174
|
-
import_fs.default.writeFileSync(mainPath, mainContent);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
199
|
+
import_fs.default.writeFileSync(cssPath, `@import "tailwindcss";
|
|
200
|
+
@import "@unciatech/file-manager/styles";
|
|
201
|
+
@source "../node_modules/@unciatech/file-manager";
|
|
202
|
+
`);
|
|
177
203
|
const componentsDir = import_path.default.join(targetDir, "src", "components");
|
|
178
|
-
if (!import_fs.default.existsSync(componentsDir)) {
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
import_fs.default.writeFileSync(
|
|
182
|
-
import_path.default.join(componentsDir, "FileManagerDemo.tsx"),
|
|
183
|
-
TEMPLATE,
|
|
184
|
-
"utf-8"
|
|
185
|
-
);
|
|
204
|
+
if (!import_fs.default.existsSync(componentsDir)) import_fs.default.mkdirSync(componentsDir, { recursive: true });
|
|
205
|
+
import_fs.default.writeFileSync(import_path.default.join(componentsDir, "FileManagerDemo.tsx"), getTemplate("/"), "utf-8");
|
|
186
206
|
const appPath = import_path.default.join(targetDir, "src", "App.tsx");
|
|
187
|
-
import_fs.default.writeFileSync(
|
|
188
|
-
appPath,
|
|
189
|
-
`import FileManagerDemo from "./components/FileManagerDemo";
|
|
207
|
+
import_fs.default.writeFileSync(appPath, `import FileManagerDemo from "./components/FileManagerDemo";
|
|
190
208
|
|
|
191
209
|
function App() {
|
|
192
210
|
return (
|
|
@@ -197,9 +215,8 @@ function App() {
|
|
|
197
215
|
}
|
|
198
216
|
|
|
199
217
|
export default App;
|
|
200
|
-
`
|
|
201
|
-
);
|
|
202
|
-
printSuccess(projectName2);
|
|
218
|
+
`);
|
|
219
|
+
printSuccess(projectName2, "npm run dev");
|
|
203
220
|
}
|
|
204
221
|
function printSuccess(projectName2, devCmd = "npm run dev") {
|
|
205
222
|
console.log("\n=========================================");
|
package/dist/cli.js
CHANGED
|
@@ -15,13 +15,13 @@ var rl = readline.createInterface({
|
|
|
15
15
|
var askQuestion = (query) => {
|
|
16
16
|
return new Promise((resolve) => rl.question(query, resolve));
|
|
17
17
|
};
|
|
18
|
-
var
|
|
18
|
+
var getTemplate = (basePath = "/media") => `"use client";
|
|
19
19
|
|
|
20
|
-
import React, { Suspense
|
|
20
|
+
import React, { Suspense } from "react";
|
|
21
21
|
import { FileManager, MockProvider } from "@unciatech/file-manager";
|
|
22
22
|
|
|
23
23
|
export default function FileManagerDemo() {
|
|
24
|
-
const
|
|
24
|
+
const mockProvider = new MockProvider();
|
|
25
25
|
|
|
26
26
|
return (
|
|
27
27
|
<div className="h-screen w-full">
|
|
@@ -29,7 +29,8 @@ export default function FileManagerDemo() {
|
|
|
29
29
|
<FileManager
|
|
30
30
|
allowedFileTypes={["audios", "videos", "images", "files"]}
|
|
31
31
|
viewMode="grid"
|
|
32
|
-
provider={
|
|
32
|
+
provider={mockProvider}
|
|
33
|
+
basePath="${basePath}"
|
|
33
34
|
/>
|
|
34
35
|
</Suspense>
|
|
35
36
|
</div>
|
|
@@ -54,8 +55,11 @@ async function main() {
|
|
|
54
55
|
console.error(`\u274C Error: ${targetFile} already exists.`);
|
|
55
56
|
process.exit(1);
|
|
56
57
|
}
|
|
57
|
-
fs.writeFileSync(targetFile,
|
|
58
|
+
fs.writeFileSync(targetFile, getTemplate("/"), "utf-8");
|
|
58
59
|
console.log(`\u2705 Success! Created ${targetFile}`);
|
|
60
|
+
console.log("");
|
|
61
|
+
console.log("You can now import and render <FileManagerDemo /> anywhere in your application.");
|
|
62
|
+
console.log("Don't forget to configure your Tailwind CSS content to scan the library for styles!");
|
|
59
63
|
process.exit(0);
|
|
60
64
|
}
|
|
61
65
|
console.log(`
|
|
@@ -66,11 +70,12 @@ async function main() {
|
|
|
66
70
|
console.log(" 2) Vite (React, Tailwind v4)");
|
|
67
71
|
console.log(" 3) Cancel");
|
|
68
72
|
const choice = await askQuestion("\nSelect an option (1-3): ");
|
|
69
|
-
rl.close();
|
|
70
73
|
const targetDir = path.join(process.cwd(), projectName);
|
|
71
74
|
if (fs.existsSync(targetDir)) {
|
|
72
75
|
console.error(`
|
|
73
|
-
\u274C Error: Directory "${projectName}" already exists.`);
|
|
76
|
+
\u274C Error: Directory "${projectName}" already exists in ${process.cwd()}.`);
|
|
77
|
+
console.error(` Please choose a different project name or delete the existing directory first.`);
|
|
78
|
+
rl.close();
|
|
74
79
|
process.exit(1);
|
|
75
80
|
}
|
|
76
81
|
try {
|
|
@@ -89,13 +94,13 @@ async function main() {
|
|
|
89
94
|
process.exit(0);
|
|
90
95
|
}
|
|
91
96
|
async function scaffoldNextjs(projectName2, targetDir) {
|
|
92
|
-
console.log("\n\u{1F4E6} Creating Next.js application...");
|
|
97
|
+
console.log("\n\u{1F4E6} Creating Next.js application (this may take a minute)...");
|
|
93
98
|
execSync(`npx create-next-app@latest ${projectName2} --ts --tailwind --eslint --app --src-dir --import-alias "@/*" --use-npm`, { stdio: "inherit" });
|
|
94
|
-
console.log("\n\u{1F4E6} Installing dependencies...");
|
|
99
|
+
console.log("\n\u{1F4E6} Installing dependencies (@unciatech/file-manager, tailwindcss-animate)...");
|
|
95
100
|
execSync("npm install @unciatech/file-manager tailwindcss-animate", { cwd: targetDir, stdio: "inherit" });
|
|
96
101
|
const componentsDir = path.join(targetDir, "src", "components");
|
|
97
102
|
if (!fs.existsSync(componentsDir)) fs.mkdirSync(componentsDir, { recursive: true });
|
|
98
|
-
fs.writeFileSync(path.join(componentsDir, "FileManagerDemo.tsx"),
|
|
103
|
+
fs.writeFileSync(path.join(componentsDir, "FileManagerDemo.tsx"), getTemplate("/media"), "utf-8");
|
|
99
104
|
const pagePath = path.join(targetDir, "src", "app", "page.tsx");
|
|
100
105
|
fs.writeFileSync(pagePath, `import FileManagerDemo from "@/components/FileManagerDemo";
|
|
101
106
|
|
|
@@ -106,22 +111,56 @@ export default function Home() {
|
|
|
106
111
|
</main>
|
|
107
112
|
);
|
|
108
113
|
}
|
|
114
|
+
`);
|
|
115
|
+
const mediaRouteDir = path.join(targetDir, "src", "app", "media", "[[...path]]");
|
|
116
|
+
fs.mkdirSync(mediaRouteDir, { recursive: true });
|
|
117
|
+
fs.writeFileSync(
|
|
118
|
+
path.join(mediaRouteDir, "page.tsx"),
|
|
119
|
+
`import FileManagerDemo from "@/components/FileManagerDemo";
|
|
120
|
+
|
|
121
|
+
export default function MediaPage() {
|
|
122
|
+
return (
|
|
123
|
+
<main className="min-h-screen bg-neutral-50">
|
|
124
|
+
<FileManagerDemo />
|
|
125
|
+
</main>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
`
|
|
129
|
+
);
|
|
130
|
+
const layoutPath = path.join(targetDir, "src", "app", "layout.tsx");
|
|
131
|
+
if (fs.existsSync(layoutPath)) {
|
|
132
|
+
let layoutContent = fs.readFileSync(layoutPath, "utf8");
|
|
133
|
+
if (!layoutContent.includes("@unciatech/file-manager/styles")) {
|
|
134
|
+
layoutContent = layoutContent.replace(
|
|
135
|
+
/^(import type)/m,
|
|
136
|
+
`import '@unciatech/file-manager/styles';
|
|
137
|
+
$1`
|
|
138
|
+
);
|
|
139
|
+
fs.writeFileSync(layoutPath, layoutContent);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const cssPath = path.join(targetDir, "src", "app", "globals.css");
|
|
143
|
+
fs.writeFileSync(cssPath, `@import "tailwindcss";
|
|
144
|
+
@import "@unciatech/file-manager/styles";
|
|
145
|
+
@import "tw-animate-css";
|
|
146
|
+
|
|
147
|
+
@source "../../node_modules/@unciatech/file-manager";
|
|
148
|
+
|
|
149
|
+
@theme {
|
|
150
|
+
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
|
|
151
|
+
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
152
|
+
}
|
|
109
153
|
`);
|
|
110
154
|
printSuccess(projectName2);
|
|
111
155
|
}
|
|
112
156
|
async function scaffoldVite(projectName2, targetDir) {
|
|
113
157
|
console.log("\n\u{1F4E6} Creating Vite React application...");
|
|
114
158
|
execSync(`npm create vite@latest ${projectName2} -- --template react-ts`, { stdio: "inherit" });
|
|
115
|
-
console.log("\n\u{1F4E6} Installing dependencies...");
|
|
159
|
+
console.log("\n\u{1F4E6} Installing dependencies (Tailwind + File Manager)...");
|
|
116
160
|
execSync("npm install", { cwd: targetDir, stdio: "inherit" });
|
|
117
|
-
execSync(
|
|
118
|
-
"npm install tailwindcss @tailwindcss/vite @unciatech/file-manager tw-animate-css",
|
|
119
|
-
{ cwd: targetDir, stdio: "inherit" }
|
|
120
|
-
);
|
|
161
|
+
execSync("npm install tailwindcss @tailwindcss/vite @unciatech/file-manager", { cwd: targetDir, stdio: "inherit" });
|
|
121
162
|
const viteConfigPath = path.join(targetDir, "vite.config.ts");
|
|
122
|
-
|
|
123
|
-
viteConfigPath,
|
|
124
|
-
`import { defineConfig } from 'vite'
|
|
163
|
+
const viteConfig = `import { defineConfig } from 'vite'
|
|
125
164
|
import react from '@vitejs/plugin-react'
|
|
126
165
|
import tailwindcss from '@tailwindcss/vite'
|
|
127
166
|
|
|
@@ -131,39 +170,18 @@ export default defineConfig({
|
|
|
131
170
|
tailwindcss(),
|
|
132
171
|
],
|
|
133
172
|
})
|
|
134
|
-
|
|
135
|
-
);
|
|
173
|
+
`;
|
|
174
|
+
fs.writeFileSync(viteConfigPath, viteConfig);
|
|
136
175
|
const cssPath = path.join(targetDir, "src", "index.css");
|
|
137
|
-
fs.writeFileSync(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
@source "../node_modules/@unciatech/file-manager/dist/**/*.{js,ts,jsx,tsx}";
|
|
143
|
-
`
|
|
144
|
-
);
|
|
145
|
-
const mainPath = path.join(targetDir, "src", "main.tsx");
|
|
146
|
-
if (fs.existsSync(mainPath)) {
|
|
147
|
-
let mainContent = fs.readFileSync(mainPath, "utf8");
|
|
148
|
-
if (!mainContent.includes("@unciatech/file-manager/styles")) {
|
|
149
|
-
mainContent = `import "@unciatech/file-manager/styles";
|
|
150
|
-
` + mainContent;
|
|
151
|
-
fs.writeFileSync(mainPath, mainContent);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
176
|
+
fs.writeFileSync(cssPath, `@import "tailwindcss";
|
|
177
|
+
@import "@unciatech/file-manager/styles";
|
|
178
|
+
@source "../node_modules/@unciatech/file-manager";
|
|
179
|
+
`);
|
|
154
180
|
const componentsDir = path.join(targetDir, "src", "components");
|
|
155
|
-
if (!fs.existsSync(componentsDir)) {
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
fs.writeFileSync(
|
|
159
|
-
path.join(componentsDir, "FileManagerDemo.tsx"),
|
|
160
|
-
TEMPLATE,
|
|
161
|
-
"utf-8"
|
|
162
|
-
);
|
|
181
|
+
if (!fs.existsSync(componentsDir)) fs.mkdirSync(componentsDir, { recursive: true });
|
|
182
|
+
fs.writeFileSync(path.join(componentsDir, "FileManagerDemo.tsx"), getTemplate("/"), "utf-8");
|
|
163
183
|
const appPath = path.join(targetDir, "src", "App.tsx");
|
|
164
|
-
fs.writeFileSync(
|
|
165
|
-
appPath,
|
|
166
|
-
`import FileManagerDemo from "./components/FileManagerDemo";
|
|
184
|
+
fs.writeFileSync(appPath, `import FileManagerDemo from "./components/FileManagerDemo";
|
|
167
185
|
|
|
168
186
|
function App() {
|
|
169
187
|
return (
|
|
@@ -174,9 +192,8 @@ function App() {
|
|
|
174
192
|
}
|
|
175
193
|
|
|
176
194
|
export default App;
|
|
177
|
-
`
|
|
178
|
-
);
|
|
179
|
-
printSuccess(projectName2);
|
|
195
|
+
`);
|
|
196
|
+
printSuccess(projectName2, "npm run dev");
|
|
180
197
|
}
|
|
181
198
|
function printSuccess(projectName2, devCmd = "npm run dev") {
|
|
182
199
|
console.log("\n=========================================");
|