@olwiba/ui 0.2.25 → 0.2.27

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 (203) hide show
  1. package/content/docs/app/app-shell.mdx +71 -0
  2. package/content/docs/app/auth-section.mdx +73 -0
  3. package/content/docs/app/billing-panel.mdx +38 -0
  4. package/content/docs/app/empty-state.mdx +47 -0
  5. package/content/docs/app/error-page.mdx +31 -0
  6. package/content/docs/app/index.mdx +13 -0
  7. package/content/docs/app/meta.json +4 -0
  8. package/content/docs/app/onboarding-wizard.mdx +41 -0
  9. package/content/docs/app/settings-section.mdx +37 -0
  10. package/content/docs/app/team-members-panel.mdx +35 -0
  11. package/content/docs/app/update-banner.mdx +43 -0
  12. package/content/docs/components/activity-feed.mdx +42 -0
  13. package/content/docs/components/chart.mdx +47 -0
  14. package/content/docs/components/command-menu.mdx +41 -0
  15. package/content/docs/components/confirm-dialog.mdx +26 -0
  16. package/content/docs/components/context-menu.mdx +26 -0
  17. package/content/docs/components/data-table.mdx +40 -0
  18. package/content/docs/components/dock.mdx +26 -0
  19. package/content/docs/components/feature-card.mdx +26 -0
  20. package/content/docs/components/file-upload.mdx +35 -0
  21. package/content/docs/components/full-page-spinner.mdx +44 -0
  22. package/content/docs/components/glass-card.mdx +26 -0
  23. package/content/docs/components/image-card.mdx +26 -0
  24. package/content/docs/components/index.mdx +49 -0
  25. package/content/docs/components/load-more.mdx +34 -0
  26. package/content/docs/components/meta.json +35 -0
  27. package/content/docs/components/notifications-popover.mdx +34 -0
  28. package/content/docs/components/notify.mdx +40 -0
  29. package/content/docs/components/olwiba-ui-context.mdx +69 -0
  30. package/content/docs/components/page-header.mdx +42 -0
  31. package/content/docs/components/pricing-card.mdx +26 -0
  32. package/content/docs/components/register-hotkeys.mdx +50 -0
  33. package/content/docs/components/root-error-fallback.mdx +39 -0
  34. package/content/docs/components/spotlight.mdx +26 -0
  35. package/content/docs/components/stat-card.mdx +26 -0
  36. package/content/docs/components/suspensed.mdx +42 -0
  37. package/content/docs/components/testimonial-card.mdx +26 -0
  38. package/content/docs/components/theme-color-updater.mdx +40 -0
  39. package/content/docs/components/theme-switch-minimal.mdx +32 -0
  40. package/content/docs/components/version-banner.mdx +44 -0
  41. package/content/docs/email/action-email.mdx +62 -0
  42. package/content/docs/email/email-layout.mdx +58 -0
  43. package/content/docs/email/email-link-fallback.mdx +46 -0
  44. package/content/docs/email/index.mdx +32 -0
  45. package/content/docs/email/meta.json +10 -0
  46. package/content/docs/email/notice-email.mdx +51 -0
  47. package/content/docs/hooks/index.mdx +21 -0
  48. package/content/docs/hooks/meta.json +16 -0
  49. package/content/docs/hooks/use-confirm.mdx +81 -0
  50. package/content/docs/hooks/use-controlled-open.mdx +53 -0
  51. package/content/docs/hooks/use-copy-to-clipboard.mdx +26 -0
  52. package/content/docs/hooks/use-debounce.mdx +26 -0
  53. package/content/docs/hooks/use-intersection-observer.mdx +26 -0
  54. package/content/docs/hooks/use-local-storage.mdx +26 -0
  55. package/content/docs/hooks/use-media-query.mdx +26 -0
  56. package/content/docs/hooks/use-mounted.mdx +39 -0
  57. package/content/docs/hooks/use-pagination.mdx +26 -0
  58. package/content/docs/hooks/use-scrolled-past.mdx +44 -0
  59. package/content/docs/index.mdx +68 -0
  60. package/content/docs/marketing/contact-section.mdx +16 -0
  61. package/content/docs/marketing/cta-section.mdx +31 -0
  62. package/content/docs/marketing/faq-section.mdx +16 -0
  63. package/content/docs/marketing/features-section.mdx +23 -0
  64. package/content/docs/marketing/footer.mdx +16 -0
  65. package/content/docs/marketing/hero-section.mdx +16 -0
  66. package/content/docs/marketing/index.mdx +22 -0
  67. package/content/docs/marketing/meta.json +20 -0
  68. package/content/docs/marketing/navbar.mdx +16 -0
  69. package/content/docs/marketing/newsletter-section.mdx +16 -0
  70. package/content/docs/marketing/post-list.mdx +32 -0
  71. package/content/docs/marketing/pricing-section.mdx +16 -0
  72. package/content/docs/marketing/stats-section.mdx +16 -0
  73. package/content/docs/marketing/steps-section.mdx +60 -0
  74. package/content/docs/marketing/team-section.mdx +16 -0
  75. package/content/docs/marketing/testimonials-section.mdx +16 -0
  76. package/content/docs/mechanics/carousel.mdx +42 -0
  77. package/content/docs/mechanics/index.mdx +11 -0
  78. package/content/docs/mechanics/meta.json +4 -0
  79. package/content/docs/mechanics/sortable.mdx +44 -0
  80. package/content/docs/meta.json +4 -0
  81. package/content/docs/motion/animated-swap.mdx +75 -0
  82. package/content/docs/motion/count-up.mdx +31 -0
  83. package/content/docs/motion/fade-in.mdx +34 -0
  84. package/content/docs/motion/index.mdx +12 -0
  85. package/content/docs/motion/meta.json +4 -0
  86. package/content/docs/motion/page-transition.mdx +29 -0
  87. package/content/docs/motion/stagger-children.mdx +31 -0
  88. package/content/docs/overlays/index.mdx +9 -0
  89. package/content/docs/overlays/meta.json +4 -0
  90. package/content/docs/overlays/overlay.mdx +60 -0
  91. package/content/docs/overlays/underlay.mdx +56 -0
  92. package/dist/email/index.d.ts +8 -1
  93. package/dist/email/index.js +3 -3
  94. package/dist/email/index.js.map +1 -1
  95. package/docs-manifest.json +253 -0
  96. package/package.json +18 -9
  97. package/site/demos/action-email.tsx +6 -0
  98. package/site/demos/activity-feed.tsx +42 -0
  99. package/site/demos/animated-swap.tsx +42 -0
  100. package/site/demos/app-shell.tsx +47 -0
  101. package/site/demos/app-ui-page.tsx +9 -0
  102. package/site/demos/application-sidebar-block.tsx +9 -0
  103. package/site/demos/auth-section.tsx +15 -0
  104. package/site/demos/auth-split-block.tsx +9 -0
  105. package/site/demos/billing-page.tsx +157 -0
  106. package/site/demos/billing-panel.tsx +26 -0
  107. package/site/demos/carousel.tsx +34 -0
  108. package/site/demos/chart.tsx +55 -0
  109. package/site/demos/command-menu.tsx +39 -0
  110. package/site/demos/confirm-dialog.tsx +27 -0
  111. package/site/demos/contact-form-block.tsx +3 -0
  112. package/site/demos/contact-section.tsx +2 -0
  113. package/site/demos/context-menu.tsx +30 -0
  114. package/site/demos/count-up.tsx +23 -0
  115. package/site/demos/cta-section.tsx +6 -0
  116. package/site/demos/dashboard-overview-block.tsx +9 -0
  117. package/site/demos/dashboard-shell-block.tsx +10 -0
  118. package/site/demos/data-table.tsx +47 -0
  119. package/site/demos/demo-brand.tsx +23 -0
  120. package/site/demos/dock.tsx +20 -0
  121. package/site/demos/document-sidebar-block.tsx +9 -0
  122. package/site/demos/email-examples.tsx +58 -0
  123. package/site/demos/email-frame.tsx +50 -0
  124. package/site/demos/email-layout.tsx +6 -0
  125. package/site/demos/email-link-fallback.tsx +6 -0
  126. package/site/demos/email-previews.generated.ts +11 -0
  127. package/site/demos/empty-state-block.tsx +3 -0
  128. package/site/demos/empty-state.tsx +23 -0
  129. package/site/demos/error-page.tsx +5 -0
  130. package/site/demos/fade-in.tsx +18 -0
  131. package/site/demos/faq-section.tsx +6 -0
  132. package/site/demos/feature-card.tsx +13 -0
  133. package/site/demos/features-section.tsx +6 -0
  134. package/site/demos/file-upload.tsx +16 -0
  135. package/site/demos/footer.tsx +42 -0
  136. package/site/demos/full-page-spinner.tsx +9 -0
  137. package/site/demos/glass-card.tsx +14 -0
  138. package/site/demos/glow-effect.tsx +3 -0
  139. package/site/demos/gradient-background.tsx +3 -0
  140. package/site/demos/grid-pattern.tsx +3 -0
  141. package/site/demos/hero-section.tsx +6 -0
  142. package/site/demos/image-card.tsx +17 -0
  143. package/site/demos/login-block.tsx +9 -0
  144. package/site/demos/marketing-cta-block.tsx +3 -0
  145. package/site/demos/marketing-demo-data.tsx +114 -0
  146. package/site/demos/marketing-faq-block.tsx +3 -0
  147. package/site/demos/marketing-features-block.tsx +3 -0
  148. package/site/demos/marketing-footer-block.tsx +3 -0
  149. package/site/demos/marketing-hero-block.tsx +10 -0
  150. package/site/demos/marketing-nav-block.tsx +3 -0
  151. package/site/demos/marketing-newsletter-block.tsx +3 -0
  152. package/site/demos/marketing-page.tsx +52 -0
  153. package/site/demos/marketing-pricing-block.tsx +3 -0
  154. package/site/demos/marketing-stats-block.tsx +3 -0
  155. package/site/demos/marketing-team-block.tsx +3 -0
  156. package/site/demos/marketing-testimonials-block.tsx +3 -0
  157. package/site/demos/navbar.tsx +32 -0
  158. package/site/demos/newsletter-section.tsx +2 -0
  159. package/site/demos/noise-overlay.tsx +3 -0
  160. package/site/demos/not-found-block.tsx +3 -0
  161. package/site/demos/notice-email.tsx +6 -0
  162. package/site/demos/notifications-popover.tsx +27 -0
  163. package/site/demos/notify.tsx +44 -0
  164. package/site/demos/olwiba-ui-context.tsx +51 -0
  165. package/site/demos/onboarding-block.tsx +3 -0
  166. package/site/demos/onboarding-wizard.tsx +43 -0
  167. package/site/demos/overlay.tsx +72 -0
  168. package/site/demos/page-header.tsx +15 -0
  169. package/site/demos/page-transition.tsx +34 -0
  170. package/site/demos/post-list.tsx +24 -0
  171. package/site/demos/pricing-card.tsx +27 -0
  172. package/site/demos/pricing-section.tsx +6 -0
  173. package/site/demos/register-hotkeys.tsx +39 -0
  174. package/site/demos/root-error-fallback.tsx +28 -0
  175. package/site/demos/settings-layout-block.tsx +3 -0
  176. package/site/demos/settings-section.tsx +22 -0
  177. package/site/demos/sign-in-page.tsx +10 -0
  178. package/site/demos/sortable.tsx +30 -0
  179. package/site/demos/spotlight.tsx +29 -0
  180. package/site/demos/stagger-children.tsx +16 -0
  181. package/site/demos/stat-card.tsx +12 -0
  182. package/site/demos/stats-section.tsx +6 -0
  183. package/site/demos/steps-section.tsx +66 -0
  184. package/site/demos/suspensed.tsx +31 -0
  185. package/site/demos/team-members-panel.tsx +26 -0
  186. package/site/demos/team-section.tsx +2 -0
  187. package/site/demos/testimonial-card.tsx +17 -0
  188. package/site/demos/testimonials-section.tsx +6 -0
  189. package/site/demos/theme-color-updater.tsx +32 -0
  190. package/site/demos/theme-switch-minimal.tsx +10 -0
  191. package/site/demos/underlay.tsx +74 -0
  192. package/site/demos/update-banner.tsx +31 -0
  193. package/site/demos/use-copy-to-clipboard.tsx +21 -0
  194. package/site/demos/use-debounce.tsx +25 -0
  195. package/site/demos/use-intersection-observer.tsx +32 -0
  196. package/site/demos/use-local-storage.tsx +22 -0
  197. package/site/demos/use-media-query.tsx +31 -0
  198. package/site/demos/use-pagination.tsx +31 -0
  199. package/site/demos/user-profile-block.tsx +3 -0
  200. package/site/demos/version-banner.tsx +27 -0
  201. package/site/lib/sandboxes.ts +1647 -0
  202. package/src/email/EmailLinkFallback.tsx +7 -1
  203. package/src/email/index.ts +3 -0
