@heyramzi/ui 2.0.1 → 2.2.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 (341) hide show
  1. package/package.json +48 -24
  2. package/scripts/sync-shadcn.mjs +3 -4
  3. package/src/agents/agent-avatar.svelte +604 -575
  4. package/src/agents/agent-cast.svelte +179 -183
  5. package/src/agents/demo.svelte +125 -113
  6. package/src/agents/helpers.ts +23 -17
  7. package/src/agents/index.ts +4 -4
  8. package/src/agents/page-state.ts +6 -6
  9. package/src/agents/types.ts +6 -6
  10. package/src/ai/ai-button/AiButton.svelte +4 -12
  11. package/src/ai/generation-progress/GenerationProgress.svelte +10 -3
  12. package/src/ai/prompt-input/PromptInputTextarea.svelte +1 -2
  13. package/src/ai/response/Response.css +2 -3
  14. package/src/animations/avatar-group-hover.css +2 -16
  15. package/src/animations/card-tilt.css +3 -6
  16. package/src/animations/digit-pop-in.css +2 -15
  17. package/src/animations/dropdown.css +4 -17
  18. package/src/animations/input-clear-dissolve.css +5 -18
  19. package/src/animations/input-shake.css +9 -41
  20. package/src/animations/learn-more-hover.css +17 -9
  21. package/src/animations/like-button.css +2 -4
  22. package/src/animations/page-side-by-side.css +2 -10
  23. package/src/animations/plus-menu-morph.css +2 -5
  24. package/src/animations/shimmer-text.css +5 -18
  25. package/src/animations/spinning-counter.css +2 -6
  26. package/src/animations/success-check.css +2 -15
  27. package/src/animations/thinking-states.css +2 -7
  28. package/src/brand/brand.test.ts +21 -5
  29. package/src/brand/index.ts +4 -10
  30. package/src/canvas/README.md +9 -12
  31. package/src/canvas/card/card-frame.svelte +43 -39
  32. package/src/canvas/card/resize-handles.svelte +89 -80
  33. package/src/canvas/chrome/chrome-zoom.svelte +101 -100
  34. package/src/canvas/chrome/lock-badge.svelte +8 -8
  35. package/src/canvas/chrome/side-handles.svelte +24 -19
  36. package/src/canvas/chrome/size-chip.svelte +30 -30
  37. package/src/canvas/chrome/snap-guides.svelte +20 -20
  38. package/src/canvas/components/icons/ToolIcon.svelte +8 -8
  39. package/src/canvas/components/shared/svg/PreviewSvg.svelte +19 -19
  40. package/src/canvas/components/shared/svg/ShapeOutline.svelte +71 -48
  41. package/src/canvas/components/shared/svg/StrokeNode.svelte +21 -27
  42. package/src/canvas/components/shared/svg/TextRule.svelte +25 -17
  43. package/src/canvas/edges/bend-handle.svelte +46 -46
  44. package/src/canvas/edges/edge-gradient.svelte +10 -10
  45. package/src/canvas/edges/gradient-edge.svelte +45 -29
  46. package/src/canvas/editor/lock.test.ts +6 -1
  47. package/src/canvas/editor/style.ts +7 -1
  48. package/src/canvas/headless/svg-figure.test.ts +5 -1
  49. package/src/canvas/lod/lod-switch.svelte +111 -106
  50. package/src/canvas/pen/PenField.svelte +87 -81
  51. package/src/canvas/pen/PenOverlay.svelte +127 -127
  52. package/src/canvas/pen/ShapeNode.svelte +31 -32
  53. package/src/canvas/pen/TextNode.svelte +54 -53
  54. package/src/canvas/pen/host-field.test.svelte +7 -7
  55. package/src/canvas/pen/shapes.ts +7 -1
  56. package/src/canvas/screen/GlyphIcon.svelte +22 -17
  57. package/src/canvas/screen/PartView.svelte +138 -72
  58. package/src/canvas/screen/ScreenBody.svelte +81 -60
  59. package/src/canvas/screen/ScreenCard.svelte +20 -20
  60. package/src/canvas/ui/CanvasToolbar.svelte +173 -85
  61. package/src/canvas/ui/FrameLayer.svelte +59 -59
  62. package/src/canvas/ui/PenLayer.svelte +39 -30
  63. package/src/canvas/ui/StylePanel.svelte +119 -102
  64. package/src/canvas/ui/canvas-grid.svelte +137 -129
  65. package/src/charts/animated-value.svelte +1 -1
  66. package/src/charts/area-chart.css +2 -5
  67. package/src/charts/area-chart.svelte +1 -1
  68. package/src/charts/bar-chart.css +2 -3
  69. package/src/charts/bar-chart.svelte +1 -1
  70. package/src/charts/charts.css +5 -17
  71. package/src/charts/crosshair.svelte +1 -1
  72. package/src/charts/dashboard/dashboard-empty.svelte +25 -25
  73. package/src/charts/dashboard/dashboard-section.svelte +24 -24
  74. package/src/charts/dashboard/data-panel.svelte +50 -50
  75. package/src/charts/dashboard/data-sort-head.svelte +56 -56
  76. package/src/charts/dashboard/data-table.svelte +138 -138
  77. package/src/charts/dashboard/panel-grid.svelte +30 -30
  78. package/src/charts/dashboard/period-filter.svelte +25 -25
  79. package/src/charts/dashboard/rating-chip.svelte +19 -19
  80. package/src/charts/dashboard/stat-band.svelte +32 -32
  81. package/src/charts/dashboard/stat-tile.svelte +106 -99
  82. package/src/charts/donut-chart.svelte +1 -1
  83. package/src/charts/edge-fade.svelte +1 -1
  84. package/src/charts/figure.svelte +1 -1
  85. package/src/charts/gauge-chart.css +4 -7
  86. package/src/charts/gauge-chart.svelte +1 -1
  87. package/src/charts/hover-focus.svelte +1 -1
  88. package/src/charts/legend.css +1 -3
  89. package/src/charts/legend.svelte +1 -1
  90. package/src/charts/line-chart.svelte +1 -1
  91. package/src/charts/number-chart.css +6 -9
  92. package/src/charts/number-chart.svelte +1 -1
  93. package/src/charts/reference-line.svelte +19 -19
  94. package/src/charts/reveal.svelte +1 -1
  95. package/src/charts/ring-chart.css +2 -4
  96. package/src/charts/ring-chart.svelte +1 -1
  97. package/src/charts/sparkline.svelte +5 -2
  98. package/src/charts/stat-card.svelte +1 -1
  99. package/src/charts/time-series-chart.css +2 -5
  100. package/src/charts/trend-pill.css +2 -4
  101. package/src/charts/trend-pill.svelte +1 -1
  102. package/src/components/copy/copy-button.svelte +93 -98
  103. package/src/components/copy/copy-button.test.ts +10 -2
  104. package/src/components/data-table/infinite-scroll.svelte +42 -42
  105. package/src/components/data-table/pagination.svelte +34 -22
  106. package/src/components/data-table/row-arrow.svelte +19 -16
  107. package/src/components/data-table/row-context-menu.svelte +52 -52
  108. package/src/components/data-table/sortable-head.svelte +25 -25
  109. package/src/components/data-table/table-skeleton.svelte +41 -36
  110. package/src/components/docs/doc-page.svelte +18 -9
  111. package/src/components/docs/on-this-page.svelte +16 -3
  112. package/src/components/docs/scroll-spy.svelte.ts +2 -3
  113. package/src/components/field-row/field-row.svelte +10 -8
  114. package/src/components/hold-to-confirm/hold-to-confirm.svelte +5 -1
  115. package/src/components/icon/icon.svelte +14 -14
  116. package/src/components/language-flag/language-flag.svelte +3 -1
  117. package/src/components/list-page/detail-empty.svelte +34 -34
  118. package/src/components/list-page/detail-header.svelte +55 -47
  119. package/src/components/list-page/detail-panel.svelte +51 -59
  120. package/src/components/list-page/detail-row.svelte +19 -19
  121. package/src/components/list-page/detail-stack.svelte +21 -21
  122. package/src/components/list-page/empty-state.svelte +30 -30
  123. package/src/components/list-page/filter-item.svelte +20 -20
  124. package/src/components/list-page/filter-popover.svelte +60 -55
  125. package/src/components/list-page/grouped-list.svelte +4 -2
  126. package/src/components/list-page/index.ts +8 -4
  127. package/src/components/list-page/list-page-shell.svelte +2 -5
  128. package/src/components/list-page/master-detail.svelte +87 -88
  129. package/src/components/list-page/notice-bar.svelte +38 -38
  130. package/src/components/list-page/prev-next.svelte +63 -63
  131. package/src/components/list-page/rail-body.svelte +18 -18
  132. package/src/components/list-page/rail-empty.svelte +23 -30
  133. package/src/components/list-page/rail-head.svelte +24 -24
  134. package/src/components/list-page/rail-row.svelte +77 -73
  135. package/src/components/list-page/section-host.ts +2 -3
  136. package/src/components/locale-switch/locale-switch.svelte +41 -41
  137. package/src/components/mark/mark.svelte +34 -38
  138. package/src/components/open-in/index.ts +1 -5
  139. package/src/components/open-in/open-in.svelte +40 -40
  140. package/src/components/picker/mark-picker.svelte +49 -49
  141. package/src/components/picker/picker.svelte +5 -3
  142. package/src/components/section-header/index.ts +1 -0
  143. package/src/components/section-header/section-header.svelte +1 -1
  144. package/src/components/section-header/section-header.test.ts +7 -1
  145. package/src/components/section-header/section-label.svelte +39 -0
  146. package/src/components/segmented/animated-tabs.svelte +31 -2
  147. package/src/components/segmented/collapse.test.ts +2 -1
  148. package/src/components/segmented/index.ts +2 -0
  149. package/src/components/segmented/segment.svelte +52 -49
  150. package/src/components/segmented/segmented-filter.svelte +79 -80
  151. package/src/components/segmented/segmented-nav.svelte +34 -40
  152. package/src/components/segmented/segmented-overflow.svelte +53 -50
  153. package/src/components/segmented/segmented-track.svelte +62 -46
  154. package/src/components/segmented/segmented.ts +2 -3
  155. package/src/components/star-rating-input/star-rating-input.svelte +103 -103
  156. package/src/components/svg/svg.svelte +4 -4
  157. package/src/components/table-view/table-view.svelte +17 -2
  158. package/src/components/table-view/table-view.test.ts +7 -1
  159. package/src/components/table-view/types.ts +11 -11
  160. package/src/components/tags-input/index.ts +13 -0
  161. package/src/components/tags-input/tags-input.svelte +305 -0
  162. package/src/components/tags-input/tags.test.ts +64 -0
  163. package/src/components/tags-input/tags.ts +142 -0
  164. package/src/components/theme/index.ts +2 -4
  165. package/src/components/theme/theme-provider.svelte +1 -3
  166. package/src/components/toolbar/index.ts +2 -0
  167. package/src/components/{list-page → toolbar}/toolbar-search.svelte +25 -25
  168. package/src/components/toolbar/toolbar.svelte +13 -9
  169. package/src/components/toolbar/toolbar.test.ts +10 -1
  170. package/src/design/index.css +21 -78
  171. package/src/design/polish.css +26 -35
  172. package/src/editor/editor-toolbar.svelte +104 -99
  173. package/src/editor/editor.svelte +296 -266
  174. package/src/editor/image-toolbar.svelte +20 -22
  175. package/src/editor/index.ts +1 -4
  176. package/src/editor/inline-editor.svelte +280 -238
  177. package/src/editor/markdown.ts +15 -15
  178. package/src/editor/renderer.svelte +71 -71
  179. package/src/editor/slash-menu.svelte +24 -27
  180. package/src/effects/animated-beam/diagrams/BeamSvg.svelte +1 -1
  181. package/src/effects/image-comparison/ImageComparison.svelte +11 -1
  182. package/src/effects/interactive-hover-button/InteractiveHoverButton.svelte +59 -46
  183. package/src/effects/magic-card/MagicCard.css +14 -7
  184. package/src/effects/marquee/Marquee.svelte +3 -5
  185. package/src/effects/reveal/observe.ts +0 -3
  186. package/src/effects/spotlight/Spotlight.svelte +1 -1
  187. package/src/effects/theme-toggle/ThemeToggle.css +25 -22
  188. package/src/effects/theme-toggle/ThemeToggle.svelte +6 -7
  189. package/src/gallery.test.ts +14 -4
  190. package/src/inbox/README.md +27 -0
  191. package/src/inbox/inbox.test.ts +214 -0
  192. package/src/inbox/index.ts +31 -0
  193. package/src/inbox/logic.ts +169 -0
  194. package/src/inbox/thread-inbox.svelte +439 -0
  195. package/src/inbox/types.ts +161 -0
  196. package/src/lib/theme-transition.ts +2 -4
  197. package/src/lib/tone.ts +2 -4
  198. package/src/lib/utils.ts +2 -2
  199. package/src/modules.test.ts +105 -0
  200. package/src/onboarding/define-tours.test.ts +55 -40
  201. package/src/onboarding/define-tours.ts +23 -23
  202. package/src/onboarding/demo.svelte +24 -5
  203. package/src/onboarding/index.ts +1 -8
  204. package/src/onboarding/onboarding-provider.svelte +19 -7
  205. package/src/onboarding/onboarding.svelte.ts +16 -16
  206. package/src/onboarding/pick.test.ts +61 -52
  207. package/src/onboarding/pick.ts +16 -13
  208. package/src/onboarding/stores.test.ts +80 -80
  209. package/src/onboarding/stores.ts +41 -39
  210. package/src/onboarding/tour-card.svelte +30 -5
  211. package/src/onboarding/tour-runner.svelte +12 -3
  212. package/src/onboarding/types.ts +20 -12
  213. package/src/onboarding/wait.ts +22 -22
  214. package/src/panel/README.md +5 -0
  215. package/src/panel/index.ts +2 -0
  216. package/src/panel/side-panel.svelte +194 -0
  217. package/src/record/README.md +3 -0
  218. package/src/record/demo-data.ts +352 -0
  219. package/src/record/field-section.svelte +57 -0
  220. package/src/record/fields.ts +194 -0
  221. package/src/record/format.ts +94 -0
  222. package/src/{tasks/record → record}/index.ts +49 -35
  223. package/src/{tasks/record → record}/info-list.svelte +145 -114
  224. package/src/record/kinds.ts +42 -0
  225. package/src/record/logic.ts +326 -0
  226. package/src/record/next-up.svelte +81 -0
  227. package/src/{tasks/record → record}/project-list.svelte +56 -50
  228. package/src/{tasks/record → record}/record-demo.svelte +130 -110
  229. package/src/{tasks/record → record}/record-header.svelte +37 -28
  230. package/src/{tasks/record → record}/record-shell.svelte +54 -54
  231. package/src/record/record-stats.svelte +48 -0
  232. package/src/record/record-timeline.svelte +251 -0
  233. package/src/record/record.test.ts +471 -0
  234. package/src/{tasks/record → record}/steps-rail.svelte +225 -216
  235. package/src/record/types.ts +299 -0
  236. package/src/record/where-we-are.svelte +125 -0
  237. package/src/shadcn/button/button.svelte +1 -1
  238. package/src/shadcn/card/card-title.svelte +1 -5
  239. package/src/shadcn/hooks/use-highlighted-code.svelte.ts +2 -13
  240. package/src/shadcn/sheet/sheet-content.svelte +2 -4
  241. package/src/shadcn/table/table-cell.svelte +2 -3
  242. package/src/shadcn/utilities.css +3 -8
  243. package/src/slides/Controls.svelte +150 -124
  244. package/src/slides/Deck.svelte +243 -238
  245. package/src/slides/Fragment.svelte +64 -57
  246. package/src/slides/Overview.svelte +106 -101
  247. package/src/slides/Presenter.svelte +300 -266
  248. package/src/slides/Slide.svelte +185 -170
  249. package/src/slides/SlideList.svelte +16 -12
  250. package/src/slides/ambient.d.ts +1 -1
  251. package/src/slides/bridges.ts +42 -23
  252. package/src/slides/deck-controller.svelte.ts +47 -35
  253. package/src/slides/demo-slides.svelte +330 -306
  254. package/src/slides/demo.svelte +164 -160
  255. package/src/slides/export/capture.ts +20 -16
  256. package/src/slides/export/ffmpeg.ts +43 -38
  257. package/src/slides/export/index.ts +5 -5
  258. package/src/slides/export/launch.ts +3 -1
  259. package/src/slides/export/pdf.ts +30 -27
  260. package/src/slides/export/types.ts +10 -8
  261. package/src/slides/index.ts +11 -11
  262. package/src/slides/labels.ts +22 -19
  263. package/src/slides/layout.ts +9 -2
  264. package/src/slides/model.ts +4 -4
  265. package/src/slides/navigation.ts +43 -31
  266. package/src/slides/theme.css +5 -7
  267. package/src/slides/types.ts +9 -10
  268. package/src/status/README.md +18 -0
  269. package/src/status/define-statuses.ts +25 -0
  270. package/src/status/index.ts +11 -0
  271. package/src/{tasks → status}/status-badge.svelte +3 -1
  272. package/src/{tasks → status}/status-dot.svelte +1 -3
  273. package/src/{tasks → status}/status-icon.svelte +1 -1
  274. package/src/status/status-types.ts +40 -0
  275. package/src/tasks/README.md +1 -1
  276. package/src/tasks/board-order.ts +2 -4
  277. package/src/tasks/demo.svelte +192 -34
  278. package/src/tasks/detail/detail-demo.svelte +75 -15
  279. package/src/tasks/detail/detail-types.ts +45 -45
  280. package/src/tasks/detail/task-detail.svelte +40 -10
  281. package/src/tasks/detail/task-property.svelte +8 -2
  282. package/src/tasks/detail/task-thread.svelte +53 -12
  283. package/src/tasks/gantt/gantt-bar.svelte +17 -6
  284. package/src/tasks/gantt/gantt-grid.svelte +40 -9
  285. package/src/tasks/gantt/gantt-group-row.svelte +8 -2
  286. package/src/tasks/gantt/gantt-header.svelte +9 -3
  287. package/src/tasks/gantt/gantt-task-row.svelte +26 -6
  288. package/src/tasks/gantt/gantt.css +2 -1
  289. package/src/tasks/gantt/gantt.test.ts +4 -2
  290. package/src/tasks/gantt/logic.test.ts +110 -20
  291. package/src/tasks/gantt/logic.ts +42 -6
  292. package/src/tasks/inbox/inbox-card.svelte +15 -7
  293. package/src/tasks/inbox/inbox-draft.svelte +1 -1
  294. package/src/tasks/inbox/inbox-logic.ts +6 -40
  295. package/src/tasks/inbox/inbox-statuses.ts +24 -24
  296. package/src/tasks/inbox/inbox-trace.svelte +9 -3
  297. package/src/tasks/inbox/inbox-types.ts +54 -58
  298. package/src/tasks/inbox/index.ts +22 -21
  299. package/src/tasks/index.ts +52 -53
  300. package/src/tasks/kanban-board.svelte +16 -12
  301. package/src/tasks/kanban-types.ts +2 -3
  302. package/src/tasks/presets/sales.ts +7 -7
  303. package/src/tasks/task-gantt.svelte +28 -8
  304. package/src/tasks/task-list.svelte +41 -17
  305. package/src/tasks/time/duration.ts +40 -40
  306. package/src/tasks/time/time-chip.svelte +9 -2
  307. package/src/tasks/time/time-dot.svelte +1 -1
  308. package/src/tasks/time/time-ring.svelte +11 -3
  309. package/src/tasks/time/time-tracker.svelte +57 -15
  310. package/src/tasks/time/time-types.ts +57 -57
  311. package/src/tasks/use-kanban-dnd.svelte.ts +2 -3
  312. package/src/thread/README.md +31 -0
  313. package/src/thread/index.ts +12 -0
  314. package/src/thread/logic.ts +61 -0
  315. package/src/thread/thread.svelte +432 -0
  316. package/src/thread/thread.test.ts +73 -0
  317. package/src/thread/types.ts +93 -0
  318. package/src/tokens/craft.css +17 -53
  319. package/src/tokens/index.css +3 -13
  320. package/src/tokens/palette.css +13 -11
  321. package/src/tokens/primitives.css +10 -23
  322. package/src/components/list-page/section-label.svelte +0 -39
  323. package/src/tasks/define-statuses.ts +0 -32
  324. package/src/tasks/inbox/inbox.svelte +0 -203
  325. package/src/tasks/record/demo-data.ts +0 -286
  326. package/src/tasks/record/field-section.svelte +0 -53
  327. package/src/tasks/record/fields.ts +0 -142
  328. package/src/tasks/record/format.ts +0 -87
  329. package/src/tasks/record/kinds.ts +0 -42
  330. package/src/tasks/record/logic.ts +0 -324
  331. package/src/tasks/record/next-up.svelte +0 -70
  332. package/src/tasks/record/record-stats.svelte +0 -48
  333. package/src/tasks/record/record-timeline.svelte +0 -231
  334. package/src/tasks/record/record.test.ts +0 -350
  335. package/src/tasks/record/types.ts +0 -280
  336. package/src/tasks/record/where-we-are.svelte +0 -121
  337. package/src/tasks/side-panel.svelte +0 -193
  338. package/src/tasks/status-types.ts +0 -40
  339. /package/src/components/{list-page → toolbar}/toolbar-trigger.ts +0 -0
  340. /package/src/{tasks → panel}/side-panel-types.ts +0 -0
  341. /package/src/{tasks/record → record}/gutter.ts +0 -0
