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,271 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useId } from "react";
|
|
4
|
+
import { Button, Checkbox, Icon, IconButton, InputGroup, Menu, Popover, Switch, cx } from "../../ui";
|
|
5
|
+
import { DEFAULT_VIEW, NONE, activeFilterCount, createTaskContext, groupOptions, optionsOf, sortOptions, valuesOf } from "./model";
|
|
6
|
+
|
|
7
|
+
// ViewToolbar — the one row above every task view: search, filter,
|
|
8
|
+
// group by, sort, show fields, and your own button at the end. It edits a
|
|
9
|
+
// view object ({ search, filters, groupBy, sort, fields, hideDone }) and
|
|
10
|
+
// hands the next one to `onViewChange`; the view applies it with
|
|
11
|
+
// applyView(). Active filters show as chips under the row, each with its
|
|
12
|
+
// own ×, and "Clear" takes them all off.
|
|
13
|
+
//
|
|
14
|
+
// On a phone the search takes the first line and the controls become
|
|
15
|
+
// icons on the second; nothing scrolls sideways.
|
|
16
|
+
|
|
17
|
+
const ctxOf = (ctx) => (ctx && ctx.statusById ? ctx : createTaskContext(ctx ?? {}));
|
|
18
|
+
|
|
19
|
+
const FILTER_KINDS = new Set(["status", "people", "priority", "project", "tags", "date", "select", "checkbox"]);
|
|
20
|
+
const SHOWABLE = ["status", "assignees", "due", "start", "priority", "project", "tags", "estimate", "progress"];
|
|
21
|
+
|
|
22
|
+
export function ViewToolbar({
|
|
23
|
+
view: viewProp,
|
|
24
|
+
onViewChange,
|
|
25
|
+
ctx,
|
|
26
|
+
tasks = [],
|
|
27
|
+
controls = ["search", "filter", "group", "sort", "fields"],
|
|
28
|
+
filterFields,
|
|
29
|
+
groupFields,
|
|
30
|
+
showableFields,
|
|
31
|
+
searchPlaceholder = "Search tasks",
|
|
32
|
+
count,
|
|
33
|
+
extra,
|
|
34
|
+
className,
|
|
35
|
+
}) {
|
|
36
|
+
const c = ctxOf(ctx);
|
|
37
|
+
const uid = useId();
|
|
38
|
+
const view = { ...DEFAULT_VIEW, ...viewProp };
|
|
39
|
+
const set = (patch) => onViewChange?.({ ...view, ...patch });
|
|
40
|
+
const has = (k) => controls.includes(k);
|
|
41
|
+
|
|
42
|
+
const filterable = c.fields.filter(
|
|
43
|
+
(f) =>
|
|
44
|
+
FILTER_KINDS.has(f.kind) &&
|
|
45
|
+
(filterFields ? filterFields.includes(f.key) : f.key !== "start") &&
|
|
46
|
+
optionsOf(f.key, c, tasks).some((o) => !o.none),
|
|
47
|
+
);
|
|
48
|
+
const groups = groupOptions(c).filter((g) => !groupFields || g.key === "none" || groupFields.includes(g.key));
|
|
49
|
+
const sorts = sortOptions(c);
|
|
50
|
+
const showable = c.fields.filter((f) => (showableFields ?? [...SHOWABLE, ...c.fields.filter((x) => x.custom).map((x) => x.key)]).includes(f.key));
|
|
51
|
+
const active = activeFilterCount(view);
|
|
52
|
+
const groupLabel = groups.find((g) => g.key === (view.groupBy ?? "none"))?.label ?? "None";
|
|
53
|
+
const sort = view.sort?.[0];
|
|
54
|
+
const sortLabel = sort ? sorts.find((s) => s.key === sort.key)?.label ?? sort.key : "Manual";
|
|
55
|
+
|
|
56
|
+
const toggleFilter = (key, value, on) => {
|
|
57
|
+
const now = new Set(view.filters?.[key] ?? []);
|
|
58
|
+
if (on) now.add(value);
|
|
59
|
+
else now.delete(value);
|
|
60
|
+
const filters = { ...view.filters, [key]: [...now] };
|
|
61
|
+
if (!filters[key].length) delete filters[key];
|
|
62
|
+
set({ filters });
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// How many tasks each filter choice holds, among all tasks.
|
|
66
|
+
const counts = (key) => {
|
|
67
|
+
const m = new Map();
|
|
68
|
+
for (const t of tasks) for (const v of valuesOf(t, key, c)) m.set(v, (m.get(v) ?? 0) + 1);
|
|
69
|
+
return m;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const chips = [];
|
|
73
|
+
for (const [key, values] of Object.entries(view.filters ?? {})) {
|
|
74
|
+
if (!values?.length) continue;
|
|
75
|
+
const field = c.fields.find((f) => f.key === key);
|
|
76
|
+
const opts = optionsOf(key, c, tasks);
|
|
77
|
+
const words = values.map((v) => opts.find((o) => o.id === v)?.label ?? (v === NONE ? "None" : v));
|
|
78
|
+
chips.push({ key, label: `${field?.label ?? key}: ${words.join(", ")}` });
|
|
79
|
+
}
|
|
80
|
+
if (view.hideDone) chips.push({ key: "__done", label: "Done hidden" });
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div className={cx("grid min-w-0 grid-cols-1 gap-2", className)}>
|
|
84
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
85
|
+
{has("search") ? (
|
|
86
|
+
<div className="min-w-0 basis-full sm:max-w-72 sm:flex-1 sm:basis-auto">
|
|
87
|
+
<label htmlFor={`${uid}-q`} className="sr-only">
|
|
88
|
+
{searchPlaceholder}
|
|
89
|
+
</label>
|
|
90
|
+
<InputGroup
|
|
91
|
+
id={`${uid}-q`}
|
|
92
|
+
icon="search"
|
|
93
|
+
type="search"
|
|
94
|
+
value={view.search ?? ""}
|
|
95
|
+
placeholder={searchPlaceholder}
|
|
96
|
+
onChange={(e) => set({ search: e.target.value })}
|
|
97
|
+
onKeyDown={(e) => {
|
|
98
|
+
if (e.key === "Escape" && view.search) {
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
set({ search: "" });
|
|
101
|
+
}
|
|
102
|
+
}}
|
|
103
|
+
action={view.search ? { label: "Clear search", icon: "x", onClick: () => set({ search: "" }) } : undefined}
|
|
104
|
+
/>
|
|
105
|
+
</div>
|
|
106
|
+
) : null}
|
|
107
|
+
<div className="flex min-w-0 flex-1 items-center gap-1">
|
|
108
|
+
{has("filter") ? (
|
|
109
|
+
<Popover
|
|
110
|
+
label="Filter tasks"
|
|
111
|
+
width="md"
|
|
112
|
+
align="start"
|
|
113
|
+
variant={active ? "secondary" : "quiet"}
|
|
114
|
+
size="sm"
|
|
115
|
+
className="max-h-[min(70vh,32rem)] overflow-y-auto p-0"
|
|
116
|
+
trigger={
|
|
117
|
+
<span className="inline-flex items-center gap-1.5">
|
|
118
|
+
<Icon name="filter" size={16} />
|
|
119
|
+
<span className="sr-only sm:not-sr-only">Filter</span>
|
|
120
|
+
{active ? (
|
|
121
|
+
<span data-nums className="rounded-full bg-primary px-1.5 text-2xs font-semibold text-primary-foreground">
|
|
122
|
+
<span className="sr-only">, </span>
|
|
123
|
+
{active}
|
|
124
|
+
<span className="sr-only"> on</span>
|
|
125
|
+
</span>
|
|
126
|
+
) : null}
|
|
127
|
+
</span>
|
|
128
|
+
}
|
|
129
|
+
>
|
|
130
|
+
<div className="grid divide-y divide-border">
|
|
131
|
+
{filterable.map((f) => {
|
|
132
|
+
const opts = optionsOf(f.key, c, tasks).filter((o) => o.id !== "past");
|
|
133
|
+
const n = counts(f.key);
|
|
134
|
+
const chosen = new Set(view.filters?.[f.key] ?? []);
|
|
135
|
+
return (
|
|
136
|
+
<fieldset key={f.key} className="grid gap-0.5 px-3 py-2">
|
|
137
|
+
<legend className="float-left mb-1 w-full pt-1 text-xs font-medium text-muted-foreground">{f.label}</legend>
|
|
138
|
+
{opts.map((o) => (
|
|
139
|
+
<div key={o.id} className="flex items-center justify-between gap-3">
|
|
140
|
+
<Checkbox
|
|
141
|
+
id={`${uid}-${f.key}-${o.id}`}
|
|
142
|
+
label={o.label}
|
|
143
|
+
checked={chosen.has(o.id)}
|
|
144
|
+
onChange={(e) => toggleFilter(f.key, o.id, e.target.checked)}
|
|
145
|
+
className="min-w-0 flex-1"
|
|
146
|
+
/>
|
|
147
|
+
<span data-nums className="text-xs text-muted-foreground">
|
|
148
|
+
{n.get(o.id) ?? 0}
|
|
149
|
+
</span>
|
|
150
|
+
</div>
|
|
151
|
+
))}
|
|
152
|
+
</fieldset>
|
|
153
|
+
);
|
|
154
|
+
})}
|
|
155
|
+
<div className="px-3 py-1">
|
|
156
|
+
<Switch id={`${uid}-done`} label="Hide done tasks" checked={Boolean(view.hideDone)} onChange={(e) => set({ hideDone: e.target.checked })} />
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
</Popover>
|
|
160
|
+
) : null}
|
|
161
|
+
{has("group") ? (
|
|
162
|
+
<Menu
|
|
163
|
+
label={`Group by ${groupLabel}`}
|
|
164
|
+
align="start"
|
|
165
|
+
trigger={
|
|
166
|
+
<span className="inline-flex items-center gap-1.5">
|
|
167
|
+
<Icon name="layers" size={16} />
|
|
168
|
+
<span className="hidden sm:inline">
|
|
169
|
+
Group<span className="text-muted-foreground">: {groupLabel}</span>
|
|
170
|
+
</span>
|
|
171
|
+
</span>
|
|
172
|
+
}
|
|
173
|
+
items={[
|
|
174
|
+
{ type: "label", label: "Group by" },
|
|
175
|
+
{ type: "radio", value: view.groupBy ?? "none", onValueChange: (v) => set({ groupBy: v }), options: groups.map((g) => ({ value: g.key, label: g.label })) },
|
|
176
|
+
]}
|
|
177
|
+
/>
|
|
178
|
+
) : null}
|
|
179
|
+
{has("sort") ? (
|
|
180
|
+
<Menu
|
|
181
|
+
label={`Sort by ${sortLabel}`}
|
|
182
|
+
align="start"
|
|
183
|
+
trigger={
|
|
184
|
+
<span className="inline-flex items-center gap-1.5">
|
|
185
|
+
<Icon name="chevrons-up-down" size={16} />
|
|
186
|
+
<span className="hidden sm:inline">
|
|
187
|
+
Sort<span className="text-muted-foreground">: {sortLabel}</span>
|
|
188
|
+
</span>
|
|
189
|
+
</span>
|
|
190
|
+
}
|
|
191
|
+
items={[
|
|
192
|
+
{ type: "label", label: "Sort by" },
|
|
193
|
+
{
|
|
194
|
+
type: "radio",
|
|
195
|
+
value: sort?.key ?? "manual",
|
|
196
|
+
onValueChange: (v) => set({ sort: v === "manual" ? [] : [{ key: v, dir: sort?.dir ?? "asc" }] }),
|
|
197
|
+
options: sorts.map((s) => ({ value: s.key, label: s.label })),
|
|
198
|
+
},
|
|
199
|
+
sort && { type: "separator" },
|
|
200
|
+
sort && {
|
|
201
|
+
type: "radio",
|
|
202
|
+
value: sort.dir,
|
|
203
|
+
onValueChange: (dir) => set({ sort: [{ key: sort.key, dir }] }),
|
|
204
|
+
options: [
|
|
205
|
+
{ value: "asc", label: "Ascending" },
|
|
206
|
+
{ value: "desc", label: "Descending" },
|
|
207
|
+
],
|
|
208
|
+
},
|
|
209
|
+
]}
|
|
210
|
+
/>
|
|
211
|
+
) : null}
|
|
212
|
+
{has("fields") ? (
|
|
213
|
+
<Menu
|
|
214
|
+
label="Show fields"
|
|
215
|
+
align="start"
|
|
216
|
+
trigger={
|
|
217
|
+
<span className="inline-flex items-center gap-1.5">
|
|
218
|
+
<Icon name="eye" size={16} />
|
|
219
|
+
<span className="hidden sm:inline">Fields</span>
|
|
220
|
+
</span>
|
|
221
|
+
}
|
|
222
|
+
items={[
|
|
223
|
+
{ type: "label", label: "Show on each task" },
|
|
224
|
+
...showable.map((f) => ({
|
|
225
|
+
type: "checkbox",
|
|
226
|
+
label: f.label,
|
|
227
|
+
checked: (view.fields ?? []).includes(f.key),
|
|
228
|
+
onCheckedChange: (on) => set({ fields: on ? [...(view.fields ?? []), f.key] : (view.fields ?? []).filter((k) => k !== f.key) }),
|
|
229
|
+
})),
|
|
230
|
+
]}
|
|
231
|
+
/>
|
|
232
|
+
) : null}
|
|
233
|
+
{typeof count === "number" ? (
|
|
234
|
+
<span data-nums className="ms-1 hidden text-xs text-muted-foreground md:inline">
|
|
235
|
+
{count} {count === 1 ? "task" : "tasks"}
|
|
236
|
+
</span>
|
|
237
|
+
) : null}
|
|
238
|
+
{extra ? <div className="ms-auto flex shrink-0 items-center gap-2">{extra}</div> : null}
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
{chips.length ? (
|
|
242
|
+
<ul className="flex flex-wrap items-center gap-1.5" aria-label="Filters on">
|
|
243
|
+
{chips.map((chip) => (
|
|
244
|
+
<li key={chip.key} className="inline-flex max-w-full items-center rounded-full border border-border bg-card ps-3 text-xs text-foreground">
|
|
245
|
+
<span className="truncate">{chip.label}</span>
|
|
246
|
+
<IconButton
|
|
247
|
+
icon="x"
|
|
248
|
+
size="sm"
|
|
249
|
+
label={`Remove filter ${chip.label}`}
|
|
250
|
+
className="-my-1 rounded-full"
|
|
251
|
+
onClick={() => {
|
|
252
|
+
if (chip.key === "__done") set({ hideDone: false });
|
|
253
|
+
else {
|
|
254
|
+
const filters = { ...view.filters };
|
|
255
|
+
delete filters[chip.key];
|
|
256
|
+
set({ filters });
|
|
257
|
+
}
|
|
258
|
+
}}
|
|
259
|
+
/>
|
|
260
|
+
</li>
|
|
261
|
+
))}
|
|
262
|
+
<li>
|
|
263
|
+
<Button variant="link" size="sm" tone="muted" onClick={() => set({ filters: {}, hideDone: false })}>
|
|
264
|
+
Clear filters
|
|
265
|
+
</Button>
|
|
266
|
+
</li>
|
|
267
|
+
</ul>
|
|
268
|
+
) : null}
|
|
269
|
+
</div>
|
|
270
|
+
);
|
|
271
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Testimonials
|
|
2
|
+
|
|
3
|
+
A marketing section of customer quotes. Each quote carries who said it
|
|
4
|
+
(name, role, company, a face or a logo), an optional star rating drawn
|
|
5
|
+
with the kit's `Rating`, an optional verified mark and "View on X"
|
|
6
|
+
source, and an optional link to the full story. Headline numbers
|
|
7
|
+
(`stats`) sit above the cards, or beside a single quote. Five layouts
|
|
8
|
+
over the same rows: a **grid** of cards, a **single** large quote, a
|
|
9
|
+
**switcher** (press a face to swap the quote), and a **carousel** (swipe,
|
|
10
|
+
arrow keys, buttons, dots), optionally in a panel or over a picture. It
|
|
11
|
+
is a full-width section: it pads itself and centres its content.
|
|
12
|
+
|
|
13
|
+
```jsx
|
|
14
|
+
import { Testimonials } from "../components/blocks/testimonials"; // a Makersclaw app ("./blocks/testimonials" from components/)
|
|
15
|
+
import { Testimonials } from "@/components/makersclaw/blocks/testimonials"; // a shadcn project
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
It is a client component: render it from a `"use client"` component.
|
|
19
|
+
|
|
20
|
+
## The data
|
|
21
|
+
|
|
22
|
+
`items` is the quotes, in order:
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
{
|
|
26
|
+
quote: "We closed the books four days faster…", // required; a row without one is skipped
|
|
27
|
+
name: "Maya Okafor", // required
|
|
28
|
+
id?: "maya", // a stable key
|
|
29
|
+
role?: "Head of Operations", company?: "Greenhaus", // shown as "role, company"
|
|
30
|
+
avatar?: "/faces/maya.jpg", // initials while it loads, and when it fails
|
|
31
|
+
logo?: <GreenhausLogo />, // a node: the company's mark, above the quote
|
|
32
|
+
rating?: 4.5, // 0–5, halves drawn; no rating, no stars
|
|
33
|
+
date?: "12 Aug 2026", // already formatted
|
|
34
|
+
verified?: true, // a check after the name
|
|
35
|
+
source?: { network: "x", href: "https://x.com/…", label? }, // "View on X" + the brand glyph
|
|
36
|
+
href?: "/customers/greenhaus", hrefLabel?: "Read the story", // a link under the quote
|
|
37
|
+
title?: "From a week of month-end to an afternoon", // single: the heading
|
|
38
|
+
image?: "/stories/greenhaus.jpg", imageAlt?: "", // single and switcher: a photo beside the quote
|
|
39
|
+
highlight?: true, // grid: a primary ring round this card
|
|
40
|
+
wide?: true, // grid: this card spans the row
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`source.network` is one of `x`, `linkedin`, `instagram`, `youtube`,
|
|
45
|
+
`facebook`, `github`, `google`; anything else shows `label` and a link
|
|
46
|
+
glyph.
|
|
47
|
+
|
|
48
|
+
## Props
|
|
49
|
+
|
|
50
|
+
- `items` — the quotes, as above. Required.
|
|
51
|
+
- `layout` — `grid` (default) · `single` (the first quote, or the one at
|
|
52
|
+
`defaultIndex`) · `switcher` · `carousel`.
|
|
53
|
+
- `kicker`, `title`, `description` — the header. In `single` and
|
|
54
|
+
`switcher` the title sits beside the quote (an item's own `title` wins
|
|
55
|
+
in `single`).
|
|
56
|
+
- `align` — the header: `center` (default for grid and carousel) ·
|
|
57
|
+
`start` (default for single and switcher).
|
|
58
|
+
- `stats` — `[{ label, value, unit?, caption? }]`, values already
|
|
59
|
+
formatted ("4,200+", "4.8" with unit "/ 5"). A strip of kit `Stat`s
|
|
60
|
+
under the header; in `single` they take the picture's place, beside the
|
|
61
|
+
quote.
|
|
62
|
+
- `columns` — the grid from `lg` up: `1` · `2` · `3` (default) · `4`. One
|
|
63
|
+
column on a phone, two from `sm`.
|
|
64
|
+
- `look` — each card: `card` (default: border and card fill) · `raised`
|
|
65
|
+
(plus a shadow) · `plain` (no box; quiet text). In `single` and
|
|
66
|
+
`carousel`, `plain` drops the panel round it.
|
|
67
|
+
- `cardAlign` — `start` (default) · `center`.
|
|
68
|
+
- `byline` — `bottom` (default: stars, quote, then the person) · `top`
|
|
69
|
+
(the person first, stars last).
|
|
70
|
+
- `quoteMark` — `true` draws a quote glyph above each quote. Default
|
|
71
|
+
`false`.
|
|
72
|
+
- `focusOnHover` — `true`: the card under the pointer stays lit and the
|
|
73
|
+
rest dim. Decoration only; nothing is selected. Default `false`.
|
|
74
|
+
- `action` — `{ label, onClick?, href?, icon? }`: "Write a review". A
|
|
75
|
+
dashed tile after the cards in `grid`, a button in `single` and
|
|
76
|
+
`carousel`, and the way forward in the empty state.
|
|
77
|
+
- `background`, `backgroundAlt` — `carousel` only: a picture behind the
|
|
78
|
+
slides, under a veil of the background colour so the text reads in
|
|
79
|
+
every theme.
|
|
80
|
+
- `defaultIndex` — the quote `single` and `switcher` open on. Default `0`.
|
|
81
|
+
- `onIndexChange(index)` — the switcher's pick, or the carousel's
|
|
82
|
+
settled slide.
|
|
83
|
+
- `loading` — `true` draws three skeleton cards (the region is
|
|
84
|
+
`aria-busy`).
|
|
85
|
+
- `empty` — `{ title?, body? }` for the empty state (no `items`). Default
|
|
86
|
+
"No reviews yet".
|
|
87
|
+
- `label` — what a screen reader calls the section. Default the title.
|
|
88
|
+
- `className` — the section's spacing and width. Never colour.
|
|
89
|
+
|
|
90
|
+
## Example
|
|
91
|
+
|
|
92
|
+
```jsx
|
|
93
|
+
// components/Proof.jsx
|
|
94
|
+
"use client";
|
|
95
|
+
import { Testimonials } from "./blocks/testimonials";
|
|
96
|
+
|
|
97
|
+
const QUOTES = [
|
|
98
|
+
{ id: "maya", name: "Maya Okafor", role: "Head of Operations", company: "Greenhaus", rating: 5,
|
|
99
|
+
quote: "We closed the books four days faster in the first month." },
|
|
100
|
+
{ id: "tomas", name: "Tomás Berg", role: "Founder", company: "Northwind Freight", rating: 4.5,
|
|
101
|
+
quote: "Every quote we send now carries its own margin." },
|
|
102
|
+
{ id: "priya", name: "Priya Raman", role: "Customer Lead", company: "Loop Studio", rating: 5,
|
|
103
|
+
quote: "Support replies went from a day to under an hour." },
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
export default function Proof() {
|
|
107
|
+
return (
|
|
108
|
+
<Testimonials
|
|
109
|
+
kicker="Customers"
|
|
110
|
+
title="Loved by small teams"
|
|
111
|
+
description="Operators, founders and support leads on what changed."
|
|
112
|
+
items={QUOTES}
|
|
113
|
+
stats={[
|
|
114
|
+
{ label: "Teams onboarded", value: "4,200+" },
|
|
115
|
+
{ label: "Average rating", value: "4.8", unit: "/ 5" },
|
|
116
|
+
{ label: "Hours saved a month", value: "31" },
|
|
117
|
+
]}
|
|
118
|
+
/>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## What it will not do
|
|
124
|
+
|
|
125
|
+
- Fetch reviews or take one in: `action` hands off, and the form is
|
|
126
|
+
yours (a `Sheet` with a `Rating` input, saved through your own action).
|
|
127
|
+
- Colour a card by brand: a `highlight` is the theme's primary ring.
|
|
128
|
+
- Autoplay: the carousel moves when the reader moves it.
|
|
129
|
+
- Draw a company's logo from a URL: pass the logo as a node.
|
|
130
|
+
|
|
131
|
+
A section it cannot be is your own component in `components/`, built
|
|
132
|
+
from the kit — not an edit to this block. Its files are fixed: `npm run
|
|
133
|
+
check` refuses a change, and `makersclaw add testimonials` restores them.
|
|
134
|
+
|
|
135
|
+
## Credits
|
|
136
|
+
|
|
137
|
+
Layouts ported from Creative Tim UI's testimonials blocks
|
|
138
|
+
(https://github.com/creativetimofficial/ui, MIT), rewritten on the
|
|
139
|
+
Makersclaw kit.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "testimonials",
|
|
3
|
+
"title": "Testimonials",
|
|
4
|
+
"description": "A marketing section of customer quotes: name, role, company, face or logo, the quote, an optional star rating, a verified mark and a \"view on X\" source, and optional headline numbers (stats). Layouts: a grid of cards (plain, card or raised; hover can light one and dim the rest; a \"write a review\" tile), one large quote, a switcher of faces, and a carousel, optionally over a picture.",
|
|
5
|
+
"useWhen": "Social proof on a public page: a landing page, a pricing page, a product page, a case-study teaser. Not for reviews a signed-in user writes and manages (a record list or form), or an app's own activity feed.",
|
|
6
|
+
"tags": ["testimonials", "reviews", "quotes", "social proof", "customers", "rating", "stars", "stats", "carousel", "marketing", "landing page", "case study"],
|
|
7
|
+
"exports": ["Testimonials"],
|
|
8
|
+
"files": ["index.js", "testimonials.jsx"],
|
|
9
|
+
"requires": [],
|
|
10
|
+
"frame": "bleed"
|
|
11
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// Testimonials in every variant — the gallery's and the smoke test's
|
|
4
|
+
// surface. Not installed into apps: `makersclaw add testimonials` lays
|
|
5
|
+
// index.js and testimonials.jsx only. Pick a variant and a state; the
|
|
6
|
+
// "write a review" tile only counts its presses here.
|
|
7
|
+
import { useState } from "react";
|
|
8
|
+
import { Field, Icon, Select, ToggleGroup } from "../components/ui";
|
|
9
|
+
import { Testimonials } from "../components/blocks/testimonials";
|
|
10
|
+
|
|
11
|
+
function Wordmark({ icon, name }) {
|
|
12
|
+
return (
|
|
13
|
+
<span className="inline-flex items-center gap-2 text-lg font-semibold tracking-tight text-muted-foreground">
|
|
14
|
+
<Icon name={icon} size={22} />
|
|
15
|
+
{name}
|
|
16
|
+
</span>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const PEOPLE = [
|
|
21
|
+
{
|
|
22
|
+
id: "maya",
|
|
23
|
+
name: "Maya Okafor",
|
|
24
|
+
role: "Head of Operations",
|
|
25
|
+
company: "Greenhaus",
|
|
26
|
+
logo: <Wordmark icon="leaf" name="Greenhaus" />,
|
|
27
|
+
quote: "We closed the books four days faster in the first month. The team stopped chasing receipts and started reading the numbers.",
|
|
28
|
+
rating: 5,
|
|
29
|
+
date: "12 Aug 2026",
|
|
30
|
+
title: "From a week of month-end to an afternoon",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "tomas",
|
|
34
|
+
name: "Tomás Berg",
|
|
35
|
+
role: "Founder",
|
|
36
|
+
company: "Northwind Freight",
|
|
37
|
+
logo: <Wordmark icon="truck" name="Northwind" />,
|
|
38
|
+
quote: "Every quote we send now carries its own margin. I can see which lanes pay before we say yes, not three weeks after.",
|
|
39
|
+
rating: 4.5,
|
|
40
|
+
date: "3 Aug 2026",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: "priya",
|
|
44
|
+
name: "Priya Raman",
|
|
45
|
+
role: "Customer Lead",
|
|
46
|
+
company: "Loop Studio",
|
|
47
|
+
logo: <Wordmark icon="layers" name="Loop Studio" />,
|
|
48
|
+
quote: "Support replies went from a day to under an hour. Customers noticed before we announced anything.",
|
|
49
|
+
rating: 5,
|
|
50
|
+
date: "28 Jul 2026",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: "daniel",
|
|
54
|
+
name: "Daniel Cho",
|
|
55
|
+
role: "CTO",
|
|
56
|
+
company: "Brightpath",
|
|
57
|
+
logo: <Wordmark icon="zap" name="Brightpath" />,
|
|
58
|
+
quote: "Setup took an afternoon and nothing has broken since. That is the whole review.",
|
|
59
|
+
rating: 4,
|
|
60
|
+
date: "19 Jul 2026",
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
const HANDLES = { maya: "@mayaops", tomas: "@tomasberg", priya: "@priyaraman", daniel: "@dcho" };
|
|
65
|
+
|
|
66
|
+
const withSource = PEOPLE.slice(0, 3).map((p) => ({
|
|
67
|
+
...p,
|
|
68
|
+
role: HANDLES[p.id],
|
|
69
|
+
company: undefined,
|
|
70
|
+
verified: true,
|
|
71
|
+
source: { network: "x", href: "https://x.com" },
|
|
72
|
+
}));
|
|
73
|
+
const noRating = PEOPLE.map(({ rating, ...p }) => p);
|
|
74
|
+
const noLogo = PEOPLE.map(({ logo, ...p }) => p);
|
|
75
|
+
const STATS = [
|
|
76
|
+
{ label: "Teams onboarded", value: "4,200+" },
|
|
77
|
+
{ label: "Average rating", value: "4.8", unit: "/ 5" },
|
|
78
|
+
{ label: "Hours saved a month", value: "31" },
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
const COMMON = { kicker: "Customers", title: "Loved by small teams", description: "Operators, founders and support leads on what changed after the switch." };
|
|
82
|
+
|
|
83
|
+
const VARIANTS = [
|
|
84
|
+
{ id: "01", label: "01 · Grid, avatars", props: { ...COMMON, items: noLogo.map(({ rating, ...p }) => p).slice(0, 3) } },
|
|
85
|
+
{ id: "02", label: "02 · Grid, verified and on X", props: { ...COMMON, align: "start", items: withSource.map(({ logo, rating, ...p }) => p) } },
|
|
86
|
+
{ id: "03", label: "03 · Grid, numbers and stars", props: { ...COMMON, items: noLogo.slice(0, 3), stats: STATS, quoteMark: true } },
|
|
87
|
+
{ id: "04", label: "04 · Three columns, stars", props: { ...COMMON, kicker: undefined, items: noLogo.slice(0, 3) } },
|
|
88
|
+
{ id: "05", label: "05 · Stars, byline first", props: { ...COMMON, items: noLogo.slice(0, 3), byline: "top" } },
|
|
89
|
+
{ id: "06", label: "06 · One quote, logo", props: { kicker: "Customer story", items: [{ ...PEOPLE[1], title: "Every lane priced before we say yes", rating: undefined }], look: "plain" } },
|
|
90
|
+
{ id: "07", label: "07 · Switcher", props: { layout: "switcher", title: "What operators say", items: noLogo } },
|
|
91
|
+
{ id: "08", label: "08 · Plain, stars", props: { ...COMMON, items: noLogo.slice(0, 3), look: "plain" } },
|
|
92
|
+
{ id: "09", label: "09 · Customer story", props: { layout: "single", kicker: "Customer story", items: [PEOPLE[0]] } },
|
|
93
|
+
{ id: "10", label: "10 · Logos, centred", props: { ...COMMON, items: noRating.slice(0, 3).map((p) => ({ ...p, href: "/customers" })), look: "plain", cardAlign: "center" } },
|
|
94
|
+
{ id: "11", label: "11 · Hover lights one", props: { ...COMMON, items: noLogo.slice(0, 3).map((p, i) => ({ ...p, highlight: i === 1 })), byline: "top", focusOnHover: true } },
|
|
95
|
+
{ id: "12", label: "12 · Logos, two columns", props: { ...COMMON, columns: 2, items: noRating.slice(0, 3).map((p, i) => ({ ...p, wide: i === 2 })) } },
|
|
96
|
+
{ id: "13", label: "13 · One card", props: { items: [{ ...noLogo[2] }] } },
|
|
97
|
+
{ id: "14", label: "14 · Raised cards", props: { ...COMMON, items: noLogo.slice(0, 3).map(({ rating, ...p }) => p), look: "raised" } },
|
|
98
|
+
{ id: "15", label: "15 · Write a review", props: { ...COMMON, columns: 4, items: noLogo.slice(0, 3), cardAlign: "center", byline: "top", action: { label: "Write a review" } } },
|
|
99
|
+
{ id: "16", label: "16 · Carousel", props: { ...COMMON, layout: "carousel", look: "plain", items: noRating } },
|
|
100
|
+
// 17 sits over a photo in an app (`background`); the gallery has no photos, so it shows the panel.
|
|
101
|
+
{ id: "17", label: "17 · Carousel in a panel", props: { layout: "carousel", items: noLogo } },
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
const STATES = [
|
|
105
|
+
{ value: "filled", label: "Filled" },
|
|
106
|
+
{ value: "loading", label: "Loading" },
|
|
107
|
+
{ value: "empty", label: "Empty" },
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
export default function TestimonialsDemo() {
|
|
111
|
+
const [variant, setVariant] = useState("03");
|
|
112
|
+
const [state, setState] = useState("filled");
|
|
113
|
+
const [asks, setAsks] = useState(0);
|
|
114
|
+
const v = VARIANTS.find((x) => x.id === variant) ?? VARIANTS[0];
|
|
115
|
+
const props = { ...v.props };
|
|
116
|
+
// 06 and 13 are one quote: the "single" layout.
|
|
117
|
+
if (v.id === "06" || v.id === "13") props.layout = "single";
|
|
118
|
+
if (v.id === "13") props.look = "card";
|
|
119
|
+
if (state === "empty") props.items = [];
|
|
120
|
+
// An action on every variant's empty state, so there is a way forward.
|
|
121
|
+
const onReview = () => setAsks((n) => n + 1);
|
|
122
|
+
if (props.action) props.action = { ...props.action, onClick: onReview };
|
|
123
|
+
else if (state === "empty") props.action = { label: "Ask a customer", icon: "send", onClick: onReview };
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<div className="grid gap-2">
|
|
127
|
+
<div className="flex flex-wrap items-end gap-3 px-4 pt-4 sm:px-6">
|
|
128
|
+
<Field id="t-variant" label="Variant" className="w-full sm:w-72">
|
|
129
|
+
<Select id="t-variant" value={variant} onChange={(e) => setVariant(e.target.value)} options={VARIANTS.map((x) => ({ value: x.id, label: x.label }))} />
|
|
130
|
+
</Field>
|
|
131
|
+
<ToggleGroup aria-label="State" items={STATES} value={state} onChange={setState} />
|
|
132
|
+
{asks ? <p className="pb-3 text-sm text-muted-foreground">Review asked for {asks}×</p> : null}
|
|
133
|
+
</div>
|
|
134
|
+
<Testimonials key={`${variant}-${state}`} {...props} loading={state === "loading"} />
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
}
|