@storyshelf/app 0.5.3

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 (268) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +18 -0
  3. package/dist/app-types.d.mts +54 -0
  4. package/dist/asset-manifest.mjs +41 -0
  5. package/dist/asset-manifest.mjs.map +1 -0
  6. package/dist/asset-paths.mjs +23 -0
  7. package/dist/asset-paths.mjs.map +1 -0
  8. package/dist/assets/htmx.min.js +3304 -0
  9. package/dist/assets/mark.svg +1 -0
  10. package/dist/capture-setup.mjs +139 -0
  11. package/dist/capture-setup.mjs.map +1 -0
  12. package/dist/credential-keys.mjs +20 -0
  13. package/dist/credential-keys.mjs.map +1 -0
  14. package/dist/credentials.mjs +56 -0
  15. package/dist/credentials.mjs.map +1 -0
  16. package/dist/index.d.mts +18 -0
  17. package/dist/index.mjs +310 -0
  18. package/dist/index.mjs.map +1 -0
  19. package/dist/lifecycle.mjs +132 -0
  20. package/dist/lifecycle.mjs.map +1 -0
  21. package/dist/middleware/auth-gate.mjs +36 -0
  22. package/dist/middleware/auth-gate.mjs.map +1 -0
  23. package/dist/middleware/csrf.mjs +75 -0
  24. package/dist/middleware/csrf.mjs.map +1 -0
  25. package/dist/middleware/rate-limit.mjs +68 -0
  26. package/dist/middleware/rate-limit.mjs.map +1 -0
  27. package/dist/middleware/request-log.mjs +30 -0
  28. package/dist/middleware/request-log.mjs.map +1 -0
  29. package/dist/middleware/server-timing.mjs +39 -0
  30. package/dist/middleware/server-timing.mjs.map +1 -0
  31. package/dist/middleware/setup-gate.mjs +37 -0
  32. package/dist/middleware/setup-gate.mjs.map +1 -0
  33. package/dist/middleware/store-scope.mjs +33 -0
  34. package/dist/middleware/store-scope.mjs.map +1 -0
  35. package/dist/notify.d.mts +17 -0
  36. package/dist/notify.mjs +141 -0
  37. package/dist/notify.mjs.map +1 -0
  38. package/dist/pages/admin-system.mjs +243 -0
  39. package/dist/pages/admin-system.mjs.map +1 -0
  40. package/dist/pages/build-detail.mjs +392 -0
  41. package/dist/pages/build-detail.mjs.map +1 -0
  42. package/dist/pages/build-diff-actions.mjs +162 -0
  43. package/dist/pages/build-diff-actions.mjs.map +1 -0
  44. package/dist/pages/build-diff-comments.mjs +104 -0
  45. package/dist/pages/build-diff-comments.mjs.map +1 -0
  46. package/dist/pages/build-diff-header.mjs +117 -0
  47. package/dist/pages/build-diff-header.mjs.map +1 -0
  48. package/dist/pages/build-diff-model.mjs +48 -0
  49. package/dist/pages/build-diff-model.mjs.map +1 -0
  50. package/dist/pages/build-diff-nav.mjs +122 -0
  51. package/dist/pages/build-diff-nav.mjs.map +1 -0
  52. package/dist/pages/build-diff-shortcuts.mjs +78 -0
  53. package/dist/pages/build-diff-shortcuts.mjs.map +1 -0
  54. package/dist/pages/build-diff-stale.mjs +70 -0
  55. package/dist/pages/build-diff-stale.mjs.map +1 -0
  56. package/dist/pages/build-diff-viewer.mjs +70 -0
  57. package/dist/pages/build-diff-viewer.mjs.map +1 -0
  58. package/dist/pages/build-diff.mjs +110 -0
  59. package/dist/pages/build-diff.mjs.map +1 -0
  60. package/dist/pages/compute-jobs.mjs +165 -0
  61. package/dist/pages/compute-jobs.mjs.map +1 -0
  62. package/dist/pages/invite.mjs +91 -0
  63. package/dist/pages/invite.mjs.map +1 -0
  64. package/dist/pages/label-detail.mjs +154 -0
  65. package/dist/pages/label-detail.mjs.map +1 -0
  66. package/dist/pages/library.mjs +343 -0
  67. package/dist/pages/library.mjs.map +1 -0
  68. package/dist/pages/login.mjs +117 -0
  69. package/dist/pages/login.mjs.map +1 -0
  70. package/dist/pages/passkey-ceremony.mjs +97 -0
  71. package/dist/pages/passkey-ceremony.mjs.map +1 -0
  72. package/dist/pages/profile.mjs +364 -0
  73. package/dist/pages/profile.mjs.map +1 -0
  74. package/dist/pages/project-builds-table.mjs +151 -0
  75. package/dist/pages/project-builds-table.mjs.map +1 -0
  76. package/dist/pages/project-builds.mjs +143 -0
  77. package/dist/pages/project-builds.mjs.map +1 -0
  78. package/dist/pages/project-create.mjs +90 -0
  79. package/dist/pages/project-create.mjs.map +1 -0
  80. package/dist/pages/project-settings.mjs +95 -0
  81. package/dist/pages/project-settings.mjs.map +1 -0
  82. package/dist/pages/projects-card.mjs +194 -0
  83. package/dist/pages/projects-card.mjs.map +1 -0
  84. package/dist/pages/projects.mjs +129 -0
  85. package/dist/pages/projects.mjs.map +1 -0
  86. package/dist/pages/root.mjs +98 -0
  87. package/dist/pages/root.mjs.map +1 -0
  88. package/dist/pages/settings-general.mjs +138 -0
  89. package/dist/pages/settings-general.mjs.map +1 -0
  90. package/dist/pages/settings-labels.mjs +107 -0
  91. package/dist/pages/settings-labels.mjs.map +1 -0
  92. package/dist/pages/settings-members.mjs +192 -0
  93. package/dist/pages/settings-members.mjs.map +1 -0
  94. package/dist/pages/settings-notifications.mjs +240 -0
  95. package/dist/pages/settings-notifications.mjs.map +1 -0
  96. package/dist/pages/settings-status.mjs +137 -0
  97. package/dist/pages/settings-status.mjs.map +1 -0
  98. package/dist/pages/settings-tests.mjs +111 -0
  99. package/dist/pages/settings-tests.mjs.map +1 -0
  100. package/dist/pages/settings-tokens.mjs +90 -0
  101. package/dist/pages/settings-tokens.mjs.map +1 -0
  102. package/dist/pages/settings-webhooks.mjs +104 -0
  103. package/dist/pages/settings-webhooks.mjs.map +1 -0
  104. package/dist/pages/storybook.mjs +116 -0
  105. package/dist/pages/storybook.mjs.map +1 -0
  106. package/dist/retention-timer.mjs +65 -0
  107. package/dist/retention-timer.mjs.map +1 -0
  108. package/dist/routers/admin-pages.mjs +48 -0
  109. package/dist/routers/admin-pages.mjs.map +1 -0
  110. package/dist/routers/admin.mjs +113 -0
  111. package/dist/routers/admin.mjs.map +1 -0
  112. package/dist/routers/assets.mjs +64 -0
  113. package/dist/routers/assets.mjs.map +1 -0
  114. package/dist/routers/attempts.mjs +96 -0
  115. package/dist/routers/attempts.mjs.map +1 -0
  116. package/dist/routers/auth-sync.mjs +64 -0
  117. package/dist/routers/auth-sync.mjs.map +1 -0
  118. package/dist/routers/auth.mjs +236 -0
  119. package/dist/routers/auth.mjs.map +1 -0
  120. package/dist/routers/baseline-guard.mjs +83 -0
  121. package/dist/routers/baseline-guard.mjs.map +1 -0
  122. package/dist/routers/builds.handlers.mjs +217 -0
  123. package/dist/routers/builds.handlers.mjs.map +1 -0
  124. package/dist/routers/builds.mjs +381 -0
  125. package/dist/routers/builds.mjs.map +1 -0
  126. package/dist/routers/comments.mjs +109 -0
  127. package/dist/routers/comments.mjs.map +1 -0
  128. package/dist/routers/flash.mjs +35 -0
  129. package/dist/routers/flash.mjs.map +1 -0
  130. package/dist/routers/health-report.mjs +159 -0
  131. package/dist/routers/health-report.mjs.map +1 -0
  132. package/dist/routers/health.mjs +46 -0
  133. package/dist/routers/health.mjs.map +1 -0
  134. package/dist/routers/helpers.mjs +110 -0
  135. package/dist/routers/helpers.mjs.map +1 -0
  136. package/dist/routers/htmx.mjs +24 -0
  137. package/dist/routers/htmx.mjs.map +1 -0
  138. package/dist/routers/labels.mjs +118 -0
  139. package/dist/routers/labels.mjs.map +1 -0
  140. package/dist/routers/media.mjs +53 -0
  141. package/dist/routers/media.mjs.map +1 -0
  142. package/dist/routers/members.mjs +177 -0
  143. package/dist/routers/members.mjs.map +1 -0
  144. package/dist/routers/notification-channels.mjs +190 -0
  145. package/dist/routers/notification-channels.mjs.map +1 -0
  146. package/dist/routers/notification-subscriptions.mjs +120 -0
  147. package/dist/routers/notification-subscriptions.mjs.map +1 -0
  148. package/dist/routers/profile.mjs +276 -0
  149. package/dist/routers/profile.mjs.map +1 -0
  150. package/dist/routers/projects.mjs +133 -0
  151. package/dist/routers/projects.mjs.map +1 -0
  152. package/dist/routers/review-next.mjs +47 -0
  153. package/dist/routers/review-next.mjs.map +1 -0
  154. package/dist/routers/schemas.mjs +337 -0
  155. package/dist/routers/schemas.mjs.map +1 -0
  156. package/dist/routers/settings-general.mjs +104 -0
  157. package/dist/routers/settings-general.mjs.map +1 -0
  158. package/dist/routers/settings-labels.mjs +52 -0
  159. package/dist/routers/settings-labels.mjs.map +1 -0
  160. package/dist/routers/settings-members.mjs +58 -0
  161. package/dist/routers/settings-members.mjs.map +1 -0
  162. package/dist/routers/settings-notifications.mjs +108 -0
  163. package/dist/routers/settings-notifications.mjs.map +1 -0
  164. package/dist/routers/settings-status.mjs +77 -0
  165. package/dist/routers/settings-status.mjs.map +1 -0
  166. package/dist/routers/settings-tokens.mjs +40 -0
  167. package/dist/routers/settings-tokens.mjs.map +1 -0
  168. package/dist/routers/settings-webhooks.mjs +67 -0
  169. package/dist/routers/settings-webhooks.mjs.map +1 -0
  170. package/dist/routers/settings.handlers.mjs +149 -0
  171. package/dist/routers/settings.handlers.mjs.map +1 -0
  172. package/dist/routers/settings.mjs +25 -0
  173. package/dist/routers/settings.mjs.map +1 -0
  174. package/dist/routers/snapshots.mjs +240 -0
  175. package/dist/routers/snapshots.mjs.map +1 -0
  176. package/dist/routers/status-configs.mjs +108 -0
  177. package/dist/routers/status-configs.mjs.map +1 -0
  178. package/dist/routers/storybook.mjs +171 -0
  179. package/dist/routers/storybook.mjs.map +1 -0
  180. package/dist/routers/tokens.mjs +91 -0
  181. package/dist/routers/tokens.mjs.map +1 -0
  182. package/dist/routers/ui.mjs +166 -0
  183. package/dist/routers/ui.mjs.map +1 -0
  184. package/dist/routers/webhooks.mjs +97 -0
  185. package/dist/routers/webhooks.mjs.map +1 -0
  186. package/dist/routers/well-known.mjs +43 -0
  187. package/dist/routers/well-known.mjs.map +1 -0
  188. package/dist/runtime.mjs +52 -0
  189. package/dist/runtime.mjs.map +1 -0
  190. package/dist/store.mjs +20 -0
  191. package/dist/store.mjs.map +1 -0
  192. package/dist/ui/avatar.mjs +76 -0
  193. package/dist/ui/avatar.mjs.map +1 -0
  194. package/dist/ui/buttons.mjs +205 -0
  195. package/dist/ui/buttons.mjs.map +1 -0
  196. package/dist/ui/code-block.mjs +47 -0
  197. package/dist/ui/code-block.mjs.map +1 -0
  198. package/dist/ui/compare-stage.mjs +344 -0
  199. package/dist/ui/compare-stage.mjs.map +1 -0
  200. package/dist/ui/csrf-field.mjs +20 -0
  201. package/dist/ui/csrf-field.mjs.map +1 -0
  202. package/dist/ui/css.mjs +36 -0
  203. package/dist/ui/css.mjs.map +1 -0
  204. package/dist/ui/document.mjs +130 -0
  205. package/dist/ui/document.mjs.map +1 -0
  206. package/dist/ui/dropdown.mjs +181 -0
  207. package/dist/ui/dropdown.mjs.map +1 -0
  208. package/dist/ui/feedback.mjs +341 -0
  209. package/dist/ui/feedback.mjs.map +1 -0
  210. package/dist/ui/filter-input.mjs +58 -0
  211. package/dist/ui/filter-input.mjs.map +1 -0
  212. package/dist/ui/forms.mjs +291 -0
  213. package/dist/ui/forms.mjs.map +1 -0
  214. package/dist/ui/icons/icon.mjs +53 -0
  215. package/dist/ui/icons/icon.mjs.map +1 -0
  216. package/dist/ui/icons/paths.mjs +61 -0
  217. package/dist/ui/icons/paths.mjs.map +1 -0
  218. package/dist/ui/icons/sprite.mjs +26 -0
  219. package/dist/ui/icons/sprite.mjs.map +1 -0
  220. package/dist/ui/kbd.mjs +33 -0
  221. package/dist/ui/kbd.mjs.map +1 -0
  222. package/dist/ui/layout.mjs +173 -0
  223. package/dist/ui/layout.mjs.map +1 -0
  224. package/dist/ui/progress.mjs +44 -0
  225. package/dist/ui/progress.mjs.map +1 -0
  226. package/dist/ui/segmented.mjs +77 -0
  227. package/dist/ui/segmented.mjs.map +1 -0
  228. package/dist/ui/shell/account.mjs +161 -0
  229. package/dist/ui/shell/account.mjs.map +1 -0
  230. package/dist/ui/shell/bare.mjs +69 -0
  231. package/dist/ui/shell/bare.mjs.map +1 -0
  232. package/dist/ui/shell/boot-script.mjs +46 -0
  233. package/dist/ui/shell/boot-script.mjs.map +1 -0
  234. package/dist/ui/shell/client-script.mjs +259 -0
  235. package/dist/ui/shell/client-script.mjs.map +1 -0
  236. package/dist/ui/shell/nav.mjs +111 -0
  237. package/dist/ui/shell/nav.mjs.map +1 -0
  238. package/dist/ui/shell/review-script.mjs +195 -0
  239. package/dist/ui/shell/review-script.mjs.map +1 -0
  240. package/dist/ui/shell/sidebar.mjs +323 -0
  241. package/dist/ui/shell/sidebar.mjs.map +1 -0
  242. package/dist/ui/shell/topbar.mjs +268 -0
  243. package/dist/ui/shell/topbar.mjs.map +1 -0
  244. package/dist/ui/stacks.mjs +82 -0
  245. package/dist/ui/stacks.mjs.map +1 -0
  246. package/dist/ui/styles/base.mjs +41 -0
  247. package/dist/ui/styles/base.mjs.map +1 -0
  248. package/dist/ui/styles/behavior.mjs +43 -0
  249. package/dist/ui/styles/behavior.mjs.map +1 -0
  250. package/dist/ui/styles/review-layout.mjs +347 -0
  251. package/dist/ui/styles/review-layout.mjs.map +1 -0
  252. package/dist/ui/styles/review.mjs +86 -0
  253. package/dist/ui/styles/review.mjs.map +1 -0
  254. package/dist/ui/styles/tokens.mjs +132 -0
  255. package/dist/ui/styles/tokens.mjs.map +1 -0
  256. package/dist/ui/styles.mjs +19 -0
  257. package/dist/ui/styles.mjs.map +1 -0
  258. package/dist/ui/subnav.mjs +91 -0
  259. package/dist/ui/subnav.mjs.map +1 -0
  260. package/dist/ui/table.mjs +73 -0
  261. package/dist/ui/table.mjs.map +1 -0
  262. package/dist/ui/theme.mjs +64 -0
  263. package/dist/ui/theme.mjs.map +1 -0
  264. package/dist/ui/thumbnail.mjs +51 -0
  265. package/dist/ui/thumbnail.mjs.map +1 -0
  266. package/dist/ui/time.mjs +50 -0
  267. package/dist/ui/time.mjs.map +1 -0
  268. package/package.json +92 -0
