@heyramzi/ui 2.8.0 → 2.10.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 (426) hide show
  1. package/COMPONENTS.md +1 -1
  2. package/README.md +1 -1
  3. package/dist/agents/helpers.js +52 -0
  4. package/dist/agents/index.js +3 -0
  5. package/dist/agents/page-state.js +65 -0
  6. package/dist/agents/types.js +1 -0
  7. package/dist/agents/vendor/color.js +149 -0
  8. package/dist/agents/vendor/draw.js +548 -0
  9. package/dist/agents/vendor/engine.js +632 -0
  10. package/dist/agents/vendor/mesh.js +727 -0
  11. package/dist/agents/vendor/plastic.js +3273 -0
  12. package/dist/agents/vendor/presets.js +171 -0
  13. package/dist/agents/vendor/shapes.js +24 -0
  14. package/dist/agents/vendor/ticker.js +56 -0
  15. package/dist/agents/vendor/types.js +0 -0
  16. package/dist/agents/vendor/wear.js +1525 -0
  17. package/dist/ai/ai-button/index.js +2 -0
  18. package/dist/ai/confirmation/confirmation-context.svelte.js +12 -0
  19. package/dist/ai/confirmation/index.js +9 -0
  20. package/dist/ai/generation-progress/index.js +2 -0
  21. package/dist/ai/index.js +11 -0
  22. package/dist/ai/loading-state/index.js +3 -0
  23. package/dist/ai/prompt-input/index.js +6 -0
  24. package/dist/ai/reasoning/index.js +4 -0
  25. package/dist/ai/reasoning/reasoning-context.svelte.js +12 -0
  26. package/dist/ai/response/index.js +3 -0
  27. package/dist/ai/suggestion/index.js +3 -0
  28. package/dist/ai/thinking-dots/index.js +3 -0
  29. package/dist/ai/typing-dots/index.js +2 -0
  30. package/dist/ai/voice-waveform/index.js +3 -0
  31. package/dist/animations/text-swap.js +30 -0
  32. package/dist/brand/index.js +65 -0
  33. package/dist/canvas/card/resize.js +10 -0
  34. package/dist/canvas/edges/edge-path.js +284 -0
  35. package/dist/canvas/editor/context-menu.js +42 -0
  36. package/dist/canvas/editor/dispatch.svelte.js +157 -0
  37. package/dist/canvas/editor/editor-context.js +8 -0
  38. package/dist/canvas/editor/editor-mode.js +0 -0
  39. package/dist/canvas/editor/frame.js +87 -0
  40. package/dist/canvas/editor/hand-context.js +8 -0
  41. package/dist/canvas/editor/history-core.js +221 -0
  42. package/dist/canvas/editor/keymap.js +193 -0
  43. package/dist/canvas/editor/layout-actions.js +170 -0
  44. package/dist/canvas/editor/lock.js +65 -0
  45. package/dist/canvas/editor/rebase.js +279 -0
  46. package/dist/canvas/editor/style.js +174 -0
  47. package/dist/canvas/editor/text-field-context.js +8 -0
  48. package/dist/canvas/editor/z-order.js +82 -0
  49. package/dist/canvas/headless/alignment.js +20 -0
  50. package/dist/canvas/headless/break-apart-find.js +324 -0
  51. package/dist/canvas/headless/break-apart-pieces.js +74 -0
  52. package/dist/canvas/headless/break-apart-plan.js +378 -0
  53. package/dist/canvas/headless/break-apart-style.js +93 -0
  54. package/dist/canvas/headless/break-apart.js +206 -0
  55. package/dist/canvas/headless/canvas-cleanup.js +70 -0
  56. package/dist/canvas/headless/edge-anchors.js +134 -0
  57. package/dist/canvas/headless/edge-memo.js +28 -0
  58. package/dist/canvas/headless/edge-serialization.js +31 -0
  59. package/dist/canvas/headless/figure-geometry.js +331 -0
  60. package/dist/canvas/headless/fit-viewport.js +82 -0
  61. package/dist/canvas/headless/grid.js +96 -0
  62. package/dist/canvas/headless/icon-node.js +45 -0
  63. package/dist/canvas/headless/index.js +1 -0
  64. package/dist/canvas/headless/linkify.js +25 -0
  65. package/dist/canvas/headless/pen-marks.js +115 -0
  66. package/dist/canvas/headless/sketch.js +250 -0
  67. package/dist/canvas/headless/snap-guides.js +100 -0
  68. package/dist/canvas/headless/svg-figure.js +137 -0
  69. package/dist/canvas/headless/table-layout.js +161 -0
  70. package/dist/canvas/index.js +25 -0
  71. package/dist/canvas/lod/lod-mode.svelte.js +22 -0
  72. package/dist/canvas/lod/render-all.svelte.js +45 -0
  73. package/dist/canvas/ops/arrange.js +83 -0
  74. package/dist/canvas/ops/ops.js +318 -0
  75. package/dist/canvas/pen/colors.js +41 -0
  76. package/dist/canvas/pen/eraser.js +35 -0
  77. package/dist/canvas/pen/geometry.js +143 -0
  78. package/dist/canvas/pen/index.js +9 -0
  79. package/dist/canvas/pen/ops.js +15 -0
  80. package/dist/canvas/pen/pen-session.js +171 -0
  81. package/dist/canvas/pen/plugin.js +129 -0
  82. package/dist/canvas/pen/shapes.js +80 -0
  83. package/dist/canvas/pen/stroke-path.js +37 -0
  84. package/dist/canvas/pen/types.js +30 -0
  85. package/dist/canvas/pen/ui.js +20 -0
  86. package/dist/canvas/plugin.js +51 -0
  87. package/dist/canvas/screen/glyphs.js +24 -0
  88. package/dist/canvas/screen/labels.js +24 -0
  89. package/dist/canvas/screen/parts.js +140 -0
  90. package/dist/canvas/screen/plugin.js +71 -0
  91. package/dist/canvas/screen/types.js +44 -0
  92. package/dist/canvas/screen/ui.js +13 -0
  93. package/dist/canvas/test-utils.js +18 -0
  94. package/dist/canvas/types.js +0 -0
  95. package/dist/canvas/ui/forward-wheel.js +27 -0
  96. package/dist/canvas/ui/icons.js +133 -0
  97. package/dist/canvas/ui/place-panel.js +57 -0
  98. package/dist/canvas/ui/shortcut-tip.js +18 -0
  99. package/dist/canvas/ui/tools.js +411 -0
  100. package/dist/charts/dashboard/chart.js +1 -0
  101. package/dist/charts/dashboard/data-table.js +7 -0
  102. package/dist/charts/dashboard/index.js +13 -0
  103. package/dist/charts/dashboard/windows.js +5 -0
  104. package/dist/charts/edge-fade.js +7 -0
  105. package/dist/charts/hover-band.js +13 -0
  106. package/dist/charts/index.js +19 -0
  107. package/dist/charts/motion.js +15 -0
  108. package/dist/charts/primitives/chart-utils.js +22 -0
  109. package/dist/charts/primitives/index.js +4 -0
  110. package/dist/components/copy/clipboard.js +38 -0
  111. package/dist/components/copy/copied.svelte.js +26 -0
  112. package/dist/components/copy/index.js +3 -0
  113. package/dist/components/data-table/data-table.js +55 -0
  114. package/dist/components/data-table/index.js +7 -0
  115. package/dist/components/docs/index.js +3 -0
  116. package/dist/components/docs/scroll-spy.svelte.js +71 -0
  117. package/dist/components/field-row/index.js +1 -0
  118. package/dist/components/hold-to-confirm/index.js +1 -0
  119. package/dist/components/icon/index.js +1 -0
  120. package/dist/components/language-flag/index.js +1 -0
  121. package/dist/components/list-page/filter-section.js +4 -0
  122. package/dist/components/list-page/index.js +25 -0
  123. package/dist/components/list-page/list-table.js +5 -0
  124. package/dist/components/list-page/queue-rail.js +3 -0
  125. package/dist/components/list-page/section-host.js +8 -0
  126. package/dist/components/list-page/step.js +5 -0
  127. package/dist/components/list-page/types.js +0 -0
  128. package/dist/components/locale-switch/index.js +1 -0
  129. package/dist/components/mark/index.js +1 -0
  130. package/dist/components/open-in/index.js +1 -0
  131. package/dist/components/picker/index.js +3 -0
  132. package/dist/components/picker/trigger.js +33 -0
  133. package/dist/components/picker/types.js +0 -0
  134. package/dist/components/section-card/index.js +1 -0
  135. package/dist/components/section-header/index.js +2 -0
  136. package/dist/components/segmented/collapse.js +32 -0
  137. package/dist/components/segmented/index.js +8 -0
  138. package/dist/components/segmented/segmented.js +50 -0
  139. package/dist/components/star-rating-input/index.js +2 -0
  140. package/dist/components/svg/index.js +1 -0
  141. package/dist/components/table-view/index.js +1 -0
  142. package/dist/components/table-view/types.js +0 -0
  143. package/dist/components/tags-input/index.js +2 -0
  144. package/dist/components/tags-input/tags.js +90 -0
  145. package/dist/components/theme/index.js +3 -0
  146. package/dist/components/toolbar/index.js +3 -0
  147. package/dist/components/toolbar/toolbar-trigger.js +4 -0
  148. package/dist/editor/anchors.js +17 -0
  149. package/dist/editor/block-id.js +62 -0
  150. package/dist/editor/block-ops.js +105 -0
  151. package/dist/editor/doc-blocks.js +181 -0
  152. package/dist/editor/extensions.js +200 -0
  153. package/dist/editor/index.js +4 -0
  154. package/dist/editor/markdown-test-helpers.js +6 -0
  155. package/dist/editor/markdown.js +486 -0
  156. package/dist/editor/serializer.js +268 -0
  157. package/dist/editor/slash-items.js +104 -0
  158. package/dist/editor/youtube-url.js +27 -0
  159. package/dist/effects/animated-beam/index.js +1 -0
  160. package/dist/effects/animated-beam/path-calculator.svelte.js +42 -0
  161. package/dist/effects/animated-beam/types.js +0 -0
  162. package/dist/effects/border-beam/css.js +420 -0
  163. package/dist/effects/border-beam/presets.js +1792 -0
  164. package/dist/effects/border-beam/register-properties.js +39 -0
  165. package/dist/effects/border-beam/types.js +0 -0
  166. package/dist/effects/image-comparison/compare.js +4 -0
  167. package/dist/effects/image-reveal/index.js +1 -0
  168. package/dist/effects/image-reveal/types.js +0 -0
  169. package/dist/effects/magnetic/magnetic.js +54 -0
  170. package/dist/effects/reveal/index.js +4 -0
  171. package/dist/effects/reveal/observe.js +43 -0
  172. package/dist/effects/reveal/types.js +0 -0
  173. package/dist/effects/shader-gradient/color.js +34 -0
  174. package/dist/effects/shader-gradient/index.js +1 -0
  175. package/dist/effects/shader-gradient/renderer.js +320 -0
  176. package/dist/effects/shader-gradient/shaders.js +280 -0
  177. package/dist/effects/shader-gradient/types.js +0 -0
  178. package/dist/icons/apple-symbol-exports.js +126 -0
  179. package/dist/icons/sf-symbols.js +465 -0
  180. package/dist/icons/trades.js +34 -0
  181. package/dist/inbox/index.js +4 -0
  182. package/dist/inbox/logic.js +156 -0
  183. package/dist/inbox/types.js +46 -0
  184. package/dist/index.js +18 -0
  185. package/dist/lib/arrive.js +13 -0
  186. package/dist/lib/icon-types.js +0 -0
  187. package/dist/lib/initials.js +17 -0
  188. package/dist/lib/layout.js +1 -0
  189. package/dist/lib/panel.js +3 -0
  190. package/dist/lib/result.js +26 -0
  191. package/dist/lib/sliding-pill.js +45 -0
  192. package/dist/lib/theme-transition.js +53 -0
  193. package/dist/lib/tone.js +32 -0
  194. package/dist/lib/utils.js +5 -0
  195. package/dist/onboarding/define-tours.js +28 -0
  196. package/dist/onboarding/index.js +4 -0
  197. package/dist/onboarding/onboarding.svelte.js +15 -0
  198. package/dist/onboarding/pick.js +16 -0
  199. package/dist/onboarding/stores.js +50 -0
  200. package/dist/onboarding/types.js +1 -0
  201. package/dist/onboarding/wait.js +25 -0
  202. package/dist/panel/index.js +1 -0
  203. package/dist/panel/side-panel-types.js +0 -0
  204. package/dist/record/demo-data.js +512 -0
  205. package/dist/record/fields.js +148 -0
  206. package/dist/record/format.js +97 -0
  207. package/dist/record/gutter.js +1 -0
  208. package/dist/record/index.js +15 -0
  209. package/dist/record/kinds.js +110 -0
  210. package/dist/record/logic.js +255 -0
  211. package/dist/record/types.js +52 -0
  212. package/dist/shadcn/accordion/index.js +5 -0
  213. package/dist/shadcn/alert/index.js +5 -0
  214. package/dist/shadcn/alert-dialog/index.js +12 -0
  215. package/dist/shadcn/attachment/index.js +10 -0
  216. package/dist/shadcn/avatar/index.js +7 -0
  217. package/dist/shadcn/badge/index.js +2 -0
  218. package/dist/shadcn/breadcrumb/index.js +8 -0
  219. package/dist/shadcn/bubble/index.js +5 -0
  220. package/dist/shadcn/button/index.js +2 -0
  221. package/dist/shadcn/calendar/index.js +19 -0
  222. package/dist/shadcn/card/index.js +8 -0
  223. package/dist/shadcn/checkbox/index.js +2 -0
  224. package/dist/shadcn/code-block/index.js +9 -0
  225. package/dist/shadcn/collapsible/index.js +4 -0
  226. package/dist/shadcn/command/index.js +13 -0
  227. package/dist/shadcn/context-menu/index.js +17 -0
  228. package/dist/shadcn/dialog/index.js +11 -0
  229. package/dist/shadcn/dropdown-menu/index.js +19 -0
  230. package/dist/shadcn/dropdown-menu/menu-item.js +23 -0
  231. package/dist/shadcn/empty/index.js +7 -0
  232. package/dist/shadcn/field/index.js +12 -0
  233. package/dist/shadcn/hooks/highlighter.js +92 -0
  234. package/dist/shadcn/hooks/is-mobile.svelte.js +7 -0
  235. package/dist/shadcn/hooks/use-highlighted-code.svelte.js +65 -0
  236. package/dist/shadcn/hover-card/index.js +5 -0
  237. package/dist/shadcn/input/index.js +3 -0
  238. package/dist/shadcn/input-otp/index.js +5 -0
  239. package/dist/shadcn/kbd/index.js +3 -0
  240. package/dist/shadcn/label/index.js +2 -0
  241. package/dist/shadcn/marker/index.js +4 -0
  242. package/dist/shadcn/message/index.js +7 -0
  243. package/dist/shadcn/message-scroller/index.js +8 -0
  244. package/dist/shadcn/popover/index.js +9 -0
  245. package/dist/shadcn/progress/index.js +2 -0
  246. package/dist/shadcn/progress/tone.js +11 -0
  247. package/dist/shadcn/radio-group/index.js +3 -0
  248. package/dist/shadcn/scroll-area/index.js +3 -0
  249. package/dist/shadcn/select/index.js +12 -0
  250. package/dist/shadcn/separator/index.js +2 -0
  251. package/dist/shadcn/sheet/index.js +11 -0
  252. package/dist/shadcn/sidebar/constants.js +6 -0
  253. package/dist/shadcn/sidebar/context.svelte.js +38 -0
  254. package/dist/shadcn/sidebar/index.js +25 -0
  255. package/dist/shadcn/skeleton/index.js +2 -0
  256. package/dist/shadcn/slider/index.js +2 -0
  257. package/dist/shadcn/sonner/index.js +1 -0
  258. package/dist/shadcn/spinner/index.js +1 -0
  259. package/dist/shadcn/switch/index.js +2 -0
  260. package/dist/shadcn/table/index.js +9 -0
  261. package/dist/shadcn/tabs/index.js +5 -0
  262. package/dist/shadcn/textarea/index.js +2 -0
  263. package/dist/shadcn/toggle/index.js +3 -0
  264. package/dist/shadcn/toggle-group/index.js +3 -0
  265. package/dist/shadcn/tooltip/context.js +8 -0
  266. package/dist/shadcn/tooltip/index.js +6 -0
  267. package/dist/shadcn/trace/index.js +9 -0
  268. package/dist/slides/bridges.js +66 -0
  269. package/dist/slides/deck-controller.svelte.js +221 -0
  270. package/dist/slides/export/capture.js +81 -0
  271. package/dist/slides/export/ffmpeg.js +85 -0
  272. package/dist/slides/export/index.js +4 -0
  273. package/dist/slides/export/launch.js +8 -0
  274. package/dist/slides/export/pdf.js +78 -0
  275. package/dist/slides/export/types.js +0 -0
  276. package/dist/slides/index.js +7 -0
  277. package/dist/slides/labels.js +26 -0
  278. package/dist/slides/layout.js +47 -0
  279. package/dist/slides/model.js +9 -0
  280. package/dist/slides/navigation.js +89 -0
  281. package/dist/slides/types.js +6 -0
  282. package/dist/status/define-statuses.js +16 -0
  283. package/dist/status/index.js +4 -0
  284. package/dist/status/status-types.js +0 -0
  285. package/dist/test-setup.js +26 -0
  286. package/dist/thread/index.js +3 -0
  287. package/dist/thread/logic.js +94 -0
  288. package/dist/thread/types.js +23 -0
  289. package/dist/work/board-order.js +109 -0
  290. package/dist/work/dates.js +19 -0
  291. package/dist/work/detail/detail-types.js +20 -0
  292. package/dist/work/docs/edited.js +39 -0
  293. package/dist/work/docs/index.js +7 -0
  294. package/dist/work/docs/labels.js +38 -0
  295. package/dist/work/docs/menu.js +121 -0
  296. package/dist/work/docs/outline.js +39 -0
  297. package/dist/work/gantt/logic.js +260 -0
  298. package/dist/work/inbox/inbox-logic.js +94 -0
  299. package/dist/work/inbox/inbox-statuses.js +86 -0
  300. package/dist/work/inbox/inbox-types.js +0 -0
  301. package/dist/work/inbox/index.js +1 -0
  302. package/dist/work/index.js +21 -0
  303. package/dist/work/kanban-drag.js +25 -0
  304. package/dist/work/kanban-types.js +0 -0
  305. package/dist/work/presets/sales.js +35 -0
  306. package/dist/work/reorder.js +10 -0
  307. package/dist/work/task-types.js +0 -0
  308. package/dist/work/time/duration.js +60 -0
  309. package/dist/work/time/time-types.js +25 -0
  310. package/dist/work/use-kanban-dnd.svelte.js +128 -0
  311. package/package.json +102 -76
  312. package/src/agents/vendor/draw.ts +4 -4
  313. package/src/canvas/headless/canvas-cleanup.test.ts +1 -1
  314. package/src/canvas/ops/ops.ts +1 -1
  315. package/src/charts/area-chart.svelte +11 -1
  316. package/src/charts/bar-chart.svelte +18 -3
  317. package/src/charts/line-chart.svelte +11 -1
  318. package/src/components/data-table/data-table.ts +4 -5
  319. package/src/components/data-table/pagination.svelte +5 -3
  320. package/src/components/docs/on-this-page.svelte +82 -5
  321. package/src/components/docs/scroll-spy.svelte.ts +6 -1
  322. package/src/components/list-page/detail-header.svelte +7 -3
  323. package/src/components/list-page/empty-state.svelte +3 -1
  324. package/src/components/list-page/filter-popover.svelte +2 -2
  325. package/src/components/list-page/rail-row.svelte +5 -2
  326. package/src/components/mark/mark.svelte +2 -1
  327. package/src/components/section-card/section-card.svelte +3 -1
  328. package/src/components/section-header/section-header.svelte +5 -5
  329. package/src/components/segmented/segment.svelte +1 -1
  330. package/src/components/table-view/table-view.svelte +6 -1
  331. package/src/components/tags-input/tags-input.svelte +1 -1
  332. package/src/components/toolbar/toolbar-trigger.ts +8 -2
  333. package/src/components/toolbar/toolbar.svelte +1 -1
  334. package/src/editor/anchors.ts +28 -0
  335. package/src/editor/doc-blocks.ts +168 -0
  336. package/src/editor/doc-page.css +389 -0
  337. package/src/editor/editor.svelte +47 -5
  338. package/src/editor/extensions.ts +26 -2
  339. package/src/editor/markdown.ts +27 -2
  340. package/src/editor/slash-items.ts +18 -0
  341. package/src/icons/trades.ts +1 -1
  342. package/src/inbox/README.md +6 -4
  343. package/src/inbox/inbox.test.ts +1 -1
  344. package/src/inbox/index.ts +2 -2
  345. package/src/inbox/logic.ts +29 -5
  346. package/src/inbox/thread-inbox.svelte +219 -92
  347. package/src/inbox/types.ts +27 -1
  348. package/src/lib/initials.test.ts +25 -0
  349. package/src/lib/initials.ts +29 -0
  350. package/src/modules.test.ts +4 -64
  351. package/src/panel/README.md +1 -1
  352. package/src/record/README.md +1 -1
  353. package/src/record/demo-data.ts +4 -4
  354. package/src/record/info-list.svelte +5 -4
  355. package/src/record/next-up.svelte +1 -1
  356. package/src/record/project-list.svelte +1 -1
  357. package/src/record/record-demo.svelte +2 -2
  358. package/src/record/steps-rail.svelte +3 -3
  359. package/src/shadcn/badge/badge.svelte +1 -1
  360. package/src/shadcn/card/card-title.svelte +1 -5
  361. package/src/shadcn/empty/empty-description.svelte +1 -1
  362. package/src/shadcn/progress/progress.svelte +8 -1
  363. package/src/shadcn/table/table-cell.svelte +10 -2
  364. package/src/status/README.md +1 -1
  365. package/src/thread/README.md +2 -0
  366. package/src/thread/index.ts +9 -1
  367. package/src/thread/logic.ts +33 -3
  368. package/src/thread/thread-body.svelte +37 -0
  369. package/src/thread/thread-events.svelte +30 -0
  370. package/src/thread/thread.svelte +74 -59
  371. package/src/thread/types.ts +21 -0
  372. package/src/{tasks → work}/README.md +11 -8
  373. package/src/{tasks → work}/detail/task-thread.svelte +8 -15
  374. package/src/work/docs/doc-editor-page.svelte +194 -0
  375. package/src/work/docs/doc-menu.svelte +333 -0
  376. package/src/work/docs/docs-demo.svelte +227 -0
  377. package/src/work/docs/edited-chip.svelte +125 -0
  378. package/src/work/docs/edited.ts +54 -0
  379. package/src/work/docs/index.ts +38 -0
  380. package/src/work/docs/labels.ts +70 -0
  381. package/src/work/docs/menu.ts +127 -0
  382. package/src/work/docs/outline.ts +60 -0
  383. package/src/{tasks → work}/gantt/gantt-group-row.svelte +1 -1
  384. package/src/{tasks → work}/inbox/inbox-card.svelte +113 -50
  385. package/src/work/inbox/inbox-logic.ts +98 -0
  386. package/src/work/inbox/inbox-trace.svelte +58 -0
  387. package/src/{tasks → work}/inbox/inbox-types.ts +2 -0
  388. package/src/{tasks → work}/index.ts +0 -10
  389. package/src/{tasks → work}/kanban-board.svelte +1 -1
  390. package/src/{tasks → work}/task-list.svelte +1 -1
  391. package/src/{tasks → work}/time/time-tracker.svelte +2 -5
  392. package/src/tasks/inbox/inbox-logic.ts +0 -21
  393. package/src/tasks/inbox/inbox-trace.svelte +0 -51
  394. /package/src/{tasks → work}/ambient.d.ts +0 -0
  395. /package/src/{tasks → work}/board-order.ts +0 -0
  396. /package/src/{tasks → work}/dates.ts +0 -0
  397. /package/src/{tasks → work}/demo.svelte +0 -0
  398. /package/src/{tasks → work}/detail/detail-demo.svelte +0 -0
  399. /package/src/{tasks → work}/detail/detail-types.ts +0 -0
  400. /package/src/{tasks → work}/detail/task-chip.svelte +0 -0
  401. /package/src/{tasks → work}/detail/task-detail.svelte +0 -0
  402. /package/src/{tasks → work}/detail/task-property.svelte +0 -0
  403. /package/src/{tasks → work}/gantt/gantt-bar.svelte +0 -0
  404. /package/src/{tasks → work}/gantt/gantt-grid.svelte +0 -0
  405. /package/src/{tasks → work}/gantt/gantt-header.svelte +0 -0
  406. /package/src/{tasks → work}/gantt/gantt-task-row.svelte +0 -0
  407. /package/src/{tasks → work}/gantt/gantt.css +0 -0
  408. /package/src/{tasks → work}/gantt/gantt.test.ts +0 -0
  409. /package/src/{tasks → work}/gantt/logic.test.ts +0 -0
  410. /package/src/{tasks → work}/gantt/logic.ts +0 -0
  411. /package/src/{tasks → work}/inbox/inbox-draft.svelte +0 -0
  412. /package/src/{tasks → work}/inbox/inbox-statuses.ts +0 -0
  413. /package/src/{tasks → work}/inbox/index.ts +0 -0
  414. /package/src/{tasks → work}/kanban-column.svelte +0 -0
  415. /package/src/{tasks → work}/kanban-drag.ts +0 -0
  416. /package/src/{tasks → work}/kanban-types.ts +0 -0
  417. /package/src/{tasks → work}/presets/sales.ts +0 -0
  418. /package/src/{tasks → work}/reorder.ts +0 -0
  419. /package/src/{tasks → work}/task-gantt.svelte +0 -0
  420. /package/src/{tasks → work}/task-types.ts +0 -0
  421. /package/src/{tasks → work}/time/duration.ts +0 -0
  422. /package/src/{tasks → work}/time/time-chip.svelte +0 -0
  423. /package/src/{tasks → work}/time/time-dot.svelte +0 -0
  424. /package/src/{tasks → work}/time/time-ring.svelte +0 -0
  425. /package/src/{tasks → work}/time/time-types.ts +0 -0
  426. /package/src/{tasks → work}/use-kanban-dnd.svelte.ts +0 -0
