@lastbrain/app 0.1.46 → 1.0.1
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/app-shell/layout.d.ts +1 -1
- package/dist/app-shell/layout.d.ts.map +1 -1
- package/dist/app-shell/layout.js +1 -1
- package/dist/components/NotificationContainer.js +1 -1
- package/dist/index.d.ts +19 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -19
- package/dist/layouts/AdminLayoutWithSidebar.d.ts +3 -2
- package/dist/layouts/AdminLayoutWithSidebar.d.ts.map +1 -1
- package/dist/layouts/AdminLayoutWithSidebar.js +5 -5
- package/dist/layouts/AppProviders.d.ts +1 -1
- package/dist/layouts/AppProviders.d.ts.map +1 -1
- package/dist/layouts/AppProviders.js +3 -3
- package/dist/layouts/AuthLayoutWithSidebar.d.ts +7 -4
- package/dist/layouts/AuthLayoutWithSidebar.d.ts.map +1 -1
- package/dist/layouts/AuthLayoutWithSidebar.js +5 -5
- package/dist/layouts/PublicLayoutWithSidebar.js +2 -2
- package/dist/layouts/RootLayout.js +1 -1
- package/dist/scripts/init-app.d.ts.map +1 -1
- package/dist/scripts/init-app.js +488 -50
- package/dist/scripts/module-add.js +1 -1
- package/dist/scripts/module-build.d.ts.map +1 -1
- package/dist/scripts/module-build.js +36 -15
- package/dist/scripts/module-create.js +8 -8
- package/dist/scripts/module-delete.d.ts.map +1 -1
- package/dist/scripts/module-delete.js +1 -1
- package/dist/templates/DefaultDoc.js +2 -2
- package/dist/templates/DocPage.js +1 -1
- package/dist/templates/DocsPageWithModules.js +1 -1
- package/dist/types/menu.d.ts +23 -0
- package/dist/types/menu.d.ts.map +1 -0
- package/dist/types/menu.js +1 -0
- package/package.json +11 -3
- package/src/app-shell/layout.tsx +1 -1
- package/src/components/NotificationContainer.tsx +1 -1
- package/src/index.ts +24 -19
- package/src/layouts/AdminLayoutWithSidebar.tsx +11 -3
- package/src/layouts/AppProviders.tsx +4 -4
- package/src/layouts/AuthLayoutWithSidebar.tsx +18 -4
- package/src/layouts/PublicLayoutWithSidebar.tsx +2 -2
- package/src/layouts/RootLayout.tsx +1 -1
- package/src/scripts/init-app.ts +514 -60
- package/src/scripts/module-add.ts +1 -1
- package/src/scripts/module-build.ts +46 -22
- package/src/scripts/module-create.ts +8 -8
- package/src/scripts/module-delete.ts +1 -4
- package/src/templates/DefaultDoc.tsx +2 -2
- package/src/templates/DocPage.tsx +1 -1
- package/src/templates/DocsPageWithModules.tsx +1 -1
- package/src/types/menu.ts +18 -0
package/src/scripts/init-app.ts
CHANGED
|
@@ -4,10 +4,7 @@ import { fileURLToPath } from "url";
|
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import inquirer from "inquirer";
|
|
6
6
|
import { execSync } from "child_process";
|
|
7
|
-
import {
|
|
8
|
-
AVAILABLE_MODULES,
|
|
9
|
-
type ModuleMetadata,
|
|
10
|
-
} from "@lastbrain/core/config/modules";
|
|
7
|
+
import { AVAILABLE_MODULES } from "@lastbrain/core/config/modules";
|
|
11
8
|
|
|
12
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
13
10
|
const __dirname = path.dirname(__filename);
|
|
@@ -131,6 +128,7 @@ export async function initApp(options: InitAppOptions) {
|
|
|
131
128
|
await createGitIgnore(targetDir, force);
|
|
132
129
|
await createEnvExample(targetDir, force);
|
|
133
130
|
await createEnvLocal(targetDir, force, isMonorepoProject);
|
|
131
|
+
await createEnvProd(targetDir, force);
|
|
134
132
|
|
|
135
133
|
// 7. Créer la structure Supabase avec migrations (seulement pour projets indépendants)
|
|
136
134
|
if (!isMonorepoProject) {
|
|
@@ -195,20 +193,31 @@ export async function initApp(options: InitAppOptions) {
|
|
|
195
193
|
stdio: "inherit",
|
|
196
194
|
});
|
|
197
195
|
console.log(chalk.green("\n✓ Migrations synchronisées\n"));
|
|
198
|
-
} catch (
|
|
196
|
+
} catch (_error) {
|
|
199
197
|
console.log(
|
|
200
198
|
chalk.yellow("\n⚠️ Erreur de synchronisation des migrations\n")
|
|
201
199
|
);
|
|
202
200
|
}
|
|
203
201
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
execSync("pnpm db:init", { cwd: targetDir, stdio: "inherit" });
|
|
207
|
-
console.log(chalk.green("\n✓ Base de données initialisée\n"));
|
|
208
|
-
} catch {
|
|
202
|
+
// Ne pas initialiser la BDD en mode monorepo
|
|
203
|
+
if (!isMonorepoProject) {
|
|
209
204
|
console.log(
|
|
210
|
-
chalk.yellow(
|
|
211
|
-
|
|
205
|
+
chalk.yellow("🗄️ Initialisation de la base de données...\n")
|
|
206
|
+
);
|
|
207
|
+
try {
|
|
208
|
+
execSync("pnpm db:init", { cwd: targetDir, stdio: "inherit" });
|
|
209
|
+
console.log(chalk.green("\n✓ Base de données initialisée\n"));
|
|
210
|
+
} catch {
|
|
211
|
+
console.log(
|
|
212
|
+
chalk.yellow(
|
|
213
|
+
"\n⚠️ Erreur d'initialisation de la DB (normal si Supabase pas configuré)\n"
|
|
214
|
+
)
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
console.log(
|
|
219
|
+
chalk.cyan(
|
|
220
|
+
"⏭️ Mode monorepo détecté - BDD centralisée, pas d'initialisation locale requise\n"
|
|
212
221
|
)
|
|
213
222
|
);
|
|
214
223
|
}
|
|
@@ -226,14 +235,20 @@ export async function initApp(options: InitAppOptions) {
|
|
|
226
235
|
console.log(
|
|
227
236
|
chalk.white(" 1. Cliquez sur 'Get Started' sur la page d'accueil")
|
|
228
237
|
);
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
238
|
+
if (isMonorepoProject) {
|
|
239
|
+
console.log(
|
|
240
|
+
chalk.white(" 2. La BDD est centralisée dans le monorepo\n")
|
|
241
|
+
);
|
|
242
|
+
} else {
|
|
243
|
+
console.log(chalk.white(" 2. Lancez Docker Desktop"));
|
|
244
|
+
console.log(
|
|
245
|
+
chalk.white(
|
|
246
|
+
" 3. Installez Supabase CLI si nécessaire : brew install supabase/tap/supabase"
|
|
247
|
+
)
|
|
248
|
+
);
|
|
249
|
+
console.log(chalk.white(" 4. Exécutez : pnpm db:init"));
|
|
250
|
+
console.log(chalk.white(" 5. Rechargez la page\n"));
|
|
251
|
+
}
|
|
237
252
|
|
|
238
253
|
// Ouvrir le navigateur
|
|
239
254
|
const openCommand =
|
|
@@ -251,7 +266,7 @@ export async function initApp(options: InitAppOptions) {
|
|
|
251
266
|
}, 2000);
|
|
252
267
|
|
|
253
268
|
// Lancer pnpm dev
|
|
254
|
-
execSync("pnpm dev", { cwd: targetDir, stdio: "inherit" });
|
|
269
|
+
execSync("pnpm dev:local", { cwd: targetDir, stdio: "inherit" });
|
|
255
270
|
} catch {
|
|
256
271
|
console.error(chalk.red("\n❌ Erreur lors du lancement\n"));
|
|
257
272
|
console.log(chalk.cyan("\nVous pouvez lancer manuellement avec :"));
|
|
@@ -259,8 +274,10 @@ export async function initApp(options: InitAppOptions) {
|
|
|
259
274
|
console.log(chalk.white(" pnpm install"));
|
|
260
275
|
console.log(chalk.white(" pnpm build:modules"));
|
|
261
276
|
console.log(chalk.white(" pnpm db:migrations:sync"));
|
|
262
|
-
|
|
263
|
-
|
|
277
|
+
if (!isMonorepoProject) {
|
|
278
|
+
console.log(chalk.white(" pnpm db:init"));
|
|
279
|
+
}
|
|
280
|
+
console.log(chalk.white(" pnpm dev:local (ou pnpm dev:prod)\n"));
|
|
264
281
|
}
|
|
265
282
|
} else {
|
|
266
283
|
console.log(chalk.cyan("\n📋 Prochaines étapes:"));
|
|
@@ -275,7 +292,12 @@ export async function initApp(options: InitAppOptions) {
|
|
|
275
292
|
console.log(
|
|
276
293
|
chalk.white(" 5. pnpm db:init (initialiser la base de données)")
|
|
277
294
|
);
|
|
278
|
-
console.log(chalk.white(" 6. pnpm dev (
|
|
295
|
+
console.log(chalk.white(" 6. pnpm dev:local (ou pnpm dev:prod)\n"));
|
|
296
|
+
|
|
297
|
+
console.log(chalk.cyan("\n💡 Scripts disponibles:"));
|
|
298
|
+
console.log(chalk.white(" • pnpm dev:local - Lance avec .env.local"));
|
|
299
|
+
console.log(chalk.white(" • pnpm dev:prod - Lance avec .env.prod"));
|
|
300
|
+
console.log(chalk.white(" • pnpm dev - Lance avec .env actuel\n"));
|
|
279
301
|
|
|
280
302
|
console.log(chalk.gray("Prérequis pour Supabase :"));
|
|
281
303
|
console.log(chalk.white(" - Docker Desktop installé et lancé"));
|
|
@@ -405,10 +427,10 @@ function getLastBrainVersions(targetDir: string): {
|
|
|
405
427
|
moduleAi: moduleAiVersion,
|
|
406
428
|
};
|
|
407
429
|
}
|
|
408
|
-
} catch (
|
|
430
|
+
} catch (_error) {
|
|
409
431
|
console.warn(
|
|
410
432
|
chalk.yellow(
|
|
411
|
-
`⚠️ Impossible de lire les versions locales (${
|
|
433
|
+
`⚠️ Impossible de lire les versions locales (${_error}), utilisation de 'latest'`
|
|
412
434
|
)
|
|
413
435
|
);
|
|
414
436
|
}
|
|
@@ -514,6 +536,7 @@ async function addDependencies(
|
|
|
514
536
|
requiredDeps["lucide-react"] = "^0.554.0";
|
|
515
537
|
requiredDeps["framer-motion"] = "^11.18.2";
|
|
516
538
|
requiredDeps["clsx"] = "^2.1.1";
|
|
539
|
+
requiredDeps["env-cmd"] = "^11.0.0";
|
|
517
540
|
}
|
|
518
541
|
|
|
519
542
|
// DevDependencies
|
|
@@ -910,17 +933,56 @@ async function createAppHeader(targetDir: string, force: boolean) {
|
|
|
910
933
|
if (!fs.existsSync(headerPath) || force) {
|
|
911
934
|
const headerContent = `"use client";
|
|
912
935
|
|
|
913
|
-
import { Header } from "@lastbrain/ui";
|
|
936
|
+
import { Header, type MenuItem } from "@lastbrain/ui";
|
|
914
937
|
import { menuConfig } from "../config/menu";
|
|
915
938
|
import { supabaseBrowserClient } from "@lastbrain/core";
|
|
916
939
|
import { useRouter } from "next/navigation";
|
|
917
940
|
import { useAuthSession, useNotificationsContext } from "@lastbrain/app";
|
|
941
|
+
import { useState, useEffect } from "react";
|
|
942
|
+
|
|
943
|
+
interface MenuIgnored {
|
|
944
|
+
public: { title: string; path: string }[];
|
|
945
|
+
auth: { title: string; path: string }[];
|
|
946
|
+
}
|
|
918
947
|
|
|
919
948
|
export function AppHeader() {
|
|
920
949
|
const router = useRouter();
|
|
921
950
|
const { user, isSuperAdmin } = useAuthSession();
|
|
922
951
|
const { data, loading, markAsRead, markAllAsRead, deleteNotification } =
|
|
923
952
|
useNotificationsContext();
|
|
953
|
+
const [menuIgnored, setMenuIgnored] = useState<MenuIgnored | undefined>();
|
|
954
|
+
const [menuCustom, setMenuCustom] = useState<MenuItem[] | undefined>();
|
|
955
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
956
|
+
|
|
957
|
+
// Charger menuIgnored et menuCustom s'ils existent
|
|
958
|
+
useEffect(() => {
|
|
959
|
+
let loadedIgnored = false;
|
|
960
|
+
let loadedCustom = false;
|
|
961
|
+
|
|
962
|
+
// Charger menu-ignored
|
|
963
|
+
import("../config/menu-ignored")
|
|
964
|
+
.then((mod) => setMenuIgnored(mod.menuIgnored))
|
|
965
|
+
.catch(() => setMenuIgnored(undefined))
|
|
966
|
+
.finally(() => {
|
|
967
|
+
loadedIgnored = true;
|
|
968
|
+
if (loadedIgnored && loadedCustom) setIsLoading(false);
|
|
969
|
+
});
|
|
970
|
+
|
|
971
|
+
// Charger menu-custom
|
|
972
|
+
import("../config/menu-custom")
|
|
973
|
+
.then((mod) => {
|
|
974
|
+
// Combiner les menus custom publics et auth
|
|
975
|
+
const customMenus: MenuItem[] = [];
|
|
976
|
+
if (mod.menuCustom?.public) customMenus.push(...mod.menuCustom.public);
|
|
977
|
+
if (mod.menuCustom?.auth) customMenus.push(...mod.menuCustom.auth);
|
|
978
|
+
setMenuCustom(customMenus.length > 0 ? customMenus : undefined);
|
|
979
|
+
})
|
|
980
|
+
.catch(() => setMenuCustom(undefined))
|
|
981
|
+
.finally(() => {
|
|
982
|
+
loadedCustom = true;
|
|
983
|
+
if (loadedIgnored && loadedCustom) setIsLoading(false);
|
|
984
|
+
});
|
|
985
|
+
}, []);
|
|
924
986
|
|
|
925
987
|
const handleLogout = async () => {
|
|
926
988
|
await supabaseBrowserClient.auth.signOut();
|
|
@@ -943,6 +1005,9 @@ export function AppHeader() {
|
|
|
943
1005
|
onMarkAsRead={markAsRead}
|
|
944
1006
|
onMarkAllAsRead={markAllAsRead}
|
|
945
1007
|
onDeleteNotification={deleteNotification}
|
|
1008
|
+
{...(menuIgnored ? { menuIgnored } : {})}
|
|
1009
|
+
{...(menuCustom ? { menuCustom } : {})}
|
|
1010
|
+
{...{ isLoadingMenus: isLoading }}
|
|
946
1011
|
/>
|
|
947
1012
|
);
|
|
948
1013
|
}
|
|
@@ -1040,7 +1105,58 @@ async function createConfigFiles(
|
|
|
1040
1105
|
const middlewarePath = path.join(targetDir, "middleware.ts");
|
|
1041
1106
|
if (!fs.existsSync(middlewarePath) || force) {
|
|
1042
1107
|
const middleware = `import { type NextRequest, NextResponse } from "next/server";
|
|
1043
|
-
import {
|
|
1108
|
+
import { createServerClient, type CookieOptions } from "@supabase/ssr";
|
|
1109
|
+
|
|
1110
|
+
/**
|
|
1111
|
+
* Crée un client Supabase pour le middleware
|
|
1112
|
+
*/
|
|
1113
|
+
function createMiddlewareClient(request: NextRequest) {
|
|
1114
|
+
let response = NextResponse.next({
|
|
1115
|
+
request: {
|
|
1116
|
+
headers: request.headers,
|
|
1117
|
+
},
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1120
|
+
const supabase = createServerClient(
|
|
1121
|
+
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
|
1122
|
+
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
|
1123
|
+
{
|
|
1124
|
+
cookies: {
|
|
1125
|
+
get(name: string) {
|
|
1126
|
+
return request.cookies.get(name)?.value;
|
|
1127
|
+
},
|
|
1128
|
+
set(name: string, value: string, options: CookieOptions) {
|
|
1129
|
+
request.cookies.set({
|
|
1130
|
+
name,
|
|
1131
|
+
value,
|
|
1132
|
+
...options,
|
|
1133
|
+
});
|
|
1134
|
+
response = NextResponse.next({
|
|
1135
|
+
request: {
|
|
1136
|
+
headers: request.headers,
|
|
1137
|
+
},
|
|
1138
|
+
});
|
|
1139
|
+
response.cookies.set({
|
|
1140
|
+
name,
|
|
1141
|
+
value,
|
|
1142
|
+
...options,
|
|
1143
|
+
});
|
|
1144
|
+
},
|
|
1145
|
+
remove(name: string, options: CookieOptions) {
|
|
1146
|
+
request.cookies.delete(name);
|
|
1147
|
+
response = NextResponse.next({
|
|
1148
|
+
request: {
|
|
1149
|
+
headers: request.headers,
|
|
1150
|
+
},
|
|
1151
|
+
});
|
|
1152
|
+
response.cookies.delete(name);
|
|
1153
|
+
},
|
|
1154
|
+
},
|
|
1155
|
+
}
|
|
1156
|
+
);
|
|
1157
|
+
|
|
1158
|
+
return { supabase, response };
|
|
1159
|
+
}
|
|
1044
1160
|
|
|
1045
1161
|
export async function middleware(request: NextRequest) {
|
|
1046
1162
|
const { pathname } = request.nextUrl;
|
|
@@ -1188,9 +1304,9 @@ export const config = {
|
|
|
1188
1304
|
const nextConfig = `/** @type {import('next').NextConfig} */
|
|
1189
1305
|
const nextConfig = {
|
|
1190
1306
|
reactStrictMode: true,
|
|
1191
|
-
|
|
1307
|
+
devIndicators: {
|
|
1192
1308
|
position: 'bottom-right',
|
|
1193
|
-
}
|
|
1309
|
+
}
|
|
1194
1310
|
};
|
|
1195
1311
|
|
|
1196
1312
|
export default nextConfig;
|
|
@@ -1205,7 +1321,7 @@ export default nextConfig;
|
|
|
1205
1321
|
let tailwindConfig = "";
|
|
1206
1322
|
|
|
1207
1323
|
if (useHeroUI) {
|
|
1208
|
-
// Configuration avec HeroUI
|
|
1324
|
+
// Configuration avec HeroUI - complète avec thèmes
|
|
1209
1325
|
tailwindConfig = `import { heroui } from "@heroui/theme";
|
|
1210
1326
|
|
|
1211
1327
|
/** @type {import('tailwindcss').Config} */
|
|
@@ -1217,8 +1333,195 @@ const config = {
|
|
|
1217
1333
|
"./node_modules/@heroui/theme/dist/**/*.{js,mjs}",
|
|
1218
1334
|
],
|
|
1219
1335
|
darkMode: "class",
|
|
1220
|
-
plugins: [
|
|
1221
|
-
|
|
1336
|
+
plugins: [
|
|
1337
|
+
heroui({
|
|
1338
|
+
themes: {
|
|
1339
|
+
light: {
|
|
1340
|
+
colors: {
|
|
1341
|
+
default: {
|
|
1342
|
+
950: "#0d0d0e",
|
|
1343
|
+
900: "#19191c",
|
|
1344
|
+
800: "#26262a",
|
|
1345
|
+
700: "#323238",
|
|
1346
|
+
600: "#3f3f46",
|
|
1347
|
+
500: "#65656b",
|
|
1348
|
+
400: "#8c8c90",
|
|
1349
|
+
300: "#b2b2b5",
|
|
1350
|
+
200: "#d9d9da",
|
|
1351
|
+
100: "#ffffff",
|
|
1352
|
+
foreground: "#000000",
|
|
1353
|
+
DEFAULT: "#d4d4d8",
|
|
1354
|
+
},
|
|
1355
|
+
primary: {
|
|
1356
|
+
50: "#eef2ff",
|
|
1357
|
+
100: "#e0e7ff",
|
|
1358
|
+
200: "#c7d2fe",
|
|
1359
|
+
300: "#a5b4fc",
|
|
1360
|
+
400: "#818cf8",
|
|
1361
|
+
500: "#6366f1",
|
|
1362
|
+
600: "#4f46e5",
|
|
1363
|
+
700: "#4338ca",
|
|
1364
|
+
800: "#3730a3",
|
|
1365
|
+
900: "#312e81",
|
|
1366
|
+
foreground: "#ffffff",
|
|
1367
|
+
DEFAULT: "#6366f1",
|
|
1368
|
+
},
|
|
1369
|
+
secondary: {
|
|
1370
|
+
50: "#f5e8ff",
|
|
1371
|
+
100: "#e8ccff",
|
|
1372
|
+
200: "#d7a6ff",
|
|
1373
|
+
300: "#c57fff",
|
|
1374
|
+
400: "#b359ff",
|
|
1375
|
+
500: "#9b37ff",
|
|
1376
|
+
600: "#7d1fcc",
|
|
1377
|
+
700: "#5f1799",
|
|
1378
|
+
800: "#410f66",
|
|
1379
|
+
900: "#240833",
|
|
1380
|
+
foreground: "#ffffff",
|
|
1381
|
+
DEFAULT: "#9b37ff",
|
|
1382
|
+
},
|
|
1383
|
+
success: {
|
|
1384
|
+
50: "#e7fff7",
|
|
1385
|
+
100: "#c3ffec",
|
|
1386
|
+
200: "#9affdf",
|
|
1387
|
+
300: "#70ffd2",
|
|
1388
|
+
400: "#4bffca",
|
|
1389
|
+
500: "#22e6b0",
|
|
1390
|
+
600: "#18b38a",
|
|
1391
|
+
700: "#108066",
|
|
1392
|
+
800: "#074d40",
|
|
1393
|
+
900: "#012b22",
|
|
1394
|
+
foreground: "#000",
|
|
1395
|
+
DEFAULT: "#22e6b0",
|
|
1396
|
+
},
|
|
1397
|
+
warning: {
|
|
1398
|
+
50: "#fff8e1",
|
|
1399
|
+
100: "#ffecb3",
|
|
1400
|
+
200: "#ffe082",
|
|
1401
|
+
300: "#ffd54f",
|
|
1402
|
+
400: "#ffca28",
|
|
1403
|
+
500: "#ffc107",
|
|
1404
|
+
600: "#ffb300",
|
|
1405
|
+
700: "#ffa000",
|
|
1406
|
+
800: "#ff8f00",
|
|
1407
|
+
900: "#ff6f00",
|
|
1408
|
+
foreground: "#000",
|
|
1409
|
+
DEFAULT: "#ffca28",
|
|
1410
|
+
},
|
|
1411
|
+
danger: {
|
|
1412
|
+
50: "#ffe6e9",
|
|
1413
|
+
100: "#ffbac1",
|
|
1414
|
+
200: "#ff8f99",
|
|
1415
|
+
300: "#ff6471",
|
|
1416
|
+
400: "#ff3949",
|
|
1417
|
+
500: "#ff112a",
|
|
1418
|
+
600: "#d80c22",
|
|
1419
|
+
700: "#b1081b",
|
|
1420
|
+
800: "#890514",
|
|
1421
|
+
900: "#62020d",
|
|
1422
|
+
foreground: "#fff",
|
|
1423
|
+
DEFAULT: "#ff112a",
|
|
1424
|
+
},
|
|
1425
|
+
background: "#f7f8fc",
|
|
1426
|
+
foreground: "#0e0e10",
|
|
1427
|
+
content1: "#ffffff",
|
|
1428
|
+
},
|
|
1429
|
+
},
|
|
1430
|
+
dark: {
|
|
1431
|
+
colors: {
|
|
1432
|
+
default: {
|
|
1433
|
+
50: "#1a1c1f",
|
|
1434
|
+
100: "#232529",
|
|
1435
|
+
200: "#2c2f34",
|
|
1436
|
+
300: "#363940",
|
|
1437
|
+
400: "#40444d",
|
|
1438
|
+
500: "#4b4f59",
|
|
1439
|
+
600: "#6c707b",
|
|
1440
|
+
700: "#8d919b",
|
|
1441
|
+
800: "#afb2bb",
|
|
1442
|
+
900: "#d1d3d9",
|
|
1443
|
+
foreground: "#ffffff",
|
|
1444
|
+
DEFAULT: "#363940",
|
|
1445
|
+
},
|
|
1446
|
+
primary: {
|
|
1447
|
+
50: "#312e81",
|
|
1448
|
+
100: "#3730a3",
|
|
1449
|
+
200: "#4338ca",
|
|
1450
|
+
300: "#4f46e5",
|
|
1451
|
+
400: "#6366f1",
|
|
1452
|
+
500: "#818cf8",
|
|
1453
|
+
600: "#a5b4fc",
|
|
1454
|
+
700: "#c7d2fe",
|
|
1455
|
+
800: "#e0e7ff",
|
|
1456
|
+
900: "#eef2ff",
|
|
1457
|
+
foreground: "#ffffff",
|
|
1458
|
+
DEFAULT: "#6366f1",
|
|
1459
|
+
},
|
|
1460
|
+
secondary: {
|
|
1461
|
+
50: "#240833",
|
|
1462
|
+
100: "#410f66",
|
|
1463
|
+
200: "#5f1799",
|
|
1464
|
+
300: "#7d1fcc",
|
|
1465
|
+
400: "#9b37ff",
|
|
1466
|
+
500: "#b359ff",
|
|
1467
|
+
600: "#c57fff",
|
|
1468
|
+
700: "#d7a6ff",
|
|
1469
|
+
800: "#e8ccff",
|
|
1470
|
+
900: "#f5e8ff",
|
|
1471
|
+
foreground: "#ffffff",
|
|
1472
|
+
DEFAULT: "#9b37ff",
|
|
1473
|
+
},
|
|
1474
|
+
success: {
|
|
1475
|
+
50: "#012b22",
|
|
1476
|
+
100: "#074d40",
|
|
1477
|
+
200: "#108066",
|
|
1478
|
+
300: "#18b38a",
|
|
1479
|
+
400: "#22e6b0",
|
|
1480
|
+
500: "#4bffca",
|
|
1481
|
+
600: "#70ffd2",
|
|
1482
|
+
700: "#9affdf",
|
|
1483
|
+
800: "#c3ffec",
|
|
1484
|
+
900: "#e7fff7",
|
|
1485
|
+
foreground: "#0e0e0e",
|
|
1486
|
+
DEFAULT: "#22e6b0",
|
|
1487
|
+
},
|
|
1488
|
+
warning: {
|
|
1489
|
+
50: "#3a2c00",
|
|
1490
|
+
100: "#5e4700",
|
|
1491
|
+
200: "#836300",
|
|
1492
|
+
300: "#a77e00",
|
|
1493
|
+
400: "#cc9900",
|
|
1494
|
+
500: "#ffc107",
|
|
1495
|
+
600: "#ffd54f",
|
|
1496
|
+
700: "#ffe082",
|
|
1497
|
+
800: "#ffecb3",
|
|
1498
|
+
900: "#fff8e1",
|
|
1499
|
+
foreground: "#000",
|
|
1500
|
+
DEFAULT: "#ffc107",
|
|
1501
|
+
},
|
|
1502
|
+
danger: {
|
|
1503
|
+
50: "#4a000a",
|
|
1504
|
+
100: "#6e000f",
|
|
1505
|
+
200: "#920014",
|
|
1506
|
+
300: "#b60019",
|
|
1507
|
+
400: "#da001f",
|
|
1508
|
+
500: "#ff112a",
|
|
1509
|
+
600: "#ff3949",
|
|
1510
|
+
700: "#ff6471",
|
|
1511
|
+
800: "#ff8f99",
|
|
1512
|
+
900: "#ffbac1",
|
|
1513
|
+
foreground: "#ffffff",
|
|
1514
|
+
DEFAULT: "#ff112a",
|
|
1515
|
+
},
|
|
1516
|
+
background: "#0f1114",
|
|
1517
|
+
foreground: "#f8f8f8",
|
|
1518
|
+
content1: "#15181d",
|
|
1519
|
+
},
|
|
1520
|
+
},
|
|
1521
|
+
},
|
|
1522
|
+
}),
|
|
1523
|
+
],
|
|
1524
|
+
};
|
|
1222
1525
|
|
|
1223
1526
|
export default config;
|
|
1224
1527
|
`;
|
|
@@ -1277,8 +1580,56 @@ export default config;
|
|
|
1277
1580
|
// tsconfig.json
|
|
1278
1581
|
const tsconfigPath = path.join(targetDir, "tsconfig.json");
|
|
1279
1582
|
if (!fs.existsSync(tsconfigPath) || force) {
|
|
1280
|
-
|
|
1281
|
-
|
|
1583
|
+
// Détecter si le projet cible est dans un monorepo
|
|
1584
|
+
const targetIsInMonorepo =
|
|
1585
|
+
fs.existsSync(
|
|
1586
|
+
path.join(targetDir, "../../../packages/core/package.json")
|
|
1587
|
+
) ||
|
|
1588
|
+
fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
|
|
1589
|
+
|
|
1590
|
+
// Générer les chemins en fonction du contexte
|
|
1591
|
+
const paths: Record<string, string[]> = {
|
|
1592
|
+
"@/*": ["./*"],
|
|
1593
|
+
};
|
|
1594
|
+
|
|
1595
|
+
if (targetIsInMonorepo) {
|
|
1596
|
+
// En monorepo, pointer sur les sources locales
|
|
1597
|
+
paths["@lastbrain/ui"] = ["../../packages/ui/src/index.ts"];
|
|
1598
|
+
paths["@lastbrain/ui/*"] = ["../../packages/ui/src/*"];
|
|
1599
|
+
paths["@lastbrain/core"] = ["../../packages/core/src/index.ts"];
|
|
1600
|
+
paths["@lastbrain/core/*"] = ["../../packages/core/src/*"];
|
|
1601
|
+
paths["@lastbrain/app"] = ["../../packages/app/src/index.ts"];
|
|
1602
|
+
paths["@lastbrain/app/*"] = ["../../packages/app/src/*"];
|
|
1603
|
+
paths["@lastbrain/module-auth"] = [
|
|
1604
|
+
"../../packages/module-auth/src/index.ts",
|
|
1605
|
+
];
|
|
1606
|
+
paths["@lastbrain/module-auth/*"] = ["../../packages/module-auth/src/*"];
|
|
1607
|
+
paths["@lastbrain/module-ai"] = ["../../packages/module-ai/src/index.ts"];
|
|
1608
|
+
paths["@lastbrain/module-ai/*"] = ["../../packages/module-ai/src/*"];
|
|
1609
|
+
paths["@lastbrain/module-legal"] = [
|
|
1610
|
+
"../../packages/module-legal/src/index.ts",
|
|
1611
|
+
];
|
|
1612
|
+
paths["@lastbrain/module-legal/*"] = [
|
|
1613
|
+
"../../packages/module-legal/src/*",
|
|
1614
|
+
];
|
|
1615
|
+
paths["@lastbrain/module-project-board"] = [
|
|
1616
|
+
"../../packages/module-project-board/src/index.ts",
|
|
1617
|
+
];
|
|
1618
|
+
paths["@lastbrain/module-project-board/*"] = [
|
|
1619
|
+
"../../packages/module-project-board/src/*",
|
|
1620
|
+
];
|
|
1621
|
+
paths["@lastbrain/module-tasks"] = [
|
|
1622
|
+
"../../packages/module-tasks/src/index.ts",
|
|
1623
|
+
];
|
|
1624
|
+
paths["@lastbrain/module-tasks/*"] = [
|
|
1625
|
+
"../../packages/module-tasks/src/*",
|
|
1626
|
+
];
|
|
1627
|
+
} else {
|
|
1628
|
+
// Hors monorepo (npm install), ne pas utiliser de paths aliases
|
|
1629
|
+
delete paths["@/*"];
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
const tsconfig: any = {
|
|
1282
1633
|
compilerOptions: {
|
|
1283
1634
|
target: "ES2020",
|
|
1284
1635
|
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
@@ -1295,14 +1646,18 @@ export default config;
|
|
|
1295
1646
|
incremental: true,
|
|
1296
1647
|
isolatedModules: true,
|
|
1297
1648
|
plugins: [{ name: "next" }],
|
|
1298
|
-
paths
|
|
1299
|
-
"@/*": ["./*"],
|
|
1300
|
-
},
|
|
1649
|
+
paths,
|
|
1301
1650
|
types: [],
|
|
1302
1651
|
},
|
|
1303
1652
|
include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
1304
1653
|
exclude: ["node_modules", "dist", ".next", "out"],
|
|
1305
1654
|
};
|
|
1655
|
+
|
|
1656
|
+
// Ajouter extends seulement en monorepo
|
|
1657
|
+
if (targetIsInMonorepo) {
|
|
1658
|
+
tsconfig.extends = "../../tsconfig.base.json";
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1306
1661
|
await fs.writeJson(tsconfigPath, tsconfig, { spaces: 2 });
|
|
1307
1662
|
console.log(chalk.green("✓ tsconfig.json créé"));
|
|
1308
1663
|
}
|
|
@@ -1333,6 +1688,69 @@ export const menuConfig: MenuConfig = {
|
|
|
1333
1688
|
console.log(chalk.green("✓ config/menu.ts créé"));
|
|
1334
1689
|
}
|
|
1335
1690
|
|
|
1691
|
+
// config/menu-ignored.ts - Optional file to hide menus and block routes
|
|
1692
|
+
const menuIgnoredPath = path.join(configDir, "menu-ignored.ts");
|
|
1693
|
+
if (!fs.existsSync(menuIgnoredPath) || force) {
|
|
1694
|
+
const menuIgnored = `import type { MenuIgnored } from "@lastbrain/app";
|
|
1695
|
+
|
|
1696
|
+
/**
|
|
1697
|
+
* Menu items to hide and routes to block
|
|
1698
|
+
* This file is optional - if it doesn't exist, all menus are shown
|
|
1699
|
+
*
|
|
1700
|
+
* Example:
|
|
1701
|
+
* export const menuIgnored: MenuIgnored = {
|
|
1702
|
+
* public: [
|
|
1703
|
+
* { title: "Documentation", path: "/docs" }
|
|
1704
|
+
* ],
|
|
1705
|
+
* auth: [
|
|
1706
|
+
* { title: "Profile", path: "/auth/profile" }
|
|
1707
|
+
* ]
|
|
1708
|
+
* };
|
|
1709
|
+
*/
|
|
1710
|
+
|
|
1711
|
+
export const menuIgnored: MenuIgnored = {
|
|
1712
|
+
public: [],
|
|
1713
|
+
auth: [],
|
|
1714
|
+
};
|
|
1715
|
+
`;
|
|
1716
|
+
await fs.writeFile(menuIgnoredPath, menuIgnored);
|
|
1717
|
+
console.log(chalk.green("✓ config/menu-ignored.ts créé"));
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
// config/menu-custom.ts - Optional file to add custom menus
|
|
1721
|
+
const menuCustomPath = path.join(configDir, "menu-custom.ts");
|
|
1722
|
+
if (!fs.existsSync(menuCustomPath) || force) {
|
|
1723
|
+
const menuCustom = `import type { MenuCustom } from "@lastbrain/app";
|
|
1724
|
+
|
|
1725
|
+
/**
|
|
1726
|
+
* Custom menu items to add without creating a module
|
|
1727
|
+
* This file is optional - if it doesn't exist, no custom menus are added
|
|
1728
|
+
*
|
|
1729
|
+
* Example:
|
|
1730
|
+
* export const menuCustom: MenuCustom = {
|
|
1731
|
+
* public: [
|
|
1732
|
+
* { label: "Blog", href: "/blog" },
|
|
1733
|
+
* { label: "Pricing", href: "/pricing" }
|
|
1734
|
+
* ],
|
|
1735
|
+
* auth: [
|
|
1736
|
+
* { label: "Invoices", href: "/auth/invoices" }
|
|
1737
|
+
* ],
|
|
1738
|
+
* admin: [
|
|
1739
|
+
* { label: "Reports", href: "/admin/reports" }
|
|
1740
|
+
* ]
|
|
1741
|
+
* };
|
|
1742
|
+
*/
|
|
1743
|
+
|
|
1744
|
+
export const menuCustom: MenuCustom = {
|
|
1745
|
+
public: [],
|
|
1746
|
+
auth: [],
|
|
1747
|
+
admin: [],
|
|
1748
|
+
};
|
|
1749
|
+
`;
|
|
1750
|
+
await fs.writeFile(menuCustomPath, menuCustom);
|
|
1751
|
+
console.log(chalk.green("✓ config/menu-custom.ts créé"));
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1336
1754
|
// config/footer.ts
|
|
1337
1755
|
const footerConfigPath = path.join(configDir, "footer.ts");
|
|
1338
1756
|
if (!fs.existsSync(footerConfigPath) || force) {
|
|
@@ -1353,6 +1771,29 @@ export const footerConfig: FooterConfig = {
|
|
|
1353
1771
|
console.log(chalk.green("✓ config/footer.ts créé"));
|
|
1354
1772
|
}
|
|
1355
1773
|
|
|
1774
|
+
// config/user-tabs.ts - User detail page tabs configuration
|
|
1775
|
+
const userTabsConfigPath = path.join(configDir, "user-tabs.ts");
|
|
1776
|
+
if (!fs.existsSync(userTabsConfigPath) || force) {
|
|
1777
|
+
const userTabsConfig = `// User tabs configuration
|
|
1778
|
+
// This file is generated and can be regenerated by running: pnpm build:modules
|
|
1779
|
+
"use client";
|
|
1780
|
+
|
|
1781
|
+
import type React from "react";
|
|
1782
|
+
|
|
1783
|
+
export interface ModuleUserTab {
|
|
1784
|
+
id: string;
|
|
1785
|
+
label: string;
|
|
1786
|
+
component: React.ComponentType<{ userId: string }>;
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
// Module user tabs - dynamically imported from active modules
|
|
1790
|
+
// To add tabs from modules, import them here and add to the array below
|
|
1791
|
+
export const moduleUserTabs: ModuleUserTab[] = [];
|
|
1792
|
+
`;
|
|
1793
|
+
await fs.writeFile(userTabsConfigPath, userTabsConfig);
|
|
1794
|
+
console.log(chalk.green("✓ config/user-tabs.ts créé"));
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1356
1797
|
// Créer les hooks
|
|
1357
1798
|
await createHooksDirectory(targetDir, force);
|
|
1358
1799
|
}
|
|
@@ -1521,16 +1962,7 @@ tmp/
|
|
|
1521
1962
|
coverage/
|
|
1522
1963
|
*.lcov
|
|
1523
1964
|
|
|
1524
|
-
# Generated by module-build
|
|
1525
|
-
app/navigation.generated.ts
|
|
1526
|
-
app/routes.generated.ts
|
|
1527
|
-
app/menu.generated.ts
|
|
1528
1965
|
|
|
1529
|
-
# Generated app-shell overrides
|
|
1530
|
-
app/(public)/
|
|
1531
|
-
app/(auth)/
|
|
1532
|
-
app/(admin)/
|
|
1533
|
-
app/layout.tsx
|
|
1534
1966
|
`;
|
|
1535
1967
|
await fs.writeFile(gitignorePath, gitignoreContent);
|
|
1536
1968
|
}
|
|
@@ -1604,6 +2036,30 @@ OPENAI_API_KEY=sk-fake-openai-key-for-development-replace-with-real-key
|
|
|
1604
2036
|
}
|
|
1605
2037
|
}
|
|
1606
2038
|
|
|
2039
|
+
async function createEnvProd(targetDir: string, force: boolean) {
|
|
2040
|
+
const envProdPath = path.join(targetDir, ".env.prod");
|
|
2041
|
+
|
|
2042
|
+
if (!fs.existsSync(envProdPath) || force) {
|
|
2043
|
+
console.log(chalk.yellow("\n🔐 Création de .env.prod..."));
|
|
2044
|
+
|
|
2045
|
+
const envContent = `# Production Environment Configuration
|
|
2046
|
+
# Copy your production values here
|
|
2047
|
+
|
|
2048
|
+
# Supabase Production
|
|
2049
|
+
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
|
|
2050
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-prod-anon-key
|
|
2051
|
+
SUPABASE_SERVICE_ROLE_KEY=your-prod-service-role-key
|
|
2052
|
+
|
|
2053
|
+
# OpenAI Production
|
|
2054
|
+
OPENAI_API_KEY=sk-proj-your-prod-api-key
|
|
2055
|
+
|
|
2056
|
+
# Note: Update these values with your actual production credentials
|
|
2057
|
+
`;
|
|
2058
|
+
await fs.writeFile(envProdPath, envContent);
|
|
2059
|
+
console.log(chalk.green("✓ .env.prod créé"));
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
|
|
1607
2063
|
async function createSupabaseStructure(targetDir: string, force: boolean) {
|
|
1608
2064
|
console.log(chalk.yellow("\n🗄️ Création de la structure Supabase..."));
|
|
1609
2065
|
|
|
@@ -1644,10 +2100,10 @@ async function createSupabaseStructure(targetDir: string, force: boolean) {
|
|
|
1644
2100
|
)
|
|
1645
2101
|
);
|
|
1646
2102
|
}
|
|
1647
|
-
} catch (
|
|
2103
|
+
} catch (_error) {
|
|
1648
2104
|
console.error(
|
|
1649
2105
|
chalk.red("✗ Erreur lors de la création de la migration:"),
|
|
1650
|
-
|
|
2106
|
+
_error
|
|
1651
2107
|
);
|
|
1652
2108
|
}
|
|
1653
2109
|
} else {
|
|
@@ -1672,24 +2128,22 @@ async function addScriptsToPackageJson(targetDir: string) {
|
|
|
1672
2128
|
) ||
|
|
1673
2129
|
fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
|
|
1674
2130
|
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
scriptsPrefix = "node node_modules/@lastbrain/app/dist/cli.js";
|
|
1680
|
-
}
|
|
2131
|
+
// Utiliser le CLI depuis le monorepo si présent, sinon depuis node_modules
|
|
2132
|
+
const scriptsPrefix = targetIsInMonorepo
|
|
2133
|
+
? "node ../../packages/app/dist/cli.js"
|
|
2134
|
+
: "node node_modules/@lastbrain/app/dist/cli.js";
|
|
1681
2135
|
|
|
1682
2136
|
const scripts = {
|
|
1683
2137
|
predev: targetIsInMonorepo
|
|
1684
|
-
? "pnpm --filter @lastbrain/core build && pnpm --filter @lastbrain/ui build && pnpm --filter @lastbrain/module-auth build && pnpm --filter @lastbrain/module-ai build"
|
|
1685
|
-
: "echo 'No prebuild needed
|
|
2138
|
+
? "pnpm --filter @lastbrain/core build && pnpm --filter @lastbrain/ui build && pnpm --filter @lastbrain/app build && pnpm --filter @lastbrain/module-auth build && pnpm --filter @lastbrain/module-ai build"
|
|
2139
|
+
: "echo 'No prebuild needed'",
|
|
1686
2140
|
dev: "next dev",
|
|
2141
|
+
"dev:local": "env-cmd -f .env.local next dev",
|
|
2142
|
+
"dev:prod": "env-cmd -f .env.prod next dev",
|
|
1687
2143
|
build: "next build",
|
|
1688
2144
|
start: "next start",
|
|
1689
2145
|
lint: "next lint",
|
|
1690
|
-
lastbrain:
|
|
1691
|
-
? "lastbrain"
|
|
1692
|
-
: "node node_modules/@lastbrain/app/dist/cli.js",
|
|
2146
|
+
lastbrain: scriptsPrefix,
|
|
1693
2147
|
"build:modules": `${scriptsPrefix} module:build`,
|
|
1694
2148
|
"db:migrations:sync": `${scriptsPrefix} db:migrations:sync`,
|
|
1695
2149
|
"db:init": `${scriptsPrefix} db:init`,
|