@@ -0,0 +1,36 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { createCssContext } from "hono/css";
5
+ //#region src/ui/css.ts
6
+ /**
7
+ * hono/css building blocks for the server-rendered UI.
8
+ *
9
+ * A single custom context so every family module shares one `<style>`
10
+ * tag (mounted in `DocumentLayout`) and one readable naming scheme:
11
+ * start each `css` template with a label comment and it becomes the
12
+ * class-name prefix (`ss-btn-<hash>`). Unlabeled templates fall back to
13
+ * the default `css-<hash>`.
14
+ *
15
+ * Rules (enforced by `ui/consistency.test.ts`, see the `ui-building-blocks`
16
+ * skill for the full contract):
17
+ * - Import `css`/`cx`/`Style` from here, never from `hono/css` directly.
18
+ * - One `css` template per variant; compose via `${base}` extension so the
19
+ * label (and readable class name) survives. Do NOT compose variants with
20
+ * `cx` — it merges styles into a new unlabeled `css-<hash>` class.
21
+ * - Pseudo-states via `&` nesting inside the template.
22
+ * - Never interpolate runtime values (brand tokens stay as CSS vars in
23
+ * the global token `<style>` tag). Static maps only.
24
+ */
25
+ const context = createCssContext({
26
+ id: "storyshelf-css",
27
+ classNameSlug: (hash, label) => label ? `ss-${label}-${hash}` : hash
28
+ });
29
+ /** Create a labeled, hashed class for a static declaration block. */
30
+ const css = (strings, ...values) => context.css(strings, ...values);
31
+ /** Collects every used class into `<style id="storyshelf-css">`. */
32
+ const Style = (args) => context.Style(args);
33
+ //#endregion
34
+ export { Style, css };
35
+
36
+ //# sourceMappingURL=css.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"css.mjs","names":[],"sources":["../../src/ui/css.ts"],"sourcesContent":["/**\n * hono/css building blocks for the server-rendered UI.\n *\n * A single custom context so every family module shares one `<style>`\n * tag (mounted in `DocumentLayout`) and one readable naming scheme:\n * start each `css` template with a label comment and it becomes the\n * class-name prefix (`ss-btn-<hash>`). Unlabeled templates fall back to\n * the default `css-<hash>`.\n *\n * Rules (enforced by `ui/consistency.test.ts`, see the `ui-building-blocks`\n * skill for the full contract):\n * - Import `css`/`cx`/`Style` from here, never from `hono/css` directly.\n * - One `css` template per variant; compose via `${base}` extension so the\n * label (and readable class name) survives. Do NOT compose variants with\n * `cx` — it merges styles into a new unlabeled `css-<hash>` class.\n * - Pseudo-states via `&` nesting inside the template.\n * - Never interpolate runtime values (brand tokens stay as CSS vars in\n * the global token `<style>` tag). Static maps only.\n */\nimport { createCssContext } from \"hono/css\";\nimport type { HtmlEscapedString } from \"hono/utils/html\";\n\n/** Values allowed inside a `css` template (static only, never user input). */\nexport type CssValue = string | number | false | null | undefined | Promise<string>;\n\n/** A `css` template function with a publicly nameable type (see below). */\nexport type CssTemplate = (strings: TemplateStringsArray, ...values: CssValue[]) => Promise<string>;\n\n/** Class-name composer with a publicly nameable type (see below). */\nexport type CxFn = (\n ...args: Array<string | boolean | null | undefined | Promise<string>>\n) => Promise<string>;\n\n/** The `<Style />` tag with a publicly nameable type (see below). */\nexport type StyleTag = (args?: { children?: Promise<string>; nonce?: string }) => HtmlEscapedString;\n\nconst context = createCssContext({\n id: \"storyshelf-css\",\n classNameSlug: (hash, label) => (label ? `ss-${label}-${hash}` : hash),\n});\n\n// Thin wrappers (not direct re-exports): hono/css declares its function\n// types via private names, which `tsc --noEmit` rejects under\n// `declaration: true` (TS4023). These annotations keep the public surface\n// nameable while returning the identical runtime objects.\n/** Create a labeled, hashed class for a static declaration block. */\n// eslint-disable-next-line promise-function-async -- thin typed wrapper returning hono/css's own promise\nexport const css: CssTemplate = (strings, ...values) => context.css(strings, ...values);\n\n/** Compose classes and conditional values (falsy-safe). */\n// eslint-disable-next-line promise-function-async -- thin typed wrapper returning hono/css's own promise\nexport const cx: CxFn = (...args) => context.cx(...args);\n\n/** Collects every used class into `<style id=\"storyshelf-css\">`. */\nexport const Style: StyleTag = (args) => context.Style(args);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAoCA,MAAM,UAAU,iBAAiB;CAC/B,IAAI;CACJ,gBAAgB,MAAM,UAAW,QAAQ,MAAM,MAAM,GAAG,SAAS;AACnE,CAAC;;AAQD,MAAa,OAAoB,SAAS,GAAG,WAAW,QAAQ,IAAI,SAAS,GAAG,MAAM;;AAOtF,MAAa,SAAmB,SAAS,QAAQ,MAAM,IAAI"}
@@ -0,0 +1,130 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { getStore } from "../store.mjs";
5
+ import { getCsrfToken } from "../middleware/csrf.mjs";
6
+ import { Style, css } from "./css.mjs";
7
+ import { assetManifest } from "../asset-manifest.mjs";
8
+ import { BareShell } from "./shell/bare.mjs";
9
+ import { bootScript } from "./shell/boot-script.mjs";
10
+ import { clientScript } from "./shell/client-script.mjs";
11
+ import { Sidebar } from "./shell/sidebar.mjs";
12
+ import { ToastRegion, TopBar } from "./shell/topbar.mjs";
13
+ import { baseStyle } from "./styles.mjs";
14
+ import { DARK_THEME, LIGHT_THEME } from "./theme.mjs";
15
+ import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
16
+ import { raw } from "hono/html";
17
+ //#region src/ui/document.tsx
18
+ const shellRoot = css`
19
+ /* shell */
20
+ display: grid;
21
+ grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
22
+ min-height: 100vh;
23
+ @media (max-width: 880px) {
24
+ & {
25
+ grid-template-columns: minmax(0, 1fr);
26
+ }
27
+ }
28
+ `;
29
+ const shellContent = css`
30
+ /* shell-content */
31
+ width: 100%;
32
+ max-width: 1200px;
33
+ margin: 0 auto;
34
+ padding: var(--space-6) var(--space-6) var(--space-8);
35
+ min-width: 0;
36
+ @media (max-width: 880px) {
37
+ & {
38
+ padding: var(--space-4);
39
+ }
40
+ }
41
+ `;
42
+ const shellContentWide = css`
43
+ /* shell-content-wide */
44
+ ${shellContent}
45
+ max-width: none;
46
+ `;
47
+ const shellBackdrop = css`
48
+ /* shell-backdrop */
49
+ position: fixed;
50
+ inset: 0;
51
+ z-index: 55;
52
+ background: rgb(0 0 0 / 0.4);
53
+ &[hidden] {
54
+ display: none;
55
+ }
56
+ `;
57
+ /** Full HTML document shell with sidebar, top bar, theme, toasts, and HTMX. */
58
+ const DocumentLayout = ({ title, nav, layout = "default", children }) => {
59
+ const { ui, config, sessionId } = getStore();
60
+ const name = ui.name ?? "StoryShelf";
61
+ const logo = ui.logo ?? assetManifest.mark.href;
62
+ const light = ui.lightTheme ?? LIGHT_THEME;
63
+ const dark = ui.darkTheme ?? DARK_THEME;
64
+ return /* @__PURE__ */ jsxs(Fragment, { children: [raw("<!DOCTYPE html>"), /* @__PURE__ */ jsxs("html", {
65
+ lang: "en",
66
+ "data-theme": "system",
67
+ children: [/* @__PURE__ */ jsxs("head", { children: [
68
+ /* @__PURE__ */ jsx("meta", { charset: "utf-8" }),
69
+ /* @__PURE__ */ jsx("meta", {
70
+ name: "viewport",
71
+ content: "width=device-width, initial-scale=1"
72
+ }),
73
+ /* @__PURE__ */ jsx("meta", {
74
+ name: "color-scheme",
75
+ content: "light dark"
76
+ }),
77
+ /* @__PURE__ */ jsx("meta", {
78
+ name: "csrf-token",
79
+ content: getCsrfToken(config.secret, sessionId)
80
+ }),
81
+ /* @__PURE__ */ jsx("link", {
82
+ rel: "icon",
83
+ type: "image/svg+xml",
84
+ href: assetManifest.mark.href
85
+ }),
86
+ /* @__PURE__ */ jsxs("title", { children: [
87
+ title,
88
+ " · ",
89
+ name
90
+ ] }),
91
+ /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: baseStyle(light, dark) } }),
92
+ /* @__PURE__ */ jsx(Style, {}),
93
+ /* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: bootScript() } })
94
+ ] }), /* @__PURE__ */ jsxs("body", { children: [
95
+ /* @__PURE__ */ jsx("a", {
96
+ class: "skip-link",
97
+ href: "#main-content",
98
+ children: "Skip to content"
99
+ }),
100
+ layout === "bare" ? /* @__PURE__ */ jsx(BareShell, {
101
+ name,
102
+ logo,
103
+ children
104
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
105
+ class: shellRoot,
106
+ children: [/* @__PURE__ */ jsx(Sidebar, {
107
+ nav,
108
+ name,
109
+ logo
110
+ }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(TopBar, { nav }), /* @__PURE__ */ jsx("main", {
111
+ id: "main-content",
112
+ class: layout === "wide" ? shellContentWide : shellContent,
113
+ tabindex: -1,
114
+ children
115
+ })] })]
116
+ }), /* @__PURE__ */ jsx("div", {
117
+ class: shellBackdrop,
118
+ "data-sidebar-backdrop": true,
119
+ hidden: true
120
+ })] }),
121
+ /* @__PURE__ */ jsx(ToastRegion, {}),
122
+ /* @__PURE__ */ jsx("script", { src: assetManifest.htmx.href }),
123
+ /* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: clientScript() } })
124
+ ] })]
125
+ })] });
126
+ };
127
+ //#endregion
128
+ export { DocumentLayout };
129
+
130
+ //# sourceMappingURL=document.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document.mjs","names":[],"sources":["../../src/ui/document.tsx"],"sourcesContent":["import { raw } from \"hono/html\";\nimport type { FC } from \"hono/jsx\";\nimport { assetManifest } from \"../asset-manifest.ts\";\nimport { getCsrfToken } from \"../middleware/csrf.ts\";\nimport { getStore } from \"../store.ts\";\nimport { Style, css } from \"./css.ts\";\nimport { BareShell } from \"./shell/bare.tsx\";\nimport { bootScript } from \"./shell/boot-script.ts\";\nimport { clientScript } from \"./shell/client-script.ts\";\nimport type { NavConfig } from \"./shell/nav.ts\";\nimport { Sidebar } from \"./shell/sidebar.tsx\";\nimport { ToastRegion, TopBar } from \"./shell/topbar.tsx\";\nimport { baseStyle } from \"./styles.ts\";\nimport { DARK_THEME, LIGHT_THEME } from \"./theme.ts\";\n\n/* eslint-disable promise-function-async -- Hono JSX components return HtmlEscapedString | Promise<HtmlEscapedString> */\n\n/** Active section, project, and breadcrumb trail passed to the shell. */\nexport type { NavConfig };\n\n/** Rendered HTML content returned by page components. */\nexport type RenderedContent = string | Promise<string>;\n\n/**\n * Page frame: `default` is a readable column, `wide` uses the full viewport,\n * `bare` drops the app chrome (sign-in, invites).\n */\ntype PageLayout = \"default\" | \"wide\" | \"bare\";\n\nconst shellRoot = css`\n /* shell */\n display: grid;\n grid-template-columns: var(--sidebar-width) minmax(0, 1fr);\n min-height: 100vh;\n @media (max-width: 880px) {\n & {\n grid-template-columns: minmax(0, 1fr);\n }\n }\n`;\n\nconst shellContent = css`\n /* shell-content */\n width: 100%;\n max-width: 1200px;\n margin: 0 auto;\n padding: var(--space-6) var(--space-6) var(--space-8);\n min-width: 0;\n @media (max-width: 880px) {\n & {\n padding: var(--space-4);\n }\n }\n`;\n\nconst shellContentWide = css`\n /* shell-content-wide */\n ${shellContent}\n max-width: none;\n`;\n\nconst shellBackdrop = css`\n /* shell-backdrop */\n position: fixed;\n inset: 0;\n z-index: 55;\n background: rgb(0 0 0 / 0.4);\n &[hidden] {\n display: none;\n }\n`;\n\n// Hono's JSX.Element is typed as `HtmlEscapedString | Promise<...>`, so JSX-returning\n// Functions can legitimately return a promise; the rule is a false positive here.\n/** Full HTML document shell with sidebar, top bar, theme, toasts, and HTMX. */\nexport const DocumentLayout: FC<{\n title: string;\n nav?: NavConfig;\n layout?: PageLayout;\n children?: unknown;\n}> = ({ title, nav, layout = \"default\", children }) => {\n const { ui, config, sessionId } = getStore();\n const name = ui.name ?? \"StoryShelf\";\n const logo = ui.logo ?? assetManifest.mark.href;\n const light = ui.lightTheme ?? LIGHT_THEME;\n const dark = ui.darkTheme ?? DARK_THEME;\n\n return (\n <>\n {/* Without a doctype browsers use quirks mode (form margins, line-box struts, …). */}\n {raw(\"<!DOCTYPE html>\")}\n <html lang=\"en\" data-theme=\"system\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta name=\"color-scheme\" content=\"light dark\" />\n <meta name=\"csrf-token\" content={getCsrfToken(config.secret, sessionId)} />\n {/* Favicon is the product's own mark, not brandable: it identifies\n StoryShelf in the tab strip. `ui.logo` stays overridable. */}\n <link rel=\"icon\" type=\"image/svg+xml\" href={assetManifest.mark.href} />\n <title>\n {title} · {name}\n </title>\n <style dangerouslySetInnerHTML={{ __html: baseStyle(light, dark) }} />\n <Style />\n <script dangerouslySetInnerHTML={{ __html: bootScript() }} />\n </head>\n <body>\n <a class=\"skip-link\" href=\"#main-content\">\n Skip to content\n </a>\n {layout === \"bare\" ? (\n <BareShell name={name} logo={logo}>\n {children}\n </BareShell>\n ) : (\n <>\n <div class={shellRoot}>\n <Sidebar nav={nav} name={name} logo={logo} />\n <div>\n <TopBar nav={nav} />\n <main\n id=\"main-content\"\n class={layout === \"wide\" ? shellContentWide : shellContent}\n tabindex={-1}\n >\n {children}\n </main>\n </div>\n </div>\n <div class={shellBackdrop} data-sidebar-backdrop hidden />\n </>\n )}\n <ToastRegion />\n <script src={assetManifest.htmx.href} />\n <script dangerouslySetInnerHTML={{ __html: clientScript() }} />\n </body>\n </html>\n </>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AA6BA,MAAM,YAAY,GAAG;;;;;;;;;;;AAYrB,MAAM,eAAe,GAAG;;;;;;;;;;;;;AAcxB,MAAM,mBAAmB,GAAG;;IAExB,aAAa;;;AAIjB,MAAM,gBAAgB,GAAG;;;;;;;;;;;AAczB,MAAa,kBAKP,EAAE,OAAO,KAAK,SAAS,WAAW,eAAe;CACrD,MAAM,EAAE,IAAI,QAAQ,cAAc,SAAS;CAC3C,MAAM,OAAO,GAAG,QAAQ;CACxB,MAAM,OAAO,GAAG,QAAQ,cAAc,KAAK;CAC3C,MAAM,QAAQ,GAAG,cAAc;CAC/B,MAAM,OAAO,GAAG,aAAa;CAE7B,OACE,qBAAA,UAAA,EAAA,UAAA,CAEG,IAAI,iBAAiB,GACtB,qBAAC,QAAD;EAAM,MAAK;EAAK,cAAW;EAA3B,UAAA,CACE,qBAAC,QAAD,EAAA,UAAA;GACE,oBAAC,QAAD,EAAM,SAAQ,QAAS,CAAA;GACvB,oBAAC,QAAD;IAAM,MAAK;IAAW,SAAQ;GAAuC,CAAA;GACrE,oBAAC,QAAD;IAAM,MAAK;IAAe,SAAQ;GAAc,CAAA;GAChD,oBAAC,QAAD;IAAM,MAAK;IAAa,SAAS,aAAa,OAAO,QAAQ,SAAS;GAAI,CAAA;GAG1E,oBAAC,QAAD;IAAM,KAAI;IAAO,MAAK;IAAgB,MAAM,cAAc,KAAK;GAAO,CAAA;GACtE,qBAAC,SAAD,EAAA,UAAA;IACG;IAAM;IAAI;GACN,EAAA,CAAA;GACP,oBAAC,SAAD,EAAO,yBAAyB,EAAE,QAAQ,UAAU,OAAO,IAAI,EAAE,EAAI,CAAA;GACrE,oBAAC,OAAD,CAAQ,CAAA;GACR,oBAAC,UAAD,EAAQ,yBAAyB,EAAE,QAAQ,WAAW,EAAE,EAAI,CAAA;EACxD,EAAA,CAAA,GACN,qBAAC,QAAD,EAAA,UAAA;GACE,oBAAC,KAAD;IAAG,OAAM;IAAY,MAAK;IAAgB,UAAA;GAEvC,CAAA;GACF,WAAW,SACV,oBAAC,WAAD;IAAiB;IAAY;IAC1B;GACQ,CAAA,IAEX,qBAAA,UAAA,EAAA,UAAA,CACE,qBAAC,OAAD;IAAK,OAAO;IAAZ,UAAA,CACE,oBAAC,SAAD;KAAc;KAAW;KAAY;IAAO,CAAA,GAC5C,qBAAC,OAAD,EAAA,UAAA,CACE,oBAAC,QAAD,EAAa,IAAM,CAAA,GACnB,oBAAC,QAAD;KACE,IAAG;KACH,OAAO,WAAW,SAAS,mBAAmB;KAC9C,UAAU;KAET;IACG,CAAA,CACH,EAAA,CAAA,CACF;GACL,CAAA,GAAA,oBAAC,OAAD;IAAK,OAAO;IAAe,yBAAA;IAAsB,QAAA;GAAQ,CAAA,CACzD,EAAA,CAAA;GAEJ,oBAAC,aAAD,CAAc,CAAA;GACd,oBAAC,UAAD,EAAQ,KAAK,cAAc,KAAK,KAAO,CAAA;GACvC,oBAAC,UAAD,EAAQ,yBAAyB,EAAE,QAAQ,aAAa,EAAE,EAAI,CAAA;EAC1D,EAAA,CAAA,CACF;CACN,CAAA,CAAA,EAAA,CAAA;AAEN"}
@@ -0,0 +1,181 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { css } from "./css.mjs";
5
+ import { Icon } from "./icons/icon.mjs";
6
+ import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
7
+ //#region src/ui/dropdown.tsx
8
+ const dropdownRoot = css`
9
+ /* dropdown */
10
+ position: relative;
11
+ display: inline-block;
12
+ vertical-align: top;
13
+ `;
14
+ const dropdownRootBlock = css`
15
+ /* dropdown-block */
16
+ ${dropdownRoot}
17
+ display: block;
18
+ width: 100%;
19
+ `;
20
+ const dropdownTrigger = css`
21
+ /* dropdown-trigger */
22
+ list-style: none;
23
+ display: inline-flex;
24
+ align-items: center;
25
+ gap: 0.4rem;
26
+ min-height: 36px;
27
+ padding: 0.25rem 0.6rem;
28
+ border: 1px solid var(--border);
29
+ border-radius: var(--radius);
30
+ background: var(--surface-card);
31
+ color: var(--text-primary);
32
+ font-size: var(--text-base);
33
+ font-weight: 600;
34
+ cursor: pointer;
35
+ &::-webkit-details-marker {
36
+ display: none;
37
+ }
38
+ &:hover {
39
+ background: var(--surface-subtle);
40
+ }
41
+ `;
42
+ const dropdownTriggerGhost = css`
43
+ /* dropdown-trigger-ghost */
44
+ ${dropdownTrigger}
45
+ min-height: 34px;
46
+ width: 100%;
47
+ justify-content: space-between;
48
+ border-color: transparent;
49
+ background: transparent;
50
+ box-shadow: none;
51
+ &:hover {
52
+ background: var(--surface-muted);
53
+ }
54
+ `;
55
+ const dropdownMenu = css`
56
+ /* dropdown-menu */
57
+ position: absolute;
58
+ z-index: 50;
59
+ top: calc(100% + 4px);
60
+ left: 0;
61
+ min-width: 12rem;
62
+ padding: 0.25rem;
63
+ background: var(--surface-card);
64
+ border: 1px solid var(--border);
65
+ border-radius: var(--radius);
66
+ box-shadow: var(--shadow-2);
67
+ `;
68
+ const dropdownMenuEnd = css`
69
+ /* dropdown-menu-end */
70
+ ${dropdownMenu}
71
+ left: auto;
72
+ right: 0;
73
+ `;
74
+ const dropdownMenuAbove = css`
75
+ /* dropdown-menu-above */
76
+ ${dropdownMenu}
77
+ top: auto;
78
+ bottom: calc(100% + 4px);
79
+ `;
80
+ const dropdownMenuAboveEnd = css`
81
+ /* dropdown-menu-above-end */
82
+ ${dropdownMenuEnd}
83
+ top: auto;
84
+ bottom: calc(100% + 4px);
85
+ `;
86
+ const menuClasses = {
87
+ below: {
88
+ start: dropdownMenu,
89
+ end: dropdownMenuEnd
90
+ },
91
+ above: {
92
+ start: dropdownMenuAbove,
93
+ end: dropdownMenuAboveEnd
94
+ }
95
+ };
96
+ const dropdownItem = css`
97
+ /* dropdown-item */
98
+ appearance: none;
99
+ display: flex;
100
+ align-items: center;
101
+ gap: 0.5rem;
102
+ width: 100%;
103
+ padding: 0.45rem 0.6rem;
104
+ border: 0;
105
+ border-radius: var(--radius-sm);
106
+ background: transparent;
107
+ color: var(--text-primary);
108
+ font: inherit;
109
+ font-size: var(--text-base);
110
+ text-align: left;
111
+ text-decoration: none;
112
+ cursor: pointer;
113
+ &:hover {
114
+ background: var(--surface-muted);
115
+ text-decoration: none;
116
+ }
117
+ &[aria-current="true"] {
118
+ background: var(--accent-subtle);
119
+ color: var(--accent-fg);
120
+ }
121
+ `;
122
+ const dropdownDivider = css`
123
+ /* dropdown-divider */
124
+ height: 1px;
125
+ margin: 0.25rem 0;
126
+ background: var(--border-subtle);
127
+ `;
128
+ /** Popover menu built on native `<details>`; `align="end"` opens leftward. */
129
+ const Dropdown = ({ label, align = "start", ariaLabel, iconOnly = false, placement = "below", block = false, children }) => {
130
+ return /* @__PURE__ */ jsxs("details", {
131
+ class: block ? dropdownRootBlock : dropdownRoot,
132
+ "data-dropdown": true,
133
+ children: [/* @__PURE__ */ jsxs("summary", {
134
+ class: block ? dropdownTriggerGhost : dropdownTrigger,
135
+ "aria-label": ariaLabel,
136
+ children: [label, iconOnly ? null : /* @__PURE__ */ jsx(Icon, {
137
+ name: placement === "above" ? "chevron-up" : "chevron-down",
138
+ size: "sm"
139
+ })]
140
+ }), /* @__PURE__ */ jsx("div", {
141
+ class: menuClasses[placement][align],
142
+ role: "menu",
143
+ children
144
+ })]
145
+ });
146
+ };
147
+ /** Menu entry: a link when `href` is set, otherwise a button (forms, actions). */
148
+ const DropdownItem = ({ href, icon, current = false, children, ...rest }) => {
149
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [icon ? /* @__PURE__ */ jsx(Icon, {
150
+ name: icon,
151
+ size: "sm"
152
+ }) : null, children] });
153
+ const aria = current ? "true" : void 0;
154
+ if (href) return /* @__PURE__ */ jsx("a", {
155
+ class: dropdownItem,
156
+ role: "menuitem",
157
+ href,
158
+ "aria-current": aria,
159
+ ...rest,
160
+ children: content
161
+ });
162
+ return /* @__PURE__ */ jsx("button", {
163
+ class: dropdownItem,
164
+ role: "menuitem",
165
+ type: "button",
166
+ "aria-current": aria,
167
+ ...rest,
168
+ children: content
169
+ });
170
+ };
171
+ /** Hairline between menu groups. */
172
+ const DropdownDivider = () => {
173
+ return /* @__PURE__ */ jsx("div", {
174
+ class: dropdownDivider,
175
+ role: "separator"
176
+ });
177
+ };
178
+ //#endregion
179
+ export { Dropdown, DropdownDivider, DropdownItem };
180
+
181
+ //# sourceMappingURL=dropdown.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dropdown.mjs","names":[],"sources":["../../src/ui/dropdown.tsx"],"sourcesContent":["import type { FC } from \"hono/jsx\";\nimport { css } from \"./css.ts\";\nimport { Icon } from \"./icons/icon.tsx\";\nimport type { IconName } from \"./icons/paths.ts\";\n\n/* eslint-disable promise-function-async -- Hono JSX components return HtmlEscapedString | Promise<HtmlEscapedString> */\n\nconst dropdownRoot = css`\n /* dropdown */\n position: relative;\n display: inline-block;\n vertical-align: top;\n`;\n\nconst dropdownRootBlock = css`\n /* dropdown-block */\n ${dropdownRoot}\n display: block;\n width: 100%;\n`;\n\nconst dropdownTrigger = css`\n /* dropdown-trigger */\n list-style: none;\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n min-height: 36px;\n padding: 0.25rem 0.6rem;\n border: 1px solid var(--border);\n border-radius: var(--radius);\n background: var(--surface-card);\n color: var(--text-primary);\n font-size: var(--text-base);\n font-weight: 600;\n cursor: pointer;\n &::-webkit-details-marker {\n display: none;\n }\n &:hover {\n background: var(--surface-subtle);\n }\n`;\n\nconst dropdownTriggerGhost = css`\n /* dropdown-trigger-ghost */\n ${dropdownTrigger}\n min-height: 34px;\n width: 100%;\n justify-content: space-between;\n border-color: transparent;\n background: transparent;\n box-shadow: none;\n &:hover {\n background: var(--surface-muted);\n }\n`;\n\nconst dropdownMenu = css`\n /* dropdown-menu */\n position: absolute;\n z-index: 50;\n top: calc(100% + 4px);\n left: 0;\n min-width: 12rem;\n padding: 0.25rem;\n background: var(--surface-card);\n border: 1px solid var(--border);\n border-radius: var(--radius);\n box-shadow: var(--shadow-2);\n`;\n\nconst dropdownMenuEnd = css`\n /* dropdown-menu-end */\n ${dropdownMenu}\n left: auto;\n right: 0;\n`;\n\nconst dropdownMenuAbove = css`\n /* dropdown-menu-above */\n ${dropdownMenu}\n top: auto;\n bottom: calc(100% + 4px);\n`;\n\nconst dropdownMenuAboveEnd = css`\n /* dropdown-menu-above-end */\n ${dropdownMenuEnd}\n top: auto;\n bottom: calc(100% + 4px);\n`;\n\nconst menuClasses = {\n below: { start: dropdownMenu, end: dropdownMenuEnd },\n above: { start: dropdownMenuAbove, end: dropdownMenuAboveEnd },\n};\n\nconst dropdownItem = css`\n /* dropdown-item */\n appearance: none;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n padding: 0.45rem 0.6rem;\n border: 0;\n border-radius: var(--radius-sm);\n background: transparent;\n color: var(--text-primary);\n font: inherit;\n font-size: var(--text-base);\n text-align: left;\n text-decoration: none;\n cursor: pointer;\n &:hover {\n background: var(--surface-muted);\n text-decoration: none;\n }\n &[aria-current=\"true\"] {\n background: var(--accent-subtle);\n color: var(--accent-fg);\n }\n`;\n\nconst dropdownDivider = css`\n /* dropdown-divider */\n height: 1px;\n margin: 0.25rem 0;\n background: var(--border-subtle);\n`;\n\n/** Popover menu built on native `<details>`; `align=\"end\"` opens leftward. */\nexport const Dropdown: FC<{\n label: unknown;\n align?: \"start\" | \"end\";\n /** Accessible name when the label is only an icon or avatar. */\n ariaLabel?: string;\n /** Hide the trailing chevron (icon-only triggers). */\n iconOnly?: boolean;\n /** Open upward (menus anchored at the bottom of the screen). */\n placement?: \"below\" | \"above\";\n /** Full-width, borderless trigger (sidebar rows). */\n block?: boolean;\n children?: unknown;\n}> = ({\n label,\n align = \"start\",\n ariaLabel,\n iconOnly = false,\n placement = \"below\",\n block = false,\n children,\n}) => {\n return (\n <details class={block ? dropdownRootBlock : dropdownRoot} data-dropdown>\n <summary class={block ? dropdownTriggerGhost : dropdownTrigger} aria-label={ariaLabel}>\n {label}\n {iconOnly ? null : (\n <Icon name={placement === \"above\" ? \"chevron-up\" : \"chevron-down\"} size=\"sm\" />\n )}\n </summary>\n <div class={menuClasses[placement][align]} role=\"menu\">\n {children}\n </div>\n </details>\n );\n};\n\n/** Menu entry: a link when `href` is set, otherwise a button (forms, actions). */\nexport const DropdownItem: FC<{\n href?: string;\n icon?: IconName;\n current?: boolean;\n children?: unknown;\n [key: string]: unknown;\n}> = ({ href, icon, current = false, children, ...rest }) => {\n const content = (\n <>\n {icon ? <Icon name={icon} size=\"sm\" /> : null}\n {children}\n </>\n );\n const aria = current ? \"true\" : undefined;\n if (href) {\n return (\n <a class={dropdownItem} role=\"menuitem\" href={href} aria-current={aria} {...rest}>\n {content}\n </a>\n );\n }\n return (\n <button class={dropdownItem} role=\"menuitem\" type=\"button\" aria-current={aria} {...rest}>\n {content}\n </button>\n );\n};\n\n/** Hairline between menu groups. */\nexport const DropdownDivider: FC = () => {\n return <div class={dropdownDivider} role=\"separator\" />;\n};\n"],"mappings":";;;;;;;AAOA,MAAM,eAAe,GAAG;;;;;;AAOxB,MAAM,oBAAoB,GAAG;;IAEzB,aAAa;;;;AAKjB,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;AAuB3B,MAAM,uBAAuB,GAAG;;IAE5B,gBAAgB;;;;;;;;;;;AAYpB,MAAM,eAAe,GAAG;;;;;;;;;;;;;AAcxB,MAAM,kBAAkB,GAAG;;IAEvB,aAAa;;;;AAKjB,MAAM,oBAAoB,GAAG;;IAEzB,aAAa;;;;AAKjB,MAAM,uBAAuB,GAAG;;IAE5B,gBAAgB;;;;AAKpB,MAAM,cAAc;CAClB,OAAO;EAAE,OAAO;EAAc,KAAK;CAAgB;CACnD,OAAO;EAAE,OAAO;EAAmB,KAAK;CAAqB;AAC/D;AAEA,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BxB,MAAM,kBAAkB,GAAG;;;;;;;AAQ3B,MAAa,YAYP,EACJ,OACA,QAAQ,SACR,WACA,WAAW,OACX,YAAY,SACZ,QAAQ,OACR,eACI;CACJ,OACE,qBAAC,WAAD;EAAS,OAAO,QAAQ,oBAAoB;EAAc,iBAAA;EAA1D,UAAA,CACE,qBAAC,WAAD;GAAS,OAAO,QAAQ,uBAAuB;GAAiB,cAAY;GAA5E,UAAA,CACG,OACA,WAAW,OACV,oBAAC,MAAD;IAAM,MAAM,cAAc,UAAU,eAAe;IAAgB,MAAK;GAAM,CAAA,CAEzE;EACT,CAAA,GAAA,oBAAC,OAAD;GAAK,OAAO,YAAY,UAAU,CAAC;GAAQ,MAAK;GAC7C;EACE,CAAA,CACE;;AAEb;;AAGA,MAAa,gBAMP,EAAE,MAAM,MAAM,UAAU,OAAO,UAAU,GAAG,WAAW;CAC3D,MAAM,UACJ,qBAAA,UAAA,EAAA,UAAA,CACG,OAAO,oBAAC,MAAD;EAAM,MAAM;EAAM,MAAK;CAAM,CAAA,IAAI,MACxC,QACD,EAAA,CAAA;CAEJ,MAAM,OAAO,UAAU,SAAS,KAAA;CAChC,IAAI,MACF,OACE,oBAAC,KAAD;EAAG,OAAO;EAAc,MAAK;EAAiB;EAAM,gBAAc;EAAM,GAAI;EACzE,UAAA;CACA,CAAA;CAGP,OACE,oBAAC,UAAD;EAAQ,OAAO;EAAc,MAAK;EAAW,MAAK;EAAS,gBAAc;EAAM,GAAI;EAChF,UAAA;CACK,CAAA;AAEZ;;AAGA,MAAa,wBAA4B;CACvC,OAAO,oBAAC,OAAD;EAAK,OAAO;EAAiB,MAAK;CAAa,CAAA;AACxD"}