@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,61 +1,61 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import * as ContextMenu from "../../shadcn/context-menu/index.js";
6
- import { HoldToConfirm } from "../hold-to-confirm/index.js";
7
- import { ArrowUpRight, Copy, LinkSimple, Trash } from "phosphor-svelte";
8
- import type { Snippet } from "svelte";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import * as ContextMenu from "../../shadcn/context-menu/index.js";
6
+ import { HoldToConfirm } from "../hold-to-confirm/index.js";
7
+ import { ArrowUpRight, Copy, LinkSimple, Trash } from "phosphor-svelte";
8
+ import type { Snippet } from "svelte";
9
9
 
10
- // =========================
11
- // TYPES
12
- // =========================
13
- interface Props {
14
- onDelete: () => void;
15
- href?: string;
16
- id?: string;
17
- deleteLabel?: string;
18
- copyLinkLabel?: string;
19
- copyIdLabel?: string;
20
- /** Called after a successful clipboard copy so consumers can show their own toast */
21
- onCopied?: () => void;
22
- children: Snippet<[Record<string, unknown>]>;
23
- };
10
+ // =========================
11
+ // TYPES
12
+ // =========================
13
+ interface Props {
14
+ onDelete: () => void;
15
+ href?: string;
16
+ id?: string;
17
+ deleteLabel?: string;
18
+ copyLinkLabel?: string;
19
+ copyIdLabel?: string;
20
+ /** Called after a successful clipboard copy so consumers can show their own toast */
21
+ onCopied?: () => void;
22
+ children: Snippet<[Record<string, unknown>]>;
23
+ }
24
24
 
25
- // =========================
26
- // PROPS
27
- // =========================
28
- let {
29
- onDelete,
30
- href,
31
- id,
32
- deleteLabel = "Delete",
33
- copyLinkLabel = "Copy link",
34
- copyIdLabel = "Copy ID",
35
- onCopied,
36
- children,
37
- }: Props = $props();
25
+ // =========================
26
+ // PROPS
27
+ // =========================
28
+ let {
29
+ onDelete,
30
+ href,
31
+ id,
32
+ deleteLabel = "Delete",
33
+ copyLinkLabel = "Copy link",
34
+ copyIdLabel = "Copy ID",
35
+ onCopied,
36
+ children,
37
+ }: Props = $props();
38
38
 
39
- // =========================
40
- // FUNCTIONS
41
- // =========================
42
- function handleOpen() {
43
- if (href) window.location.href = href;
44
- }
39
+ // =========================
40
+ // FUNCTIONS
41
+ // =========================
42
+ function handleOpen() {
43
+ if (href) window.location.href = href;
44
+ }
45
45
 
46
- // WHY the whole URL and not the path: what leaves this menu is pasted into a
47
- // message, a doc or an agent prompt, none of which can resolve "/clients/42".
48
- async function handleCopyLink() {
49
- if (!href) return;
50
- await navigator.clipboard.writeText(new URL(href, window.location.origin).href);
51
- onCopied?.();
52
- }
46
+ // WHY the whole URL and not the path: what leaves this menu is pasted into a
47
+ // message, a doc or an agent prompt, none of which can resolve "/clients/42".
48
+ async function handleCopyLink() {
49
+ if (!href) return;
50
+ await navigator.clipboard.writeText(new URL(href, window.location.origin).href);
51
+ onCopied?.();
52
+ }
53
53
 
54
- async function handleCopyId() {
55
- if (!id) return;
56
- await navigator.clipboard.writeText(id);
57
- onCopied?.();
58
- }
54
+ async function handleCopyId() {
55
+ if (!id) return;
56
+ await navigator.clipboard.writeText(id);
57
+ onCopied?.();
58
+ }
59
59
  </script>
60
60
 
61
61
  <!-- =========================== -->
@@ -1,34 +1,34 @@
1
1
  <script lang="ts" generics="T">
2
- import type { Snippet } from "svelte";
3
- import { CaretDown, CaretUp, CaretUpDown } from "phosphor-svelte";
4
- import { cn } from "../../lib/utils.js";
5
- import type { SortDirection, SortState } from "./data-table.js";
2
+ import type { Snippet } from "svelte";
3
+ import { CaretDown, CaretUp, CaretUpDown } from "phosphor-svelte";
4
+ import { cn } from "../../lib/utils.js";
5
+ import type { SortDirection, SortState } from "./data-table.js";
6
6
 
