@lastbrain/app 0.1.47 → 1.0.2

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.
Files changed (51) hide show
  1. package/dist/app-shell/layout.d.ts +1 -1
  2. package/dist/app-shell/layout.d.ts.map +1 -1
  3. package/dist/app-shell/layout.js +1 -1
  4. package/dist/components/NotificationContainer.js +1 -1
  5. package/dist/index.d.ts +19 -19
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +19 -19
  8. package/dist/layouts/AdminLayoutWithSidebar.d.ts +3 -2
  9. package/dist/layouts/AdminLayoutWithSidebar.d.ts.map +1 -1
  10. package/dist/layouts/AdminLayoutWithSidebar.js +5 -5
  11. package/dist/layouts/AppProviders.d.ts +1 -1
  12. package/dist/layouts/AppProviders.d.ts.map +1 -1
  13. package/dist/layouts/AppProviders.js +3 -3
  14. package/dist/layouts/AuthLayoutWithSidebar.d.ts +7 -4
  15. package/dist/layouts/AuthLayoutWithSidebar.d.ts.map +1 -1
  16. package/dist/layouts/AuthLayoutWithSidebar.js +5 -5
  17. package/dist/layouts/PublicLayoutWithSidebar.js +2 -2
  18. package/dist/layouts/RootLayout.js +1 -1
  19. package/dist/scripts/init-app.d.ts.map +1 -1
  20. package/dist/scripts/init-app.js +457 -39
  21. package/dist/scripts/module-add.js +1 -1
  22. package/dist/scripts/module-build.d.ts.map +1 -1
  23. package/dist/scripts/module-build.js +36 -15
  24. package/dist/scripts/module-create.js +8 -8
  25. package/dist/scripts/module-delete.d.ts.map +1 -1
  26. package/dist/scripts/module-delete.js +1 -1
  27. package/dist/templates/DefaultDoc.d.ts.map +1 -1
  28. package/dist/templates/DefaultDoc.js +1 -1
  29. package/dist/templates/DocPage.js +1 -1
  30. package/dist/templates/DocsPageWithModules.js +1 -1
  31. package/dist/types/menu.d.ts +23 -0
  32. package/dist/types/menu.d.ts.map +1 -0
  33. package/dist/types/menu.js +1 -0
  34. package/package.json +9 -1
  35. package/src/app-shell/layout.tsx +1 -1
  36. package/src/components/NotificationContainer.tsx +1 -1
  37. package/src/index.ts +24 -19
  38. package/src/layouts/AdminLayoutWithSidebar.tsx +11 -3
  39. package/src/layouts/AppProviders.tsx +4 -4
  40. package/src/layouts/AuthLayoutWithSidebar.tsx +18 -4
  41. package/src/layouts/PublicLayoutWithSidebar.tsx +2 -2
  42. package/src/layouts/RootLayout.tsx +1 -1
  43. package/src/scripts/init-app.ts +479 -49
  44. package/src/scripts/module-add.ts +1 -1
  45. package/src/scripts/module-build.ts +46 -22
  46. package/src/scripts/module-create.ts +8 -8
  47. package/src/scripts/module-delete.ts +1 -4
  48. package/src/templates/DefaultDoc.tsx +264 -0
  49. package/src/templates/DocPage.tsx +1 -1
  50. package/src/templates/DocsPageWithModules.tsx +1 -1
  51. package/src/types/menu.ts +18 -0
