@lastbrain/app 0.1.7 → 0.1.9

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 (40) hide show
  1. package/dist/scripts/init-app.js +3 -3
  2. package/dist/styles.css +2 -0
  3. package/package.json +11 -3
  4. package/src/app-shell/(admin)/layout.tsx +13 -0
  5. package/src/app-shell/(auth)/layout.tsx +13 -0
  6. package/src/app-shell/(public)/page.tsx +11 -0
  7. package/src/app-shell/layout.tsx +5 -0
  8. package/src/app-shell/not-found.tsx +28 -0
  9. package/src/auth/authHelpers.ts +24 -0
  10. package/src/auth/useAuthSession.ts +54 -0
  11. package/src/cli.ts +96 -0
  12. package/src/index.ts +21 -0
  13. package/src/layouts/AdminLayout.tsx +7 -0
  14. package/src/layouts/AppProviders.tsx +61 -0
  15. package/src/layouts/AuthLayout.tsx +7 -0
  16. package/src/layouts/PublicLayout.tsx +7 -0
  17. package/src/layouts/RootLayout.tsx +27 -0
  18. package/src/modules/module-loader.ts +14 -0
  19. package/src/scripts/README.md +262 -0
  20. package/src/scripts/db-init.ts +338 -0
  21. package/src/scripts/db-migrations-sync.ts +86 -0
  22. package/src/scripts/dev-sync.ts +218 -0
  23. package/src/scripts/init-app.ts +1077 -0
  24. package/src/scripts/module-add.ts +242 -0
  25. package/src/scripts/module-build.ts +502 -0
  26. package/src/scripts/module-create.ts +809 -0
  27. package/src/scripts/module-list.ts +37 -0
  28. package/src/scripts/module-remove.ts +367 -0
  29. package/src/scripts/readme-build.ts +60 -0
  30. package/src/styles.css +3 -0
  31. package/src/templates/AuthGuidePage.tsx +68 -0
  32. package/src/templates/DefaultDoc.tsx +462 -0
  33. package/src/templates/DocPage.tsx +381 -0
  34. package/src/templates/DocsPageWithModules.tsx +22 -0
  35. package/src/templates/MigrationsGuidePage.tsx +61 -0
  36. package/src/templates/ModuleGuidePage.tsx +71 -0
  37. package/src/templates/SimpleDocPage.tsx +587 -0
  38. package/src/templates/SimpleHomePage.tsx +385 -0
  39. package/src/templates/env.example/.env.example +6 -0
  40. package/src/templates/migrations/20201010100000_app_base.sql +228 -0