7
- // ========================= TYPES
8
- interface Props {
9
- key: keyof T & string;
10
- sort: SortState<T>;
11
- onSort: (key: keyof T & string) => void;
12
- class?: string;
13
- children: Snippet;
14
- };
7
+ // ========================= TYPES
8
+ interface Props {
9
+ key: keyof T & string;
10
+ sort: SortState<T>;
11
+ onSort: (key: keyof T & string) => void;
12
+ class?: string;
13
+ children: Snippet;
14
+ }
15
15
 
16
- // ========================= PROPS
17
- let { key, sort, onSort, class: className, children }: Props = $props();
16
+ // ========================= PROPS
17
+ let { key, sort, onSort, class: className, children }: Props = $props();
18
18
 
19
- // ========================= DERIVED
20
- let active = $derived(sort?.key === key);
21
- let direction = $derived<SortDirection | null>(sort && active ? sort.direction : null);
22
- let ariaSort = $derived<"ascending" | "descending" | "none">(
23
- direction === "asc" ? "ascending" : direction === "desc" ? "descending" : "none",
24
- );
19
+ // ========================= DERIVED
20
+ let active = $derived(sort?.key === key);
21
+ let direction = $derived<SortDirection | null>(sort && active ? sort.direction : null);
22
+ let ariaSort = $derived<"ascending" | "descending" | "none">(
23
+ direction === "asc" ? "ascending" : direction === "desc" ? "descending" : "none",
24
+ );
25
25
 
