@c9up/nebula 0.1.0

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 (327) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +256 -0
  3. package/dist/adapters/css.d.ts +33 -0
  4. package/dist/adapters/css.js +67 -0
  5. package/dist/adapters/index.d.ts +16 -0
  6. package/dist/adapters/index.js +27 -0
  7. package/dist/adapters/tailwind.d.ts +25 -0
  8. package/dist/adapters/tailwind.js +122 -0
  9. package/dist/adapters/types.d.ts +49 -0
  10. package/dist/adapters/types.js +21 -0
  11. package/dist/adapters/unocss.d.ts +17 -0
  12. package/dist/adapters/unocss.js +107 -0
  13. package/dist/atoms/AspectRatio.d.ts +17 -0
  14. package/dist/atoms/AspectRatio.js +19 -0
  15. package/dist/atoms/Avatar.d.ts +23 -0
  16. package/dist/atoms/Avatar.js +46 -0
  17. package/dist/atoms/Badge.d.ts +25 -0
  18. package/dist/atoms/Badge.js +28 -0
  19. package/dist/atoms/Button.d.ts +58 -0
  20. package/dist/atoms/Button.js +67 -0
  21. package/dist/atoms/Checkbox.d.ts +41 -0
  22. package/dist/atoms/Checkbox.js +47 -0
  23. package/dist/atoms/Input.d.ts +36 -0
  24. package/dist/atoms/Input.js +50 -0
  25. package/dist/atoms/Kbd.d.ts +14 -0
  26. package/dist/atoms/Kbd.js +17 -0
  27. package/dist/atoms/Label.d.ts +24 -0
  28. package/dist/atoms/Label.js +26 -0
  29. package/dist/atoms/Marker.d.ts +42 -0
  30. package/dist/atoms/Marker.js +55 -0
  31. package/dist/atoms/NativeSelect.d.ts +43 -0
  32. package/dist/atoms/NativeSelect.js +81 -0
  33. package/dist/atoms/Progress.d.ts +21 -0
  34. package/dist/atoms/Progress.js +48 -0
  35. package/dist/atoms/ScrollArea.d.ts +28 -0
  36. package/dist/atoms/ScrollArea.js +37 -0
  37. package/dist/atoms/Separator.d.ts +16 -0
  38. package/dist/atoms/Separator.js +21 -0
  39. package/dist/atoms/Skeleton.d.ts +13 -0
  40. package/dist/atoms/Skeleton.js +18 -0
  41. package/dist/atoms/Slider.d.ts +30 -0
  42. package/dist/atoms/Slider.js +40 -0
  43. package/dist/atoms/Spinner.d.ts +17 -0
  44. package/dist/atoms/Spinner.js +20 -0
  45. package/dist/atoms/Switch.d.ts +24 -0
  46. package/dist/atoms/Switch.js +41 -0
  47. package/dist/atoms/Textarea.d.ts +28 -0
  48. package/dist/atoms/Textarea.js +36 -0
  49. package/dist/atoms/Toggle.d.ts +38 -0
  50. package/dist/atoms/Toggle.js +45 -0
  51. package/dist/atoms/index.d.ts +32 -0
  52. package/dist/atoms/index.js +32 -0
  53. package/dist/cli/add.d.ts +44 -0
  54. package/dist/cli/add.js +99 -0
  55. package/dist/cli/index.d.ts +10 -0
  56. package/dist/cli/index.js +10 -0
  57. package/dist/cli/registry.d.ts +31 -0
  58. package/dist/cli/registry.js +83 -0
  59. package/dist/config.d.ts +81 -0
  60. package/dist/config.js +43 -0
  61. package/dist/configure.d.ts +34 -0
  62. package/dist/configure.js +85 -0
  63. package/dist/index.d.ts +41 -0
  64. package/dist/index.js +41 -0
  65. package/dist/lib/children.d.ts +28 -0
  66. package/dist/lib/children.js +27 -0
  67. package/dist/lib/cn.d.ts +13 -0
  68. package/dist/lib/cn.js +13 -0
  69. package/dist/lib/cva.d.ts +83 -0
  70. package/dist/lib/cva.js +178 -0
  71. package/dist/lib/icons.d.ts +44 -0
  72. package/dist/lib/icons.js +79 -0
  73. package/dist/lib/id.d.ts +31 -0
  74. package/dist/lib/id.js +41 -0
  75. package/dist/lib/index.d.ts +12 -0
  76. package/dist/lib/index.js +12 -0
  77. package/dist/lib/motion.d.ts +31 -0
  78. package/dist/lib/motion.js +39 -0
  79. package/dist/lib/props.d.ts +48 -0
  80. package/dist/lib/props.js +59 -0
  81. package/dist/lib/styled.d.ts +31 -0
  82. package/dist/lib/styled.js +39 -0
  83. package/dist/molecules/Accordion.d.ts +35 -0
  84. package/dist/molecules/Accordion.js +117 -0
  85. package/dist/molecules/Alert.d.ts +30 -0
  86. package/dist/molecules/Alert.js +35 -0
  87. package/dist/molecules/Attachment.d.ts +39 -0
  88. package/dist/molecules/Attachment.js +103 -0
  89. package/dist/molecules/Breadcrumb.d.ts +29 -0
  90. package/dist/molecules/Breadcrumb.js +73 -0
  91. package/dist/molecules/Bubble.d.ts +56 -0
  92. package/dist/molecules/Bubble.js +92 -0
  93. package/dist/molecules/ButtonGroup.d.ts +23 -0
  94. package/dist/molecules/ButtonGroup.js +30 -0
  95. package/dist/molecules/Card.d.ts +17 -0
  96. package/dist/molecules/Card.js +17 -0
  97. package/dist/molecules/Collapsible.d.ts +40 -0
  98. package/dist/molecules/Collapsible.js +71 -0
  99. package/dist/molecules/Empty.d.ts +16 -0
  100. package/dist/molecules/Empty.js +16 -0
  101. package/dist/molecules/Field.d.ts +54 -0
  102. package/dist/molecules/Field.js +82 -0
  103. package/dist/molecules/InputGroup.d.ts +33 -0
  104. package/dist/molecules/InputGroup.js +35 -0
  105. package/dist/molecules/InputOTP.d.ts +33 -0
  106. package/dist/molecules/InputOTP.js +140 -0
  107. package/dist/molecules/Item.d.ts +41 -0
  108. package/dist/molecules/Item.js +48 -0
  109. package/dist/molecules/Message.d.ts +43 -0
  110. package/dist/molecules/Message.js +82 -0
  111. package/dist/molecules/Pagination.d.ts +41 -0
  112. package/dist/molecules/Pagination.js +144 -0
  113. package/dist/molecules/RadioGroup.d.ts +32 -0
  114. package/dist/molecules/RadioGroup.js +65 -0
  115. package/dist/molecules/Resizable.d.ts +37 -0
  116. package/dist/molecules/Resizable.js +136 -0
  117. package/dist/molecules/Table.d.ts +37 -0
  118. package/dist/molecules/Table.js +78 -0
  119. package/dist/molecules/Tabs.d.ts +37 -0
  120. package/dist/molecules/Tabs.js +109 -0
  121. package/dist/molecules/ToggleGroup.d.ts +37 -0
  122. package/dist/molecules/ToggleGroup.js +68 -0
  123. package/dist/molecules/Typography.d.ts +26 -0
  124. package/dist/molecules/Typography.js +67 -0
  125. package/dist/molecules/index.d.ts +37 -0
  126. package/dist/molecules/index.js +37 -0
  127. package/dist/organisms/AlertDialog.d.ts +40 -0
  128. package/dist/organisms/AlertDialog.js +104 -0
  129. package/dist/organisms/Calendar.d.ts +96 -0
  130. package/dist/organisms/Calendar.js +353 -0
  131. package/dist/organisms/Carousel.d.ts +29 -0
  132. package/dist/organisms/Carousel.js +128 -0
  133. package/dist/organisms/Chart.d.ts +55 -0
  134. package/dist/organisms/Chart.js +189 -0
  135. package/dist/organisms/Combobox.d.ts +41 -0
  136. package/dist/organisms/Combobox.js +102 -0
  137. package/dist/organisms/Command.d.ts +46 -0
  138. package/dist/organisms/Command.js +171 -0
  139. package/dist/organisms/CommandDialog.d.ts +42 -0
  140. package/dist/organisms/CommandDialog.js +116 -0
  141. package/dist/organisms/ContextMenu.d.ts +29 -0
  142. package/dist/organisms/ContextMenu.js +102 -0
  143. package/dist/organisms/DataTable.d.ts +50 -0
  144. package/dist/organisms/DataTable.js +257 -0
  145. package/dist/organisms/DatePicker.d.ts +34 -0
  146. package/dist/organisms/DatePicker.js +115 -0
  147. package/dist/organisms/DateRangePicker.d.ts +34 -0
  148. package/dist/organisms/DateRangePicker.js +122 -0
  149. package/dist/organisms/Dialog.d.ts +50 -0
  150. package/dist/organisms/Dialog.js +116 -0
  151. package/dist/organisms/Drawer.d.ts +40 -0
  152. package/dist/organisms/Drawer.js +131 -0
  153. package/dist/organisms/DropdownMenu.d.ts +30 -0
  154. package/dist/organisms/DropdownMenu.js +91 -0
  155. package/dist/organisms/Form.d.ts +114 -0
  156. package/dist/organisms/Form.js +151 -0
  157. package/dist/organisms/HoverCard.d.ts +30 -0
  158. package/dist/organisms/HoverCard.js +68 -0
  159. package/dist/organisms/Menubar.d.ts +28 -0
  160. package/dist/organisms/Menubar.js +147 -0
  161. package/dist/organisms/MessageScroller.d.ts +36 -0
  162. package/dist/organisms/MessageScroller.js +124 -0
  163. package/dist/organisms/NavigationMenu.d.ts +41 -0
  164. package/dist/organisms/NavigationMenu.js +139 -0
  165. package/dist/organisms/Popover.d.ts +33 -0
  166. package/dist/organisms/Popover.js +58 -0
  167. package/dist/organisms/Questionnaire.d.ts +74 -0
  168. package/dist/organisms/Questionnaire.js +235 -0
  169. package/dist/organisms/Select.d.ts +47 -0
  170. package/dist/organisms/Select.js +250 -0
  171. package/dist/organisms/Sheet.d.ts +34 -0
  172. package/dist/organisms/Sheet.js +107 -0
  173. package/dist/organisms/Sidebar.d.ts +100 -0
  174. package/dist/organisms/Sidebar.js +228 -0
  175. package/dist/organisms/Toaster.d.ts +67 -0
  176. package/dist/organisms/Toaster.js +189 -0
  177. package/dist/organisms/Tooltip.d.ts +39 -0
  178. package/dist/organisms/Tooltip.js +94 -0
  179. package/dist/organisms/index.d.ts +40 -0
  180. package/dist/organisms/index.js +40 -0
  181. package/dist/primitives/controllable.d.ts +38 -0
  182. package/dist/primitives/controllable.js +43 -0
  183. package/dist/primitives/dismissable.d.ts +53 -0
  184. package/dist/primitives/dismissable.js +158 -0
  185. package/dist/primitives/floating.d.ts +116 -0
  186. package/dist/primitives/floating.js +289 -0
  187. package/dist/primitives/floatingSurface.d.ts +56 -0
  188. package/dist/primitives/floatingSurface.js +142 -0
  189. package/dist/primitives/focusTrap.d.ts +47 -0
  190. package/dist/primitives/focusTrap.js +101 -0
  191. package/dist/primitives/focusable.d.ts +53 -0
  192. package/dist/primitives/focusable.js +109 -0
  193. package/dist/primitives/index.d.ts +27 -0
  194. package/dist/primitives/index.js +27 -0
  195. package/dist/primitives/menu.d.ts +102 -0
  196. package/dist/primitives/menu.js +356 -0
  197. package/dist/primitives/modalSurface.d.ts +54 -0
  198. package/dist/primitives/modalSurface.js +146 -0
  199. package/dist/primitives/portal.d.ts +34 -0
  200. package/dist/primitives/portal.js +42 -0
  201. package/dist/primitives/presence.d.ts +45 -0
  202. package/dist/primitives/presence.js +152 -0
  203. package/dist/primitives/rovingFocus.d.ts +47 -0
  204. package/dist/primitives/rovingFocus.js +176 -0
  205. package/dist/primitives/scrollLock.d.ts +21 -0
  206. package/dist/primitives/scrollLock.js +75 -0
  207. package/dist/primitives/typeahead.d.ts +39 -0
  208. package/dist/primitives/typeahead.js +123 -0
  209. package/dist/templates/AppShell.d.ts +30 -0
  210. package/dist/templates/AppShell.js +42 -0
  211. package/dist/templates/AuthLayout.d.ts +23 -0
  212. package/dist/templates/AuthLayout.js +42 -0
  213. package/dist/templates/SettingsLayout.d.ts +27 -0
  214. package/dist/templates/SettingsLayout.js +42 -0
  215. package/dist/templates/index.d.ts +16 -0
  216. package/dist/templates/index.js +16 -0
  217. package/nebula.css +2 -0
  218. package/package.json +92 -0
  219. package/registry.json +1107 -0
  220. package/src/adapters/css.ts +75 -0
  221. package/src/adapters/index.ts +40 -0
  222. package/src/adapters/tailwind.ts +134 -0
  223. package/src/adapters/types.ts +53 -0
  224. package/src/adapters/unocss.ts +116 -0
  225. package/src/atoms/AspectRatio.ts +28 -0
  226. package/src/atoms/Avatar.ts +67 -0
  227. package/src/atoms/Badge.ts +46 -0
  228. package/src/atoms/Button.ts +96 -0
  229. package/src/atoms/Checkbox.ts +76 -0
  230. package/src/atoms/Input.ts +76 -0
  231. package/src/atoms/Kbd.ts +28 -0
  232. package/src/atoms/Label.ts +38 -0
  233. package/src/atoms/Marker.ts +79 -0
  234. package/src/atoms/NativeSelect.ts +115 -0
  235. package/src/atoms/Progress.ts +64 -0
  236. package/src/atoms/ScrollArea.ts +53 -0
  237. package/src/atoms/Separator.ts +36 -0
  238. package/src/atoms/Skeleton.ts +24 -0
  239. package/src/atoms/Slider.ts +65 -0
  240. package/src/atoms/Spinner.ts +28 -0
  241. package/src/atoms/Switch.ts +56 -0
  242. package/src/atoms/Textarea.ts +58 -0
  243. package/src/atoms/Toggle.ts +67 -0
  244. package/src/atoms/index.ts +62 -0
  245. package/src/cli/add.ts +126 -0
  246. package/src/cli/index.ts +22 -0
  247. package/src/cli/registry.ts +116 -0
  248. package/src/config.ts +102 -0
  249. package/src/configure.ts +127 -0
  250. package/src/index.ts +53 -0
  251. package/src/lib/children.ts +43 -0
  252. package/src/lib/cn.ts +14 -0
  253. package/src/lib/cva.ts +249 -0
  254. package/src/lib/icons.ts +138 -0
  255. package/src/lib/id.ts +44 -0
  256. package/src/lib/index.ts +21 -0
  257. package/src/lib/motion.ts +48 -0
  258. package/src/lib/props.ts +83 -0
  259. package/src/lib/styled.ts +60 -0
  260. package/src/molecules/Accordion.ts +161 -0
  261. package/src/molecules/Alert.ts +58 -0
  262. package/src/molecules/Attachment.ts +132 -0
  263. package/src/molecules/Breadcrumb.ts +107 -0
  264. package/src/molecules/Bubble.ts +134 -0
  265. package/src/molecules/ButtonGroup.ts +55 -0
  266. package/src/molecules/Card.ts +42 -0
  267. package/src/molecules/Collapsible.ts +89 -0
  268. package/src/molecules/Empty.ts +43 -0
  269. package/src/molecules/Field.ts +131 -0
  270. package/src/molecules/InputGroup.ts +62 -0
  271. package/src/molecules/InputOTP.ts +166 -0
  272. package/src/molecules/Item.ts +89 -0
  273. package/src/molecules/Message.ts +127 -0
  274. package/src/molecules/Pagination.ts +197 -0
  275. package/src/molecules/RadioGroup.ts +104 -0
  276. package/src/molecules/Resizable.ts +166 -0
  277. package/src/molecules/Table.ts +118 -0
  278. package/src/molecules/Tabs.ts +148 -0
  279. package/src/molecules/ToggleGroup.ts +109 -0
  280. package/src/molecules/Typography.ts +94 -0
  281. package/src/molecules/index.ts +144 -0
  282. package/src/organisms/AlertDialog.ts +133 -0
  283. package/src/organisms/Calendar.ts +470 -0
  284. package/src/organisms/Carousel.ts +161 -0
  285. package/src/organisms/Chart.ts +257 -0
  286. package/src/organisms/Combobox.ts +140 -0
  287. package/src/organisms/Command.ts +211 -0
  288. package/src/organisms/CommandDialog.ts +149 -0
  289. package/src/organisms/ContextMenu.ts +125 -0
  290. package/src/organisms/DataTable.ts +328 -0
  291. package/src/organisms/DatePicker.ts +141 -0
  292. package/src/organisms/DateRangePicker.ts +149 -0
  293. package/src/organisms/Dialog.ts +162 -0
  294. package/src/organisms/Drawer.ts +167 -0
  295. package/src/organisms/DropdownMenu.ts +112 -0
  296. package/src/organisms/Form.ts +217 -0
  297. package/src/organisms/HoverCard.ts +92 -0
  298. package/src/organisms/Menubar.ts +167 -0
  299. package/src/organisms/MessageScroller.ts +145 -0
  300. package/src/organisms/NavigationMenu.ts +184 -0
  301. package/src/organisms/Popover.ts +84 -0
  302. package/src/organisms/Questionnaire.ts +322 -0
  303. package/src/organisms/Select.ts +286 -0
  304. package/src/organisms/Sheet.ts +144 -0
  305. package/src/organisms/Sidebar.ts +336 -0
  306. package/src/organisms/Toaster.ts +246 -0
  307. package/src/organisms/Tooltip.ts +124 -0
  308. package/src/organisms/index.ts +134 -0
  309. package/src/primitives/controllable.ts +64 -0
  310. package/src/primitives/dismissable.ts +195 -0
  311. package/src/primitives/floating.ts +453 -0
  312. package/src/primitives/floatingSurface.ts +209 -0
  313. package/src/primitives/focusTrap.ts +132 -0
  314. package/src/primitives/focusable.ts +108 -0
  315. package/src/primitives/index.ts +88 -0
  316. package/src/primitives/menu.ts +491 -0
  317. package/src/primitives/modalSurface.ts +199 -0
  318. package/src/primitives/portal.ts +61 -0
  319. package/src/primitives/presence.ts +185 -0
  320. package/src/primitives/rovingFocus.ts +212 -0
  321. package/src/primitives/scrollLock.ts +79 -0
  322. package/src/primitives/typeahead.ts +156 -0
  323. package/src/templates/AppShell.ts +56 -0
  324. package/src/templates/AuthLayout.ts +66 -0
  325. package/src/templates/SettingsLayout.ts +63 -0
  326. package/src/templates/index.ts +21 -0
  327. package/theme.css +151 -0
