makersclaw 0.2.0 → 0.3.1
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/THIRD-PARTY-NOTICES.md +180 -0
- package/package.json +3 -2
- 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 +10 -6
- 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 +205 -8
- 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 +12 -7
- 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 +3411 -29
- 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 +55 -5
- package/registry/blocks/board/block.json +2 -2
- package/registry/blocks/board/board.jsx +230 -86
- 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 +80 -0
- 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/cli.mjs +19 -6
- package/src/install.mjs +18 -0
- package/src/registry.mjs +38 -4
- package/src/shadcn.mjs +14 -1
- 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/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/template.json +264 -8
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// How an item is coloured on the calendar — tokens only. A timed block
|
|
2
|
+
// and an all-day bar wear a tint with a solid leading edge; a timed item
|
|
3
|
+
// in a month cell is a dot. The colour comes from the task's project
|
|
4
|
+
// (chart-1…5), or its status's tone with colorBy="status"; one without
|
|
5
|
+
// either wears the theme's primary.
|
|
6
|
+
|
|
7
|
+
const HUE_TINT = {
|
|
8
|
+
1: "bg-chart-1/15 hover:bg-chart-1/25 border-s-chart-1",
|
|
9
|
+
2: "bg-chart-2/15 hover:bg-chart-2/25 border-s-chart-2",
|
|
10
|
+
3: "bg-chart-3/15 hover:bg-chart-3/25 border-s-chart-3",
|
|
11
|
+
4: "bg-chart-4/15 hover:bg-chart-4/25 border-s-chart-4",
|
|
12
|
+
5: "bg-chart-5/15 hover:bg-chart-5/25 border-s-chart-5",
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const HUE_DOT = { 1: "bg-chart-1", 2: "bg-chart-2", 3: "bg-chart-3", 4: "bg-chart-4", 5: "bg-chart-5" };
|
|
16
|
+
|
|
17
|
+
const TONE_TINT = {
|
|
18
|
+
neutral: "bg-muted hover:bg-accent border-s-muted-foreground",
|
|
19
|
+
primary: "bg-primary/10 hover:bg-primary/15 border-s-primary",
|
|
20
|
+
info: "bg-info/15 hover:bg-info/25 border-s-info",
|
|
21
|
+
success: "bg-success/15 hover:bg-success/25 border-s-success",
|
|
22
|
+
warning: "bg-warning/15 hover:bg-warning/25 border-s-warning",
|
|
23
|
+
danger: "bg-destructive/10 hover:bg-destructive/20 border-s-destructive",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const TONE_DOT = {
|
|
27
|
+
neutral: "bg-muted-foreground",
|
|
28
|
+
primary: "bg-primary",
|
|
29
|
+
info: "bg-info",
|
|
30
|
+
success: "bg-success",
|
|
31
|
+
warning: "bg-warning",
|
|
32
|
+
danger: "bg-destructive",
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const DEFAULT = { tint: TONE_TINT.primary, dot: TONE_DOT.primary };
|
|
36
|
+
|
|
37
|
+
/** { tint, dot } class strings for a task. */
|
|
38
|
+
export function paintOf(task, ctx, colorBy = "project") {
|
|
39
|
+
if (colorBy === "status") {
|
|
40
|
+
const s = ctx.statusById.get(String(task.status));
|
|
41
|
+
if (s?.hue && HUE_TINT[s.hue]) return { tint: HUE_TINT[s.hue], dot: HUE_DOT[s.hue] };
|
|
42
|
+
const tone = s?.tone ?? "neutral";
|
|
43
|
+
return { tint: TONE_TINT[tone] ?? TONE_TINT.neutral, dot: TONE_DOT[tone] ?? TONE_DOT.neutral };
|
|
44
|
+
}
|
|
45
|
+
if (colorBy === "project") {
|
|
46
|
+
const p = ctx.projectById.get(String(task.project));
|
|
47
|
+
if (p?.hue && HUE_TINT[p.hue]) return { tint: HUE_TINT[p.hue], dot: HUE_DOT[p.hue] };
|
|
48
|
+
}
|
|
49
|
+
return DEFAULT;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** A drag handle's props with our keys first: `onKey(e)` returns true
|
|
53
|
+
* when it handled the key, and dnd-kit's own keyboard pickup never sees
|
|
54
|
+
* it (Enter opens, Delete deletes, the arrows nudge a timed block). */
|
|
55
|
+
export function withKeys(handle, onKey) {
|
|
56
|
+
return {
|
|
57
|
+
...handle,
|
|
58
|
+
onKeyDown: (e) => {
|
|
59
|
+
if (onKey?.(e) === true) return;
|
|
60
|
+
handle?.onKeyDown?.(e);
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Whether a key event came from a field the founder is typing in. */
|
|
66
|
+
export function isTyping(e) {
|
|
67
|
+
const t = e.target;
|
|
68
|
+
return Boolean(t && (t.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(t.tagName)));
|
|
69
|
+
}
|
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { cx } from "../../ui";
|
|
5
|
+
import { dayOf, formatDate, isDone, isWeekend, minutesOf, useDraggableTask, useDropTarget } from "../task-model";
|
|
6
|
+
import { DAY_MINUTES, eventTimeLabel, hourLabel, layoutLanes, layoutTimed, minutesLabel, snapMinutes } from "./calendar-model";
|
|
7
|
+
import { DraftInput } from "./draft";
|
|
8
|
+
import { paintOf, withKeys } from "./paint";
|
|
9
|
+
|
|
10
|
+
// The week and the day: a strip of all-day items on top, then the hours
|
|
11
|
+
// as a scrolling grid with one column per day. Timed tasks are tinted
|
|
12
|
+
// blocks placed by their times; overlapping ones share the column side by
|
|
13
|
+
// side. Drag a block to move it (it snaps to the quarter hour and to the
|
|
14
|
+
// day columns as it goes), drag its bottom edge to change how long it
|
|
15
|
+
// runs, press on an empty stretch and drag to make a new one (a click
|
|
16
|
+
// makes an hour). A line marks now. The available-time layer draws closed
|
|
17
|
+
// hours muted and open slots as dashed boxes.
|
|
18
|
+
//
|
|
19
|
+
// Keyboard: a focused block moves with the arrow keys (up/down 15
|
|
20
|
+
// minutes, left/right a day), Shift+up/down changes its length, Enter
|
|
21
|
+
// opens it, Delete removes it (with Undo).
|
|
22
|
+
|
|
23
|
+
const GUTTER = "w-14 shrink-0";
|
|
24
|
+
|
|
25
|
+
export function TimeGrid({ days, events, api, hourHeight = 48, height = "40rem", closed, slots, renderSlot, onSlotClick, selectedSlot, slotLabel, now }) {
|
|
26
|
+
const { ctx, locale } = api;
|
|
27
|
+
const n = days.length;
|
|
28
|
+
const cols = { gridTemplateColumns: `repeat(${n}, minmax(0, 1fr))` };
|
|
29
|
+
const scrollRef = useRef(null);
|
|
30
|
+
const colsRef = useRef(null);
|
|
31
|
+
const colWidth = () => (colsRef.current?.getBoundingClientRect().width ?? 700) / n;
|
|
32
|
+
const timed = useMemo(() => events.filter((e) => e.timed), [events]);
|
|
33
|
+
const allDay = useMemo(() => events.filter((e) => !e.timed), [events]);
|
|
34
|
+
const nowDay = dayOf(now);
|
|
35
|
+
const nowMin = now ? minutesOf(now) : null;
|
|
36
|
+
|
|
37
|
+
// Open the grid near what matters: now, else the day's first item, else 8 AM.
|
|
38
|
+
const first = timed.length ? Math.min(...timed.map((e) => e.from)) : null;
|
|
39
|
+
const focusMin = nowDay && days.includes(nowDay) && nowMin !== null ? nowMin - 90 : first !== null ? first - 30 : 8 * 60;
|
|
40
|
+
const scrollKey = `${days[0]}:${n}`;
|
|
41
|
+
const scrolled = useRef(null);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (scrolled.current === scrollKey || !scrollRef.current) return;
|
|
44
|
+
scrolled.current = scrollKey;
|
|
45
|
+
scrollRef.current.scrollTop = Math.max(0, (focusMin / 60) * hourHeight);
|
|
46
|
+
}, [scrollKey, focusMin, hourHeight]);
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div className="overflow-hidden rounded-lg border border-border bg-card">
|
|
50
|
+
<div className="flex overflow-y-hidden border-b border-border [scrollbar-gutter:stable]">
|
|
51
|
+
<div className={GUTTER} />
|
|
52
|
+
<div className="grid flex-1" style={cols}>
|
|
53
|
+
{days.map((day) => (
|
|
54
|
+
<DayHead key={day} day={day} api={api} single={n === 1} />
|
|
55
|
+
))}
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
<AllDayStrip days={days} events={allDay} api={api} cols={cols} />
|
|
59
|
+
<div ref={scrollRef} className="relative overflow-y-auto overscroll-contain [scrollbar-gutter:stable]" style={{ height }}>
|
|
60
|
+
<div className="relative flex" style={{ height: 24 * hourHeight }}>
|
|
61
|
+
<div className={cx(GUTTER, "relative")} aria-hidden="true">
|
|
62
|
+
{Array.from({ length: 23 }, (_, i) => i + 1).map((h) => (
|
|
63
|
+
<span key={h} data-nums className="absolute end-2 -translate-y-1/2 text-2xs text-muted-foreground" style={{ top: h * hourHeight }}>
|
|
64
|
+
{hourLabel(h, { locale })}
|
|
65
|
+
</span>
|
|
66
|
+
))}
|
|
67
|
+
</div>
|
|
68
|
+
<div ref={colsRef} className="relative grid flex-1" style={cols}>
|
|
69
|
+
<div aria-hidden="true" className="pointer-events-none absolute inset-0">
|
|
70
|
+
{Array.from({ length: 23 }, (_, i) => i + 1).map((h) => (
|
|
71
|
+
<div key={h} className="absolute inset-x-0 border-t border-border" style={{ top: h * hourHeight }} />
|
|
72
|
+
))}
|
|
73
|
+
</div>
|
|
74
|
+
{days.map((day, i) => (
|
|
75
|
+
<DayColumn
|
|
76
|
+
key={day}
|
|
77
|
+
day={day}
|
|
78
|
+
index={i}
|
|
79
|
+
days={days}
|
|
80
|
+
events={timed.filter((e) => e.start === day)}
|
|
81
|
+
api={api}
|
|
82
|
+
hourHeight={hourHeight}
|
|
83
|
+
colWidth={colWidth}
|
|
84
|
+
closed={closed ? closed(day) : null}
|
|
85
|
+
slots={slots?.filter((s) => s.day === day)}
|
|
86
|
+
renderSlot={renderSlot}
|
|
87
|
+
onSlotClick={onSlotClick}
|
|
88
|
+
selectedSlot={selectedSlot}
|
|
89
|
+
slotLabel={slotLabel}
|
|
90
|
+
nowMin={day === nowDay ? nowMin : null}
|
|
91
|
+
weekend={isWeekend(day, ctx.weekend)}
|
|
92
|
+
/>
|
|
93
|
+
))}
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function DayHead({ day, api, single }) {
|
|
102
|
+
const { ctx, locale } = api;
|
|
103
|
+
const today = day === ctx.today;
|
|
104
|
+
return (
|
|
105
|
+
<div className={cx("flex min-w-0 items-center justify-center border-s border-border py-2 first:border-s-0", single && "justify-start ps-3")}>
|
|
106
|
+
{/* raw: the heading is the way into that day (a button in the header
|
|
107
|
+
row); a kit Button would pad it as an action. */}
|
|
108
|
+
<button
|
|
109
|
+
type="button"
|
|
110
|
+
onClick={() => api.openDay(day)}
|
|
111
|
+
disabled={single}
|
|
112
|
+
aria-label={`${formatDate(day, { weekday: "long", month: "long", day: "numeric" }, { locale })}. Open the day`}
|
|
113
|
+
aria-current={today ? "date" : undefined}
|
|
114
|
+
className="group/head inline-flex min-w-0 items-center gap-1.5 rounded-md px-1.5 py-1 outline-none transition-colors duration-150 hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-default disabled:hover:bg-transparent"
|
|
115
|
+
>
|
|
116
|
+
<span className={cx("text-xs", today ? "font-medium text-primary" : "text-muted-foreground")}>{formatDate(day, { weekday: "short" }, { locale })}</span>
|
|
117
|
+
<span
|
|
118
|
+
data-nums
|
|
119
|
+
className={cx("inline-flex size-7 items-center justify-center rounded-full text-sm font-semibold", today ? "bg-primary text-primary-foreground" : "text-foreground")}
|
|
120
|
+
>
|
|
121
|
+
{Number(day.slice(8, 10))}
|
|
122
|
+
</span>
|
|
123
|
+
</button>
|
|
124
|
+
</div>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ---- the all-day strip ----------------------------------------------------
|
|
129
|
+
|
|
130
|
+
const STRIP_LANES = 3;
|
|
131
|
+
|
|
132
|
+
function AllDayStrip({ days, events, api, cols }) {
|
|
133
|
+
const [open, setOpen] = useState(false);
|
|
134
|
+
const rowRef = useRef(null);
|
|
135
|
+
const layout = useMemo(() => layoutLanes(events, days), [events, days]);
|
|
136
|
+
const over = layout.lanes > STRIP_LANES && !open;
|
|
137
|
+
const lanes = over ? STRIP_LANES - 1 : layout.lanes;
|
|
138
|
+
const hiddenCount = layout.items.filter((it) => it.lane >= lanes).length;
|
|
139
|
+
const cellWidth = () => (rowRef.current?.getBoundingClientRect().width ?? 700) / days.length;
|
|
140
|
+
const drafting = api.draft?.allDay && days.includes(api.draft.day);
|
|
141
|
+
const rows = Math.max(lanes + (over ? 1 : 0) + (drafting ? 1 : 0), 1);
|
|
142
|
+
return (
|
|
143
|
+
<div className="flex overflow-y-hidden border-b border-border [scrollbar-gutter:stable]">
|
|
144
|
+
<div className={cx(GUTTER, "flex items-start justify-end pe-2 pt-1.5 text-2xs text-muted-foreground")}>All day</div>
|
|
145
|
+
<div ref={rowRef} className="relative grid flex-1" style={{ ...cols, minHeight: rows * 24 + 8 }}>
|
|
146
|
+
{days.map((day) => (
|
|
147
|
+
<StripCell key={day} day={day} api={api} />
|
|
148
|
+
))}
|
|
149
|
+
<div className="pointer-events-none absolute inset-x-0 top-1 grid gap-y-0.5" style={{ ...cols, gridAutoRows: "22px" }}>
|
|
150
|
+
{layout.items
|
|
151
|
+
.filter((it) => it.lane < lanes)
|
|
152
|
+
.map((it) => (
|
|
153
|
+
<StripItem key={it.event.id} item={it} days={days} api={api} cellWidth={cellWidth} />
|
|
154
|
+
))}
|
|
155
|
+
{over ? (
|
|
156
|
+
// raw: a line of small text sized to a lane that opens the strip;
|
|
157
|
+
// a kit Button is a 36px action.
|
|
158
|
+
<button
|
|
159
|
+
type="button"
|
|
160
|
+
onClick={() => setOpen(true)}
|
|
161
|
+
style={{ gridColumn: `1 / span ${days.length}`, gridRow: lanes + 1 }}
|
|
162
|
+
className="pointer-events-auto mx-1 justify-self-start rounded-sm px-1.5 text-xs font-medium text-muted-foreground outline-none hover:bg-accent hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring"
|
|
163
|
+
>
|
|
164
|
+
{hiddenCount} more
|
|
165
|
+
</button>
|
|
166
|
+
) : null}
|
|
167
|
+
{drafting ? (
|
|
168
|
+
<div
|
|
169
|
+
style={{ gridColumn: `${days.indexOf(api.draft.day) + 1}`, gridRow: lanes + (over ? 2 : 1) }}
|
|
170
|
+
className="pointer-events-auto mx-1 flex items-center rounded-sm bg-primary/10 px-1.5 ring-1 ring-primary"
|
|
171
|
+
>
|
|
172
|
+
<DraftInput label={`New all-day task on ${formatDate(api.draft.day, { weekday: "long", month: "long", day: "numeric" })}`} onSubmit={api.saveDraft} onCancel={api.cancelDraft} />
|
|
173
|
+
</div>
|
|
174
|
+
) : null}
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function StripCell({ day, api }) {
|
|
182
|
+
const label = `${formatDate(day, { weekday: "long", month: "long", day: "numeric" }, { locale: api.locale })}, all day`;
|
|
183
|
+
const drop = useDropTarget(`strip:${day}`, { kind: "cell", day, label });
|
|
184
|
+
return (
|
|
185
|
+
<div
|
|
186
|
+
ref={drop.setNodeRef}
|
|
187
|
+
onClick={(e) => {
|
|
188
|
+
if (api.editable && e.target === e.currentTarget) api.startDraft({ day, allDay: true });
|
|
189
|
+
}}
|
|
190
|
+
className={cx("border-s border-border transition-colors duration-150 first:border-s-0", drop.isOver && "bg-accent")}
|
|
191
|
+
/>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function StripItem({ item, days, api, cellWidth }) {
|
|
196
|
+
const { event, col, span, lane, clippedStart, clippedEnd } = item;
|
|
197
|
+
const { ctx, editable } = api;
|
|
198
|
+
const task = event.task;
|
|
199
|
+
const done = isDone(task, ctx);
|
|
200
|
+
const paint = paintOf(task, ctx, api.colorBy);
|
|
201
|
+
const title = task.title || "Untitled";
|
|
202
|
+
const d = useDraggableTask(`strip:${event.id}`, { kind: "span", task, event }, { disabled: !editable });
|
|
203
|
+
const canResize = editable && !clippedEnd;
|
|
204
|
+
const r = useDraggableTask(`sx:${event.id}`, { kind: "resize-x", task, event, cellWidth }, { disabled: !canResize });
|
|
205
|
+
const grow = r.isDragging && r.transform ? Math.round(r.transform.x / cellWidth()) : 0;
|
|
206
|
+
const shownSpan = Math.max(1, Math.min(days.length - col, span + Math.max(grow, 1 - span)));
|
|
207
|
+
const keys = withKeys(d.handle, (e) => {
|
|
208
|
+
if (e.key === "Enter") return true;
|
|
209
|
+
if ((e.key === "Delete" || e.key === "Backspace") && editable) {
|
|
210
|
+
e.preventDefault();
|
|
211
|
+
api.remove(task);
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
if (editable && e.shiftKey && (e.key === "ArrowRight" || e.key === "ArrowLeft")) {
|
|
215
|
+
e.preventDefault();
|
|
216
|
+
api.extend(event, e.key === "ArrowRight" ? 1 : -1);
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
return false;
|
|
220
|
+
});
|
|
221
|
+
return (
|
|
222
|
+
// raw: an all-day bar is a drag source that also opens; a kit
|
|
223
|
+
// Button would centre and pad it as an action.
|
|
224
|
+
<button
|
|
225
|
+
type="button"
|
|
226
|
+
ref={d.setNodeRef}
|
|
227
|
+
data-cal-id={event.id}
|
|
228
|
+
{...(editable ? keys : {})}
|
|
229
|
+
onPointerDown={(e) => {
|
|
230
|
+
if (!editable) return;
|
|
231
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
232
|
+
const w = rect.width / shownSpan;
|
|
233
|
+
api.setGrab(days[col + Math.max(0, Math.min(shownSpan - 1, Math.floor((e.clientX - rect.left) / w)))]);
|
|
234
|
+
keys.onPointerDown?.(e);
|
|
235
|
+
}}
|
|
236
|
+
onClick={api.open ? () => api.open(task) : undefined}
|
|
237
|
+
aria-label={`${title}, ${event.start === event.end ? "all day" : `${formatDate(event.start, { month: "short", day: "numeric" })} to ${formatDate(event.end, { month: "short", day: "numeric" })}`}${done ? ", done" : ""}`}
|
|
238
|
+
title={title}
|
|
239
|
+
style={{ gridColumn: `${col + 1} / span ${shownSpan}`, gridRow: lane + 1 }}
|
|
240
|
+
className={cx(
|
|
241
|
+
"pointer-events-auto relative flex min-w-0 items-center rounded-sm border-s-[3px] px-1.5 text-left text-xs font-medium text-foreground outline-none transition-[opacity,background-color] duration-150 focus-visible:ring-2 focus-visible:ring-ring",
|
|
242
|
+
paint.tint,
|
|
243
|
+
clippedStart ? "ms-0 rounded-s-none border-s-0 ps-2" : "ms-1",
|
|
244
|
+
clippedEnd ? "me-0 rounded-e-none" : "me-1",
|
|
245
|
+
editable ? "cursor-grab active:cursor-grabbing" : api.open ? "cursor-pointer" : "cursor-default",
|
|
246
|
+
d.isDragging && "opacity-40",
|
|
247
|
+
r.isDragging && "ring-2 ring-primary",
|
|
248
|
+
done && "text-muted-foreground",
|
|
249
|
+
)}
|
|
250
|
+
>
|
|
251
|
+
<span className={cx("min-w-0 flex-1 truncate", done && "line-through")}>{title}</span>
|
|
252
|
+
{canResize ? (
|
|
253
|
+
<span
|
|
254
|
+
ref={r.setNodeRef}
|
|
255
|
+
{...r.handle}
|
|
256
|
+
role="presentation"
|
|
257
|
+
tabIndex={-1}
|
|
258
|
+
aria-hidden="true"
|
|
259
|
+
onClick={(e) => e.stopPropagation()}
|
|
260
|
+
className="absolute inset-y-0 end-0 w-2 cursor-ew-resize rounded-e-sm hover:bg-primary/30"
|
|
261
|
+
/>
|
|
262
|
+
) : null}
|
|
263
|
+
</button>
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// ---- one day's column of hours ------------------------------------------
|
|
268
|
+
|
|
269
|
+
function DayColumn({ day, index, days, events, api, hourHeight, colWidth, closed, slots, renderSlot, onSlotClick, selectedSlot, slotLabel, nowMin, weekend }) {
|
|
270
|
+
const { editable, locale } = api;
|
|
271
|
+
const ppm = hourHeight / 60;
|
|
272
|
+
const ref = useRef(null);
|
|
273
|
+
const label = formatDate(day, { weekday: "long", month: "long", day: "numeric" }, { locale });
|
|
274
|
+
const drop = useDropTarget(`col:${day}`, { kind: "column", day, label, top: () => ref.current?.getBoundingClientRect().top ?? 0 });
|
|
275
|
+
const layout = useMemo(() => layoutTimed(events), [events]);
|
|
276
|
+
const [hover, setHover] = useState(null); // minutes under the mouse
|
|
277
|
+
const [making, setMaking] = useState(null); // { a, b } while press-dragging a new block
|
|
278
|
+
const lastPointer = useRef("mouse");
|
|
279
|
+
const drafting = api.draft && !api.draft.allDay && api.draft.day === day ? api.draft : null;
|
|
280
|
+
|
|
281
|
+
const minuteAt = (clientY) => {
|
|
282
|
+
const top = ref.current?.getBoundingClientRect().top ?? 0;
|
|
283
|
+
return Math.max(0, Math.min(DAY_MINUTES - 15, (clientY - top) / ppm));
|
|
284
|
+
};
|
|
285
|
+
const onBg = (e) => e.target === e.currentTarget || e.target.dataset?.calBg !== undefined;
|
|
286
|
+
|
|
287
|
+
return (
|
|
288
|
+
<div
|
|
289
|
+
ref={(el) => {
|
|
290
|
+
ref.current = el;
|
|
291
|
+
drop.setNodeRef(el);
|
|
292
|
+
}}
|
|
293
|
+
data-cal-bg=""
|
|
294
|
+
className={cx(
|
|
295
|
+
"relative border-s border-border transition-colors duration-150 first:border-s-0",
|
|
296
|
+
weekend && "bg-muted/20",
|
|
297
|
+
drop.isOver && "bg-accent/50",
|
|
298
|
+
)}
|
|
299
|
+
onPointerDown={(e) => {
|
|
300
|
+
lastPointer.current = e.pointerType;
|
|
301
|
+
if (!editable || e.pointerType !== "mouse" || e.button !== 0 || !onBg(e)) return;
|
|
302
|
+
const m = snapMinutes(minuteAt(e.clientY) - 7, 15);
|
|
303
|
+
setMaking({ a: m, b: m + 15 });
|
|
304
|
+
e.currentTarget.setPointerCapture?.(e.pointerId);
|
|
305
|
+
}}
|
|
306
|
+
onPointerMove={(e) => {
|
|
307
|
+
if (e.pointerType !== "mouse") return;
|
|
308
|
+
const m = minuteAt(e.clientY);
|
|
309
|
+
if (making) {
|
|
310
|
+
const b = snapMinutes(m, 15);
|
|
311
|
+
setMaking((x) => (x && (b !== x.b ? { ...x, b: Math.max(b, x.a + 15) } : x)));
|
|
312
|
+
} else if (editable && onBg(e)) {
|
|
313
|
+
const h = Math.floor(m / 30) * 30;
|
|
314
|
+
if (h !== hover) setHover(h);
|
|
315
|
+
} else if (hover !== null) setHover(null);
|
|
316
|
+
}}
|
|
317
|
+
onPointerLeave={() => setHover(null)}
|
|
318
|
+
onPointerUp={(e) => {
|
|
319
|
+
if (!making) return;
|
|
320
|
+
e.currentTarget.releasePointerCapture?.(e.pointerId);
|
|
321
|
+
const { a, b } = making;
|
|
322
|
+
setMaking(null);
|
|
323
|
+
setHover(null);
|
|
324
|
+
// A click (no real drag) makes the default length from the half hour.
|
|
325
|
+
if (b - a <= 15) {
|
|
326
|
+
const from = Math.floor(a / 30) * 30;
|
|
327
|
+
api.startDraft({ day, from, to: Math.min(DAY_MINUTES, from + api.defaultDuration) });
|
|
328
|
+
} else api.startDraft({ day, from: a, to: b });
|
|
329
|
+
}}
|
|
330
|
+
onClick={(e) => {
|
|
331
|
+
// A tap on a touch screen: an hour from the half hour tapped.
|
|
332
|
+
if (!editable || lastPointer.current === "mouse" || !onBg(e)) return;
|
|
333
|
+
const from = Math.floor(minuteAt(e.clientY) / 30) * 30;
|
|
334
|
+
api.startDraft({ day, from, to: Math.min(DAY_MINUTES, from + api.defaultDuration) });
|
|
335
|
+
}}
|
|
336
|
+
>
|
|
337
|
+
{closed?.map(([a, b]) => (
|
|
338
|
+
<div key={a} data-cal-bg="" aria-hidden="true" className="absolute inset-x-0 bg-muted/60" style={{ top: a * ppm, height: (b - a) * ppm }} />
|
|
339
|
+
))}
|
|
340
|
+
{slots?.map((s) => (
|
|
341
|
+
<Slot key={s.id} slot={s} ppm={ppm} renderSlot={renderSlot} onSlotClick={onSlotClick} selected={selectedSlot != null && (selectedSlot === s.id || selectedSlot === s.start)} label={slotLabel} locale={locale} />
|
|
342
|
+
))}
|
|
343
|
+
{hover !== null && !making && !drafting ? (
|
|
344
|
+
<div
|
|
345
|
+
aria-hidden="true"
|
|
346
|
+
className="pointer-events-none absolute inset-x-1 flex items-start rounded-md border border-dashed border-primary/40 px-1.5 pt-0.5 text-2xs font-medium text-primary"
|
|
347
|
+
style={{ top: hover * ppm + 1, height: 30 * ppm - 2 }}
|
|
348
|
+
>
|
|
349
|
+
+ {minutesLabel(hover, { locale })}
|
|
350
|
+
</div>
|
|
351
|
+
) : null}
|
|
352
|
+
{events.map((e) => (
|
|
353
|
+
<EventBlock key={e.id} event={e} pos={layout.get(e.id) ?? { col: 0, cols: 1, span: 1 }} ppm={ppm} api={api} index={index} days={days} colWidth={colWidth} />
|
|
354
|
+
))}
|
|
355
|
+
{making ? (
|
|
356
|
+
<div aria-hidden="true" className="pointer-events-none absolute inset-x-1 z-10 rounded-md bg-primary/15 px-1.5 py-0.5 text-2xs font-medium text-primary ring-1 ring-primary" style={{ top: making.a * ppm, height: (making.b - making.a) * ppm }}>
|
|
357
|
+
{minutesLabel(making.a, { locale })} – {minutesLabel(making.b, { locale })}
|
|
358
|
+
</div>
|
|
359
|
+
) : null}
|
|
360
|
+
{drafting ? (
|
|
361
|
+
<div
|
|
362
|
+
className="absolute inset-x-1 z-20 flex flex-col gap-0.5 rounded-md bg-card px-1.5 py-1 shadow-md ring-1 ring-primary"
|
|
363
|
+
style={{ top: drafting.from * ppm, height: Math.max((drafting.to - drafting.from) * ppm, 40) }}
|
|
364
|
+
>
|
|
365
|
+
<DraftInput label={`New task on ${label}, ${minutesLabel(drafting.from, { locale })} to ${minutesLabel(drafting.to, { locale })}`} onSubmit={api.saveDraft} onCancel={api.cancelDraft} />
|
|
366
|
+
<span data-nums className="text-2xs text-muted-foreground">
|
|
367
|
+
{minutesLabel(drafting.from, { locale })} – {minutesLabel(drafting.to, { locale })}
|
|
368
|
+
</span>
|
|
369
|
+
</div>
|
|
370
|
+
) : null}
|
|
371
|
+
{nowMin !== null ? (
|
|
372
|
+
<div aria-hidden="true" className="pointer-events-none absolute inset-x-0 z-10 flex items-center" style={{ top: nowMin * ppm - 1 }}>
|
|
373
|
+
<span className="-ms-1 size-2.5 shrink-0 rounded-full bg-primary ring-2 ring-card" />
|
|
374
|
+
<span className="h-0.5 flex-1 bg-primary" />
|
|
375
|
+
</div>
|
|
376
|
+
) : null}
|
|
377
|
+
</div>
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function Slot({ slot, ppm, renderSlot, onSlotClick, selected, label = "Open", locale }) {
|
|
382
|
+
const style = { top: slot.from * ppm + 1, height: Math.max((slot.to - slot.from) * ppm - 2, 16) };
|
|
383
|
+
const words = `${label}, ${minutesLabel(slot.from, { locale })} to ${minutesLabel(slot.to, { locale })}`;
|
|
384
|
+
const face = renderSlot ? (
|
|
385
|
+
renderSlot(slot, { selected })
|
|
386
|
+
) : (
|
|
387
|
+
<span data-nums className="truncate">
|
|
388
|
+
{minutesLabel(slot.from, { locale })}
|
|
389
|
+
</span>
|
|
390
|
+
);
|
|
391
|
+
const cls = cx(
|
|
392
|
+
"absolute inset-x-1 flex items-start overflow-hidden rounded-md border border-dashed px-1.5 pt-0.5 text-left text-2xs font-medium transition-colors duration-150",
|
|
393
|
+
selected ? "border-solid border-primary bg-primary text-primary-foreground" : "border-primary/50 bg-primary/5 text-primary",
|
|
394
|
+
);
|
|
395
|
+
if (!onSlotClick) {
|
|
396
|
+
return (
|
|
397
|
+
<div className={cx(cls, "pointer-events-none")} style={style} aria-label={words}>
|
|
398
|
+
{face}
|
|
399
|
+
</div>
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
return (
|
|
403
|
+
// raw: an open slot is a box on the grid placed by its times; a kit
|
|
404
|
+
// Button would pad and centre it as an action.
|
|
405
|
+
<button
|
|
406
|
+
type="button"
|
|
407
|
+
onClick={(e) => {
|
|
408
|
+
e.stopPropagation();
|
|
409
|
+
onSlotClick(slot);
|
|
410
|
+
}}
|
|
411
|
+
onPointerDown={(e) => e.stopPropagation()}
|
|
412
|
+
aria-label={words}
|
|
413
|
+
aria-pressed={selected}
|
|
414
|
+
style={style}
|
|
415
|
+
className={cx(cls, "z-[1] outline-none hover:bg-primary/15 focus-visible:ring-2 focus-visible:ring-ring", selected && "hover:bg-primary")}
|
|
416
|
+
>
|
|
417
|
+
{face}
|
|
418
|
+
</button>
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function EventBlock({ event, pos, ppm, api, index, days, colWidth }) {
|
|
423
|
+
const { ctx, editable, locale } = api;
|
|
424
|
+
const task = event.task;
|
|
425
|
+
const done = isDone(task, ctx);
|
|
426
|
+
const paint = paintOf(task, ctx, api.colorBy);
|
|
427
|
+
const title = task.title || "Untitled";
|
|
428
|
+
const d = useDraggableTask(`ev:${event.id}`, { kind: "timed", task, event, colIndex: index, colWidth }, { disabled: !editable });
|
|
429
|
+
const canResize = editable && !event.deadline;
|
|
430
|
+
const r = useDraggableTask(`ry:${event.id}`, { kind: "resize-y", task, event }, { disabled: !canResize });
|
|
431
|
+
|
|
432
|
+
// While dragged, the block itself shows where it will land: snapped to
|
|
433
|
+
// the quarter hour and to a day column.
|
|
434
|
+
let from = event.from;
|
|
435
|
+
let to = event.to;
|
|
436
|
+
let dx = 0;
|
|
437
|
+
if (d.isDragging && d.transform) {
|
|
438
|
+
const w = colWidth();
|
|
439
|
+
const k = Math.max(-index, Math.min(days.length - 1 - index, Math.round(d.transform.x / w)));
|
|
440
|
+
dx = k * w;
|
|
441
|
+
const dm = Math.max(-event.from, Math.min(DAY_MINUTES - event.to, snapMinutes(d.transform.y / ppm, api.snap)));
|
|
442
|
+
from += dm;
|
|
443
|
+
to += dm;
|
|
444
|
+
}
|
|
445
|
+
if (r.isDragging && r.transform) to = Math.max(from + 15, Math.min(DAY_MINUTES, to + snapMinutes(r.transform.y / ppm, api.snap)));
|
|
446
|
+
const h = Math.max((to - from) * ppm, 18);
|
|
447
|
+
const tall = h >= 38;
|
|
448
|
+
const shown = { ...event, from, to };
|
|
449
|
+
const time = eventTimeLabel(shown, { locale });
|
|
450
|
+
const moving = d.isDragging || r.isDragging;
|
|
451
|
+
|
|
452
|
+
const keys = withKeys(d.handle, (e) => {
|
|
453
|
+
if (e.key === "Enter" || e.key === " ") return true;
|
|
454
|
+
if (!editable) return false;
|
|
455
|
+
if (e.key === "Delete" || e.key === "Backspace") {
|
|
456
|
+
e.preventDefault();
|
|
457
|
+
api.remove(task);
|
|
458
|
+
return true;
|
|
459
|
+
}
|
|
460
|
+
const step = { ArrowUp: -1, ArrowDown: 1, ArrowLeft: -1, ArrowRight: 1 }[e.key];
|
|
461
|
+
if (!step) return false;
|
|
462
|
+
e.preventDefault();
|
|
463
|
+
if (e.key === "ArrowLeft" || e.key === "ArrowRight") api.nudge(event, { dd: step });
|
|
464
|
+
else if (e.shiftKey) api.nudge(event, { dr: step * 15 });
|
|
465
|
+
else api.nudge(event, { dm: step * 15 });
|
|
466
|
+
return true;
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
return (
|
|
470
|
+
// raw: a timed block is a drag source placed by its times that also
|
|
471
|
+
// opens; a kit Button would centre and pad it as an action.
|
|
472
|
+
<button
|
|
473
|
+
type="button"
|
|
474
|
+
ref={d.setNodeRef}
|
|
475
|
+
data-cal-id={event.id}
|
|
476
|
+
{...(editable ? keys : { onKeyDown: keys.onKeyDown })}
|
|
477
|
+
onClick={api.open ? () => api.open(task) : undefined}
|
|
478
|
+
aria-label={`${title}, ${time}${done ? ", done" : ""}`}
|
|
479
|
+
aria-keyshortcuts={editable ? "ArrowUp ArrowDown ArrowLeft ArrowRight Shift+ArrowUp Shift+ArrowDown Enter Delete" : undefined}
|
|
480
|
+
title={`${title}\n${time}`}
|
|
481
|
+
style={{
|
|
482
|
+
top: from * ppm + 1,
|
|
483
|
+
height: h - 2,
|
|
484
|
+
left: `calc(${(pos.col / pos.cols) * 100}% + 2px)`,
|
|
485
|
+
width: `calc(${(pos.span / pos.cols) * 100}% - ${pos.col + pos.span < pos.cols ? 2 : 6}px)`,
|
|
486
|
+
transform: dx ? `translateX(${dx}px)` : undefined,
|
|
487
|
+
}}
|
|
488
|
+
className={cx(
|
|
489
|
+
"absolute flex flex-col overflow-hidden rounded-md border-s-[3px] px-1.5 text-left text-xs leading-tight text-foreground outline-none transition-[box-shadow,opacity,background-color] duration-150 focus-visible:z-20 focus-visible:ring-2 focus-visible:ring-ring",
|
|
490
|
+
paint.tint,
|
|
491
|
+
tall ? "py-1" : "justify-center py-0",
|
|
492
|
+
pos.cols > 1 && !moving && "ring-1 ring-card",
|
|
493
|
+
editable ? "cursor-grab active:cursor-grabbing" : api.open ? "cursor-pointer" : "cursor-default",
|
|
494
|
+
moving && "z-30 shadow-lg ring-1 ring-primary/40",
|
|
495
|
+
event.preview && "z-20 ring-2 ring-primary",
|
|
496
|
+
done && "text-muted-foreground",
|
|
497
|
+
)}
|
|
498
|
+
>
|
|
499
|
+
{tall ? (
|
|
500
|
+
<>
|
|
501
|
+
<span className={cx("line-clamp-2 font-medium", done && "line-through")}>{title}</span>
|
|
502
|
+
<span data-nums className="mt-0.5 truncate text-2xs text-muted-foreground">
|
|
503
|
+
{time}
|
|
504
|
+
</span>
|
|
505
|
+
</>
|
|
506
|
+
) : (
|
|
507
|
+
<span className="flex min-w-0 items-baseline gap-1.5">
|
|
508
|
+
<span className={cx("truncate font-medium", done && "line-through")}>{title}</span>
|
|
509
|
+
<span data-nums className="shrink-0 text-2xs text-muted-foreground">
|
|
510
|
+
{minutesLabel(from, { locale })}
|
|
511
|
+
</span>
|
|
512
|
+
</span>
|
|
513
|
+
)}
|
|
514
|
+
{canResize ? (
|
|
515
|
+
<span
|
|
516
|
+
ref={r.setNodeRef}
|
|
517
|
+
{...r.handle}
|
|
518
|
+
role="presentation"
|
|
519
|
+
tabIndex={-1}
|
|
520
|
+
aria-hidden="true"
|
|
521
|
+
onClick={(e) => e.stopPropagation()}
|
|
522
|
+
className="absolute inset-x-0 bottom-0 h-2 cursor-ns-resize after:absolute after:inset-x-1/3 after:bottom-0.5 after:h-0.5 after:rounded-full after:bg-foreground/30 after:opacity-0 after:transition-opacity hover:after:opacity-100"
|
|
523
|
+
/>
|
|
524
|
+
) : null}
|
|
525
|
+
</button>
|
|
526
|
+
);
|
|
527
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Icon, cx } from "../../ui";
|
|
4
|
+
import { DueLabel, TaskChip, useDraggableTask, useDropTarget } from "../task-model";
|
|
5
|
+
import { withKeys } from "./paint";
|
|
6
|
+
|
|
7
|
+
// The unscheduled tray: open tasks with no date yet. Beside a wide
|
|
8
|
+
// calendar it is a column to drag from (onto a day, onto an hour) and to
|
|
9
|
+
// drop on (which takes the date off). On a phone, where there is nothing
|
|
10
|
+
// to drag onto, each task has a date picker instead.
|
|
11
|
+
|
|
12
|
+
export function UnscheduledTray({ tasks, api, mode = "panel", className }) {
|
|
13
|
+
const drop = useDropTarget("tray", { kind: "tray", label: "Unscheduled" }, { disabled: !api.editable || mode !== "panel" });
|
|
14
|
+
const dragging = drop.active && drop.active.data?.kind !== "tray";
|
|
15
|
+
return (
|
|
16
|
+
<section
|
|
17
|
+
ref={drop.setNodeRef}
|
|
18
|
+
aria-label="Unscheduled tasks"
|
|
19
|
+
className={cx(
|
|
20
|
+
"flex min-h-0 flex-col gap-2 transition-colors duration-150",
|
|
21
|
+
mode === "panel" && "rounded-lg border border-border bg-card p-3",
|
|
22
|
+
mode === "panel" && dragging && "border-dashed border-primary",
|
|
23
|
+
drop.isOver && "bg-accent",
|
|
24
|
+
className,
|
|
25
|
+
)}
|
|
26
|
+
>
|
|
27
|
+
{mode === "panel" ? (
|
|
28
|
+
<header className="flex items-baseline justify-between gap-2">
|
|
29
|
+
<h3 className="text-sm font-semibold">Unscheduled</h3>
|
|
30
|
+
<span data-nums className="text-xs text-muted-foreground">
|
|
31
|
+
{tasks.length}
|
|
32
|
+
</span>
|
|
33
|
+
</header>
|
|
34
|
+
) : null}
|
|
35
|
+
{dragging ? (
|
|
36
|
+
<p className="text-xs text-muted-foreground">Drop here to take the date off.</p>
|
|
37
|
+
) : tasks.length && api.editable && mode === "panel" ? (
|
|
38
|
+
<p className="text-xs text-muted-foreground">Drag a task onto a day or an hour to schedule it.</p>
|
|
39
|
+
) : null}
|
|
40
|
+
{tasks.length ? (
|
|
41
|
+
<ul className="grid gap-1.5">
|
|
42
|
+
{tasks.map((t) => (mode === "panel" ? <TrayItem key={t.id} task={t} api={api} /> : <SheetItem key={t.id} task={t} api={api} />))}
|
|
43
|
+
</ul>
|
|
44
|
+
) : (
|
|
45
|
+
<div className="grid place-items-center gap-1.5 rounded-md border border-dashed border-border px-3 py-6 text-center">
|
|
46
|
+
<Icon name="circle-check" size={18} className="text-muted-foreground" />
|
|
47
|
+
<p className="text-sm font-medium">Everything has a date</p>
|
|
48
|
+
<p className="text-xs text-muted-foreground">Tasks without one wait here.</p>
|
|
49
|
+
</div>
|
|
50
|
+
)}
|
|
51
|
+
</section>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function TrayItem({ task, api }) {
|
|
56
|
+
const d = useDraggableTask(`tray:${task.id}`, { kind: "tray", task }, { disabled: !api.editable });
|
|
57
|
+
const keys = withKeys(d.handle, (e) => e.key === "Enter");
|
|
58
|
+
return (
|
|
59
|
+
<li ref={d.setNodeRef} data-cal-id={task.id}>
|
|
60
|
+
<TaskChip
|
|
61
|
+
task={task}
|
|
62
|
+
ctx={api.ctx}
|
|
63
|
+
onOpen={api.open ?? undefined}
|
|
64
|
+
dragging={d.isDragging}
|
|
65
|
+
dragProps={api.editable ? keys : undefined}
|
|
66
|
+
className={cx("min-h-9", api.editable && "cursor-grab active:cursor-grabbing")}
|
|
67
|
+
/>
|
|
68
|
+
</li>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function SheetItem({ task, api }) {
|
|
73
|
+
return (
|
|
74
|
+
<li className="group/row flex min-h-11 items-center gap-2">
|
|
75
|
+
<TaskChip task={task} ctx={api.ctx} onOpen={api.open ?? undefined} className="min-h-9 flex-1" />
|
|
76
|
+
{api.editable ? (
|
|
77
|
+
<DueLabel
|
|
78
|
+
value={null}
|
|
79
|
+
ctx={api.ctx}
|
|
80
|
+
quiet={false}
|
|
81
|
+
placeholder="Schedule"
|
|
82
|
+
onChange={(day) => day && api.update(task, { due: day }, `Scheduled “${task.title}”`)}
|
|
83
|
+
/>
|
|
84
|
+
) : null}
|
|
85
|
+
</li>
|
|
86
|
+
);
|
|
87
|
+
}
|