@@ -626,8 +626,8 @@ const config = {
626
626
  content: [
627
627
  "./app/**/*.{js,ts,jsx,tsx,mdx}",
628
628
  "./components/**/*.{js,ts,jsx,tsx,mdx}",
629
- "./node_modules/@lastbrain/*/dist/**/*.js",
630
- "./node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}"
629
+ "./node_modules/@lastbrain/**/*.{js,jsx,ts,tsx}",
630
+ "./node_modules/@heroui/**/*.{js,jsx,ts,tsx}"
631
631
  ],
632
632
  theme: {
633
633
  extend: {},
@@ -645,7 +645,7 @@ export default config;
645
645
  content: [
646
646
  "./app/**/*.{js,ts,jsx,tsx,mdx}",
647
647
  "./components/**/*.{js,ts,jsx,tsx,mdx}",
648
- "./node_modules/@lastbrain/*/dist/**/*.js",
648
+ "./node_modules/@lastbrain/**/*.{js,jsx,ts,tsx}",
649
649
  ],
650
650
  theme: {
651
651
  extend: {
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.1.17 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports ((-webkit-hyphens:none) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-font-weight:initial;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-orange-100:oklch(95.4% .038 75.164);--color-orange-400:oklch(75% .183 55.934);--color-orange-500:oklch(70.5% .213 47.604);--color-orange-600:oklch(64.6% .222 41.116);--color-orange-900:oklch(40.8% .123 38.172);--color-green-100:oklch(96.2% .044 156.743);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-green-600:oklch(62.7% .194 149.214);--color-green-900:oklch(39.3% .095 152.535);--color-cyan-100:oklch(95.6% .045 203.388);--color-cyan-400:oklch(78.9% .154 211.53);--color-cyan-600:oklch(60.9% .126 221.723);--color-cyan-900:oklch(39.8% .07 227.392);--color-blue-50:oklch(97% .014 254.604);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-200:oklch(88.2% .059 254.128);--color-blue-300:oklch(80.9% .105 251.813);--color-blue-400:oklch(70.7% .165 254.624);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-blue-800:oklch(42.4% .199 265.638);--color-blue-900:oklch(37.9% .146 265.522);--color-blue-950:oklch(28.2% .091 267.935);--color-purple-50:oklch(97.7% .014 308.299);--color-purple-100:oklch(94.6% .033 307.174);--color-purple-400:oklch(71.4% .203 305.504);--color-purple-500:oklch(62.7% .265 303.9);--color-purple-600:oklch(55.8% .288 302.321);--color-purple-900:oklch(38.1% .176 304.987);--color-purple-950:oklch(29.1% .149 302.717);--color-pink-50:oklch(97.1% .014 343.198);--color-pink-100:oklch(94.8% .028 342.258);--color-pink-400:oklch(71.8% .202 349.761);--color-pink-600:oklch(59.2% .249 .584);--color-pink-900:oklch(40.8% .153 2.432);--color-slate-50:oklch(98.4% .003 247.858);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-slate-950:oklch(12.9% .042 264.695);--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-2xl:42rem;--container-3xl:48rem;--container-4xl:56rem;--container-5xl:64rem;--container-6xl:72rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height:calc(1.5/1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25/1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5/2.25);--text-5xl:3rem;--text-5xl--line-height:1;--text-6xl:3.75rem;--text-6xl--line-height:1;--text-7xl:4.5rem;--text-7xl--line-height:1;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--radius-md:.375rem;--radius-lg:.5rem;--blur-lg:16px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::-moz-placeholder{opacity:1}::placeholder{opacity:1}@supports (not (-webkit-appearance:-apple-pay-button)) or (contain-intrinsic-size:1px){::-moz-placeholder{color:currentColor}::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::-moz-placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing)*0)}.top-4{top:calc(var(--spacing)*4)}.top-18{top:calc(var(--spacing)*18)}.bottom-0{bottom:calc(var(--spacing)*0)}.left-0{left:calc(var(--spacing)*0)}.z-50{z-index:50}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mx-auto{margin-inline:auto}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-4{margin-top:calc(var(--spacing)*4)}.mb-1{margin-bottom:calc(var(--spacing)*1)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-6{margin-bottom:calc(var(--spacing)*6)}.mb-8{margin-bottom:calc(var(--spacing)*8)}.mb-12{margin-bottom:calc(var(--spacing)*12)}.mb-16{margin-bottom:calc(var(--spacing)*16)}.ml-2{margin-left:calc(var(--spacing)*2)}.ml-4{margin-left:calc(var(--spacing)*4)}.ml-6{margin-left:calc(var(--spacing)*6)}.ml-8{margin-left:calc(var(--spacing)*8)}.ml-12{margin-left:calc(var(--spacing)*12)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.table{display:table}.h-8{height:calc(var(--spacing)*8)}.h-16{height:calc(var(--spacing)*16)}.min-h-screen{min-height:100vh}.w-8{width:calc(var(--spacing)*8)}.w-64{width:calc(var(--spacing)*64)}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-3xl{max-width:var(--container-3xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:calc(var(--spacing)*0)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.cursor-pointer{cursor:pointer}.scroll-mt-32{scroll-margin-top:calc(var(--spacing)*32)}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-6{gap:calc(var(--spacing)*6)}.gap-8{gap:calc(var(--spacing)*8)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*6)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*6)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*8)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*8)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-10>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*10)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*10)*calc(1 - var(--tw-space-y-reverse)))}.self-start{align-self:flex-start}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-blue-200{border-color:var(--color-blue-200)}.border-blue-500{border-color:var(--color-blue-500)}.border-green-500{border-color:var(--color-green-500)}.border-orange-500{border-color:var(--color-orange-500)}.border-purple-500{border-color:var(--color-purple-500)}.border-slate-200{border-color:var(--color-slate-200)}.border-l-blue-500{border-left-color:var(--color-blue-500)}.border-l-green-500{border-left-color:var(--color-green-500)}.border-l-orange-500{border-left-color:var(--color-orange-500)}.border-l-purple-500{border-left-color:var(--color-purple-500)}.bg-blue-50{background-color:var(--color-blue-50)}.bg-blue-100{background-color:var(--color-blue-100)}.bg-cyan-100{background-color:var(--color-cyan-100)}.bg-green-100{background-color:var(--color-green-100)}.bg-orange-100{background-color:var(--color-orange-100)}.bg-pink-100{background-color:var(--color-pink-100)}.bg-purple-100{background-color:var(--color-purple-100)}.bg-slate-50{background-color:var(--color-slate-50)}.bg-slate-100{background-color:var(--color-slate-100)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-white{background-color:var(--color-white)}.bg-linear-to-br{--tw-gradient-position:to bottom right}@supports (background-image:linear-gradient(in lab, red, red)){.bg-linear-to-br{--tw-gradient-position:to bottom right in oklab}}.bg-linear-to-br{background-image:linear-gradient(var(--tw-gradient-stops))}.bg-linear-to-r{--tw-gradient-position:to right}@supports (background-image:linear-gradient(in lab, red, red)){.bg-linear-to-r{--tw-gradient-position:to right in oklab}}.bg-linear-to-r{background-image:linear-gradient(var(--tw-gradient-stops))}.from-blue-50{--tw-gradient-from:var(--color-blue-50);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-blue-600{--tw-gradient-from:var(--color-blue-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.via-purple-50{--tw-gradient-via:var(--color-purple-50);--tw-gradient-via-stops:var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-via)var(--tw-gradient-via-position),var(--tw-gradient-to)var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.via-purple-600{--tw-gradient-via:var(--color-purple-600);--tw-gradient-via-stops:var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-via)var(--tw-gradient-via-position),var(--tw-gradient-to)var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.to-pink-50{--tw-gradient-to:var(--color-pink-50);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-pink-600{--tw-gradient-to:var(--color-pink-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-purple-50{--tw-gradient-to:var(--color-purple-50);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-purple-600{--tw-gradient-to:var(--color-purple-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.mask-\[radial-gradient\(ellipse_at_center\,transparent_20\%\,black\)\]{-webkit-mask-image:radial-gradient(#0000 20%,#000);mask-image:radial-gradient(#0000 20%,#000)}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.p-2{padding:calc(var(--spacing)*2)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-6{padding:calc(var(--spacing)*6)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-5{padding-inline:calc(var(--spacing)*5)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-1{padding-block:calc(var(--spacing)*1)}.py-2{padding-block:calc(var(--spacing)*2)}.py-3{padding-block:calc(var(--spacing)*3)}.py-8{padding-block:calc(var(--spacing)*8)}.py-10{padding-block:calc(var(--spacing)*10)}.py-16{padding-block:calc(var(--spacing)*16)}.py-20{padding-block:calc(var(--spacing)*20)}.py-24{padding-block:calc(var(--spacing)*24)}.pt-2{padding-top:calc(var(--spacing)*2)}.pt-4{padding-top:calc(var(--spacing)*4)}.pt-8{padding-top:calc(var(--spacing)*8)}.pt-18{padding-top:calc(var(--spacing)*18)}.pt-32{padding-top:calc(var(--spacing)*32)}.pb-0{padding-bottom:calc(var(--spacing)*0)}.pb-2{padding-bottom:calc(var(--spacing)*2)}.pb-24{padding-bottom:calc(var(--spacing)*24)}.pl-4{padding-left:calc(var(--spacing)*4)}.pl-5{padding-left:calc(var(--spacing)*5)}.text-center{text-align:center}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-pre-wrap{white-space:pre-wrap}.text-blue-100{color:var(--color-blue-100)}.text-blue-600{color:var(--color-blue-600)}.text-blue-700{color:var(--color-blue-700)}.text-blue-900{color:var(--color-blue-900)}.text-cyan-600{color:var(--color-cyan-600)}.text-green-600{color:var(--color-green-600)}.text-orange-600{color:var(--color-orange-600)}.text-pink-600{color:var(--color-pink-600)}.text-purple-600{color:var(--color-purple-600)}.text-slate-500{color:var(--color-slate-500)}.text-slate-600{color:var(--color-slate-600)}.text-slate-700{color:var(--color-slate-700)}.text-slate-900{color:var(--color-slate-900)}.text-transparent{color:#0000}.text-white{color:var(--color-white)}.opacity-70{opacity:.7}.filter{filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.backdrop-blur-lg{--tw-backdrop-blur:blur(var(--blur-lg));backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (hover:hover){.hover\:bg-blue-50:hover{background-color:var(--color-blue-50)}.hover\:bg-slate-50:hover{background-color:var(--color-slate-50)}.hover\:underline:hover{text-decoration-line:underline}.hover\:shadow-lg:hover{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.hover\:shadow-xl:hover{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a),0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}@media (min-width:40rem){.sm\:flex-row{flex-direction:row}}@media (min-width:48rem){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:px-4{padding-inline:calc(var(--spacing)*4)}.md\:px-5{padding-inline:calc(var(--spacing)*5)}.md\:py-32{padding-block:calc(var(--spacing)*32)}.md\:pt-12{padding-top:calc(var(--spacing)*12)}.md\:text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.md\:text-7xl{font-size:var(--text-7xl);line-height:var(--tw-leading,var(--text-7xl--line-height))}}@media (min-width:64rem){.lg\:block{display:block}.lg\:hidden{display:none}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:pb-8{padding-bottom:calc(var(--spacing)*8)}}@media (prefers-color-scheme:dark){.dark\:border-blue-800{border-color:var(--color-blue-800)}.dark\:border-slate-700{border-color:var(--color-slate-700)}.dark\:bg-blue-900\/30{background-color:#1c398e4d}@supports (color:color-mix(in lab, red, red)){.dark\:bg-blue-900\/30{background-color:color-mix(in oklab,var(--color-blue-900)30%,transparent)}}.dark\:bg-blue-950\/30{background-color:#1624564d}@supports (color:color-mix(in lab, red, red)){.dark\:bg-blue-950\/30{background-color:color-mix(in oklab,var(--color-blue-950)30%,transparent)}}.dark\:bg-cyan-900\/30{background-color:#104e644d}@supports (color:color-mix(in lab, red, red)){.dark\:bg-cyan-900\/30{background-color:color-mix(in oklab,var(--color-cyan-900)30%,transparent)}}.dark\:bg-green-900\/30{background-color:#0d542b4d}@supports (color:color-mix(in lab, red, red)){.dark\:bg-green-900\/30{background-color:color-mix(in oklab,var(--color-green-900)30%,transparent)}}.dark\:bg-orange-900\/30{background-color:#7e2a0c4d}@supports (color:color-mix(in lab, red, red)){.dark\:bg-orange-900\/30{background-color:color-mix(in oklab,var(--color-orange-900)30%,transparent)}}.dark\:bg-pink-900\/30{background-color:#8610434d}@supports (color:color-mix(in lab, red, red)){.dark\:bg-pink-900\/30{background-color:color-mix(in oklab,var(--color-pink-900)30%,transparent)}}.dark\:bg-purple-900\/30{background-color:#59168b4d}@supports (color:color-mix(in lab, red, red)){.dark\:bg-purple-900\/30{background-color:color-mix(in oklab,var(--color-purple-900)30%,transparent)}}.dark\:bg-slate-800{background-color:var(--color-slate-800)}.dark\:bg-slate-900{background-color:var(--color-slate-900)}.dark\:bg-slate-900\/50{background-color:#0f172b80}@supports (color:color-mix(in lab, red, red)){.dark\:bg-slate-900\/50{background-color:color-mix(in oklab,var(--color-slate-900)50%,transparent)}}.dark\:bg-slate-950{background-color:var(--color-slate-950)}.dark\:from-blue-950\/30{--tw-gradient-from:#1624564d}@supports (color:color-mix(in lab, red, red)){.dark\:from-blue-950\/30{--tw-gradient-from:color-mix(in oklab,var(--color-blue-950)30%,transparent)}}.dark\:from-blue-950\/30{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.dark\:from-slate-900{--tw-gradient-from:var(--color-slate-900);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.dark\:via-purple-900\/20{--tw-gradient-via:#59168b33}@supports (color:color-mix(in lab, red, red)){.dark\:via-purple-900\/20{--tw-gradient-via:color-mix(in oklab,var(--color-purple-900)20%,transparent)}}.dark\:via-purple-900\/20{--tw-gradient-via-stops:var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-via)var(--tw-gradient-via-position),var(--tw-gradient-to)var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.dark\:to-blue-900\/20{--tw-gradient-to:#1c398e33}@supports (color:color-mix(in lab, red, red)){.dark\:to-blue-900\/20{--tw-gradient-to:color-mix(in oklab,var(--color-blue-900)20%,transparent)}}.dark\:to-blue-900\/20{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.dark\:to-purple-950\/30{--tw-gradient-to:#3c03664d}@supports (color:color-mix(in lab, red, red)){.dark\:to-purple-950\/30{--tw-gradient-to:color-mix(in oklab,var(--color-purple-950)30%,transparent)}}.dark\:to-purple-950\/30{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.dark\:text-blue-100{color:var(--color-blue-100)}.dark\:text-blue-300{color:var(--color-blue-300)}.dark\:text-blue-400{color:var(--color-blue-400)}.dark\:text-cyan-400{color:var(--color-cyan-400)}.dark\:text-green-400{color:var(--color-green-400)}.dark\:text-orange-400{color:var(--color-orange-400)}.dark\:text-pink-400{color:var(--color-pink-400)}.dark\:text-purple-400{color:var(--color-purple-400)}.dark\:text-slate-300{color:var(--color-slate-300)}.dark\:text-slate-400{color:var(--color-slate-400)}.dark\:text-slate-500{color:var(--color-slate-500)}.dark\:text-white{color:var(--color-white)}@media (hover:hover){.dark\:hover\:bg-slate-800:hover{background-color:var(--color-slate-800)}}}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lastbrain/app",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Framework modulaire Next.js avec CLI et système de modules",
5
5
  "private": false,
6
6
  "type": "module",
@@ -27,7 +27,8 @@
27
27
  "lastbrain": "./dist/cli.js"
28
28
  },
29
29
  "files": [
30
- "dist"
30
+ "dist",
31
+ "src"
31
32
  ],
32
33
  "dependencies": {
33
34
  "@lastbrain/core": "0.1.0",
@@ -47,15 +48,22 @@
47
48
  "next": ">=15.0.0"
48
49
  },
49
50
  "devDependencies": {
51
+ "@heroui/theme": "^2.4.23",
52
+ "@tailwindcss/postcss": "^4.0.0",
50
53
  "@types/fs-extra": "^11.0.4",
51
54
  "@types/inquirer": "^9.0.9",
52
55
  "@types/node": "^20.0.0",
56
+ "autoprefixer": "^10.4.0",
53
57
  "inquirer": "^13.0.1",
58
+ "postcss": "^8.4.0",
59
+ "postcss-cli": "^11.0.0",
60
+ "tailwindcss": "^4.0.0",
54
61
  "typescript": "^5.4.0"
55
62
  },
56
63
  "scripts": {
57
64
  "dev": "tsc -p tsconfig.json --watch",
58
- "build": "tsc -p tsconfig.json && npm run copy:templates && chmod +x dist/cli.js",
65
+ "build": "tsc -p tsconfig.json && npm run build:css && npm run copy:templates && chmod +x dist/cli.js",
66
+ "build:css": "NODE_ENV=production pnpm exec postcss ./src/styles.css -o ./dist/styles.css",
59
67
  "copy:templates": "mkdir -p dist/templates/migrations dist/templates/env.example dist/templates/gitignore && cp src/templates/migrations/* dist/templates/migrations/ 2>/dev/null || true && cp src/templates/env.example/.env.example dist/templates/env.example/ 2>/dev/null || true && cp src/templates/gitignore/.gitignore dist/templates/gitignore/ 2>/dev/null || true",
60
68
  "module:build": "node dist/scripts/module-build.js",
61
69
  "module:create": "node dist/scripts/module-create.js",
@@ -0,0 +1,13 @@
1
+ "use client";
2
+
3
+ import type { PropsWithChildren } from "react";
4
+
5
+ export default function AdminShellLayout({ children }: PropsWithChildren<{}>) {
6
+ return (
7
+ <div className="mx-auto max-w-5xl px-4 py-16">
8
+ <h1 className="text-3xl font-bold">Section Admin</h1>
9
+ <p className="text-slate-600">Gestion avancée des modules.</p>
10
+ {children}
11
+ </div>
12
+ );
13
+ }
@@ -0,0 +1,13 @@
1
+ "use client";
2
+
3
+ import type { PropsWithChildren } from "react";
4
+
5
+ export default function AuthLayout({ children }: PropsWithChildren<{}>) {
6
+ return (
7
+ <div className="mx-auto max-w-5xl px-4 py-16">
8
+ <h1 className="text-3xl font-bold">Section Auth</h1>
9
+ <p className="text-slate-600">Les pages authentifiées regroupées ici.</p>
10
+ {children}
11
+ </div>
12
+ );
13
+ }
@@ -0,0 +1,11 @@
1
+ "use client";
2
+
3
+ export default function PublicPage() {
4
+ return (
5
+ <div className="mx-auto max-w-3xl space-y-4 px-4 py-16 text-center">
6
+ <h1 className="text-3xl font-bold">Bienvenue sur LastBrain</h1>
7
+ <p className="text-slate-600">Cette coquille publique présente la structure par défaut.</p>
8
+ <button className="rounded-full bg-slate-900 px-5 py-2 text-white">Connexion</button>
9
+ </div>
10
+ );
11
+ }
@@ -0,0 +1,5 @@
1
+ "use client";
2
+
3
+ import { RootLayout } from "../layouts/RootLayout.js";
4
+
5
+ export default RootLayout;
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ import { Button } from "@lastbrain/ui";
3
+ import { useRouter } from "next/navigation";
4
+
5
+ export default function NotFound() {
6
+ const router = useRouter();
7
+ return (
8
+ <div className="flex min-h-screen items-center justify-center bg-background">
9
+ <div className="mx-auto max-w-md text-center">
10
+ <h1 className="mb-4 text-6xl font-bold text-foreground">404</h1>
11
+ <h2 className="mb-4 text-2xl font-semibold text-foreground">
12
+ Page non trouvée
13
+ </h2>
14
+ <p className="mb-8 text-muted-foreground">
15
+ La page que vous recherchez n'existe pas ou a été déplacée.
16
+ </p>
17
+ <Button
18
+ onPress={() => {
19
+ router.back();
20
+ }}
21
+ className="inline-flex items-center justify-center rounded-md bg-primary px-6 py-3 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90"
22
+ >
23
+ Retour à l'accueil
24
+ </Button>
25
+ </div>
26
+ </div>
27
+ );
28
+ }
@@ -0,0 +1,24 @@
1
+ "use client";
2
+
3
+ import { supabaseBrowserClient } from "@lastbrain/core";
4
+
5
+ export async function signOut() {
6
+ const { error } = await supabaseBrowserClient.auth.signOut();
7
+ if (error) {
8
+ console.error("Error signing out:", error);
9
+ throw error;
10
+ }
11
+ }
12
+
13
+ export async function signIn(email: string, password: string) {
14
+ const { data, error } = await supabaseBrowserClient.auth.signInWithPassword({
15
+ email,
16
+ password,
17
+ });
18
+
19
+ if (error) {
20
+ throw error;
21
+ }
22
+
23
+ return data;
24
+ }
@@ -0,0 +1,54 @@
1
+ "use client";
2
+
3
+ import { useEffect, useState } from "react";
4
+ import { supabaseBrowserClient } from "@lastbrain/core";
5
+ import type { User } from "@supabase/supabase-js";
6
+
7
+ export function useAuthSession() {
8
+ const [user, setUser] = useState<User | null>(null);
9
+ const [loading, setLoading] = useState(true);
10
+ const [isSuperAdmin, setIsSuperAdmin] = useState(false);
11
+
12
+ useEffect(() => {
13
+ const checkSuperAdmin = async (userId: string) => {
14
+ try {
15
+ const { data, error } = await supabaseBrowserClient.rpc(
16
+ "is_superadmin",
17
+ { user_id: userId }
18
+ );
19
+ if (!error && data) {
20
+ setIsSuperAdmin(data);
21
+ }
22
+ } catch (error) {
23
+ console.error("Error checking superadmin status:", error);
24
+ setIsSuperAdmin(false);
25
+ }
26
+ };
27
+
28
+ // Récupérer la session initiale
29
+ supabaseBrowserClient.auth.getSession().then(({ data: { session } }) => {
30
+ setUser(session?.user ?? null);
31
+ if (session?.user) {
32
+ checkSuperAdmin(session.user.id);
33
+ }
34
+ setLoading(false);
35
+ });
36
+
37
+ // Écouter les changements d'auth
38
+ const {
39
+ data: { subscription },
40
+ } = supabaseBrowserClient.auth.onAuthStateChange((_event, session) => {
41
+ setUser(session?.user ?? null);
42
+ if (session?.user) {
43
+ checkSuperAdmin(session.user.id);
44
+ } else {
45
+ setIsSuperAdmin(false);
46
+ }
47
+ setLoading(false);
48
+ });
49
+
50
+ return () => subscription.unsubscribe();
51
+ }, []);
52
+
53
+ return { user, loading, isSuperAdmin };
54
+ }
package/src/cli.ts ADDED
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from "commander";
4
+ import path from "path";
5
+ import { initApp } from "./scripts/init-app.js";
6
+ import { addModule } from "./scripts/module-add.js";
7
+ import { removeModule } from "./scripts/module-remove.js";
8
+ import { listModules } from "./scripts/module-list.js";
9
+ import { createModule } from "./scripts/module-create.js";
10
+
11
+ const program = new Command();
12
+
13
+ program
14
+ .name("lastbrain")
15
+ .description("CLI pour créer et gérer des applications LastBrain")
16
+ .version("0.1.0");
17
+
18
+ program
19
+ .command("init [directory]")
20
+ .description("Initialise une nouvelle application Next.js LastBrain")
21
+ .option("-f, --force", "Écrase les fichiers existants")
22
+ .option("--no-heroui", "Ne pas utiliser HeroUI (Tailwind CSS uniquement)")
23
+ .option("--with-auth", "Inclure le module d'authentification")
24
+ .option(
25
+ "--no-interactive",
26
+ "Mode non-interactif (skip la sélection des modules)"
27
+ )
28
+ .action(async (directory: string | undefined, options) => {
29
+ try {
30
+ const targetDir = directory
31
+ ? path.resolve(process.cwd(), directory)
32
+ : process.cwd();
33
+
34
+ await initApp({
35
+ force: options.force || false,
36
+ targetDir,
37
+ projectName: directory || path.basename(process.cwd()),
38
+ useHeroUI: options.heroui !== false, // Par défaut true, false si --no-heroui
39
+ withAuth: options.withAuth || false,
40
+ interactive: options.interactive !== false,
41
+ });
42
+ } catch (error) {
43
+ console.error("❌ Erreur lors de l'initialisation:", error);
44
+ process.exit(1);
45
+ }
46
+ });
47
+
48
+ program
49
+ .command("add-module <module>")
50
+ .description("Ajoute un module à l'application")
51
+ .action(async (moduleName: string) => {
52
+ try {
53
+ await addModule(moduleName, process.cwd());
54
+ } catch (error) {
55
+ console.error("❌ Erreur lors de l'ajout du module:", error);
56
+ process.exit(1);
57
+ }
58
+ });
59
+
60
+ program
61
+ .command("remove-module <module>")
62
+ .description("Supprime un module de l'application")
63
+ .action(async (moduleName: string) => {
64
+ try {
65
+ await removeModule(moduleName, process.cwd());
66
+ } catch (error) {
67
+ console.error("❌ Erreur lors de la suppression du module:", error);
68
+ process.exit(1);
69
+ }
70
+ });
71
+
72
+ program
73
+ .command("list-modules")
74
+ .description("Liste les modules disponibles et installés")
75
+ .action(async () => {
76
+ try {
77
+ await listModules(process.cwd());
78
+ } catch (error) {
79
+ console.error("❌ Erreur lors de la liste des modules:", error);
80
+ process.exit(1);
81
+ }
82
+ });
83
+
84
+ program
85
+ .command("create-module")
86
+ .description("Crée un nouveau module dans packages/")
87
+ .action(async () => {
88
+ try {
89
+ await createModule();
90
+ } catch (error) {
91
+ console.error("❌ Erreur lors de la création du module:", error);
92
+ process.exit(1);
93
+ }
94
+ });
95
+
96
+ program.parse();
package/src/index.ts ADDED
@@ -0,0 +1,21 @@
1
+ export {
2
+ AppProviders,
3
+ useAuth,
4
+ useModules,
5
+ useNotifications,
6
+ } from "./layouts/AppProviders.js";
7
+ export { useAuthSession } from "./auth/useAuthSession.js";
8
+ export { signOut, signIn } from "./auth/authHelpers.js";
9
+ export { RootLayout } from "./layouts/RootLayout.js";
10
+ export { PublicLayout } from "./layouts/PublicLayout.js";
11
+ export { AuthLayout } from "./layouts/AuthLayout.js";
12
+ export { AdminLayout } from "./layouts/AdminLayout.js";
13
+ export { getModuleConfigs } from "./modules/module-loader.js";
14
+ // Templates de pages (starter + docs)
15
+
16
+ export { SimpleHomePage } from "./templates/SimpleHomePage.js";
17
+ export { DocPage } from "./templates/DocPage.js";
18
+ export { SimpleDocPage } from "./templates/SimpleDocPage.js";
19
+ export { ModuleGuidePage } from "./templates/ModuleGuidePage.js";
20
+ export { AuthGuidePage } from "./templates/AuthGuidePage.js";
21
+ export { MigrationsGuidePage } from "./templates/MigrationsGuidePage.js";
@@ -0,0 +1,7 @@
1
+ "use client";
2
+
3
+ import type { PropsWithChildren } from "react";
4
+
5
+ export function AdminLayout({ children }: PropsWithChildren<{}>) {
6
+ return <div className="pt-18 px-2 md:px-5">{children}</div>;
7
+ }
@@ -0,0 +1,61 @@
1
+ "use client";
2
+
3
+ import type { PropsWithChildren } from "react";
4
+ import { createContext, useContext, useMemo } from "react";
5
+ import { getModuleConfigs } from "../modules/module-loader.js";
6
+ import { Header, ToastProvider } from "@lastbrain/ui";
7
+ import { useAuthSession } from "../auth/useAuthSession.js";
8
+ import type { User } from "@supabase/supabase-js";
9
+ import { useRouter } from "next/navigation.js";
10
+
11
+ const ModuleContext = createContext(getModuleConfigs());
12
+ const NotificationContext = createContext({ messages: [] as string[] });
13
+ const AuthContext = createContext<{
14
+ user: User | null;
15
+ loading: boolean;
16
+ isSuperAdmin: boolean;
17
+ }>({
18
+ user: null,
19
+ loading: true,
20
+ isSuperAdmin: false,
21
+ });
22
+
23
+ export function useModules() {
24
+ return useContext(ModuleContext);
25
+ }
26
+
27
+ export function useNotifications() {
28
+ return useContext(NotificationContext);
29
+ }
30
+
31
+ export function useAuth() {
32
+ return useContext(AuthContext);
33
+ }
34
+
35
+ export function AppProviders({ children }: PropsWithChildren<{}>) {
36
+ const modules = useMemo(() => getModuleConfigs(), []);
37
+ const notifications = useMemo(() => ({ messages: [] as string[] }), []);
38
+ const { user, loading, isSuperAdmin } = useAuthSession();
39
+ // const router = useRouter();
40
+ const authValue = useMemo(
41
+ () => ({ user, loading, isSuperAdmin }),
42
+ [user, loading, isSuperAdmin]
43
+ );
44
+
45
+ // const handleLogout = async () => {
46
+ // const { signOut } = await import("../auth/authHelpers.js");
47
+ // await signOut();
48
+ // router.push("/auth/signin");
49
+ // };
50
+
51
+ return (
52
+ <AuthContext.Provider value={authValue}>
53
+ <ModuleContext.Provider value={modules}>
54
+ <NotificationContext.Provider value={notifications}>
55
+ {children}
56
+ <ToastProvider placement="top-right" toastOffset={75} />
57
+ </NotificationContext.Provider>
58
+ </ModuleContext.Provider>
59
+ </AuthContext.Provider>
60
+ );
61
+ }
@@ -0,0 +1,7 @@
1
+ "use client";
2
+
3
+ import type { PropsWithChildren } from "react";
4
+
5
+ export function AuthLayout({ children }: PropsWithChildren<{}>) {
6
+ return <div className="pt-18 px-2 md:px-5 ">{children}</div>;
7
+ }
@@ -0,0 +1,7 @@
1
+ "use client";
2
+
3
+ import type { PropsWithChildren } from "react";
4
+
5
+ export function PublicLayout({ children }: PropsWithChildren<{}>) {
6
+ return <section className=" px-4 ">{children}</section>;
7
+ }
@@ -0,0 +1,27 @@
1
+ "use client";
2
+
3
+ import type { PropsWithChildren } from "react";
4
+ import { ThemeProvider } from "next-themes";
5
+ import { AppProviders } from "./AppProviders.js";
6
+
7
+ // Note: L'app Next.js doit importer son propre globals.css dans son layout
8
+ export function RootLayout({ children }: PropsWithChildren<{}>) {
9
+ return (
10
+ <html lang="fr" suppressHydrationWarning>
11
+ <body className="min-h-screen">
12
+ <ThemeProvider
13
+ attribute="class"
14
+ defaultTheme="light"
15
+ enableSystem={false}
16
+ storageKey="lastbrain-theme"
17
+ >
18
+ <AppProviders>
19
+ <div className=" min-h-screen bg-slate-50 text-slate-900 dark:bg-slate-950 dark:text-white">
20
+ {children}
21
+ </div>
22
+ </AppProviders>
23
+ </ThemeProvider>
24
+ </body>
25
+ </html>
26
+ );
27
+ }
@@ -0,0 +1,14 @@
1
+ import type { ModuleBuildConfig } from "@lastbrain/core";
2
+
3
+ // Ce fichier est utilisé côté client par AppProviders
4
+ // Le chargement des modules se fait uniquement au build-time dans module-build.ts
5
+ // Côté client, on exporte un tableau vide car les modules sont déjà compilés
6
+ export const moduleConfigs: ModuleBuildConfig[] = [];
7
+
8
+ export function getModuleConfigs() {
9
+ return moduleConfigs;
10
+ }
11
+
12
+ export function registerModuleConfig(config: ModuleBuildConfig) {
13
+ moduleConfigs.push(config);
14
+ }