makersclaw 0.1.0 → 0.3.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.
- package/LICENSE +21 -0
- package/README.md +41 -1
- package/THIRD-PARTY-NOTICES.md +180 -0
- package/package.json +15 -8
- package/r/annotate.json +62 -0
- package/r/approval-request.json +52 -0
- package/r/audio-player.json +74 -0
- package/r/auth-form.json +55 -0
- package/r/board.json +55 -0
- package/r/calendar-view.json +105 -0
- package/r/cart.json +62 -0
- package/r/chart.json +83 -0
- package/r/chat.json +95 -0
- package/r/code-editor.json +94 -0
- package/r/comment-box.json +64 -0
- package/r/contact-section.json +53 -0
- package/r/core.json +341 -0
- package/r/csv-import.json +63 -0
- package/r/data-table.json +69 -0
- package/r/diagram.json +74 -0
- package/r/doc-editor.json +82 -0
- package/r/doc-page.json +61 -0
- package/r/email-render.json +73 -0
- package/r/faq.json +50 -0
- package/r/file-upload.json +54 -0
- package/r/flow-canvas.json +93 -0
- package/r/footer.json +52 -0
- package/r/gantt.json +70 -0
- package/r/job-panel.json +56 -0
- package/r/json-editor.json +66 -0
- package/r/map.json +89 -0
- package/r/menubar.json +52 -0
- package/r/mind-map.json +67 -0
- package/r/navigation-menu.json +52 -0
- package/r/order-detail.json +54 -0
- package/r/org-chart.json +66 -0
- package/r/page-builder.json +105 -0
- package/r/payment-methods.json +51 -0
- package/r/pdf-document.json +79 -0
- package/r/pdf-viewer.json +88 -0
- package/r/product-detail.json +76 -0
- package/r/product-grid.json +65 -0
- package/r/record-form.json +67 -0
- package/r/record-notes.json +55 -0
- package/r/registry.json +3612 -0
- package/r/search-dialog.json +51 -0
- package/r/settings-list.json +66 -0
- package/r/setup-checklist.json +51 -0
- package/r/share-dialog.json +52 -0
- package/r/sidebar.json +69 -0
- package/r/signature-pad.json +72 -0
- package/r/sketch-canvas.json +99 -0
- package/r/spreadsheet.json +90 -0
- package/r/stat-cards.json +66 -0
- package/r/task-list.json +63 -0
- package/r/task-model.json +98 -0
- package/r/testimonials.json +52 -0
- package/r/transaction-list.json +53 -0
- package/r/whiteboard.json +66 -0
- package/registry/blocks/annotate/README.md +179 -0
- package/registry/blocks/annotate/annotate-data.js +250 -0
- package/registry/blocks/annotate/annotate.jsx +646 -0
- package/registry/blocks/annotate/block.json +10 -0
- package/registry/blocks/annotate/demo.jsx +135 -0
- package/registry/blocks/annotate/index.js +15 -0
- package/registry/blocks/approval-request/README.md +116 -0
- package/registry/blocks/approval-request/approval-request.jsx +386 -0
- package/registry/blocks/approval-request/block.json +10 -0
- package/registry/blocks/approval-request/demo.jsx +127 -0
- package/registry/blocks/approval-request/index.js +4 -0
- package/registry/blocks/audio-player/README.md +167 -0
- package/registry/blocks/audio-player/audio-player.jsx +623 -0
- package/registry/blocks/audio-player/block.json +14 -0
- package/registry/blocks/audio-player/colors.js +109 -0
- package/registry/blocks/audio-player/demo.jsx +209 -0
- package/registry/blocks/audio-player/index.js +6 -0
- package/registry/blocks/audio-player/time.js +67 -0
- package/registry/blocks/audio-player/wavesurfer.js +9 -0
- package/registry/blocks/auth-form/README.md +126 -0
- package/registry/blocks/auth-form/auth-form.jsx +568 -0
- package/registry/blocks/auth-form/block.json +10 -0
- package/registry/blocks/auth-form/demo.jsx +131 -0
- package/registry/blocks/auth-form/index.js +3 -0
- package/registry/blocks/board/README.md +64 -13
- package/registry/blocks/board/block.json +2 -2
- package/registry/blocks/board/board.jsx +237 -94
- package/registry/blocks/board/demo.jsx +103 -24
- package/registry/blocks/calendar-view/README.md +180 -0
- package/registry/blocks/calendar-view/agenda.jsx +147 -0
- package/registry/blocks/calendar-view/block.json +76 -0
- package/registry/blocks/calendar-view/calendar-model.js +442 -0
- package/registry/blocks/calendar-view/calendar.jsx +627 -0
- package/registry/blocks/calendar-view/demo.jsx +195 -0
- package/registry/blocks/calendar-view/draft.jsx +49 -0
- package/registry/blocks/calendar-view/index.js +39 -0
- package/registry/blocks/calendar-view/month.jsx +346 -0
- package/registry/blocks/calendar-view/paint.js +69 -0
- package/registry/blocks/calendar-view/time-grid.jsx +527 -0
- package/registry/blocks/calendar-view/tray.jsx +87 -0
- package/registry/blocks/cart/README.md +146 -0
- package/registry/blocks/cart/block.json +10 -0
- package/registry/blocks/cart/cart.jsx +597 -0
- package/registry/blocks/cart/demo.jsx +98 -0
- package/registry/blocks/cart/index.js +4 -0
- package/registry/blocks/cart/money.js +28 -0
- package/registry/blocks/chart/README.md +316 -0
- package/registry/blocks/chart/block.json +10 -0
- package/registry/blocks/chart/cartesian.jsx +642 -0
- package/registry/blocks/chart/core.jsx +262 -0
- package/registry/blocks/chart/demo.jsx +357 -0
- package/registry/blocks/chart/heatmap.jsx +336 -0
- package/registry/blocks/chart/index.js +8 -0
- package/registry/blocks/chart/pie.jsx +245 -0
- package/registry/blocks/chart/sparkline.jsx +88 -0
- package/registry/blocks/chat/README.md +273 -0
- package/registry/blocks/chat/attachment.jsx +95 -0
- package/registry/blocks/chat/block.json +10 -0
- package/registry/blocks/chat/chat.jsx +132 -0
- package/registry/blocks/chat/composer.jsx +364 -0
- package/registry/blocks/chat/demo.jsx +578 -0
- package/registry/blocks/chat/header.jsx +34 -0
- package/registry/blocks/chat/index.js +9 -0
- package/registry/blocks/chat/message.jsx +450 -0
- package/registry/blocks/chat/scroller.jsx +247 -0
- package/registry/blocks/chat/text.jsx +104 -0
- package/registry/blocks/code-editor/README.md +210 -0
- package/registry/blocks/code-editor/block.json +22 -0
- package/registry/blocks/code-editor/code-editor.jsx +534 -0
- package/registry/blocks/code-editor/codemirror.js +38 -0
- package/registry/blocks/code-editor/demo.jsx +205 -0
- package/registry/blocks/code-editor/index.js +8 -0
- package/registry/blocks/code-editor/json.js +317 -0
- package/registry/blocks/code-editor/sql.js +136 -0
- package/registry/blocks/code-editor/text.js +101 -0
- package/registry/blocks/code-editor/theme.js +186 -0
- package/registry/blocks/comment-box/README.md +123 -0
- package/registry/blocks/comment-box/block.json +10 -0
- package/registry/blocks/comment-box/comment-body.jsx +217 -0
- package/registry/blocks/comment-box/comment-box.jsx +198 -0
- package/registry/blocks/comment-box/comment-time.jsx +77 -0
- package/registry/blocks/comment-box/demo.jsx +141 -0
- package/registry/blocks/comment-box/index.js +8 -0
- package/registry/blocks/contact-section/README.md +152 -0
- package/registry/blocks/contact-section/block.json +11 -0
- package/registry/blocks/contact-section/contact-section.jsx +509 -0
- package/registry/blocks/contact-section/demo.jsx +93 -0
- package/registry/blocks/contact-section/index.js +4 -0
- package/registry/blocks/csv-import/README.md +133 -0
- package/registry/blocks/csv-import/block.json +13 -0
- package/registry/blocks/csv-import/csv-import.jsx +479 -0
- package/registry/blocks/csv-import/demo.jsx +106 -0
- package/registry/blocks/csv-import/import.js +200 -0
- package/registry/blocks/csv-import/index.js +7 -0
- package/registry/blocks/data-table/README.md +386 -0
- package/registry/blocks/data-table/block.json +10 -0
- package/registry/blocks/data-table/data-table.jsx +1164 -0
- package/registry/blocks/data-table/demo.jsx +588 -0
- package/registry/blocks/data-table/index.js +5 -0
- package/registry/blocks/data-table/model.js +169 -0
- package/registry/blocks/diagram/README.md +108 -0
- package/registry/blocks/diagram/block.json +13 -0
- package/registry/blocks/diagram/demo.jsx +113 -0
- package/registry/blocks/diagram/diagram.jsx +481 -0
- package/registry/blocks/diagram/index.js +7 -0
- package/registry/blocks/diagram/mermaid.js +52 -0
- package/registry/blocks/diagram/palette.js +313 -0
- package/registry/blocks/diagram/source.js +98 -0
- package/registry/blocks/doc-editor/README.md +215 -0
- package/registry/blocks/doc-editor/block.json +15 -0
- package/registry/blocks/doc-editor/demo.jsx +225 -0
- package/registry/blocks/doc-editor/doc-editor.jsx +291 -0
- package/registry/blocks/doc-editor/doc.js +309 -0
- package/registry/blocks/doc-editor/index.js +7 -0
- package/registry/blocks/doc-editor/schema.jsx +56 -0
- package/registry/blocks/doc-editor/shadcn-classes.js +110 -0
- package/registry/blocks/doc-editor/theme.js +82 -0
- package/registry/blocks/doc-page/README.md +119 -0
- package/registry/blocks/doc-page/autosave.js +104 -0
- package/registry/blocks/doc-page/block.json +10 -0
- package/registry/blocks/doc-page/demo.jsx +137 -0
- package/registry/blocks/doc-page/doc-page.jsx +276 -0
- package/registry/blocks/doc-page/index.js +4 -0
- package/registry/blocks/email-render/README.md +151 -0
- package/registry/blocks/email-render/block.json +14 -0
- package/registry/blocks/email-render/demo.jsx +153 -0
- package/registry/blocks/email-render/doc-email.jsx +210 -0
- package/registry/blocks/email-render/email.jsx +221 -0
- package/registry/blocks/email-render/index.js +10 -0
- package/registry/blocks/email-render/render.js +50 -0
- package/registry/blocks/email-render/theme.js +215 -0
- package/registry/blocks/faq/README.md +101 -0
- package/registry/blocks/faq/block.json +11 -0
- package/registry/blocks/faq/demo.jsx +89 -0
- package/registry/blocks/faq/faq.jsx +220 -0
- package/registry/blocks/faq/index.js +4 -0
- package/registry/blocks/file-upload/README.md +138 -0
- package/registry/blocks/file-upload/block.json +10 -0
- package/registry/blocks/file-upload/demo.jsx +204 -0
- package/registry/blocks/file-upload/file-upload.jsx +635 -0
- package/registry/blocks/file-upload/index.js +4 -0
- package/registry/blocks/flow-canvas/README.md +420 -0
- package/registry/blocks/flow-canvas/block.json +13 -0
- package/registry/blocks/flow-canvas/board.js +819 -0
- package/registry/blocks/flow-canvas/chrome.jsx +649 -0
- package/registry/blocks/flow-canvas/context.jsx +35 -0
- package/registry/blocks/flow-canvas/demo.jsx +249 -0
- package/registry/blocks/flow-canvas/edges.jsx +107 -0
- package/registry/blocks/flow-canvas/flow-canvas.jsx +1329 -0
- package/registry/blocks/flow-canvas/index.js +41 -0
- package/registry/blocks/flow-canvas/nodes.jsx +392 -0
- package/registry/blocks/flow-canvas/theme.js +174 -0
- package/registry/blocks/footer/README.md +133 -0
- package/registry/blocks/footer/block.json +11 -0
- package/registry/blocks/footer/demo.jsx +119 -0
- package/registry/blocks/footer/footer.jsx +406 -0
- package/registry/blocks/footer/index.js +4 -0
- package/registry/blocks/gantt/README.md +220 -0
- package/registry/blocks/gantt/block.json +10 -0
- package/registry/blocks/gantt/demo.jsx +148 -0
- package/registry/blocks/gantt/gantt.jsx +923 -0
- package/registry/blocks/gantt/index.js +7 -0
- package/registry/blocks/gantt/rows.jsx +468 -0
- package/registry/blocks/gantt/schedule.js +278 -0
- package/registry/blocks/job-panel/README.md +86 -2
- package/registry/blocks/job-panel/block.json +3 -3
- package/registry/blocks/job-panel/demo.jsx +230 -3
- package/registry/blocks/job-panel/job-panel.jsx +169 -3
- package/registry/blocks/json-editor/README.md +133 -0
- package/registry/blocks/json-editor/block.json +10 -0
- package/registry/blocks/json-editor/demo.jsx +92 -0
- package/registry/blocks/json-editor/index.js +7 -0
- package/registry/blocks/json-editor/json-editor.jsx +305 -0
- package/registry/blocks/json-editor/json-tree.jsx +393 -0
- package/registry/blocks/json-editor/tree.js +225 -0
- package/registry/blocks/map/README.md +221 -0
- package/registry/blocks/map/block.json +14 -0
- package/registry/blocks/map/demo.jsx +201 -0
- package/registry/blocks/map/geo.js +198 -0
- package/registry/blocks/map/index.js +8 -0
- package/registry/blocks/map/list.jsx +128 -0
- package/registry/blocks/map/map-view.jsx +715 -0
- package/registry/blocks/map/maplibre.js +30 -0
- package/registry/blocks/map/marks.jsx +146 -0
- package/registry/blocks/map/theme.js +142 -0
- package/registry/blocks/menubar/README.md +109 -0
- package/registry/blocks/menubar/block.json +10 -0
- package/registry/blocks/menubar/demo.jsx +128 -0
- package/registry/blocks/menubar/index.js +4 -0
- package/registry/blocks/menubar/menubar.jsx +199 -0
- package/registry/blocks/mind-map/README.md +206 -0
- package/registry/blocks/mind-map/block.json +10 -0
- package/registry/blocks/mind-map/demo.jsx +103 -0
- package/registry/blocks/mind-map/index.js +31 -0
- package/registry/blocks/mind-map/mind-map.jsx +1125 -0
- package/registry/blocks/mind-map/topic.jsx +143 -0
- package/registry/blocks/mind-map/tree.js +645 -0
- package/registry/blocks/navigation-menu/README.md +124 -0
- package/registry/blocks/navigation-menu/block.json +10 -0
- package/registry/blocks/navigation-menu/demo.jsx +84 -0
- package/registry/blocks/navigation-menu/index.js +4 -0
- package/registry/blocks/navigation-menu/navigation-menu.jsx +448 -0
- package/registry/blocks/order-detail/README.md +109 -0
- package/registry/blocks/order-detail/block.json +10 -0
- package/registry/blocks/order-detail/demo.jsx +88 -0
- package/registry/blocks/order-detail/index.js +4 -0
- package/registry/blocks/order-detail/order-detail.jsx +354 -0
- package/registry/blocks/org-chart/README.md +145 -0
- package/registry/blocks/org-chart/block.json +10 -0
- package/registry/blocks/org-chart/demo.jsx +94 -0
- package/registry/blocks/org-chart/index.js +7 -0
- package/registry/blocks/org-chart/org-chart.jsx +631 -0
- package/registry/blocks/org-chart/org.js +245 -0
- package/registry/blocks/org-chart/person.jsx +96 -0
- package/registry/blocks/page-builder/README.md +257 -0
- package/registry/blocks/page-builder/block.json +14 -0
- package/registry/blocks/page-builder/demo.jsx +145 -0
- package/registry/blocks/page-builder/grapes.js +18 -0
- package/registry/blocks/page-builder/index.js +11 -0
- package/registry/blocks/page-builder/page-builder.jsx +704 -0
- package/registry/blocks/page-builder/page-view.jsx +33 -0
- package/registry/blocks/page-builder/page.js +118 -0
- package/registry/blocks/page-builder/panels.jsx +588 -0
- package/registry/blocks/page-builder/sections.js +209 -0
- package/registry/blocks/page-builder/theme.js +87 -0
- package/registry/blocks/page-builder/thumbs.jsx +189 -0
- package/registry/blocks/page-builder/tokens.js +329 -0
- package/registry/blocks/payment-methods/README.md +104 -0
- package/registry/blocks/payment-methods/block.json +10 -0
- package/registry/blocks/payment-methods/demo.jsx +71 -0
- package/registry/blocks/payment-methods/index.js +4 -0
- package/registry/blocks/payment-methods/payment-methods.jsx +302 -0
- package/registry/blocks/pdf-document/README.md +213 -0
- package/registry/blocks/pdf-document/block.json +13 -0
- package/registry/blocks/pdf-document/demo.jsx +136 -0
- package/registry/blocks/pdf-document/index.js +33 -0
- package/registry/blocks/pdf-document/money.js +83 -0
- package/registry/blocks/pdf-document/pdf-document.jsx +144 -0
- package/registry/blocks/pdf-document/primitives.jsx +271 -0
- package/registry/blocks/pdf-document/quote.jsx +179 -0
- package/registry/blocks/pdf-document/theme.js +193 -0
- package/registry/blocks/pdf-viewer/README.md +191 -0
- package/registry/blocks/pdf-viewer/block.json +14 -0
- package/registry/blocks/pdf-viewer/demo.jsx +252 -0
- package/registry/blocks/pdf-viewer/helpers.js +270 -0
- package/registry/blocks/pdf-viewer/index.js +8 -0
- package/registry/blocks/pdf-viewer/notes.jsx +195 -0
- package/registry/blocks/pdf-viewer/pdf-viewer.jsx +1368 -0
- package/registry/blocks/pdf-viewer/pdfjs.js +37 -0
- package/registry/blocks/pdf-viewer/ssr-shim-end.js +6 -0
- package/registry/blocks/pdf-viewer/ssr-shim.js +44 -0
- package/registry/blocks/product-detail/README.md +217 -0
- package/registry/blocks/product-detail/block.json +10 -0
- package/registry/blocks/product-detail/demo.jsx +233 -0
- package/registry/blocks/product-detail/index.js +7 -0
- package/registry/blocks/product-detail/price.jsx +115 -0
- package/registry/blocks/product-detail/product-detail.jsx +348 -0
- package/registry/blocks/product-detail/product-media.jsx +102 -0
- package/registry/blocks/product-detail/product-options.jsx +144 -0
- package/registry/blocks/product-grid/README.md +162 -0
- package/registry/blocks/product-grid/block.json +10 -0
- package/registry/blocks/product-grid/demo.jsx +255 -0
- package/registry/blocks/product-grid/index.js +5 -0
- package/registry/blocks/product-grid/product-card.jsx +232 -0
- package/registry/blocks/product-grid/product-grid.jsx +235 -0
- package/registry/blocks/record-form/README.md +196 -0
- package/registry/blocks/record-form/block.json +10 -0
- package/registry/blocks/record-form/demo.jsx +525 -0
- package/registry/blocks/record-form/index.js +4 -0
- package/registry/blocks/record-form/record-fields.jsx +457 -0
- package/registry/blocks/record-form/record-form.jsx +415 -0
- package/registry/blocks/record-form/rules.js +81 -0
- package/registry/blocks/record-notes/README.md +139 -0
- package/registry/blocks/record-notes/block.json +10 -0
- package/registry/blocks/record-notes/demo.jsx +179 -0
- package/registry/blocks/record-notes/index.js +4 -0
- package/registry/blocks/record-notes/record-notes.jsx +266 -0
- package/registry/blocks/search-dialog/README.md +108 -0
- package/registry/blocks/search-dialog/block.json +10 -0
- package/registry/blocks/search-dialog/demo.jsx +116 -0
- package/registry/blocks/search-dialog/index.js +3 -0
- package/registry/blocks/search-dialog/search-dialog.jsx +235 -0
- package/registry/blocks/settings-list/README.md +171 -0
- package/registry/blocks/settings-list/block.json +10 -0
- package/registry/blocks/settings-list/demo.jsx +333 -0
- package/registry/blocks/settings-list/index.js +4 -0
- package/registry/blocks/settings-list/row-state.jsx +93 -0
- package/registry/blocks/settings-list/settings-list.jsx +349 -0
- package/registry/blocks/settings-list/settings-matrix.jsx +118 -0
- package/registry/blocks/setup-checklist/README.md +142 -0
- package/registry/blocks/setup-checklist/block.json +10 -0
- package/registry/blocks/setup-checklist/demo.jsx +159 -0
- package/registry/blocks/setup-checklist/index.js +4 -0
- package/registry/blocks/setup-checklist/setup-checklist.jsx +446 -0
- package/registry/blocks/share-dialog/README.md +113 -0
- package/registry/blocks/share-dialog/block.json +10 -0
- package/registry/blocks/share-dialog/demo.jsx +140 -0
- package/registry/blocks/share-dialog/index.js +3 -0
- package/registry/blocks/share-dialog/share-dialog.jsx +384 -0
- package/registry/blocks/sidebar/README.md +190 -0
- package/registry/blocks/sidebar/block.json +43 -0
- package/registry/blocks/sidebar/demo.jsx +577 -0
- package/registry/blocks/sidebar/index.js +4 -0
- package/registry/blocks/sidebar/sidebar-panel.jsx +149 -0
- package/registry/blocks/sidebar/sidebar.jsx +864 -0
- package/registry/blocks/signature-pad/README.md +137 -0
- package/registry/blocks/signature-pad/block.json +13 -0
- package/registry/blocks/signature-pad/colors.js +115 -0
- package/registry/blocks/signature-pad/demo.jsx +94 -0
- package/registry/blocks/signature-pad/index.js +6 -0
- package/registry/blocks/signature-pad/pad.js +7 -0
- package/registry/blocks/signature-pad/signature-pad.jsx +434 -0
- package/registry/blocks/signature-pad/signature.js +68 -0
- package/registry/blocks/sketch-canvas/README.md +280 -0
- package/registry/blocks/sketch-canvas/block.json +13 -0
- package/registry/blocks/sketch-canvas/demo.jsx +159 -0
- package/registry/blocks/sketch-canvas/excalidraw.js +40 -0
- package/registry/blocks/sketch-canvas/index.js +9 -0
- package/registry/blocks/sketch-canvas/palette.js +226 -0
- package/registry/blocks/sketch-canvas/sketch-canvas.jsx +1188 -0
- package/registry/blocks/sketch-canvas/sketch.js +179 -0
- package/registry/blocks/sketch-canvas/ssr-shim-end.js +6 -0
- package/registry/blocks/sketch-canvas/ssr-shim.js +45 -0
- package/registry/blocks/sketch-canvas/stamps.js +104 -0
- package/registry/blocks/sketch-canvas/theme.js +131 -0
- package/registry/blocks/spreadsheet/README.md +307 -0
- package/registry/blocks/spreadsheet/block.json +13 -0
- package/registry/blocks/spreadsheet/cells.jsx +455 -0
- package/registry/blocks/spreadsheet/chrome.jsx +325 -0
- package/registry/blocks/spreadsheet/demo.jsx +177 -0
- package/registry/blocks/spreadsheet/grid.js +387 -0
- package/registry/blocks/spreadsheet/index.js +34 -0
- package/registry/blocks/spreadsheet/spreadsheet.jsx +1732 -0
- package/registry/blocks/spreadsheet/types.js +473 -0
- package/registry/blocks/stat-cards/README.md +173 -0
- package/registry/blocks/stat-cards/block.json +10 -0
- package/registry/blocks/stat-cards/demo.jsx +257 -0
- package/registry/blocks/stat-cards/index.js +4 -0
- package/registry/blocks/stat-cards/stat-cards.jsx +307 -0
- package/registry/blocks/stat-cards/usage.jsx +243 -0
- package/registry/blocks/task-list/README.md +176 -0
- package/registry/blocks/task-list/block.json +10 -0
- package/registry/blocks/task-list/demo.jsx +134 -0
- package/registry/blocks/task-list/index.js +5 -0
- package/registry/blocks/task-list/task-list.jsx +907 -0
- package/registry/blocks/task-model/README.md +455 -0
- package/registry/blocks/task-model/block.json +167 -0
- package/registry/blocks/task-model/changes.js +89 -0
- package/registry/blocks/task-model/dates.js +371 -0
- package/registry/blocks/task-model/demo.jsx +215 -0
- package/registry/blocks/task-model/dnd.jsx +240 -0
- package/registry/blocks/task-model/index.js +97 -0
- package/registry/blocks/task-model/model.js +919 -0
- package/registry/blocks/task-model/parts.jsx +449 -0
- package/registry/blocks/task-model/toolbar.jsx +271 -0
- package/registry/blocks/testimonials/README.md +139 -0
- package/registry/blocks/testimonials/block.json +11 -0
- package/registry/blocks/testimonials/demo.jsx +137 -0
- package/registry/blocks/testimonials/index.js +4 -0
- package/registry/blocks/testimonials/testimonials.jsx +430 -0
- package/registry/blocks/transaction-list/README.md +126 -0
- package/registry/blocks/transaction-list/block.json +10 -0
- package/registry/blocks/transaction-list/demo.jsx +79 -0
- package/registry/blocks/transaction-list/index.js +4 -0
- package/registry/blocks/transaction-list/transaction-list.jsx +383 -0
- package/registry/blocks/whiteboard/README.md +179 -0
- package/registry/blocks/whiteboard/block.json +10 -0
- package/registry/blocks/whiteboard/demo.jsx +169 -0
- package/registry/blocks/whiteboard/index.js +6 -0
- package/registry/blocks/whiteboard/templates.js +150 -0
- package/registry/blocks/whiteboard/whiteboard.jsx +721 -0
- package/src/install.mjs +18 -0
- package/src/shadcn.mjs +171 -0
- package/templates/next/files/README.md +145 -11
- package/templates/next/files/app/globals.css +55 -4
- package/templates/next/files/check/run.mjs +3 -3
- package/templates/next/files/components/parts/fixture.jsx +1 -1
- package/templates/next/files/components/parts/sample.js +15 -0
- package/templates/next/files/components/ui/avatar.jsx +141 -0
- package/templates/next/files/components/ui/breadcrumb.jsx +149 -0
- package/templates/next/files/components/ui/button-group.jsx +70 -0
- package/templates/next/files/components/ui/button.jsx +132 -12
- package/templates/next/files/components/ui/calendar.jsx +609 -0
- package/templates/next/files/components/ui/carousel.jsx +281 -0
- package/templates/next/files/components/ui/collapsible.jsx +208 -0
- package/templates/next/files/components/ui/combobox.jsx +608 -0
- package/templates/next/files/components/ui/command.jsx +577 -0
- package/templates/next/files/components/ui/context-menu.jsx +191 -0
- package/templates/next/files/components/ui/date-picker.jsx +360 -0
- package/templates/next/files/components/ui/distribution.jsx +117 -0
- package/templates/next/files/components/ui/feedback.jsx +143 -0
- package/templates/next/files/components/ui/field.jsx +115 -3
- package/templates/next/files/components/ui/file-input.jsx +234 -0
- package/templates/next/files/components/ui/icon.jsx +130 -8
- package/templates/next/files/components/ui/image.jsx +143 -0
- package/templates/next/files/components/ui/index.js +47 -2
- package/templates/next/files/components/ui/input-group.jsx +213 -0
- package/templates/next/files/components/ui/input-otp.jsx +170 -0
- package/templates/next/files/components/ui/item.jsx +206 -0
- package/templates/next/files/components/ui/menu.jsx +454 -82
- package/templates/next/files/components/ui/notice.jsx +126 -14
- package/templates/next/files/components/ui/pagination.jsx +156 -0
- package/templates/next/files/components/ui/popover.jsx +284 -0
- package/templates/next/files/components/ui/radio.jsx +193 -0
- package/templates/next/files/components/ui/rating.jsx +131 -0
- package/templates/next/files/components/ui/resizable.jsx +338 -0
- package/templates/next/files/components/ui/scroll-area.jsx +123 -0
- package/templates/next/files/components/ui/separator.jsx +119 -0
- package/templates/next/files/components/ui/sheet.jsx +96 -11
- package/templates/next/files/components/ui/slider.jsx +174 -0
- package/templates/next/files/components/ui/stat.jsx +574 -0
- package/templates/next/files/components/ui/steps.jsx +338 -0
- package/templates/next/files/components/ui/swatch.jsx +33 -0
- package/templates/next/files/components/ui/table.jsx +130 -0
- package/templates/next/files/components/ui/toast.jsx +440 -0
- package/templates/next/files/components/ui/toggle.jsx +195 -0
- package/templates/next/files/components/ui/tooltip.jsx +270 -0
- package/templates/next/files/lib/sample.js +4 -12
- package/templates/next/template.json +264 -8
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
// The calendar's arithmetic — pure, no React. Where a task sits on a
|
|
2
|
+
// calendar (a timed block on one day, or an all-day span), how
|
|
3
|
+
// overlapping blocks share a column, how spans stack into lanes, the
|
|
4
|
+
// patches a move or a resize saves, the window each mode shows, and the
|
|
5
|
+
// available-time layer (working hours, open slots) booking-page builds
|
|
6
|
+
// on. Dates are task-model's wall-calendar strings; minutes are minutes
|
|
7
|
+
// after midnight.
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
addDays,
|
|
11
|
+
addMonths,
|
|
12
|
+
dayNumber,
|
|
13
|
+
dayOf,
|
|
14
|
+
diffDays,
|
|
15
|
+
formatDate,
|
|
16
|
+
formatTime,
|
|
17
|
+
minutesOf,
|
|
18
|
+
monthGrid,
|
|
19
|
+
shiftDates,
|
|
20
|
+
spanOf,
|
|
21
|
+
startOfWeek,
|
|
22
|
+
weekdayOf,
|
|
23
|
+
withTime,
|
|
24
|
+
} from "../task-model";
|
|
25
|
+
|
|
26
|
+
export const DAY_MINUTES = 1440;
|
|
27
|
+
export const CALENDAR_MODES = ["month", "week", "day", "agenda"];
|
|
28
|
+
export const MODE_LABELS = { month: "Month", week: "Week", day: "Day", agenda: "Agenda" };
|
|
29
|
+
|
|
30
|
+
const clamp = (n, lo, hi) => Math.max(lo, Math.min(hi, n));
|
|
31
|
+
|
|
32
|
+
/** Rounds minutes to the nearest `step` (default 15). */
|
|
33
|
+
export function snapMinutes(minutes, step = 15) {
|
|
34
|
+
return Math.round(minutes / step) * step;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** How long a timed block runs when the task says only when it starts:
|
|
38
|
+
* its estimate (hours), else `fallback` minutes. */
|
|
39
|
+
export function durationOf(task, fallback = 60) {
|
|
40
|
+
const est = Number(task?.estimate);
|
|
41
|
+
return est > 0 ? clamp(Math.round(est * 60), 15, 8 * 60) : fallback;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Where a task sits on a calendar, or null when it has no date.
|
|
46
|
+
* { id, task, timed, start, end, from, to, deadline, startOnly }
|
|
47
|
+
* `start` / `end` are days (inclusive). A timed item lives on one day
|
|
48
|
+
* (`start === end`) from `from` to `to` minutes: a start and a due time
|
|
49
|
+
* on the same day; a start time alone (runs its estimate, else an hour);
|
|
50
|
+
* or a due time alone (a `deadline`: a half-hour block at the due time).
|
|
51
|
+
* Anything else — plain days, or a span over several days — is all-day.
|
|
52
|
+
*/
|
|
53
|
+
export function eventOf(task, { defaultMinutes = 60 } = {}) {
|
|
54
|
+
const span = spanOf(task);
|
|
55
|
+
if (!span) return null;
|
|
56
|
+
const base = { id: String(task.id), task, start: span.start, end: span.end, timed: false, from: null, to: null, deadline: false, startOnly: false };
|
|
57
|
+
if (span.start !== span.end) return base;
|
|
58
|
+
const sDay = dayOf(task.start);
|
|
59
|
+
const dDay = dayOf(task.due);
|
|
60
|
+
const sm = sDay ? minutesOf(task.start) : null;
|
|
61
|
+
const dm = dDay ? minutesOf(task.due) : null;
|
|
62
|
+
if (sm === null && dm === null) return base;
|
|
63
|
+
let from;
|
|
64
|
+
let to;
|
|
65
|
+
let deadline = false;
|
|
66
|
+
let startOnly = false;
|
|
67
|
+
if (sm !== null && dm !== null && dm > sm) [from, to] = [sm, dm];
|
|
68
|
+
else if (sm !== null) {
|
|
69
|
+
from = sm;
|
|
70
|
+
to = sm + durationOf(task, defaultMinutes);
|
|
71
|
+
startOnly = !dDay;
|
|
72
|
+
} else {
|
|
73
|
+
from = dm;
|
|
74
|
+
to = dm + 30;
|
|
75
|
+
deadline = true;
|
|
76
|
+
}
|
|
77
|
+
from = clamp(from, 0, DAY_MINUTES - 15);
|
|
78
|
+
to = clamp(to, from + 15, DAY_MINUTES);
|
|
79
|
+
return { ...base, timed: true, from, to, deadline, startOnly };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Every dated task as an event (in the order given). */
|
|
83
|
+
export function eventsOf(tasks, options) {
|
|
84
|
+
const out = [];
|
|
85
|
+
for (const t of tasks ?? []) {
|
|
86
|
+
const e = eventOf(t, options);
|
|
87
|
+
if (e) out.push(e);
|
|
88
|
+
}
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Tasks with neither a start nor a due date: the unscheduled tray. */
|
|
93
|
+
export function unscheduledOf(tasks) {
|
|
94
|
+
return (tasks ?? []).filter((t) => !spanOf(t));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Side-by-side columns for the timed events of one day, the way Google
|
|
99
|
+
* Calendar lays a busy morning: events that overlap (directly or through
|
|
100
|
+
* a chain) share a cluster; each takes the first column free at its
|
|
101
|
+
* start; a block widens over the columns to its right that stay free for
|
|
102
|
+
* its whole run. Returns Map id → { col, cols, span }. `minMinutes` is
|
|
103
|
+
* the shortest block drawn (short ones still need room for a title).
|
|
104
|
+
*/
|
|
105
|
+
export function layoutTimed(events, { minMinutes = 20 } = {}) {
|
|
106
|
+
const list = [...events]
|
|
107
|
+
.filter((e) => e.timed)
|
|
108
|
+
.map((e) => ({ e, a: e.from, b: Math.max(e.to, e.from + minMinutes) }))
|
|
109
|
+
.sort((x, y) => x.a - y.a || y.b - x.b || String(x.e.task.title).localeCompare(String(y.e.task.title)));
|
|
110
|
+
const out = new Map();
|
|
111
|
+
let cluster = [];
|
|
112
|
+
let clusterEnd = -1;
|
|
113
|
+
const flush = () => {
|
|
114
|
+
if (!cluster.length) return;
|
|
115
|
+
const cols = Math.max(...cluster.map((c) => c.col)) + 1;
|
|
116
|
+
for (const c of cluster) {
|
|
117
|
+
let span = 1;
|
|
118
|
+
for (let k = c.col + 1; k < cols; k++) {
|
|
119
|
+
if (cluster.some((o) => o.col === k && o.a < c.b && c.a < o.b)) break;
|
|
120
|
+
span++;
|
|
121
|
+
}
|
|
122
|
+
out.set(c.e.id, { col: c.col, cols, span });
|
|
123
|
+
}
|
|
124
|
+
cluster = [];
|
|
125
|
+
clusterEnd = -1;
|
|
126
|
+
};
|
|
127
|
+
let ends = [];
|
|
128
|
+
for (const item of list) {
|
|
129
|
+
if (item.a >= clusterEnd) {
|
|
130
|
+
flush();
|
|
131
|
+
ends = [];
|
|
132
|
+
}
|
|
133
|
+
let col = ends.findIndex((end) => end <= item.a);
|
|
134
|
+
if (col < 0) col = ends.length;
|
|
135
|
+
ends[col] = item.b;
|
|
136
|
+
cluster.push({ ...item, col });
|
|
137
|
+
clusterEnd = Math.max(clusterEnd, item.b);
|
|
138
|
+
}
|
|
139
|
+
flush();
|
|
140
|
+
return out;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Spans stacked into lanes across a row of days (a month week, a week's
|
|
145
|
+
* all-day strip): longest first among those starting together, each in
|
|
146
|
+
* the first lane free for its days. Returns { items: [{ event, lane, col,
|
|
147
|
+
* span, clippedStart, clippedEnd }], lanes } — `col` / `span` in days
|
|
148
|
+
* from the row's first; `clipped*` when it runs past the row's ends.
|
|
149
|
+
*/
|
|
150
|
+
export function layoutLanes(events, days) {
|
|
151
|
+
const n = days.length;
|
|
152
|
+
if (!n) return { items: [], lanes: 0 };
|
|
153
|
+
const first = days[0];
|
|
154
|
+
const last = days[n - 1];
|
|
155
|
+
const list = events
|
|
156
|
+
.filter((e) => e.start <= last && e.end >= first)
|
|
157
|
+
.map((e) => {
|
|
158
|
+
const a = Math.max(0, diffDays(first, e.start));
|
|
159
|
+
const b = Math.min(n - 1, diffDays(first, e.end));
|
|
160
|
+
return { event: e, col: a, span: b - a + 1, clippedStart: e.start < first, clippedEnd: e.end > last };
|
|
161
|
+
})
|
|
162
|
+
.sort(
|
|
163
|
+
(x, y) =>
|
|
164
|
+
x.col - y.col ||
|
|
165
|
+
y.span - x.span ||
|
|
166
|
+
Number(x.event.timed) - Number(y.event.timed) ||
|
|
167
|
+
(x.event.from ?? -1) - (y.event.from ?? -1) ||
|
|
168
|
+
String(x.event.task.title).localeCompare(String(y.event.task.title)),
|
|
169
|
+
);
|
|
170
|
+
const lanes = [];
|
|
171
|
+
const items = [];
|
|
172
|
+
for (const it of list) {
|
|
173
|
+
let lane = lanes.findIndex((cells) => !cells.some((c) => c >= it.col && c < it.col + it.span));
|
|
174
|
+
if (lane < 0) {
|
|
175
|
+
lane = lanes.length;
|
|
176
|
+
lanes.push([]);
|
|
177
|
+
}
|
|
178
|
+
for (let k = it.col; k < it.col + it.span; k++) lanes[lane].push(k);
|
|
179
|
+
items.push({ ...it, lane });
|
|
180
|
+
}
|
|
181
|
+
return { items, lanes: lanes.length };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ---- the patches a gesture saves -----------------------------------------
|
|
185
|
+
|
|
186
|
+
/** A timed event moved to `day` at `from` minutes, keeping its length. */
|
|
187
|
+
export function moveEventPatch(event, day, from) {
|
|
188
|
+
const len = event.to - event.from;
|
|
189
|
+
const a = clamp(snapMinutes(from, 1), 0, DAY_MINUTES - len);
|
|
190
|
+
if (event.deadline) return { due: withTime(day, a) };
|
|
191
|
+
if (event.startOnly) return { start: withTime(day, a) };
|
|
192
|
+
return { start: withTime(day, a), due: withTime(day, a + len) };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** A timed event's end dragged to `to` minutes (at least 15 after it
|
|
196
|
+
* starts). A deadline or a start-only task becomes a start–due block. */
|
|
197
|
+
export function resizeEventPatch(event, to) {
|
|
198
|
+
const b = clamp(to, event.from + 15, DAY_MINUTES);
|
|
199
|
+
if (event.deadline || event.startOnly) return { start: withTime(event.start, event.from), due: withTime(event.start, b) };
|
|
200
|
+
return { due: withTime(event.start, b) };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** A timed event given a new day and a new [from, to] (a keyboard nudge
|
|
204
|
+
* that may move and resize at once). */
|
|
205
|
+
export function placeEventPatch(event, day, from, to) {
|
|
206
|
+
if (to - from === event.to - event.from) return moveEventPatch(event, day, from);
|
|
207
|
+
const a = clamp(from, 0, DAY_MINUTES - 15);
|
|
208
|
+
const b = clamp(to, a + 15, DAY_MINUTES);
|
|
209
|
+
return { start: withTime(day, a), due: withTime(day, b) };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** A task put on the time grid (from all-day, from the tray): a block
|
|
213
|
+
* of `minutes` from `from`. */
|
|
214
|
+
export function timedPatch(day, from, minutes = 60) {
|
|
215
|
+
const a = clamp(from, 0, DAY_MINUTES - 15);
|
|
216
|
+
return { start: withTime(day, a), due: withTime(day, Math.min(DAY_MINUTES, a + minutes)) };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** A task dropped on a day (a month cell, the all-day strip). An all-day
|
|
220
|
+
* span moves whole (by the days between where it was grabbed and where
|
|
221
|
+
* it landed); a timed one keeps its times on the new day; an
|
|
222
|
+
* unscheduled one gets that day as its due date. */
|
|
223
|
+
export function dayPatch(task, day, { grabbed } = {}) {
|
|
224
|
+
const e = eventOf(task);
|
|
225
|
+
if (!e) return { due: day };
|
|
226
|
+
const shift = diffDays(grabbed ?? e.start, day);
|
|
227
|
+
return shift ? shiftDates(task, shift) : null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** A timed task made all-day on `day` (dropped on the all-day strip). */
|
|
231
|
+
export function allDayPatch(day) {
|
|
232
|
+
return { start: null, due: day };
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** An all-day span's last day dragged to `end` (never before it starts). */
|
|
236
|
+
export function extendPatch(event, end) {
|
|
237
|
+
const e = end < event.start ? event.start : end;
|
|
238
|
+
const task = event.task;
|
|
239
|
+
if (e === event.start && !dayOf(task.start)) return { due: withTime(e, minutesOf(task.due)) };
|
|
240
|
+
return { start: withTime(event.start, minutesOf(task.start)), due: withTime(e, minutesOf(task.due)) };
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** Takes a task off the calendar (dropped on the unscheduled tray). */
|
|
244
|
+
export const UNSCHEDULE = Object.freeze({ start: null, due: null });
|
|
245
|
+
|
|
246
|
+
// ---- what each mode shows ------------------------------------------------
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* The days a mode shows around `anchor`: { from, to, days, weeks? }.
|
|
250
|
+
* month the weeks that hold the anchor's month (4–6 rows)
|
|
251
|
+
* week the anchor's week, or `count` days from the anchor (a phone's
|
|
252
|
+
* three-day week)
|
|
253
|
+
* day the anchor
|
|
254
|
+
* agenda `agendaDays` days from the anchor
|
|
255
|
+
*/
|
|
256
|
+
export function rangeFor(mode, anchor, { weekStartsOn = 1, count = 7, agendaDays = 14 } = {}) {
|
|
257
|
+
const a = dayOf(anchor);
|
|
258
|
+
if (mode === "month") {
|
|
259
|
+
const weeks = monthGrid(a, { weekStartsOn });
|
|
260
|
+
return { from: weeks[0][0], to: weeks[weeks.length - 1][6], days: weeks.flat(), weeks };
|
|
261
|
+
}
|
|
262
|
+
if (mode === "week") {
|
|
263
|
+
const from = count >= 7 ? startOfWeek(a, weekStartsOn) : a;
|
|
264
|
+
const days = Array.from({ length: count >= 7 ? 7 : count }, (_, i) => addDays(from, i));
|
|
265
|
+
return { from: days[0], to: days[days.length - 1], days };
|
|
266
|
+
}
|
|
267
|
+
if (mode === "agenda") {
|
|
268
|
+
const days = Array.from({ length: agendaDays }, (_, i) => addDays(a, i));
|
|
269
|
+
return { from: days[0], to: days[days.length - 1], days };
|
|
270
|
+
}
|
|
271
|
+
return { from: a, to: a, days: [a] };
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/** The anchor one step back (dir −1) or on (+1) in a mode. */
|
|
275
|
+
export function stepAnchor(mode, anchor, dir, { count = 7, agendaDays = 14 } = {}) {
|
|
276
|
+
if (mode === "month") return addMonths(anchor, dir);
|
|
277
|
+
if (mode === "week") return addDays(anchor, dir * (count >= 7 ? 7 : count));
|
|
278
|
+
if (mode === "agenda") return addDays(anchor, dir * agendaDays);
|
|
279
|
+
return addDays(anchor, dir);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/** A range in words: "Sep 21 – 27, 2026", "Sep 28 – Oct 4, 2026",
|
|
283
|
+
* "Dec 29, 2026 – Jan 4, 2027". */
|
|
284
|
+
export function rangeLabel(from, to, { locale } = {}) {
|
|
285
|
+
if (from === to) return formatDate(from, { month: "short", day: "numeric", year: "numeric" }, { locale });
|
|
286
|
+
const sameYear = from.slice(0, 4) === to.slice(0, 4);
|
|
287
|
+
const sameMonth = sameYear && from.slice(5, 7) === to.slice(5, 7);
|
|
288
|
+
const a = formatDate(from, sameYear ? { month: "short", day: "numeric" } : { month: "short", day: "numeric", year: "numeric" }, { locale });
|
|
289
|
+
const b = formatDate(to, sameMonth ? { day: "numeric" } : { month: "short", day: "numeric" }, { locale });
|
|
290
|
+
return `${a} – ${b}, ${to.slice(0, 4)}`;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** The heading a mode shows: "September 2026", a week's range, "Wednesday,
|
|
294
|
+
* September 23" (with the year when it is not `today`'s). */
|
|
295
|
+
export function titleFor(mode, range, anchor, { today, locale } = {}) {
|
|
296
|
+
if (mode === "month") return formatDate(anchor, { month: "long", year: "numeric" }, { locale });
|
|
297
|
+
if (mode === "day") {
|
|
298
|
+
const sameYear = !today || anchor.slice(0, 4) === today.slice(0, 4);
|
|
299
|
+
return formatDate(anchor, sameYear ? { weekday: "long", month: "long", day: "numeric" } : { weekday: "long", month: "long", day: "numeric", year: "numeric" }, { locale });
|
|
300
|
+
}
|
|
301
|
+
return rangeLabel(range.from, range.to, { locale });
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** "9 AM" / "21" — an hour on the grid's gutter. */
|
|
305
|
+
export function hourLabel(hour, { locale } = {}) {
|
|
306
|
+
return new Intl.DateTimeFormat(locale, { hour: "numeric", timeZone: "UTC" }).format(new Date(hour * 3600000));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** "9:30 AM" for minutes after midnight. */
|
|
310
|
+
export function minutesLabel(minutes, { locale } = {}) {
|
|
311
|
+
return formatTime(withTime("2000-01-01", Math.min(minutes, DAY_MINUTES - 1)), { locale });
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** "9:30 – 11:00 AM"-ish words for a timed event, "All day", or "Due
|
|
315
|
+
* 5:00 PM" for a deadline. */
|
|
316
|
+
export function eventTimeLabel(event, { locale } = {}) {
|
|
317
|
+
if (!event?.timed) return "All day";
|
|
318
|
+
if (event.deadline) return `Due ${minutesLabel(event.from, { locale })}`;
|
|
319
|
+
return `${minutesLabel(event.from, { locale })} – ${minutesLabel(event.to, { locale })}`;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// ---- the available-time layer --------------------------------------------
|
|
323
|
+
|
|
324
|
+
const HHMM = /^(\d{1,2}):(\d{2})$/;
|
|
325
|
+
const toMin = (v) => {
|
|
326
|
+
if (typeof v === "number") return v;
|
|
327
|
+
const m = HHMM.exec(String(v ?? ""));
|
|
328
|
+
return m ? +m[1] * 60 + +m[2] : null;
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
function intervals(list) {
|
|
332
|
+
return (list ?? [])
|
|
333
|
+
.map((r) => (Array.isArray(r) ? [toMin(r[0]), toMin(r[1])] : [toMin(r?.from), toMin(r?.to)]))
|
|
334
|
+
.filter(([a, b]) => a !== null && b !== null && b > a)
|
|
335
|
+
.map(([a, b]) => [clamp(a, 0, DAY_MINUTES), clamp(b, 0, DAY_MINUTES)])
|
|
336
|
+
.sort((x, y) => x[0] - y[0]);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* The open hours on a day, as [[from, to], …] minutes. `availability` is
|
|
341
|
+
* { days: [1,2,3,4,5], from: "09:00", to: "17:00" } the simple week
|
|
342
|
+
* { weekly: { 1: [["09:00","12:00"], ["13:00","17:00"]], … } } per weekday (0 Sunday)
|
|
343
|
+
* …either, plus dates: { "2026-12-24": [["09:00","12:00"]], "2026-12-25": [] }
|
|
344
|
+
* or a function (day) → [[from, to], …]
|
|
345
|
+
* Nothing given → the whole day is open.
|
|
346
|
+
*/
|
|
347
|
+
export function availabilityOn(day, availability) {
|
|
348
|
+
if (!availability) return [[0, DAY_MINUTES]];
|
|
349
|
+
if (typeof availability === "function") return intervals(availability(day));
|
|
350
|
+
const d = dayOf(day);
|
|
351
|
+
if (availability.dates && Object.hasOwn(availability.dates, d)) return intervals(availability.dates[d]);
|
|
352
|
+
const wd = weekdayOf(d);
|
|
353
|
+
if (availability.weekly) return intervals(availability.weekly[wd] ?? availability.weekly[String(wd)]);
|
|
354
|
+
const days = availability.days ?? [1, 2, 3, 4, 5];
|
|
355
|
+
if (!days.includes(wd)) return [];
|
|
356
|
+
return intervals([[availability.from ?? "09:00", availability.to ?? "17:00"]]);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/** The closed stretches of a day: the complement of availabilityOn. */
|
|
360
|
+
export function closedOn(day, availability) {
|
|
361
|
+
const open = availabilityOn(day, availability);
|
|
362
|
+
const out = [];
|
|
363
|
+
let cursor = 0;
|
|
364
|
+
for (const [a, b] of open) {
|
|
365
|
+
if (a > cursor) out.push([cursor, a]);
|
|
366
|
+
cursor = Math.max(cursor, b);
|
|
367
|
+
}
|
|
368
|
+
if (cursor < DAY_MINUTES) out.push([cursor, DAY_MINUTES]);
|
|
369
|
+
return out;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function busyIntervals(busy, day, buffer) {
|
|
373
|
+
const out = [];
|
|
374
|
+
for (const b of busy ?? []) {
|
|
375
|
+
let a;
|
|
376
|
+
let z;
|
|
377
|
+
if (b && Object.hasOwn(b, "end")) {
|
|
378
|
+
// an interval { start, end } (a booking, a meeting)
|
|
379
|
+
const sd = dayOf(b.start);
|
|
380
|
+
const ed = dayOf(b.end);
|
|
381
|
+
if (!sd || !ed || sd > day || ed < day) continue;
|
|
382
|
+
a = sd < day ? 0 : minutesOf(b.start) ?? 0;
|
|
383
|
+
z = ed > day ? DAY_MINUTES : minutesOf(b.end) ?? DAY_MINUTES;
|
|
384
|
+
} else {
|
|
385
|
+
// a task: only a timed block takes time; an all-day date does not
|
|
386
|
+
const e = eventOf(b);
|
|
387
|
+
if (!e?.timed || e.start !== day) continue;
|
|
388
|
+
a = e.from;
|
|
389
|
+
z = e.to;
|
|
390
|
+
}
|
|
391
|
+
out.push([a - buffer, z + buffer]);
|
|
392
|
+
}
|
|
393
|
+
return out;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Open slots between two days — what a booking page offers, and what a
|
|
398
|
+
* calendar's `getSlots` can return as is:
|
|
399
|
+
* freeSlots({ from, to, availability, busy, minutes: 30, step, buffer, notice, now })
|
|
400
|
+
* → [{ id, day, start: "2026-09-24T09:00", end: "2026-09-24T09:30", from: 540, to: 570 }]
|
|
401
|
+
* `busy` mixes tasks (their timed blocks) and { start, end } intervals;
|
|
402
|
+
* `buffer` minutes are kept free around each; `step` is how far apart
|
|
403
|
+
* slots start (default `minutes`); nothing starts before `now` plus
|
|
404
|
+
* `notice` minutes (`now` a "YYYY-MM-DDTHH:mm" string).
|
|
405
|
+
*/
|
|
406
|
+
export function freeSlots({ from, to, availability, busy = [], minutes = 30, step, buffer = 0, notice = 0, now } = {}) {
|
|
407
|
+
const a = dayNumber(from);
|
|
408
|
+
const z = dayNumber(to ?? from);
|
|
409
|
+
if (a === null || z === null) return [];
|
|
410
|
+
const inc = step > 0 ? step : minutes;
|
|
411
|
+
const nowDay = dayOf(now);
|
|
412
|
+
const earliest = nowDay ? (minutesOf(now) ?? 0) + notice : null;
|
|
413
|
+
const out = [];
|
|
414
|
+
for (let n = a; n <= z && out.length < 5000; n++) {
|
|
415
|
+
const day = addDays(from, n - a);
|
|
416
|
+
if (nowDay && day < nowDay) continue;
|
|
417
|
+
const taken = busyIntervals(busy, day, buffer);
|
|
418
|
+
for (const [open, close] of availabilityOn(day, availability)) {
|
|
419
|
+
for (let s = open; s + minutes <= close; s += inc) {
|
|
420
|
+
const e = s + minutes;
|
|
421
|
+
if (nowDay && day === nowDay && s < earliest) continue;
|
|
422
|
+
if (taken.some(([x, y]) => s < y && x < e)) continue;
|
|
423
|
+
out.push({ id: `${day}T${s}`, day, start: withTime(day, s), end: withTime(day, Math.min(e, DAY_MINUTES - 1)), from: s, to: e });
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return out;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/** A slot list (from `slots` or `getSlots`) normalised to the shape the
|
|
431
|
+
* grid draws: { id, day, from, to, start, end, …yours }. */
|
|
432
|
+
export function normalizeSlots(slots) {
|
|
433
|
+
const out = [];
|
|
434
|
+
for (const s of slots ?? []) {
|
|
435
|
+
const day = s.day ?? dayOf(s.start);
|
|
436
|
+
const from = s.from ?? minutesOf(s.start);
|
|
437
|
+
const to = s.to ?? minutesOf(s.end) ?? (from !== null ? from + 30 : null);
|
|
438
|
+
if (!day || from === null || to === null) continue;
|
|
439
|
+
out.push({ ...s, id: String(s.id ?? `${day}T${from}`), day, from, to, start: s.start ?? withTime(day, from), end: s.end ?? withTime(day, to) });
|
|
440
|
+
}
|
|
441
|
+
return out;
|
|
442
|
+
}
|