26
- function handleKeydown(e: KeyboardEvent) {
27
- if (e.key === "Enter" || e.key === " ") {
28
- e.preventDefault();
29
- onSort(key);
26
+ function handleKeydown(e: KeyboardEvent) {
27
+ if (e.key === "Enter" || e.key === " ") {
28
+ e.preventDefault();
29
+ onSort(key);
30
+ }
30
31
  }
31
- }
32
32
  </script>
33
33
 
34
34
  <th
@@ -1,43 +1,38 @@
1
1
  <script lang="ts">
2
- // ========================= IMPORTS
3
- import { Skeleton } from "../../shadcn/skeleton/index.js";
2
+ // ========================= IMPORTS
3
+ import { Skeleton } from "../../shadcn/skeleton/index.js";
4
4
 
5
- // ========================= TYPES
6
- type ColumnDef = {
7
- width?: string;
8
- align?: "left" | "center" | "right";
9
- /** Show a small circle before the skeleton bar (e.g. logo/avatar column) */
10
- circle?: boolean;
11
- };
5
+ // ========================= TYPES
6
+ type ColumnDef = {
7
+ width?: string;
8
+ align?: "left" | "center" | "right";
9
+ /** Show a small circle before the skeleton bar (e.g. logo/avatar column) */
10
+ circle?: boolean;
11
+ };
12
12
 
13
- interface Props {
14
- /** Number of skeleton rows to render */
15
- rows?: number;
16
- /** Column definitions control skeleton widths and alignment */
17
- columns?: ColumnDef[];
18
- /** Simple mode: just specify column count */
19
- columnCount?: number;
20
- class?: string;
21
- };
13
+ interface Props {
14
+ /** Number of skeleton rows to render */
15
+ rows?: number;
16
+ /** Column definitions control skeleton widths and alignment */
17
+ columns?: ColumnDef[];
18
+ /** Simple mode: just specify column count */
19
+ columnCount?: number;
20
+ class?: string;
21
+ }
22
22
 
23
- // ========================= PROPS
24
- let {
25
- rows = 5,
26
- columns,
27
- columnCount = 6,
28
- class: className,
29
- }: Props = $props();
23
+ // ========================= PROPS
24
+ let { rows = 5, columns, columnCount = 6, class: className }: Props = $props();
30
25
 
31
- // ========================= DERIVED
32
- let cols = $derived(
33
- columns ??
34
- Array.from<unknown, ColumnDef>({ length: columnCount }, () => ({
35
- width: undefined,
36
- align: "left" as const,
37
- })),
38
- );
26
+ // ========================= DERIVED
27
+ let cols = $derived(
28
+ columns ??
29
+ Array.from<unknown, ColumnDef>({ length: columnCount }, () => ({
30
+ width: undefined,
31
+ align: "left" as const,
32
+ })),
33
+ );
39
34
 
40
- const WIDTHS = ["w-24", "w-20", "w-28", "w-16", "w-32", "w-20"];
35
+ const WIDTHS = ["w-24", "w-20", "w-28", "w-16", "w-32", "w-20"];
41
36
  </script>
42
37
 
43
38
  <!-- =========================== -->
@@ -53,9 +48,19 @@ const WIDTHS = ["w-24", "w-20", "w-28", "w-16", "w-32", "w-20"];
53
48
  {#each cols as col, colIdx (colIdx)}
54
49
  <td
55
50
  data-slot="table-cell"
56
- class="h-11 px-2 {col.align === 'center' ? 'text-center' : col.align === 'right' ? 'text-right' : ''}"
51
+ class="h-11 px-2 {col.align === 'center'
52
+ ? 'text-center'
53
+ : col.align === 'right'
54
+ ? 'text-right'
55
+ : ''}"
57
56
  >
58
- <div class="flex items-center gap-2 {col.align === 'center' ? 'justify-center' : col.align === 'right' ? 'justify-end' : ''}">
57
+ <div
58
+ class="flex items-center gap-2 {col.align === 'center'
59
+ ? 'justify-center'
60
+ : col.align === 'right'
61
+ ? 'justify-end'
62
+ : ''}"
63
+ >
59
64
  {#if col.circle}
60
65
  <Skeleton class="size-6 shrink-0 rounded-md" />
61
66
  {/if}
@@ -81,17 +81,17 @@
81
81
  <!-- =========================== -->
82
82
  <!-- MARKUP -->
83
83
  <!-- =========================== -->
84
- <!-- The anatomy, once: header, then the reading column with its contents rail.
85
- A surface supplies content and never lays this out, so two pages can't
86
- arrive with different layouts. The pane is its own container, since the
87
- room left after the map is what decides the rail, not the window. -->
84
+ <!-- The one anatomy every doc page shares; the pane is its own container, since
85
+ the room left after the map, not the window, decides the rail. -->
88
86
  <div
89
87
  bind:this={scroller}
90
88
  class="doc-page @container/page thin-scrollbar relative min-h-0 flex-1 overflow-y-auto"
91
89
  >
92
90
  {#if hasRail}
93
91
  <!-- Below the rail's width the contents sit on a strip that stays put. -->
94
- <div class="sticky top-0 z-20 border-b border-border bg-background/95 backdrop-blur @3xl/page:hidden">
92
+ <div
93
+ class="sticky top-0 z-20 border-b border-border bg-background/95 backdrop-blur @3xl/page:hidden"
94
+ >
95
95
  <OnThisPage
96
96
  variant="bar"
97
97
  items={headings}
@@ -124,14 +124,21 @@
124
124
  {title}
125
125
  </h1>
126
126
  {#if summary}
127
- <p class="mt-1.5 max-w-[60ch] text-[15px] leading-relaxed text-muted-foreground text-pretty">
127
+ <p
128
+ class="mt-1.5 max-w-[60ch] text-[15px] leading-relaxed text-muted-foreground text-pretty"
129
+ >
128
130
  {summary}
129
131
  </p>
130
132
  {/if}
131
133
  {#if meta.length > 0}
132
- <p class="mt-3 flex flex-wrap items-center gap-x-2 text-xs tabular-nums text-muted-foreground">
134
+ <p
135
+ class="mt-3 flex flex-wrap items-center gap-x-2 text-xs tabular-nums text-muted-foreground"
136
+ >
133
137
  {#each meta as item, i (item)}
134
- {#if i > 0}<span aria-hidden="true" class="size-0.5 rounded-full bg-current opacity-50"></span>{/if}
138
+ {#if i > 0}<span
139
+ aria-hidden="true"
140
+ class="size-0.5 rounded-full bg-current opacity-50"
141
+ ></span>{/if}
135
142
  <span>{item}</span>
136
143
  {/each}
137
144
  </p>
@@ -148,7 +155,9 @@
148
155
 
149
156
  {#if hasRail}
150
157
  <!-- `self-start`, since a sticky child only travels inside its own box. -->
151
- <aside class="hidden w-48 shrink-0 self-start pt-10 @3xl/page:sticky @3xl/page:top-0 @3xl/page:block">
158
+ <aside
159
+ class="hidden w-48 shrink-0 self-start pt-10 @3xl/page:sticky @3xl/page:top-0 @3xl/page:block"
160
+ >
152
161
  <OnThisPage
153
162
  items={headings}
154
163
  active={spy.active}
@@ -42,8 +42,15 @@
42
42
  // =========================
43
43
  // DERIVED
44
44
  // =========================
45
- let activeIndex = $derived(Math.max(0, items.findIndex((item) => item.id === active)));
46
- let activeLabel = $derived(items.find((item) => item.id === active)?.label ?? items[0]?.label ?? "");
45
+ let activeIndex = $derived(
46
+ Math.max(
47
+ 0,
48
+ items.findIndex((item) => item.id === active),
49
+ ),
50
+ );
51
+ let activeLabel = $derived(
52
+ items.find((item) => item.id === active)?.label ?? items[0]?.label ?? "",
53
+ );
47
54
  // How far through the document: the bar's hairline, and the number a reader
48
55
  // reads at a glance.
49
56
  let progress = $derived(items.length > 1 ? activeIndex / (items.length - 1) : 0);
@@ -205,7 +212,13 @@
205
212
 
206
213
  /* A long list fades into its edges instead of ending on a hard cut. */
207
214
  .otp-fade {
208
- mask-image: linear-gradient(to bottom, transparent, #000 0.5rem, #000 calc(100% - 1.5rem), transparent);
215
+ mask-image: linear-gradient(
216
+ to bottom,
217
+ transparent,
218
+ #000 0.5rem,
219
+ #000 calc(100% - 1.5rem),
220
+ transparent
221
+ );
209
222
  }
210
223
 
211
224
  @media (prefers-reduced-motion: reduce) {
@@ -6,9 +6,8 @@
6
6
  export type DocHeading = { id: string; label: string };
7
7
 
8
8
  /**
9
- * Where a heading sits inside the scroller, in scroller content coordinates.
10
- * The default reads the live DOM by id. A framed document supplies its own,
11
- * since its headings live in another document.
9
+ * A heading's offset in scroller coordinates. A framed document must supply its own, since
10
+ * its headings live in another document.
12
11
  */
13
12
  export type LocateHeading = (id: string) => number | null;
14
13
 
@@ -25,7 +25,15 @@
25
25
  // =========================
26
26
  // PROPS
27
27
  // =========================
28
- let { label, for: htmlFor, description, error, class: className, children, action }: Props = $props();
28
+ let {
29
+ label,
30
+ for: htmlFor,
31
+ description,
32
+ error,
33
+ class: className,
34
+ children,
35
+ action,
36
+ }: Props = $props();
29
37
  </script>
30
38
 
31
39
  <!-- =========================== -->
@@ -35,13 +43,7 @@
35
43
  <!-- WHY the coarse-pointer height: Button grows to 44px on touch and Input
36
44
  does not, so a row built from the two drew a 12px step. -->
37
45
  <!-- =========================== -->
38
- <Field.Simple
39
- {label}
40
- {description}
41
- {error}
42
- for={htmlFor}
43
- class={cn("max-w-xl", className)}
44
- >
46
+ <Field.Simple {label} {description} {error} for={htmlFor} class={cn("max-w-xl", className)}>
45
47
  <div
46
48
  class="flex items-start gap-2 any-pointer-coarse:[&_[data-slot=input]]:h-11"
47
49
  data-slot="field-row"
@@ -183,7 +183,11 @@
183
183
  width: 2px;
184
184
  margin-left: -2px;
185
185
  opacity: 0;
186
- background: color-mix(in oklch, var(--color-destructive-foreground) 65%, var(--color-destructive));
186
+ background: color-mix(
187
+ in oklch,
188
+ var(--color-destructive-foreground) 65%,
189
+ var(--color-destructive)
190
+ );
187
191
  box-shadow: 0 0 4px 0 color-mix(in oklch, var(--color-destructive) 92%, transparent);
188
192
  transition:
189
193
  left var(--duration-quick) var(--ease-smooth-out),
@@ -1,20 +1,20 @@
1
1
  <script lang="ts">
2
- import type { PhosphorIcon, IconWeight } from "../../lib/icon-types.js";
2
+ import type { PhosphorIcon, IconWeight } from "../../lib/icon-types.js";
3
3
 
4
- // =========================
5
- // TYPES
6
- // =========================
7
- interface Props {
8
- icon: PhosphorIcon;
9
- size?: number;
10
- class?: string;
11
- weight?: IconWeight;
12
- };
4
+ // =========================
5
+ // TYPES
6
+ // =========================
7
+ interface Props {
8
+ icon: PhosphorIcon;
9
+ size?: number;
10
+ class?: string;
11
+ weight?: IconWeight;
12
+ }
13
13
 
14
- // =========================
15
- // PROPS
16
- // =========================
17
- let { icon: IconComp, size = 24, class: className = "", weight }: Props = $props();
14
+ // =========================
15
+ // PROPS
16
+ // =========================
17
+ let { icon: IconComp, size = 24, class: className = "", weight }: Props = $props();
18
18
  </script>
19
19
 
20
20
  <!-- =========================== -->
@@ -56,5 +56,7 @@
56
56
  {/if}
57
57
  </span>
58
58
  {:else if showLabel}
59
- <span class={cn("text-xs font-medium uppercase text-muted-foreground", className)}>{language}</span>
59
+ <span class={cn("text-xs font-medium uppercase text-muted-foreground", className)}
60
+ >{language}</span
61
+ >
60
62
  {/if}
@@ -1,40 +1,40 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import EmptyState from "./empty-state.svelte";
6
- import { cn } from "../../lib/utils.js";
7
- import type { PhosphorIcon, IconWeight } from "../../lib/icon-types.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import EmptyState from "./empty-state.svelte";
6
+ import { cn } from "../../lib/utils.js";
7
+ import type { PhosphorIcon, IconWeight } from "../../lib/icon-types.js";
8
8
 
9
- // =========================
10
- // TYPES
11
- // =========================
12
- interface Props {
13
- // Shown when nothing is picked or the board is empty. Both mean "content
14
- // goes here", so both get a dashed `border-2` edge.
15
- icon?: PhosphorIcon;
16
- iconWeight?: IconWeight;
17
- title: string;
18
- description?: string;
19
- actionLabel?: string;
20
- actionHref?: string;
21
- onAction?: () => void;
22
- class?: string;
23
- };
9
+ // =========================
10
+ // TYPES
11
+ // =========================
12
+ interface Props {
13
+ // Shown when nothing is picked or the board is empty. Both mean "content
14
+ // goes here", so both get a dashed `border-2` edge.
15
+ icon?: PhosphorIcon;
16
+ iconWeight?: IconWeight;
17
+ title: string;
18
+ description?: string;
19
+ actionLabel?: string;
20
+ actionHref?: string;
21
+ onAction?: () => void;
22
+ class?: string;
23
+ }
24
24
 
25
- // =========================
26
- // PROPS
27
- // =========================
28
- let {
29
- icon,
30
- iconWeight,
31
- title,
32
- description,
33
- actionLabel,
34
- actionHref,
35
- onAction,
36
- class: className,
37
- }: Props = $props();
25
+ // =========================
26
+ // PROPS
27
+ // =========================
28
+ let {
29
+ icon,
30
+ iconWeight,
31
+ title,
32
+ description,
33
+ actionLabel,
34
+ actionHref,
35
+ onAction,
36
+ class: className,
37
+ }: Props = $props();
38
38
  </script>
39
39
 
40
40
  <!-- =========================== -->
@@ -1,52 +1,61 @@
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
- // Answers three questions in one order: what is this, what state is it in,
13
- // what can I do with it. Each queue page used to order them differently.
14
- title: string;
15
- // The state chip beside the title.
16
- badge?: Snippet;
17
- // A picture ahead of the title, like a video frame or a deck cover. Some
18
- // records aren't recognisable from their title alone.
19
- leading?: Snippet;
20
- // Facts about the record, rendered as one dot-separated line under the
21
- // title. Falsy entries drop out, so a caller can inline its conditionals.
22
- meta?: Array<string | null | undefined | false>;
23
- // A sentence under the meta line, when the record explains itself.
24
- note?: string | null;
25
- // What you can do to the record. Pinned right of the identity block, EXCEPT
26
- // when a picture leads: see the note in the markup.
27
- actions?: Snippet;
28
- // The top-right control, a record's way out. Pass `undefined` when empty:
29
- // an empty snippet is still truthy and reserves the corner.
30
- corner?: Snippet;
31
- // Hairline-separated rows below the identity block. Use `DetailRow`.
32
- children?: Snippet;
33
- class?: string;
34
- };
8
+ // =========================
9
+ // TYPES
10
+ // =========================
11
+ interface Props {
12
+ // Answers three questions in one order: what is this, what state is it in,
13
+ // what can I do with it. Each queue page used to order them differently.
14
+ title: string;
15
+ // The state chip beside the title.
16
+ badge?: Snippet;
17
+ // A picture ahead of the title, like a video frame or a deck cover. Some
18
+ // records aren't recognisable from their title alone.
19
+ leading?: Snippet;
20
+ // Facts about the record, rendered as one dot-separated line under the
21
+ // title. Falsy entries drop out, so a caller can inline its conditionals.
22
+ meta?: Array<string | null | undefined | false>;
23
+ // A sentence under the meta line, when the record explains itself.
24
+ note?: string | null;
25
+ // What you can do to the record. Pinned right of the identity block, EXCEPT
26
+ // when a picture leads: see the note in the markup.
27
+ actions?: Snippet;
28
+ // The top-right control, a record's way out. Pass `undefined` when empty:
29
+ // an empty snippet is still truthy and reserves the corner.
30
+ corner?: Snippet;
31
+ // Hairline-separated rows below the identity block. Use `DetailRow`.
32
+ children?: Snippet;
33
+ class?: string;
34
+ }
35
35
 
36
- // =========================
37
- // PROPS
38
- // =========================
39
- let { title, badge, leading, meta, note, actions, corner, children, class: className }: Props =
40
- $props();
36
+ // =========================
37
+ // PROPS
38
+ // =========================
39
+ let {
40
+ title,
41
+ badge,
42
+ leading,
43
+ meta,
44
+ note,
45
+ actions,
46
+ corner,
47
+ children,
48
+ class: className,
49
+ }: Props = $props();
41
50
 
42
- // =========================
43
- // DERIVED
44
- // =========================
45
- let facts = $derived((meta ?? []).filter((item): item is string => Boolean(item)));
46
- // Actions stack under the meta when something else claims the right edge:
47
- // a picture, or the corner. Pinned beside a corner, they left the title
48
- // a third of the row.
49
- let stackActions = $derived(Boolean(leading || corner));
51
+ // =========================
52
+ // DERIVED
53
+ // =========================
54
+ let facts = $derived((meta ?? []).filter((item): item is string => Boolean(item)));
55
+ // Actions stack under the meta when something else claims the right edge:
56
+ // a picture, or the corner. Pinned beside a corner, they left the title
57
+ // a third of the row.
58
+ let stackActions = $derived(Boolean(leading || corner));
50
59
  </script>
51
60
 
52
61
  <!-- =========================== -->
@@ -69,8 +78,7 @@ let stackActions = $derived(Boolean(leading || corner));
69
78
  <!-- No text-balance: it evens the lines out, so a two-line title stopped
70
79
  short of the corner instead of running the full width. -->
71
80
  <h2 class="min-w-0 font-heading text-lg font-semibold leading-snug tracking-tight">
72
- {title}{#if badge}<span class="ms-2 inline-flex align-middle">{@render badge()}</span
73
- >{/if}
81
+ {title}{#if badge}<span class="ms-2 inline-flex align-middle">{@render badge()}</span>{/if}
74
82
  </h2>
75
83
  {#if facts.length > 0}
76
84
  <!-- Each dot hangs off the fact it leads, so a wrapped line's dot stays