@@ -14,7 +14,7 @@ import type {
14
14
  // Utiliser PROJECT_ROOT si défini (pour pnpm --filter), sinon process.cwd()
15
15
  const projectRoot = process.env.PROJECT_ROOT || process.cwd();
16
16
  // Si on est dans une app, monter jusqu'à la racine du monorepo
17
- const monorepoRoot = projectRoot.includes("/apps/")
17
+ const _monorepoRoot = projectRoot.includes("/apps/")
18
18
  ? path.resolve(projectRoot, "..", "..")
19
19
  : projectRoot;
20
20
  const appDirectory = path.join(projectRoot, "app");
@@ -235,6 +235,13 @@ function buildPage(moduleConfig: ModuleBuildConfig, page: ModulePageConfig) {
235
235
  page.path.includes("users/[id]") &&
236
236
  page.componentExport === "UserPage";
237
237
 
238
+ // Détecter les pages légales qui utilisent cookies (privacy, terms, returns)
239
+ const isLegalPage =
240
+ page.section === "public" &&
241
+ (page.path.includes("privacy") ||
242
+ page.path.includes("terms") ||
243
+ page.path.includes("returns"));
244
+
238
245
  let content: string;
239
246
 
240
247
  if (isUserDetailPage) {
@@ -273,7 +280,17 @@ const ${page.componentExport} = dynamic(
273
280
  { ssr: false }
274
281
  );
275
282
 
276
- export default function ${wrapperName}${hasDynamicParams ? "(props: any)" : "()"} {
283
+ export default function ${wrapperName}${hasDynamicParams ? "(props: Record<string, unknown>)" : "()"} {
284
+ return <${page.componentExport} ${hasDynamicParams ? "{...props}" : ""} />;
285
+ }
286
+ `;
287
+ } else if (isLegalPage) {
288
+ content = `// GENERATED BY LASTBRAIN MODULE BUILD
289
+ import { ${page.componentExport} } from "${moduleConfig.moduleName}";
290
+
291
+ export const dynamic = 'force-dynamic';
292
+
293
+ export default function ${wrapperName}${hasDynamicParams ? "(props: Record<string, unknown>)" : "()"} {
277
294
  return <${page.componentExport} ${hasDynamicParams ? "{...props}" : ""} />;
278
295
  }
279
296
  `;
@@ -281,7 +298,7 @@ export default function ${wrapperName}${hasDynamicParams ? "(props: any)" : "()"
281
298
  content = `// GENERATED BY LASTBRAIN MODULE BUILD
282
299
  import { ${page.componentExport} } from "${moduleConfig.moduleName}";
283
300
 
284
- export default function ${wrapperName}${hasDynamicParams ? "(props: any)" : "()"} {
301
+ export default function ${wrapperName}${hasDynamicParams ? "(props: Record<string, unknown>)" : "()"} {
285
302
  return <${page.componentExport} ${hasDynamicParams ? "{...props}" : ""} />;
286
303
  }
287
304
  `;
@@ -1012,33 +1029,40 @@ async function generateUserTabsConfig(moduleConfigs: ModuleBuildConfig[]) {
1012
1029
  )
1013
1030
  .sort((a, b) => (a.order || 0) - (b.order || 0));
1014
1031
 
1015
- if (userTabsConfigs.length === 0) {
1016
- console.log("⏭️ No user tabs configuration found in modules");
1017
- return;
1018
- }
1032
+ let appContent: string;
1019
1033
 
1020
- // Générer les imports statiques (Next/dynamic pour chaque composant)
1021
- const importsForApp = userTabsConfigs
1022
- .map(
1023
- (tab) =>
1024
- `const ${tab.componentExport} = dynamic(() => import("${tab.moduleName}").then(mod => ({ default: mod.${tab.componentExport} })), { ssr: true });`
1025
- )
1026
- .join("\n");
1034
+ if (userTabsConfigs.length === 0) {
1035
+ console.log(
1036
+ "⏭️ No user tabs configuration found in modules, creating empty config"
1037
+ );
1027
1038
 
1028
- // Générer le tableau des tabs
1029
- const tabsArray = userTabsConfigs
1030
- .map(
1031
- (tab) => ` {
1039
+ // Créer un fichier vide avec l'interface correcte
1040
+ const timestamp = new Date().toISOString();
1041
+ appContent = `// GENERATED FILE - DO NOT EDIT MANUALLY\n// User tabs configuration\n// Generated at: ${timestamp}\n\n"use client";\n\nimport type React from "react";\n\nexport interface ModuleUserTab {\n key: string;\n title: string;\n icon?: string;\n component: React.ComponentType<{ userId: string }>;\n}\n\nexport const moduleUserTabs: ModuleUserTab[] = [];\n\nexport default moduleUserTabs;\n`;
1042
+ } else {
1043
+ // Générer les imports statiques (Next/dynamic pour chaque composant)
1044
+ const importsForApp = userTabsConfigs
1045
+ .map(
1046
+ (tab) =>
1047
+ `const ${tab.componentExport} = dynamic(() => import("${tab.moduleName}").then(mod => ({ default: mod.${tab.componentExport} })), { ssr: true });`
1048
+ )
1049
+ .join("\n");
1050
+
1051
+ // Générer le tableau des tabs
1052
+ const tabsArray = userTabsConfigs
1053
+ .map(
1054
+ (tab) => ` {
1032
1055
  key: "${tab.key}",
1033
1056
  title: "${tab.title}",
1034
1057
  icon: "${tab.icon || ""}",
1035
1058
  component: ${tab.componentExport},
1036
1059
  }`
1037
- )
1038
- .join(",\n");
1060
+ )
1061
+ .join(",\n");
1039
1062
 
1040
- const timestamp = new Date().toISOString();
1041
- const appContent = `// GENERATED FILE - DO NOT EDIT MANUALLY\n// User tabs configuration\n// Generated at: ${timestamp}\n\n"use client";\n\nimport dynamic from "next/dynamic";\nimport type React from "react";\n\n${importsForApp}\n\nexport interface ModuleUserTab {\n key: string;\n title: string;\n icon?: string;\n component: React.ComponentType<{ userId: string }>;\n}\n\nexport const moduleUserTabs: ModuleUserTab[] = [\n${tabsArray}\n];\n\nexport default moduleUserTabs;\n`;
1063
+ const timestamp = new Date().toISOString();
1064
+ appContent = `// GENERATED FILE - DO NOT EDIT MANUALLY\n// User tabs configuration\n// Generated at: ${timestamp}\n\n"use client";\n\nimport dynamic from "next/dynamic";\nimport type React from "react";\n\n${importsForApp}\n\nexport interface ModuleUserTab {\n key: string;\n title: string;\n icon?: string;\n component: React.ComponentType<{ userId: string }>;\n}\n\nexport const moduleUserTabs: ModuleUserTab[] = [\n${tabsArray}\n];\n\nexport default moduleUserTabs;\n`;
1065
+ }
1042
1066
 
1043
1067
  // Créer le fichier de configuration (uniquement dans /config)
1044
1068
  const outputPath = path.join(projectRoot, "config", "user-tabs.ts");
@@ -399,7 +399,7 @@ export { default as buildConfig } from "./${moduleNameOnly}.build.config";
399
399
  /**
400
400
  * Génère le contenu du fichier server.ts
401
401
  */
402
- function generateServerTs(tables: TableConfig[]): string {
402
+ function _generateServerTs(tables: TableConfig[]): string {
403
403
  const exports: string[] = [];
404
404
 
405
405
  for (const table of tables) {
@@ -1280,7 +1280,7 @@ export function getAvailableModuleNames(): string[] {
1280
1280
  );
1281
1281
  if (arrayMatch) {
1282
1282
  const arrayContent = arrayMatch[1];
1283
- const lastItem = arrayContent.trim().split("\n").pop();
1283
+ const _lastItem = arrayContent.trim().split("\n").pop();
1284
1284
 
1285
1285
  // Ajouter le nouveau module à la fin du tableau
1286
1286
  const newArrayContent =
@@ -1299,9 +1299,9 @@ export function getAvailableModuleNames(): string[] {
1299
1299
  )
1300
1300
  );
1301
1301
  }
1302
- } catch (error) {
1302
+ } catch (_error) {
1303
1303
  console.log(
1304
- chalk.yellow(` ⚠️ Erreur lors de la mise à jour du registre: ${error}`)
1304
+ chalk.yellow(` ⚠️ Erreur lors de la mise à jour du registre: ${_error}`)
1305
1305
  );
1306
1306
  console.log(
1307
1307
  chalk.gray(" Vous devrez ajouter manuellement le module au registre")
@@ -1472,7 +1472,7 @@ export async function createModuleStructure(
1472
1472
  stdio: "inherit",
1473
1473
  });
1474
1474
  console.log(chalk.green("\n✅ Dépendances installées avec succès!"));
1475
- } catch (error) {
1475
+ } catch (_error) {
1476
1476
  console.log(
1477
1477
  chalk.yellow(
1478
1478
  "\n⚠️ Erreur lors de l'installation, veuillez exécuter manuellement:"
@@ -1493,7 +1493,7 @@ export async function createModuleStructure(
1493
1493
  stdio: "inherit",
1494
1494
  });
1495
1495
  console.log(chalk.green("✓ Module compilé"));
1496
- } catch (error) {
1496
+ } catch (_error) {
1497
1497
  console.log(
1498
1498
  chalk.yellow("⚠️ Build automatique échoué, exécutez: cd"),
1499
1499
  config.slug,
@@ -1696,8 +1696,8 @@ export async function createModule() {
1696
1696
  let rootDir: string;
1697
1697
  try {
1698
1698
  rootDir = findWorkspaceRoot();
1699
- } catch (error) {
1700
- console.error(chalk.red("❌ " + (error as Error).message));
1699
+ } catch (_error) {
1700
+ console.error(chalk.red("❌ " + (_error as Error).message));
1701
1701
  process.exit(1);
1702
1702
  }
1703
1703
 
@@ -3,10 +3,7 @@ import path from "path";
3
3
  import chalk from "chalk";
4
4
  import inquirer from "inquirer";
5
5
  import { fileURLToPath } from "url";
6
- import {
7
- AVAILABLE_MODULES,
8
- type ModuleMetadata,
9
- } from "@lastbrain/core/config/modules";
6
+ import { AVAILABLE_MODULES } from "@lastbrain/core/config/modules";
10
7
 
11
8
  const __filename = fileURLToPath(import.meta.url);
12
9
  const __dirname = path.dirname(__filename);
@@ -613,6 +613,270 @@ export function DefaultDocumentation() {
613
613
  </code>
614
614
  .
615
615
  </p>
616
+ <h3 className="text-lg font-semibold mb-2">
617
+ 1. Ajouter une page et un menu custom
618
+ </h3>
619
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
620
+ 1. Crée une page dans l'app cible (exemple public) :
621
+ </p>
622
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
623
+ {" "}
624
+ ```tsx
625
+ </p>
626
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
627
+ {" "}
628
+ // apps/lastbrain/app/nouvelle-page/page.tsx
629
+ </p>
630
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
631
+ {" "}
632
+ export default function NouvellePage() &lbrace;
633
+ </p>
634
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
635
+ {" "}
636
+ return <div>Nouvelle Page</div>;
637
+ </p>
638
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
639
+ {" "}
640
+ &rbrace;
641
+ </p>
642
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
643
+ {" "}
644
+ ```
645
+ </p>
646
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
647
+ 2. Déclare le menu dans{" "}
648
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
649
+ apps/lastbrain/config/menu-custom.ts
650
+ </code>{" "}
651
+ (fichier optionnel, non écrasé par les outils) :
652
+ </p>
653
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
654
+ {" "}
655
+ ```ts
656
+ </p>
657
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
658
+ {" "}
659
+ import type &lbrace; MenuCustom &rbrace; from "./menu-custom";
660
+ </p>
661
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
662
+ {" "}
663
+ export const menuCustom: MenuCustom = &lbrace;
664
+ </p>
665
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
666
+ {" "}
667
+ public: [
668
+ </p>
669
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
670
+ {" "}
671
+ &lbrace;
672
+ </p>
673
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
674
+ {" "}
675
+ title: "Nouvelle Page",
676
+ </p>
677
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
678
+ {" "}
679
+ description: "Une page custom",
680
+ </p>
681
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
682
+ {" "}
683
+ icon: "Plus",
684
+ </p>
685
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
686
+ {" "}
687
+ path: "/nouvelle-page",
688
+ </p>
689
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
690
+ {" "}
691
+ order: 100,
692
+ </p>
693
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
694
+ {" "}
695
+ &rbrace;,
696
+ </p>
697
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2"> ],</p>
698
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
699
+ {" "}
700
+ auth: [],
701
+ </p>
702
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
703
+ {" "}
704
+ admin: [],
705
+ </p>
706
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
707
+ {" "}
708
+ &rbrace;;
709
+ </p>
710
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
711
+ {" "}
712
+ ```
713
+ </p>
714
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
715
+ 3. Choisis le préfixe de route pour la section :
716
+ </p>
717
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
718
+ {" "}
719
+ -{" "}
720
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
721
+ /
722
+ </code>{" "}
723
+ pour les pages publiques (header + palette + AppAside public).
724
+ </p>
725
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
726
+ {" "}
727
+ -{" "}
728
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
729
+ /auth/...
730
+ </code>{" "}
731
+ pour les pages authentifiées (header + palette + AppAside auth).
732
+ </p>
733
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
734
+ {" "}
735
+ -{" "}
736
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
737
+ /admin/...
738
+ </code>{" "}
739
+ pour les pages admin (header + palette + AppAside admin).
740
+ </p>
741
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
742
+ 4. (Optionnel) Ajoute{" "}
743
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
744
+ order
745
+ </code>
746
+ ,{" "}
747
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
748
+ icon
749
+ </code>
750
+ ,{" "}
751
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
752
+ description
753
+ </code>{" "}
754
+ ou{" "}
755
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
756
+ shortcutDisplay
757
+ </code>{" "}
758
+ pour contrôler le tri, l'icône Lucide et l'affichage dans la
759
+ palette.
760
+ </p>
761
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
762
+ 5. Aucun rebuild spécial : le système charge automatiquement{" "}
763
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
764
+ menu-custom.ts
765
+ </code>{" "}
766
+ et fusionne les menus custom avec la config existante dans le
767
+ Header, le Aside et la palette (KeyboardKey).
768
+ </p>
769
+ <h4 className="font-medium mb-2">Cas d'usage rapides</h4>
770
+ <div className="space-y-2">
771
+ <div className="flex items-start gap-2">
772
+ <span className="text-green-600">✅</span>
773
+ <span>
774
+ Page publique custom : place ton fichier dans{" "}
775
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
776
+ apps/lastbrain/app/(custom)/nouvelle-page/page.tsx
777
+ </code>{" "}
778
+ et ajoute l'entrée dans{" "}
779
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
780
+ menuCustom.public
781
+ </code>{" "}
782
+ avec{" "}
783
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
784
+ path: "/nouvelle-page"
785
+ </code>
786
+ .
787
+ </span>
788
+ </div>
789
+ <div className="flex items-start gap-2">
790
+ <span className="text-green-600">✅</span>
791
+ <span>
792
+ Page auth custom : place la page dans{" "}
793
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
794
+ apps/lastbrain/app/(custom)/auth/ma-page/page.tsx
795
+ </code>{" "}
796
+ avec un{" "}
797
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
798
+ path: "/auth/ma-page"
799
+ </code>{" "}
800
+ dans{" "}
801
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
802
+ menuCustom.auth
803
+ </code>
804
+ .
805
+ </span>
806
+ </div>
807
+ <div className="flex items-start gap-2">
808
+ <span className="text-green-600">✅</span>
809
+ <span>
810
+ Page admin custom : même principe avec un chemin{" "}
811
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
812
+ /admin/...
813
+ </code>{" "}
814
+ et une entrée dans{" "}
815
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
816
+ menuCustom.admin
817
+ </code>
818
+ .
819
+ </span>
820
+ </div>
821
+ </div>
822
+ <h3 className="text-lg font-semibold mb-2">
823
+ 2. Masquer des menus et bloquer les routes (menu-ignored)
824
+ </h3>
825
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
826
+ 1. Crée{" "}
827
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
828
+ apps/lastbrain/config/menu-ignored.ts
829
+ </code>{" "}
830
+ si absent :
831
+ </p>
832
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
833
+ {" "}
834
+ ```ts
835
+ </p>
836
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
837
+ {" "}
838
+ export const menuIgnored = &lbrace;
839
+ </p>
840
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
841
+ {" "}
842
+ public: [&lbrace; title: "Boutique", path: "/shop" &rbrace;],
843
+ </p>
844
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
845
+ {" "}
846
+ auth: [
847
+ </p>
848
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
849
+ {" "}
850
+ &lbrace; title: "Mes commandes", path:
851
+ "/auth/core-order/account/orders" &rbrace;,
852
+ </p>
853
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2"> ],</p>
854
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
855
+ {" "}
856
+ &rbrace;;
857
+ </p>
858
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
859
+ {" "}
860
+ ```
861
+ </p>
862
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
863
+ 2. Le Header, l'AppAside et la palette excluent ces entrées par{" "}
864
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
865
+ title
866
+ </code>
867
+ .
868
+ </p>
869
+ <p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
870
+ 3. Le middleware redirige toute route correspondante (
871
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
872
+ path
873
+ </code>{" "}
874
+ exact ou préfixe) vers{" "}
875
+ <code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
876
+ /404
877
+ </code>
878
+ .
879
+ </p>
616
880
  </CardBody>
617
881
  </Card>
618
882
 
@@ -30,7 +30,7 @@ import {
30
30
  HardDrive,
31
31
  RotateCcw,
32
32
  } from "lucide-react";
33
- import { DefaultDocumentation } from "./DefaultDoc.js";
33
+ import { DefaultDocumentation } from "./DefaultDoc";
34
34
 
35
35
  // Composant NavigationListbox séparé pour éviter la recréation
36
36
  interface NavigationListboxProps {
@@ -1,6 +1,6 @@
1
1
  // Template for docs page with dynamic module loading
2
2
  import React from "react";
3
- import { DocPage } from "./DocPage.js";
3
+ import { DocPage } from "./DocPage";
4
4
 
5
5
  // This will be replaced by module-build script with actual imports
6
6
  // MODULES_IMPORTS_PLACEHOLDER
@@ -0,0 +1,18 @@
1
+ import type { MenuItem } from "@lastbrain/ui";
2
+
3
+ /**
4
+ * Menu items to hide from display and block routes
5
+ */
6
+ export interface MenuIgnored {
7
+ public: { title: string; path: string }[];
8
+ auth: { title: string; path: string }[];
9
+ }
10
+
11
+ /**
12
+ * Custom menu items to add without creating a module
13
+ */
14
+ export interface MenuCustom {
15
+ public?: MenuItem[];
16
+ auth?: MenuItem[];
17
+ admin?: MenuItem[];
18
+ }