@lastbrain/app 0.1.40 → 0.1.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/useNotifications.d.ts +1 -0
- package/dist/hooks/useNotifications.d.ts.map +1 -1
- package/dist/layouts/AdminLayout.d.ts.map +1 -1
- package/dist/layouts/AdminLayout.js +0 -1
- package/dist/layouts/AuthLayout.d.ts.map +1 -1
- package/dist/layouts/AuthLayout.js +0 -1
- package/dist/layouts/PublicLayout.d.ts +5 -2
- package/dist/layouts/PublicLayout.d.ts.map +1 -1
- package/dist/layouts/PublicLayout.js +4 -3
- package/dist/scripts/init-app.js +131 -50
- package/dist/scripts/module-add.d.ts.map +1 -1
- package/dist/scripts/module-add.js +22 -52
- package/dist/scripts/module-build.d.ts.map +1 -1
- package/dist/scripts/module-build.js +381 -9
- package/dist/styles.css +1 -1
- package/dist/templates/DefaultDoc.d.ts.map +1 -1
- package/dist/templates/DefaultDoc.js +2 -2
- package/dist/templates/DocPage.js +1 -1
- package/package.json +1 -1
- package/src/hooks/useNotifications.ts +1 -0
- package/src/layouts/AdminLayout.tsx +0 -2
- package/src/layouts/AuthLayout.tsx +0 -2
- package/src/layouts/PublicLayout.tsx +14 -2
- package/src/scripts/init-app.ts +144 -49
- package/src/scripts/module-add.ts +36 -82
- package/src/scripts/module-build.ts +447 -13
- package/src/templates/DefaultDoc.tsx +362 -12
- package/src/templates/DocPage.tsx +3 -3
package/src/scripts/init-app.ts
CHANGED
|
@@ -85,7 +85,7 @@ export async function initApp(options: InitAppOptions) {
|
|
|
85
85
|
await createNextStructure(targetDir, force, useHeroUI, withAuth);
|
|
86
86
|
|
|
87
87
|
// 4. Créer les fichiers de configuration
|
|
88
|
-
await createConfigFiles(targetDir, force, useHeroUI);
|
|
88
|
+
await createConfigFiles(targetDir, force, useHeroUI, projectName);
|
|
89
89
|
|
|
90
90
|
// 5. Créer le système de proxy storage
|
|
91
91
|
await createStorageProxy(targetDir, force);
|
|
@@ -490,75 +490,38 @@ async function createNextStructure(
|
|
|
490
490
|
let layoutContent = "";
|
|
491
491
|
|
|
492
492
|
if (useHeroUI) {
|
|
493
|
-
// Layout avec HeroUI
|
|
493
|
+
// Layout avec HeroUI - Server Component
|
|
494
494
|
layoutContent = `// GENERATED BY LASTBRAIN APP-SHELL
|
|
495
|
-
|
|
496
|
-
"use client";
|
|
495
|
+
// Server Component pour permettre le SSR des pages enfants
|
|
497
496
|
|
|
498
497
|
import "../styles/globals.css";
|
|
499
|
-
import {
|
|
500
|
-
|
|
501
|
-
import { ThemeProvider } from "next-themes";
|
|
502
|
-
import { useRouter } from "next/navigation";
|
|
503
|
-
import { AppProviders } from "../components/AppProviders";
|
|
498
|
+
import { ClientLayout } from "../components/ClientLayout";
|
|
504
499
|
import type { PropsWithChildren } from "react";
|
|
505
|
-
import { AppHeader } from "../components/AppHeader";
|
|
506
500
|
|
|
507
501
|
export default function RootLayout({ children }: PropsWithChildren<{}>) {
|
|
508
|
-
const router = useRouter();
|
|
509
|
-
|
|
510
502
|
return (
|
|
511
503
|
<html lang="fr" suppressHydrationWarning>
|
|
512
504
|
<body className="min-h-screen">
|
|
513
|
-
<
|
|
514
|
-
<ThemeProvider
|
|
515
|
-
attribute="class"
|
|
516
|
-
defaultTheme="dark"
|
|
517
|
-
enableSystem={false}
|
|
518
|
-
storageKey="lastbrain-theme"
|
|
519
|
-
>
|
|
520
|
-
<AppProviders>
|
|
521
|
-
<AppHeader />
|
|
522
|
-
<div className="min-h-screen text-foreground bg-background">
|
|
523
|
-
{children}
|
|
524
|
-
</div>
|
|
525
|
-
</AppProviders>
|
|
526
|
-
</ThemeProvider>
|
|
527
|
-
</HeroUIProvider>
|
|
505
|
+
<ClientLayout>{children}</ClientLayout>
|
|
528
506
|
</body>
|
|
529
507
|
</html>
|
|
530
508
|
);
|
|
531
509
|
}
|
|
532
510
|
`;
|
|
533
511
|
} else {
|
|
534
|
-
// Layout Tailwind CSS uniquement
|
|
512
|
+
// Layout Tailwind CSS uniquement - Server Component
|
|
535
513
|
layoutContent = `// GENERATED BY LASTBRAIN APP-SHELL
|
|
536
|
-
|
|
537
|
-
"use client";
|
|
514
|
+
// Server Component pour permettre le SSR des pages enfants
|
|
538
515
|
|
|
539
516
|
import "../styles/globals.css";
|
|
540
|
-
import {
|
|
541
|
-
import { AppProviders } from "../components/AppProviders";
|
|
517
|
+
import { ClientLayout } from "../components/ClientLayout";
|
|
542
518
|
import type { PropsWithChildren } from "react";
|
|
543
|
-
import { AppHeader } from "../components/AppHeader";
|
|
544
519
|
|
|
545
520
|
export default function RootLayout({ children }: PropsWithChildren<{}>) {
|
|
546
521
|
return (
|
|
547
522
|
<html lang="fr" suppressHydrationWarning>
|
|
548
523
|
<body className="min-h-screen">
|
|
549
|
-
<
|
|
550
|
-
attribute="class"
|
|
551
|
-
defaultTheme="light"
|
|
552
|
-
enableSystem={false}
|
|
553
|
-
storageKey="lastbrain-theme"
|
|
554
|
-
>
|
|
555
|
-
<AppProviders>
|
|
556
|
-
<AppHeader />
|
|
557
|
-
<div className="min-h-screen bg-slate-50 text-slate-900 dark:bg-slate-950 dark:text-white">
|
|
558
|
-
{children}
|
|
559
|
-
</div>
|
|
560
|
-
</AppProviders>
|
|
561
|
-
</ThemeProvider>
|
|
524
|
+
<ClientLayout>{children}</ClientLayout>
|
|
562
525
|
</body>
|
|
563
526
|
</html>
|
|
564
527
|
);
|
|
@@ -593,9 +556,16 @@ export default function RootLayout({ children }: PropsWithChildren<{}>) {
|
|
|
593
556
|
const homePageContent = `// GENERATED BY LASTBRAIN APP-SHELL
|
|
594
557
|
|
|
595
558
|
import { SimpleHomePage } from "@lastbrain/app";
|
|
559
|
+
import { Footer } from "@lastbrain/ui";
|
|
560
|
+
import { footerConfig } from "../config/footer";
|
|
596
561
|
|
|
597
562
|
export default function RootPage() {
|
|
598
|
-
return
|
|
563
|
+
return (
|
|
564
|
+
<>
|
|
565
|
+
<SimpleHomePage showAuth={${withAuth}} />
|
|
566
|
+
<Footer config={footerConfig} />
|
|
567
|
+
</>
|
|
568
|
+
);
|
|
599
569
|
}
|
|
600
570
|
`;
|
|
601
571
|
await fs.writeFile(homePagePath, homePageContent);
|
|
@@ -643,6 +613,9 @@ export default function NotFound() {
|
|
|
643
613
|
await createRoute(appDir, "auth", "auth", force);
|
|
644
614
|
await createRoute(appDir, "docs", "public", force);
|
|
645
615
|
|
|
616
|
+
// Créer le composant ClientLayout (wrapper client avec providers)
|
|
617
|
+
await createClientLayout(targetDir, force, useHeroUI);
|
|
618
|
+
|
|
646
619
|
// Créer le composant AppHeader
|
|
647
620
|
await createAppHeader(targetDir, force);
|
|
648
621
|
|
|
@@ -653,6 +626,92 @@ export default function NotFound() {
|
|
|
653
626
|
await createAppProvidersWrapper(targetDir, force);
|
|
654
627
|
}
|
|
655
628
|
|
|
629
|
+
async function createClientLayout(
|
|
630
|
+
targetDir: string,
|
|
631
|
+
force: boolean,
|
|
632
|
+
useHeroUI: boolean,
|
|
633
|
+
) {
|
|
634
|
+
const componentsDir = path.join(targetDir, "components");
|
|
635
|
+
await fs.ensureDir(componentsDir);
|
|
636
|
+
|
|
637
|
+
const clientLayoutPath = path.join(componentsDir, "ClientLayout.tsx");
|
|
638
|
+
|
|
639
|
+
if (!fs.existsSync(clientLayoutPath) || force) {
|
|
640
|
+
let clientLayoutContent = "";
|
|
641
|
+
|
|
642
|
+
if (useHeroUI) {
|
|
643
|
+
// ClientLayout avec HeroUI
|
|
644
|
+
clientLayoutContent = `"use client";
|
|
645
|
+
|
|
646
|
+
import { HeroUIProvider } from "@heroui/system";
|
|
647
|
+
import { ThemeProvider } from "next-themes";
|
|
648
|
+
import { useRouter } from "next/navigation";
|
|
649
|
+
import { AppProviders } from "./AppProviders";
|
|
650
|
+
import { AppHeader } from "./AppHeader";
|
|
651
|
+
import type { ReactNode } from "react";
|
|
652
|
+
|
|
653
|
+
export function ClientLayout({ children }: { children: ReactNode }) {
|
|
654
|
+
const router = useRouter();
|
|
655
|
+
|
|
656
|
+
return (
|
|
657
|
+
<HeroUIProvider navigate={router.push}>
|
|
658
|
+
<ThemeProvider
|
|
659
|
+
attribute="class"
|
|
660
|
+
defaultTheme="dark"
|
|
661
|
+
enableSystem={false}
|
|
662
|
+
storageKey="lastbrain-theme"
|
|
663
|
+
>
|
|
664
|
+
<AppProviders>
|
|
665
|
+
<AppHeader />
|
|
666
|
+
<div className="min-h-screen text-foreground bg-background">
|
|
667
|
+
{children}
|
|
668
|
+
</div>
|
|
669
|
+
</AppProviders>
|
|
670
|
+
</ThemeProvider>
|
|
671
|
+
</HeroUIProvider>
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
`;
|
|
675
|
+
} else {
|
|
676
|
+
// ClientLayout Tailwind CSS uniquement
|
|
677
|
+
clientLayoutContent = `"use client";
|
|
678
|
+
|
|
679
|
+
import { ThemeProvider } from "next-themes";
|
|
680
|
+
import { AppProviders } from "./AppProviders";
|
|
681
|
+
import { AppHeader } from "./AppHeader";
|
|
682
|
+
import type { ReactNode } from "react";
|
|
683
|
+
|
|
684
|
+
export function ClientLayout({ children }: { children: ReactNode }) {
|
|
685
|
+
return (
|
|
686
|
+
<ThemeProvider
|
|
687
|
+
attribute="class"
|
|
688
|
+
defaultTheme="light"
|
|
689
|
+
enableSystem={false}
|
|
690
|
+
storageKey="lastbrain-theme"
|
|
691
|
+
>
|
|
692
|
+
<AppProviders>
|
|
693
|
+
<AppHeader />
|
|
694
|
+
<div className="min-h-screen bg-slate-50 text-slate-900 dark:bg-slate-950 dark:text-white">
|
|
695
|
+
{children}
|
|
696
|
+
</div>
|
|
697
|
+
</AppProviders>
|
|
698
|
+
</ThemeProvider>
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
`;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
await fs.writeFile(clientLayoutPath, clientLayoutContent);
|
|
705
|
+
console.log(chalk.green("✓ components/ClientLayout.tsx créé"));
|
|
706
|
+
} else {
|
|
707
|
+
console.log(
|
|
708
|
+
chalk.gray(
|
|
709
|
+
" components/ClientLayout.tsx existe déjà (utilisez --force pour écraser)",
|
|
710
|
+
),
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
656
715
|
async function createRoute(
|
|
657
716
|
appDir: string,
|
|
658
717
|
routeName: string,
|
|
@@ -700,12 +759,27 @@ export default function AuthLayout({
|
|
|
700
759
|
);
|
|
701
760
|
}`;
|
|
702
761
|
} else {
|
|
703
|
-
// Layout standard pour les autres routes
|
|
762
|
+
// Layout standard pour les autres routes (ex: docs = public)
|
|
704
763
|
const layoutComponent =
|
|
705
764
|
layoutType.charAt(0).toUpperCase() + layoutType.slice(1) + "Layout";
|
|
706
|
-
|
|
765
|
+
|
|
766
|
+
if (routeName === "docs") {
|
|
767
|
+
// Layout docs avec footer
|
|
768
|
+
layoutContent = `import { ${layoutComponent} } from "@lastbrain/app";
|
|
769
|
+
import { footerConfig } from "../../config/footer";
|
|
770
|
+
|
|
771
|
+
export default function DocsLayout({
|
|
772
|
+
children,
|
|
773
|
+
}: {
|
|
774
|
+
children: React.ReactNode;
|
|
775
|
+
}) {
|
|
776
|
+
return <${layoutComponent} footerConfig={footerConfig}>{children}</${layoutComponent}>;
|
|
777
|
+
}`;
|
|
778
|
+
} else {
|
|
779
|
+
layoutContent = `import { ${layoutComponent} } from "@lastbrain/app";
|
|
707
780
|
|
|
708
781
|
export default ${layoutComponent};`;
|
|
782
|
+
}
|
|
709
783
|
}
|
|
710
784
|
|
|
711
785
|
await fs.writeFile(layoutPath, layoutContent);
|
|
@@ -900,6 +974,7 @@ async function createConfigFiles(
|
|
|
900
974
|
targetDir: string,
|
|
901
975
|
force: boolean,
|
|
902
976
|
useHeroUI: boolean,
|
|
977
|
+
projectName?: string,
|
|
903
978
|
) {
|
|
904
979
|
console.log(chalk.yellow("\n⚙️ Création des fichiers de configuration..."));
|
|
905
980
|
|
|
@@ -1174,6 +1249,26 @@ export const menuConfig: MenuConfig = {
|
|
|
1174
1249
|
console.log(chalk.green("✓ config/menu.ts créé"));
|
|
1175
1250
|
}
|
|
1176
1251
|
|
|
1252
|
+
// config/footer.ts
|
|
1253
|
+
const footerConfigPath = path.join(configDir, "footer.ts");
|
|
1254
|
+
if (!fs.existsSync(footerConfigPath) || force) {
|
|
1255
|
+
const footerConfig = `// Auto-generated footer configuration
|
|
1256
|
+
// Run "node ../../scripts/generate-footer-config.js ./apps/[your-app]" to regenerate
|
|
1257
|
+
"use client";
|
|
1258
|
+
|
|
1259
|
+
import type { FooterConfig } from "@lastbrain/ui";
|
|
1260
|
+
|
|
1261
|
+
export const footerConfig: FooterConfig = {
|
|
1262
|
+
companyName: "${projectName}",
|
|
1263
|
+
companyDescription: "Application LastBrain",
|
|
1264
|
+
links: [],
|
|
1265
|
+
social: [],
|
|
1266
|
+
};
|
|
1267
|
+
`;
|
|
1268
|
+
await fs.writeFile(footerConfigPath, footerConfig);
|
|
1269
|
+
console.log(chalk.green("✓ config/footer.ts créé"));
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1177
1272
|
// Créer les hooks
|
|
1178
1273
|
await createHooksDirectory(targetDir, force);
|
|
1179
1274
|
}
|
|
@@ -204,94 +204,48 @@ export async function addModule(moduleName: string, targetDir: string) {
|
|
|
204
204
|
console.log(
|
|
205
205
|
chalk.yellow("\n⬆️ Application des nouvelles migrations..."),
|
|
206
206
|
);
|
|
207
|
-
try {
|
|
208
|
-
// Essayer en capturant la sortie pour diagnostiquer les erreurs fréquentes
|
|
209
|
-
execSync("supabase migration up --local", {
|
|
210
|
-
cwd: targetDir,
|
|
211
|
-
stdio: "pipe",
|
|
212
|
-
});
|
|
213
|
-
console.log(chalk.green("✓ Migrations appliquées"));
|
|
214
|
-
} catch (error: any) {
|
|
215
|
-
const output = String(
|
|
216
|
-
error?.stderr || error?.stdout || error?.message || "",
|
|
217
|
-
);
|
|
218
|
-
const mismatch = output.includes(
|
|
219
|
-
"Remote migration versions not found in local migrations directory",
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
if (mismatch) {
|
|
223
|
-
console.warn(
|
|
224
|
-
chalk.yellow("⚠️ Historique des migrations désynchronisé."),
|
|
225
|
-
);
|
|
226
207
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
208
|
+
// Appliquer directement avec psql au lieu de supabase migration up
|
|
209
|
+
const migrationsDir = path.join(targetDir, "supabase", "migrations");
|
|
210
|
+
const migrationFiles = fs
|
|
211
|
+
.readdirSync(migrationsDir)
|
|
212
|
+
.filter((f) => f.endsWith(".sql"))
|
|
213
|
+
.filter((f) => copiedMigrationFiles.includes(f))
|
|
214
|
+
.sort();
|
|
215
|
+
|
|
216
|
+
if (migrationFiles.length === 0) {
|
|
217
|
+
console.log(
|
|
218
|
+
chalk.yellow("⚠️ Aucune nouvelle migration à appliquer"),
|
|
219
|
+
);
|
|
220
|
+
} else {
|
|
221
|
+
try {
|
|
222
|
+
const dbUrl =
|
|
223
|
+
"postgresql://postgres:postgres@127.0.0.1:54322/postgres";
|
|
224
|
+
|
|
225
|
+
for (const file of migrationFiles) {
|
|
226
|
+
const filePath = path.join(migrationsDir, file);
|
|
227
|
+
console.log(chalk.gray(` Exécution de ${file}...`));
|
|
228
|
+
|
|
229
|
+
execSync(`psql "${dbUrl}" -f "${filePath}"`, {
|
|
230
|
+
cwd: targetDir,
|
|
231
|
+
stdio: "pipe",
|
|
232
|
+
});
|
|
240
233
|
}
|
|
241
234
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
)
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
);
|
|
249
|
-
} else {
|
|
250
|
-
// Réparation automatique de l'historique
|
|
251
|
-
const datesStr = migrationDates.join(" ");
|
|
252
|
-
console.log(
|
|
253
|
-
chalk.yellow(`\n🔧 Réparation automatique de l'historique...`),
|
|
254
|
-
);
|
|
255
|
-
console.log(chalk.gray(` Dates: ${datesStr}`));
|
|
256
|
-
|
|
257
|
-
try {
|
|
258
|
-
execSync(
|
|
259
|
-
`supabase migration repair --status reverted ${datesStr} --local`,
|
|
260
|
-
{
|
|
261
|
-
cwd: targetDir,
|
|
262
|
-
stdio: "inherit",
|
|
263
|
-
},
|
|
264
|
-
);
|
|
265
|
-
console.log(chalk.green("✓ Historique réparé"));
|
|
266
|
-
|
|
267
|
-
console.log(
|
|
268
|
-
chalk.yellow("\n⬆️ Application des nouvelles migrations..."),
|
|
269
|
-
);
|
|
270
|
-
execSync("supabase migration up --local", {
|
|
271
|
-
cwd: targetDir,
|
|
272
|
-
stdio: "inherit",
|
|
273
|
-
});
|
|
274
|
-
console.log(chalk.green("✓ Migrations appliquées"));
|
|
275
|
-
} catch (e) {
|
|
276
|
-
console.error(
|
|
277
|
-
chalk.red("❌ Échec de la réparation automatique"),
|
|
278
|
-
);
|
|
279
|
-
console.log(
|
|
280
|
-
chalk.gray(
|
|
281
|
-
`\nVous pouvez essayer manuellement:\n supabase migration repair --status reverted ${datesStr} --local\n supabase migration up --local`,
|
|
282
|
-
),
|
|
283
|
-
);
|
|
284
|
-
console.log(
|
|
285
|
-
chalk.gray(
|
|
286
|
-
`\nOu faire un reset complet:\n supabase db reset\n`,
|
|
287
|
-
),
|
|
288
|
-
);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
} else {
|
|
235
|
+
console.log(
|
|
236
|
+
chalk.green(
|
|
237
|
+
`✓ ${migrationFiles.length} migration(s) appliquée(s)`,
|
|
238
|
+
),
|
|
239
|
+
);
|
|
240
|
+
} catch (error: any) {
|
|
292
241
|
console.error(
|
|
293
242
|
chalk.red("❌ Erreur lors de l'application des migrations"),
|
|
294
243
|
);
|
|
244
|
+
console.log(
|
|
245
|
+
chalk.gray(
|
|
246
|
+
"\nVous pouvez essayer manuellement:\n supabase db reset\n",
|
|
247
|
+
),
|
|
248
|
+
);
|
|
295
249
|
}
|
|
296
250
|
}
|
|
297
251
|
} else {
|