@@ -0,0 +1,71 @@
1
+ ---
2
+ title: AppShell
3
+ description: Full-page sidebar shell with collapsible nav, user menu, and header. Pass your nav items, brand, and user; get a consistent shell across every route.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="app-shell" shellPreview />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { AppShell } from "@olwiba/ui";
22
+ import { LayoutDashboard, Plus, UserRound } from "lucide-react";
23
+ import { Link } from "your-router"; // TanStack, Next.js, etc.
24
+
25
+ export function AppLayout({ children }) {
26
+ return (
27
+ <AppShell
28
+ brand={{ name: "My App", href: "/" }}
29
+ navItems={[
30
+ { icon: LayoutDashboard, label: "Dashboard", href: "/dashboard", isActive: true },
31
+ ]}
32
+ action={{ icon: Plus, label: "New item", href: "/new" }}
33
+ user={{
34
+ email: "user@example.com",
35
+ plan: "free",
36
+ avatarFallback: <UserRound aria-hidden className="size-5" />,
37
+ onSignOut: () => signOut(),
38
+ }}
39
+ pageTitle="Dashboard"
40
+ renderLink={({ href, children }) => <Link to={href}>{children}</Link>}
41
+ >
42
+ {children}
43
+ </AppShell>
44
+ );
45
+ }
46
+ ```
47
+
48
+ Use `sidebarPosition="contained"` in docs sandboxes or embedded previews so the shell fits its parent rather than filling the viewport:
49
+
50
+ ```tsx
51
+ <AppShell sidebarPosition="contained" />
52
+ ```
53
+
54
+ ## API Reference
55
+
56
+ <APIReference name="AppShell" props={[
57
+ { name: "brand", type: "AppShellBrand", description: "App name, logo, and href for the sidebar header." },
58
+ { name: "navItems", type: "AppNavItem[]", description: "Primary navigation links rendered in the sidebar." },
59
+ { name: "action", type: "AppShellAction", description: "CTA button above nav items (e.g. New item, Quick create)." },
60
+ { name: "user", type: "AppShellUser", description: "User info and callbacks shown in the sidebar footer dropdown." },
61
+ { name: "pageTitle", type: "string", default: '"Dashboard"', description: "Title shown in the top header bar." },
62
+ { name: "headerStart", type: "ReactNode | ((controls: AppShellHeaderControls) => ReactNode)", description: "Header-start content. Its render form can expand the shell without importing the private sidebar context." },
63
+ { name: "sidebarFooterStart", type: "ReactNode", description: "Product chrome rendered above the user menu in the sidebar footer." },
64
+ { name: "sidebarContentKey", type: "string", description: "Remount key for animated sidebar identity or navigation-mode changes." },
65
+ { name: "sidebarContentClassName", type: "string", description: "Classes applied to the sidebar header, content, and footer." },
66
+ { name: "renderLink", type: "AppShellRenderLink", description: "Override link rendering for SPA navigation. Default: native <a>." },
67
+ { name: "collapsible", type: '"icon" | "offcanvas" | "none"', default: '"icon"', description: 'Sidebar collapse behaviour.' },
68
+ { name: "sidebarPosition", type: '"viewport" | "contained"', default: '"viewport"', description: 'Use "contained" for docs sandboxes or embedded previews; "viewport" for full-page app shells.' },
69
+ { name: "side", type: '"left" | "right"', default: '"left"', description: "Which side the sidebar sits on." },
70
+ { name: "children", type: "ReactNode", description: "Page content rendered in the main area." },
71
+ ]} />
@@ -0,0 +1,73 @@
1
+ ---
2
+ title: AuthSection
3
+ description: Sign in, sign up, forgot/reset password, and code verification — one form, five modes.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="auth-section" shellPreview />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { AuthSection } from "@olwiba/ui";
22
+
23
+ // Centered (default)
24
+ <AuthSection
25
+ onSubmit={(e) => { e.preventDefault(); signIn() }}
26
+ onSso={() => signInWithSso()}
27
+ signUpHref="/register"
28
+ forgotPasswordHref="/forgot-password"
29
+ />
30
+
31
+ // Split layout with decorative panel
32
+ <AuthSection
33
+ layout="split"
34
+ onSubmit={(e) => { e.preventDefault(); signIn() }}
35
+ />
36
+
37
+ // Custom form
38
+ <AuthSection layout="split">
39
+ <MyCustomForm />
40
+ </AuthSection>
41
+
42
+ // Forgot password
43
+ <AuthSection mode="forgot-password" signInHref="/sign-in" onSubmit={handleForgotPassword} success={sent ? "Check your inbox for a reset link." : undefined} />
44
+
45
+ // Reset password (reached via the emailed link)
46
+ <AuthSection mode="reset-password" signInHref="/sign-in" onSubmit={handleResetPassword} />
47
+
48
+ // Verify code (email verification or 2FA)
49
+ <AuthSection mode="verify" destination={email} onSubmit={handleVerify} onResend={handleResend} />
50
+ ```
51
+
52
+ Every mode shares the same `AuthSection`/`DefaultForm` — swap `mode` rather than reaching for a separate screen component per auth step.
53
+
54
+ ## API Reference
55
+
56
+ <APIReference name="AuthSection" props={[
57
+ { name: "mode", type: '"signin" | "signup" | "forgot-password" | "reset-password" | "verify"', default: '"signin"', description: "Controls form title, fields, and footer text." },
58
+ { name: "layout", type: '"centered" | "split"', default: '"centered"', description: "Visual layout of the auth screen." },
59
+ { name: "children", type: "ReactNode", description: "Custom form content. Defaults to the built-in form." },
60
+ { name: "panel", type: "ReactNode", description: "Split layout only — custom content for the left decorative panel." },
61
+ { name: "onSubmit", type: "(e: FormEvent) => void", description: "Form submit handler." },
62
+ { name: "onSso", type: "() => void", description: "Shows a SSO button when provided (signin only)." },
63
+ { name: "signUpHref", type: "string", default: '"#"', description: "Link for the sign-up prompt (signin)." },
64
+ { name: "signInHref", type: "string", default: '"#"', description: "Link back to sign-in (signup / forgot-password / reset-password / verify)." },
65
+ { name: "forgotPasswordHref", type: "string", default: '"#"', description: "Link for the forgot password prompt (signin)." },
66
+ { name: "onResend", type: "() => void", description: "Re-sends the one-time code (verify)." },
67
+ { name: "destination", type: "string", description: "Address the code was sent to (verify)." },
68
+ { name: "codeLength", type: "number", default: "6", description: "Number of digits in the code (verify)." },
69
+ { name: "brand", type: "ReactNode", description: "Logo or brand mark shown above the form title." },
70
+ { name: "error", type: "string", description: "Error message shown below the form fields." },
71
+ { name: "success", type: "string", description: "Positive confirmation message shown below the form fields." },
72
+ { name: "className", type: "string", description: "Class applied to the outer wrapper." },
73
+ ]} />
@@ -0,0 +1,38 @@
1
+ ---
2
+ title: BillingPanel
3
+ description: In-app billing summary — current plan, usage, payment method, and invoice history.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="billing-panel" />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { BillingPanel } from "@olwiba/ui";
22
+
23
+ <BillingPanel
24
+ planName="Pro"
25
+ planPrice="$29/mo"
26
+ renewalDate="March 12, 2026"
27
+ usage={[{ label: "Seats", used: 6, limit: 10 }]}
28
+ paymentMethod={{ brand: "Visa", last4: "4242", expiry: "08/27" }}
29
+ invoices={invoices}
30
+ onManagePlan={() => openPlanDialog()}
31
+ />
32
+ ```
33
+
34
+ This is the account-side billing view — for marketing plan comparisons, use `PricingSection`/`UpgradePrompt` instead.
35
+
36
+ ## API Reference
37
+
38
+ <APIReference name="BillingPanel" props={[]} />
@@ -0,0 +1,47 @@
1
+ ---
2
+ title: EmptyState
3
+ description: Zero-content placeholder with icon, heading, description, and an optional CTA button.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <ComponentPreview name="empty-state" />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { EmptyState } from "@olwiba/ui";
22
+ import { FolderOpen } from "lucide-react";
23
+
24
+ <EmptyState
25
+ icon={FolderOpen}
26
+ title="No projects yet"
27
+ description="Create your first project to get started."
28
+ variant="card"
29
+ action={<Button>New project</Button>}
30
+ secondaryAction={<Button variant="ghost">Learn more</Button>}
31
+ />
32
+ ```
33
+
34
+ ## API Reference
35
+
36
+ <APIReference name="EmptyState" props={[
37
+ { name: "icon", type: "LucideIcon", description: "Icon rendered above the heading." },
38
+ { name: "title", type: "string", description: "Primary heading." },
39
+ { name: "description", type: "ReactNode", description: "Supporting content below the heading." },
40
+ { name: "eyebrow", type: "ReactNode", description: "Optional compact label above the heading." },
41
+ { name: "action", type: "ReactNode", description: "Primary action." },
42
+ { name: "secondaryAction", type: "ReactNode", description: "Secondary action rendered alongside the primary action." },
43
+ { name: "variant", type: '"plain" | "card"', default: '"plain"', description: "Use card for route-level product empty states." },
44
+ { name: "compact", type: "boolean", default: "false", description: "Reduces the card presentation's height and padding." },
45
+ { name: "fill", type: "boolean", default: "false", description: "Fills a flex-sized parent." },
46
+ { name: "className", type: "string", description: "Class applied to the root element." },
47
+ ]} />
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: ErrorPage
3
+ description: Full-page 404 / error fallback with navigation actions.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <ComponentPreview name="error-page" />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { ErrorPage } from "@olwiba/ui";
22
+
23
+ // In a TanStack Router not-found route
24
+ export const Route = createFileRoute("/404")({
25
+ component: () => <ErrorPage />,
26
+ });
27
+ ```
28
+
29
+ ## API Reference
30
+
31
+ `ErrorPage` takes no props — it renders a self-contained 404 screen with a Go back and Take me home action.
@@ -0,0 +1,13 @@
1
+ ---
2
+ title: App UI
3
+ description: Shells and screens for application UIs — sidebar shell, auth, empty states, and error pages.
4
+ ---
5
+
6
+ App UI components are the structural building blocks of a product interface. They're configured once and used across every route.
7
+
8
+ | Component | Description |
9
+ |-----------|-------------|
10
+ | `AppShell` | Full-page sidebar shell with nav, user menu, and header |
11
+ | `AuthSection` | Sign-in screen — centered or split layout |
12
+ | `EmptyState` | Zero-content placeholder with icon, copy, and CTA |
13
+ | `ErrorPage` | 404 / error fallback page |
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "App UI",
3
+ "pages": ["index", "app-shell", "auth-section", "empty-state", "error-page", "settings-section", "team-members-panel", "billing-panel", "onboarding-wizard", "update-banner"]
4
+ }
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: OnboardingWizard
3
+ description: Stateful multi-step onboarding flow.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="onboarding-wizard" />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { OnboardingWizard } from "@olwiba/ui";
22
+
23
+ <OnboardingWizard
24
+ onComplete={() => router.push("/dashboard")}
25
+ steps={[
26
+ { id: "welcome", title: "Welcome", content: <WelcomeStep /> },
27
+ {
28
+ id: "workspace",
29
+ title: "Name your workspace",
30
+ content: <WorkspaceNameStep />,
31
+ onNext: () => (name.trim() ? true : "Give your workspace a name to continue."),
32
+ },
33
+ ]}
34
+ />
35
+ ```
36
+
37
+ One component driven by a `steps` array — swap the array to reshape the flow rather than hand-building a new wizard per feature. `onNext` can return `false` or an error string to block advancing.
38
+
39
+ ## API Reference
40
+
41
+ <APIReference name="OnboardingWizard" props={[]} />
@@ -0,0 +1,37 @@
1
+ ---
2
+ title: SettingsSection
3
+ description: One title/description/content row for building a settings page.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="settings-section" />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { SettingsSection } from "@olwiba/ui";
22
+
23
+ <div className="divide-y divide-border">
24
+ <SettingsSection title="Profile" description="This appears on your public profile.">
25
+ <MyProfileForm />
26
+ </SettingsSection>
27
+ <SettingsSection title="Delete workspace" description="This cannot be undone." danger>
28
+ <Button variant="destructive">Delete workspace</Button>
29
+ </SettingsSection>
30
+ </div>
31
+ ```
32
+
33
+ Stack a few inside a `divide-y` wrapper to build a full settings page — one block reused per row, rather than a bespoke layout each time.
34
+
35
+ ## API Reference
36
+
37
+ <APIReference name="SettingsSection" props={[]} />
@@ -0,0 +1,35 @@
1
+ ---
2
+ title: TeamMembersPanel
3
+ description: Member list with role management and an invite dialog.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="team-members-panel" />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { TeamMembersPanel } from "@olwiba/ui";
22
+
23
+ <TeamMembersPanel
24
+ members={members}
25
+ onInvite={(email, role) => inviteMember(email, role)}
26
+ onRoleChange={(id, role) => updateRole(id, role)}
27
+ onRemove={(id) => removeMember(id)}
28
+ />
29
+ ```
30
+
31
+ Built on top of `DataTable` — pass `roles` to customize the options offered in the invite dialog and per-row role menu.
32
+
33
+ ## API Reference
34
+
35
+ <APIReference name="TeamMembersPanel" props={[]} />
@@ -0,0 +1,43 @@
1
+ ---
2
+ title: UpdateBanner
3
+ description: Slide-in banner that tells users a new deploy shipped and their tab is stale — poll a version endpoint, offer one-click refresh.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="update-banner" />
11
+
12
+ ## Usage
13
+
14
+ Bake a build version into the client bundle (e.g. vite `define` with the git SHA), expose the same value from a `/api/version` endpoint, and mount the banner once in the root layout:
15
+
16
+ ```tsx
17
+ import { UpdateBanner } from "@olwiba/ui";
18
+
19
+ declare const __BUILD_VERSION__: string;
20
+
21
+ <UpdateBanner
22
+ currentVersion={__BUILD_VERSION__}
23
+ fetchVersion={async () => {
24
+ const res = await fetch("/api/version", { cache: "no-store" });
25
+ return res.json();
26
+ }}
27
+ />
28
+ ```
29
+
30
+ When a new deploy goes live, open tabs still run the old bundle; the next poll sees a different server version and the banner slides in. Refresh defaults to a full reload — pass `onRefresh` to hook a celebration or custom flow first.
31
+
32
+ ## API Reference
33
+
34
+ <APIReference name="UpdateBanner" props={[
35
+ { name: "currentVersion", type: "string", description: "Version baked into the running bundle at build time." },
36
+ { name: "fetchVersion", type: "() => Promise<{ version: string }>", description: "Fetch the deployed version — the host app wires its own endpoint." },
37
+ { name: "intervalMs", type: "number", default: "300000", description: "Poll interval in ms." },
38
+ { name: "forceShow", type: "boolean", default: "false", description: "Force the banner visible (demos/testing)." },
39
+ { name: "onRefresh", type: "() => void", description: "Refresh click handler; defaults to window.location.reload()." },
40
+ { name: "message", type: "ReactNode", description: "Banner copy." },
41
+ { name: "buttonLabel", type: "string", default: '"Refresh now"', description: "Refresh button label." },
42
+ { name: "className", type: "string", description: "Class applied to the banner card." },
43
+ ]} />
@@ -0,0 +1,42 @@
1
+ ---
2
+ title: ActivityFeed
3
+ description: Vertical activity timeline with avatar or icon markers connected by a rail.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="activity-feed" />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { ActivityFeed } from "@olwiba/ui";
22
+
23
+ <ActivityFeed
24
+ items={[
25
+ {
26
+ id: "1",
27
+ title: <><b>Ana</b> deployed to production</>,
28
+ description: "v0.1.16 · 12 commits",
29
+ timestamp: "2h ago",
30
+ avatar: "/avatars/ana.png",
31
+ initials: "AS",
32
+ },
33
+ { id: "2", title: "Subscription renewed", timestamp: "Yesterday", icon: <CreditCard /> },
34
+ ]}
35
+ />
36
+ ```
37
+
38
+ Presentation-only: pass pre-formatted timestamps and rich `title` nodes from your own data layer. Items with `avatar` render an avatar marker; otherwise `icon` (or a default) renders in a bordered circle.
39
+
40
+ ## API Reference
41
+
42
+ <APIReference name="ActivityFeed" props={[]} />
@@ -0,0 +1,47 @@
1
+ ---
2
+ title: Chart
3
+ description: Theme-aware line, area, bar, and donut charts — one component, type switches the form.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="chart" />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { Chart } from "@olwiba/ui";
22
+
23
+ <Chart
24
+ type="line"
25
+ data={revenue}
26
+ xKey="month"
27
+ series={[
28
+ { key: "mrr", label: "MRR" },
29
+ { key: "costs", label: "Costs" },
30
+ ]}
31
+ valueFormatter={(v) => `$${v.toLocaleString()}`}
32
+ />
33
+ ```
34
+
35
+ Pick the form by the data's job: `line`/`area` for change over time, `bar` for magnitude comparison, `donut` for part-of-whole. Colors come from the `--chart-1..5` theme tokens in fixed order — series keep their color when others are filtered out. Override per series with `color`.
36
+
37
+ Donut uses `xKey` for slice labels and `series[0].key` for values. More than 5 slices: fold the tail into an "Other" row in your data rather than adding hues.
38
+
39
+ ```tsx
40
+ <Chart type="donut" data={plans} xKey="plan" series={[{ key: "users" }]} />
41
+ ```
42
+
43
+ A legend renders automatically for multiple series (and donuts); a single named series doesn't need one. Tooltips are always on.
44
+
45
+ ## API Reference
46
+
47
+ <APIReference name="Chart" props={[]} />
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: CommandMenu
3
+ description: Global Cmd+K / Ctrl+K search palette.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="command-menu" />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { CommandMenu } from "@olwiba/ui";
22
+ import { LayoutDashboard, Settings } from "lucide-react";
23
+
24
+ <CommandMenu
25
+ groups={[
26
+ {
27
+ heading: "Navigate",
28
+ items: [
29
+ { id: "dashboard", label: "Dashboard", icon: LayoutDashboard, onSelect: () => router.push("/dashboard") },
30
+ { id: "settings", label: "Settings", icon: Settings, onSelect: () => router.push("/settings") },
31
+ ],
32
+ },
33
+ ]}
34
+ />
35
+ ```
36
+
37
+ Registers the Cmd+K (mac) / Ctrl+K (win) hotkey by default — pass `hotkey={false}` and your own `open`/`onOpenChange` if you'd rather trigger it from a button.
38
+
39
+ ## API Reference
40
+
41
+ <APIReference name="CommandMenu" props={[]} />
@@ -0,0 +1,26 @@
1
+ ---
2
+ title: ConfirmDialog
3
+ description: Modal confirmation dialog — UI shell for the useConfirm hook.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="confirm-dialog" />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { ConfirmDialog } from "@olwiba/ui";
22
+ ```
23
+
24
+ ## API Reference
25
+
26
+ <APIReference name="ConfirmDialog" props={[]} />
@@ -0,0 +1,26 @@
1
+ ---
2
+ title: ContextMenu
3
+ description: Right-click context menu with animated entry.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="context-menu" />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { ContextMenu } from "@olwiba/ui";
22
+ ```
23
+
24
+ ## API Reference
25
+
26
+ <APIReference name="ContextMenu" props={[]} />
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: DataTable
3
+ description: Sortable, paginated, optionally-selectable data table built on TanStack Table.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="data-table" />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { DataTable, type DataTableColumn } from "@olwiba/ui";
22
+
23
+ const columns: DataTableColumn<Project>[] = [
24
+ { accessorKey: "name", header: "Project" },
25
+ { accessorKey: "status", header: "Status" },
26
+ ];
27
+
28
+ <DataTable
29
+ columns={columns}
30
+ data={projects}
31
+ searchKey="name"
32
+ toolbar={<Button size="sm">New project</Button>}
33
+ />
34
+ ```
35
+
36
+ One component — toggle `searchKey`, `selectable`, and `pageSize` rather than reaching for a different table per use case. Columns are standard TanStack Table `ColumnDef`s, so sorting, custom cells, and accessors all work as usual.
37
+
38
+ ## API Reference
39
+
40
+ <APIReference name="DataTable" props={[]} />