@@ -0,0 +1,56 @@
1
+ /**
2
+ * AppShell — sidebar, header, content.
3
+ *
4
+ * The layout behind almost every signed-in page. Shipping it is what makes
5
+ * nebula an atomic-design library rather than a component bag: shadcn stops at
6
+ * organisms and leaves the page skeleton to be rebuilt per app, which is why
7
+ * two pages in the same product end up with different header heights.
8
+ *
9
+ * `h-svh` on the shell and `overflow-auto` on the content column, not on the
10
+ * body. That is what keeps the header and the sidebar fixed while only the
11
+ * content scrolls — pinning them with `position: fixed` instead means
12
+ * hand-maintaining a top padding that matches the header, and it breaks the
13
+ * moment the header wraps to two lines.
14
+ *
15
+ * `svh` rather than `vh` because mobile browsers shrink the viewport as their
16
+ * address bar retracts; `vh` leaves the last hundred pixels of a full-height
17
+ * layout under the browser chrome.
18
+ */
19
+
20
+ import { component, html } from "@c9up/aurora";
21
+ import { type Slot, slot } from "../lib/children.js";
22
+ import { cn } from "../lib/cn.js";
23
+ import { type Reactive, read } from "../lib/props.js";
24
+
25
+ export interface AppShellProps {
26
+ /** The navigation column — usually a `Sidebar`. */
27
+ sidebar?: Slot;
28
+ /** The top bar, spanning the content column. */
29
+ header?: Slot;
30
+ children?: Slot;
31
+ class?: Reactive<string>;
32
+ contentClass?: Reactive<string>;
33
+ }
34
+
35
+ export const AppShell = component<AppShellProps>((props) => {
36
+ return html`<div
37
+ data-slot="app-shell"
38
+ class="${() => cn("bg-background flex h-svh w-full overflow-hidden", read(props.class))}"
39
+ >
40
+ ${slot(props.sidebar)}
41
+ <div data-slot="app-shell-main" class="flex min-w-0 flex-1 flex-col">
42
+ ${
43
+ props.header === undefined
44
+ ? null
45
+ : html`<header
46
+ data-slot="app-shell-header"
47
+ class="bg-background flex h-14 shrink-0 items-center gap-2 border-b px-4"
48
+ >${slot(props.header)}</header>`
49
+ }
50
+ <main
51
+ data-slot="app-shell-content"
52
+ class="${() => cn("min-h-0 flex-1 overflow-auto p-4 md:p-6", read(props.contentClass))}"
53
+ >${slot(props.children)}</main>
54
+ </div>
55
+ </div>`;
56
+ });
@@ -0,0 +1,66 @@
1
+ /**
2
+ * AuthLayout — a centred card for sign-in, sign-up and password reset.
3
+ *
4
+ * `min-h-svh` with the card centred by flex, rather than absolute positioning
5
+ * and a translate. Centring by transform breaks as soon as the card grows
6
+ * taller than the viewport — a sign-up form with four fields and a validation
7
+ * error on each — because the top half goes above the fold with nothing to
8
+ * scroll to.
9
+ */
10
+
11
+ import { component, html } from "@c9up/aurora";
12
+ import type { Child } from "../lib/children.js";
13
+ import { type Slot, slot } from "../lib/children.js";
14
+ import { cn } from "../lib/cn.js";
15
+ import { type Reactive, read } from "../lib/props.js";
16
+
17
+ export interface AuthLayoutProps {
18
+ /** Product name or logo, above the card. */
19
+ brand?: Slot;
20
+ title: Child;
21
+ description?: Child;
22
+ children?: Slot;
23
+ /** Under the card — "Already have an account?" and the like. */
24
+ footer?: Slot;
25
+ class?: Reactive<string>;
26
+ }
27
+
28
+ export const AuthLayout = component<AuthLayoutProps>((props) => {
29
+ return html`<div
30
+ data-slot="auth-layout"
31
+ class="${() =>
32
+ cn(
33
+ "bg-muted/40 flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10",
34
+ read(props.class),
35
+ )}"
36
+ >
37
+ <div class="flex w-full max-w-sm flex-col gap-6">
38
+ ${
39
+ props.brand === undefined
40
+ ? null
41
+ : html`<div class="flex justify-center">${slot(props.brand)}</div>`
42
+ }
43
+ <div
44
+ data-slot="auth-card"
45
+ class="bg-card text-card-foreground flex flex-col gap-6 rounded-xl border p-6 shadow-sm"
46
+ >
47
+ <div class="flex flex-col gap-1.5 text-center">
48
+ <h1 class="text-xl leading-none font-semibold">${props.title}</h1>
49
+ ${
50
+ props.description === undefined
51
+ ? null
52
+ : html`<p class="text-muted-foreground text-sm">${props.description}</p>`
53
+ }
54
+ </div>
55
+ ${slot(props.children)}
56
+ </div>
57
+ ${
58
+ props.footer === undefined
59
+ ? null
60
+ : html`<div class="text-muted-foreground text-center text-sm">
61
+ ${slot(props.footer)}
62
+ </div>`
63
+ }
64
+ </div>
65
+ </div>`;
66
+ });
@@ -0,0 +1,63 @@
1
+ /**
2
+ * SettingsLayout — a section list beside a settings panel.
3
+ *
4
+ * The list is a real `<nav>` of links, not a Tabs component. Settings sections
5
+ * are pages: they need their own URL so a link to "Billing" works, and so the
6
+ * back button returns to the previous section rather than leaving the page
7
+ * entirely. Tabs would give the same look and none of that.
8
+ *
9
+ * The list sits above the panel on narrow screens and beside it from `md` up,
10
+ * which is the one responsive decision this layout has to make.
11
+ */
12
+
13
+ import { component, html } from "@c9up/aurora";
14
+ import type { Child } from "../lib/children.js";
15
+ import { type Slot, slot } from "../lib/children.js";
16
+ import { cn } from "../lib/cn.js";
17
+ import { type Reactive, read } from "../lib/props.js";
18
+
19
+ export interface SettingsSection {
20
+ label: Child;
21
+ href: string;
22
+ active?: boolean;
23
+ }
24
+
25
+ export interface SettingsLayoutProps {
26
+ title: Child;
27
+ description?: Child;
28
+ sections: readonly SettingsSection[];
29
+ children?: Slot;
30
+ class?: Reactive<string>;
31
+ }
32
+
33
+ export const SettingsLayout = component<SettingsLayoutProps>((props) => {
34
+ return html`<div
35
+ data-slot="settings-layout"
36
+ class="${() => cn("flex flex-col gap-6 p-4 md:p-10", read(props.class))}"
37
+ >
38
+ <div class="flex flex-col gap-1.5">
39
+ <h1 class="text-2xl font-semibold tracking-tight">${props.title}</h1>
40
+ ${
41
+ props.description === undefined
42
+ ? null
43
+ : html`<p class="text-muted-foreground text-sm">${props.description}</p>`
44
+ }
45
+ </div>
46
+ <div class="flex flex-col gap-8 md:flex-row md:gap-12">
47
+ <nav
48
+ data-slot="settings-nav"
49
+ aria-label="Settings sections"
50
+ class="flex gap-2 overflow-x-auto md:w-48 md:shrink-0 md:flex-col md:overflow-visible"
51
+ >
52
+ ${props.sections.map(
53
+ (section) => html`<a
54
+ href="${section.href}"
55
+ aria-current="${section.active === true ? "page" : undefined}"
56
+ class="hover:bg-accent hover:text-accent-foreground aria-[current=page]:bg-accent aria-[current=page]:font-medium rounded-md px-3 py-2 text-sm whitespace-nowrap transition-colors"
57
+ >${section.label}</a>`,
58
+ )}
59
+ </nav>
60
+ <div data-slot="settings-panel" class="min-w-0 flex-1">${slot(props.children)}</div>
61
+ </div>
62
+ </div>`;
63
+ });
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Templates — page skeletons.
3
+ *
4
+ * Atomic design's fourth level, and the one shadcn does not have: it stops at
5
+ * organisms and ships "blocks" as copy-paste examples instead. The gap shows
6
+ * up as drift — two pages in the same product with different header heights
7
+ * and different content padding, because each was assembled from organisms by
8
+ * hand.
9
+ *
10
+ * A template is layout only. It positions slots and owns no state, no data and
11
+ * no behaviour, which is what keeps it usable for pages it was not written
12
+ * with in mind.
13
+ */
14
+
15
+ export { AppShell, type AppShellProps } from "./AppShell.js";
16
+ export { AuthLayout, type AuthLayoutProps } from "./AuthLayout.js";
17
+ export {
18
+ SettingsLayout,
19
+ type SettingsLayoutProps,
20
+ type SettingsSection,
21
+ } from "./SettingsLayout.js";
package/theme.css ADDED
@@ -0,0 +1,151 @@
1
+ /*
2
+ * nebula design tokens.
3
+ *
4
+ * Plain CSS custom properties, deliberately: this file has to be readable by
5
+ * all three adapters. Tailwind maps it through `@theme inline`, UnoCSS through
6
+ * its `theme` object, and the `css` adapter emits utilities straight against
7
+ * it. Anything engine-specific here would force a fork per adapter.
8
+ *
9
+ * The palette is shadcn's neutral base in oklch. oklch rather than hex because
10
+ * the whole point of the scale is that `--muted-foreground` sits a predictable
11
+ * perceptual distance from `--foreground`; in sRGB hex that relationship is
12
+ * eyeballed and breaks the moment someone retunes one end of it.
13
+ *
14
+ * Dark mode is applied by `.dark` on an ancestor, matching what the aurora
15
+ * apps in this workspace already do (`@custom-variant dark (&:is(.dark *))`).
16
+ * `prefers-color-scheme` is deliberately NOT wired here — a theme toggle needs
17
+ * to be able to override the system, and a media query cannot be overridden by
18
+ * a class.
19
+ */
20
+
21
+ :root {
22
+ --radius: 0.625rem;
23
+
24
+ --background: oklch(1 0 0);
25
+ --foreground: oklch(0.145 0 0);
26
+
27
+ --card: oklch(1 0 0);
28
+ --card-foreground: oklch(0.145 0 0);
29
+
30
+ --popover: oklch(1 0 0);
31
+ --popover-foreground: oklch(0.145 0 0);
32
+
33
+ --primary: oklch(0.205 0 0);
34
+ --primary-foreground: oklch(0.985 0 0);
35
+
36
+ --secondary: oklch(0.97 0 0);
37
+ --secondary-foreground: oklch(0.205 0 0);
38
+
39
+ --muted: oklch(0.97 0 0);
40
+ --muted-foreground: oklch(0.556 0 0);
41
+
42
+ --accent: oklch(0.97 0 0);
43
+ --accent-foreground: oklch(0.205 0 0);
44
+
45
+ --destructive: oklch(0.577 0.245 27.325);
46
+ --destructive-foreground: oklch(0.985 0 0);
47
+
48
+ --border: oklch(0.922 0 0);
49
+ --input: oklch(0.922 0 0);
50
+ --ring: oklch(0.708 0 0);
51
+
52
+ --chart-1: oklch(0.646 0.222 41.116);
53
+ --chart-2: oklch(0.6 0.118 184.704);
54
+ --chart-3: oklch(0.398 0.07 227.392);
55
+ --chart-4: oklch(0.828 0.189 84.429);
56
+ --chart-5: oklch(0.769 0.188 70.08);
57
+
58
+ --sidebar: oklch(0.985 0 0);
59
+ --sidebar-foreground: oklch(0.145 0 0);
60
+ --sidebar-primary: oklch(0.205 0 0);
61
+ --sidebar-primary-foreground: oklch(0.985 0 0);
62
+ --sidebar-accent: oklch(0.97 0 0);
63
+ --sidebar-accent-foreground: oklch(0.205 0 0);
64
+ --sidebar-border: oklch(0.922 0 0);
65
+ --sidebar-ring: oklch(0.708 0 0);
66
+ }
67
+
68
+ .dark {
69
+ --background: oklch(0.145 0 0);
70
+ --foreground: oklch(0.985 0 0);
71
+
72
+ --card: oklch(0.205 0 0);
73
+ --card-foreground: oklch(0.985 0 0);
74
+
75
+ --popover: oklch(0.269 0 0);
76
+ --popover-foreground: oklch(0.985 0 0);
77
+
78
+ --primary: oklch(0.922 0 0);
79
+ --primary-foreground: oklch(0.205 0 0);
80
+
81
+ --secondary: oklch(0.269 0 0);
82
+ --secondary-foreground: oklch(0.985 0 0);
83
+
84
+ --muted: oklch(0.269 0 0);
85
+ --muted-foreground: oklch(0.708 0 0);
86
+
87
+ --accent: oklch(0.371 0 0);
88
+ --accent-foreground: oklch(0.985 0 0);
89
+
90
+ --destructive: oklch(0.704 0.191 22.216);
91
+ --destructive-foreground: oklch(0.985 0 0);
92
+
93
+ /*
94
+ * Borders and inputs are translucent white in dark mode rather than a
95
+ * lighter grey. A solid border reads as a seam against `--card`, which sits
96
+ * above `--background`; alpha lets one value hold up over both surfaces.
97
+ */
98
+ --border: oklch(1 0 0 / 10%);
99
+ --input: oklch(1 0 0 / 15%);
100
+ --ring: oklch(0.556 0 0);
101
+
102
+ --chart-1: oklch(0.488 0.243 264.376);
103
+ --chart-2: oklch(0.696 0.17 162.48);
104
+ --chart-3: oklch(0.769 0.188 70.08);
105
+ --chart-4: oklch(0.627 0.265 303.9);
106
+ --chart-5: oklch(0.645 0.246 16.439);
107
+
108
+ --sidebar: oklch(0.205 0 0);
109
+ --sidebar-foreground: oklch(0.985 0 0);
110
+ --sidebar-primary: oklch(0.488 0.243 264.376);
111
+ --sidebar-primary-foreground: oklch(0.985 0 0);
112
+ --sidebar-accent: oklch(0.269 0 0);
113
+ --sidebar-accent-foreground: oklch(0.985 0 0);
114
+ --sidebar-border: oklch(1 0 0 / 10%);
115
+ --sidebar-ring: oklch(0.556 0 0);
116
+ }
117
+
118
+ /*
119
+ * Keyframes for the enter/exit animations the overlay components reference
120
+ * through `data-[state=open]:animate-in` and friends.
121
+ *
122
+ * These live in nebula rather than in the adapter because `presence()` will
123
+ * hold a node in the DOM waiting for an animation that the stylesheet has to
124
+ * actually define. Ship the behaviour without the keyframes and every overlay
125
+ * unmounts a frame after it is told to close, silently losing the exit.
126
+ */
127
+ @keyframes nebula-fade-in {
128
+ from {
129
+ opacity: 0;
130
+ }
131
+ }
132
+
133
+ @keyframes nebula-fade-out {
134
+ to {
135
+ opacity: 0;
136
+ }
137
+ }
138
+
139
+ @keyframes nebula-zoom-in {
140
+ from {
141
+ opacity: 0;
142
+ transform: scale(0.95);
143
+ }
144
+ }
145
+
146
+ @keyframes nebula-zoom-out {
147
+ to {
148
+ opacity: 0;
149
+ transform: scale(0.95);
150
+ }
151
+ }