@@ -1,91 +1,94 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import type { Snippet } from "svelte";
6
- import { setContext } from "svelte";
7
- import { CaretLeft } from "phosphor-svelte";
8
- import { cn } from "../../lib/utils.js";
9
- import { Button } from "../../shadcn/button/index.js";
10
- import { MASTER_DETAIL_PANE, type MasterDetailPane } from "./queue-rail.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import type { Snippet } from "svelte";
6
+ import { setContext } from "svelte";
7
+ import { CaretLeft } from "phosphor-svelte";
8
+ import { cn } from "../../lib/utils.js";
9
+ import { Button } from "../../shadcn/button/index.js";
10
+ import {
11
+ MASTER_DETAIL_PANE,
12
+ type MasterDetailPane,
13
+ } from "./queue-rail.js";
11
14
 
12
- // =========================
13
- // TYPES
14
- // =========================
15
- interface Props {
16
- // The list rail (an <aside>) and the content pane. Pages style both; this
17
- // shell owns the two columns and the min-h-0/min-w-0 scroll containment.
18
- rail: Snippet;
19
- detail: Snippet;
20
- // A full-width strip above both columns for facts to read before acting,
21
- // like a posting cap. Pages wrapping the shell to add one broke the padding.
22
- banner?: Snippet;
23
- // WHY: a CSS grid track for the rail column ("16rem", "minmax(280px, 340px)").
24
- // Queue pages pass `queueRailWidth` rather than a literal.
25
- railWidth?: string;
26
- // Stack to one column below this. "lg" because rail and detail can't both be
27
- // read under 1024px. null only for a rail narrow enough for a phone.
28
- stackBelow?: "lg" | "xl" | null;
29
- // WHY: the phone back button says where it goes back to. "Back" alone is the
30
- // browser's word and the reader has to remember what they left.
31
- backLabel?: string;
32
- // Bindable so a url naming a record opens on it after a refresh or a pasted
33
- // link. The page sets it. Ignored above the stack breakpoint.
34
- pane?: "rail" | "detail";
35
- gap?: boolean;
36
- pad?: boolean;
37
- railClass?: string;
38
- detailClass?: string;
39
- class?: string;
40
- };
15
+ // =========================
16
+ // TYPES
17
+ // =========================
18
+ interface Props {
19
+ // The list rail (an <aside>) and the content pane. Pages style both; this
20
+ // shell owns the two columns and the min-h-0/min-w-0 scroll containment.
21
+ rail: Snippet;
22
+ detail: Snippet;
23
+ // A full-width strip above both columns for facts to read before acting,
24
+ // like a posting cap. Pages wrapping the shell to add one broke the padding.
25
+ banner?: Snippet;
26
+ // WHY: a CSS grid track for the rail column ("16rem", "minmax(280px, 340px)").
27
+ // Queue pages pass `queueRailWidth` rather than a literal.
28
+ railWidth?: string;
29
+ // Stack to one column below this. "lg" because rail and detail can't both be
30
+ // read under 1024px. null only for a rail narrow enough for a phone.
31
+ stackBelow?: "lg" | "xl" | null;
32
+ // WHY: the phone back button says where it goes back to. "Back" alone is the
33
+ // browser's word and the reader has to remember what they left.
34
+ backLabel?: string;
35
+ // Bindable so a url naming a record opens on it after a refresh or a pasted
36
+ // link. The page sets it. Ignored above the stack breakpoint.
37
+ pane?: "rail" | "detail";
38
+ gap?: boolean;
39
+ pad?: boolean;
40
+ railClass?: string;
41
+ detailClass?: string;
42
+ class?: string;
43
+ }
41
44
 