@@ -0,0 +1,66 @@
1
+ import { parseSlideParam } from "./navigation.js";
2
+ export function attachUrlSync(deck, { param = "s", write } = {}) {
3
+ const initial = parseSlideParam(new URL(location.href).searchParams.get(param), deck.entries.length);
4
+ if (initial !== null) deck.go(initial, 0, "remote");
5
+ return deck.listen(({ index })=>{
6
+ const url = new URL(location.href);
7
+ url.searchParams.set(param, String(index + 1));
8
+ if (write) write(url);
9
+ else history.replaceState(history.state, "", url);
10
+ });
11
+ }
12
+ export function attachBridge(deck, { origin = location.origin } = {}) {
13
+ const onMessage = (event)=>{
14
+ if (origin !== "*" && event.origin !== origin) return;
15
+ const data = event.data;
16
+ if (data?.type === "deck:nav") {
17
+ if (data.delta === -1) deck.prev();
18
+ else if (data.delta === 1) deck.next();
19
+ } else if (data?.type === "deck:go" && Number.isInteger(data.index)) {
20
+ deck.go(data.index, Number.isInteger(data.step) ? data.step : 0, "remote");
21
+ }
22
+ };
23
+ window.addEventListener("message", onMessage);
24
+ const stop = deck.listen(({ index, step }, source)=>{
25
+ if (source === "local" && window.parent !== window) {
26
+ window.parent.postMessage({
27
+ type: "deck:change",
28
+ index,
29
+ step,
30
+ total: deck.visible.length
31
+ }, origin);
32
+ }
33
+ });
34
+ return ()=>{
35
+ window.removeEventListener("message", onMessage);
36
+ stop();
37
+ };
38
+ }
39
+ export function attachChannel(deck, name) {
40
+ if (typeof BroadcastChannel === "undefined") return ()=>{};
41
+ const channel = new BroadcastChannel(`heyramzi-slides:${name}`);
42
+ const self = crypto.randomUUID();
43
+ const send = (message)=>channel.postMessage(message);
44
+ const state = ({ index, step } = deck.position)=>({
45
+ type: "state",
46
+ from: self,
47
+ index,
48
+ step
49
+ });
50
+ channel.onmessage = ({ data })=>{
51
+ if (data.from === self) return;
52
+ if (data.type === "hello") send(state());
53
+ else deck.go(data.index, data.step, "remote");
54
+ };
55
+ const stop = deck.listen((position, source)=>{
56
+ if (source === "local") send(state(position));
57
+ });
58
+ send({
59
+ type: "hello",
60
+ from: self
61
+ });
62
+ return ()=>{
63
+ stop();
64
+ channel.close();
65
+ };
66
+ }
@@ -0,0 +1,221 @@
1
+ import { untrack } from "svelte";
2
+ import { fitBox, gridBoxes } from "./layout.js";
3
+ import { keyAction, nextPosition, ordinalOf, prevPosition, progressOf, settle, visibleIndexes } from "./navigation.js";
4
+ import { resolveLabels } from "./labels.js";
5
+ import { DEFAULT_CANVAS } from "./types.js";
6
+ const live = new Set();
7
+ let active = null;
8
+ const claimKeys = (deck)=>{
9
+ active = deck;
10
+ };
11
+ const CONTROLS_ROOM = 56;
12
+ const MORPH_MS = 900;
13
+ const clamp = (value, min, max)=>Math.min(max, Math.max(min, value));
14
+ function isEditable(el) {
15
+ return el.isContentEditable || [
16
+ "INPUT",
17
+ "TEXTAREA",
18
+ "SELECT"
19
+ ].includes(el.tagName);
20
+ }
21
+ const byDocumentOrder = (a, b)=>a.el && b.el ? a.el.compareDocumentPosition(b.el) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1 : 0;
22
+ export class DeckController {
23
+ entries = $state.raw([]);
24
+ view = $state("slide");
25
+ cursor = $state(0);
26
+ direction = $state(1);
27
+ morphing = $state(false);
28
+ size = $state({
29
+ w: 0,
30
+ h: 0
31
+ });
32
+ options;
33
+ #listeners = new Set();
34
+ #timer;
35
+ constructor(options){
36
+ this.options = options;
37
+ }
38
+ canvas = $derived(this.options.canvas ?? DEFAULT_CANVAS);
39
+ labels = $derived(resolveLabels(this.options.labels));
40
+ slides = $derived(this.entries.map((entry)=>({
41
+ steps: this.options.fragments === false ? 0 : entry.steps,
42
+ hidden: entry.hidden
43
+ })));
44
+ visible = $derived(visibleIndexes(this.slides));
45
+ position = $derived(settle(this.slides, {
46
+ index: this.options.index,
47
+ step: this.options.step
48
+ }));
49
+ ordinal = $derived(ordinalOf(this.slides, this.position.index));
50
+ progress = $derived(progressOf(this.slides, this.position));
51
+ current = $derived(this.entries[this.position.index]);
52
+ upcoming = $derived(this.visible.find((i)=>i > this.position.index) ?? null);
53
+ overview = $derived(this.view === "overview");
54
+ revealAll = $derived(this.overview || this.options.fragments === false);
55
+ atStart = $derived(prevPosition(this.slides, this.position, this.options.loop) === null);
56
+ atEnd = $derived(nextPosition(this.slides, this.position, this.options.loop) === null);
57
+ fit = $derived(fitBox(this.size, this.canvas));
58
+ grid = $derived(gridBoxes({
59
+ w: this.size.w,
60
+ h: Math.max(0, this.size.h - (this.options.controls === false ? 0 : CONTROLS_ROOM))
61
+ }, this.canvas, this.visible.length));
62
+ boxOf(index) {
63
+ if (!this.overview) return this.fit;
64
+ return this.grid.boxes[this.visible.indexOf(index)];
65
+ }
66
+ register(entry) {
67
+ untrack(()=>{
68
+ this.entries = [
69
+ ...this.entries,
70
+ entry
71
+ ].sort(byDocumentOrder);
72
+ });
73
+ return ()=>untrack(()=>{
74
+ this.entries = this.entries.filter((candidate)=>candidate !== entry);
75
+ this.#write(this.position);
76
+ });
77
+ }
78
+ listen(listener) {
79
+ this.#listeners.add(listener);
80
+ return ()=>this.#listeners.delete(listener);
81
+ }
82
+ activate() {
83
+ claimKeys(this);
84
+ }
85
+ mount() {
86
+ live.add(this);
87
+ claimKeys(this);
88
+ return ()=>{
89
+ live.delete(this);
90
+ if (active === this) active = null;
91
+ clearTimeout(this.#timer);
92
+ };
93
+ }
94
+ get listening() {
95
+ if (this.options.keyboard === false) return false;
96
+ const eligible = [
97
+ ...live
98
+ ].filter((deck)=>deck.options.keyboard !== false);
99
+ return eligible.length <= 1 || active === this;
100
+ }
101
+ #write(position) {
102
+ this.options.index = position.index;
103
+ this.options.step = position.step;
104
+ }
105
+ commit(target, source = "local") {
106
+ if (!target) return;
107
+ const from = this.position;
108
+ const to = settle(this.slides, target);
109
+ if (to.index === from.index && to.step === from.step) return;
110
+ this.direction = to.index >= from.index ? 1 : -1;
111
+ const apply = ()=>this.#write(to);
112
+ if (to.index !== from.index && this.options.transition) this.options.transition(apply);
113
+ else apply();
114
+ for (const listener of this.#listeners)listener(to, source);
115
+ }
116
+ next() {
117
+ this.commit(nextPosition(this.slides, this.position, this.options.loop));
118
+ }
119
+ prev() {
120
+ this.commit(prevPosition(this.slides, this.position, this.options.loop));
121
+ }
122
+ go(index, step = 0, source = "local") {
123
+ this.commit({
124
+ index,
125
+ step
126
+ }, source);
127
+ }
128
+ toggleOverview(force) {
129
+ const open = force ?? !this.overview;
130
+ if (open === this.overview) return;
131
+ if (open) this.cursor = Math.max(0, this.visible.indexOf(this.position.index));
132
+ this.view = open ? "overview" : "slide";
133
+ this.#morph();
134
+ }
135
+ select(index) {
136
+ this.toggleOverview(false);
137
+ const keep = index === this.position.index;
138
+ this.go(index, keep ? this.position.step : 0);
139
+ }
140
+ #morph() {
141
+ this.morphing = true;
142
+ clearTimeout(this.#timer);
143
+ this.#timer = setTimeout(()=>this.morphing = false, MORPH_MS);
144
+ }
145
+ #moveCursor(to) {
146
+ this.cursor = clamp(to, 0, this.visible.length - 1);
147
+ }
148
+ handleKey(event) {
149
+ if (event.defaultPrevented || !this.listening || event.altKey || event.ctrlKey || event.metaKey) return null;
150
+ const target = event.target instanceof HTMLElement ? event.target : null;
151
+ if (target && isEditable(target)) return null;
152
+ const action = keyAction(event.key, event.shiftKey);
153
+ if (!action) return null;
154
+ if ((event.key === " " || event.key === "Enter") && target?.closest("button, a, summary")) return null;
155
+ const handled = this.overview ? this.#overviewKey(action) : this.#slideKey(action);
156
+ if (!handled) return null;
157
+ event.preventDefault();
158
+ return action;
159
+ }
160
+ #slideKey(action) {
161
+ switch(action){
162
+ case "next":
163
+ this.next();
164
+ return true;
165
+ case "prev":
166
+ this.prev();
167
+ return true;
168
+ case "first":
169
+ this.go(this.visible[0] ?? 0);
170
+ return true;
171
+ case "last":
172
+ this.go(this.visible[this.visible.length - 1] ?? 0);
173
+ return true;
174
+ case "overview":
175
+ this.toggleOverview(true);
176
+ return true;
177
+ case "fullscreen":
178
+ return true;
179
+ case "presenter":
180
+ return !!this.options.presenter;
181
+ default:
182
+ return false;
183
+ }
184
+ }
185
+ #overviewKey(action) {
186
+ const cols = this.grid.cols;
187
+ switch(action){
188
+ case "next":
189
+ this.#moveCursor(this.cursor + 1);
190
+ return true;
191
+ case "prev":
192
+ this.#moveCursor(this.cursor - 1);
193
+ return true;
194
+ case "down":
195
+ this.#moveCursor(this.cursor + cols);
196
+ return true;
197
+ case "up":
198
+ this.#moveCursor(this.cursor - cols);
199
+ return true;
200
+ case "first":
201
+ this.#moveCursor(0);
202
+ return true;
203
+ case "last":
204
+ this.#moveCursor(this.visible.length - 1);
205
+ return true;
206
+ case "select":
207
+ this.select(this.visible[this.cursor] ?? this.position.index);
208
+ return true;
209
+ case "close":
210
+ case "overview":
211
+ this.toggleOverview(false);
212
+ return true;
213
+ case "fullscreen":
214
+ return true;
215
+ case "presenter":
216
+ return !!this.options.presenter;
217
+ default:
218
+ return false;
219
+ }
220
+ }
221
+ }
@@ -0,0 +1,81 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ export const DEFAULT_WAITS = [
4
+ "networkidle",
5
+ "load"
6
+ ];
7
+ export async function gotoSettled(page, url, options = {}) {
8
+ const waits = options.waits ?? DEFAULT_WAITS;
9
+ const timeout = options.timeout ?? 45_000;
10
+ let failure;
11
+ for (const waitUntil of waits){
12
+ try {
13
+ return await page.goto(url, {
14
+ waitUntil,
15
+ timeout
16
+ });
17
+ } catch (error) {
18
+ failure = error;
19
+ }
20
+ }
21
+ throw failure ?? new Error("gotoSettled needs at least one wait condition.");
22
+ }
23
+ export async function capturePage(browser, source, options) {
24
+ const page = await browser.newPage({
25
+ viewport: options.size,
26
+ deviceScaleFactor: options.scale ?? 1
27
+ });
28
+ try {
29
+ if ("url" in source) await gotoSettled(page, source.url, options.goto);
30
+ else await page.setContent(source.html, {
31
+ waitUntil: "load"
32
+ });
33
+ if (options.style) await page.addStyleTag({
34
+ content: options.style
35
+ });
36
+ if (options.wait) await page.waitForTimeout(options.wait);
37
+ const { selector } = options;
38
+ let bytes;
39
+ if (selector) {
40
+ const target = page.locator(selector).first();
41
+ await target.waitFor({
42
+ state: "visible"
43
+ });
44
+ bytes = await target.screenshot({
45
+ type: "png"
46
+ });
47
+ } else {
48
+ bytes = await page.screenshot({
49
+ type: "png",
50
+ fullPage: options.fullPage
51
+ });
52
+ }
53
+ if (options.path) {
54
+ await mkdir(path.dirname(options.path), {
55
+ recursive: true
56
+ });
57
+ await writeFile(options.path, bytes);
58
+ }
59
+ return bytes;
60
+ } finally{
61
+ await page.close();
62
+ }
63
+ }
64
+ export function frameName(index, digits = 2, extension = "png") {
65
+ return `${String(index + 1).padStart(digits, "0")}.${extension}`;
66
+ }
67
+ export async function captureEach(elements, dir, options = {}) {
68
+ await mkdir(dir, {
69
+ recursive: true
70
+ });
71
+ const count = await elements.count();
72
+ const files = [];
73
+ for(let index = 0; index < count; index++){
74
+ const file = path.join(dir, frameName(index, options.digits));
75
+ await elements.nth(index).screenshot({
76
+ path: file
77
+ });
78
+ files.push(file);
79
+ }
80
+ return files;
81
+ }
@@ -0,0 +1,85 @@
1
+ import { spawn } from "node:child_process";
2
+ import { mkdir, rm } from "node:fs/promises";
3
+ import path from "node:path";
4
+ export function runFfmpeg(args, ffmpeg = "ffmpeg") {
5
+ return new Promise((resolve, reject)=>{
6
+ const child = spawn(ffmpeg, args, {
7
+ stdio: [
8
+ "ignore",
9
+ "ignore",
10
+ "pipe"
11
+ ]
12
+ });
13
+ let stderr = "";
14
+ child.stderr.on("data", (chunk)=>{
15
+ stderr += chunk;
16
+ });
17
+ child.on("error", (error)=>reject(new Error(`${ffmpeg} could not be started (${error.message}). Video export needs ffmpeg on PATH, or pass its path.`)));
18
+ child.on("close", (code)=>code === 0 ? resolve() : reject(new Error(`${ffmpeg} exited ${code}:\n${stderr.slice(-1500)}`)));
19
+ });
20
+ }
21
+ export function encodeArgs(dir, outFile, options) {
22
+ return [
23
+ "-y",
24
+ "-hide_banner",
25
+ "-loglevel",
26
+ "error",
27
+ "-framerate",
28
+ String(options.fps),
29
+ "-i",
30
+ path.join(dir, options.pattern ?? "%04d.png"),
31
+ "-an",
32
+ "-vf",
33
+ "format=yuv420p",
34
+ "-c:v",
35
+ "libx264",
36
+ "-preset",
37
+ options.preset ?? "slow",
38
+ "-crf",
39
+ String(options.crf ?? 23),
40
+ "-movflags",
41
+ "+faststart",
42
+ outFile
43
+ ];
44
+ }
45
+ export async function encodeFrames(dir, outFile, options) {
46
+ await mkdir(path.dirname(outFile), {
47
+ recursive: true
48
+ });
49
+ await runFfmpeg(encodeArgs(dir, outFile, options), options.ffmpeg);
50
+ }
51
+ export function loopFrameCount(seconds, fps) {
52
+ return Math.max(1, Math.round(seconds * fps));
53
+ }
54
+ export async function renderLoop(outFile, options) {
55
+ const fps = options.fps ?? 30;
56
+ const seconds = options.seconds ?? 2.5;
57
+ const frames = loopFrameCount(seconds, fps);
58
+ const work = `${outFile}.frames`;
59
+ await mkdir(work, {
60
+ recursive: true
61
+ });
62
+ try {
63
+ for(let index = 0; index < frames; index++){
64
+ await options.drawFrame({
65
+ index,
66
+ t: index / frames,
67
+ file: path.join(work, `${String(index).padStart(4, "0")}.png`)
68
+ });
69
+ }
70
+ await encodeFrames(work, outFile, {
71
+ ...options,
72
+ fps
73
+ });
74
+ } finally{
75
+ await rm(work, {
76
+ recursive: true,
77
+ force: true
78
+ });
79
+ }
80
+ return {
81
+ file: outFile,
82
+ frames,
83
+ seconds
84
+ };
85
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./capture.js";
2
+ export * from "./ffmpeg.js";
3
+ export * from "./launch.js";
4
+ export * from "./pdf.js";
@@ -0,0 +1,8 @@
1
+ export async function launchChromium(chromium) {
2
+ return chromium.launch({
3
+ headless: true
4
+ }).catch(()=>chromium.launch({
5
+ headless: true,
6
+ channel: "chrome"
7
+ }));
8
+ }
@@ -0,0 +1,78 @@
1
+ import { readFile } from "node:fs/promises";
2
+ export const RESET_CSS = `*{margin:0;padding:0;box-sizing:border-box;}
3
+ html{-webkit-print-color-adjust:exact;print-color-adjust:exact;}`;
4
+ export function pageRule(size) {
5
+ return `@page{size:${size.width}px ${size.height}px;margin:0;}`;
6
+ }
7
+ export function imagePagesCss(size, background) {
8
+ return `${RESET_CSS}
9
+ ${background ? `body{background:${background};}\n` : ""}${pageRule(size)}
10
+ .page{display:block;width:${size.width}px;height:${size.height}px;break-after:page;}
11
+ .page:last-child{break-after:auto;}`;
12
+ }
13
+ export function imagePagesHtml(dataUrls, size, background) {
14
+ const pages = dataUrls.map((dataUrl)=>`<img class="page" src="${dataUrl}" alt="">`).join("");
15
+ return `<!doctype html><html><head><meta charset="utf-8"><style>
16
+ ${imagePagesCss(size, background)}
17
+ </style></head><body>${pages}</body></html>`;
18
+ }
19
+ export function countPdfPages(pdf) {
20
+ return (Buffer.from(pdf).toString("latin1").match(/\/Type\s*\/Page[^s]/g) ?? []).length;
21
+ }
22
+ export async function printPage(page, options = {}) {
23
+ const { ready } = options;
24
+ if (typeof ready === "string") {
25
+ await page.waitForSelector(ready, {
26
+ timeout: options.readyTimeout ?? 60_000
27
+ });
28
+ } else if (ready) {
29
+ await ready(page);
30
+ }
31
+ await page.evaluate(()=>document.fonts.ready.then(()=>undefined));
32
+ if (options.settle) await page.waitForTimeout(options.settle);
33
+ const brokenImages = await page.evaluate(()=>[
34
+ ...document.images
35
+ ].filter((img)=>!img.complete || img.naturalWidth === 0).map((img)=>img.src));
36
+ const { size } = options;
37
+ const pdf = await page.pdf({
38
+ path: options.path,
39
+ printBackground: true,
40
+ ...size ? {
41
+ width: `${size.width}px`,
42
+ height: `${size.height}px`
43
+ } : {
44
+ preferCSSPageSize: true
45
+ },
46
+ pageRanges: options.pageRanges
47
+ });
48
+ return {
49
+ pdf,
50
+ pages: countPdfPages(pdf),
51
+ brokenImages
52
+ };
53
+ }
54
+ export async function printUrl(page, url, options = {}) {
55
+ const response = await page.goto(url, {
56
+ waitUntil: options.waitUntil ?? "load"
57
+ });
58
+ options.check?.(response, page);
59
+ return printPage(page, options);
60
+ }
61
+ export async function printHtml(page, html, options = {}) {
62
+ await page.setContent(html, {
63
+ waitUntil: options.waitUntil ?? "load"
64
+ });
65
+ return printPage(page, options);
66
+ }
67
+ export async function imagesToPdf(page, images, options) {
68
+ if (images.length === 0) throw new Error("imagesToPdf needs at least one image.");
69
+ const dataUrls = await Promise.all(images.map(async (image)=>{
70
+ const bytes = typeof image === "string" ? await readFile(image) : image;
71
+ return `data:image/png;base64,${Buffer.from(bytes).toString("base64")}`;
72
+ }));
73
+ const { pdf } = await printHtml(page, imagePagesHtml(dataUrls, options.size, options.background), {
74
+ size: options.size,
75
+ pageRanges: `1-${images.length}`
76
+ });
77
+ return pdf;
78
+ }
File without changes
@@ -0,0 +1,7 @@
1
+ export { default as Deck } from "../../src/slides/Deck.svelte";
2
+ export { default as Slide } from "../../src/slides/Slide.svelte";
3
+ export { default as Fragment } from "../../src/slides/Fragment.svelte";
4
+ export { default as Presenter } from "../../src/slides/Presenter.svelte";
5
+ export { DeckController } from "./deck-controller.svelte.js";
6
+ export { defaultLabels } from "./labels.js";
7
+ export { DEFAULT_CANVAS } from "./types.js";
@@ -0,0 +1,26 @@
1
+ export const defaultLabels = {
2
+ deck: "Slide deck",
3
+ deckRole: "presentation",
4
+ slideRole: "slide",
5
+ previous: "Previous slide",
6
+ next: "Next slide",
7
+ fullscreen: "Toggle fullscreen",
8
+ overview: "Slide overview",
9
+ presenter: "Open presenter view",
10
+ progress: "Deck progress",
11
+ slide: (n, of)=>`Slide ${n} of ${of}`,
12
+ upcoming: "Next",
13
+ current: "Now",
14
+ notes: "Notes",
15
+ noNotes: "No notes for this slide.",
16
+ endOfDeck: "End of deck.",
17
+ timer: "Elapsed time",
18
+ startTimer: "Start timer",
19
+ pauseTimer: "Pause timer",
20
+ resetTimer: "Reset timer",
21
+ unknownType: (type)=>`Unknown slide type: ${type}`
22
+ };
23
+ export const resolveLabels = (labels)=>({
24
+ ...defaultLabels,
25
+ ...labels
26
+ });
@@ -0,0 +1,47 @@
1
+ export function fitBox(view, canvas) {
2
+ const scale = Math.max(0, Math.min(view.w / canvas.w, view.h / canvas.h));
3
+ return {
4
+ x: (view.w - canvas.w * scale) / 2,
5
+ y: (view.h - canvas.h * scale) / 2,
6
+ scale
7
+ };
8
+ }
9
+ function scaleFor(cols, count, view, canvas, pad, gap) {
10
+ const rows = Math.ceil(count / cols);
11
+ const byWidth = (view.w - 2 * pad - (cols - 1) * gap) / cols / canvas.w;
12
+ const byHeight = (view.h - 2 * pad - (rows - 1) * gap) / rows / canvas.h;
13
+ return Math.min(byWidth, byHeight);
14
+ }
15
+ export function gridBoxes(view, canvas, count) {
16
+ if (count === 0 || view.w <= 0 || view.h <= 0) return {
17
+ cols: 1,
18
+ boxes: []
19
+ };
20
+ const pad = Math.min(56, Math.max(16, view.w * 0.04));
21
+ const gap = Math.max(26, pad * 0.6);
22
+ let cols = 1;
23
+ let scale = scaleFor(1, count, view, canvas, pad, gap);
24
+ for(let c = 2; c <= count; c++){
25
+ const candidate = scaleFor(c, count, view, canvas, pad, gap);
26
+ if (candidate > scale) [cols, scale] = [
27
+ c,
28
+ candidate
29
+ ];
30
+ }
31
+ const cellW = canvas.w * scale;
32
+ const cellH = canvas.h * scale;
33
+ const rows = Math.ceil(count / cols);
34
+ const left = (view.w - (cols * cellW + (cols - 1) * gap)) / 2;
35
+ const top = (view.h - (rows * cellH + (rows - 1) * gap)) / 2;
36
+ const boxes = Array.from({
37
+ length: count
38
+ }, (_, i)=>({
39
+ x: left + i % cols * (cellW + gap),
40
+ y: top + Math.floor(i / cols) * (cellH + gap),
41
+ scale
42
+ }));
43
+ return {
44
+ cols,
45
+ boxes
46
+ };
47
+ }
@@ -0,0 +1,9 @@
1
+ export const defineSlideType = (definition)=>definition;
2
+ export function defineRegistry(types) {
3
+ const registry = {};
4
+ for (const slide of types){
5
+ if (slide.type in registry) throw new Error(`Slide type "${slide.type}" is registered twice.`);
6
+ registry[slide.type] = slide;
7
+ }
8
+ return registry;
9
+ }