@vamos-ui/react 0.0.0-stage → 0.2.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 +100 -0
- package/dist/blocks/site/_kit-1.js +135 -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 +112 -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 +51 -0
- package/dist/blocks/site/feature-grid.d.ts +46 -0
- package/dist/blocks/site/feature-grid.js +49 -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 +47 -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 +67 -0
- package/dist/blocks/site/logo-strip.d.ts +42 -0
- package/dist/blocks/site/logo-strip.js +26 -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 +55 -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 +82 -0
- package/dist/blocks/site/process.d.ts +36 -0
- package/dist/blocks/site/process.js +41 -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 +97 -0
- package/dist/blocks/site/site-shell.js +227 -0
- package/dist/blocks/site/stats-band.d.ts +40 -0
- package/dist/blocks/site/stats-band.js +41 -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 +65 -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 +11 -0
- package/dist/business/index.js +20 -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/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 +42 -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/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/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 +275 -0
- package/dist/components/command.js +493 -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/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/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/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/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 +86 -0
- package/dist/index.js +87 -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 +22 -0
- package/dist/lib/public.js +33 -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 +138 -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/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 +101 -0
- package/dist/sortable/sortable-tree.js +450 -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/navigation.css +293 -0
- package/dist/styles/overlays.css +244 -0
- package/dist/styles.css +742 -0
- package/package.json +156 -4
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { cn2 as cn } from "./shared/kit-2.js";
|
|
3
|
+
import { Section, Container } from "../section.js";
|
|
4
|
+
import { SectionHeader } from "../section-header.js";
|
|
5
|
+
import { BlockImage } from "../block-image.js";
|
|
6
|
+
import { labelTemplates, site2Text } from "./shared/labels-2.js";
|
|
7
|
+
import { addressLines, fieldAttr, prettyPhone, telHref, useBlockIds2 } from "./shared/kit-2.js";
|
|
8
|
+
import { openingHoursJsonLd, weekRows, summarizeHours } from "./shared/opening-hours.js";
|
|
9
|
+
import { OpenNow } from "./shared/open-now.js";
|
|
10
|
+
import { ConsentGate } from "./shared/consent-gate.js";
|
|
11
|
+
import { openNowLabelKeys } from "./shared/island-keys.js";
|
|
12
|
+
import { BrandIcon, BRAND_NAMES } from "./shared/brand-icons.js";
|
|
13
|
+
const DIRECTION_BRAND = { google: "google-maps", apple: "apple-maps", yandex: "yandex-maps", waze: "waze" };
|
|
14
|
+
const query = (b) => (b.address.geo ? `${b.address.geo.lat},${b.address.geo.lng}` : [b.name, ...addressLines(b.address, { withCountry: true })].join(", "));
|
|
15
|
+
/** Direction URL for a provider (no API keys). */
|
|
16
|
+
export function directionsUrl(provider, b) {
|
|
17
|
+
const q = encodeURIComponent(query(b));
|
|
18
|
+
const geo = b.address.geo;
|
|
19
|
+
switch (provider) {
|
|
20
|
+
case "google":
|
|
21
|
+
return `https://www.google.com/maps/dir/?api=1&destination=${q}`;
|
|
22
|
+
case "apple":
|
|
23
|
+
return `https://maps.apple.com/?daddr=${q}`;
|
|
24
|
+
case "yandex":
|
|
25
|
+
return geo ? `https://yandex.com/maps/?rtext=~${geo.lat}%2C${geo.lng}` : `https://yandex.com/maps/?text=${q}`;
|
|
26
|
+
case "waze":
|
|
27
|
+
return geo ? `https://waze.com/ul?ll=${geo.lat}%2C${geo.lng}&navigate=yes` : `https://waze.com/ul?q=${q}&navigate=yes`;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Keyless embed URL (Google `output=embed` or an OpenStreetMap export frame). */
|
|
31
|
+
export function mapEmbedUrl(b, provider = "google") {
|
|
32
|
+
if (b.mapEmbedUrl)
|
|
33
|
+
return b.mapEmbedUrl;
|
|
34
|
+
if (provider === "osm") {
|
|
35
|
+
const g = b.address.geo;
|
|
36
|
+
if (!g)
|
|
37
|
+
return undefined;
|
|
38
|
+
const d = 0.004;
|
|
39
|
+
return `https://www.openstreetmap.org/export/embed.html?bbox=${g.lng - d}%2C${g.lat - d}%2C${g.lng + d}%2C${g.lat + d}&layer=mapnik&marker=${g.lat}%2C${g.lng}`;
|
|
40
|
+
}
|
|
41
|
+
return `https://www.google.com/maps?q=${encodeURIComponent(query(b))}&z=16&output=embed`;
|
|
42
|
+
}
|
|
43
|
+
/** schema.org LocalBusiness (or a subtype) per branch — usable without the renderer. */
|
|
44
|
+
export function localBusinessJsonLd(props) {
|
|
45
|
+
return props.branches.map((b) => ({
|
|
46
|
+
"@type": props.businessType ?? "LocalBusiness",
|
|
47
|
+
name: b.name,
|
|
48
|
+
telephone: b.phone,
|
|
49
|
+
email: b.email,
|
|
50
|
+
address: {
|
|
51
|
+
"@type": "PostalAddress",
|
|
52
|
+
streetAddress: b.address.line,
|
|
53
|
+
addressLocality: b.address.district ?? b.address.city,
|
|
54
|
+
addressRegion: b.address.region ?? b.address.city,
|
|
55
|
+
postalCode: b.address.postalCode,
|
|
56
|
+
addressCountry: b.address.country,
|
|
57
|
+
},
|
|
58
|
+
geo: b.address.geo ? { "@type": "GeoCoordinates", latitude: b.address.geo.lat, longitude: b.address.geo.lng } : undefined,
|
|
59
|
+
hasMap: b.placeUrl,
|
|
60
|
+
openingHoursSpecification: openingHoursJsonLd(b.hours),
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Address, map, opening hours and directions for a local business — the most visited section of
|
|
65
|
+
* restaurant, spa and clinic sites, and the source of LocalBusiness SEO. The map is a facade (no
|
|
66
|
+
* Maps JS API, no key); the iframe loads after a click or functional consent. "Open now" is a
|
|
67
|
+
* client island computed in the business's time zone. Server component.
|
|
68
|
+
*
|
|
69
|
+
* ```tsx
|
|
70
|
+
* <MapHours title="Find *us*" branches={[{ name: "Meyhane Rasimpaşa", address, phone: "+902160000000", hours, mapImage }]} directions={["google", "apple", "yandex"]} />
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export function MapHours({ variant: variantProp = "map-split", eyebrow, title, lead, branches, businessType, mapProvider = "google", directions = ["google", "apple"], showOpenNow = true, hoursDisplay = "week", now, id, anchor, theme, headingLevel = 2, className, labels, locale = "en-US", components, editMode, }) {
|
|
74
|
+
const t = site2Text(labels, locale);
|
|
75
|
+
const { base, headingId } = useBlockIds2(id, "location");
|
|
76
|
+
const first = branches[0];
|
|
77
|
+
let variant = variantProp;
|
|
78
|
+
if (variant === "branches" && branches.length < 2)
|
|
79
|
+
variant = "map-split";
|
|
80
|
+
if (variant === "map-split" && (!first?.mapImage?.src || mapProvider === "none"))
|
|
81
|
+
variant = "info";
|
|
82
|
+
const ctx = { t, locale, components, labels, editMode, now, showOpenNow, hoursDisplay, directions, mapProvider, openNow: labelTemplates(labels, openNowLabelKeys) };
|
|
83
|
+
const header = title || eyebrow || lead ? _jsx(SectionHeader, { eyebrow: eyebrow, title: title, lead: lead, headingId: headingId, headingLevel: headingLevel, editMode: editMode, labels: labels, locale: locale }) : null;
|
|
84
|
+
if (!first)
|
|
85
|
+
return null;
|
|
86
|
+
return (_jsx(Section, { theme: theme, anchor: anchor, headingId: title ? headingId : undefined, blockId: id, blockType: "location", editMode: editMode, className: cn("vb-location", className), "data-variant": variant, "data-business": businessType, children: _jsx(Container, { className: "flex flex-col gap-12 @4xl:gap-16", children: variant === "map-split" ? (_jsxs("div", { className: "grid gap-x-(--gutter) gap-y-10 @4xl:grid-cols-12", children: [_jsx("div", { className: "@4xl:col-span-7", children: _jsx(MapFacade, { branch: first, ctx: ctx }) }), _jsxs("div", { className: "flex flex-col gap-8 @4xl:col-span-5", children: [header, _jsx(BranchDetails, { branch: first, ctx: ctx, index: 0 })] })] })) : variant === "info" ? (_jsxs(_Fragment, { children: [header, _jsx(InfoColumns, { branch: first, ctx: ctx })] })) : (_jsxs(_Fragment, { children: [header, _jsx(BranchPicker, { branches: branches, ctx: ctx, name: `${base}-branch` })] })) }) }));
|
|
87
|
+
}
|
|
88
|
+
function MapFacade({ branch, ctx }) {
|
|
89
|
+
const src = ctx.mapProvider !== "none" ? mapEmbedUrl(branch, ctx.mapProvider) : undefined;
|
|
90
|
+
const preview = branch.mapImage?.src ? (_jsxs(_Fragment, { children: [_jsx(BlockImage, { ...branch.mapImage, decorative: true, aspect: "4:3", sizes: "(min-width: 56rem) 58vw, 100vw", className: "size-full", imgClassName: "vb-map-img", components: ctx.components }), _jsx("span", { "aria-hidden": true, className: "vb-map-pin absolute start-1/2 top-1/2 -translate-x-1/2 -translate-y-full text-accent rtl:translate-x-1/2", children: _jsxs("svg", { viewBox: "0 0 32 40", className: "h-10 w-8 drop-shadow-sm", children: [_jsx("path", { d: "M16 0C7.16 0 0 7.16 0 16c0 11.2 14.4 23.2 15.04 23.72a1.5 1.5 0 0 0 1.92 0C17.6 39.2 32 27.2 32 16 32 7.16 24.84 0 16 0Z", fill: "currentColor" }), _jsx("circle", { cx: "16", cy: "16", r: "6", fill: "var(--accent-fg)" })] }) })] })) : null;
|
|
91
|
+
if (!src)
|
|
92
|
+
return preview ? _jsx("div", { className: "vb-gate relative aspect-[4/3] overflow-hidden rounded-ui bg-surface-2", children: preview }) : null;
|
|
93
|
+
return (_jsx(ConsentGate, { src: src, title: ctx.t("mapOf", { name: branch.name }), loadLabel: ctx.t("loadMap"), notice: ctx.t("mapNotice", { provider: ctx.mapProvider === "osm" ? "OpenStreetMap" : "Google Maps" }), rememberLabel: ctx.t("rememberChoice"), category: "functional", children: preview }));
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Weekly hours as a table; today is bold with `aria-current="date"`, special days show their note.
|
|
97
|
+
* `openDaysOnly` leaves out closed days that carry no note.
|
|
98
|
+
*/
|
|
99
|
+
export function HoursTable({ hours, caption, t, locale, now, openDaysOnly, className }) {
|
|
100
|
+
const all = weekRows(hours, { locale, at: now ?? Date.now() });
|
|
101
|
+
const rows = openDaysOnly ? all.filter((r) => !r.closed || r.note) : all;
|
|
102
|
+
if (!rows.length)
|
|
103
|
+
return null;
|
|
104
|
+
return (_jsxs("table", { className: cn("vb-hours w-full border-collapse text-small", className), children: [_jsx("caption", { className: "sr-only", children: caption }), _jsx("tbody", { children: rows.map((r) => (_jsxs("tr", { "aria-current": r.today ? "date" : undefined, className: cn("border-b border-line last:border-b-0", r.today && "font-medium text-fg"), children: [_jsxs("th", { scope: "row", className: cn("py-2.5 pe-4 text-start font-normal", r.today ? "font-medium text-fg" : "text-fg-muted"), children: [r.label, r.today ? _jsx("span", { className: "ms-2 font-mono text-eyebrow uppercase tracking-[0.06em] text-accent-ink", children: t("today") }) : null] }), _jsxs("td", { className: cn("py-2.5 text-end tabular", r.closed ? "text-fg-subtle" : "text-fg"), children: [r.closed ? t("closedDay") : r.allDay ? t("open24h") : r.text, r.note ? _jsx("span", { className: "block text-xs text-fg-muted", children: r.note }) : null] })] }, r.weekday))) })] }));
|
|
105
|
+
}
|
|
106
|
+
function Directions({ branch, ctx }) {
|
|
107
|
+
if (!ctx.directions.length)
|
|
108
|
+
return null;
|
|
109
|
+
return (_jsxs("div", { className: "flex flex-col gap-3", children: [_jsx("p", { className: "font-mono text-eyebrow uppercase tracking-[0.08em] text-fg-muted", children: ctx.t("directions") }), _jsx("ul", { className: "flex flex-wrap gap-2", children: ctx.directions.map((p) => (_jsx("li", { children: _jsxs("a", { href: directionsUrl(p, branch), target: "_blank", rel: "noopener noreferrer", "data-track": `directions:${p}`, className: "inline-flex h-11 items-center gap-2 rounded-ui border border-line px-3.5 text-sm text-fg transition-colors hover:border-fg focus-ring", children: [_jsx(BrandIcon, { name: DIRECTION_BRAND[p], className: "size-4 text-fg-muted" }), BRAND_NAMES[DIRECTION_BRAND[p]], _jsxs("span", { className: "sr-only", children: [" ", ctx.t("opensInNewTab")] })] }) }, p))) })] }));
|
|
110
|
+
}
|
|
111
|
+
function AddressBlock({ branch, ctx, large }) {
|
|
112
|
+
return (_jsx("address", { className: cn("not-italic text-fg", large ? "text-lead" : "text-body"), children: addressLines(branch.address, { locale: ctx.locale }).map((l, i) => (_jsx("span", { className: "block", children: l }, i))) }));
|
|
113
|
+
}
|
|
114
|
+
function BranchDetails({ branch, ctx, index }) {
|
|
115
|
+
return (_jsxs("div", { className: "flex flex-col gap-7", children: [_jsxs("div", { className: "flex flex-col gap-3", ...fieldAttr(ctx.editMode, `branches.${index}.address`), children: [_jsx(AddressBlock, { branch: branch, ctx: ctx, large: true }), branch.notes ? _jsx("p", { className: "text-small text-fg-muted", children: branch.notes }) : null, branch.phone ? (_jsx("a", { href: telHref(branch.phone), className: "self-start text-body font-medium tabular text-fg underline decoration-line underline-offset-[0.25em] hover:decoration-current focus-ring rounded-[2px]", "data-track": "call", children: prettyPhone(branch.phone) })) : null] }), ctx.hoursDisplay !== "none" || ctx.showOpenNow ? (_jsxs("div", { className: "flex flex-col gap-3 border-t border-line pt-5", children: [_jsxs("div", { className: "flex flex-wrap items-baseline justify-between gap-3", children: [_jsx("p", { className: "font-mono text-eyebrow uppercase tracking-[0.08em] text-fg-muted", children: ctx.t("openingHours") }), ctx.showOpenNow ? _jsx(OpenNow, { hours: branch.hours, labels: ctx.openNow, locale: ctx.locale, now: ctx.now }) : null] }), ctx.hoursDisplay !== "none" ? (_jsx(HoursTable, { hours: branch.hours, caption: ctx.t("openingHoursOf", { name: branch.name }), t: ctx.t, locale: ctx.locale, now: ctx.now, openDaysOnly: ctx.hoursDisplay === "open-days" })) : null] })) : null, _jsx(Directions, { branch: branch, ctx: ctx })] }));
|
|
116
|
+
}
|
|
117
|
+
function InfoColumns({ branch, ctx }) {
|
|
118
|
+
const summary = summarizeHours(branch.hours, ctx.locale).filter((s) => ctx.hoursDisplay !== "open-days" || !s.closed);
|
|
119
|
+
const showHours = ctx.hoursDisplay !== "none" || ctx.showOpenNow;
|
|
120
|
+
return (_jsxs("div", { className: cn("grid gap-x-(--gutter) gap-y-10 border-t border-line pt-8", showHours ? "@2xl:grid-cols-3" : "@2xl:grid-cols-2"), children: [_jsxs("div", { className: "flex flex-col gap-3", children: [_jsx("p", { className: "font-mono text-eyebrow uppercase tracking-[0.08em] text-fg-muted", children: ctx.t("address") }), _jsx(AddressBlock, { branch: branch, ctx: ctx, large: true }), branch.notes ? _jsx("p", { className: "text-small text-fg-muted", children: branch.notes }) : null, ctx.directions[0] ? (_jsxs("a", { href: directionsUrl(ctx.directions[0], branch), target: "_blank", rel: "noopener noreferrer", className: "mt-1 self-start text-small font-medium text-fg underline decoration-line underline-offset-[0.25em] hover:decoration-current focus-ring rounded-[2px]", "data-track": `directions:${ctx.directions[0]}`, children: [ctx.t("directionsVia", { provider: BRAND_NAMES[DIRECTION_BRAND[ctx.directions[0]]] }), _jsxs("span", { className: "sr-only", children: [" ", ctx.t("opensInNewTab")] })] })) : null] }), showHours ? (_jsxs("div", { className: "flex flex-col gap-3", children: [_jsx("div", { className: "flex flex-wrap items-baseline justify-between gap-3", children: _jsx("p", { className: "font-mono text-eyebrow uppercase tracking-[0.08em] text-fg-muted", children: ctx.t("hours") }) }), ctx.hoursDisplay !== "none" ? (_jsx("ul", { className: "flex flex-col gap-1.5 text-lead", children: summary.map((s, i) => (_jsxs("li", { className: "flex justify-between gap-6 tabular", children: [_jsx("span", { className: "text-fg-muted", children: s.days }), _jsx("span", { className: s.closed ? "text-fg-subtle" : "text-fg", children: s.closed ? ctx.t("closedDay") : s.text })] }, i))) })) : null, ctx.showOpenNow ? _jsx(OpenNow, { hours: branch.hours, labels: ctx.openNow, locale: ctx.locale, now: ctx.now, className: "mt-2" }) : null] })) : null, _jsxs("div", { className: "flex flex-col gap-3", children: [_jsx("p", { className: "font-mono text-eyebrow uppercase tracking-[0.08em] text-fg-muted", children: ctx.t("contactDetails") }), branch.phone ? (_jsx("a", { href: telHref(branch.phone), className: "self-start text-lead font-medium tabular text-fg hover:text-accent-ink focus-ring rounded-[2px]", "data-track": "call", children: prettyPhone(branch.phone) })) : null, branch.email ? (_jsx("a", { href: `mailto:${branch.email}`, className: "self-start text-fg underline decoration-line underline-offset-[0.25em] hover:decoration-current focus-ring rounded-[2px]", "data-track": "email", children: branch.email })) : null] })] }));
|
|
121
|
+
}
|
|
122
|
+
function BranchPicker({ branches, ctx, name }) {
|
|
123
|
+
const list = branches.slice(0, 12);
|
|
124
|
+
return (_jsxs("div", { className: "vb-branches grid gap-x-(--gutter) gap-y-10 @4xl:grid-cols-12", children: [_jsxs("fieldset", { className: "flex flex-col @4xl:col-span-4", children: [_jsx("legend", { className: "mb-3 font-mono text-eyebrow uppercase tracking-[0.08em] text-fg-muted", children: ctx.t("chooseBranch") }), _jsx("div", { className: "flex flex-col border-t border-line", children: list.map((b, i) => (_jsxs("label", { className: "vb-branch-option relative flex cursor-pointer flex-col gap-1 border-b border-line py-4 ps-4", children: [_jsx("input", { type: "radio", name: name, value: i, "data-i": i, defaultChecked: i === 0, className: "vb-branch-input sr-only" }), _jsx("span", { className: "text-h3 font-semibold tracking-[-0.012em] text-fg", children: b.name }), _jsx("span", { className: "text-small text-fg-muted", children: b.address.district ?? b.address.city }), ctx.showOpenNow ? _jsx(OpenNow, { hours: b.hours, labels: ctx.openNow, locale: ctx.locale, now: ctx.now, className: "text-xs" }) : null] }, i))) })] }), _jsx("div", { className: "@4xl:col-span-8", children: list.map((b, i) => (_jsxs("div", { "data-i": i, className: "vb-branch-panel gap-x-(--gutter) gap-y-8 @2xl:grid-cols-2", children: [_jsx("div", { className: "@2xl:col-span-2", children: b.mapImage?.src && ctx.mapProvider !== "none" ? _jsx(MapFacade, { branch: b, ctx: ctx }) : null }), _jsx("h3", { className: "sr-only", children: b.name }), _jsxs("div", { className: "flex flex-col gap-3", children: [_jsx(AddressBlock, { branch: b, ctx: ctx, large: true }), b.notes ? _jsx("p", { className: "text-small text-fg-muted", children: b.notes }) : null, b.phone ? (_jsx("a", { href: telHref(b.phone), className: "self-start font-medium tabular text-fg underline decoration-line underline-offset-[0.25em] hover:decoration-current focus-ring rounded-[2px]", "data-track": "call", children: prettyPhone(b.phone) })) : null, _jsx("div", { className: "mt-3", children: _jsx(Directions, { branch: b, ctx: ctx }) })] }), ctx.hoursDisplay !== "none" ? (_jsx(HoursTable, { hours: b.hours, caption: ctx.t("openingHoursOf", { name: b.name }), t: ctx.t, locale: ctx.locale, now: ctx.now, openDaysOnly: ctx.hoursDisplay === "open-days" })) : null] }, i))) })] }));
|
|
125
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { BlockBaseProps } from "../types.js";
|
|
3
|
+
import type { RichDoc } from "../schema/rich-doc.js";
|
|
4
|
+
import { type SiteBlockLabels, type SiteCta, type SiteImage } from "./_kit-1.js";
|
|
5
|
+
export type MediaTextVariant = "side" | "overlap" | "bleed";
|
|
6
|
+
export interface MediaTextVideo {
|
|
7
|
+
provider: "youtube" | "vimeo" | "mp4";
|
|
8
|
+
url: string;
|
|
9
|
+
/** Accessible title ("A morning in our kitchen"). Default: the block title. */
|
|
10
|
+
title?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface MediaTextProps extends Omit<BlockBaseProps, "variant" | "labels"> {
|
|
13
|
+
/**
|
|
14
|
+
* side: 5/7 or 7/5, text top-aligned with the image (not centred).
|
|
15
|
+
* overlap: the image takes 8 columns, a surface panel overlaps its bottom corner by 2.
|
|
16
|
+
* bleed: the image runs to the section edge, the text stays inside the container.
|
|
17
|
+
*/
|
|
18
|
+
variant?: MediaTextVariant;
|
|
19
|
+
eyebrow?: React.ReactNode;
|
|
20
|
+
title: React.ReactNode;
|
|
21
|
+
body?: RichDoc | string;
|
|
22
|
+
/** Short points with accent dashes (≤ 6). */
|
|
23
|
+
bullets?: React.ReactNode[];
|
|
24
|
+
cta?: SiteCta;
|
|
25
|
+
/** The image (also the video poster). */
|
|
26
|
+
media: SiteImage;
|
|
27
|
+
/** Static preview → plays only after a click (YouTube via youtube-nocookie). */
|
|
28
|
+
video?: MediaTextVideo;
|
|
29
|
+
/** Logical side of the image. Default `"start"`. */
|
|
30
|
+
mediaSide?: "start" | "end";
|
|
31
|
+
/** Crop ratio. Default `"4:5"`. */
|
|
32
|
+
aspect?: "4:5" | "3:2" | "1:1";
|
|
33
|
+
labels?: SiteBlockLabels;
|
|
34
|
+
}
|
|
35
|
+
/** Embed URL for a video facade (YouTube → youtube-nocookie, Vimeo → player). */
|
|
36
|
+
export declare function videoEmbedUrl(v: MediaTextVideo): string;
|
|
37
|
+
/**
|
|
38
|
+
* The most used body section: an image or video beside text. Server component; a video is a
|
|
39
|
+
* click-to-load facade island (no third-party request before the visitor asks).
|
|
40
|
+
*
|
|
41
|
+
* ```tsx
|
|
42
|
+
* <MediaText eyebrow="The kitchen" title="Fish from the *morning* boats" body="…" media={{ src, alt, width, height }} />
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function MediaText({ variant, eyebrow, title, body, bullets, cta, media, video, mediaSide, aspect, id, theme, anchor, className, headingLevel, labels, locale, components, editMode, }: MediaTextProps): React.JSX.Element;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Play } from "lucide-react";
|
|
3
|
+
import { cn } from "../../lib/cn.js";
|
|
4
|
+
import { Container, Section } from "../section.js";
|
|
5
|
+
import { SectionHeader } from "../section-header.js";
|
|
6
|
+
import { BlockImage } from "../block-image.js";
|
|
7
|
+
import { RichText } from "../rich-text.js";
|
|
8
|
+
import { EmbedFacade } from "./embed-facade.js";
|
|
9
|
+
import { CtaList, siteText, useBlockIds } from "./_kit-1.js";
|
|
10
|
+
/** Embed URL for a video facade (YouTube → youtube-nocookie, Vimeo → player). */
|
|
11
|
+
export function videoEmbedUrl(v) {
|
|
12
|
+
if (v.provider === "youtube") {
|
|
13
|
+
const id = /(?:v=|youtu\.be\/|embed\/|shorts\/)([\w-]{6,})/.exec(v.url)?.[1];
|
|
14
|
+
return id ? `https://www.youtube-nocookie.com/embed/${id}?autoplay=1&rel=0` : v.url;
|
|
15
|
+
}
|
|
16
|
+
if (v.provider === "vimeo") {
|
|
17
|
+
const id = /vimeo\.com\/(?:video\/)?(\d+)/.exec(v.url)?.[1];
|
|
18
|
+
return id ? `https://player.vimeo.com/video/${id}?autoplay=1&dnt=1` : v.url;
|
|
19
|
+
}
|
|
20
|
+
return v.url;
|
|
21
|
+
}
|
|
22
|
+
const textOf = (n) => (typeof n === "string" ? n.replace(/\*/g, "") : "");
|
|
23
|
+
/**
|
|
24
|
+
* The most used body section: an image or video beside text. Server component; a video is a
|
|
25
|
+
* click-to-load facade island (no third-party request before the visitor asks).
|
|
26
|
+
*
|
|
27
|
+
* ```tsx
|
|
28
|
+
* <MediaText eyebrow="The kitchen" title="Fish from the *morning* boats" body="…" media={{ src, alt, width, height }} />
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export function MediaText({ variant = "side", eyebrow, title, body, bullets, cta, media, video, mediaSide = "start", aspect = "4:5", id, theme, anchor, className, headingLevel = 2, labels, locale, components, editMode, }) {
|
|
32
|
+
const t = siteText(labels, locale);
|
|
33
|
+
const { base, headingId } = useBlockIds(id, "media-text");
|
|
34
|
+
const end = mediaSide === "end";
|
|
35
|
+
const ratio = variant === "overlap" ? "3:2" : aspect;
|
|
36
|
+
const image = (sizes, cls) => {
|
|
37
|
+
const img = _jsx(BlockImage, { ...media, aspect: ratio, sizes: sizes, className: cn("size-full", cls), components: components, labels: labels, locale: locale, editMode: editMode, field: "props.media" });
|
|
38
|
+
if (!video)
|
|
39
|
+
return img;
|
|
40
|
+
const vTitle = video.title ?? textOf(title);
|
|
41
|
+
return (_jsx("div", { className: cn("relative overflow-hidden", cls), style: { aspectRatio: ratio.replace(":", " / ") }, children: _jsxs(EmbedFacade, { kind: video.provider === "mp4" ? "video" : "iframe", src: videoEmbedUrl(video), title: vTitle || t("video"), buttonLabel: t("playVideo", { title: vTitle || t("video") }), children: [_jsx(BlockImage, { ...media, alt: undefined, decorative: true, aspect: ratio, sizes: sizes, className: "size-full", components: components }), _jsx("span", { "aria-hidden": true, className: "vb-play absolute inset-0 grid place-items-center", children: _jsx("span", { className: "inline-flex size-16 items-center justify-center rounded-full bg-scene text-fg transition-colors duration-200 group-hover/facade:bg-accent group-hover/facade:text-accent-fg", children: _jsx(Play, { strokeWidth: 1.5, className: "ms-0.5 size-6" }) }) })] }) }));
|
|
42
|
+
};
|
|
43
|
+
const text = (_jsxs("div", { className: "flex flex-col gap-7", children: [_jsx(SectionHeader, { eyebrow: eyebrow, title: title, headingLevel: headingLevel, headingId: headingId, editMode: editMode, labels: labels, locale: locale }), body ? _jsx(RichText, { doc: body, components: components, labels: labels, locale: locale, headingOffset: 1, editMode: editMode, field: "props.body", className: "text-fg-muted" }) : null, bullets?.length ? (_jsx("ul", { className: "flex flex-col border-t border-line", "data-field": editMode ? "props.bullets" : undefined, children: bullets.slice(0, 6).map((b, i) => (_jsxs("li", { className: "flex gap-4 border-b border-line py-3 text-body text-fg", children: [_jsx("span", { "aria-hidden": true, className: "mt-[0.8em] h-px w-4 shrink-0 bg-accent" }), _jsx("span", { children: b })] }, i))) })) : null, cta ? _jsx(CtaList, { actions: [cta], components: components, labels: labels, locale: locale, max: 1, editMode: editMode }) : null] }));
|
|
44
|
+
let content;
|
|
45
|
+
if (variant === "overlap") {
|
|
46
|
+
content = (_jsxs(Container, { className: "grid gap-y-0 @4xl:grid-cols-12 @4xl:pb-[calc(var(--section-y)*0.4)]", children: [_jsx("div", { className: cn("@4xl:col-span-8 @4xl:row-start-1", end && "@4xl:col-start-5"), children: image("(min-width: 56rem) 60vw, 100vw", "rounded-ui") }), _jsx("div", { className: cn("vb-overlap-panel surface relative -mt-12 mx-[clamp(0.75rem,3cqi,1.5rem)] rounded-ui p-[clamp(1.5rem,4cqi,3rem)] @4xl:row-start-1 @4xl:mx-0 @4xl:mt-0 @4xl:self-end @4xl:translate-y-[calc(var(--section-y)*0.35)]", end ? "@4xl:col-span-6 @4xl:col-start-1" : "@4xl:col-span-6 @4xl:col-start-7"), children: text })] }));
|
|
47
|
+
}
|
|
48
|
+
else if (variant === "bleed") {
|
|
49
|
+
content = (_jsxs(Container, { className: "grid gap-x-(--gutter) gap-y-10 @4xl:grid-cols-12 @4xl:items-start", children: [_jsx("div", { className: cn("@4xl:col-span-7", end ? "vb-bleed-end @4xl:order-2 @4xl:col-start-6" : "vb-bleed-start"), children: image("(min-width: 56rem) 60vw, 100vw") }), _jsx("div", { className: cn("@4xl:col-span-4 @4xl:pt-4", end ? "@4xl:order-1 @4xl:col-start-1" : "@4xl:col-start-9"), children: text })] }));
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
content = (_jsxs(Container, { className: "grid gap-x-(--gutter) gap-y-10 @4xl:grid-cols-12 @4xl:items-start", children: [_jsx("div", { className: cn("@4xl:col-span-5", end && "@4xl:order-2 @4xl:col-start-8"), children: image("(min-width: 56rem) 40vw, 100vw", "rounded-ui") }), _jsx("div", { className: cn("@4xl:col-span-6", end ? "@4xl:order-1 @4xl:col-start-1" : "@4xl:col-start-7"), children: text })] }));
|
|
53
|
+
}
|
|
54
|
+
return (_jsx(Section, { theme: theme, anchor: anchor, headingId: headingId, blockId: base, blockType: "media-text", editMode: editMode, className: cn("vb-media-text", variant === "overlap" && "vb-media-overlap", className), "data-variant": variant, "data-side": mediaSide, children: _jsx("div", { className: "vb-reveal", children: content }) }));
|
|
55
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { BlockBaseProps } from "../types.js";
|
|
3
|
+
import type { MoneyValue } from "../schema/types.js";
|
|
4
|
+
import { type Site2BlockLabels } from "./shared/labels-2.js";
|
|
5
|
+
import { type SiteImage2 } from "./shared/kit-2.js";
|
|
6
|
+
export type MenuVariant = "classic" | "photo" | "service-list";
|
|
7
|
+
export type MenuTag = "vegetarian" | "vegan" | "gluten-free" | "spicy" | "new" | "chef-pick";
|
|
8
|
+
/** The 14 EU / Codex allergens. */
|
|
9
|
+
export declare const ALLERGENS: readonly ["gluten", "crustaceans", "eggs", "fish", "peanuts", "soybeans", "milk", "nuts", "celery", "mustard", "sesame", "sulphites", "lupin", "molluscs"];
|
|
10
|
+
export type Allergen = (typeof ALLERGENS)[number];
|
|
11
|
+
export interface MenuPrice {
|
|
12
|
+
/** "Small", "Bottle", "50 min". */
|
|
13
|
+
label?: React.ReactNode;
|
|
14
|
+
/** Missing = "Market price". */
|
|
15
|
+
amount?: MoneyValue;
|
|
16
|
+
}
|
|
17
|
+
export interface MenuItem {
|
|
18
|
+
name: React.ReactNode;
|
|
19
|
+
description?: React.ReactNode;
|
|
20
|
+
/** 1–4 prices. */
|
|
21
|
+
prices: MenuPrice[];
|
|
22
|
+
/** "50 min" (service-list). */
|
|
23
|
+
duration?: React.ReactNode;
|
|
24
|
+
tags?: MenuTag[];
|
|
25
|
+
allergens?: Allergen[];
|
|
26
|
+
/** Square photo (`photo` variant). */
|
|
27
|
+
image?: SiteImage2;
|
|
28
|
+
/** "Not today" — shown as a label, never a strikethrough. */
|
|
29
|
+
unavailable?: boolean;
|
|
30
|
+
/** service-list: the item's booking link (falls back to `bookHref`). */
|
|
31
|
+
bookHref?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface MenuCategory {
|
|
34
|
+
title: React.ReactNode;
|
|
35
|
+
note?: React.ReactNode;
|
|
36
|
+
items: MenuItem[];
|
|
37
|
+
/** Anchor id; default derived from the title. */
|
|
38
|
+
anchor?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface MenuListProps extends Omit<BlockBaseProps, "variant" | "labels"> {
|
|
41
|
+
/**
|
|
42
|
+
* classic: printed-menu feel — dotted leaders, tabular prices, serif category titles under a
|
|
43
|
+
* thin double rule. photo: a 72px square photo per item. service-list: spa/salon rows of
|
|
44
|
+
* service · duration · price with a "Book" link.
|
|
45
|
+
*/
|
|
46
|
+
variant?: MenuVariant;
|
|
47
|
+
eyebrow?: React.ReactNode;
|
|
48
|
+
title?: React.ReactNode;
|
|
49
|
+
lead?: React.ReactNode;
|
|
50
|
+
categories: MenuCategory[];
|
|
51
|
+
/** Required by D6-8: "Prices include VAT. 10% service is not added." */
|
|
52
|
+
priceNote?: React.ReactNode;
|
|
53
|
+
/** Sticky category jump bar. Default: more than two categories. */
|
|
54
|
+
showNav?: boolean;
|
|
55
|
+
/** service-list: booking page for every row. */
|
|
56
|
+
bookHref?: string;
|
|
57
|
+
/** Show allergen lists under items. Default true. */
|
|
58
|
+
showAllergens?: boolean;
|
|
59
|
+
labels?: Site2BlockLabels;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Restaurant menus and spa/salon price lists — also a QR-menu page. Category jump bar with plain
|
|
63
|
+
* anchors, money through `Intl` (full currency name for screen readers), tags as words (never
|
|
64
|
+
* emoji), the 14 allergens localized. Server component, 0 JS.
|
|
65
|
+
*
|
|
66
|
+
* ```tsx
|
|
67
|
+
* <MenuList title="The *menu*" priceNote="Prices include VAT." categories={[{ title: "Cold meze", items: [{ name: "Haydari", prices: [{ amount: { amount: "180", currency: "TRY" } }] }] }]} />
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function MenuList({ variant, eyebrow, title, lead, categories: all, priceNote, showNav, bookHref, showAllergens, id, anchor, theme, headingLevel, className, labels, locale, components, editMode, }: MenuListProps): React.JSX.Element;
|
|
71
|
+
/** schema.org `Menu` → `MenuSection` → `MenuItem` + `Offer`. */
|
|
72
|
+
export declare function menuJsonLd(props: Pick<MenuListProps, "categories"> & {
|
|
73
|
+
name?: string;
|
|
74
|
+
}): Record<string, unknown>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn2 as cn } from "./shared/kit-2.js";
|
|
3
|
+
import { slugify } from "../../lib/text.js";
|
|
4
|
+
import { Section, Container } from "../section.js";
|
|
5
|
+
import { SectionHeader } from "../section-header.js";
|
|
6
|
+
import { BlockImage } from "../block-image.js";
|
|
7
|
+
import { BlockLink } from "../block-link.js";
|
|
8
|
+
import { site2Text } from "./shared/labels-2.js";
|
|
9
|
+
import { fieldAttr, formatMoney, formatMoneyLong, textOf, useBlockIds2 } from "./shared/kit-2.js";
|
|
10
|
+
/** The 14 EU / Codex allergens. */
|
|
11
|
+
export const ALLERGENS = ["gluten", "crustaceans", "eggs", "fish", "peanuts", "soybeans", "milk", "nuts", "celery", "mustard", "sesame", "sulphites", "lupin", "molluscs"];
|
|
12
|
+
const TAG_KEY = { vegetarian: "tagVegetarian", vegan: "tagVegan", "gluten-free": "tagGlutenFree", spicy: "tagSpicy", new: "tagNew", "chef-pick": "tagChefPick" };
|
|
13
|
+
/**
|
|
14
|
+
* Restaurant menus and spa/salon price lists — also a QR-menu page. Category jump bar with plain
|
|
15
|
+
* anchors, money through `Intl` (full currency name for screen readers), tags as words (never
|
|
16
|
+
* emoji), the 14 allergens localized. Server component, 0 JS.
|
|
17
|
+
*
|
|
18
|
+
* ```tsx
|
|
19
|
+
* <MenuList title="The *menu*" priceNote="Prices include VAT." categories={[{ title: "Cold meze", items: [{ name: "Haydari", prices: [{ amount: { amount: "180", currency: "TRY" } }] }] }]} />
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function MenuList({ variant = "classic", eyebrow, title, lead, categories: all, priceNote, showNav, bookHref, showAllergens = true, id, anchor, theme, headingLevel = 2, className, labels, locale = "en-US", components, editMode, }) {
|
|
23
|
+
const t = site2Text(labels, locale);
|
|
24
|
+
const { base, headingId } = useBlockIds2(id, "menu");
|
|
25
|
+
const categories = all.filter((c) => c.items.length > 0 || editMode);
|
|
26
|
+
const nav = showNav ?? categories.length > 2;
|
|
27
|
+
const catId = (c, i) => c.anchor ?? `${slugify(textOf(c.title), { locale }) || "section"}-${i}`;
|
|
28
|
+
const ctx = { t, locale, components, labels, editMode, variant, bookHref, showAllergens };
|
|
29
|
+
return (_jsx(Section, { theme: theme, anchor: anchor, headingId: title ? headingId : undefined, blockId: id, blockType: "menu", editMode: editMode, className: cn("vb-menu", className), "data-variant": variant, children: _jsxs(Container, { className: "flex flex-col gap-10 @4xl:gap-14", children: [title || eyebrow || lead ? _jsx(SectionHeader, { eyebrow: eyebrow, title: title, lead: lead, headingId: headingId, headingLevel: headingLevel, align: "split", editMode: editMode, labels: labels, locale: locale }) : null, nav ? (_jsx("nav", { "aria-label": t("menuCategories"), className: "vb-menu-nav sticky top-[var(--topbar-h,0px)] z-10 -mx-(--gutter) border-b border-line bg-scene px-(--gutter)", children: _jsx("ul", { className: "scrollbar-none flex gap-1 overflow-x-auto py-2", children: categories.map((c, i) => (_jsx("li", { className: "shrink-0", children: _jsx("a", { href: `#${base}-${catId(c, i)}`, className: "inline-flex h-10 items-center whitespace-nowrap rounded-full px-3.5 text-sm text-fg-muted transition-colors hover:bg-hover hover:text-fg focus-ring", children: c.title }) }, i))) }) })) : null, _jsx("div", { className: "flex flex-col gap-14 @4xl:gap-20", children: categories.map((c, ci) => {
|
|
30
|
+
const hid = `${base}-${catId(c, ci)}`;
|
|
31
|
+
return (_jsxs("section", { id: hid, "aria-labelledby": `${hid}-h`, className: "vb-menu-cat flex flex-col gap-6", children: [_jsxs("div", { className: "flex flex-col gap-2 border-t-[3px] border-double border-line pt-5 @2xl:flex-row @2xl:items-baseline @2xl:justify-between @2xl:gap-8", children: [_jsx("h3", { id: `${hid}-h`, className: "font-display text-display-m text-fg", ...fieldAttr(editMode, `categories.${ci}.title`), children: c.title }), c.note ? _jsx("p", { className: "max-w-[44ch] text-small text-fg-muted @2xl:text-end", children: c.note }) : null] }), variant === "service-list" ? (_jsx("ul", { className: "flex flex-col", children: c.items.map((item, ii) => (_jsx(ServiceRow, { item: item, ctx: ctx }, ii))) })) : (_jsx("ul", { className: cn("grid gap-x-(--gutter) gap-y-7", variant === "classic" && "@4xl:grid-cols-2 @4xl:gap-x-16"), children: c.items.map((item, ii) => (_jsx(DishItem, { item: item, ctx: ctx }, ii))) }))] }, ci));
|
|
32
|
+
}) }), priceNote ? (_jsx("p", { className: "border-t border-line pt-5 text-small text-fg-muted", ...fieldAttr(editMode, "priceNote"), children: priceNote })) : null] }) }));
|
|
33
|
+
}
|
|
34
|
+
function Price({ price, ctx, className }) {
|
|
35
|
+
if (!price.amount)
|
|
36
|
+
return _jsx("span", { className: cn("text-small text-fg-muted", className), children: ctx.t("marketPrice") });
|
|
37
|
+
return (_jsxs("span", { className: cn("tabular text-fg", className), children: [_jsx("span", { "aria-hidden": true, children: formatMoney(price.amount, ctx.locale) }), _jsx("span", { className: "sr-only", children: formatMoneyLong(price.amount, ctx.locale) })] }));
|
|
38
|
+
}
|
|
39
|
+
function Prices({ item, ctx }) {
|
|
40
|
+
if (item.prices.length === 1 && !item.prices[0].label)
|
|
41
|
+
return _jsx(Price, { price: item.prices[0], ctx: ctx, className: "font-medium" });
|
|
42
|
+
return (_jsx("span", { className: "flex flex-wrap justify-end gap-x-4 gap-y-1", children: item.prices.slice(0, 4).map((p, i) => (_jsxs("span", { className: "inline-flex items-baseline gap-1.5 whitespace-nowrap", children: [p.label ? _jsx("span", { className: "text-xs text-fg-muted", children: p.label }) : null, _jsx(Price, { price: p, ctx: ctx, className: "font-medium" })] }, i))) }));
|
|
43
|
+
}
|
|
44
|
+
function Tags({ item, ctx }) {
|
|
45
|
+
const words = [
|
|
46
|
+
...(item.unavailable ? [_jsx("span", { className: "text-fg", children: ctx.t("unavailable") }, "u")] : []),
|
|
47
|
+
...(item.tags ?? []).map((tag) => (_jsx("span", { className: "text-accent-ink", children: ctx.t(TAG_KEY[tag]) }, tag))),
|
|
48
|
+
];
|
|
49
|
+
if (!words.length)
|
|
50
|
+
return null;
|
|
51
|
+
return (_jsx("span", { className: "flex flex-wrap gap-x-3 gap-y-1 font-mono text-eyebrow uppercase tracking-[0.06em]", children: words }));
|
|
52
|
+
}
|
|
53
|
+
function Allergens({ item, ctx }) {
|
|
54
|
+
if (!ctx.showAllergens || !item.allergens?.length)
|
|
55
|
+
return null;
|
|
56
|
+
return (_jsxs("p", { className: "text-xs text-fg-muted", children: [_jsxs("span", { className: "font-medium", children: [ctx.t("allergens"), ":"] }), " ", item.allergens.map((a) => ctx.t(`allergen_${a}`)).join(", ")] }));
|
|
57
|
+
}
|
|
58
|
+
function DishItem({ item, ctx }) {
|
|
59
|
+
const photo = ctx.variant === "photo";
|
|
60
|
+
return (_jsxs("li", { "data-unavailable": item.unavailable ? "" : undefined, className: cn("vb-menu-item flex gap-4", item.unavailable && "opacity-70"), children: [photo ? (item.image?.src ? (_jsx(BlockImage, { ...item.image, alt: item.image.alt ?? "", decorative: !item.image.alt, aspect: "1:1", sizes: "72px", className: "size-[72px] shrink-0 rounded-ui-sm", components: ctx.components })) : (_jsx("span", { "aria-hidden": true, className: "size-[72px] shrink-0" }))) : null, _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [_jsxs("div", { className: "flex items-baseline gap-3", children: [_jsx("h4", { className: "text-body font-medium text-fg", children: item.name }), !photo ? _jsx("span", { "aria-hidden": true, className: "vb-leader min-w-6 flex-1 translate-y-[-0.3em] border-b border-dotted border-fg-subtle" }) : _jsx("span", { className: "flex-1" }), _jsx(Prices, { item: item, ctx: ctx })] }), item.description ? _jsx("p", { className: "max-w-[56ch] text-small text-fg-muted text-pretty", children: item.description }) : null, _jsx(Tags, { item: item, ctx: ctx }), _jsx(Allergens, { item: item, ctx: ctx })] })] }));
|
|
61
|
+
}
|
|
62
|
+
function ServiceRow({ item, ctx }) {
|
|
63
|
+
const href = item.bookHref ?? ctx.bookHref;
|
|
64
|
+
const name = textOf(item.name);
|
|
65
|
+
return (_jsxs("li", { "data-unavailable": item.unavailable ? "" : undefined, className: "grid gap-x-(--gutter) gap-y-2 border-b border-line py-5 first:border-t @2xl:grid-cols-12 @2xl:items-baseline", children: [_jsxs("div", { className: "flex flex-col gap-1.5 @2xl:col-span-6", children: [_jsx("h4", { className: "text-body font-medium text-fg", children: item.name }), item.description ? _jsx("p", { className: "text-small text-fg-muted text-pretty", children: item.description }) : null, _jsx(Tags, { item: item, ctx: ctx })] }), _jsx("p", { className: "font-mono text-eyebrow uppercase tracking-[0.06em] text-fg-muted @2xl:col-span-2", children: item.prices.length === 1 ? item.duration : null }), _jsx("div", { className: "@2xl:col-span-3 @2xl:text-end", children: _jsx(Prices, { item: item, ctx: ctx }) }), _jsx("div", { className: "@2xl:col-span-1 @2xl:text-end", children: href && !item.unavailable ? (_jsx(BlockLink, { href: href, components: ctx.components, labels: ctx.labels, locale: ctx.locale, "aria-label": name ? ctx.t("bookService", { service: name }) : undefined, className: "text-small font-medium text-fg underline decoration-line underline-offset-[0.25em] hover:decoration-current focus-ring rounded-[2px]", "data-track": "book", children: ctx.t("book") })) : null })] }));
|
|
66
|
+
}
|
|
67
|
+
/** schema.org `Menu` → `MenuSection` → `MenuItem` + `Offer`. */
|
|
68
|
+
export function menuJsonLd(props) {
|
|
69
|
+
return {
|
|
70
|
+
"@type": "Menu",
|
|
71
|
+
name: props.name,
|
|
72
|
+
hasMenuSection: props.categories.map((c) => ({
|
|
73
|
+
"@type": "MenuSection",
|
|
74
|
+
name: textOf(c.title),
|
|
75
|
+
hasMenuItem: c.items.map((i) => ({
|
|
76
|
+
"@type": "MenuItem",
|
|
77
|
+
name: textOf(i.name),
|
|
78
|
+
description: textOf(i.description) || undefined,
|
|
79
|
+
offers: i.prices.filter((p) => p.amount).map((p) => ({ "@type": "Offer", price: p.amount.amount, priceCurrency: p.amount.currency, name: textOf(p.label) || undefined })),
|
|
80
|
+
suitableForDiet: (i.tags ?? []).flatMap((tag) => (tag === "vegan" ? ["https://schema.org/VeganDiet"] : tag === "vegetarian" ? ["https://schema.org/VegetarianDiet"] : tag === "gluten-free" ? ["https://schema.org/GlutenFreeDiet"] : [])),
|
|
81
|
+
})),
|
|
82
|
+
})),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface NavbarSubmenuProps {
|
|
3
|
+
/** Trigger text. */
|
|
4
|
+
label: React.ReactNode;
|
|
5
|
+
/** Server-rendered links (the panel content). */
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
/** The current page lives in this group (`aria-current` styling on the trigger). */
|
|
8
|
+
active?: boolean;
|
|
9
|
+
/** Wide panel with descriptions. */
|
|
10
|
+
wide?: boolean;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Disclosure-pattern dropdown for navbar groups (~1 KB island; only rendered when an item has
|
|
15
|
+
* children). Click / Enter / Space toggles, Escape closes and returns focus, focus or a click
|
|
16
|
+
* leaving the group closes it, ArrowDown opens and moves into the panel.
|
|
17
|
+
*/
|
|
18
|
+
export declare function NavbarSubmenu({ label, children, active, wide, className }: NavbarSubmenuProps): React.JSX.Element;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { ChevronDown } from "lucide-react";
|
|
5
|
+
import { cn } from "../../lib/cn.js";
|
|
6
|
+
/**
|
|
7
|
+
* Disclosure-pattern dropdown for navbar groups (~1 KB island; only rendered when an item has
|
|
8
|
+
* children). Click / Enter / Space toggles, Escape closes and returns focus, focus or a click
|
|
9
|
+
* leaving the group closes it, ArrowDown opens and moves into the panel.
|
|
10
|
+
*/
|
|
11
|
+
export function NavbarSubmenu({ label, children, active, wide, className }) {
|
|
12
|
+
const [open, setOpen] = React.useState(false);
|
|
13
|
+
const root = React.useRef(null);
|
|
14
|
+
const trigger = React.useRef(null);
|
|
15
|
+
const panelId = React.useId();
|
|
16
|
+
React.useEffect(() => {
|
|
17
|
+
if (!open)
|
|
18
|
+
return;
|
|
19
|
+
const onDown = (e) => {
|
|
20
|
+
if (!root.current?.contains(e.target))
|
|
21
|
+
setOpen(false);
|
|
22
|
+
};
|
|
23
|
+
document.addEventListener("pointerdown", onDown);
|
|
24
|
+
return () => document.removeEventListener("pointerdown", onDown);
|
|
25
|
+
}, [open]);
|
|
26
|
+
const links = () => Array.from(root.current?.querySelectorAll("[data-nav-panel] a[href]") ?? []);
|
|
27
|
+
return (_jsxs("div", { ref: root, className: cn("relative", className), "data-state": open ? "open" : "closed", onKeyDown: (e) => {
|
|
28
|
+
if (e.key === "Escape" && open) {
|
|
29
|
+
e.stopPropagation();
|
|
30
|
+
setOpen(false);
|
|
31
|
+
trigger.current?.focus();
|
|
32
|
+
}
|
|
33
|
+
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
34
|
+
const list = links();
|
|
35
|
+
if (!list.length)
|
|
36
|
+
return;
|
|
37
|
+
e.preventDefault();
|
|
38
|
+
if (!open) {
|
|
39
|
+
setOpen(true);
|
|
40
|
+
requestAnimationFrame(() => links()[0]?.focus());
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const i = list.indexOf(document.activeElement);
|
|
44
|
+
const next = e.key === "ArrowDown" ? (i + 1) % list.length : i <= 0 ? list.length - 1 : i - 1;
|
|
45
|
+
list[next]?.focus();
|
|
46
|
+
}
|
|
47
|
+
}, onBlur: (e) => {
|
|
48
|
+
if (open && !root.current?.contains(e.relatedTarget))
|
|
49
|
+
setOpen(false);
|
|
50
|
+
}, children: [_jsxs("button", { ref: trigger, type: "button", "aria-expanded": open, "aria-controls": panelId, "data-active": active ? "" : undefined, className: "vb-nav-link inline-flex items-center gap-1", onClick: () => setOpen((o) => !o), children: [label, _jsx(ChevronDown, { "aria-hidden": true, strokeWidth: 1.5, className: cn("size-3.5 transition-transform duration-200", open && "rotate-180") })] }), _jsx("div", { id: panelId, "data-nav-panel": "", "data-state": open ? "open" : "closed", hidden: !open, className: cn("surface-popover absolute start-0 top-[calc(100%+0.75rem)] z-(--z-popover) rounded-ui p-2 ui-pop", wide ? "w-[min(34rem,80vw)]" : "w-60"), children: children })] }));
|
|
51
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { BlockBaseProps } from "../types.js";
|
|
3
|
+
import { type SiteBlockLabels, type SiteCta, type SiteImage, type SiteMeta } from "./_kit-1.js";
|
|
4
|
+
export type NavbarVariant = "bar" | "split" | "minimal" | "rail";
|
|
5
|
+
export interface NavbarLink {
|
|
6
|
+
label: React.ReactNode;
|
|
7
|
+
href: string;
|
|
8
|
+
/** One line under the label in a submenu ("Weekly menus from the pass"). */
|
|
9
|
+
description?: React.ReactNode;
|
|
10
|
+
newTab?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface NavbarItem extends NavbarLink {
|
|
13
|
+
/** Submenu links (≤ 8). Desktop: a disclosure dropdown island; mobile: an indented list. */
|
|
14
|
+
children?: NavbarLink[];
|
|
15
|
+
}
|
|
16
|
+
export interface NavbarLocale {
|
|
17
|
+
/** "en", "tr" — shown uppercase. */
|
|
18
|
+
code: string;
|
|
19
|
+
href: string;
|
|
20
|
+
/** Marks the active language. Default: `code` matches the `locale` prop. */
|
|
21
|
+
current?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface NavbarProps extends Omit<BlockBaseProps, "variant" | "labels"> {
|
|
24
|
+
/**
|
|
25
|
+
* bar: logo, links beside it, phone + one CTA at the end.
|
|
26
|
+
* split: logo dead centre, links on both sides, CTA as a text link at the far end.
|
|
27
|
+
* minimal: wordmark + "Menu" + CTA; a full-screen menu with display-size links.
|
|
28
|
+
* rail: links inside one framed pill in the middle, "Sign in" + "Try free" at the end.
|
|
29
|
+
*/
|
|
30
|
+
variant?: NavbarVariant;
|
|
31
|
+
logo?: SiteImage;
|
|
32
|
+
/** Shown instead of `logo` inside dark sections / dark mode. */
|
|
33
|
+
logoDark?: SiteImage;
|
|
34
|
+
/** Text mark when there's no logo (or beside it in `minimal`). */
|
|
35
|
+
wordmark?: React.ReactNode;
|
|
36
|
+
/** Brand link. Default `"/"`. */
|
|
37
|
+
homeHref?: string;
|
|
38
|
+
items?: NavbarItem[];
|
|
39
|
+
/** Up to two calls to action; one primary. */
|
|
40
|
+
actions?: SiteCta[];
|
|
41
|
+
/** E.164 (`+902160000000`). Shown in national format, dialled as `tel:`. */
|
|
42
|
+
phone?: string;
|
|
43
|
+
locales?: NavbarLocale[];
|
|
44
|
+
/** Stick to the top; the background fills in as the page scrolls (CSS scroll timeline). */
|
|
45
|
+
sticky?: boolean;
|
|
46
|
+
/** Start transparent with light text over a full-bleed hero. */
|
|
47
|
+
overlay?: boolean;
|
|
48
|
+
/** Path of the current page → `aria-current="page"`. */
|
|
49
|
+
currentPath?: string;
|
|
50
|
+
/** Facts at the bottom of the full-screen menu (address, hours). */
|
|
51
|
+
panelMeta?: SiteMeta[];
|
|
52
|
+
/** Render the "Skip to content" link first. Default true. */
|
|
53
|
+
skipLink?: boolean;
|
|
54
|
+
labels?: SiteBlockLabels;
|
|
55
|
+
}
|
|
56
|
+
/** National format in the number's own locale, international elsewhere ("0216 000 00 00" for tr). */
|
|
57
|
+
export declare function formatSitePhone(e164: string, locale?: string): string;
|
|
58
|
+
/**
|
|
59
|
+
* Site top navigation in four characters. Server component: the mobile menu is a native
|
|
60
|
+
* `popover` (0 JS), submenus a tiny disclosure island, the scrolled background a CSS scroll
|
|
61
|
+
* timeline.
|
|
62
|
+
*
|
|
63
|
+
* ```tsx
|
|
64
|
+
* <Navbar wordmark="Kıyı" items={[{ label: "Menu", href: "/menu" }]} actions={[{ link: { href: "/book", label: "Book a table" }, style: "primary" }]} sticky />
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function Navbar({ variant, logo, logoDark, wordmark, homeHref, items, actions, phone, locales, sticky, overlay, currentPath, panelMeta, skipLink, id, anchor, className, labels, locale, components, editMode, }: NavbarProps): React.JSX.Element;
|