makersclaw 0.2.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/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/install.mjs +18 -0
- package/src/shadcn.mjs +8 -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/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,509 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useId, useState } from "react";
|
|
4
|
+
import { Button, Checkbox, Field, Icon, Image, Input, Kicker, Notice, RadioGroup, Textarea, Toggle, cx } from "../../ui";
|
|
5
|
+
|
|
6
|
+
// ContactSection — a public "contact us" section: a form (name, email,
|
|
7
|
+
// message; optional phone, company, subject, a topic picked from chips
|
|
8
|
+
// or radios, a consent box) and/or the ways to reach you (email, phone,
|
|
9
|
+
// address, hours, offices). Three layouts: the form alone, the form
|
|
10
|
+
// beside an info panel, and info cards (alone, above the form or beside
|
|
11
|
+
// it). The form validates in place, submits through `onSubmit(values)`
|
|
12
|
+
// — async, returning { ok } — and shows the failure, or a sent state.
|
|
13
|
+
//
|
|
14
|
+
// <ContactSection title="Talk to us" details={DETAILS}
|
|
15
|
+
// onSubmit={async (v) => sendMessage(v)} />
|
|
16
|
+
//
|
|
17
|
+
// README.md beside this file lists every prop.
|
|
18
|
+
|
|
19
|
+
const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
20
|
+
const OPTIONAL = ["phone", "company", "subject"];
|
|
21
|
+
|
|
22
|
+
const optionOf = (o) => (typeof o === "string" ? { value: o, label: o } : o);
|
|
23
|
+
|
|
24
|
+
function Header({ kicker, title, description, center }) {
|
|
25
|
+
if (!kicker && !title && !description) return null;
|
|
26
|
+
return (
|
|
27
|
+
<div className={cx("grid gap-3", center ? "mx-auto max-w-2xl justify-items-center text-center" : "max-w-2xl")}>
|
|
28
|
+
{kicker ? <Kicker>{kicker}</Kicker> : null}
|
|
29
|
+
{title ? <h2 className="text-balance text-3xl font-semibold tracking-tight sm:text-4xl">{title}</h2> : null}
|
|
30
|
+
{description ? <p className="text-pretty text-base text-muted-foreground sm:text-lg">{description}</p> : null}
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// A detail's value: a link when it has an href (mailto:, tel:, a map).
|
|
36
|
+
// raw: a plain <a>, not Button: it inherits the colour of the panel it
|
|
37
|
+
// sits on (a filled panel is primary), and these hrefs leave the app.
|
|
38
|
+
function Value({ detail, className }) {
|
|
39
|
+
if (!detail.href) return <span className={className}>{detail.value}</span>;
|
|
40
|
+
return (
|
|
41
|
+
<a href={detail.href} className={cx("break-words rounded-sm underline-offset-4 outline-none hover:underline focus-visible:ring-2 focus-visible:ring-ring", className)}>
|
|
42
|
+
{detail.value}
|
|
43
|
+
</a>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function DetailRows({ details, filled }) {
|
|
48
|
+
if (!details?.length) return null;
|
|
49
|
+
return (
|
|
50
|
+
<ul className="grid gap-5">
|
|
51
|
+
{details.map((d, i) => (
|
|
52
|
+
<li key={d.label ?? i} className="flex min-w-0 items-start gap-4">
|
|
53
|
+
<span className={cx("grid size-10 shrink-0 place-items-center rounded-lg", filled ? "bg-primary-foreground/15" : "bg-muted text-foreground")}>
|
|
54
|
+
<Icon name={d.icon ?? "info"} size={18} />
|
|
55
|
+
</span>
|
|
56
|
+
<div className="grid min-w-0 gap-0.5">
|
|
57
|
+
{d.label ? <p className={cx("text-sm", filled ? "opacity-80" : "text-muted-foreground")}>{d.label}</p> : null}
|
|
58
|
+
<Value detail={d} className="font-medium" />
|
|
59
|
+
{d.description ? <p className={cx("text-sm", filled ? "opacity-80" : "text-muted-foreground")}>{d.description}</p> : null}
|
|
60
|
+
</div>
|
|
61
|
+
</li>
|
|
62
|
+
))}
|
|
63
|
+
</ul>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function Offices({ offices, filled }) {
|
|
68
|
+
if (!offices?.length) return null;
|
|
69
|
+
return (
|
|
70
|
+
<div className="grid gap-6 sm:grid-cols-2">
|
|
71
|
+
{offices.map((o, i) => (
|
|
72
|
+
<div key={o.name ?? i} className="grid min-w-0 content-start gap-1">
|
|
73
|
+
<p className="flex items-center gap-2 font-semibold">
|
|
74
|
+
<Icon name={o.icon ?? "building"} size={16} className={filled ? "opacity-80" : "text-muted-foreground"} />
|
|
75
|
+
{o.name}
|
|
76
|
+
</p>
|
|
77
|
+
{(o.lines ?? []).map((line, k) => (
|
|
78
|
+
<p key={k} className={cx("text-sm", filled ? "opacity-80" : "text-muted-foreground")}>
|
|
79
|
+
{line}
|
|
80
|
+
</p>
|
|
81
|
+
))}
|
|
82
|
+
</div>
|
|
83
|
+
))}
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function Panel({ title, body, details, offices, look }) {
|
|
89
|
+
const filled = look === "filled";
|
|
90
|
+
return (
|
|
91
|
+
<aside
|
|
92
|
+
className={cx(
|
|
93
|
+
"grid min-w-0 content-start gap-8 rounded-xl p-6 sm:p-8",
|
|
94
|
+
filled ? "bg-primary text-primary-foreground" : "border border-border bg-muted/40",
|
|
95
|
+
)}
|
|
96
|
+
>
|
|
97
|
+
{title || body ? (
|
|
98
|
+
<div className="grid gap-2">
|
|
99
|
+
{title ? <h3 className="text-xl font-semibold">{title}</h3> : null}
|
|
100
|
+
{body ? <p className={cx("text-pretty", filled ? "opacity-80" : "text-muted-foreground")}>{body}</p> : null}
|
|
101
|
+
</div>
|
|
102
|
+
) : null}
|
|
103
|
+
<DetailRows details={details} filled={filled} />
|
|
104
|
+
<Offices offices={offices} filled={filled} />
|
|
105
|
+
</aside>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function DetailCards({ details, center, columns }) {
|
|
110
|
+
if (!details?.length) return null;
|
|
111
|
+
const cols = columns ?? Math.min(details.length, 3);
|
|
112
|
+
return (
|
|
113
|
+
<ul className={cx("grid gap-4", cols === 1 ? "grid-cols-1" : cols === 2 ? "sm:grid-cols-2" : cols === 4 ? "sm:grid-cols-2 lg:grid-cols-4" : "sm:grid-cols-2 lg:grid-cols-3")}>
|
|
114
|
+
{details.map((d, i) => (
|
|
115
|
+
<li
|
|
116
|
+
key={d.label ?? i}
|
|
117
|
+
className={cx("grid min-w-0 content-start gap-3 rounded-lg border border-border bg-card p-6 text-card-foreground", center && "justify-items-center text-center")}
|
|
118
|
+
>
|
|
119
|
+
<span className={cx("grid size-12 place-items-center bg-primary text-primary-foreground", center ? "rounded-full" : "rounded-lg")}>
|
|
120
|
+
<Icon name={d.icon ?? "info"} size={22} />
|
|
121
|
+
</span>
|
|
122
|
+
{d.label ? <h3 className="font-semibold">{d.label}</h3> : null}
|
|
123
|
+
{d.description ? <p className="text-pretty text-sm text-muted-foreground">{d.description}</p> : null}
|
|
124
|
+
{d.value ? <Value detail={d} className="font-medium text-primary" /> : null}
|
|
125
|
+
</li>
|
|
126
|
+
))}
|
|
127
|
+
</ul>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// The phone, email and hours on one line above a form.
|
|
132
|
+
function DetailLine({ details, center }) {
|
|
133
|
+
if (!details?.length) return null;
|
|
134
|
+
return (
|
|
135
|
+
<ul className={cx("flex flex-wrap gap-x-6 gap-y-2 text-sm", center && "justify-center")}>
|
|
136
|
+
{details.map((d, i) => (
|
|
137
|
+
<li key={d.label ?? i} className="flex min-w-0 items-center gap-2">
|
|
138
|
+
<Icon name={d.icon ?? "info"} size={16} className="shrink-0 text-muted-foreground" />
|
|
139
|
+
{d.label ? <span className="sr-only">{d.label}: </span> : null}
|
|
140
|
+
<Value detail={d} className="font-medium" />
|
|
141
|
+
</li>
|
|
142
|
+
))}
|
|
143
|
+
</ul>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function blank(names, fields, topics) {
|
|
148
|
+
const v = { email: "", message: "" };
|
|
149
|
+
if (names === "one") v.name = "";
|
|
150
|
+
else Object.assign(v, { firstName: "", lastName: "" });
|
|
151
|
+
for (const f of fields) v[f] = "";
|
|
152
|
+
if (topics) v.topic = "";
|
|
153
|
+
return v;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function ContactForm({
|
|
157
|
+
onSubmit,
|
|
158
|
+
names,
|
|
159
|
+
fields,
|
|
160
|
+
topics,
|
|
161
|
+
consent,
|
|
162
|
+
messageRows,
|
|
163
|
+
messageLabel,
|
|
164
|
+
submitLabel,
|
|
165
|
+
sent,
|
|
166
|
+
defaultValues,
|
|
167
|
+
labels,
|
|
168
|
+
}) {
|
|
169
|
+
const uid = useId();
|
|
170
|
+
const id = (k) => `${uid}-${k}`;
|
|
171
|
+
const start = () => ({ ...blank(names, fields, topics), ...defaultValues, ...(consent ? { consent: false } : {}) });
|
|
172
|
+
const [values, setValues] = useState(start);
|
|
173
|
+
const [errors, setErrors] = useState({});
|
|
174
|
+
const [status, setStatus] = useState("idle");
|
|
175
|
+
const [failure, setFailure] = useState(null);
|
|
176
|
+
const L = { firstName: "First name", lastName: "Last name", name: "Name", email: "Email", phone: "Phone", company: "Company", subject: "Subject", ...labels };
|
|
177
|
+
|
|
178
|
+
const set = (k, v) => {
|
|
179
|
+
setValues((prev) => ({ ...prev, [k]: v }));
|
|
180
|
+
if (errors[k]) setErrors((prev) => ({ ...prev, [k]: undefined }));
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
function validate() {
|
|
184
|
+
const e = {};
|
|
185
|
+
if (names === "one" && !values.name?.trim()) e.name = "Tell us your name.";
|
|
186
|
+
if (names !== "one" && !values.firstName?.trim()) e.firstName = "Tell us your first name.";
|
|
187
|
+
if (!values.email?.trim()) e.email = "We need an email to reply to.";
|
|
188
|
+
else if (!EMAIL.test(values.email.trim())) e.email = "That email does not look right.";
|
|
189
|
+
if (topics?.required && !values.topic) e.topic = "Pick one.";
|
|
190
|
+
if (!values.message?.trim()) e.message = "Write a line or two.";
|
|
191
|
+
if (consent && !values.consent) e.consent = "Please agree before sending.";
|
|
192
|
+
return e;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function submit(ev) {
|
|
196
|
+
ev.preventDefault();
|
|
197
|
+
if (status === "sending") return;
|
|
198
|
+
const e = validate();
|
|
199
|
+
setErrors(e);
|
|
200
|
+
const first = Object.keys(e)[0];
|
|
201
|
+
if (first) {
|
|
202
|
+
// The first problem gets the focus, so a keyboard user lands on it.
|
|
203
|
+
const el = document.getElementById(id(first));
|
|
204
|
+
(el?.matches("input, textarea") ? el : el?.querySelector("input, button, textarea"))?.focus();
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
setStatus("sending");
|
|
208
|
+
setFailure(null);
|
|
209
|
+
const out = { ...values };
|
|
210
|
+
for (const k of Object.keys(out)) if (typeof out[k] === "string") out[k] = out[k].trim();
|
|
211
|
+
let res;
|
|
212
|
+
try {
|
|
213
|
+
res = await onSubmit(out);
|
|
214
|
+
} catch (err) {
|
|
215
|
+
res = { ok: false, error: err?.message };
|
|
216
|
+
}
|
|
217
|
+
if (res?.ok) {
|
|
218
|
+
setStatus("sent");
|
|
219
|
+
} else {
|
|
220
|
+
setStatus("idle");
|
|
221
|
+
setFailure(res?.error || "Your message was not sent. Check your connection and try again.");
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (status === "sent")
|
|
226
|
+
return (
|
|
227
|
+
<div className="grid gap-4" aria-live="polite">
|
|
228
|
+
<Notice tone="success" title={sent?.title ?? "Message sent"}>
|
|
229
|
+
{sent?.body ?? "Thanks — we read every message and reply within one working day."}
|
|
230
|
+
</Notice>
|
|
231
|
+
<div>
|
|
232
|
+
<Button
|
|
233
|
+
variant="secondary"
|
|
234
|
+
icon="repeat"
|
|
235
|
+
onClick={() => {
|
|
236
|
+
setValues(start());
|
|
237
|
+
setErrors({});
|
|
238
|
+
setStatus("idle");
|
|
239
|
+
}}
|
|
240
|
+
>
|
|
241
|
+
Send another
|
|
242
|
+
</Button>
|
|
243
|
+
</div>
|
|
244
|
+
</div>
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
const topicOptions = (topics?.options ?? []).map(optionOf);
|
|
248
|
+
const sending = status === "sending";
|
|
249
|
+
return (
|
|
250
|
+
<form noValidate onSubmit={submit} className="grid gap-5" aria-busy={sending || undefined}>
|
|
251
|
+
{topics && topics.style !== "radio" ? (
|
|
252
|
+
<div className="grid gap-2">
|
|
253
|
+
<p id={id("topic-label")} className="text-sm font-medium">
|
|
254
|
+
{topics.label ?? "What is it about?"}
|
|
255
|
+
{topics.required ? <span aria-hidden="true" className="text-destructive"> *</span> : null}
|
|
256
|
+
</p>
|
|
257
|
+
<div id={id("topic")} role="group" aria-labelledby={id("topic-label")} className="flex flex-wrap gap-2">
|
|
258
|
+
{topicOptions.map((o) => (
|
|
259
|
+
<Toggle
|
|
260
|
+
key={o.value}
|
|
261
|
+
size="sm"
|
|
262
|
+
pressed={values.topic === o.value}
|
|
263
|
+
onPressedChange={(on) => set("topic", on ? o.value : "")}
|
|
264
|
+
className="max-w-full"
|
|
265
|
+
>
|
|
266
|
+
{o.label}
|
|
267
|
+
</Toggle>
|
|
268
|
+
))}
|
|
269
|
+
</div>
|
|
270
|
+
{errors.topic ? (
|
|
271
|
+
<p role="alert" className="text-xs text-destructive">
|
|
272
|
+
{errors.topic}
|
|
273
|
+
</p>
|
|
274
|
+
) : null}
|
|
275
|
+
</div>
|
|
276
|
+
) : null}
|
|
277
|
+
|
|
278
|
+
{names === "one" ? (
|
|
279
|
+
<Field id={id("name")} label={L.name} required error={errors.name}>
|
|
280
|
+
<Input id={id("name")} name="name" autoComplete="name" value={values.name} onChange={(e) => set("name", e.target.value)} invalid={!!errors.name} />
|
|
281
|
+
</Field>
|
|
282
|
+
) : (
|
|
283
|
+
<div className="grid gap-5 sm:grid-cols-2">
|
|
284
|
+
<Field id={id("firstName")} label={L.firstName} required error={errors.firstName}>
|
|
285
|
+
<Input
|
|
286
|
+
id={id("firstName")}
|
|
287
|
+
name="firstName"
|
|
288
|
+
autoComplete="given-name"
|
|
289
|
+
value={values.firstName}
|
|
290
|
+
onChange={(e) => set("firstName", e.target.value)}
|
|
291
|
+
invalid={!!errors.firstName}
|
|
292
|
+
/>
|
|
293
|
+
</Field>
|
|
294
|
+
<Field id={id("lastName")} label={L.lastName}>
|
|
295
|
+
<Input id={id("lastName")} name="lastName" autoComplete="family-name" value={values.lastName} onChange={(e) => set("lastName", e.target.value)} />
|
|
296
|
+
</Field>
|
|
297
|
+
</div>
|
|
298
|
+
)}
|
|
299
|
+
|
|
300
|
+
<div className={cx("grid gap-5", fields.includes("phone") && "sm:grid-cols-2")}>
|
|
301
|
+
<Field id={id("email")} label={L.email} required error={errors.email}>
|
|
302
|
+
<Input
|
|
303
|
+
id={id("email")}
|
|
304
|
+
name="email"
|
|
305
|
+
type="email"
|
|
306
|
+
inputMode="email"
|
|
307
|
+
autoComplete="email"
|
|
308
|
+
placeholder="you@company.com"
|
|
309
|
+
value={values.email}
|
|
310
|
+
onChange={(e) => set("email", e.target.value)}
|
|
311
|
+
invalid={!!errors.email}
|
|
312
|
+
/>
|
|
313
|
+
</Field>
|
|
314
|
+
{fields.includes("phone") ? (
|
|
315
|
+
<Field id={id("phone")} label={L.phone} hint="Optional">
|
|
316
|
+
<Input id={id("phone")} name="phone" type="tel" inputMode="tel" autoComplete="tel" value={values.phone} onChange={(e) => set("phone", e.target.value)} />
|
|
317
|
+
</Field>
|
|
318
|
+
) : null}
|
|
319
|
+
</div>
|
|
320
|
+
|
|
321
|
+
{fields.includes("company") ? (
|
|
322
|
+
<Field id={id("company")} label={L.company} hint="Optional">
|
|
323
|
+
<Input id={id("company")} name="company" autoComplete="organization" value={values.company} onChange={(e) => set("company", e.target.value)} />
|
|
324
|
+
</Field>
|
|
325
|
+
) : null}
|
|
326
|
+
|
|
327
|
+
{topics && topics.style === "radio" ? (
|
|
328
|
+
<Field id={id("topic")} label={topics.label ?? "What is it about?"} required={topics.required} error={errors.topic}>
|
|
329
|
+
<RadioGroup
|
|
330
|
+
id={id("topic")}
|
|
331
|
+
name="topic"
|
|
332
|
+
orientation="horizontal"
|
|
333
|
+
options={topicOptions}
|
|
334
|
+
value={values.topic}
|
|
335
|
+
onChange={(v) => set("topic", v)}
|
|
336
|
+
invalid={!!errors.topic}
|
|
337
|
+
/>
|
|
338
|
+
</Field>
|
|
339
|
+
) : null}
|
|
340
|
+
|
|
341
|
+
{fields.includes("subject") ? (
|
|
342
|
+
<Field id={id("subject")} label={L.subject}>
|
|
343
|
+
<Input id={id("subject")} name="subject" value={values.subject} onChange={(e) => set("subject", e.target.value)} />
|
|
344
|
+
</Field>
|
|
345
|
+
) : null}
|
|
346
|
+
|
|
347
|
+
<Field id={id("message")} label={messageLabel ?? "Message"} required error={errors.message}>
|
|
348
|
+
<Textarea
|
|
349
|
+
id={id("message")}
|
|
350
|
+
name="message"
|
|
351
|
+
rows={messageRows}
|
|
352
|
+
placeholder="What can we help with?"
|
|
353
|
+
value={values.message}
|
|
354
|
+
onChange={(e) => set("message", e.target.value)}
|
|
355
|
+
invalid={!!errors.message}
|
|
356
|
+
/>
|
|
357
|
+
</Field>
|
|
358
|
+
|
|
359
|
+
{consent ? (
|
|
360
|
+
<div className="grid gap-1">
|
|
361
|
+
<Checkbox
|
|
362
|
+
id={id("consent")}
|
|
363
|
+
name="consent"
|
|
364
|
+
checked={!!values.consent}
|
|
365
|
+
onChange={(e) => set("consent", e.target.checked)}
|
|
366
|
+
aria-invalid={errors.consent ? true : undefined}
|
|
367
|
+
aria-describedby={errors.consent ? id("consent-error") : undefined}
|
|
368
|
+
label={consent}
|
|
369
|
+
/>
|
|
370
|
+
{errors.consent ? (
|
|
371
|
+
<p id={id("consent-error")} role="alert" className="text-xs text-destructive">
|
|
372
|
+
{errors.consent}
|
|
373
|
+
</p>
|
|
374
|
+
) : null}
|
|
375
|
+
</div>
|
|
376
|
+
) : null}
|
|
377
|
+
|
|
378
|
+
{failure ? (
|
|
379
|
+
<Notice tone="danger" title="Not sent">
|
|
380
|
+
{failure}
|
|
381
|
+
</Notice>
|
|
382
|
+
) : null}
|
|
383
|
+
|
|
384
|
+
<div>
|
|
385
|
+
<Button type="submit" variant="primary" icon="send" loading={sending} className="w-full sm:w-auto">
|
|
386
|
+
{submitLabel ?? "Send message"}
|
|
387
|
+
</Button>
|
|
388
|
+
</div>
|
|
389
|
+
</form>
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export function ContactSection({
|
|
394
|
+
layout = "split",
|
|
395
|
+
kicker,
|
|
396
|
+
title = "Get in touch",
|
|
397
|
+
description,
|
|
398
|
+
align,
|
|
399
|
+
details,
|
|
400
|
+
offices,
|
|
401
|
+
panel = "plain",
|
|
402
|
+
panelTitle,
|
|
403
|
+
panelBody,
|
|
404
|
+
cardsPosition = "above",
|
|
405
|
+
cardColumns,
|
|
406
|
+
image,
|
|
407
|
+
imageAlt = "",
|
|
408
|
+
imagePosition = "side",
|
|
409
|
+
onSubmit,
|
|
410
|
+
nameFields = "split",
|
|
411
|
+
fields = [],
|
|
412
|
+
topics,
|
|
413
|
+
consent,
|
|
414
|
+
messageLabel,
|
|
415
|
+
messageRows = 5,
|
|
416
|
+
submitLabel,
|
|
417
|
+
sent,
|
|
418
|
+
defaultValues,
|
|
419
|
+
labels,
|
|
420
|
+
label,
|
|
421
|
+
className,
|
|
422
|
+
}) {
|
|
423
|
+
const extra = (fields ?? []).filter((f) => OPTIONAL.includes(f));
|
|
424
|
+
const center = (align ?? (layout === "split" ? "start" : "center")) === "center";
|
|
425
|
+
const form = onSubmit ? (
|
|
426
|
+
<ContactForm
|
|
427
|
+
onSubmit={onSubmit}
|
|
428
|
+
names={nameFields === "one" ? "one" : "split"}
|
|
429
|
+
fields={extra}
|
|
430
|
+
topics={topics?.options?.length ? topics : null}
|
|
431
|
+
consent={consent}
|
|
432
|
+
messageRows={messageRows}
|
|
433
|
+
messageLabel={messageLabel}
|
|
434
|
+
submitLabel={submitLabel}
|
|
435
|
+
sent={sent}
|
|
436
|
+
defaultValues={defaultValues}
|
|
437
|
+
labels={labels}
|
|
438
|
+
/>
|
|
439
|
+
) : null;
|
|
440
|
+
const formCard = form ? <div className="min-w-0 rounded-xl border border-border bg-card p-5 text-card-foreground sm:p-8">{form}</div> : null;
|
|
441
|
+
|
|
442
|
+
let body;
|
|
443
|
+
if (layout === "cards") {
|
|
444
|
+
const cards = <DetailCards details={details} center={center && cardsPosition !== "beside"} columns={cardsPosition === "beside" && form ? 1 : cardColumns} />;
|
|
445
|
+
body = !form ? (
|
|
446
|
+
cards
|
|
447
|
+
) : cardsPosition === "beside" ? (
|
|
448
|
+
<div className="grid gap-8 lg:grid-cols-[minmax(0,2fr)_minmax(0,3fr)]">
|
|
449
|
+
{cards}
|
|
450
|
+
{formCard}
|
|
451
|
+
</div>
|
|
452
|
+
) : (
|
|
453
|
+
<div className="grid gap-10">
|
|
454
|
+
{cards}
|
|
455
|
+
<div className="mx-auto w-full max-w-2xl">{formCard}</div>
|
|
456
|
+
</div>
|
|
457
|
+
);
|
|
458
|
+
} else if (layout === "form") {
|
|
459
|
+
if (image && imagePosition === "background" && form)
|
|
460
|
+
body = (
|
|
461
|
+
<div className="relative isolate overflow-hidden rounded-xl">
|
|
462
|
+
<div className="absolute inset-0 -z-10">
|
|
463
|
+
<Image src={image} alt={imageAlt} rounded="none" className="h-full w-full" />
|
|
464
|
+
</div>
|
|
465
|
+
<div className="grid justify-items-center bg-background/70 px-4 py-10 sm:px-8 sm:py-16">
|
|
466
|
+
<div className="w-full max-w-xl">{formCard}</div>
|
|
467
|
+
</div>
|
|
468
|
+
</div>
|
|
469
|
+
);
|
|
470
|
+
else if (image && form)
|
|
471
|
+
body = (
|
|
472
|
+
<div className="grid items-stretch gap-8 md:grid-cols-2">
|
|
473
|
+
<div className="hidden md:block">
|
|
474
|
+
<Image src={image} alt={imageAlt} rounded="lg" className="h-full min-h-96 w-full" />
|
|
475
|
+
</div>
|
|
476
|
+
<div className="grid min-w-0 content-start gap-6">
|
|
477
|
+
<DetailLine details={details} />
|
|
478
|
+
{formCard}
|
|
479
|
+
</div>
|
|
480
|
+
</div>
|
|
481
|
+
);
|
|
482
|
+
else
|
|
483
|
+
body = (
|
|
484
|
+
<div className="mx-auto grid w-full max-w-2xl gap-6">
|
|
485
|
+
<DetailLine details={details} center={center} />
|
|
486
|
+
{formCard}
|
|
487
|
+
</div>
|
|
488
|
+
);
|
|
489
|
+
} else {
|
|
490
|
+
const side = <Panel title={panelTitle} body={panelBody} details={details} offices={offices} look={panel} />;
|
|
491
|
+
body = form ? (
|
|
492
|
+
<div className="grid gap-8 lg:grid-cols-[minmax(0,3fr)_minmax(0,2fr)]">
|
|
493
|
+
{formCard}
|
|
494
|
+
{side}
|
|
495
|
+
</div>
|
|
496
|
+
) : (
|
|
497
|
+
side
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
return (
|
|
502
|
+
<section aria-label={label ?? (typeof title === "string" ? title : "Contact")} className={cx("px-4 py-16 sm:px-6 sm:py-20", className)}>
|
|
503
|
+
<div className="mx-auto grid w-full max-w-6xl gap-10 sm:gap-12">
|
|
504
|
+
<Header kicker={kicker} title={title} description={description} center={center} />
|
|
505
|
+
{body}
|
|
506
|
+
</div>
|
|
507
|
+
</section>
|
|
508
|
+
);
|
|
509
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// The ContactSection in every variant — the gallery's and the smoke
|
|
4
|
+
// test's surface. Not installed into apps: `makersclaw add
|
|
5
|
+
// contact-section` lays index.js and contact-section.jsx only. Pick a
|
|
6
|
+
// variant, and whether the next send succeeds or fails; nothing is sent.
|
|
7
|
+
import { useState } from "react";
|
|
8
|
+
import { Field, Select, ToggleGroup } from "../components/ui";
|
|
9
|
+
import { ContactSection } from "../components/blocks/contact-section";
|
|
10
|
+
|
|
11
|
+
const EMAIL = { icon: "mail", label: "Email", value: "hello@fieldline.io", href: "mailto:hello@fieldline.io" };
|
|
12
|
+
const PHONE = { icon: "phone", label: "Phone", value: "+44 20 7946 0321", href: "tel:+442079460321" };
|
|
13
|
+
const ADDRESS = { icon: "map", label: "Studio", value: "14 Canal Street, Manchester M1 3HE" };
|
|
14
|
+
const HOURS = { icon: "clock", label: "Hours", value: "Mon–Fri, 9:00–18:00 GMT" };
|
|
15
|
+
|
|
16
|
+
const CARDS = [
|
|
17
|
+
{ ...EMAIL, label: "Email us", description: "For anything at all. A person replies within a working day." },
|
|
18
|
+
{ ...PHONE, label: "Call sales", description: "Talk through a plan for your team, no slides." },
|
|
19
|
+
{ ...ADDRESS, label: "Visit", description: "Coffee is on us. Book ahead so someone is in." },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
const QUICK = [
|
|
23
|
+
{ icon: "message-circle", label: "Live chat", description: "Weekdays, usually under five minutes.", value: "Start a chat", href: "/chat" },
|
|
24
|
+
{ icon: "life-buoy", label: "Help centre", description: "Guides for setup, billing and imports.", value: "Browse guides", href: "/help" },
|
|
25
|
+
{ icon: "calendar", label: "Book a call", description: "Thirty minutes with someone from sales.", value: "Pick a time", href: "/book" },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const OFFICES = [
|
|
29
|
+
{ name: "Manchester", lines: ["14 Canal Street", "M1 3HE, United Kingdom", "+44 20 7946 0321"] },
|
|
30
|
+
{ name: "Lisbon", lines: ["Rua da Prata 88", "1100-420 Lisboa, Portugal", "+351 21 555 0192"] },
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const TOPICS = ["Sales", "Support", "Partnerships", "Press"];
|
|
34
|
+
const CONSENT = "I agree to the privacy policy and to being contacted about this message.";
|
|
35
|
+
const HEAD = { kicker: "Contact", title: "Talk to a person", description: "Questions about plans, a migration, or a feature you need — write and we reply within one working day." };
|
|
36
|
+
|
|
37
|
+
const VARIANTS = [
|
|
38
|
+
{ id: "01", label: "01 · Form beside contact info", props: { ...HEAD, layout: "split", details: [EMAIL, PHONE, ADDRESS], consent: CONSENT, panelTitle: "Other ways in", panelBody: "Prefer a call or a visit? Here is where to find us." } },
|
|
39
|
+
{ id: "02", label: "02 · Form with a phone field", props: { ...HEAD, layout: "form", fields: ["phone"], details: [EMAIL, PHONE] } },
|
|
40
|
+
{ id: "03", label: "03 · Form with a filled panel", props: { ...HEAD, layout: "split", panel: "filled", details: [EMAIL, PHONE, ADDRESS], panelTitle: "Contact information", panelBody: "Fill in the form and we reply within one working day." } },
|
|
41
|
+
{ id: "04", label: "04 · Icon cards only", props: { ...HEAD, layout: "cards", align: "start", details: CARDS } },
|
|
42
|
+
{ id: "05", label: "05 · Topic chips above the form", props: { ...HEAD, layout: "form", topics: { label: "What is it about?", options: TOPICS, style: "chips", required: true } } },
|
|
43
|
+
{ id: "06", label: "06 · Round icon cards, centred", props: { ...HEAD, layout: "cards", details: CARDS } },
|
|
44
|
+
{ id: "07", label: "07 · Form with offices", props: { ...HEAD, layout: "split", offices: OFFICES, consent: CONSENT, panelTitle: "Our offices" } },
|
|
45
|
+
{ id: "08", label: "08 · Area of interest radios", props: { ...HEAD, layout: "split", panel: "filled", details: [EMAIL, PHONE], panelTitle: "Contact information", topics: { label: "Area of interest", options: TOPICS, style: "radio" } } },
|
|
46
|
+
{ id: "09", label: "09 · Detailed info panel", props: { ...HEAD, layout: "split", panel: "filled", details: [EMAIL, PHONE, ADDRESS, HOURS], offices: OFFICES.slice(1), panelTitle: "Everything in one place", panelBody: "Email is fastest. For anything urgent on a paid plan, call." } },
|
|
47
|
+
{ id: "10", label: "10 · Info cards above the form", props: { ...HEAD, layout: "cards", details: CARDS } },
|
|
48
|
+
{ id: "11", label: "11 · Phone and email above the form", props: { ...HEAD, layout: "form", details: [PHONE, EMAIL, HOURS] } },
|
|
49
|
+
{ id: "12", label: "12 · Form with a company field", props: { ...HEAD, layout: "form", fields: ["company"], nameFields: "one", consent: CONSENT } },
|
|
50
|
+
{ id: "13", label: "13 · Info cards beside the form", props: { ...HEAD, layout: "cards", cardsPosition: "beside", align: "start", details: [EMAIL, PHONE, HOURS] } },
|
|
51
|
+
{ id: "14", label: "14 · Subject and required marks", props: { ...HEAD, layout: "form", fields: ["subject", "phone"], consent: CONSENT } },
|
|
52
|
+
{ id: "15", label: "15 · Contact options and a quick form", props: { ...HEAD, layout: "cards", details: QUICK, nameFields: "one", fields: ["phone"], messageLabel: "Your question", messageRows: 3, submitLabel: "Send" } },
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
// Cards-only variants have no form: they get no onSubmit.
|
|
56
|
+
const NO_FORM = new Set(["04", "06"]);
|
|
57
|
+
|
|
58
|
+
const OUTCOMES = [
|
|
59
|
+
{ value: "ok", label: "Send succeeds" },
|
|
60
|
+
{ value: "fail", label: "Send fails" },
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
export default function ContactSectionDemo() {
|
|
64
|
+
const [variant, setVariant] = useState("01");
|
|
65
|
+
const [outcome, setOutcome] = useState("ok");
|
|
66
|
+
const [last, setLast] = useState(null);
|
|
67
|
+
const v = VARIANTS.find((x) => x.id === variant) ?? VARIANTS[0];
|
|
68
|
+
|
|
69
|
+
async function send(values) {
|
|
70
|
+
await new Promise((r) => setTimeout(r, 900));
|
|
71
|
+
if (outcome === "fail") return { ok: false, error: "Our mail server did not answer. Your message is still here — try again in a minute." };
|
|
72
|
+
setLast(values);
|
|
73
|
+
return { ok: true };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<div className="grid gap-2">
|
|
78
|
+
<div className="flex flex-wrap items-end gap-3 px-4 pt-4 sm:px-6">
|
|
79
|
+
<Field id="c-variant" label="Variant" className="w-full sm:w-80">
|
|
80
|
+
<Select id="c-variant" value={variant} onChange={(e) => setVariant(e.target.value)} options={VARIANTS.map((x) => ({ value: x.id, label: x.label }))} />
|
|
81
|
+
</Field>
|
|
82
|
+
<ToggleGroup aria-label="Next send" items={OUTCOMES} value={outcome} onChange={setOutcome} />
|
|
83
|
+
</div>
|
|
84
|
+
{last ? (
|
|
85
|
+
<p className="px-4 text-sm text-muted-foreground sm:px-6">
|
|
86
|
+
Last sent: <span className="font-medium text-foreground">{last.email}</span>
|
|
87
|
+
{last.topic ? ` · ${last.topic}` : ""}
|
|
88
|
+
</p>
|
|
89
|
+
) : null}
|
|
90
|
+
<ContactSection key={variant} {...v.props} onSubmit={NO_FORM.has(variant) ? undefined : send} />
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
}
|