@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/dist/scripts/init-app.js
CHANGED
|
@@ -4,7 +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 { AVAILABLE_MODULES
|
|
7
|
+
import { AVAILABLE_MODULES } from "@lastbrain/core/config/modules";
|
|
8
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
9
|
const __dirname = path.dirname(__filename);
|
|
10
10
|
export async function initApp(options) {
|
|
@@ -86,6 +86,7 @@ export async function initApp(options) {
|
|
|
86
86
|
await createGitIgnore(targetDir, force);
|
|
87
87
|
await createEnvExample(targetDir, force);
|
|
88
88
|
await createEnvLocal(targetDir, force, isMonorepoProject);
|
|
89
|
+
await createEnvProd(targetDir, force);
|
|
89
90
|
// 7. Créer la structure Supabase avec migrations (seulement pour projets indépendants)
|
|
90
91
|
if (!isMonorepoProject) {
|
|
91
92
|
console.log(chalk.blue("🗄️ Création de la structure Supabase locale...\n"));
|
|
@@ -130,16 +131,22 @@ export async function initApp(options) {
|
|
|
130
131
|
});
|
|
131
132
|
console.log(chalk.green("\n✓ Migrations synchronisées\n"));
|
|
132
133
|
}
|
|
133
|
-
catch (
|
|
134
|
+
catch (_error) {
|
|
134
135
|
console.log(chalk.yellow("\n⚠️ Erreur de synchronisation des migrations\n"));
|
|
135
136
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
// Ne pas initialiser la BDD en mode monorepo
|
|
138
|
+
if (!isMonorepoProject) {
|
|
139
|
+
console.log(chalk.yellow("🗄️ Initialisation de la base de données...\n"));
|
|
140
|
+
try {
|
|
141
|
+
execSync("pnpm db:init", { cwd: targetDir, stdio: "inherit" });
|
|
142
|
+
console.log(chalk.green("\n✓ Base de données initialisée\n"));
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
console.log(chalk.yellow("\n⚠️ Erreur d'initialisation de la DB (normal si Supabase pas configuré)\n"));
|
|
146
|
+
}
|
|
140
147
|
}
|
|
141
|
-
|
|
142
|
-
console.log(chalk.
|
|
148
|
+
else {
|
|
149
|
+
console.log(chalk.cyan("⏭️ Mode monorepo détecté - BDD centralisée, pas d'initialisation locale requise\n"));
|
|
143
150
|
}
|
|
144
151
|
// Détecter le port (par défaut 3000 pour Next.js)
|
|
145
152
|
const port = 3000;
|
|
@@ -148,10 +155,15 @@ export async function initApp(options) {
|
|
|
148
155
|
console.log(chalk.cyan(`📱 Ouvrez votre navigateur sur : ${url}\n`));
|
|
149
156
|
console.log(chalk.blue("\n📋 Prochaines étapes après le démarrage :"));
|
|
150
157
|
console.log(chalk.white(" 1. Cliquez sur 'Get Started' sur la page d'accueil"));
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
158
|
+
if (isMonorepoProject) {
|
|
159
|
+
console.log(chalk.white(" 2. La BDD est centralisée dans le monorepo\n"));
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
console.log(chalk.white(" 2. Lancez Docker Desktop"));
|
|
163
|
+
console.log(chalk.white(" 3. Installez Supabase CLI si nécessaire : brew install supabase/tap/supabase"));
|
|
164
|
+
console.log(chalk.white(" 4. Exécutez : pnpm db:init"));
|
|
165
|
+
console.log(chalk.white(" 5. Rechargez la page\n"));
|
|
166
|
+
}
|
|
155
167
|
// Ouvrir le navigateur
|
|
156
168
|
const openCommand = process.platform === "darwin"
|
|
157
169
|
? "open"
|
|
@@ -167,7 +179,7 @@ export async function initApp(options) {
|
|
|
167
179
|
}
|
|
168
180
|
}, 2000);
|
|
169
181
|
// Lancer pnpm dev
|
|
170
|
-
execSync("pnpm dev", { cwd: targetDir, stdio: "inherit" });
|
|
182
|
+
execSync("pnpm dev:local", { cwd: targetDir, stdio: "inherit" });
|
|
171
183
|
}
|
|
172
184
|
catch {
|
|
173
185
|
console.error(chalk.red("\n❌ Erreur lors du lancement\n"));
|
|
@@ -176,8 +188,10 @@ export async function initApp(options) {
|
|
|
176
188
|
console.log(chalk.white(" pnpm install"));
|
|
177
189
|
console.log(chalk.white(" pnpm build:modules"));
|
|
178
190
|
console.log(chalk.white(" pnpm db:migrations:sync"));
|
|
179
|
-
|
|
180
|
-
|
|
191
|
+
if (!isMonorepoProject) {
|
|
192
|
+
console.log(chalk.white(" pnpm db:init"));
|
|
193
|
+
}
|
|
194
|
+
console.log(chalk.white(" pnpm dev:local (ou pnpm dev:prod)\n"));
|
|
181
195
|
}
|
|
182
196
|
}
|
|
183
197
|
else {
|
|
@@ -187,7 +201,11 @@ export async function initApp(options) {
|
|
|
187
201
|
console.log(chalk.white(" 3. pnpm build:modules (générer les routes des modules)"));
|
|
188
202
|
console.log(chalk.white(" 4. pnpm db:migrations:sync (synchroniser les migrations)"));
|
|
189
203
|
console.log(chalk.white(" 5. pnpm db:init (initialiser la base de données)"));
|
|
190
|
-
console.log(chalk.white(" 6. pnpm dev (
|
|
204
|
+
console.log(chalk.white(" 6. pnpm dev:local (ou pnpm dev:prod)\n"));
|
|
205
|
+
console.log(chalk.cyan("\n💡 Scripts disponibles:"));
|
|
206
|
+
console.log(chalk.white(" • pnpm dev:local - Lance avec .env.local"));
|
|
207
|
+
console.log(chalk.white(" • pnpm dev:prod - Lance avec .env.prod"));
|
|
208
|
+
console.log(chalk.white(" • pnpm dev - Lance avec .env actuel\n"));
|
|
191
209
|
console.log(chalk.gray("Prérequis pour Supabase :"));
|
|
192
210
|
console.log(chalk.white(" - Docker Desktop installé et lancé"));
|
|
193
211
|
console.log(chalk.white(" - Supabase CLI : brew install supabase/tap/supabase\n"));
|
|
@@ -283,8 +301,8 @@ function getLastBrainVersions(targetDir) {
|
|
|
283
301
|
};
|
|
284
302
|
}
|
|
285
303
|
}
|
|
286
|
-
catch (
|
|
287
|
-
console.warn(chalk.yellow(`⚠️ Impossible de lire les versions locales (${
|
|
304
|
+
catch (_error) {
|
|
305
|
+
console.warn(chalk.yellow(`⚠️ Impossible de lire les versions locales (${_error}), utilisation de 'latest'`));
|
|
288
306
|
}
|
|
289
307
|
// Fallback: utiliser "latest"
|
|
290
308
|
return {
|
|
@@ -375,6 +393,7 @@ async function addDependencies(targetDir, useHeroUI, withAuth, selectedModules =
|
|
|
375
393
|
requiredDeps["lucide-react"] = "^0.554.0";
|
|
376
394
|
requiredDeps["framer-motion"] = "^11.18.2";
|
|
377
395
|
requiredDeps["clsx"] = "^2.1.1";
|
|
396
|
+
requiredDeps["env-cmd"] = "^11.0.0";
|
|
378
397
|
}
|
|
379
398
|
// DevDependencies
|
|
380
399
|
const requiredDevDeps = {
|
|
@@ -716,17 +735,56 @@ async function createAppHeader(targetDir, force) {
|
|
|
716
735
|
if (!fs.existsSync(headerPath) || force) {
|
|
717
736
|
const headerContent = `"use client";
|
|
718
737
|
|
|
719
|
-
import { Header } from "@lastbrain/ui";
|
|
738
|
+
import { Header, type MenuItem } from "@lastbrain/ui";
|
|
720
739
|
import { menuConfig } from "../config/menu";
|
|
721
740
|
import { supabaseBrowserClient } from "@lastbrain/core";
|
|
722
741
|
import { useRouter } from "next/navigation";
|
|
723
742
|
import { useAuthSession, useNotificationsContext } from "@lastbrain/app";
|
|
743
|
+
import { useState, useEffect } from "react";
|
|
744
|
+
|
|
745
|
+
interface MenuIgnored {
|
|
746
|
+
public: { title: string; path: string }[];
|
|
747
|
+
auth: { title: string; path: string }[];
|
|
748
|
+
}
|
|
724
749
|
|
|
725
750
|
export function AppHeader() {
|
|
726
751
|
const router = useRouter();
|
|
727
752
|
const { user, isSuperAdmin } = useAuthSession();
|
|
728
753
|
const { data, loading, markAsRead, markAllAsRead, deleteNotification } =
|
|
729
754
|
useNotificationsContext();
|
|
755
|
+
const [menuIgnored, setMenuIgnored] = useState<MenuIgnored | undefined>();
|
|
756
|
+
const [menuCustom, setMenuCustom] = useState<MenuItem[] | undefined>();
|
|
757
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
758
|
+
|
|
759
|
+
// Charger menuIgnored et menuCustom s'ils existent
|
|
760
|
+
useEffect(() => {
|
|
761
|
+
let loadedIgnored = false;
|
|
762
|
+
let loadedCustom = false;
|
|
763
|
+
|
|
764
|
+
// Charger menu-ignored
|
|
765
|
+
import("../config/menu-ignored")
|
|
766
|
+
.then((mod) => setMenuIgnored(mod.menuIgnored))
|
|
767
|
+
.catch(() => setMenuIgnored(undefined))
|
|
768
|
+
.finally(() => {
|
|
769
|
+
loadedIgnored = true;
|
|
770
|
+
if (loadedIgnored && loadedCustom) setIsLoading(false);
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
// Charger menu-custom
|
|
774
|
+
import("../config/menu-custom")
|
|
775
|
+
.then((mod) => {
|
|
776
|
+
// Combiner les menus custom publics et auth
|
|
777
|
+
const customMenus: MenuItem[] = [];
|
|
778
|
+
if (mod.menuCustom?.public) customMenus.push(...mod.menuCustom.public);
|
|
779
|
+
if (mod.menuCustom?.auth) customMenus.push(...mod.menuCustom.auth);
|
|
780
|
+
setMenuCustom(customMenus.length > 0 ? customMenus : undefined);
|
|
781
|
+
})
|
|
782
|
+
.catch(() => setMenuCustom(undefined))
|
|
783
|
+
.finally(() => {
|
|
784
|
+
loadedCustom = true;
|
|
785
|
+
if (loadedIgnored && loadedCustom) setIsLoading(false);
|
|
786
|
+
});
|
|
787
|
+
}, []);
|
|
730
788
|
|
|
731
789
|
const handleLogout = async () => {
|
|
732
790
|
await supabaseBrowserClient.auth.signOut();
|
|
@@ -749,6 +807,9 @@ export function AppHeader() {
|
|
|
749
807
|
onMarkAsRead={markAsRead}
|
|
750
808
|
onMarkAllAsRead={markAllAsRead}
|
|
751
809
|
onDeleteNotification={deleteNotification}
|
|
810
|
+
{...(menuIgnored ? { menuIgnored } : {})}
|
|
811
|
+
{...(menuCustom ? { menuCustom } : {})}
|
|
812
|
+
{...{ isLoadingMenus: isLoading }}
|
|
752
813
|
/>
|
|
753
814
|
);
|
|
754
815
|
}
|
|
@@ -826,7 +887,58 @@ async function createConfigFiles(targetDir, force, useHeroUI, projectName) {
|
|
|
826
887
|
const middlewarePath = path.join(targetDir, "middleware.ts");
|
|
827
888
|
if (!fs.existsSync(middlewarePath) || force) {
|
|
828
889
|
const middleware = `import { type NextRequest, NextResponse } from "next/server";
|
|
829
|
-
import {
|
|
890
|
+
import { createServerClient, type CookieOptions } from "@supabase/ssr";
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* Crée un client Supabase pour le middleware
|
|
894
|
+
*/
|
|
895
|
+
function createMiddlewareClient(request: NextRequest) {
|
|
896
|
+
let response = NextResponse.next({
|
|
897
|
+
request: {
|
|
898
|
+
headers: request.headers,
|
|
899
|
+
},
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
const supabase = createServerClient(
|
|
903
|
+
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
|
904
|
+
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
|
905
|
+
{
|
|
906
|
+
cookies: {
|
|
907
|
+
get(name: string) {
|
|
908
|
+
return request.cookies.get(name)?.value;
|
|
909
|
+
},
|
|
910
|
+
set(name: string, value: string, options: CookieOptions) {
|
|
911
|
+
request.cookies.set({
|
|
912
|
+
name,
|
|
913
|
+
value,
|
|
914
|
+
...options,
|
|
915
|
+
});
|
|
916
|
+
response = NextResponse.next({
|
|
917
|
+
request: {
|
|
918
|
+
headers: request.headers,
|
|
919
|
+
},
|
|
920
|
+
});
|
|
921
|
+
response.cookies.set({
|
|
922
|
+
name,
|
|
923
|
+
value,
|
|
924
|
+
...options,
|
|
925
|
+
});
|
|
926
|
+
},
|
|
927
|
+
remove(name: string, options: CookieOptions) {
|
|
928
|
+
request.cookies.delete(name);
|
|
929
|
+
response = NextResponse.next({
|
|
930
|
+
request: {
|
|
931
|
+
headers: request.headers,
|
|
932
|
+
},
|
|
933
|
+
});
|
|
934
|
+
response.cookies.delete(name);
|
|
935
|
+
},
|
|
936
|
+
},
|
|
937
|
+
}
|
|
938
|
+
);
|
|
939
|
+
|
|
940
|
+
return { supabase, response };
|
|
941
|
+
}
|
|
830
942
|
|
|
831
943
|
export async function middleware(request: NextRequest) {
|
|
832
944
|
const { pathname } = request.nextUrl;
|
|
@@ -969,9 +1081,9 @@ export const config = {
|
|
|
969
1081
|
const nextConfig = `/** @type {import('next').NextConfig} */
|
|
970
1082
|
const nextConfig = {
|
|
971
1083
|
reactStrictMode: true,
|
|
972
|
-
|
|
1084
|
+
devIndicators: {
|
|
973
1085
|
position: 'bottom-right',
|
|
974
|
-
}
|
|
1086
|
+
}
|
|
975
1087
|
};
|
|
976
1088
|
|
|
977
1089
|
export default nextConfig;
|
|
@@ -984,7 +1096,7 @@ export default nextConfig;
|
|
|
984
1096
|
if (!fs.existsSync(tailwindConfigPath) || force) {
|
|
985
1097
|
let tailwindConfig = "";
|
|
986
1098
|
if (useHeroUI) {
|
|
987
|
-
// Configuration avec HeroUI
|
|
1099
|
+
// Configuration avec HeroUI - complète avec thèmes
|
|
988
1100
|
tailwindConfig = `import { heroui } from "@heroui/theme";
|
|
989
1101
|
|
|
990
1102
|
/** @type {import('tailwindcss').Config} */
|
|
@@ -996,8 +1108,195 @@ const config = {
|
|
|
996
1108
|
"./node_modules/@heroui/theme/dist/**/*.{js,mjs}",
|
|
997
1109
|
],
|
|
998
1110
|
darkMode: "class",
|
|
999
|
-
plugins: [
|
|
1000
|
-
|
|
1111
|
+
plugins: [
|
|
1112
|
+
heroui({
|
|
1113
|
+
themes: {
|
|
1114
|
+
light: {
|
|
1115
|
+
colors: {
|
|
1116
|
+
default: {
|
|
1117
|
+
950: "#0d0d0e",
|
|
1118
|
+
900: "#19191c",
|
|
1119
|
+
800: "#26262a",
|
|
1120
|
+
700: "#323238",
|
|
1121
|
+
600: "#3f3f46",
|
|
1122
|
+
500: "#65656b",
|
|
1123
|
+
400: "#8c8c90",
|
|
1124
|
+
300: "#b2b2b5",
|
|
1125
|
+
200: "#d9d9da",
|
|
1126
|
+
100: "#ffffff",
|
|
1127
|
+
foreground: "#000000",
|
|
1128
|
+
DEFAULT: "#d4d4d8",
|
|
1129
|
+
},
|
|
1130
|
+
primary: {
|
|
1131
|
+
50: "#eef2ff",
|
|
1132
|
+
100: "#e0e7ff",
|
|
1133
|
+
200: "#c7d2fe",
|
|
1134
|
+
300: "#a5b4fc",
|
|
1135
|
+
400: "#818cf8",
|
|
1136
|
+
500: "#6366f1",
|
|
1137
|
+
600: "#4f46e5",
|
|
1138
|
+
700: "#4338ca",
|
|
1139
|
+
800: "#3730a3",
|
|
1140
|
+
900: "#312e81",
|
|
1141
|
+
foreground: "#ffffff",
|
|
1142
|
+
DEFAULT: "#6366f1",
|
|
1143
|
+
},
|
|
1144
|
+
secondary: {
|
|
1145
|
+
50: "#f5e8ff",
|
|
1146
|
+
100: "#e8ccff",
|
|
1147
|
+
200: "#d7a6ff",
|
|
1148
|
+
300: "#c57fff",
|
|
1149
|
+
400: "#b359ff",
|
|
1150
|
+
500: "#9b37ff",
|
|
1151
|
+
600: "#7d1fcc",
|
|
1152
|
+
700: "#5f1799",
|
|
1153
|
+
800: "#410f66",
|
|
1154
|
+
900: "#240833",
|
|
1155
|
+
foreground: "#ffffff",
|
|
1156
|
+
DEFAULT: "#9b37ff",
|
|
1157
|
+
},
|
|
1158
|
+
success: {
|
|
1159
|
+
50: "#e7fff7",
|
|
1160
|
+
100: "#c3ffec",
|
|
1161
|
+
200: "#9affdf",
|
|
1162
|
+
300: "#70ffd2",
|
|
1163
|
+
400: "#4bffca",
|
|
1164
|
+
500: "#22e6b0",
|
|
1165
|
+
600: "#18b38a",
|
|
1166
|
+
700: "#108066",
|
|
1167
|
+
800: "#074d40",
|
|
1168
|
+
900: "#012b22",
|
|
1169
|
+
foreground: "#000",
|
|
1170
|
+
DEFAULT: "#22e6b0",
|
|
1171
|
+
},
|
|
1172
|
+
warning: {
|
|
1173
|
+
50: "#fff8e1",
|
|
1174
|
+
100: "#ffecb3",
|
|
1175
|
+
200: "#ffe082",
|
|
1176
|
+
300: "#ffd54f",
|
|
1177
|
+
400: "#ffca28",
|
|
1178
|
+
500: "#ffc107",
|
|
1179
|
+
600: "#ffb300",
|
|
1180
|
+
700: "#ffa000",
|
|
1181
|
+
800: "#ff8f00",
|
|
1182
|
+
900: "#ff6f00",
|
|
1183
|
+
foreground: "#000",
|
|
1184
|
+
DEFAULT: "#ffca28",
|
|
1185
|
+
},
|
|
1186
|
+
danger: {
|
|
1187
|
+
50: "#ffe6e9",
|
|
1188
|
+
100: "#ffbac1",
|
|
1189
|
+
200: "#ff8f99",
|
|
1190
|
+
300: "#ff6471",
|
|
1191
|
+
400: "#ff3949",
|
|
1192
|
+
500: "#ff112a",
|
|
1193
|
+
600: "#d80c22",
|
|
1194
|
+
700: "#b1081b",
|
|
1195
|
+
800: "#890514",
|
|
1196
|
+
900: "#62020d",
|
|
1197
|
+
foreground: "#fff",
|
|
1198
|
+
DEFAULT: "#ff112a",
|
|
1199
|
+
},
|
|
1200
|
+
background: "#f7f8fc",
|
|
1201
|
+
foreground: "#0e0e10",
|
|
1202
|
+
content1: "#ffffff",
|
|
1203
|
+
},
|
|
1204
|
+
},
|
|
1205
|
+
dark: {
|
|
1206
|
+
colors: {
|
|
1207
|
+
default: {
|
|
1208
|
+
50: "#1a1c1f",
|
|
1209
|
+
100: "#232529",
|
|
1210
|
+
200: "#2c2f34",
|
|
1211
|
+
300: "#363940",
|
|
1212
|
+
400: "#40444d",
|
|
1213
|
+
500: "#4b4f59",
|
|
1214
|
+
600: "#6c707b",
|
|
1215
|
+
700: "#8d919b",
|
|
1216
|
+
800: "#afb2bb",
|
|
1217
|
+
900: "#d1d3d9",
|
|
1218
|
+
foreground: "#ffffff",
|
|
1219
|
+
DEFAULT: "#363940",
|
|
1220
|
+
},
|
|
1221
|
+
primary: {
|
|
1222
|
+
50: "#312e81",
|
|
1223
|
+
100: "#3730a3",
|
|
1224
|
+
200: "#4338ca",
|
|
1225
|
+
300: "#4f46e5",
|
|
1226
|
+
400: "#6366f1",
|
|
1227
|
+
500: "#818cf8",
|
|
1228
|
+
600: "#a5b4fc",
|
|
1229
|
+
700: "#c7d2fe",
|
|
1230
|
+
800: "#e0e7ff",
|
|
1231
|
+
900: "#eef2ff",
|
|
1232
|
+
foreground: "#ffffff",
|
|
1233
|
+
DEFAULT: "#6366f1",
|
|
1234
|
+
},
|
|
1235
|
+
secondary: {
|
|
1236
|
+
50: "#240833",
|
|
1237
|
+
100: "#410f66",
|
|
1238
|
+
200: "#5f1799",
|
|
1239
|
+
300: "#7d1fcc",
|
|
1240
|
+
400: "#9b37ff",
|
|
1241
|
+
500: "#b359ff",
|
|
1242
|
+
600: "#c57fff",
|
|
1243
|
+
700: "#d7a6ff",
|
|
1244
|
+
800: "#e8ccff",
|
|
1245
|
+
900: "#f5e8ff",
|
|
1246
|
+
foreground: "#ffffff",
|
|
1247
|
+
DEFAULT: "#9b37ff",
|
|
1248
|
+
},
|
|
1249
|
+
success: {
|
|
1250
|
+
50: "#012b22",
|
|
1251
|
+
100: "#074d40",
|
|
1252
|
+
200: "#108066",
|
|
1253
|
+
300: "#18b38a",
|
|
1254
|
+
400: "#22e6b0",
|
|
1255
|
+
500: "#4bffca",
|
|
1256
|
+
600: "#70ffd2",
|
|
1257
|
+
700: "#9affdf",
|
|
1258
|
+
800: "#c3ffec",
|
|
1259
|
+
900: "#e7fff7",
|
|
1260
|
+
foreground: "#0e0e0e",
|
|
1261
|
+
DEFAULT: "#22e6b0",
|
|
1262
|
+
},
|
|
1263
|
+
warning: {
|
|
1264
|
+
50: "#3a2c00",
|
|
1265
|
+
100: "#5e4700",
|
|
1266
|
+
200: "#836300",
|
|
1267
|
+
300: "#a77e00",
|
|
1268
|
+
400: "#cc9900",
|
|
1269
|
+
500: "#ffc107",
|
|
1270
|
+
600: "#ffd54f",
|
|
1271
|
+
700: "#ffe082",
|
|
1272
|
+
800: "#ffecb3",
|
|
1273
|
+
900: "#fff8e1",
|
|
1274
|
+
foreground: "#000",
|
|
1275
|
+
DEFAULT: "#ffc107",
|
|
1276
|
+
},
|
|
1277
|
+
danger: {
|
|
1278
|
+
50: "#4a000a",
|
|
1279
|
+
100: "#6e000f",
|
|
1280
|
+
200: "#920014",
|
|
1281
|
+
300: "#b60019",
|
|
1282
|
+
400: "#da001f",
|
|
1283
|
+
500: "#ff112a",
|
|
1284
|
+
600: "#ff3949",
|
|
1285
|
+
700: "#ff6471",
|
|
1286
|
+
800: "#ff8f99",
|
|
1287
|
+
900: "#ffbac1",
|
|
1288
|
+
foreground: "#ffffff",
|
|
1289
|
+
DEFAULT: "#ff112a",
|
|
1290
|
+
},
|
|
1291
|
+
background: "#0f1114",
|
|
1292
|
+
foreground: "#f8f8f8",
|
|
1293
|
+
content1: "#15181d",
|
|
1294
|
+
},
|
|
1295
|
+
},
|
|
1296
|
+
},
|
|
1297
|
+
}),
|
|
1298
|
+
],
|
|
1299
|
+
};
|
|
1001
1300
|
|
|
1002
1301
|
export default config;
|
|
1003
1302
|
`;
|
|
@@ -1054,8 +1353,51 @@ export default config;
|
|
|
1054
1353
|
// tsconfig.json
|
|
1055
1354
|
const tsconfigPath = path.join(targetDir, "tsconfig.json");
|
|
1056
1355
|
if (!fs.existsSync(tsconfigPath) || force) {
|
|
1356
|
+
// Détecter si le projet cible est dans un monorepo
|
|
1357
|
+
const targetIsInMonorepo = fs.existsSync(path.join(targetDir, "../../../packages/core/package.json")) ||
|
|
1358
|
+
fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
|
|
1359
|
+
// Générer les chemins en fonction du contexte
|
|
1360
|
+
const paths = {
|
|
1361
|
+
"@/*": ["./*"],
|
|
1362
|
+
};
|
|
1363
|
+
if (targetIsInMonorepo) {
|
|
1364
|
+
// En monorepo, pointer sur les sources locales
|
|
1365
|
+
paths["@lastbrain/ui"] = ["../../packages/ui/src/index.ts"];
|
|
1366
|
+
paths["@lastbrain/ui/*"] = ["../../packages/ui/src/*"];
|
|
1367
|
+
paths["@lastbrain/core"] = ["../../packages/core/src/index.ts"];
|
|
1368
|
+
paths["@lastbrain/core/*"] = ["../../packages/core/src/*"];
|
|
1369
|
+
paths["@lastbrain/app"] = ["../../packages/app/src/index.ts"];
|
|
1370
|
+
paths["@lastbrain/app/*"] = ["../../packages/app/src/*"];
|
|
1371
|
+
paths["@lastbrain/module-auth"] = [
|
|
1372
|
+
"../../packages/module-auth/src/index.ts",
|
|
1373
|
+
];
|
|
1374
|
+
paths["@lastbrain/module-auth/*"] = ["../../packages/module-auth/src/*"];
|
|
1375
|
+
paths["@lastbrain/module-ai"] = ["../../packages/module-ai/src/index.ts"];
|
|
1376
|
+
paths["@lastbrain/module-ai/*"] = ["../../packages/module-ai/src/*"];
|
|
1377
|
+
paths["@lastbrain/module-legal"] = [
|
|
1378
|
+
"../../packages/module-legal/src/index.ts",
|
|
1379
|
+
];
|
|
1380
|
+
paths["@lastbrain/module-legal/*"] = [
|
|
1381
|
+
"../../packages/module-legal/src/*",
|
|
1382
|
+
];
|
|
1383
|
+
paths["@lastbrain/module-project-board"] = [
|
|
1384
|
+
"../../packages/module-project-board/src/index.ts",
|
|
1385
|
+
];
|
|
1386
|
+
paths["@lastbrain/module-project-board/*"] = [
|
|
1387
|
+
"../../packages/module-project-board/src/*",
|
|
1388
|
+
];
|
|
1389
|
+
paths["@lastbrain/module-tasks"] = [
|
|
1390
|
+
"../../packages/module-tasks/src/index.ts",
|
|
1391
|
+
];
|
|
1392
|
+
paths["@lastbrain/module-tasks/*"] = [
|
|
1393
|
+
"../../packages/module-tasks/src/*",
|
|
1394
|
+
];
|
|
1395
|
+
}
|
|
1396
|
+
else {
|
|
1397
|
+
// Hors monorepo (npm install), ne pas utiliser de paths aliases
|
|
1398
|
+
delete paths["@/*"];
|
|
1399
|
+
}
|
|
1057
1400
|
const tsconfig = {
|
|
1058
|
-
extends: "../../tsconfig.base.json",
|
|
1059
1401
|
compilerOptions: {
|
|
1060
1402
|
target: "ES2020",
|
|
1061
1403
|
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
@@ -1072,14 +1414,16 @@ export default config;
|
|
|
1072
1414
|
incremental: true,
|
|
1073
1415
|
isolatedModules: true,
|
|
1074
1416
|
plugins: [{ name: "next" }],
|
|
1075
|
-
paths
|
|
1076
|
-
"@/*": ["./*"],
|
|
1077
|
-
},
|
|
1417
|
+
paths,
|
|
1078
1418
|
types: [],
|
|
1079
1419
|
},
|
|
1080
1420
|
include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
1081
1421
|
exclude: ["node_modules", "dist", ".next", "out"],
|
|
1082
1422
|
};
|
|
1423
|
+
// Ajouter extends seulement en monorepo
|
|
1424
|
+
if (targetIsInMonorepo) {
|
|
1425
|
+
tsconfig.extends = "../../tsconfig.base.json";
|
|
1426
|
+
}
|
|
1083
1427
|
await fs.writeJson(tsconfigPath, tsconfig, { spaces: 2 });
|
|
1084
1428
|
console.log(chalk.green("✓ tsconfig.json créé"));
|
|
1085
1429
|
}
|
|
@@ -1108,6 +1452,67 @@ export const menuConfig: MenuConfig = {
|
|
|
1108
1452
|
await fs.writeFile(menuConfigPath, menuConfig);
|
|
1109
1453
|
console.log(chalk.green("✓ config/menu.ts créé"));
|
|
1110
1454
|
}
|
|
1455
|
+
// config/menu-ignored.ts - Optional file to hide menus and block routes
|
|
1456
|
+
const menuIgnoredPath = path.join(configDir, "menu-ignored.ts");
|
|
1457
|
+
if (!fs.existsSync(menuIgnoredPath) || force) {
|
|
1458
|
+
const menuIgnored = `import type { MenuIgnored } from "@lastbrain/app";
|
|
1459
|
+
|
|
1460
|
+
/**
|
|
1461
|
+
* Menu items to hide and routes to block
|
|
1462
|
+
* This file is optional - if it doesn't exist, all menus are shown
|
|
1463
|
+
*
|
|
1464
|
+
* Example:
|
|
1465
|
+
* export const menuIgnored: MenuIgnored = {
|
|
1466
|
+
* public: [
|
|
1467
|
+
* { title: "Documentation", path: "/docs" }
|
|
1468
|
+
* ],
|
|
1469
|
+
* auth: [
|
|
1470
|
+
* { title: "Profile", path: "/auth/profile" }
|
|
1471
|
+
* ]
|
|
1472
|
+
* };
|
|
1473
|
+
*/
|
|
1474
|
+
|
|
1475
|
+
export const menuIgnored: MenuIgnored = {
|
|
1476
|
+
public: [],
|
|
1477
|
+
auth: [],
|
|
1478
|
+
};
|
|
1479
|
+
`;
|
|
1480
|
+
await fs.writeFile(menuIgnoredPath, menuIgnored);
|
|
1481
|
+
console.log(chalk.green("✓ config/menu-ignored.ts créé"));
|
|
1482
|
+
}
|
|
1483
|
+
// config/menu-custom.ts - Optional file to add custom menus
|
|
1484
|
+
const menuCustomPath = path.join(configDir, "menu-custom.ts");
|
|
1485
|
+
if (!fs.existsSync(menuCustomPath) || force) {
|
|
1486
|
+
const menuCustom = `import type { MenuCustom } from "@lastbrain/app";
|
|
1487
|
+
|
|
1488
|
+
/**
|
|
1489
|
+
* Custom menu items to add without creating a module
|
|
1490
|
+
* This file is optional - if it doesn't exist, no custom menus are added
|
|
1491
|
+
*
|
|
1492
|
+
* Example:
|
|
1493
|
+
* export const menuCustom: MenuCustom = {
|
|
1494
|
+
* public: [
|
|
1495
|
+
* { label: "Blog", href: "/blog" },
|
|
1496
|
+
* { label: "Pricing", href: "/pricing" }
|
|
1497
|
+
* ],
|
|
1498
|
+
* auth: [
|
|
1499
|
+
* { label: "Invoices", href: "/auth/invoices" }
|
|
1500
|
+
* ],
|
|
1501
|
+
* admin: [
|
|
1502
|
+
* { label: "Reports", href: "/admin/reports" }
|
|
1503
|
+
* ]
|
|
1504
|
+
* };
|
|
1505
|
+
*/
|
|
1506
|
+
|
|
1507
|
+
export const menuCustom: MenuCustom = {
|
|
1508
|
+
public: [],
|
|
1509
|
+
auth: [],
|
|
1510
|
+
admin: [],
|
|
1511
|
+
};
|
|
1512
|
+
`;
|
|
1513
|
+
await fs.writeFile(menuCustomPath, menuCustom);
|
|
1514
|
+
console.log(chalk.green("✓ config/menu-custom.ts créé"));
|
|
1515
|
+
}
|
|
1111
1516
|
// config/footer.ts
|
|
1112
1517
|
const footerConfigPath = path.join(configDir, "footer.ts");
|
|
1113
1518
|
if (!fs.existsSync(footerConfigPath) || force) {
|
|
@@ -1127,6 +1532,28 @@ export const footerConfig: FooterConfig = {
|
|
|
1127
1532
|
await fs.writeFile(footerConfigPath, footerConfig);
|
|
1128
1533
|
console.log(chalk.green("✓ config/footer.ts créé"));
|
|
1129
1534
|
}
|
|
1535
|
+
// config/user-tabs.ts - User detail page tabs configuration
|
|
1536
|
+
const userTabsConfigPath = path.join(configDir, "user-tabs.ts");
|
|
1537
|
+
if (!fs.existsSync(userTabsConfigPath) || force) {
|
|
1538
|
+
const userTabsConfig = `// User tabs configuration
|
|
1539
|
+
// This file is generated and can be regenerated by running: pnpm build:modules
|
|
1540
|
+
"use client";
|
|
1541
|
+
|
|
1542
|
+
import type React from "react";
|
|
1543
|
+
|
|
1544
|
+
export interface ModuleUserTab {
|
|
1545
|
+
id: string;
|
|
1546
|
+
label: string;
|
|
1547
|
+
component: React.ComponentType<{ userId: string }>;
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
// Module user tabs - dynamically imported from active modules
|
|
1551
|
+
// To add tabs from modules, import them here and add to the array below
|
|
1552
|
+
export const moduleUserTabs: ModuleUserTab[] = [];
|
|
1553
|
+
`;
|
|
1554
|
+
await fs.writeFile(userTabsConfigPath, userTabsConfig);
|
|
1555
|
+
console.log(chalk.green("✓ config/user-tabs.ts créé"));
|
|
1556
|
+
}
|
|
1130
1557
|
// Créer les hooks
|
|
1131
1558
|
await createHooksDirectory(targetDir, force);
|
|
1132
1559
|
}
|
|
@@ -1286,16 +1713,7 @@ tmp/
|
|
|
1286
1713
|
coverage/
|
|
1287
1714
|
*.lcov
|
|
1288
1715
|
|
|
1289
|
-
# Generated by module-build
|
|
1290
|
-
app/navigation.generated.ts
|
|
1291
|
-
app/routes.generated.ts
|
|
1292
|
-
app/menu.generated.ts
|
|
1293
1716
|
|
|
1294
|
-
# Generated app-shell overrides
|
|
1295
|
-
app/(public)/
|
|
1296
|
-
app/(auth)/
|
|
1297
|
-
app/(admin)/
|
|
1298
|
-
app/layout.tsx
|
|
1299
1717
|
`;
|
|
1300
1718
|
await fs.writeFile(gitignorePath, gitignoreContent);
|
|
1301
1719
|
}
|
|
@@ -1357,6 +1775,27 @@ OPENAI_API_KEY=sk-fake-openai-key-for-development-replace-with-real-key
|
|
|
1357
1775
|
console.log(chalk.green("✓ .env.local créé"));
|
|
1358
1776
|
}
|
|
1359
1777
|
}
|
|
1778
|
+
async function createEnvProd(targetDir, force) {
|
|
1779
|
+
const envProdPath = path.join(targetDir, ".env.prod");
|
|
1780
|
+
if (!fs.existsSync(envProdPath) || force) {
|
|
1781
|
+
console.log(chalk.yellow("\n🔐 Création de .env.prod..."));
|
|
1782
|
+
const envContent = `# Production Environment Configuration
|
|
1783
|
+
# Copy your production values here
|
|
1784
|
+
|
|
1785
|
+
# Supabase Production
|
|
1786
|
+
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
|
|
1787
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-prod-anon-key
|
|
1788
|
+
SUPABASE_SERVICE_ROLE_KEY=your-prod-service-role-key
|
|
1789
|
+
|
|
1790
|
+
# OpenAI Production
|
|
1791
|
+
OPENAI_API_KEY=sk-proj-your-prod-api-key
|
|
1792
|
+
|
|
1793
|
+
# Note: Update these values with your actual production credentials
|
|
1794
|
+
`;
|
|
1795
|
+
await fs.writeFile(envProdPath, envContent);
|
|
1796
|
+
console.log(chalk.green("✓ .env.prod créé"));
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1360
1799
|
async function createSupabaseStructure(targetDir, force) {
|
|
1361
1800
|
console.log(chalk.yellow("\n🗄️ Création de la structure Supabase..."));
|
|
1362
1801
|
const supabaseDir = path.join(targetDir, "supabase");
|
|
@@ -1377,8 +1816,8 @@ async function createSupabaseStructure(targetDir, force) {
|
|
|
1377
1816
|
console.log(chalk.green("✓ supabase/migrations/20201010100000_app_base.sql créé (vide)"));
|
|
1378
1817
|
}
|
|
1379
1818
|
}
|
|
1380
|
-
catch (
|
|
1381
|
-
console.error(chalk.red("✗ Erreur lors de la création de la migration:"),
|
|
1819
|
+
catch (_error) {
|
|
1820
|
+
console.error(chalk.red("✗ Erreur lors de la création de la migration:"), _error);
|
|
1382
1821
|
}
|
|
1383
1822
|
}
|
|
1384
1823
|
else {
|
|
@@ -1392,22 +1831,21 @@ async function addScriptsToPackageJson(targetDir) {
|
|
|
1392
1831
|
// Détecter si le projet cible est dans un workspace
|
|
1393
1832
|
const targetIsInMonorepo = fs.existsSync(path.join(targetDir, "../../../packages/core/package.json")) ||
|
|
1394
1833
|
fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
}
|
|
1834
|
+
// Utiliser le CLI depuis le monorepo si présent, sinon depuis node_modules
|
|
1835
|
+
const scriptsPrefix = targetIsInMonorepo
|
|
1836
|
+
? "node ../../packages/app/dist/cli.js"
|
|
1837
|
+
: "node node_modules/@lastbrain/app/dist/cli.js";
|
|
1400
1838
|
const scripts = {
|
|
1401
1839
|
predev: targetIsInMonorepo
|
|
1402
|
-
? "pnpm --filter @lastbrain/core build && pnpm --filter @lastbrain/ui build && pnpm --filter @lastbrain/module-auth build && pnpm --filter @lastbrain/module-ai build"
|
|
1403
|
-
: "echo 'No prebuild needed
|
|
1840
|
+
? "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"
|
|
1841
|
+
: "echo 'No prebuild needed'",
|
|
1404
1842
|
dev: "next dev",
|
|
1843
|
+
"dev:local": "env-cmd -f .env.local next dev",
|
|
1844
|
+
"dev:prod": "env-cmd -f .env.prod next dev",
|
|
1405
1845
|
build: "next build",
|
|
1406
1846
|
start: "next start",
|
|
1407
1847
|
lint: "next lint",
|
|
1408
|
-
lastbrain:
|
|
1409
|
-
? "lastbrain"
|
|
1410
|
-
: "node node_modules/@lastbrain/app/dist/cli.js",
|
|
1848
|
+
lastbrain: scriptsPrefix,
|
|
1411
1849
|
"build:modules": `${scriptsPrefix} module:build`,
|
|
1412
1850
|
"db:migrations:sync": `${scriptsPrefix} db:migrations:sync`,
|
|
1413
1851
|
"db:init": `${scriptsPrefix} db:init`,
|