@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # 🗂️ File Manager
2
2
 
3
- A robust, production-ready React / Next.js file management system designed to mirror the capabilities of professional asset managers (like Google Drive, macOS Finder, or Strapi Media Library).
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 / React
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
- ## 🚀 How to Install and Use in Your Project
25
+ ## Setup & Requirements
26
26
 
27
- If you want to integrate this File Manager into your own Next.js or React application, follow this step-by-step guide.
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 { FileManagerProvider } from "@/context/file-manager-context";
133
- import { FileManager } from "@/components/file-manager";
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 TEMPLATE = `"use client";
41
+ var getTemplate = (basePath = "/media") => `"use client";
42
42
 
43
- import React, { Suspense, useMemo } from "react";
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 provider = useMemo(() => new MockProvider(), []);
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={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, TEMPLATE, "utf-8");
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"), TEMPLATE, "utf-8");
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
- import_fs.default.writeFileSync(
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
- cssPath,
162
- `@import "tailwindcss";
163
- @import "tw-animate-css";
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
- import_fs.default.mkdirSync(componentsDir, { recursive: true });
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 TEMPLATE = `"use client";
18
+ var getTemplate = (basePath = "/media") => `"use client";
19
19
 
20
- import React, { Suspense, useMemo } from "react";
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 provider = useMemo(() => new MockProvider(), []);
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={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, TEMPLATE, "utf-8");
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"), TEMPLATE, "utf-8");
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
- fs.writeFileSync(
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
- cssPath,
139
- `@import "tailwindcss";
140
- @import "tw-animate-css";
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
- fs.mkdirSync(componentsDir, { recursive: true });
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=========================================");