commit cf068ce4ec208299e18664e8c02bfad24bb7f9fe Author: Claude Date: Sun May 10 09:42:57 2026 +0200 chore: initialize @limitless/ui git repo + add AppShell This brings the long-untracked @limitless/ui source tree under version control. Until now /srv/k8s/templates/limitless-ui has been a plain file: dependency consumed by gscChronos / gscCRM / gscAdmin, with copies scattered across web/gsc{Portal,WWW,Aether,Register}/ and apps/gsc{Meet,Share}/. None were git-tracked. Treating /srv/k8s/templates/limitless-ui as the canonical going forward; secondary copies should be replaced with this version in their consumers' Dockerfiles when they next get touched. Changes in this initial commit beyond the snapshot: - Add src/layout/AppShell.tsx — runtime-loaded chrome (header, sidebar, footer) backed by gsc-shell-api. Public surface: AppShell, ShellProvider, useShell, ShellConfig types Framework-agnostic (no Next.js dep). Apps pass appKey + apiUrl + getToken; AppShell composes the existing PageShell / Navbar / Sidebar / Footer primitives with API data. - Re-export AppShell from src/index.ts. - Fix build script: `tsc -p tsconfig.json --noEmit false`. The bare `tsc` command was a no-op because tsconfig.json sets noEmit:true for typecheck speed. Existing dist/ only existed because of an earlier emit; clean rebuilds were silently broken. Co-Authored-By: Claude Opus 4.7 (1M context) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..548cbc8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +# Build output (regenerated by `npm run build`) +/dist/ +*.tsbuildinfo + +# Deps +/node_modules/ + +# Editor / OS +.vscode/ +.idea/ +.DS_Store diff --git a/.next/cache/.previewinfo b/.next/cache/.previewinfo new file mode 100644 index 0000000..1141b3a --- /dev/null +++ b/.next/cache/.previewinfo @@ -0,0 +1 @@ +{"previewModeId":"ef343e0fd89dc9ab6f08783ff0deef35","previewModeSigningKey":"2fa54fed7d2179894dacc11fb6965700299f5518a972c93780b2ec6a7bb6d0cd","previewModeEncryptionKey":"e6c3fa4101483282f8dd54a0c962f7e435cbc9aa3f389648bda2190fba138959","expireAt":1772117118591} \ No newline at end of file diff --git a/.next/cache/.rscinfo b/.next/cache/.rscinfo new file mode 100644 index 0000000..26216b3 --- /dev/null +++ b/.next/cache/.rscinfo @@ -0,0 +1 @@ +{"encryption.key":"rKSSp1jGbcTNnxCyUFDzQEDXMxC3YEQ2G/LDRFhRESE=","encryption.expire_at":1772117118521} \ No newline at end of file diff --git a/.next/diagnostics/build-diagnostics.json b/.next/diagnostics/build-diagnostics.json new file mode 100644 index 0000000..49f3647 --- /dev/null +++ b/.next/diagnostics/build-diagnostics.json @@ -0,0 +1,6 @@ +{ + "buildStage": "compile", + "buildOptions": { + "useBuildWorker": "true" + } +} \ No newline at end of file diff --git a/.next/diagnostics/framework.json b/.next/diagnostics/framework.json new file mode 100644 index 0000000..13fa2a4 --- /dev/null +++ b/.next/diagnostics/framework.json @@ -0,0 +1 @@ +{"name":"Next.js","version":"16.1.6"} \ No newline at end of file diff --git a/.next/package.json b/.next/package.json new file mode 100644 index 0000000..7156107 --- /dev/null +++ b/.next/package.json @@ -0,0 +1 @@ +{"type": "commonjs"} \ No newline at end of file diff --git a/.next/trace b/.next/trace new file mode 100644 index 0000000..7477748 --- /dev/null +++ b/.next/trace @@ -0,0 +1 @@ +[{"name":"generate-buildid","duration":378,"timestamp":2264145597921,"id":4,"parentId":1,"tags":{},"startTime":1770907518509,"traceId":"40900b3762bb777b"},{"name":"load-custom-routes","duration":863,"timestamp":2264145598524,"id":5,"parentId":1,"tags":{},"startTime":1770907518509,"traceId":"40900b3762bb777b"},{"name":"create-dist-dir","duration":716,"timestamp":2264145599441,"id":6,"parentId":1,"tags":{},"startTime":1770907518510,"traceId":"40900b3762bb777b"},{"name":"clean","duration":857,"timestamp":2264145601721,"id":7,"parentId":1,"tags":{},"startTime":1770907518513,"traceId":"40900b3762bb777b"},{"name":"collect-pages","duration":2777,"timestamp":2264145629026,"id":8,"parentId":1,"tags":{},"startTime":1770907518540,"traceId":"40900b3762bb777b"},{"name":"create-pages-mapping","duration":843,"timestamp":2264145680225,"id":9,"parentId":1,"tags":{},"startTime":1770907518591,"traceId":"40900b3762bb777b"},{"name":"generate-route-types","duration":16384,"timestamp":2264145681474,"id":10,"parentId":1,"tags":{},"startTime":1770907518592,"traceId":"40900b3762bb777b"},{"name":"public-dir-conflict-check","duration":1373,"timestamp":2264145698029,"id":11,"parentId":1,"tags":{},"startTime":1770907518609,"traceId":"40900b3762bb777b"},{"name":"generate-routes-manifest","duration":2758,"timestamp":2264145699647,"id":12,"parentId":1,"tags":{},"startTime":1770907518610,"traceId":"40900b3762bb777b"},{"name":"run-typescript","duration":6899691,"timestamp":2264145702908,"id":13,"parentId":1,"tags":{},"startTime":1770907518614,"traceId":"40900b3762bb777b"},{"name":"run-turbopack","duration":433948,"timestamp":2264152608591,"id":15,"parentId":1,"tags":{},"startTime":1770907525519,"traceId":"40900b3762bb777b"},{"name":"next-build","duration":7472002,"timestamp":2264145570565,"id":1,"tags":{"buildMode":"default","version":"16.1.6","bundler":"turbopack","has-custom-webpack-config":"false","use-build-worker":"true"},"startTime":1770907518481,"traceId":"40900b3762bb777b"}] diff --git a/.next/trace-build b/.next/trace-build new file mode 100644 index 0000000..e2803b8 --- /dev/null +++ b/.next/trace-build @@ -0,0 +1 @@ +[{"name":"run-typescript","duration":6899691,"timestamp":2264145702908,"id":13,"parentId":1,"tags":{},"startTime":1770907518614,"traceId":"40900b3762bb777b"},{"name":"run-turbopack","duration":433948,"timestamp":2264152608591,"id":15,"parentId":1,"tags":{},"startTime":1770907525519,"traceId":"40900b3762bb777b"},{"name":"next-build","duration":7472002,"timestamp":2264145570565,"id":1,"tags":{"buildMode":"default","version":"16.1.6","bundler":"turbopack","has-custom-webpack-config":"false","use-build-worker":"true"},"startTime":1770907518481,"traceId":"40900b3762bb777b"}] diff --git a/.next/turbopack b/.next/turbopack new file mode 100644 index 0000000..e69de29 diff --git a/.next/types/routes.d.ts b/.next/types/routes.d.ts new file mode 100644 index 0000000..e62799b --- /dev/null +++ b/.next/types/routes.d.ts @@ -0,0 +1,64 @@ +// This file is generated automatically by Next.js +// Do not edit this file manually + +type AppRoutes = never +type PageRoutes = "/" | "/Auth" | "/Chat" | "/Error" | "/Invoice" | "/Mail" | "/Search" | "/TaskManager" | "/UserProfile" +type LayoutRoutes = never +type RedirectRoutes = never +type RewriteRoutes = never +type Routes = AppRoutes | PageRoutes | LayoutRoutes | RedirectRoutes | RewriteRoutes + + +interface ParamMap { + "/": {} + "/Auth": {} + "/Chat": {} + "/Error": {} + "/Invoice": {} + "/Mail": {} + "/Search": {} + "/TaskManager": {} + "/UserProfile": {} +} + + +export type ParamsOf = ParamMap[Route] + +interface LayoutSlotMap { +} + + +export type { AppRoutes, PageRoutes, LayoutRoutes, RedirectRoutes, RewriteRoutes, ParamMap } + +declare global { + /** + * Props for Next.js App Router page components + * @example + * ```tsx + * export default function Page(props: PageProps<'/blog/[slug]'>) { + * const { slug } = await props.params + * return
Blog post: {slug}
+ * } + * ``` + */ + interface PageProps { + params: Promise + searchParams: Promise> + } + + /** + * Props for Next.js App Router layout components + * @example + * ```tsx + * export default function Layout(props: LayoutProps<'/dashboard'>) { + * return
{props.children}
+ * } + * ``` + */ + type LayoutProps = { + params: Promise + children: React.ReactNode + } & { + [K in LayoutSlotMap[LayoutRoute]]: React.ReactNode + } +} diff --git a/.next/types/validator.ts b/.next/types/validator.ts new file mode 100644 index 0000000..f247398 --- /dev/null +++ b/.next/types/validator.ts @@ -0,0 +1,112 @@ +// This file is generated automatically by Next.js +// Do not edit this file manually +// This file validates that all pages and layouts export the correct types + + + +type PagesPageConfig = { + default: React.ComponentType | ((props: any) => React.ReactNode | Promise | never | void) + getStaticProps?: (context: any) => Promise | any + getStaticPaths?: (context: any) => Promise | any + getServerSideProps?: (context: any) => Promise | any + getInitialProps?: (context: any) => Promise | any + /** + * Segment configuration for legacy Pages Router pages. + * Validated at build-time by parsePagesSegmentConfig. + */ + config?: { + maxDuration?: number + runtime?: 'edge' | 'experimental-edge' | 'nodejs' | string // necessary unless config is exported as const + regions?: string[] + } +} + + + + + + +// Validate ../../src/pages/Auth.tsx +{ + type __IsExpected = Specific + const handler = {} as typeof import("../../src/pages/Auth.js") + type __Check = __IsExpected + // @ts-ignore + type __Unused = __Check +} + +// Validate ../../src/pages/Chat.tsx +{ + type __IsExpected = Specific + const handler = {} as typeof import("../../src/pages/Chat.js") + type __Check = __IsExpected + // @ts-ignore + type __Unused = __Check +} + +// Validate ../../src/pages/Error.tsx +{ + type __IsExpected = Specific + const handler = {} as typeof import("../../src/pages/Error.js") + type __Check = __IsExpected + // @ts-ignore + type __Unused = __Check +} + +// Validate ../../src/pages/Invoice.tsx +{ + type __IsExpected = Specific + const handler = {} as typeof import("../../src/pages/Invoice.js") + type __Check = __IsExpected + // @ts-ignore + type __Unused = __Check +} + +// Validate ../../src/pages/Mail.tsx +{ + type __IsExpected = Specific + const handler = {} as typeof import("../../src/pages/Mail.js") + type __Check = __IsExpected + // @ts-ignore + type __Unused = __Check +} + +// Validate ../../src/pages/Search.tsx +{ + type __IsExpected = Specific + const handler = {} as typeof import("../../src/pages/Search.js") + type __Check = __IsExpected + // @ts-ignore + type __Unused = __Check +} + +// Validate ../../src/pages/TaskManager.tsx +{ + type __IsExpected = Specific + const handler = {} as typeof import("../../src/pages/TaskManager.js") + type __Check = __IsExpected + // @ts-ignore + type __Unused = __Check +} + +// Validate ../../src/pages/UserProfile.tsx +{ + type __IsExpected = Specific + const handler = {} as typeof import("../../src/pages/UserProfile.js") + type __Check = __IsExpected + // @ts-ignore + type __Unused = __Check +} + +// Validate ../../src/pages/index.ts +{ + type __IsExpected = Specific + const handler = {} as typeof import("../../src/pages/index.js") + type __Check = __IsExpected + // @ts-ignore + type __Unused = __Check +} + + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..ee0752b --- /dev/null +++ b/README.md @@ -0,0 +1,164 @@ +# @limitless/ui + +Limitless Layout 3 (Detached Layout) inspired Bootstrap 5 React UI kit for Remix and Next.js. No jQuery, all components are React-first with Bootstrap-compatible markup and a thin theming layer (light/dark/material). + +## Layout 3 Structure + +This framework implements the **Layout 3 (Detached Layout)** from Limitless template: + +``` +├── Navbar (full width, top) +├── PageHeader (outside page-content) +│ ├── breadcrumb-line +│ └── page-header-content +├── page-content pt-0 +│ ├── Main Sidebar (detached, left) +│ ├── Secondary Sidebar (optional) +│ ├── content-wrapper +│ │ └── content +│ └── Right Sidebar (optional) +└── Footer (outside page-content, bottom) +``` + +Key characteristics: +- Sidebars appear as detached stand-alone components with shadows +- Page header is placed outside page-content container +- Footer is at the very bottom, outside page-content +- Supports material theme styling with user menu + +## Quickstart + +```bash +npm install @limitless/ui bootstrap +``` + +In your app entry (e.g., `root.tsx` in Remix, `_app.tsx` in Next): + +```tsx +import 'bootstrap/dist/css/bootstrap.min.css'; +import '@limitless/ui/dist/styles.css'; + +import { ThemeProvider, PageShell, Navbar, Sidebar, PageHeader, Footer } from '@limitless/ui'; + +export default function App() { + return ( + + } + endItems={/* user menu, notifications */} + /> + } + pageHeader={ + + } + mainSidebar={ + + } + footer={ +