@vamos-ui/react 0.0.0-stage → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +27 -2
- package/dist/blocks/block-heading.d.ts +29 -0
- package/dist/blocks/block-heading.js +39 -0
- package/dist/blocks/block-image.d.ts +52 -0
- package/dist/blocks/block-image.js +48 -0
- package/dist/blocks/block-link.d.ts +30 -0
- package/dist/blocks/block-link.js +36 -0
- package/dist/blocks/create-blocks.d.ts +54 -0
- package/dist/blocks/create-blocks.js +52 -0
- package/dist/blocks/index.d.ts +55 -0
- package/dist/blocks/index.js +59 -0
- package/dist/blocks/json-ld.d.ts +18 -0
- package/dist/blocks/json-ld.js +44 -0
- package/dist/blocks/labels.d.ts +20 -0
- package/dist/blocks/labels.js +43 -0
- package/dist/blocks/rich-text.d.ts +36 -0
- package/dist/blocks/rich-text.js +106 -0
- package/dist/blocks/schema/define-block.d.ts +151 -0
- package/dist/blocks/schema/define-block.js +120 -0
- package/dist/blocks/schema/emphasis.d.ts +17 -0
- package/dist/blocks/schema/emphasis.js +69 -0
- package/dist/blocks/schema/fields.d.ts +497 -0
- package/dist/blocks/schema/fields.js +240 -0
- package/dist/blocks/schema/icons.d.ts +2 -0
- package/dist/blocks/schema/icons.js +26 -0
- package/dist/blocks/schema/index.d.ts +18 -0
- package/dist/blocks/schema/index.js +21 -0
- package/dist/blocks/schema/lint-types.d.ts +16 -0
- package/dist/blocks/schema/lint-types.js +2 -0
- package/dist/blocks/schema/lint.d.ts +32 -0
- package/dist/blocks/schema/lint.js +164 -0
- package/dist/blocks/schema/localize.d.ts +20 -0
- package/dist/blocks/schema/localize.js +29 -0
- package/dist/blocks/schema/localized.d.ts +25 -0
- package/dist/blocks/schema/localized.js +53 -0
- package/dist/blocks/schema/migrate.d.ts +24 -0
- package/dist/blocks/schema/migrate.js +75 -0
- package/dist/blocks/schema/nodes.d.ts +196 -0
- package/dist/blocks/schema/nodes.js +78 -0
- package/dist/blocks/schema/rich-doc-schema.d.ts +32 -0
- package/dist/blocks/schema/rich-doc-schema.js +66 -0
- package/dist/blocks/schema/rich-doc.d.ts +90 -0
- package/dist/blocks/schema/rich-doc.js +62 -0
- package/dist/blocks/schema/safety.d.ts +20 -0
- package/dist/blocks/schema/safety.js +49 -0
- package/dist/blocks/schema/types.d.ts +172 -0
- package/dist/blocks/schema/types.js +3 -0
- package/dist/blocks/schema/validate.d.ts +17 -0
- package/dist/blocks/schema/validate.js +32 -0
- package/dist/blocks/schema/walk.d.ts +22 -0
- package/dist/blocks/schema/walk.js +60 -0
- package/dist/blocks/section-header.d.ts +38 -0
- package/dist/blocks/section-header.js +22 -0
- package/dist/blocks/section.d.ts +59 -0
- package/dist/blocks/section.js +66 -0
- package/dist/blocks/site/_kit-1.d.ts +101 -0
- package/dist/blocks/site/_kit-1.js +137 -0
- package/dist/blocks/site/_site-icon-1.d.ts +6 -0
- package/dist/blocks/site/_site-icon-1.js +15 -0
- package/dist/blocks/site/announcement-bar.d.ts +42 -0
- package/dist/blocks/site/announcement-bar.js +38 -0
- package/dist/blocks/site/announcement-dismiss.d.ts +18 -0
- package/dist/blocks/site/announcement-dismiss.js +28 -0
- package/dist/blocks/site/article-layout.d.ts +65 -0
- package/dist/blocks/site/article-layout.js +88 -0
- package/dist/blocks/site/blog-list.d.ts +79 -0
- package/dist/blocks/site/blog-list.js +78 -0
- package/dist/blocks/site/comparison-table.d.ts +54 -0
- package/dist/blocks/site/comparison-table.js +38 -0
- package/dist/blocks/site/consent-banner.d.ts +52 -0
- package/dist/blocks/site/consent-banner.js +33 -0
- package/dist/blocks/site/contact-dock.d.ts +52 -0
- package/dist/blocks/site/contact-dock.js +55 -0
- package/dist/blocks/site/contact-form.d.ts +60 -0
- package/dist/blocks/site/contact-form.js +45 -0
- package/dist/blocks/site/cta-booking.d.ts +43 -0
- package/dist/blocks/site/cta-booking.js +69 -0
- package/dist/blocks/site/cta.d.ts +74 -0
- package/dist/blocks/site/cta.js +113 -0
- package/dist/blocks/site/embed-facade.d.ts +20 -0
- package/dist/blocks/site/embed-facade.js +21 -0
- package/dist/blocks/site/faq.d.ts +48 -0
- package/dist/blocks/site/faq.js +52 -0
- package/dist/blocks/site/feature-grid.d.ts +46 -0
- package/dist/blocks/site/feature-grid.js +50 -0
- package/dist/blocks/site/feature-tabs.d.ts +22 -0
- package/dist/blocks/site/feature-tabs.js +11 -0
- package/dist/blocks/site/footer.d.ts +68 -0
- package/dist/blocks/site/footer.js +61 -0
- package/dist/blocks/site/gallery-section.d.ts +42 -0
- package/dist/blocks/site/gallery-section.js +48 -0
- package/dist/blocks/site/hero-video.d.ts +15 -0
- package/dist/blocks/site/hero-video.js +31 -0
- package/dist/blocks/site/hero.d.ts +64 -0
- package/dist/blocks/site/hero.js +73 -0
- package/dist/blocks/site/logo-strip.d.ts +44 -0
- package/dist/blocks/site/logo-strip.js +27 -0
- package/dist/blocks/site/map-hours.d.ts +83 -0
- package/dist/blocks/site/map-hours.js +125 -0
- package/dist/blocks/site/media-text.d.ts +45 -0
- package/dist/blocks/site/media-text.js +56 -0
- package/dist/blocks/site/menu-list.d.ts +74 -0
- package/dist/blocks/site/menu-list.js +84 -0
- package/dist/blocks/site/navbar-submenu.d.ts +18 -0
- package/dist/blocks/site/navbar-submenu.js +51 -0
- package/dist/blocks/site/navbar.d.ts +67 -0
- package/dist/blocks/site/navbar.js +64 -0
- package/dist/blocks/site/not-found.d.ts +40 -0
- package/dist/blocks/site/not-found.js +38 -0
- package/dist/blocks/site/page-intro.d.ts +46 -0
- package/dist/blocks/site/page-intro.js +44 -0
- package/dist/blocks/site/pricing-table.d.ts +67 -0
- package/dist/blocks/site/pricing-table.js +83 -0
- package/dist/blocks/site/process.d.ts +36 -0
- package/dist/blocks/site/process.js +42 -0
- package/dist/blocks/site/registry-1.d.ts +720 -0
- package/dist/blocks/site/registry-1.js +783 -0
- package/dist/blocks/site/registry-2.d.ts +914 -0
- package/dist/blocks/site/registry-2.js +563 -0
- package/dist/blocks/site/rich-text-section.d.ts +34 -0
- package/dist/blocks/site/rich-text-section.js +32 -0
- package/dist/blocks/site/shared/brand-icons.d.ts +21 -0
- package/dist/blocks/site/shared/brand-icons.js +56 -0
- package/dist/blocks/site/shared/consent-gate.d.ts +41 -0
- package/dist/blocks/site/shared/consent-gate.js +43 -0
- package/dist/blocks/site/shared/consent-island.d.ts +38 -0
- package/dist/blocks/site/shared/consent-island.js +63 -0
- package/dist/blocks/site/shared/consent.d.ts +49 -0
- package/dist/blocks/site/shared/consent.js +130 -0
- package/dist/blocks/site/shared/contact-form-island.d.ts +41 -0
- package/dist/blocks/site/shared/contact-form-island.js +100 -0
- package/dist/blocks/site/shared/copy-link.d.ts +10 -0
- package/dist/blocks/site/shared/copy-link.js +25 -0
- package/dist/blocks/site/shared/dock-avoid.d.ts +15 -0
- package/dist/blocks/site/shared/dock-avoid.js +107 -0
- package/dist/blocks/site/shared/dock-hours.d.ts +13 -0
- package/dist/blocks/site/shared/dock-hours.js +25 -0
- package/dist/blocks/site/shared/gallery-lightbox.d.ts +12 -0
- package/dist/blocks/site/shared/gallery-lightbox.js +10 -0
- package/dist/blocks/site/shared/island-keys.d.ts +10 -0
- package/dist/blocks/site/shared/island-keys.js +44 -0
- package/dist/blocks/site/shared/kit-2.d.ts +55 -0
- package/dist/blocks/site/shared/kit-2.js +84 -0
- package/dist/blocks/site/shared/labels-2.d.ts +209 -0
- package/dist/blocks/site/shared/labels-2.js +427 -0
- package/dist/blocks/site/shared/open-now.d.ts +22 -0
- package/dist/blocks/site/shared/open-now.js +27 -0
- package/dist/blocks/site/shared/opening-hours.d.ts +117 -0
- package/dist/blocks/site/shared/opening-hours.js +245 -0
- package/dist/blocks/site/shared/site-accent.d.ts +48 -0
- package/dist/blocks/site/shared/site-accent.js +249 -0
- package/dist/blocks/site/shared/site-form.d.ts +79 -0
- package/dist/blocks/site/shared/site-form.js +111 -0
- package/dist/blocks/site/shared/site-routing.d.ts +54 -0
- package/dist/blocks/site/shared/site-routing.js +86 -0
- package/dist/blocks/site/shared/testimonials-carousel.d.ts +17 -0
- package/dist/blocks/site/shared/testimonials-carousel.js +64 -0
- package/dist/blocks/site/site-shell.d.ts +108 -0
- package/dist/blocks/site/site-shell.js +254 -0
- package/dist/blocks/site/stats-band.d.ts +42 -0
- package/dist/blocks/site/stats-band.js +45 -0
- package/dist/blocks/site/team.d.ts +44 -0
- package/dist/blocks/site/team.js +48 -0
- package/dist/blocks/site/testimonials.d.ts +68 -0
- package/dist/blocks/site/testimonials.js +66 -0
- package/dist/blocks/types.d.ts +63 -0
- package/dist/blocks/types.js +2 -0
- package/dist/business/approval-flow.d.ts +152 -0
- package/dist/business/approval-flow.js +221 -0
- package/dist/business/export-core.d.ts +55 -0
- package/dist/business/export-core.js +101 -0
- package/dist/business/export.d.ts +148 -0
- package/dist/business/export.js +264 -0
- package/dist/business/import-core.d.ts +104 -0
- package/dist/business/import-core.js +281 -0
- package/dist/business/import-wizard.d.ts +186 -0
- package/dist/business/import-wizard.js +401 -0
- package/dist/business/index.d.ts +12 -0
- package/dist/business/index.js +22 -0
- package/dist/business/line-items-core.d.ts +129 -0
- package/dist/business/line-items-core.js +183 -0
- package/dist/business/line-items.d.ts +119 -0
- package/dist/business/line-items.js +299 -0
- package/dist/business/multi-step-form.d.ts +131 -0
- package/dist/business/multi-step-form.js +337 -0
- package/dist/business/permission-core.d.ts +59 -0
- package/dist/business/permission-core.js +99 -0
- package/dist/business/permission-matrix.d.ts +158 -0
- package/dist/business/permission-matrix.js +341 -0
- package/dist/business/setup-checklist.d.ts +80 -0
- package/dist/business/setup-checklist.js +92 -0
- package/dist/business/signer-status.d.ts +53 -0
- package/dist/business/signer-status.js +76 -0
- package/dist/charts/area-chart.d.ts +35 -0
- package/dist/charts/area-chart.js +33 -0
- package/dist/charts/bar-chart.d.ts +27 -0
- package/dist/charts/bar-chart.js +46 -0
- package/dist/charts/bar-list.d.ts +47 -0
- package/dist/charts/bar-list.js +60 -0
- package/dist/charts/chart-shell.d.ts +173 -0
- package/dist/charts/chart-shell.js +205 -0
- package/dist/charts/chart.d.ts +73 -0
- package/dist/charts/chart.js +106 -0
- package/dist/charts/combo-chart.d.ts +29 -0
- package/dist/charts/combo-chart.js +47 -0
- package/dist/charts/donut-chart.d.ts +33 -0
- package/dist/charts/donut-chart.js +113 -0
- package/dist/charts/funnel.d.ts +51 -0
- package/dist/charts/funnel.js +69 -0
- package/dist/charts/gauge.d.ts +62 -0
- package/dist/charts/gauge.js +104 -0
- package/dist/charts/heatmap.d.ts +81 -0
- package/dist/charts/heatmap.js +338 -0
- package/dist/charts/index.d.ts +12 -0
- package/dist/charts/index.js +14 -0
- package/dist/charts/line-chart.d.ts +21 -0
- package/dist/charts/line-chart.js +36 -0
- package/dist/charts/test-utils.d.ts +2 -0
- package/dist/charts/test-utils.js +38 -0
- package/dist/charts/utils.d.ts +130 -0
- package/dist/charts/utils.js +262 -0
- package/dist/components/_qr-core.d.ts +26 -0
- package/dist/components/_qr-core.js +376 -0
- package/dist/components/accordion.d.ts +47 -0
- package/dist/components/accordion.js +70 -0
- package/dist/components/activity-timeline.d.ts +149 -0
- package/dist/components/activity-timeline.js +122 -0
- package/dist/components/address-field.d.ts +116 -0
- package/dist/components/address-field.js +219 -0
- package/dist/components/alert-dialog.d.ts +99 -0
- package/dist/components/alert-dialog.js +192 -0
- package/dist/components/alert.d.ts +42 -0
- package/dist/components/alert.js +82 -0
- package/dist/components/app-shell.d.ts +159 -0
- package/dist/components/app-shell.js +289 -0
- package/dist/components/attachment-list.d.ts +96 -0
- package/dist/components/attachment-list.js +196 -0
- package/dist/components/audit-log.d.ts +150 -0
- package/dist/components/audit-log.js +205 -0
- package/dist/components/avatar.d.ts +87 -0
- package/dist/components/avatar.js +126 -0
- package/dist/components/backup-codes.d.ts +42 -0
- package/dist/components/backup-codes.js +67 -0
- package/dist/components/badge.d.ts +41 -0
- package/dist/components/badge.js +68 -0
- package/dist/components/breadcrumb.d.ts +78 -0
- package/dist/components/breadcrumb.js +106 -0
- package/dist/components/button-group.d.ts +52 -0
- package/dist/components/button-group.js +77 -0
- package/dist/components/button.d.ts +58 -0
- package/dist/components/button.js +107 -0
- package/dist/components/calendar.d.ts +240 -0
- package/dist/components/calendar.js +483 -0
- package/dist/components/card.d.ts +66 -0
- package/dist/components/card.js +76 -0
- package/dist/components/carousel.d.ts +170 -0
- package/dist/components/carousel.js +348 -0
- package/dist/components/checkbox.d.ts +78 -0
- package/dist/components/checkbox.js +138 -0
- package/dist/components/color-picker.d.ts +112 -0
- package/dist/components/color-picker.js +235 -0
- package/dist/components/combobox.d.ts +136 -0
- package/dist/components/combobox.js +294 -0
- package/dist/components/command.d.ts +281 -0
- package/dist/components/command.js +498 -0
- package/dist/components/comment-thread.d.ts +252 -0
- package/dist/components/comment-thread.js +449 -0
- package/dist/components/context-menu.d.ts +77 -0
- package/dist/components/context-menu.js +82 -0
- package/dist/components/currency-input.d.ts +43 -0
- package/dist/components/currency-input.js +85 -0
- package/dist/components/date-picker.d.ts +141 -0
- package/dist/components/date-picker.js +241 -0
- package/dist/components/date-range-picker.d.ts +91 -0
- package/dist/components/date-range-picker.js +251 -0
- package/dist/components/description-list.d.ts +92 -0
- package/dist/components/description-list.js +42 -0
- package/dist/components/dialog.d.ts +139 -0
- package/dist/components/dialog.js +185 -0
- package/dist/components/dropdown-menu.d.ts +100 -0
- package/dist/components/dropdown-menu.js +102 -0
- package/dist/components/editor-layout.d.ts +166 -0
- package/dist/components/editor-layout.js +237 -0
- package/dist/components/empty-state.d.ts +49 -0
- package/dist/components/empty-state.js +68 -0
- package/dist/components/entity-card.d.ts +83 -0
- package/dist/components/entity-card.js +92 -0
- package/dist/components/file-upload.d.ts +256 -0
- package/dist/components/file-upload.js +490 -0
- package/dist/components/formatted-input.d.ts +177 -0
- package/dist/components/formatted-input.js +399 -0
- package/dist/components/hierarchy-chart.d.ts +190 -0
- package/dist/components/hierarchy-chart.js +890 -0
- package/dist/components/hover-card.d.ts +21 -0
- package/dist/components/hover-card.js +32 -0
- package/dist/components/iban-input.d.ts +38 -0
- package/dist/components/iban-input.js +112 -0
- package/dist/components/id-input.d.ts +65 -0
- package/dist/components/id-input.js +130 -0
- package/dist/components/image.d.ts +130 -0
- package/dist/components/image.js +168 -0
- package/dist/components/input-otp.d.ts +62 -0
- package/dist/components/input-otp.js +73 -0
- package/dist/components/input.d.ts +141 -0
- package/dist/components/input.js +187 -0
- package/dist/components/item.d.ts +96 -0
- package/dist/components/item.js +113 -0
- package/dist/components/kbd.d.ts +64 -0
- package/dist/components/kbd.js +119 -0
- package/dist/components/list-layout.d.ts +144 -0
- package/dist/components/list-layout.js +210 -0
- package/dist/components/native-select.d.ts +33 -0
- package/dist/components/native-select.js +48 -0
- package/dist/components/navigation-menu.d.ts +127 -0
- package/dist/components/navigation-menu.js +129 -0
- package/dist/components/notification-center.d.ts +164 -0
- package/dist/components/notification-center.js +399 -0
- package/dist/components/page-header.d.ts +60 -0
- package/dist/components/page-header.js +60 -0
- package/dist/components/pagination.d.ts +121 -0
- package/dist/components/pagination.js +174 -0
- package/dist/components/phone-input.d.ts +49 -0
- package/dist/components/phone-input.js +266 -0
- package/dist/components/pin-map.d.ts +58 -0
- package/dist/components/pin-map.js +167 -0
- package/dist/components/popover.d.ts +38 -0
- package/dist/components/popover.js +69 -0
- package/dist/components/progress.d.ts +79 -0
- package/dist/components/progress.js +97 -0
- package/dist/components/qr-code.d.ts +36 -0
- package/dist/components/qr-code.js +27 -0
- package/dist/components/radio-group.d.ts +43 -0
- package/dist/components/radio-group.js +81 -0
- package/dist/components/record-detail-layout.d.ts +167 -0
- package/dist/components/record-detail-layout.js +233 -0
- package/dist/components/record-picker.d.ts +199 -0
- package/dist/components/record-picker.js +650 -0
- package/dist/components/resizable.d.ts +50 -0
- package/dist/components/resizable.js +88 -0
- package/dist/components/scroll-area.d.ts +40 -0
- package/dist/components/scroll-area.js +56 -0
- package/dist/components/select.d.ts +126 -0
- package/dist/components/select.js +137 -0
- package/dist/components/separator.d.ts +31 -0
- package/dist/components/separator.js +41 -0
- package/dist/components/settings-layout.d.ts +134 -0
- package/dist/components/settings-layout.js +180 -0
- package/dist/components/sheet.d.ts +103 -0
- package/dist/components/sheet.js +165 -0
- package/dist/components/sidebar.d.ts +171 -0
- package/dist/components/sidebar.js +421 -0
- package/dist/components/signature-pad.d.ts +85 -0
- package/dist/components/signature-pad.js +283 -0
- package/dist/components/skeleton.d.ts +64 -0
- package/dist/components/skeleton.js +53 -0
- package/dist/components/sla-timer.d.ts +75 -0
- package/dist/components/sla-timer.js +142 -0
- package/dist/components/slider.d.ts +57 -0
- package/dist/components/slider.js +133 -0
- package/dist/components/slug-input.d.ts +69 -0
- package/dist/components/slug-input.js +201 -0
- package/dist/components/sparkline.d.ts +54 -0
- package/dist/components/sparkline.js +122 -0
- package/dist/components/spinner.d.ts +34 -0
- package/dist/components/spinner.js +34 -0
- package/dist/components/stat.d.ts +135 -0
- package/dist/components/stat.js +130 -0
- package/dist/components/status-picker.d.ts +107 -0
- package/dist/components/status-picker.js +175 -0
- package/dist/components/stepper.d.ts +86 -0
- package/dist/components/stepper.js +103 -0
- package/dist/components/switch.d.ts +34 -0
- package/dist/components/switch.js +70 -0
- package/dist/components/table.d.ts +101 -0
- package/dist/components/table.js +72 -0
- package/dist/components/tabs.d.ts +103 -0
- package/dist/components/tabs.js +173 -0
- package/dist/components/tag-input.d.ts +77 -0
- package/dist/components/tag-input.js +305 -0
- package/dist/components/task-list.d.ts +89 -0
- package/dist/components/task-list.js +238 -0
- package/dist/components/time-picker.d.ts +119 -0
- package/dist/components/time-picker.js +399 -0
- package/dist/components/toast.d.ts +87 -0
- package/dist/components/toast.js +142 -0
- package/dist/components/toggle.d.ts +77 -0
- package/dist/components/toggle.js +109 -0
- package/dist/components/tooltip.d.ts +69 -0
- package/dist/components/tooltip.js +105 -0
- package/dist/components/top-bar.d.ts +87 -0
- package/dist/components/top-bar.js +99 -0
- package/dist/components/tour.d.ts +60 -0
- package/dist/components/tour.js +139 -0
- package/dist/components/tree-select.d.ts +89 -0
- package/dist/components/tree-select.js +243 -0
- package/dist/components/tree-view.d.ts +109 -0
- package/dist/components/tree-view.js +170 -0
- package/dist/components/typography.d.ts +107 -0
- package/dist/components/typography.js +128 -0
- package/dist/components/user-picker.d.ts +89 -0
- package/dist/components/user-picker.js +162 -0
- package/dist/components/version-history.d.ts +191 -0
- package/dist/components/version-history.js +431 -0
- package/dist/data-table/csv.d.ts +27 -0
- package/dist/data-table/csv.js +68 -0
- package/dist/data-table/data-table.d.ts +423 -0
- package/dist/data-table/data-table.js +1259 -0
- package/dist/data-table/filter-bar.d.ts +146 -0
- package/dist/data-table/filter-bar.js +569 -0
- package/dist/data-table/filter-fns.d.ts +65 -0
- package/dist/data-table/filter-fns.js +382 -0
- package/dist/data-table/index.d.ts +8 -0
- package/dist/data-table/index.js +9 -0
- package/dist/data-table/saved-views.d.ts +100 -0
- package/dist/data-table/saved-views.js +251 -0
- package/dist/data-table/types.d.ts +168 -0
- package/dist/data-table/types.js +87 -0
- package/dist/data-table/url-state.d.ts +94 -0
- package/dist/data-table/url-state.js +303 -0
- package/dist/data-table/view-state.d.ts +16 -0
- package/dist/data-table/view-state.js +81 -0
- package/dist/editor/_test-setup.d.ts +1 -0
- package/dist/editor/_test-setup.js +33 -0
- package/dist/editor/block-editor.d.ts +137 -0
- package/dist/editor/block-editor.js +280 -0
- package/dist/editor/commands.d.ts +31 -0
- package/dist/editor/commands.js +150 -0
- package/dist/editor/context.d.ts +108 -0
- package/dist/editor/context.js +30 -0
- package/dist/editor/convert.d.ts +66 -0
- package/dist/editor/convert.js +567 -0
- package/dist/editor/drag-handle.d.ts +10 -0
- package/dist/editor/drag-handle.js +69 -0
- package/dist/editor/extensions.d.ts +34 -0
- package/dist/editor/extensions.js +239 -0
- package/dist/editor/index.d.ts +14 -0
- package/dist/editor/index.js +17 -0
- package/dist/editor/inserter.d.ts +12 -0
- package/dist/editor/inserter.js +88 -0
- package/dist/editor/inspector.d.ts +17 -0
- package/dist/editor/inspector.js +65 -0
- package/dist/editor/items.d.ts +62 -0
- package/dist/editor/items.js +195 -0
- package/dist/editor/labels.d.ts +119 -0
- package/dist/editor/labels.js +130 -0
- package/dist/editor/markdown.d.ts +14 -0
- package/dist/editor/markdown.js +209 -0
- package/dist/editor/menus.d.ts +20 -0
- package/dist/editor/menus.js +236 -0
- package/dist/editor/nodes.d.ts +14 -0
- package/dist/editor/nodes.js +201 -0
- package/dist/editor/outline.d.ts +11 -0
- package/dist/editor/outline.js +52 -0
- package/dist/editor/schema-form.d.ts +64 -0
- package/dist/editor/schema-form.js +290 -0
- package/dist/editor/slash-menu.d.ts +15 -0
- package/dist/editor/slash-menu.js +119 -0
- package/dist/fonts/catalog.d.ts +53 -0
- package/dist/fonts/catalog.js +121 -0
- package/dist/fonts/font-picker.d.ts +70 -0
- package/dist/fonts/font-picker.js +225 -0
- package/dist/fonts/index.d.ts +6 -0
- package/dist/fonts/index.js +7 -0
- package/dist/fonts/loader.d.ts +66 -0
- package/dist/fonts/loader.js +161 -0
- package/dist/fonts/pairing-picker.d.ts +31 -0
- package/dist/fonts/pairing-picker.js +81 -0
- package/dist/fonts/pairings.d.ts +84 -0
- package/dist/fonts/pairings.js +149 -0
- package/dist/fonts/provider.d.ts +34 -0
- package/dist/fonts/provider.js +51 -0
- package/dist/form/index.d.ts +1 -0
- package/dist/form/index.js +1 -0
- package/dist/format/core.d.ts +149 -0
- package/dist/format/core.js +357 -0
- package/dist/format/index.d.ts +4 -0
- package/dist/format/index.js +5 -0
- package/dist/format/use-format.d.ts +1 -0
- package/dist/format/use-format.js +3 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.js +92 -0
- package/dist/lib/cn.d.ts +3 -0
- package/dist/lib/cn.js +16 -0
- package/dist/lib/color.d.ts +64 -0
- package/dist/lib/color.js +177 -0
- package/dist/lib/compose-refs.d.ts +24 -0
- package/dist/lib/compose-refs.js +45 -0
- package/dist/lib/data-islands.d.ts +194 -0
- package/dist/lib/data-islands.js +368 -0
- package/dist/lib/date.d.ts +129 -0
- package/dist/lib/date.js +386 -0
- package/dist/lib/field-context.d.ts +64 -0
- package/dist/lib/field-context.js +62 -0
- package/dist/lib/floating-arrow.d.ts +18 -0
- package/dist/lib/floating-arrow.js +15 -0
- package/dist/lib/islands.d.ts +38 -0
- package/dist/lib/islands.js +40 -0
- package/dist/lib/labels.d.ts +51 -0
- package/dist/lib/labels.js +56 -0
- package/dist/lib/layer.d.ts +36 -0
- package/dist/lib/layer.js +42 -0
- package/dist/lib/locale.d.ts +85 -0
- package/dist/lib/locale.js +105 -0
- package/dist/lib/menu.d.ts +58 -0
- package/dist/lib/menu.js +99 -0
- package/dist/lib/message-format.d.ts +20 -0
- package/dist/lib/message-format.js +116 -0
- package/dist/lib/nav.d.ts +132 -0
- package/dist/lib/nav.js +178 -0
- package/dist/lib/provider.d.ts +100 -0
- package/dist/lib/provider.js +105 -0
- package/dist/lib/public.d.ts +23 -0
- package/dist/lib/public.js +34 -0
- package/dist/lib/sr-name.d.ts +18 -0
- package/dist/lib/sr-name.js +17 -0
- package/dist/lib/text.d.ts +100 -0
- package/dist/lib/text.js +233 -0
- package/dist/lib/theme-scope.d.ts +58 -0
- package/dist/lib/theme-scope.js +59 -0
- package/dist/lib/use-async-list.d.ts +60 -0
- package/dist/lib/use-async-list.js +119 -0
- package/dist/lib/use-container-width.d.ts +19 -0
- package/dist/lib/use-container-width.js +39 -0
- package/dist/lib/use-controllable-state.d.ts +33 -0
- package/dist/lib/use-controllable-state.js +56 -0
- package/dist/lib/use-edge-fade.d.ts +13 -0
- package/dist/lib/use-edge-fade.js +43 -0
- package/dist/lib/use-formatted-input.d.ts +69 -0
- package/dist/lib/use-formatted-input.js +152 -0
- package/dist/lib/use-hotkeys.d.ts +80 -0
- package/dist/lib/use-hotkeys.js +221 -0
- package/dist/lib/use-hover-intent.d.ts +44 -0
- package/dist/lib/use-hover-intent.js +119 -0
- package/dist/lib/use-media-query.d.ts +21 -0
- package/dist/lib/use-media-query.js +28 -0
- package/dist/lib/use-reduced-motion.d.ts +8 -0
- package/dist/lib/use-reduced-motion.js +13 -0
- package/dist/lib/use-tree.d.ts +153 -0
- package/dist/lib/use-tree.js +534 -0
- package/dist/lib/value-format.d.ts +25 -0
- package/dist/lib/value-format.js +56 -0
- package/dist/lib/variants.d.ts +131 -0
- package/dist/lib/variants.js +109 -0
- package/dist/locale-data/core/date.d.ts +24 -0
- package/dist/locale-data/core/date.js +68 -0
- package/dist/locale-data/core/decimal.d.ts +19 -0
- package/dist/locale-data/core/decimal.js +79 -0
- package/dist/locale-data/core/holidays.d.ts +30 -0
- package/dist/locale-data/core/holidays.js +79 -0
- package/dist/locale-data/core/iban.d.ts +29 -0
- package/dist/locale-data/core/iban.js +74 -0
- package/dist/locale-data/core/index.d.ts +7 -0
- package/dist/locale-data/core/index.js +6 -0
- package/dist/locale-data/core/types.d.ts +173 -0
- package/dist/locale-data/core/types.js +6 -0
- package/dist/locale-data/core/week-info.d.ts +23 -0
- package/dist/locale-data/core/week-info.js +85 -0
- package/dist/locale-data/core/working-days.d.ts +27 -0
- package/dist/locale-data/core/working-days.js +133 -0
- package/dist/locale-data/index.d.ts +2 -0
- package/dist/locale-data/index.js +4 -0
- package/dist/locale-data/tr/address-tr.json +1 -0
- package/dist/locale-data/tr/address.d.ts +23 -0
- package/dist/locale-data/tr/address.js +52 -0
- package/dist/locale-data/tr/holidays.d.ts +31 -0
- package/dist/locale-data/tr/holidays.js +81 -0
- package/dist/locale-data/tr/iban.d.ts +21 -0
- package/dist/locale-data/tr/iban.js +45 -0
- package/dist/locale-data/tr/id.d.ts +36 -0
- package/dist/locale-data/tr/id.js +120 -0
- package/dist/locale-data/tr/index.d.ts +12 -0
- package/dist/locale-data/tr/index.js +33 -0
- package/dist/locale-data/tr/kdv.d.ts +91 -0
- package/dist/locale-data/tr/kdv.js +222 -0
- package/dist/locales/en.d.ts +2102 -0
- package/dist/locales/en.js +2088 -0
- package/dist/locales/tr.d.ts +2086 -0
- package/dist/locales/tr.js +2087 -0
- package/dist/media/focal-point.d.ts +42 -0
- package/dist/media/focal-point.js +96 -0
- package/dist/media/gallery-layout.d.ts +19 -0
- package/dist/media/gallery-layout.js +61 -0
- package/dist/media/gallery.d.ts +64 -0
- package/dist/media/gallery.js +140 -0
- package/dist/media/image-cropper.d.ts +86 -0
- package/dist/media/image-cropper.js +170 -0
- package/dist/media/image-field.d.ts +115 -0
- package/dist/media/image-field.js +212 -0
- package/dist/media/index.d.ts +19 -0
- package/dist/media/index.js +23 -0
- package/dist/media/lightbox.d.ts +82 -0
- package/dist/media/lightbox.js +171 -0
- package/dist/media/link-preview.d.ts +97 -0
- package/dist/media/link-preview.js +177 -0
- package/dist/media/media-library.d.ts +244 -0
- package/dist/media/media-library.js +776 -0
- package/dist/media/media-picker.d.ts +96 -0
- package/dist/media/media-picker.js +209 -0
- package/dist/media/media-provider.d.ts +23 -0
- package/dist/media/media-provider.js +44 -0
- package/dist/media/media-utils.d.ts +39 -0
- package/dist/media/media-utils.js +145 -0
- package/dist/media/memory-adapter.d.ts +22 -0
- package/dist/media/memory-adapter.js +162 -0
- package/dist/media/rest-adapter.d.ts +90 -0
- package/dist/media/rest-adapter.js +208 -0
- package/dist/media/serp.d.ts +62 -0
- package/dist/media/serp.js +108 -0
- package/dist/media/test-fixtures.d.ts +3 -0
- package/dist/media/test-fixtures.js +37 -0
- package/dist/media/types.d.ts +183 -0
- package/dist/media/types.js +3 -0
- package/dist/media/use-pan-zoom.d.ts +51 -0
- package/dist/media/use-pan-zoom.js +156 -0
- package/dist/media/use-upload-queue.d.ts +64 -0
- package/dist/media/use-upload-queue.js +115 -0
- package/dist/media/video-player.d.ts +135 -0
- package/dist/media/video-player.js +319 -0
- package/dist/motion/core.d.ts +32 -0
- package/dist/motion/core.js +77 -0
- package/dist/motion/count-up.d.ts +29 -0
- package/dist/motion/count-up.js +92 -0
- package/dist/motion/index.d.ts +11 -0
- package/dist/motion/index.js +13 -0
- package/dist/motion/motion-scope.d.ts +17 -0
- package/dist/motion/motion-scope.js +16 -0
- package/dist/motion/page-transition.d.ts +33 -0
- package/dist/motion/page-transition.js +61 -0
- package/dist/motion/parallax.d.ts +37 -0
- package/dist/motion/parallax.js +90 -0
- package/dist/motion/pointer.d.ts +38 -0
- package/dist/motion/pointer.js +117 -0
- package/dist/motion/reveal.d.ts +72 -0
- package/dist/motion/reveal.js +133 -0
- package/dist/motion/scroll-shrink.d.ts +18 -0
- package/dist/motion/scroll-shrink.js +47 -0
- package/dist/motion/skeleton-swap.d.ts +17 -0
- package/dist/motion/skeleton-swap.js +43 -0
- package/dist/motion/text-reveal.d.ts +30 -0
- package/dist/motion/text-reveal.js +29 -0
- package/dist/motion/ticker.d.ts +35 -0
- package/dist/motion/ticker.js +16 -0
- package/dist/next/index.d.ts +42 -0
- package/dist/next/index.js +36 -0
- package/dist/render/block-renderer.d.ts +56 -0
- package/dist/render/block-renderer.js +137 -0
- package/dist/render/index.d.ts +6 -0
- package/dist/render/index.js +7 -0
- package/dist/render/prepare.d.ts +61 -0
- package/dist/render/prepare.js +119 -0
- package/dist/scheduler/core/duration.d.ts +83 -0
- package/dist/scheduler/core/duration.js +174 -0
- package/dist/scheduler/core/gantt.d.ts +63 -0
- package/dist/scheduler/core/gantt.js +226 -0
- package/dist/scheduler/core/index.d.ts +6 -0
- package/dist/scheduler/core/index.js +7 -0
- package/dist/scheduler/core/layout.d.ts +97 -0
- package/dist/scheduler/core/layout.js +249 -0
- package/dist/scheduler/core/time-scale.d.ts +89 -0
- package/dist/scheduler/core/time-scale.js +173 -0
- package/dist/scheduler/gantt.d.ts +125 -0
- package/dist/scheduler/gantt.js +532 -0
- package/dist/scheduler/index.d.ts +6 -0
- package/dist/scheduler/index.js +7 -0
- package/dist/scheduler/resource-calendar.d.ts +218 -0
- package/dist/scheduler/resource-calendar.js +661 -0
- package/dist/scheduler/scheduler.d.ts +168 -0
- package/dist/scheduler/scheduler.js +768 -0
- package/dist/scheduler/shared.d.ts +63 -0
- package/dist/scheduler/shared.js +145 -0
- package/dist/scheduler/time-tracker.d.ts +138 -0
- package/dist/scheduler/time-tracker.js +403 -0
- package/dist/sortable/core.d.ts +67 -0
- package/dist/sortable/core.js +167 -0
- package/dist/sortable/index.d.ts +8 -0
- package/dist/sortable/index.js +10 -0
- package/dist/sortable/kanban-core.d.ts +70 -0
- package/dist/sortable/kanban-core.js +67 -0
- package/dist/sortable/kanban.d.ts +147 -0
- package/dist/sortable/kanban.js +472 -0
- package/dist/sortable/sortable-list.d.ts +71 -0
- package/dist/sortable/sortable-list.js +76 -0
- package/dist/sortable/sortable-tree.d.ts +105 -0
- package/dist/sortable/sortable-tree.js +462 -0
- package/dist/sortable/sortable.d.ts +188 -0
- package/dist/sortable/sortable.js +485 -0
- package/dist/sortable/use-pointer-drag.d.ts +75 -0
- package/dist/sortable/use-pointer-drag.js +173 -0
- package/dist/sortable/use-time-scale.d.ts +11 -0
- package/dist/sortable/use-time-scale.js +19 -0
- package/dist/styles/base.css +51 -0
- package/dist/styles/blocks.css +949 -0
- package/dist/styles/calendar.css +642 -0
- package/dist/styles/charts.css +264 -0
- package/dist/styles/data.css +474 -0
- package/dist/styles/editors.css +1022 -0
- package/dist/styles/forms.css +406 -0
- package/dist/styles/media.css +515 -0
- package/dist/styles/motion.css +389 -0
- package/dist/styles/navigation.css +293 -0
- package/dist/styles/overlays.css +244 -0
- package/dist/styles.css +743 -0
- package/package.json +160 -4
|
@@ -0,0 +1,783 @@
|
|
|
1
|
+
// Block definitions (layer 2) for registry-1 site blocks: announcement, navbar, hero, features,
|
|
2
|
+
// logo-strip, stats, page-intro, rich-text, media-text, cta, faq, steps. Server/admin only — this
|
|
3
|
+
// file imports zod; component files never import it.
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { f, localizedSchema } from "../schema/fields.js";
|
|
6
|
+
import { defineBlock } from "../schema/define-block.js";
|
|
7
|
+
import { sanitizeHref } from "../schema/safety.js";
|
|
8
|
+
import { richFromText } from "../schema/rich-doc.js";
|
|
9
|
+
import { AnnouncementBar } from "./announcement-bar.js";
|
|
10
|
+
import { Navbar } from "./navbar.js";
|
|
11
|
+
import { Hero } from "./hero.js";
|
|
12
|
+
import { FeatureGrid } from "./feature-grid.js";
|
|
13
|
+
import { LogoStrip } from "./logo-strip.js";
|
|
14
|
+
import { StatsBand } from "./stats-band.js";
|
|
15
|
+
import { PageIntro, breadcrumbJsonLd } from "./page-intro.js";
|
|
16
|
+
import { RichTextSection } from "./rich-text-section.js";
|
|
17
|
+
import { MediaText } from "./media-text.js";
|
|
18
|
+
import { Cta } from "./cta.js";
|
|
19
|
+
import { Faq, faqJsonLd } from "./faq.js";
|
|
20
|
+
import { Steps } from "./process.js";
|
|
21
|
+
// Components take richer plain props (ReactNode, unions) than the JSON schema; the schema shape
|
|
22
|
+
// is a subset of each component's props, checked by registry-1.test.tsx through the renderer.
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
24
|
+
const asBlock = (c) => c;
|
|
25
|
+
/** A localized, sanitised href (relative, #, ?, http(s), mailto, tel, sms). */
|
|
26
|
+
const href = (label = "Link") => localizedSchema(z
|
|
27
|
+
.string()
|
|
28
|
+
.min(1)
|
|
29
|
+
.refine((h) => sanitizeHref(h) !== null, { message: "Unsafe or unsupported link (javascript:, data: and unknown schemes are rejected)." })).meta({
|
|
30
|
+
title: label,
|
|
31
|
+
vamos: { field: "text", localized: true, widget: "link", label },
|
|
32
|
+
});
|
|
33
|
+
const metaList = (max, opts = {}) => f.list(f.group({ label: f.text({ max: 24, label: "Label" }), value: f.text({ max: 80, label: "Value" }) }), { max, itemLabel: "label", label: "Facts", ...opts });
|
|
34
|
+
const header = {
|
|
35
|
+
eyebrow: f.text({ max: 40, label: "Eyebrow" }).optional(),
|
|
36
|
+
title: f.heading({ max: 90, label: "Title" }).optional(),
|
|
37
|
+
lead: f.text({ max: 240, multiline: true, label: "Lead" }).optional(),
|
|
38
|
+
};
|
|
39
|
+
const RICH_BODY = { nodes: ["paragraph", "heading", "list", "blockquote", "hr"], marks: ["bold", "italic", "link"] };
|
|
40
|
+
// Unsplash photos used by the examples (real venues, no stock "laptop smile").
|
|
41
|
+
const IMG = {
|
|
42
|
+
dining: { src: "https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?w=2000&q=70&auto=format&fit=crop", width: 2000, height: 1333 },
|
|
43
|
+
table: { src: "https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=2000&q=70&auto=format&fit=crop", width: 2000, height: 1333 },
|
|
44
|
+
spa: { src: "https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=1400&q=70&auto=format&fit=crop", width: 1400, height: 1750 },
|
|
45
|
+
spaStones: { src: "https://images.unsplash.com/photo-1540555700478-4be289fbecef?w=1600&q=70&auto=format&fit=crop", width: 1600, height: 1067 },
|
|
46
|
+
office: { src: "https://images.unsplash.com/photo-1497366216548-37526070297c?w=2400&q=70&auto=format&fit=crop", width: 2400, height: 1600 },
|
|
47
|
+
team: { src: "https://images.unsplash.com/photo-1522071820081-009f0129c71c?w=1600&q=70&auto=format&fit=crop", width: 1600, height: 1067 },
|
|
48
|
+
dashboard: { src: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=2400&q=70&auto=format&fit=crop", width: 2400, height: 1600 },
|
|
49
|
+
};
|
|
50
|
+
const book = { link: { href: "/reservations", label: "Book a table" }, style: "primary" };
|
|
51
|
+
/* ---------------------------------------------------------------- Announcement */
|
|
52
|
+
const announcementSchema = z.object({
|
|
53
|
+
text: f.text({ max: 120, label: "Text" }),
|
|
54
|
+
link: f.link({ label: "Link" }).optional(),
|
|
55
|
+
tone: f.select(["neutral", "accent", "warning"], { label: "Tone" }).optional(),
|
|
56
|
+
dismissible: f.toggle({ label: "Can be dismissed" }).optional(),
|
|
57
|
+
label: f.text({ max: 16, label: "Label", variants: ["centered"] }).optional(),
|
|
58
|
+
from: z.iso.datetime({ offset: true }).optional(),
|
|
59
|
+
until: z.iso.datetime({ offset: true }).optional(),
|
|
60
|
+
});
|
|
61
|
+
export const announcementBlock = defineBlock({
|
|
62
|
+
type: "announcement",
|
|
63
|
+
version: 1,
|
|
64
|
+
title: "Announcement bar",
|
|
65
|
+
description: "One-line, time-boxed notice above the navbar.",
|
|
66
|
+
category: "site",
|
|
67
|
+
region: "header",
|
|
68
|
+
icon: "megaphone",
|
|
69
|
+
keywords: ["banner", "notice", "top bar", "holiday"],
|
|
70
|
+
variants: ["inline", "centered"],
|
|
71
|
+
defaultVariant: "inline",
|
|
72
|
+
variantMeta: {
|
|
73
|
+
inline: { label: "Inline", description: "36px strip, text at the start, underlined link with an arrow right after it, dismiss at the end." },
|
|
74
|
+
centered: { label: "Centred", description: "Same strip, a mono “Notice” label before the centred text and link." },
|
|
75
|
+
},
|
|
76
|
+
supports: { theme: false, spacing: false },
|
|
77
|
+
schema: announcementSchema,
|
|
78
|
+
preview: { props: { text: "Closed 1–3 April for Eid — open again Thursday from noon.", link: { href: "/hours", label: "Holiday hours" }, tone: "neutral" } },
|
|
79
|
+
examples: (variant) => variant === "centered"
|
|
80
|
+
? { text: "v2.4 is out: shared inboxes and WhatsApp templates.", link: { href: "/changelog/2-4", label: "What’s new" }, tone: "accent", dismissible: true, label: "Release" }
|
|
81
|
+
: { text: "Closed 1–3 April for Eid — open again Thursday from noon.", link: { href: "/hours", label: "Holiday hours" }, tone: "neutral" },
|
|
82
|
+
component: asBlock(AnnouncementBar),
|
|
83
|
+
});
|
|
84
|
+
/* ---------------------------------------------------------------- Navbar */
|
|
85
|
+
const navLink = { label: f.text({ max: 40, label: "Label" }), href: href(), description: f.text({ max: 80, label: "Description" }).optional() };
|
|
86
|
+
const navbarSchema = z.object({
|
|
87
|
+
logo: f.image({ label: "Logo" }).optional(),
|
|
88
|
+
logoDark: f.image({ label: "Logo on dark" }).optional(),
|
|
89
|
+
wordmark: f.text({ max: 30, label: "Wordmark" }).optional(),
|
|
90
|
+
homeHref: href("Home link").optional(),
|
|
91
|
+
items: f.list(f.group({ ...navLink, children: f.list(f.group(navLink), { max: 8, itemLabel: "label", label: "Submenu" }).optional() }), { max: 7, itemLabel: "label", label: "Links" }),
|
|
92
|
+
actions: f.list(f.cta(), { max: 2, label: "Actions" }).optional(),
|
|
93
|
+
phone: f.phone({ label: "Phone" }).optional(),
|
|
94
|
+
locales: f.list(f.group({ code: f.text({ max: 8, localized: false, label: "Code" }), href: href() }), { max: 6, label: "Languages" }).optional(),
|
|
95
|
+
sticky: f.toggle({ label: "Sticky" }).optional(),
|
|
96
|
+
overlay: f.toggle({ label: "Transparent over the hero" }).optional(),
|
|
97
|
+
panelMeta: metaList(3).optional(),
|
|
98
|
+
});
|
|
99
|
+
export const navbarBlock = defineBlock({
|
|
100
|
+
type: "navbar",
|
|
101
|
+
version: 1,
|
|
102
|
+
title: "Navbar",
|
|
103
|
+
description: "Site top navigation: links, phone, language switch and one call to action.",
|
|
104
|
+
category: "site",
|
|
105
|
+
region: "header",
|
|
106
|
+
icon: "panel-top",
|
|
107
|
+
keywords: ["menu", "header", "navigation"],
|
|
108
|
+
variants: ["bar", "split", "minimal", "rail"],
|
|
109
|
+
defaultVariant: "bar",
|
|
110
|
+
variantMeta: {
|
|
111
|
+
bar: { label: "Bar", description: "Logo at the start, small links beside it, a mono phone number and one CTA at the end; hairline below." },
|
|
112
|
+
split: { label: "Split", description: "Logo dead centre, links split to both sides, the CTA as a text link at the far end (restaurant, spa)." },
|
|
113
|
+
minimal: { label: "Minimal", description: "Wordmark + “Menu” + CTA; a full-screen menu with display-size serif links and address/hours at the bottom." },
|
|
114
|
+
rail: { label: "Rail", description: "Links in one framed pill in the middle (glassy in glass mode), “Sign in” ghost + “Try free” primary at the end (SaaS)." },
|
|
115
|
+
},
|
|
116
|
+
supports: { spacing: false },
|
|
117
|
+
schema: navbarSchema,
|
|
118
|
+
preview: {
|
|
119
|
+
props: {
|
|
120
|
+
wordmark: "Kıyı",
|
|
121
|
+
items: [
|
|
122
|
+
{ label: "Menu", href: "/menu" },
|
|
123
|
+
{ label: "Private dining", href: "/private-dining" },
|
|
124
|
+
{ label: "Wine", href: "/wine" },
|
|
125
|
+
{ label: "Visit", href: "/visit" },
|
|
126
|
+
],
|
|
127
|
+
phone: "+902160000000",
|
|
128
|
+
actions: [book],
|
|
129
|
+
sticky: true,
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
examples: (variant) => {
|
|
133
|
+
if (variant === "rail")
|
|
134
|
+
return {
|
|
135
|
+
wordmark: "Ledgerly",
|
|
136
|
+
items: [
|
|
137
|
+
{ label: "Product", href: "/product" },
|
|
138
|
+
{ label: "Pricing", href: "/pricing" },
|
|
139
|
+
{ label: "Customers", href: "/customers" },
|
|
140
|
+
{ label: "Changelog", href: "/changelog" },
|
|
141
|
+
],
|
|
142
|
+
actions: [
|
|
143
|
+
{ link: { href: "/login", label: "Sign in" }, style: "secondary" },
|
|
144
|
+
{ link: { href: "/signup", label: "Try free" }, style: "primary" },
|
|
145
|
+
],
|
|
146
|
+
sticky: true,
|
|
147
|
+
};
|
|
148
|
+
if (variant === "split")
|
|
149
|
+
return {
|
|
150
|
+
wordmark: "Hamam Moda",
|
|
151
|
+
items: [
|
|
152
|
+
{ label: "Treatments", href: "/treatments" },
|
|
153
|
+
{ label: "Rituals", href: "/rituals" },
|
|
154
|
+
{ label: "Gift cards", href: "/gift-cards" },
|
|
155
|
+
{ label: "Visit", href: "/visit" },
|
|
156
|
+
],
|
|
157
|
+
actions: [{ link: { href: "/book", label: "Book a treatment" }, style: "link" }],
|
|
158
|
+
};
|
|
159
|
+
if (variant === "minimal")
|
|
160
|
+
return {
|
|
161
|
+
wordmark: "Studio Arda",
|
|
162
|
+
items: [
|
|
163
|
+
{ label: "Work", href: "/work" },
|
|
164
|
+
{ label: "Services", href: "/services" },
|
|
165
|
+
{ label: "About", href: "/about" },
|
|
166
|
+
{ label: "Journal", href: "/journal" },
|
|
167
|
+
{ label: "Contact", href: "/contact" },
|
|
168
|
+
],
|
|
169
|
+
actions: [{ link: { href: "/contact", label: "Start a project" }, style: "primary" }],
|
|
170
|
+
panelMeta: [
|
|
171
|
+
{ label: "Studio", value: "Rıhtım Caddesi 14, Cevizli, Istanbul" },
|
|
172
|
+
{ label: "Hours", value: "Mon–Fri, 9:30–18:30" },
|
|
173
|
+
],
|
|
174
|
+
};
|
|
175
|
+
return {
|
|
176
|
+
wordmark: "Kıyı",
|
|
177
|
+
items: [
|
|
178
|
+
{ label: "Menu", href: "/menu" },
|
|
179
|
+
{ label: "Private dining", href: "/private-dining" },
|
|
180
|
+
{ label: "Wine", href: "/wine" },
|
|
181
|
+
{ label: "Visit", href: "/visit" },
|
|
182
|
+
],
|
|
183
|
+
phone: "+902160000000",
|
|
184
|
+
actions: [book],
|
|
185
|
+
sticky: true,
|
|
186
|
+
};
|
|
187
|
+
},
|
|
188
|
+
component: asBlock(Navbar),
|
|
189
|
+
});
|
|
190
|
+
/* ---------------------------------------------------------------- Hero */
|
|
191
|
+
const heroSchema = z.object({
|
|
192
|
+
eyebrow: f.text({ max: 40, label: "Eyebrow" }).optional(),
|
|
193
|
+
title: f.heading({ max: 90, label: "Title" }),
|
|
194
|
+
lead: f.text({ max: 240, multiline: true, label: "Lead" }).optional(),
|
|
195
|
+
actions: f.list(f.cta(), { max: 2, label: "Actions" }).optional(),
|
|
196
|
+
media: f.image({ label: "Image", variants: ["editorial", "split-media", "full-bleed"] }).optional(),
|
|
197
|
+
video: z
|
|
198
|
+
.object({ src: z.string().regex(/^(https:\/\/|\/)[^\s]+\.mp4(\?[^\s]*)?$/i, { message: "Use an MP4 URL." }) })
|
|
199
|
+
.meta({ title: "Background video", vamos: { field: "group", label: "Background video", variants: ["full-bleed"] } })
|
|
200
|
+
.optional(),
|
|
201
|
+
caption: f.text({ max: 80, label: "Photo caption", variants: ["split-media"] }).optional(),
|
|
202
|
+
meta: metaList(4, { variants: ["editorial", "split-media", "product"] }).optional(),
|
|
203
|
+
screenshot: f.image({ label: "Screenshot", variants: ["product"] }).optional(),
|
|
204
|
+
release: f
|
|
205
|
+
.group({ label: f.text({ max: 60, label: "Label" }), href: href(), tag: f.text({ max: 12, localized: false, label: "Tag" }).optional() }, { label: "Release chip", variants: ["product"] })
|
|
206
|
+
.optional(),
|
|
207
|
+
services: f.list(f.group({ label: f.text({ max: 40, label: "Label" }), href: href() }), { max: 8, itemLabel: "label", label: "Services", variants: ["statement"] }).optional(),
|
|
208
|
+
aside: f
|
|
209
|
+
.group({ title: f.text({ max: 40, label: "Title" }), body: f.text({ max: 120, label: "Text" }).optional(), cta: f.cta().optional() }, { label: "Corner card", variants: ["full-bleed"] })
|
|
210
|
+
.optional(),
|
|
211
|
+
height: f.select(["auto", "screen"], { label: "Height", variants: ["full-bleed"] }).optional(),
|
|
212
|
+
});
|
|
213
|
+
export const heroBlock = defineBlock({
|
|
214
|
+
type: "hero",
|
|
215
|
+
version: 1,
|
|
216
|
+
title: "Hero",
|
|
217
|
+
description: "The first screen and the page h1, in five characters.",
|
|
218
|
+
category: "intro",
|
|
219
|
+
icon: "panel-top",
|
|
220
|
+
keywords: ["header", "intro", "banner", "above the fold"],
|
|
221
|
+
variants: ["editorial", "split-media", "full-bleed", "product", "statement"],
|
|
222
|
+
defaultVariant: "editorial",
|
|
223
|
+
variantMeta: {
|
|
224
|
+
editorial: {
|
|
225
|
+
label: "Editorial",
|
|
226
|
+
description: "Huge start-aligned serif title with one italic word, a narrow lead and a text-link CTA, mono facts at the end, a 21:9 photo strip bleeding edge to edge.",
|
|
227
|
+
},
|
|
228
|
+
"split-media": { label: "Split media", description: "Asymmetric 7/5: text and two buttons on the start side, a 4:5 portrait bleeding off the end edge with a mono caption in its corner." },
|
|
229
|
+
"full-bleed": { label: "Full bleed", description: "Full-screen photo or muted video under a bottom-up scrim; title bottom-start, a small hours + booking card bottom-end. Always dark." },
|
|
230
|
+
product: { label: "Product", description: "Release chip, title, lead, “Try free / Watch demo”; a real screenshot without device frame, cropped by the section’s bottom edge." },
|
|
231
|
+
statement: { label: "Statement", description: "No image: one centred sentence at display-2xl, services underneath as slash-separated links." },
|
|
232
|
+
},
|
|
233
|
+
supports: { pageTitle: true },
|
|
234
|
+
schema: heroSchema,
|
|
235
|
+
preview: {
|
|
236
|
+
variant: "editorial",
|
|
237
|
+
props: {
|
|
238
|
+
eyebrow: "Studio Arda · Maltepe, Istanbul",
|
|
239
|
+
title: "Websites for places people *actually* visit.",
|
|
240
|
+
lead: "We design and run sites for restaurants, clinics and hotels on the Asian side — menus your staff can edit and booking that lands on WhatsApp.",
|
|
241
|
+
actions: [{ link: { href: "/work", label: "See the work" }, style: "link" }],
|
|
242
|
+
meta: [
|
|
243
|
+
{ label: "Founded", value: "2014" },
|
|
244
|
+
{ label: "Sites live", value: "126" },
|
|
245
|
+
],
|
|
246
|
+
media: { ...IMG.office, alt: "The studio’s long table by the window, late afternoon", focal: { x: 0.5, y: 0.6 } },
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
examples: (variant) => {
|
|
250
|
+
switch (variant) {
|
|
251
|
+
case "split-media":
|
|
252
|
+
return {
|
|
253
|
+
eyebrow: "Day spa · Moda",
|
|
254
|
+
title: "Two hours, *nowhere* to be.",
|
|
255
|
+
lead: "A marble hammam, a quiet pool and therapists who have been with us for a decade. Open daily from 10 am; last treatment at 8.",
|
|
256
|
+
actions: [
|
|
257
|
+
{ link: { href: "/book", label: "Book a treatment" }, style: "primary" },
|
|
258
|
+
{ link: { href: "/treatments", label: "Treatments & prices" }, style: "secondary" },
|
|
259
|
+
],
|
|
260
|
+
media: { ...IMG.spa, alt: "A therapist preparing warm stones beside a massage table", focal: { x: 0.5, y: 0.4 } },
|
|
261
|
+
caption: "Treatment room 3, 2nd floor",
|
|
262
|
+
};
|
|
263
|
+
case "full-bleed":
|
|
264
|
+
return {
|
|
265
|
+
eyebrow: "Meyhane · Cevizli",
|
|
266
|
+
title: "Dinner, *slowly*.",
|
|
267
|
+
lead: "Twenty-two cold meze and fish from the morning boats.",
|
|
268
|
+
media: { ...IMG.dining, alt: "The dining room at dusk, candles on oak tables" },
|
|
269
|
+
aside: { title: "Open today", body: "18:00 – 00:30 · kitchen until 23:00", cta: book },
|
|
270
|
+
height: "auto",
|
|
271
|
+
};
|
|
272
|
+
case "product":
|
|
273
|
+
return {
|
|
274
|
+
release: { tag: "v2.4", label: "November — shared inboxes", href: "/changelog/2-4" },
|
|
275
|
+
title: "Every booking request in *one* inbox.",
|
|
276
|
+
lead: "WhatsApp, Instagram and your website form, answered by the whole front desk. Set up in an afternoon.",
|
|
277
|
+
actions: [
|
|
278
|
+
{ link: { href: "/signup", label: "Try free for 14 days" }, style: "primary" },
|
|
279
|
+
{ link: { href: "/demo", label: "Watch a 3-min demo" }, style: "secondary" },
|
|
280
|
+
],
|
|
281
|
+
screenshot: { ...IMG.dashboard, alt: "The inbox: conversations on the left, a booking thread open on the right" },
|
|
282
|
+
};
|
|
283
|
+
case "statement":
|
|
284
|
+
return {
|
|
285
|
+
title: "We build sites that *open* the door, not just the browser tab.",
|
|
286
|
+
services: [
|
|
287
|
+
{ label: "Restaurant sites", href: "/services/restaurants" },
|
|
288
|
+
{ label: "Clinic & spa sites", href: "/services/clinics" },
|
|
289
|
+
{ label: "Ad management", href: "/services/ads" },
|
|
290
|
+
{ label: "Local SEO", href: "/services/local-seo" },
|
|
291
|
+
],
|
|
292
|
+
};
|
|
293
|
+
default:
|
|
294
|
+
return {
|
|
295
|
+
eyebrow: "Studio Arda · Maltepe, Istanbul",
|
|
296
|
+
title: "Websites for places people *actually* visit.",
|
|
297
|
+
lead: "We design and run sites for restaurants, clinics and hotels on the Asian side — menus your staff can edit and booking that lands on WhatsApp.",
|
|
298
|
+
actions: [{ link: { href: "/work", label: "See the work" }, style: "link" }],
|
|
299
|
+
meta: [
|
|
300
|
+
{ label: "Founded", value: "2014" },
|
|
301
|
+
{ label: "Sites live", value: "126" },
|
|
302
|
+
],
|
|
303
|
+
media: { ...IMG.office, alt: "The studio’s long table by the window, late afternoon", focal: { x: 0.5, y: 0.6 } },
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
lint: (props, node) => {
|
|
308
|
+
const v = node.variant ?? "editorial";
|
|
309
|
+
const out = [];
|
|
310
|
+
if ((v === "split-media" || v === "full-bleed") && !props.media)
|
|
311
|
+
out.push({ code: "hero-missing-media", severity: "warning", message: `The ${v} hero needs a photo.`, path: "props.media" });
|
|
312
|
+
if (v === "product" && !props.screenshot)
|
|
313
|
+
out.push({ code: "hero-missing-media", severity: "warning", message: "The product hero needs a real screenshot.", path: "props.screenshot" });
|
|
314
|
+
if (v === "full-bleed" && props.video && !props.media)
|
|
315
|
+
out.push({ code: "hero-missing-poster", severity: "error", message: "A background video needs a poster image (media).", path: "props.media" });
|
|
316
|
+
return out;
|
|
317
|
+
},
|
|
318
|
+
component: asBlock(Hero),
|
|
319
|
+
});
|
|
320
|
+
/* ---------------------------------------------------------------- Feature grid */
|
|
321
|
+
export const featuresBlock = defineBlock({
|
|
322
|
+
type: "features",
|
|
323
|
+
version: 1,
|
|
324
|
+
title: "Feature grid",
|
|
325
|
+
description: "Services, treatments or product modules — without the card wall.",
|
|
326
|
+
category: "content",
|
|
327
|
+
icon: "layout-grid",
|
|
328
|
+
keywords: ["services", "features", "benefits", "modules"],
|
|
329
|
+
variants: ["list", "grid", "tabs", "sticky-media"],
|
|
330
|
+
defaultVariant: "list",
|
|
331
|
+
variantMeta: {
|
|
332
|
+
list: { label: "List", description: "Two columns of rows; a hairline on top of each, a mono 01 at the start, title and description. No cards, no icons." },
|
|
333
|
+
grid: { label: "Grid", description: "3–4 columns; each item a 1px top rule and 16px of space above the title, an optional small icon before it." },
|
|
334
|
+
tabs: { label: "Tabs", description: "Feature titles stacked on the start side (active one marked by a vertical accent rule), its large image on the end side." },
|
|
335
|
+
"sticky-media": { label: "Sticky media", description: "A sticky image on the start side swaps as the long list on the end side scrolls (CSS view timelines)." },
|
|
336
|
+
},
|
|
337
|
+
schema: z.object({
|
|
338
|
+
...header,
|
|
339
|
+
items: f.list(f.group({
|
|
340
|
+
title: f.text({ max: 60, label: "Title" }),
|
|
341
|
+
text: f.text({ max: 220, multiline: true, label: "Text" }).optional(),
|
|
342
|
+
icon: f.icon({ label: "Icon", variants: ["grid"] }).optional(),
|
|
343
|
+
media: f.image({ label: "Image", variants: ["grid", "tabs", "sticky-media"] }).optional(),
|
|
344
|
+
link: f.group({ href: href(), label: f.text({ max: 40, label: "Label" }).optional() }, { label: "Link" }).optional(),
|
|
345
|
+
}), { min: 2, max: 12, itemLabel: "title", label: "Items" }),
|
|
346
|
+
numbered: f.toggle({ label: "Numbered" }).optional(),
|
|
347
|
+
columns: z
|
|
348
|
+
.union([z.literal(2), z.literal(3), z.literal(4)])
|
|
349
|
+
.meta({ title: "Columns", vamos: { field: "select", label: "Columns", variants: ["grid"] } })
|
|
350
|
+
.optional(),
|
|
351
|
+
}),
|
|
352
|
+
preview: {
|
|
353
|
+
props: {
|
|
354
|
+
eyebrow: "Services",
|
|
355
|
+
title: "What we *build*",
|
|
356
|
+
lead: "Four things, done properly. Everything else we hand to people who do it better.",
|
|
357
|
+
items: [
|
|
358
|
+
{ title: "Restaurant & venue sites", text: "Menus your floor staff edit from a phone, allergens that stay in sync, booking that lands in WhatsApp." },
|
|
359
|
+
{ title: "Clinic & spa sites", text: "Treatment pages that rank for the district, prices with tax notes, and appointment requests without a call centre." },
|
|
360
|
+
{ title: "Ad management", text: "Google and Meta campaigns measured against real bookings, not clicks. Monthly report in plain language." },
|
|
361
|
+
{ title: "Local SEO", text: "Business Profile upkeep, review replies and a weekly grid of where you rank across the neighbourhood." },
|
|
362
|
+
],
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
component: asBlock(FeatureGrid),
|
|
366
|
+
});
|
|
367
|
+
/* ---------------------------------------------------------------- Logo strip */
|
|
368
|
+
export const logoStripBlock = defineBlock({
|
|
369
|
+
type: "logo-strip",
|
|
370
|
+
version: 1,
|
|
371
|
+
title: "Logo strip",
|
|
372
|
+
description: "“Brands we work with” proof.",
|
|
373
|
+
category: "proof",
|
|
374
|
+
icon: "award",
|
|
375
|
+
keywords: ["clients", "logos", "customers", "trusted by"],
|
|
376
|
+
variants: ["row", "marquee", "grid"],
|
|
377
|
+
defaultVariant: "row",
|
|
378
|
+
variantMeta: {
|
|
379
|
+
row: { label: "Row", description: "A small caption at the start, logos on one line at an equal optical height (28px), greyscale." },
|
|
380
|
+
marquee: { label: "Marquee", description: "A full-width endless band with faded edges; pauses on hover and focus; static under reduced motion." },
|
|
381
|
+
grid: { label: "Grid", description: "4–6 columns separated by 1px gridlines like a table, logos centred in cells." },
|
|
382
|
+
},
|
|
383
|
+
schema: z.object({
|
|
384
|
+
caption: f.text({ max: 80, label: "Caption" }).optional(),
|
|
385
|
+
logos: f.list(f.group({
|
|
386
|
+
name: f.text({ max: 40, localized: false, label: "Brand" }),
|
|
387
|
+
image: f.image({ label: "Logo" }),
|
|
388
|
+
imageDark: f.image({ label: "Logo on dark" }).optional(),
|
|
389
|
+
link: f.group({ href: href(), newTab: f.toggle().optional() }).optional(),
|
|
390
|
+
}), { min: 4, max: 24, itemLabel: "name", label: "Logos" }),
|
|
391
|
+
monochrome: f.toggle({ label: "Monochrome" }).optional(),
|
|
392
|
+
columns: z
|
|
393
|
+
.union([z.literal(4), z.literal(5), z.literal(6)])
|
|
394
|
+
.meta({ title: "Columns", vamos: { field: "select", label: "Columns", variants: ["grid"] } })
|
|
395
|
+
.optional(),
|
|
396
|
+
speed: f.number({ min: 15, max: 120, label: "Seconds per loop", variants: ["marquee"] }).optional(),
|
|
397
|
+
}),
|
|
398
|
+
preview: {
|
|
399
|
+
props: {
|
|
400
|
+
caption: "Running the sites of 120+ businesses since 2014",
|
|
401
|
+
logos: ["Kıyı", "Hamam Moda", "Ledgerly", "Defne Clinic"].map((name) => ({
|
|
402
|
+
name,
|
|
403
|
+
image: { src: `https://ui.vamos.ist/logos/${name.toLowerCase().replace(/[^a-z]+/g, "-")}.svg`, width: 160, height: 40, alt: name },
|
|
404
|
+
})),
|
|
405
|
+
},
|
|
406
|
+
},
|
|
407
|
+
lint: (props, node) => node.variant === "marquee" && props.logos.length < 6
|
|
408
|
+
? [{ code: "marquee-too-few", severity: "info", message: "A marquee with fewer than 6 logos repeats visibly — use the row variant.", path: "props.logos" }]
|
|
409
|
+
: [],
|
|
410
|
+
component: asBlock(LogoStrip),
|
|
411
|
+
});
|
|
412
|
+
/* ---------------------------------------------------------------- Stats band */
|
|
413
|
+
export const statsBlock = defineBlock({
|
|
414
|
+
type: "stats",
|
|
415
|
+
version: 1,
|
|
416
|
+
title: "Stats band",
|
|
417
|
+
description: "Concrete, sourced numbers.",
|
|
418
|
+
category: "proof",
|
|
419
|
+
icon: "chart-bar",
|
|
420
|
+
keywords: ["numbers", "figures", "metrics", "results"],
|
|
421
|
+
variants: ["inline", "with-text", "ledger"],
|
|
422
|
+
defaultVariant: "inline",
|
|
423
|
+
variantMeta: {
|
|
424
|
+
inline: { label: "Inline", description: "3–4 figures on one line between vertical rules; the figure at display-l, unit as a small superscript, label below." },
|
|
425
|
+
"with-text": { label: "With text", description: "A paragraph on the start side, a 2×2 grid of figures on the end side." },
|
|
426
|
+
ledger: { label: "Ledger", description: "Each figure a row — label, dotted leader, figure — like an annual report, with a mono source line." },
|
|
427
|
+
},
|
|
428
|
+
schema: z.object({
|
|
429
|
+
...header,
|
|
430
|
+
body: f.rich({ nodes: ["paragraph", "list"], marks: ["bold", "italic", "link"], label: "Text", variants: ["with-text"] }).optional(),
|
|
431
|
+
items: f.list(f.group({
|
|
432
|
+
value: z.union([z.number(), z.string().max(12)]).meta({ title: "Figure", vamos: { field: "text", label: "Figure" } }),
|
|
433
|
+
unit: f.text({ max: 8, localized: false, label: "Unit" }).optional(),
|
|
434
|
+
unitLabel: f.text({ max: 24, label: "Unit (spoken)" }).optional(),
|
|
435
|
+
label: f.text({ max: 60, label: "Label" }),
|
|
436
|
+
source: f.text({ max: 80, label: "Source" }).optional(),
|
|
437
|
+
}), { min: 2, max: 5, itemLabel: "label", label: "Figures" }),
|
|
438
|
+
}),
|
|
439
|
+
preview: {
|
|
440
|
+
props: {
|
|
441
|
+
items: [
|
|
442
|
+
{ value: 4.8, label: "Google rating", source: "1,240 reviews · Google Business Profile, Nov 2026" },
|
|
443
|
+
{ value: 340, label: "Sites launched in 12 years", source: "Studio records, 2014–2026" },
|
|
444
|
+
{ value: 38, unit: "%", label: "Of bookings now arrive on WhatsApp", source: "Client median, Q3 2026" },
|
|
445
|
+
{ value: "11 min", label: "Median first reply to a booking request", source: "Inbox data, Oct 2026" },
|
|
446
|
+
],
|
|
447
|
+
},
|
|
448
|
+
},
|
|
449
|
+
lint: (props) => props.items.flatMap((it, i) => {
|
|
450
|
+
const out = [];
|
|
451
|
+
if (!it.source)
|
|
452
|
+
out.push({ code: "stat-missing-source", severity: "warning", message: "Add a source to this figure (D6-8): unsourced numbers read as marketing.", path: `props.items.${i}.source` });
|
|
453
|
+
if (typeof it.value === "number" && it.value >= 100 && it.value % 100 === 0 && it.unit === "+")
|
|
454
|
+
out.push({ code: "stat-round-number", severity: "info", message: "Round “500+” figures look invented — use the exact count.", path: `props.items.${i}.value` });
|
|
455
|
+
return out;
|
|
456
|
+
}),
|
|
457
|
+
component: asBlock(StatsBand),
|
|
458
|
+
});
|
|
459
|
+
/* ---------------------------------------------------------------- Page intro */
|
|
460
|
+
export const pageIntroBlock = defineBlock({
|
|
461
|
+
type: "page-intro",
|
|
462
|
+
version: 1,
|
|
463
|
+
title: "Page intro",
|
|
464
|
+
description: "The h1 and breadcrumb of an inner page.",
|
|
465
|
+
category: "intro",
|
|
466
|
+
icon: "heading",
|
|
467
|
+
keywords: ["page header", "title", "breadcrumb"],
|
|
468
|
+
variants: ["simple", "with-media", "ruled"],
|
|
469
|
+
defaultVariant: "simple",
|
|
470
|
+
variantMeta: {
|
|
471
|
+
simple: { label: "Simple", description: "A small breadcrumb, the title at display-l, the lead beside it on wide containers." },
|
|
472
|
+
"with-media": { label: "With media", description: "Title + lead, then a 21:9 image bleeding past the container." },
|
|
473
|
+
ruled: { label: "Ruled", description: "Title at the start, 2–3 facts behind a vertical rule at the end, a full-width hairline below." },
|
|
474
|
+
},
|
|
475
|
+
supports: { pageTitle: true },
|
|
476
|
+
schema: z.object({
|
|
477
|
+
breadcrumb: f.list(f.group({ label: f.text({ max: 40, label: "Label" }), href: href().optional() }), { max: 6, itemLabel: "label", label: "Breadcrumb" }).optional(),
|
|
478
|
+
eyebrow: f.text({ max: 40, label: "Eyebrow" }).optional(),
|
|
479
|
+
title: f.heading({ max: 70, label: "Title" }),
|
|
480
|
+
lead: f.text({ max: 200, multiline: true, label: "Lead" }).optional(),
|
|
481
|
+
media: f.image({ aspect: "21:9", label: "Image", variants: ["with-media"] }).optional(),
|
|
482
|
+
meta: metaList(3, { variants: ["ruled"] }).optional(),
|
|
483
|
+
}),
|
|
484
|
+
preview: {
|
|
485
|
+
props: {
|
|
486
|
+
breadcrumb: [{ label: "Home", href: "/" }, { label: "Treatments" }],
|
|
487
|
+
title: "Treatments, *by the hour*",
|
|
488
|
+
lead: "Every treatment starts with twenty minutes in the hammam. Prices include VAT and a pot of linden tea afterwards.",
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
jsonLd: (props) => (props.breadcrumb?.length ? breadcrumbJsonLd(props.breadcrumb.map((c) => ({ label: c.label, href: c.href }))) : null),
|
|
492
|
+
component: asBlock(PageIntro),
|
|
493
|
+
});
|
|
494
|
+
/* ---------------------------------------------------------------- Rich text */
|
|
495
|
+
export const richTextBlock = defineBlock({
|
|
496
|
+
type: "rich-text",
|
|
497
|
+
version: 1,
|
|
498
|
+
title: "Rich text section",
|
|
499
|
+
description: "Long text: about, privacy notice, service description.",
|
|
500
|
+
category: "text",
|
|
501
|
+
icon: "file-text",
|
|
502
|
+
keywords: ["text", "article", "legal", "privacy", "about"],
|
|
503
|
+
variants: ["column", "aside-heading", "two-column"],
|
|
504
|
+
defaultVariant: "column",
|
|
505
|
+
variantMeta: {
|
|
506
|
+
column: { label: "Column", description: "A 42rem column on grid columns 2–9 (not centred); optional drop cap in editorial." },
|
|
507
|
+
"aside-heading": { label: "Aside heading", description: "A sticky title on the start side (4 cols), the text on the end side (7 cols) — good for legal texts." },
|
|
508
|
+
"two-column": { label: "Two columns", description: "Newspaper columns on wide containers only." },
|
|
509
|
+
},
|
|
510
|
+
schema: z.object({
|
|
511
|
+
eyebrow: f.text({ max: 40, label: "Eyebrow" }).optional(),
|
|
512
|
+
title: f.heading({ max: 90, label: "Title" }).optional(),
|
|
513
|
+
body: f.rich({ ...RICH_BODY, label: "Text" }),
|
|
514
|
+
dropCap: f.toggle({ label: "Drop cap", variants: ["column"] }).optional(),
|
|
515
|
+
note: f.text({ max: 80, label: "Note", variants: ["aside-heading"] }).optional(),
|
|
516
|
+
size: f.select(["sm", "md", "lg"], { label: "Text size" }).optional(),
|
|
517
|
+
}),
|
|
518
|
+
preview: {
|
|
519
|
+
props: {
|
|
520
|
+
title: "How we *started*",
|
|
521
|
+
body: {
|
|
522
|
+
type: "doc",
|
|
523
|
+
content: [
|
|
524
|
+
{
|
|
525
|
+
type: "paragraph",
|
|
526
|
+
content: [{ text: "Kıyı opened in 2011 as a six-table meyhane next to the Cevizli fish market. The menu was whatever the boats brought in, written on a slate by the door." }],
|
|
527
|
+
},
|
|
528
|
+
{
|
|
529
|
+
type: "paragraph",
|
|
530
|
+
content: [
|
|
531
|
+
{ text: "Fifteen years later the slate is still there. So is " },
|
|
532
|
+
{ text: "Hüseyin Usta", marks: [{ type: "bold" }] },
|
|
533
|
+
{ text: ", who has cleaned every sea bass we’ve served." },
|
|
534
|
+
],
|
|
535
|
+
},
|
|
536
|
+
],
|
|
537
|
+
},
|
|
538
|
+
},
|
|
539
|
+
},
|
|
540
|
+
component: asBlock(RichTextSection),
|
|
541
|
+
});
|
|
542
|
+
/* ---------------------------------------------------------------- Media + text */
|
|
543
|
+
export const mediaTextBlock = defineBlock({
|
|
544
|
+
type: "media-text",
|
|
545
|
+
version: 1,
|
|
546
|
+
title: "Media + text",
|
|
547
|
+
description: "An image or video beside text — the most used body section.",
|
|
548
|
+
category: "content",
|
|
549
|
+
icon: "image",
|
|
550
|
+
keywords: ["image and text", "split", "about", "video"],
|
|
551
|
+
variants: ["side", "overlap", "bleed"],
|
|
552
|
+
defaultVariant: "side",
|
|
553
|
+
variantMeta: {
|
|
554
|
+
side: { label: "Side by side", description: "5/7 or 7/5; the text top-aligned with the image, not vertically centred." },
|
|
555
|
+
overlap: { label: "Overlap", description: "The image takes 8 columns; a surface panel with the text overlaps its bottom corner by 2." },
|
|
556
|
+
bleed: { label: "Bleed", description: "The image runs to the section edge, the text stays inside the container." },
|
|
557
|
+
},
|
|
558
|
+
schema: z.object({
|
|
559
|
+
eyebrow: f.text({ max: 40, label: "Eyebrow" }).optional(),
|
|
560
|
+
title: f.heading({ max: 90, label: "Title" }),
|
|
561
|
+
body: f.rich({ nodes: ["paragraph", "list"], marks: ["bold", "italic", "link"], label: "Text" }).optional(),
|
|
562
|
+
bullets: f.list(f.text({ max: 90 }), { max: 6, label: "Points" }).optional(),
|
|
563
|
+
cta: f.cta({ label: "Action" }).optional(),
|
|
564
|
+
media: f.image({ label: "Image" }),
|
|
565
|
+
video: f
|
|
566
|
+
.group({
|
|
567
|
+
provider: f.select(["youtube", "vimeo", "mp4"], { label: "Provider" }),
|
|
568
|
+
url: z.url().meta({ title: "URL", vamos: { field: "text", label: "URL", widget: "url" } }),
|
|
569
|
+
title: f.text({ max: 80, label: "Video title" }).optional(),
|
|
570
|
+
}, { label: "Video" })
|
|
571
|
+
.optional(),
|
|
572
|
+
mediaSide: f.select(["start", "end"], { label: "Image side" }).optional(),
|
|
573
|
+
aspect: f.select(["4:5", "3:2", "1:1"], { label: "Image ratio" }).optional(),
|
|
574
|
+
}),
|
|
575
|
+
preview: {
|
|
576
|
+
props: {
|
|
577
|
+
eyebrow: "The kitchen",
|
|
578
|
+
title: "Fish from the *morning* boats",
|
|
579
|
+
body: richFromText("Hüseyin Usta is at the Cevizli market at six. What he buys decides the menu — there is no printed fish list, only the slate by the door."),
|
|
580
|
+
bullets: ["Sea bass, bonito and red mullet in season", "Meze made the same morning", "Raki list of forty, by the glass"],
|
|
581
|
+
cta: { link: { href: "/menu", label: "Tonight’s menu" }, style: "link" },
|
|
582
|
+
media: { ...IMG.table, alt: "Plates of meze on a white tablecloth" },
|
|
583
|
+
},
|
|
584
|
+
},
|
|
585
|
+
component: asBlock(MediaText),
|
|
586
|
+
});
|
|
587
|
+
/* ---------------------------------------------------------------- CTA */
|
|
588
|
+
const ctaSchema = z.object({
|
|
589
|
+
eyebrow: f.text({ max: 40, label: "Eyebrow" }).optional(),
|
|
590
|
+
title: f.heading({ max: 80, label: "Title" }),
|
|
591
|
+
lead: f.text({ max: 200, multiline: true, label: "Lead" }).optional(),
|
|
592
|
+
actions: f.list(f.cta(), { max: 2, label: "Actions" }).optional(),
|
|
593
|
+
media: f.image({ label: "Image", variants: ["split"] }).optional(),
|
|
594
|
+
contact: f
|
|
595
|
+
.group({ phone: f.phone().optional(), whatsapp: f.phone({ label: "WhatsApp" }).optional(), whatsappText: f.text({ max: 200, label: "WhatsApp message" }).optional() }, { label: "Contact line", variants: ["band", "split", "minimal"] })
|
|
596
|
+
.optional(),
|
|
597
|
+
newsletter: f
|
|
598
|
+
.group({
|
|
599
|
+
action: z
|
|
600
|
+
.string()
|
|
601
|
+
.min(1)
|
|
602
|
+
.refine((h) => sanitizeHref(h) !== null)
|
|
603
|
+
.meta({ title: "Form action URL", vamos: { field: "text", label: "Form action URL", widget: "url" } })
|
|
604
|
+
.optional(),
|
|
605
|
+
placeholder: f.text({ max: 60 }).optional(),
|
|
606
|
+
buttonLabel: f.text({ max: 30 }).optional(),
|
|
607
|
+
consent: f.rich({ nodes: ["paragraph"], marks: ["bold", "italic", "link"], label: "Consent text" }).optional(),
|
|
608
|
+
}, { label: "Newsletter", variants: ["newsletter"] })
|
|
609
|
+
.optional(),
|
|
610
|
+
booking: f
|
|
611
|
+
.group({
|
|
612
|
+
provider: f.select(["whatsapp", "url", "phone", "embed"], { label: "Provider" }),
|
|
613
|
+
whatsapp: f.phone({ label: "WhatsApp" }).optional(),
|
|
614
|
+
phone: f.phone().optional(),
|
|
615
|
+
url: z
|
|
616
|
+
.url()
|
|
617
|
+
.meta({ title: "Booking URL", vamos: { field: "text", label: "Booking URL", widget: "url" } })
|
|
618
|
+
.optional(),
|
|
619
|
+
fields: f.list(f.select(["date", "time", "guests", "service"]), { max: 4, label: "Fields" }).optional(),
|
|
620
|
+
services: f.list(f.text({ max: 40, localized: false }), { max: 12, label: "Services" }).optional(),
|
|
621
|
+
times: f.list(z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/), { max: 48, label: "Times" }).optional(),
|
|
622
|
+
maxGuests: f.number({ min: 1, max: 40, int: true, label: "Largest party" }).optional(),
|
|
623
|
+
closedDays: f.list(f.select(["mon", "tue", "wed", "thu", "fri", "sat", "sun"]), { max: 7, label: "Closed on" }).optional(),
|
|
624
|
+
timeZone: z.string().optional(),
|
|
625
|
+
messageTemplate: f.text({ max: 200, label: "Message template" }).optional(),
|
|
626
|
+
preview: f.image({ label: "Calendar preview" }).optional(),
|
|
627
|
+
}, { label: "Booking", variants: ["booking"] })
|
|
628
|
+
.optional(),
|
|
629
|
+
fineprint: f.text({ max: 160, label: "Small print" }).optional(),
|
|
630
|
+
});
|
|
631
|
+
export const ctaBlock = defineBlock({
|
|
632
|
+
type: "cta",
|
|
633
|
+
version: 1,
|
|
634
|
+
title: "CTA",
|
|
635
|
+
description: "End-of-page call to action, newsletter signup or booking bar.",
|
|
636
|
+
category: "conversion",
|
|
637
|
+
icon: "send",
|
|
638
|
+
keywords: ["call to action", "contact", "newsletter", "booking", "reservation"],
|
|
639
|
+
variants: ["band", "split", "minimal", "newsletter", "booking"],
|
|
640
|
+
defaultVariant: "band",
|
|
641
|
+
variantMeta: {
|
|
642
|
+
band: { label: "Band", description: "A full-width accent band; a big title at the start, actions at the end on the bottom edge, a mono phone + WhatsApp line beneath." },
|
|
643
|
+
split: { label: "Split", description: "Title + action on the start side, a cropped venue or team photo on the end side." },
|
|
644
|
+
minimal: { label: "Minimal", description: "No background change; a very large centred title and one huge underlined text link. No buttons." },
|
|
645
|
+
newsletter: { label: "Newsletter", description: "Title + short text at the start, email field and button side by side at the end, consent text underneath." },
|
|
646
|
+
booking: { label: "Booking bar", description: "A thin bar — date · time · guests or service — separated by hairlines, ending with “Ask for availability”; 2×2 on mobile." },
|
|
647
|
+
},
|
|
648
|
+
schema: ctaSchema,
|
|
649
|
+
preview: {
|
|
650
|
+
props: {
|
|
651
|
+
title: "Book the *long table*",
|
|
652
|
+
lead: "Up to fourteen guests, a set menu of nine plates and the wine pairing Ece picks on the day.",
|
|
653
|
+
actions: [book, { link: { href: "/private-dining", label: "Private dining" }, style: "secondary" }],
|
|
654
|
+
contact: { phone: "+902160000000", whatsapp: "+905321234567" },
|
|
655
|
+
},
|
|
656
|
+
},
|
|
657
|
+
examples: (variant) => {
|
|
658
|
+
switch (variant) {
|
|
659
|
+
case "minimal":
|
|
660
|
+
return { title: "Have a place people should *find*?", actions: [{ link: { href: "/contact", label: "Let’s talk about your project" }, style: "link" }] };
|
|
661
|
+
case "newsletter":
|
|
662
|
+
return {
|
|
663
|
+
title: "The Thursday wine list, by email",
|
|
664
|
+
lead: "Four bottles we opened this week and what to eat with them. One email, Thursdays at noon.",
|
|
665
|
+
newsletter: { action: "/api/newsletter", consent: richFromText("We only send the list. Unsubscribe from any email in one click.") },
|
|
666
|
+
};
|
|
667
|
+
case "booking":
|
|
668
|
+
return { title: "Reserve a table", booking: { provider: "whatsapp", whatsapp: "+905321234567", fields: ["date", "time", "guests"], closedDays: ["mon"], timeZone: "Europe/Istanbul" } };
|
|
669
|
+
case "split":
|
|
670
|
+
return {
|
|
671
|
+
title: "Bring your *team* for lunch",
|
|
672
|
+
lead: "Weekday set lunch for groups of six to twenty, in and out in fifty minutes.",
|
|
673
|
+
actions: [{ link: { href: "/groups", label: "Plan a group lunch" }, style: "primary" }],
|
|
674
|
+
media: { ...IMG.table, alt: "A long table set for lunch" },
|
|
675
|
+
};
|
|
676
|
+
default:
|
|
677
|
+
return {
|
|
678
|
+
title: "Book the *long table*",
|
|
679
|
+
lead: "Up to fourteen guests, a set menu of nine plates and the wine pairing Ece picks on the day.",
|
|
680
|
+
actions: [book, { link: { href: "/private-dining", label: "Private dining" }, style: "secondary" }],
|
|
681
|
+
contact: { phone: "+902160000000", whatsapp: "+905321234567" },
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
},
|
|
685
|
+
component: asBlock(Cta),
|
|
686
|
+
});
|
|
687
|
+
/* ---------------------------------------------------------------- FAQ */
|
|
688
|
+
export const faqBlock = defineBlock({
|
|
689
|
+
type: "faq",
|
|
690
|
+
version: 1,
|
|
691
|
+
title: "FAQ",
|
|
692
|
+
description: "Questions and answers; zero-JS accordion; FAQPage JSON-LD.",
|
|
693
|
+
category: "content",
|
|
694
|
+
icon: "help-circle",
|
|
695
|
+
keywords: ["questions", "faq", "accordion", "help"],
|
|
696
|
+
variants: ["split", "stacked", "columns"],
|
|
697
|
+
defaultVariant: "split",
|
|
698
|
+
variantMeta: {
|
|
699
|
+
split: { label: "Split", description: "A sticky title and a “Can’t find your question?” link on the start side, the accordion on the end side; a thin + turns into −." },
|
|
700
|
+
stacked: { label: "Stacked", description: "Title above, the accordion full width at a 42rem measure." },
|
|
701
|
+
columns: { label: "Columns", description: "No accordion — every question and answer open in two columns (short answers, maximally indexable)." },
|
|
702
|
+
},
|
|
703
|
+
schema: z.object({
|
|
704
|
+
...header,
|
|
705
|
+
items: f.list(f.group({ q: f.text({ max: 140, label: "Question" }), a: f.rich({ nodes: ["paragraph", "list"], marks: ["bold", "italic", "link"], label: "Answer" }) }), {
|
|
706
|
+
min: 1,
|
|
707
|
+
max: 30,
|
|
708
|
+
itemLabel: "q",
|
|
709
|
+
label: "Questions",
|
|
710
|
+
}),
|
|
711
|
+
exclusive: f.toggle({ label: "One open at a time" }).optional(),
|
|
712
|
+
openFirst: f.toggle({ label: "Open the first" }).optional(),
|
|
713
|
+
contact: f.cta({ label: "Contact link" }).optional(),
|
|
714
|
+
}),
|
|
715
|
+
preview: {
|
|
716
|
+
props: {
|
|
717
|
+
title: "Before you *book*",
|
|
718
|
+
items: [
|
|
719
|
+
{ q: "Is there parking?", a: { type: "doc", content: [{ type: "paragraph", content: [{ text: "Yes — the Piazza garage, level −2. Show your receipt for three hours free." }] }] } },
|
|
720
|
+
{ q: "Can I cancel a booking?", a: { type: "doc", content: [{ type: "paragraph", content: [{ text: "Free until 24 hours before. After that we keep the ₺500 deposit per person." }] }] } },
|
|
721
|
+
{ q: "Do you cater for allergies?", a: { type: "doc", content: [{ type: "paragraph", content: [{ text: "Tell us when you book. Every dish on the menu lists its 14 allergens." }] }] } },
|
|
722
|
+
],
|
|
723
|
+
contact: { link: { href: "https://wa.me/905321234567", label: "Message us on WhatsApp", newTab: true }, style: "link" },
|
|
724
|
+
},
|
|
725
|
+
},
|
|
726
|
+
jsonLd: (props) => faqJsonLd(props.items.map((it) => ({ q: it.q, a: it.a }))),
|
|
727
|
+
component: asBlock(Faq),
|
|
728
|
+
});
|
|
729
|
+
/* ---------------------------------------------------------------- Steps */
|
|
730
|
+
export const stepsBlock = defineBlock({
|
|
731
|
+
type: "steps",
|
|
732
|
+
version: 1,
|
|
733
|
+
title: "Process / steps",
|
|
734
|
+
description: "How we work, a first visit, setup steps — an ordered list.",
|
|
735
|
+
category: "content",
|
|
736
|
+
icon: "list-ordered",
|
|
737
|
+
keywords: ["process", "how it works", "timeline", "steps"],
|
|
738
|
+
variants: ["vertical", "horizontal", "split"],
|
|
739
|
+
defaultVariant: "vertical",
|
|
740
|
+
variantMeta: {
|
|
741
|
+
vertical: { label: "Vertical", description: "A thin rule along the start edge with mono numbers on it; a duration tag per step." },
|
|
742
|
+
horizontal: { label: "Horizontal", description: "A timeline on wide containers — numbers above the line, text below; vertical on narrow ones." },
|
|
743
|
+
split: { label: "Split", description: "A sticky title on the start side (4 cols), big display-size numbers with hairline-separated steps on the end side." },
|
|
744
|
+
},
|
|
745
|
+
schema: z.object({
|
|
746
|
+
...header,
|
|
747
|
+
steps: f.list(f.group({
|
|
748
|
+
title: f.text({ max: 60, label: "Title" }),
|
|
749
|
+
text: f.text({ max: 240, multiline: true, label: "Text" }).optional(),
|
|
750
|
+
duration: f.text({ max: 20, label: "Duration" }).optional(),
|
|
751
|
+
media: f.image({ label: "Image" }).optional(),
|
|
752
|
+
}), { min: 2, max: 8, itemLabel: "title", label: "Steps" }),
|
|
753
|
+
actions: f.list(f.cta(), { max: 2, label: "Actions" }).optional(),
|
|
754
|
+
}),
|
|
755
|
+
preview: {
|
|
756
|
+
props: {
|
|
757
|
+
eyebrow: "How we work",
|
|
758
|
+
title: "Six weeks from *brief* to launch",
|
|
759
|
+
steps: [
|
|
760
|
+
{ title: "Discovery", text: "Two hours at your place, not ours. We watch how bookings arrive today and who answers them.", duration: "Week 1" },
|
|
761
|
+
{ title: "Design", text: "Real copy and your own photos from day one. One direction, refined — never three to pick from.", duration: "Weeks 2–3" },
|
|
762
|
+
{ title: "Build & content", text: "Your staff learn to edit the menu while we build. Old URLs are redirected one by one.", duration: "Weeks 4–5" },
|
|
763
|
+
{ title: "Launch & first month", text: "We watch Search Console and booking volume daily for thirty days and fix what we find.", duration: "Week 6 →" },
|
|
764
|
+
],
|
|
765
|
+
},
|
|
766
|
+
},
|
|
767
|
+
component: asBlock(Steps),
|
|
768
|
+
});
|
|
769
|
+
/** Every registry-1 definition, in inserter order. */
|
|
770
|
+
export const siteBlocks1 = [
|
|
771
|
+
announcementBlock,
|
|
772
|
+
navbarBlock,
|
|
773
|
+
heroBlock,
|
|
774
|
+
pageIntroBlock,
|
|
775
|
+
featuresBlock,
|
|
776
|
+
mediaTextBlock,
|
|
777
|
+
richTextBlock,
|
|
778
|
+
statsBlock,
|
|
779
|
+
logoStripBlock,
|
|
780
|
+
stepsBlock,
|
|
781
|
+
faqBlock,
|
|
782
|
+
ctaBlock,
|
|
783
|
+
];
|