42
- // =========================
43
- // PROPS
44
- // =========================
45
- let {
46
- rail,
47
- detail,
48
- banner,
49
- railWidth = "minmax(260px, 320px)",
50
- stackBelow = "lg",
51
- backLabel = "Back to the list",
52
- // The rail wins by default: an unpicked detail is an empty state or a
53
- // guessed row, both worse than the list.
54
- pane = $bindable("rail"),
55
- gap = true,
56
- pad = true,
57
- railClass,
58
- detailClass,
59
- class: className,
60
- }: Props = $props();
45
+ // =========================
46
+ // PROPS
47
+ // =========================
48
+ let {
49
+ rail,
50
+ detail,
51
+ banner,
52
+ railWidth = "minmax(260px, 320px)",
53
+ stackBelow = "lg",
54
+ backLabel = "Back to the list",
55
+ // The rail wins by default: an unpicked detail is an empty state or a
56
+ // guessed row, both worse than the list.
57
+ pane = $bindable("rail"),
58
+ gap = true,
59
+ pad = true,
60
+ railClass,
61
+ detailClass,
62
+ class: className,
63
+ }: Props = $props();
61
64
 
62
- // =========================
63
- // DERIVED
64
- // =========================
65
- // One pane at a time when stacked. Two rows put a 34svh list scroller on top of
66
- // a record scroller, and neither was readable.
67
- let gridClass = $derived(
68
- stackBelow === "xl"
69
- ? "grid-cols-1 grid-rows-[minmax(0,1fr)] xl:grid-rows-1 xl:[grid-template-columns:var(--md-cols)]"
70
- : stackBelow === "lg"
71
- ? "grid-cols-1 grid-rows-[minmax(0,1fr)] lg:grid-rows-1 lg:[grid-template-columns:var(--md-cols)]"
72
- : "[grid-template-columns:var(--md-cols)]",
73
- );
74
- // Hidden while stacked; back to normal above the breakpoint, where both panes show.
75
- let hideWhileStacked = $derived(stackBelow === "xl" ? "max-xl:hidden" : "max-lg:hidden");
76
- // Drawn only while stacked. The back bar has no job beside a visible rail.
77
- let stackedOnly = $derived(stackBelow === "xl" ? "xl:hidden" : "lg:hidden");
65
+ // =========================
66
+ // DERIVED
67
+ // =========================
68
+ // One pane at a time when stacked. Two rows put a 34svh list scroller on top of
69
+ // a record scroller, and neither was readable.
70
+ let gridClass = $derived(
71
+ stackBelow === "xl"
72
+ ? "grid-cols-1 grid-rows-[minmax(0,1fr)] xl:grid-rows-1 xl:[grid-template-columns:var(--md-cols)]"
73
+ : stackBelow === "lg"
74
+ ? "grid-cols-1 grid-rows-[minmax(0,1fr)] lg:grid-rows-1 lg:[grid-template-columns:var(--md-cols)]"
75
+ : "[grid-template-columns:var(--md-cols)]",
76
+ );
77
+ // Hidden while stacked; back to normal above the breakpoint, where both panes show.
78
+ let hideWhileStacked = $derived(stackBelow === "xl" ? "max-xl:hidden" : "max-lg:hidden");
79
+ // Drawn only while stacked. The back bar has no job beside a visible rail.
80
+ let stackedOnly = $derived(stackBelow === "xl" ? "xl:hidden" : "lg:hidden");
78
81
 
79
- // =========================
80
- // FUNCTIONS
81
- // =========================
82
- // `RailRow` calls this when a record is picked. Above the breakpoint the classes
83
- // that read `pane` are all prefixed away, so the flag changes nothing there.
84
- setContext<MasterDetailPane>(MASTER_DETAIL_PANE, {
85
- open: () => {
86
- if (stackBelow) pane = "detail";
87
- },
88
- });
82
+ // =========================
83
+ // FUNCTIONS
84
+ // =========================
85
+ // `RailRow` calls this when a record is picked. Above the breakpoint the classes
86
+ // that read `pane` are all prefixed away, so the flag changes nothing there.
87
+ setContext<MasterDetailPane>(MASTER_DETAIL_PANE, {
88
+ open: () => {
89
+ if (stackBelow) pane = "detail";
90
+ },
91
+ });
89
92
  </script>
90
93
 
91
94
  <!-- =========================== -->
@@ -106,11 +109,7 @@ setContext<MasterDetailPane>(MASTER_DETAIL_PANE, {
106
109
  data-stack={stackBelow ?? undefined}
107
110
  >
108
111
  <aside
109
- class={cn(
110
- "md-rail min-h-0",
111
- railClass,
112
- stackBelow && pane === "detail" && hideWhileStacked,
113
- )}
112
+ class={cn("md-rail min-h-0", railClass, stackBelow && pane === "detail" && hideWhileStacked)}
114
113
  >
115
114
  {@render rail()}
116
115
  </aside>
@@ -1,47 +1,47 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import type { Snippet } from "svelte";
6
- import { Warning, Info, CheckCircle, WarningCircle } from "phosphor-svelte";
7
- import { cn } from "../../lib/utils.js";
8
- import { Alert } from "../../shadcn/alert/index.js";
9
- import { TONE_CLASS, type Tone as SeverityTone } from "../../lib/tone.js";
10
- import type { PhosphorIcon } from "../../lib/icon-types.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import type { Snippet } from "svelte";
6
+ import { Warning, Info, CheckCircle, WarningCircle } from "phosphor-svelte";
7
+ import { cn } from "../../lib/utils.js";
8
+ import { Alert } from "../../shadcn/alert/index.js";
9
+ import { TONE_CLASS, type Tone as SeverityTone } from "../../lib/tone.js";
10
+ import type { PhosphorIcon } from "../../lib/icon-types.js";
11
11
 
12
- // =========================
13
- // TYPES
14
- // =========================
15
- // A strip that stops the reader is a severity. Neutral and accent are chip tones.
16
- type Tone = Extract<SeverityTone, "destructive" | "warning" | "info" | "success">;
12
+ // =========================
13
+ // TYPES
14
+ // =========================
15
+ // A strip that stops the reader is a severity. Neutral and accent are chip tones.
16
+ type Tone = Extract<SeverityTone, "destructive" | "warning" | "info" | "success">;
17
17
 
18
- interface Props {
19
- // The "look at this before you act" strip. Hand-rolled ones used raw amber
20
- // and sky, so one severity showed two colours one route apart.
21
- tone?: Tone;
22
- icon?: PhosphorIcon;
23
- // The trailing control: a retry, a jump to the thing that needs fixing.
24
- actions?: Snippet;
25
- children: Snippet;
26
- class?: string;
27
- }
18
+ interface Props {
19
+ // The "look at this before you act" strip. Hand-rolled ones used raw amber
20
+ // and sky, so one severity showed two colours one route apart.
21
+ tone?: Tone;
22
+ icon?: PhosphorIcon;
23
+ // The trailing control: a retry, a jump to the thing that needs fixing.
24
+ actions?: Snippet;
25
+ children: Snippet;
26
+ class?: string;
27
+ }
28
28
 
29
- const TONE_ICON: Record<Tone, PhosphorIcon> = {
30
- destructive: Warning,
31
- warning: WarningCircle,
32
- info: Info,
33
- success: CheckCircle,
34
- };
29
+ const TONE_ICON: Record<Tone, PhosphorIcon> = {
30
+ destructive: Warning,
31
+ warning: WarningCircle,
32
+ info: Info,
33
+ success: CheckCircle,
34
+ };
35
35
 
36
- // =========================
37
- // PROPS
38
- // =========================
39
- let { tone = "destructive", icon, actions, children, class: className }: Props = $props();
36
+ // =========================
37
+ // PROPS
38
+ // =========================
39
+ let { tone = "destructive", icon, actions, children, class: className }: Props = $props();
40
40
 
41
- // =========================
42
- // DERIVED
43
- // =========================
44
- let Icon = $derived(icon ?? TONE_ICON[tone]);
41
+ // =========================
42
+ // DERIVED
43
+ // =========================
44
+ let Icon = $derived(icon ?? TONE_ICON[tone]);
45
45
  </script>
46
46
 
47
47
  <!-- =========================== -->
@@ -1,74 +1,74 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { CaretLeft, CaretRight } from "phosphor-svelte";
6
- import { cn } from "../../lib/utils.js";
7
- import { Button } from "../../shadcn/button/index.js";
8
- import { stepTo } from "./step.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import { CaretLeft, CaretRight } from "phosphor-svelte";
6
+ import { cn } from "../../lib/utils.js";
7
+ import { Button } from "../../shadcn/button/index.js";
8
+ import { stepTo } from "./step.js";
9
9
 
10
- // =========================
11
- // TYPES
12
- // =========================
13
- interface Props {
14
- /** Ids in the order the list shows them. */
15
- ids: readonly string[];
16
- current: string | null | undefined;
17
- onselect: (id: string) => void;
18
- previousLabel?: string;
19
- nextLabel?: string;
20
- /** Off when two steppers share a page, so one key press moves one list. */
21
- keys?: boolean;
22
- class?: string;
23
- };
10
+ // =========================
11
+ // TYPES
12
+ // =========================
13
+ interface Props {
14
+ /** Ids in the order the list shows them. */
15
+ ids: readonly string[];
16
+ current: string | null | undefined;
17
+ onselect: (id: string) => void;
18
+ previousLabel?: string;
19
+ nextLabel?: string;
20
+ /** Off when two steppers share a page, so one key press moves one list. */
21
+ keys?: boolean;
22
+ class?: string;
23
+ }
24
24
 
25
- // =========================
26
- // PROPS
27
- // =========================
28
- let {
29
- ids,
30
- current,
31
- onselect,
32
- previousLabel = "Previous",
33
- nextLabel = "Next",
34
- keys = true,
35
- class: className,
36
- }: Props = $props();
25
+ // =========================
26
+ // PROPS
27
+ // =========================
28
+ let {
29
+ ids,
30
+ current,
31
+ onselect,
32
+ previousLabel = "Previous",
33
+ nextLabel = "Next",
34
+ keys = true,
35
+ class: className,
36
+ }: Props = $props();
37
37
 
38
- // =========================
39
- // DERIVED
40
- // =========================
41
- let index = $derived(current ? ids.indexOf(current) : -1);
42
- let prev = $derived(stepTo(ids, current, -1));
43
- let next = $derived(stepTo(ids, current, 1));
38
+ // =========================
39
+ // DERIVED
40
+ // =========================
41
+ let index = $derived(current ? ids.indexOf(current) : -1);
42
+ let prev = $derived(stepTo(ids, current, -1));
43
+ let next = $derived(stepTo(ids, current, 1));
44
44
 
45
- // =========================
46
- // HANDLERS
47
- // =========================
48
- function isTyping(event: KeyboardEvent): boolean {
49
- const target = event.target as HTMLElement | null;
50
- return Boolean(target?.closest("input, textarea, select, [contenteditable='true']"));
51
- }
45
+ // =========================
46
+ // HANDLERS
47
+ // =========================
48
+ function isTyping(event: KeyboardEvent): boolean {
49
+ const target = event.target as HTMLElement | null;
50
+ return Boolean(target?.closest("input, textarea, select, [contenteditable='true']"));
51
+ }
52
52
 
53
- function ignored(event: KeyboardEvent): boolean {
54
- const modified = event.metaKey || event.ctrlKey || event.altKey;
55
- return !keys || modified || event.defaultPrevented || isTyping(event);
56
- }
53
+ function ignored(event: KeyboardEvent): boolean {
54
+ const modified = event.metaKey || event.ctrlKey || event.altKey;
55
+ return !keys || modified || event.defaultPrevented || isTyping(event);
56
+ }
57
57
 
58
- // K and J, as in Gmail: the arrows already belong to slide viewers and text fields.
59
- function targetFor(key: string): string | null {
60
- if (key === "k") return prev;
61
- if (key === "j") return next;
62
- return null;
63
- }
58
+ // K and J, as in Gmail: the arrows already belong to slide viewers and text fields.
59
+ function targetFor(key: string): string | null {
60
+ if (key === "k") return prev;
61
+ if (key === "j") return next;
62
+ return null;
63
+ }
64
64
 
65
- function onkeydown(event: KeyboardEvent) {
66
- if (ignored(event)) return;
67
- const id = targetFor(event.key);
68
- if (!id) return;
69
- event.preventDefault();
70
- onselect(id);
71
- }
65
+ function onkeydown(event: KeyboardEvent) {
66
+ if (ignored(event)) return;
67
+ const id = targetFor(event.key);
68
+ if (!id) return;
69
+ event.preventDefault();
70
+ onselect(id);
71
+ }
72
72
  </script>
73
73
 
74
74
  <svelte:window {onkeydown} />
@@ -1,24 +1,24 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import type { Snippet } from "svelte";
6
- import { cn } from "../../lib/utils.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import type { Snippet } from "svelte";
6
+ import { cn } from "../../lib/utils.js";
7
7
 
8
- // =========================
9
- // TYPES
10
- // =========================
11
- interface Props {
12
- // The scroller under `RailHead`. `min-h-0` makes a flex child scroll instead
13
- // of growing its parent, and it's the line hand-rolled rails forgot.
14
- children: Snippet;
15
- class?: string;
16
- };
8
+ // =========================
9
+ // TYPES
10
+ // =========================
11
+ interface Props {
12
+ // The scroller under `RailHead`. `min-h-0` makes a flex child scroll instead
13
+ // of growing its parent, and it's the line hand-rolled rails forgot.
14
+ children: Snippet;
15
+ class?: string;
16
+ }
17
17
 
18
- // =========================
19
- // PROPS
20
- // =========================
21
- let { children, class: className }: Props = $props();
18
+ // =========================
19
+ // PROPS
20
+ // =========================
21
+ let { children, class: className }: Props = $props();
22
22
  </script>
23
23
 
24
24
  <!-- =========================== -->
@@ -1,36 +1,29 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { cn } from "../../lib/utils.js";
6
- import * as Empty from "../../shadcn/empty/index.js";
7
- import type { PhosphorIcon, IconWeight } from "../../lib/icon-types.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import { cn } from "../../lib/utils.js";
6
+ import * as Empty from "../../shadcn/empty/index.js";
7
+ import type { PhosphorIcon, IconWeight } from "../../lib/icon-types.js";
8
8
 
9
- // =========================
10
- // TYPES
11
- // =========================
12
- interface Props {
13
- // Not `EmptyState`, which has a 48px icon and an action. This says a filter
14
- // came back empty, in one sentence that fits a 280px rail.
15
- icon?: PhosphorIcon;
16
- iconWeight?: IconWeight;
17
- iconClass?: string;
18
- title: string;
19
- hint?: string;
20
- class?: string;
21
- }
9
+ // =========================
10
+ // TYPES
11
+ // =========================
12
+ interface Props {
13
+ // Not `EmptyState`, which has a 48px icon and an action. This says a filter
14
+ // came back empty, in one sentence that fits a 280px rail.
15
+ icon?: PhosphorIcon;
16
+ iconWeight?: IconWeight;
17
+ iconClass?: string;
18
+ title: string;
19
+ hint?: string;
20
+ class?: string;
21
+ }
22
22
 
23
- // =========================
24
- // PROPS
25
- // =========================
26
- let {
27
- icon: Icon,
28
- iconWeight,
29
- iconClass,
30
- title,
31
- hint,
32
- class: className,
33
- }: Props = $props();
23
+ // =========================
24
+ // PROPS
25
+ // =========================
26
+ let { icon: Icon, iconWeight, iconClass, title, hint, class: className }: Props = $props();
34
27
  </script>
35
28
 
36
29
  <!-- =========================== -->
@@ -1,30 +1,30 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import type { Snippet } from "svelte";
6
- import SectionLabel from "./section-label.svelte";
7
- import { cn } from "../../lib/utils.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import type { Snippet } from "svelte";
6
+ import SectionLabel from "../section-header/section-label.svelte";
7
+ import { cn } from "../../lib/utils.js";
8
8
 
9
- // =========================
10
- // TYPES
11
- // =========================
12
- interface Props {
13
- // The fixed top of a queue rail: label, filter, search. A fixed height, so
14
- // rows start on the same line on every queue page.
15
- label?: string;
16
- // A low-emphasis control beside the label (compose, refresh).
17
- action?: Snippet;
18
- // The filter, the search, whatever narrows the list. Optional: a rail of four
19
- // records has nothing to narrow, and an empty strip under the label is chrome.
20
- children?: Snippet;
21
- class?: string;
22
- };
9
+ // =========================
10
+ // TYPES
11
+ // =========================
12
+ interface Props {
13
+ // The fixed top of a queue rail: label, filter, search. A fixed height, so
14
+ // rows start on the same line on every queue page.
15
+ label?: string;
16
+ // A low-emphasis control beside the label (compose, refresh).
17
+ action?: Snippet;
18
+ // The filter, the search, whatever narrows the list. Optional: a rail of four
19
+ // records has nothing to narrow, and an empty strip under the label is chrome.
20
+ children?: Snippet;
21
+ class?: string;
22
+ }
23
23
 
24
- // =========================
25
- // PROPS
26
- // =========================
27
- let { label, action, children, class: className }: Props = $props();
24
+ // =========================
25
+ // PROPS
26
+ // =========================
27
+ let { label, action, children, class: className }: Props = $props();
28
28
  </script>
29
29
 
30
30
  <!-- =========================== -->