@vamos-ui/react 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/blocks/block-heading.js +1 -1
- package/dist/blocks/block-link.js +1 -1
- package/dist/blocks/index.d.ts +3 -3
- package/dist/blocks/index.js +3 -3
- package/dist/blocks/labels.d.ts +8 -0
- package/dist/blocks/labels.js +60 -0
- package/dist/blocks/section-header.js +1 -1
- package/dist/blocks/section.js +2 -2
- package/dist/blocks/site/feature-tabs.js +1 -1
- package/dist/blocks/site/footer.d.ts +10 -1
- package/dist/blocks/site/footer.js +28 -4
- package/dist/blocks/site/registry-2.js +3 -1
- package/dist/blocks/site/shared/labels-2.d.ts +8 -0
- package/dist/blocks/site/shared/labels-2.js +808 -0
- package/dist/blocks/site/site-shell.js +3 -3
- package/dist/business/approval-flow.js +2 -2
- package/dist/business/import-wizard.js +1 -1
- package/dist/business/line-items.js +1 -1
- package/dist/business/multi-step-form.js +2 -2
- package/dist/business/permission-matrix.js +1 -1
- package/dist/business/setup-checklist.js +2 -2
- package/dist/business/signer-status.js +1 -1
- package/dist/charts/bar-list.js +1 -1
- package/dist/charts/chart-shell.js +1 -1
- package/dist/charts/donut-chart.js +1 -1
- package/dist/charts/funnel.js +1 -1
- package/dist/charts/gauge.js +2 -2
- package/dist/components/accordion.d.ts +1 -1
- package/dist/components/accordion.js +8 -8
- package/dist/components/activity-timeline.js +6 -6
- package/dist/components/address-field.js +3 -3
- package/dist/components/alert-dialog.d.ts +1 -1
- package/dist/components/alert-dialog.js +8 -8
- package/dist/components/alert.js +2 -2
- package/dist/components/app-shell.js +3 -3
- package/dist/components/aspect-ratio.js +2 -2
- package/dist/components/attachment-list.js +2 -2
- package/dist/components/audit-log.js +1 -1
- package/dist/components/avatar.d.ts +1 -1
- package/dist/components/avatar.js +8 -8
- package/dist/components/backup-codes.js +1 -1
- package/dist/components/badge.js +3 -3
- package/dist/components/breadcrumb.js +10 -9
- package/dist/components/button-group.js +4 -4
- package/dist/components/button.js +4 -4
- package/dist/components/calendar.js +5 -5
- package/dist/components/card.js +8 -8
- package/dist/components/carousel.js +9 -9
- package/dist/components/checkbox.d.ts +1 -1
- package/dist/components/checkbox.js +6 -6
- package/dist/components/collapsible.d.ts +1 -1
- package/dist/components/collapsible.js +4 -4
- package/dist/components/color-picker.js +3 -3
- package/dist/components/combobox.js +1 -1
- package/dist/components/command.js +9 -9
- package/dist/components/comment-thread.js +3 -3
- package/dist/components/context-menu.d.ts +1 -1
- package/dist/components/context-menu.js +9 -9
- package/dist/components/currency-input.js +1 -1
- package/dist/components/date-picker.js +2 -2
- package/dist/components/date-range-picker.js +1 -1
- package/dist/components/description-list.js +2 -2
- package/dist/components/dialog.d.ts +1 -1
- package/dist/components/dialog.js +9 -9
- package/dist/components/dropdown-menu.d.ts +1 -1
- package/dist/components/dropdown-menu.js +9 -9
- package/dist/components/editor-layout.js +9 -9
- package/dist/components/empty-state.js +2 -2
- package/dist/components/entity-card.js +1 -1
- package/dist/components/file-upload.js +5 -5
- package/dist/components/formatted-input.js +3 -3
- package/dist/components/hierarchy-chart.js +1 -1
- package/dist/components/hover-card.d.ts +1 -1
- package/dist/components/hover-card.js +3 -3
- package/dist/components/iban-input.js +1 -1
- package/dist/components/id-input.js +3 -3
- package/dist/components/image.js +5 -5
- package/dist/components/input-otp.js +6 -6
- package/dist/components/input.d.ts +1 -1
- package/dist/components/input.js +6 -6
- package/dist/components/item.js +4 -4
- package/dist/components/kbd.js +3 -3
- package/dist/components/list-layout.js +9 -9
- package/dist/components/menubar.d.ts +1 -1
- package/dist/components/menubar.js +12 -12
- package/dist/components/native-select.js +1 -1
- package/dist/components/navigation-menu.d.ts +1 -1
- package/dist/components/navigation-menu.js +12 -11
- package/dist/components/notification-center.js +4 -4
- package/dist/components/page-header.js +3 -3
- package/dist/components/pagination.js +9 -9
- package/dist/components/phone-input.js +1 -1
- package/dist/components/pin-map.js +1 -1
- package/dist/components/placeholder-art.js +1 -1
- package/dist/components/popover.d.ts +1 -1
- package/dist/components/popover.js +7 -7
- package/dist/components/progress.js +3 -3
- package/dist/components/qr-code.js +1 -1
- package/dist/components/radio-group.d.ts +1 -1
- package/dist/components/radio-group.js +4 -4
- package/dist/components/record-detail-layout.js +10 -10
- package/dist/components/record-picker.js +2 -2
- package/dist/components/resizable.js +2 -2
- package/dist/components/scroll-area.d.ts +1 -1
- package/dist/components/scroll-area.js +4 -4
- package/dist/components/select.d.ts +1 -1
- package/dist/components/select.js +10 -10
- package/dist/components/separator.d.ts +1 -1
- package/dist/components/separator.js +3 -3
- package/dist/components/settings-layout.js +6 -6
- package/dist/components/sheet.js +3 -3
- package/dist/components/sidebar.js +12 -11
- package/dist/components/signature-pad.js +1 -1
- package/dist/components/skeleton.js +5 -5
- package/dist/components/sla-timer.js +2 -2
- package/dist/components/slider.d.ts +1 -1
- package/dist/components/slider.js +2 -2
- package/dist/components/slug-input.js +1 -1
- package/dist/components/sparkline.js +1 -1
- package/dist/components/spinner.js +2 -2
- package/dist/components/stat.js +5 -5
- package/dist/components/status-picker.js +2 -2
- package/dist/components/stepper.js +1 -1
- package/dist/components/switch.d.ts +1 -1
- package/dist/components/switch.js +3 -3
- package/dist/components/table.js +10 -10
- package/dist/components/tabs.d.ts +1 -1
- package/dist/components/tabs.js +11 -11
- package/dist/components/tag-input.js +1 -1
- package/dist/components/task-list.js +1 -1
- package/dist/components/time-picker.js +3 -3
- package/dist/components/toggle.d.ts +2 -1
- package/dist/components/toggle.js +7 -6
- package/dist/components/tooltip.d.ts +1 -1
- package/dist/components/tooltip.js +5 -4
- package/dist/components/top-bar.js +4 -4
- package/dist/components/tour.js +1 -1
- package/dist/components/tree-select.js +2 -2
- package/dist/components/tree-view.js +3 -3
- package/dist/components/typography.js +11 -11
- package/dist/components/user-picker.js +2 -2
- package/dist/components/version-history.js +3 -3
- package/dist/data-table/data-table.js +1 -1
- package/dist/data-table/filter-bar.js +2 -2
- package/dist/data-table/index.d.ts +15 -8
- package/dist/data-table/index.js +9 -8
- package/dist/data-table/saved-views.js +1 -1
- package/dist/editor/block-editor.js +1 -1
- package/dist/editor/context.js +1 -1
- package/dist/editor/menus.js +1 -1
- package/dist/fonts/font-picker.js +3 -3
- package/dist/fonts/pairing-picker.js +1 -1
- package/dist/fonts/provider.js +1 -1
- package/dist/index.d.ts +188 -94
- package/dist/index.js +94 -94
- package/dist/lib/data-islands.js +1 -1
- package/dist/lib/field-context.js +1 -1
- package/dist/lib/floating-arrow.js +1 -1
- package/dist/lib/islands.js +1 -1
- package/dist/lib/layer.js +3 -3
- package/dist/lib/locale.js +2 -2
- package/dist/lib/menu.js +2 -2
- package/dist/lib/provider.js +4 -4
- package/dist/lib/theme-scope.js +4 -3
- package/dist/lib/variants.js +2 -2
- package/dist/media/focal-point.js +1 -1
- package/dist/media/gallery.js +1 -1
- package/dist/media/image-cropper.js +1 -1
- package/dist/media/image-field.js +2 -2
- package/dist/media/lightbox.js +4 -3
- package/dist/media/link-preview.js +3 -3
- package/dist/media/media-library.js +3 -3
- package/dist/media/media-picker.js +1 -1
- package/dist/media/media-provider.js +1 -1
- package/dist/media/video-player.js +4 -4
- package/dist/motion/count-up.js +1 -1
- package/dist/motion/motion-scope.js +2 -2
- package/dist/motion/page-transition.js +1 -1
- package/dist/motion/parallax.js +2 -2
- package/dist/motion/pointer.js +3 -3
- package/dist/motion/reveal.js +3 -3
- package/dist/motion/skeleton-swap.js +1 -1
- package/dist/motion/text-reveal.js +1 -1
- package/dist/motion/ticker.js +1 -1
- package/dist/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/dist/scheduler/gantt.js +2 -2
- package/dist/scheduler/resource-calendar.js +2 -2
- package/dist/scheduler/scheduler.js +3 -3
- package/dist/scheduler/time-tracker.js +4 -4
- package/dist/sortable/kanban.js +2 -2
- package/dist/sortable/sortable-list.js +2 -2
- package/dist/sortable/sortable.js +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,10 @@ export default function Page() {
|
|
|
23
23
|
}
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
Next.js with webpack (`next build --webpack`, the Next.js 15 default): add
|
|
27
|
+
`experimental: { optimizePackageImports: ["@vamos-ui/react"] }` to next.config, or a Server Component
|
|
28
|
+
that imports from the package root ships every client component. Turbopack and Vite need nothing.
|
|
29
|
+
|
|
26
30
|
Prefer to own the source? Copy single components with the CLI: `npx vamos-ui add button`.
|
|
27
31
|
|
|
28
32
|
MIT licensed. “Vamos UI” and the logo are trademarks of Vamos.
|
|
@@ -29,7 +29,7 @@ export function renderEmphasis(text) {
|
|
|
29
29
|
* <BlockHeading level={1} size="display-xl" text="Dinner, *slowly*." />
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
32
|
-
export const BlockHeading = React.forwardRef(function BlockHeading({ text, children, level = 2, size = "display-m", editMode, field, labels, locale, className, ...props }, ref) {
|
|
32
|
+
export const BlockHeading = /*#__PURE__*/ React.forwardRef(function BlockHeading({ text, children, level = 2, size = "display-m", editMode, field, labels, locale, className, ...props }, ref) {
|
|
33
33
|
const Tag = `h${level}`;
|
|
34
34
|
const content = children ?? renderEmphasis(text);
|
|
35
35
|
const empty = content === undefined || content === null || content === "";
|
|
@@ -14,7 +14,7 @@ import { isExternalUrl, sanitizeHref } from "./schema/safety.js";
|
|
|
14
14
|
* <BlockLink href="https://maps.app.goo.gl/x" newTab>Directions</BlockLink>
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
|
-
export const BlockLink = React.forwardRef(function BlockLink({ href, newTab, appearance, size = "lg", components, labels, locale, field, editMode, className, children, rel, target, ...props }, ref) {
|
|
17
|
+
export const BlockLink = /*#__PURE__*/ React.forwardRef(function BlockLink({ href, newTab, appearance, size = "lg", components, labels, locale, field, editMode, className, children, rel, target, ...props }, ref) {
|
|
18
18
|
const safe = sanitizeHref(href);
|
|
19
19
|
const classes = cn(appearance === "link" ? "inline-flex min-h-6 pointer-coarse:min-h-11 items-center gap-1.5 font-medium text-fg underline decoration-line underline-offset-[0.3em] transition-colors hover:decoration-current focus-ring rounded-[2px]" : null, appearance && appearance !== "link" ? cn(buttonVariants({ variant: appearance, size }), appearance === "primary" && "vb-action-primary", appearance === "secondary" && "vb-action-secondary") : null, className);
|
|
20
20
|
const fieldAttr = editMode && field ? { "data-field": field } : undefined;
|
package/dist/blocks/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export { BlockLink, type BlockLinkProps } from "./block-link.js";
|
|
|
6
6
|
export { RichText, renderInline, renderRichBlocks, type RichTextProps, type RichTextRenderOptions } from "./rich-text.js";
|
|
7
7
|
export { JsonLd, mergeJsonLd, serializeJsonLd, type JsonLdProps, type JsonLdNode } from "./json-ld.js";
|
|
8
8
|
export { createBlocks, fieldAttrs, type CreateBlocksOptions, type BoundBlocks } from "./create-blocks.js";
|
|
9
|
-
export { blockLabels, blockLabelsTr, blockText, type BlockLabels } from "./labels.js";
|
|
9
|
+
export { blockLabels, blockLabelsTr, blockLabelsDe, blockLabelsFr, blockLabelsEs, blockLabelsAr, blockText, type BlockLabels } from "./labels.js";
|
|
10
10
|
export type { BlockAdapters, BlockBaseProps, BlockComponentProps, BlockRuntime, ImageData, LinkData } from "./types.js";
|
|
11
11
|
export { parseEmphasis, stripEmphasis, type EmphasisPart } from "./schema/emphasis.js";
|
|
12
12
|
export { sanitizeHref, isExternalUrl, linkKindOf } from "./schema/safety.js";
|
|
@@ -40,7 +40,7 @@ export { GallerySection, type GallerySectionProps, type GalleryVariant, type Gal
|
|
|
40
40
|
export { ConsentBanner, ConsentDefaults, type ConsentBannerProps, type ConsentVariant } from "./site/consent-banner.js";
|
|
41
41
|
export { ContactDock, type ContactDockProps, type ContactDockVariant, type DockAction, type MessagingProvider } from "./site/contact-dock.js";
|
|
42
42
|
export { EmbedFacade, type EmbedFacadeProps } from "./site/embed-facade.js";
|
|
43
|
-
export { Footer, type FooterProps, type FooterVariant } from "./site/footer.js";
|
|
43
|
+
export { Footer, footerJsonLd, type FooterProps, type FooterVariant } from "./site/footer.js";
|
|
44
44
|
export { NotFound, type NotFoundProps, type NotFoundVariant, type NotFoundKind } from "./site/not-found.js";
|
|
45
45
|
export { isOpenAt, hoursStatus, hoursOn, weekRows, summarizeHours, orderedWeek, weekStartOf, weekdayName, formatTime, formatRange, zonedMoment, openingHoursJsonLd, describeStatus, timeVars, type OpenStatus, type OpenState, type WeekRow, type DayHours, type ZonedMoment, type Weekday, type TimeRange } from "./site/shared/opening-hours.js";
|
|
46
46
|
export { OpenNow, type OpenNowProps } from "./site/shared/open-now.js";
|
|
@@ -49,7 +49,7 @@ export { ConsentSettingsButton } from "./site/shared/consent-island.js";
|
|
|
49
49
|
export { getConsent, onConsent, readConsent, writeConsent, parseConsent, openConsentPreferences, consentDefaultsScript, consentModeSignals, CONSENT_COOKIE, CONSENT_EVENT, CONSENT_OPEN_EVENT, CONSENT_CATEGORIES, type ConsentCategory, type ConsentRecord, type ConsentChoices } from "./site/shared/consent.js";
|
|
50
50
|
export { validateContactForm, isSpam, contactFieldLabel, HONEYPOT_FIELD, type ContactFieldConfig, type ContactFieldName, type SiteFormState, type SiteFormAction, type ContactValidation } from "./site/shared/site-form.js";
|
|
51
51
|
export { BrandIcon, BRAND_NAMES, type BrandName, type BrandIconProps } from "./site/shared/brand-icons.js";
|
|
52
|
-
export { site2Labels, site2LabelsTr, type Site2Labels, type Site2BlockLabels } from "./site/shared/labels-2.js";
|
|
52
|
+
export { site2Labels, site2LabelsTr, site2LabelsDe, site2LabelsFr, site2LabelsEs, site2LabelsAr, type Site2Labels, type Site2BlockLabels } from "./site/shared/labels-2.js";
|
|
53
53
|
export { SiteShell, SiteShellPage, SiteShellLocale, SiteShellLink, useSiteShell, type SiteShellProps, type SiteShellPageProps, type SiteShellLocaleProps, type SiteShellLinkProps, type SiteShellContextValue } from "./site/site-shell.js";
|
|
54
54
|
export { siteAccent, siteAccentCss, siteAccentKey, isBuiltInAccent, BUILT_IN_SITE_ACCENTS, SITE_TEXT_CONTRAST, type SiteAccentPalette, type SiteAccentOptions } from "./site/shared/site-accent.js";
|
|
55
55
|
export { sitePageHref, siteLocaleHref, parseSiteHref, readSiteLocation, writeSiteLocation, type SiteRouting, type SiteLocation, type SiteRouteParams } from "./site/shared/site-routing.js";
|
package/dist/blocks/index.js
CHANGED
|
@@ -8,7 +8,7 @@ export { BlockLink } from "./block-link.js";
|
|
|
8
8
|
export { RichText, renderInline, renderRichBlocks } from "./rich-text.js";
|
|
9
9
|
export { JsonLd, mergeJsonLd, serializeJsonLd } from "./json-ld.js";
|
|
10
10
|
export { createBlocks, fieldAttrs } from "./create-blocks.js";
|
|
11
|
-
export { blockLabels, blockLabelsTr, blockText } from "./labels.js";
|
|
11
|
+
export { blockLabels, blockLabelsTr, blockLabelsDe, blockLabelsFr, blockLabelsEs, blockLabelsAr, blockText } from "./labels.js";
|
|
12
12
|
// Pure helpers (no zod) re-exported for components
|
|
13
13
|
export { parseEmphasis, stripEmphasis } from "./schema/emphasis.js";
|
|
14
14
|
export { sanitizeHref, isExternalUrl, linkKindOf } from "./schema/safety.js";
|
|
@@ -42,7 +42,7 @@ export { GallerySection } from "./site/gallery-section.js";
|
|
|
42
42
|
export { ConsentBanner, ConsentDefaults } from "./site/consent-banner.js";
|
|
43
43
|
export { ContactDock } from "./site/contact-dock.js";
|
|
44
44
|
export { EmbedFacade } from "./site/embed-facade.js";
|
|
45
|
-
export { Footer } from "./site/footer.js";
|
|
45
|
+
export { Footer, footerJsonLd } from "./site/footer.js";
|
|
46
46
|
export { NotFound } from "./site/not-found.js";
|
|
47
47
|
// Shared modules: opening hours, consent, form contract, brand marks, labels
|
|
48
48
|
export { isOpenAt, hoursStatus, hoursOn, weekRows, summarizeHours, orderedWeek, weekStartOf, weekdayName, formatTime, formatRange, zonedMoment, openingHoursJsonLd, describeStatus, timeVars } from "./site/shared/opening-hours.js";
|
|
@@ -52,7 +52,7 @@ export { ConsentSettingsButton } from "./site/shared/consent-island.js";
|
|
|
52
52
|
export { getConsent, onConsent, readConsent, writeConsent, parseConsent, openConsentPreferences, consentDefaultsScript, consentModeSignals, CONSENT_COOKIE, CONSENT_EVENT, CONSENT_OPEN_EVENT, CONSENT_CATEGORIES } from "./site/shared/consent.js";
|
|
53
53
|
export { validateContactForm, isSpam, contactFieldLabel, HONEYPOT_FIELD } from "./site/shared/site-form.js";
|
|
54
54
|
export { BrandIcon, BRAND_NAMES } from "./site/shared/brand-icons.js";
|
|
55
|
-
export { site2Labels, site2LabelsTr } from "./site/shared/labels-2.js";
|
|
55
|
+
export { site2Labels, site2LabelsTr, site2LabelsDe, site2LabelsFr, site2LabelsEs, site2LabelsAr } from "./site/shared/labels-2.js";
|
|
56
56
|
// Site shell: locale switch, inner pages and a scoped accent for whole-site blocks
|
|
57
57
|
export { SiteShell, SiteShellPage, SiteShellLocale, SiteShellLink, useSiteShell } from "./site/site-shell.js";
|
|
58
58
|
export { siteAccent, siteAccentCss, siteAccentKey, isBuiltInAccent, BUILT_IN_SITE_ACCENTS, SITE_TEXT_CONTRAST } from "./site/shared/site-accent.js";
|
package/dist/blocks/labels.d.ts
CHANGED
|
@@ -16,5 +16,13 @@ export declare const blockLabels: {
|
|
|
16
16
|
export type BlockLabels = typeof blockLabels;
|
|
17
17
|
/** Turkish dictionary for site blocks. */
|
|
18
18
|
export declare const blockLabelsTr: BlockLabels;
|
|
19
|
+
/** German dictionary for site blocks. */
|
|
20
|
+
export declare const blockLabelsDe: BlockLabels;
|
|
21
|
+
/** French dictionary for site blocks. */
|
|
22
|
+
export declare const blockLabelsFr: BlockLabels;
|
|
23
|
+
/** Spanish dictionary for site blocks. */
|
|
24
|
+
export declare const blockLabelsEs: BlockLabels;
|
|
25
|
+
/** Arabic dictionary for site blocks. */
|
|
26
|
+
export declare const blockLabelsAr: BlockLabels;
|
|
19
27
|
/** Label lookup for server components: `labels` prop → English. */
|
|
20
28
|
export declare function blockText(labels?: Partial<BlockLabels>, locale?: string): (key: keyof BlockLabels, vars?: Record<string, unknown>) => string;
|
package/dist/blocks/labels.js
CHANGED
|
@@ -30,6 +30,66 @@ export const blockLabelsTr = {
|
|
|
30
30
|
emptyImage: "Görsel yok",
|
|
31
31
|
codeSample: "Kod örneği",
|
|
32
32
|
};
|
|
33
|
+
/** German dictionary for site blocks. */
|
|
34
|
+
export const blockLabelsDe = {
|
|
35
|
+
opensInNewTab: "(öffnet in einem neuen Tab)",
|
|
36
|
+
skipToContent: "Zum Inhalt springen",
|
|
37
|
+
addTitle: "Titel hinzufügen",
|
|
38
|
+
addText: "Text hinzufügen",
|
|
39
|
+
addImage: "Bild hinzufügen",
|
|
40
|
+
unknownBlock: "Unbekannter Block „{type}“",
|
|
41
|
+
unknownBlockHint: "Dieser Blocktyp ist nicht installiert. Sein Inhalt bleibt erhalten und wird wieder angezeigt, sobald der Block verfügbar ist.",
|
|
42
|
+
invalidBlock: "„{type}“ enthält ungültige Inhalte",
|
|
43
|
+
invalidBlockHint: "{count, plural, one {# Feld wurde} other {# Felder wurden}} durch Standardwerte ersetzt. Korrigieren Sie sie im Editor.",
|
|
44
|
+
newerBlock: "„{type}“ wurde mit einer neueren Version gespeichert (v{v})",
|
|
45
|
+
emptyImage: "Kein Bild",
|
|
46
|
+
codeSample: "Codebeispiel",
|
|
47
|
+
};
|
|
48
|
+
/** French dictionary for site blocks. */
|
|
49
|
+
export const blockLabelsFr = {
|
|
50
|
+
opensInNewTab: "(s’ouvre dans un nouvel onglet)",
|
|
51
|
+
skipToContent: "Aller au contenu",
|
|
52
|
+
addTitle: "Ajouter un titre",
|
|
53
|
+
addText: "Ajouter du texte",
|
|
54
|
+
addImage: "Ajouter une image",
|
|
55
|
+
unknownBlock: "Bloc inconnu « {type} »",
|
|
56
|
+
unknownBlockHint: "Ce type de bloc n’est pas installé. Son contenu est conservé et s’affichera de nouveau dès que le bloc sera disponible.",
|
|
57
|
+
invalidBlock: "« {type} » contient des données non valides",
|
|
58
|
+
invalidBlockHint: "{count, plural, one {# champ a été remplacé} other {# champs ont été remplacés}} par les valeurs par défaut. Corrigez-les dans l’éditeur.",
|
|
59
|
+
newerBlock: "« {type} » a été enregistré avec une version plus récente (v{v})",
|
|
60
|
+
emptyImage: "Aucune image",
|
|
61
|
+
codeSample: "Exemple de code",
|
|
62
|
+
};
|
|
63
|
+
/** Spanish dictionary for site blocks. */
|
|
64
|
+
export const blockLabelsEs = {
|
|
65
|
+
opensInNewTab: "(se abre en una pestaña nueva)",
|
|
66
|
+
skipToContent: "Saltar al contenido",
|
|
67
|
+
addTitle: "Añade un título",
|
|
68
|
+
addText: "Añade texto",
|
|
69
|
+
addImage: "Añade una imagen",
|
|
70
|
+
unknownBlock: "Bloque desconocido «{type}»",
|
|
71
|
+
unknownBlockHint: "Este tipo de bloque no está instalado. Su contenido se conserva y volverá a mostrarse cuando el bloque esté disponible.",
|
|
72
|
+
invalidBlock: "«{type}» tiene contenido no válido",
|
|
73
|
+
invalidBlockHint: "{count, plural, one {Se ha sustituido # campo} other {Se han sustituido # campos}} por valores predeterminados. Corrígelos en el editor.",
|
|
74
|
+
newerBlock: "«{type}» se guardó con una versión más reciente (v{v})",
|
|
75
|
+
emptyImage: "Sin imagen",
|
|
76
|
+
codeSample: "Ejemplo de código",
|
|
77
|
+
};
|
|
78
|
+
/** Arabic dictionary for site blocks. */
|
|
79
|
+
export const blockLabelsAr = {
|
|
80
|
+
opensInNewTab: "(يُفتح في علامة تبويب جديدة)",
|
|
81
|
+
skipToContent: "انتقل إلى المحتوى",
|
|
82
|
+
addTitle: "أضف عنوانًا",
|
|
83
|
+
addText: "أضف نصًا",
|
|
84
|
+
addImage: "أضف صورة",
|
|
85
|
+
unknownBlock: "كتلة غير معروفة «{type}»",
|
|
86
|
+
unknownBlockHint: "نوع الكتلة هذا غير مثبّت. يُحتفظ بمحتواها وستظهر مجددًا عند توفّر الكتلة.",
|
|
87
|
+
invalidBlock: "تحتوي «{type}» على محتوى غير صالح",
|
|
88
|
+
invalidBlockHint: "{count, plural, zero {لم يُستبدل أي حقل} one {استُبدل حقل واحد} two {استُبدل حقلان} few {استُبدلت # حقول} many {استُبدل # حقلًا} other {استُبدل # حقل}} بالقيم الافتراضية. صحّحها في المحرر.",
|
|
89
|
+
newerBlock: "حُفظت «{type}» بإصدار أحدث (v{v})",
|
|
90
|
+
emptyImage: "لا توجد صورة",
|
|
91
|
+
codeSample: "مثال برمجي",
|
|
92
|
+
};
|
|
33
93
|
/** Label lookup for server components: `labels` prop → English. */
|
|
34
94
|
export function blockText(labels, locale = "en-US") {
|
|
35
95
|
const merged = { ...blockLabels };
|
|
@@ -10,7 +10,7 @@ import { BlockHeading, renderEmphasis } from "./block-heading.js";
|
|
|
10
10
|
* <SectionHeader eyebrow="Private dining" title="Rooms for *twelve* or forty" lead="…" align="split" headingId="rooms" />
|
|
11
11
|
* ```
|
|
12
12
|
*/
|
|
13
|
-
export const SectionHeader = React.forwardRef(function SectionHeader({ eyebrow, index, title, lead, actions, align = "start", size = "m", headingLevel = 2, headingId, editMode, labels, locale, className, ...props }, ref) {
|
|
13
|
+
export const SectionHeader = /*#__PURE__*/ React.forwardRef(function SectionHeader({ eyebrow, index, title, lead, actions, align = "start", size = "m", headingLevel = 2, headingId, editMode, labels, locale, className, ...props }, ref) {
|
|
14
14
|
const heading = (_jsx(BlockHeading, { id: headingId, level: headingLevel, size: size === "l" ? "display-l" : "display-m", text: title, editMode: editMode, field: "props.title", labels: labels, locale: locale }));
|
|
15
15
|
const eyebrowEl = eyebrow || index ? (_jsxs("p", { className: cn("flex items-center gap-3 font-mono text-eyebrow uppercase tracking-[0.08em] text-fg-muted", align === "center" && "justify-center"), "data-field": editMode ? "props.eyebrow" : undefined, children: [index ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "tabular text-fg", children: index }), _jsx("span", { "aria-hidden": true, className: "h-px w-6 bg-current opacity-40" })] })) : null, eyebrow ? _jsx("span", { children: renderEmphasis(eyebrow) }) : null] })) : null;
|
|
16
16
|
const leadEl = lead ? (_jsx("p", { className: "vb-lead max-w-(--measure) text-lead text-fg-muted", "data-field": editMode ? "props.lead" : undefined, children: lead })) : null;
|
package/dist/blocks/section.js
CHANGED
|
@@ -46,7 +46,7 @@ export function sectionThemeAttributes(theme) {
|
|
|
46
46
|
* </Section>
|
|
47
47
|
* ```
|
|
48
48
|
*/
|
|
49
|
-
export const Section = React.forwardRef(function Section({ as: Comp = "section", theme, anchor, headingId, blockId, blockType, editMode, priority, components, labels, className, style, children, ...props }, ref) {
|
|
49
|
+
export const Section = /*#__PURE__*/ React.forwardRef(function Section({ as: Comp = "section", theme, anchor, headingId, blockId, blockType, editMode, priority, components, labels, className, style, children, ...props }, ref) {
|
|
50
50
|
const t = sectionThemeAttributes(theme);
|
|
51
51
|
const bg = theme?.surface === "media" ? theme.background : undefined;
|
|
52
52
|
return (_jsxs(Comp, { ref: ref, id: anchor, "aria-labelledby": headingId, className: cn("vb-section", t.className, className), style: t.style || style ? { ...t.style, ...style } : undefined, "data-block-id": editMode ? blockId : undefined, "data-block-type": editMode ? blockType : undefined, ...t.attrs, ...props, children: [bg ? _jsx(SectionMedia, { image: bg, priority: priority, components: components, labels: labels }) : null, children] }));
|
|
@@ -56,7 +56,7 @@ function SectionMedia({ image, priority, components, labels }) {
|
|
|
56
56
|
return (_jsx("div", { className: "vb-section-media", "aria-hidden": "true", children: _jsx(BlockImage, { src: image.src, width: image.width, height: image.height, blurDataURL: image.blurDataURL, focal: image.focal, decorative: true, priority: priority, sizes: "100vw", components: components, labels: labels }) }));
|
|
57
57
|
}
|
|
58
58
|
/** Centres content at a token width with fluid gutters (`--gutter`). Server component. */
|
|
59
|
-
export const Container = React.forwardRef(function Container({ size = "content", className, ...props }, ref) {
|
|
59
|
+
export const Container = /*#__PURE__*/ React.forwardRef(function Container({ size = "content", className, ...props }, ref) {
|
|
60
60
|
return _jsx("div", { ref: ref, "data-size": size === "content" ? undefined : size, className: cn("vb-container", className), ...props });
|
|
61
61
|
});
|
|
62
62
|
/** "Skip to content" — the first focusable element of a site, before the navbar. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import
|
|
3
|
+
import * as Tabs from "radix-ui/tabs";
|
|
4
4
|
import { cn } from "../../lib/cn.js";
|
|
5
5
|
/**
|
|
6
6
|
* Tabs island of the Feature grid `tabs` variant (WAI-ARIA Tabs via Radix, vertical arrow keys).
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { type JsonLdNode } from "../json-ld.js";
|
|
2
3
|
import type { BlockBaseProps } from "../types.js";
|
|
3
4
|
import type { AddressValue, SocialNetwork } from "../schema/types.js";
|
|
4
5
|
import { type Site2BlockLabels } from "./shared/labels-2.js";
|
|
@@ -53,8 +54,16 @@ export interface FooterProps extends Omit<BlockBaseProps, "variant" | "labels" |
|
|
|
53
54
|
};
|
|
54
55
|
/** © year. Default: the render year. */
|
|
55
56
|
year?: number;
|
|
57
|
+
/**
|
|
58
|
+
* Organization JSON-LD built from brand, company, contact and social. Default true. Pass an
|
|
59
|
+
* object to refine it (`{ "@type": "Dentist", url: "https://…" }`; a LocalBusiness subtype
|
|
60
|
+
* suits a shop or clinic), or false when the page already emits its own.
|
|
61
|
+
*/
|
|
62
|
+
jsonLd?: boolean | JsonLdNode;
|
|
56
63
|
labels?: Site2BlockLabels;
|
|
57
64
|
}
|
|
65
|
+
/** `Organization` JSON-LD from the footer's details (absolute brand href becomes `url`). */
|
|
66
|
+
export declare function footerJsonLd(props: Pick<FooterProps, "brand" | "company" | "contact" | "social">): JsonLdNode;
|
|
58
67
|
/**
|
|
59
68
|
* Site footer: navigation, contact, socials, legal links and the company details e-commerce law
|
|
60
69
|
* requires in many countries. `footer` landmark with labelled inner navs; social links are named
|
|
@@ -65,4 +74,4 @@ export interface FooterProps extends Omit<BlockBaseProps, "variant" | "labels" |
|
|
|
65
74
|
* company={{ legalName: "Vamos Dijital Ajans Ltd. Şti.", registry: [{ label: "Tax no.", value: "923 145 6780" }] }} />
|
|
66
75
|
* ```
|
|
67
76
|
*/
|
|
68
|
-
export declare function Footer({ variant, brand, about, columns, contact, social, legalLinks, company, credit, cookieSettings, newsletter, year, id, anchor, theme, className, labels, locale, components, editMode, }: FooterProps): React.JSX.Element;
|
|
77
|
+
export declare function Footer({ variant, brand, about, columns, contact, social, legalLinks, company, credit, cookieSettings, newsletter, year, jsonLd, id, anchor, theme, className, labels, locale, components, editMode, }: FooterProps): React.JSX.Element;
|
|
@@ -4,6 +4,7 @@ import { cn2 as cn } from "./shared/kit-2.js";
|
|
|
4
4
|
import { Section, Container } from "../section.js";
|
|
5
5
|
import { BlockImage } from "../block-image.js";
|
|
6
6
|
import { BlockLink } from "../block-link.js";
|
|
7
|
+
import { JsonLd } from "../json-ld.js";
|
|
7
8
|
import { labelTemplates, site2Text } from "./shared/labels-2.js";
|
|
8
9
|
import { addressLines, fieldAttr, prettyPhone, telHref, useBlockIds2 } from "./shared/kit-2.js";
|
|
9
10
|
import { BrandIcon, BRAND_NAMES } from "./shared/brand-icons.js";
|
|
@@ -11,6 +12,27 @@ import { ConsentSettingsButton } from "./shared/consent-island.js";
|
|
|
11
12
|
import { ContactFormIsland } from "./shared/contact-form-island.js";
|
|
12
13
|
import { contactIslandLabelKeys } from "./shared/island-keys.js";
|
|
13
14
|
import { TAP } from "./shared/tap.js";
|
|
15
|
+
/** `Organization` JSON-LD from the footer's details (absolute brand href becomes `url`). */
|
|
16
|
+
export function footerJsonLd(props) {
|
|
17
|
+
const { brand, company, contact, social = [] } = props;
|
|
18
|
+
const address = contact?.address;
|
|
19
|
+
return {
|
|
20
|
+
"@type": "Organization",
|
|
21
|
+
name: brand.name,
|
|
22
|
+
...(company?.legalName && company.legalName !== brand.name ? { legalName: company.legalName } : null),
|
|
23
|
+
...(brand.href && /^https?:\/\//.test(brand.href) ? { url: brand.href } : null),
|
|
24
|
+
...(contact?.phone ? { telephone: contact.phone } : null),
|
|
25
|
+
...(contact?.email ? { email: contact.email } : null),
|
|
26
|
+
...(address
|
|
27
|
+
? {
|
|
28
|
+
address: typeof address === "string"
|
|
29
|
+
? address.replace(/\n/g, ", ")
|
|
30
|
+
: { "@type": "PostalAddress", streetAddress: address.line, addressLocality: address.district ? `${address.district}, ${address.city}` : address.city, ...(address.region ? { addressRegion: address.region } : null), ...(address.postalCode ? { postalCode: address.postalCode } : null), addressCountry: address.country },
|
|
31
|
+
}
|
|
32
|
+
: null),
|
|
33
|
+
...(social.length ? { sameAs: social.map((s) => s.href) } : null),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
14
36
|
const isImage = (v) => !!v && typeof v === "object" && "src" in v && !React.isValidElement(v);
|
|
15
37
|
/**
|
|
16
38
|
* Site footer: navigation, contact, socials, legal links and the company details e-commerce law
|
|
@@ -22,29 +44,31 @@ const isImage = (v) => !!v && typeof v === "object" && "src" in v && !React.isVa
|
|
|
22
44
|
* company={{ legalName: "Vamos Dijital Ajans Ltd. Şti.", registry: [{ label: "Tax no.", value: "923 145 6780" }] }} />
|
|
23
45
|
* ```
|
|
24
46
|
*/
|
|
25
|
-
export function Footer({ variant = "columns", brand, about, columns = [], contact, social = [], legalLinks = [], company, credit, cookieSettings = true, newsletter, year, id, anchor, theme, className, labels, locale = "en-US", components, editMode, }) {
|
|
47
|
+
export function Footer({ variant = "columns", brand, about, columns = [], contact, social = [], legalLinks = [], company, credit, cookieSettings = true, newsletter, year, jsonLd = true, id, anchor, theme, className, labels, locale = "en-US", components, editMode, }) {
|
|
26
48
|
const t = site2Text(labels, locale);
|
|
27
49
|
const { base } = useBlockIds2(id, "footer");
|
|
28
50
|
const y = String(year ?? new Date().getFullYear());
|
|
29
51
|
const ctx = { t, locale, components, labels, editMode };
|
|
30
52
|
const copyright = t("copyright", { year: y, name: company?.legalName ?? brand.name });
|
|
53
|
+
// The edit canvas skips it; the document renderer collects the definition's JSON-LD instead.
|
|
54
|
+
const structured = jsonLd && !editMode ? _jsx(JsonLd, { data: { ...footerJsonLd({ brand, company, contact, social }), ...(typeof jsonLd === "object" ? jsonLd : null) } }) : null;
|
|
31
55
|
const legalLine = (_jsxs("div", { className: "flex flex-col gap-3 text-small text-fg-muted @4xl:flex-row @4xl:items-center @4xl:justify-between @4xl:gap-8", children: [_jsx("p", { children: copyright }), _jsx("nav", { "aria-label": t("legal"), children: _jsxs("ul", { className: "flex flex-wrap items-center gap-x-5 gap-y-2 pointer-coarse:gap-y-0", children: [legalLinks.map((l, i) => (_jsx("li", { children: _jsx(BlockLink, { href: l.href, newTab: l.newTab, components: components, labels: labels, locale: locale, className: cn(TAP, "rounded-[2px] text-fg-muted underline-offset-[0.25em] transition-colors hover:text-fg hover:underline focus-ring"), children: l.label }) }, i))), cookieSettings ? (_jsx("li", { children: _jsx(ConsentSettingsButton, { className: cn(TAP, "text-fg-muted transition-colors hover:text-fg"), children: t("cookieSettings") }) })) : null, credit ? (_jsx("li", { children: _jsx(BlockLink, { href: credit.href, newTab: credit.newTab, components: components, labels: labels, locale: locale, className: cn(TAP, "rounded-[2px] text-fg-muted underline-offset-[0.25em] hover:text-fg hover:underline focus-ring"), children: t("madeBy", { name: typeof credit.label === "string" ? credit.label : "" }) }) })) : null] }) })] }));
|
|
32
56
|
// The legal name already sits in the © line; the company row only earns its place with registry data.
|
|
33
57
|
const companyLine = company?.registry?.length ? (_jsxs("div", { className: "flex flex-col gap-1.5 @4xl:flex-row @4xl:items-baseline @4xl:gap-6", ...fieldAttr(editMode, "company"), children: [_jsx("p", { className: "text-small text-fg-muted", children: company.legalName }), company.registry?.length ? (_jsx("dl", { className: "flex flex-wrap gap-x-6 gap-y-1 font-mono text-eyebrow uppercase tracking-[0.06em] text-fg-muted", children: company.registry.map((r, i) => (_jsxs("div", { className: "flex gap-2", children: [_jsx("dt", { children: r.label }), _jsx("dd", { className: "tabular text-fg-muted", children: r.value })] }, i))) })) : null] })) : null;
|
|
34
58
|
if (variant === "minimal") {
|
|
35
|
-
return (
|
|
59
|
+
return (_jsxs(Section, { as: "footer", theme: { rhythm: "tight", ...theme }, anchor: anchor, blockId: id, blockType: "footer", editMode: editMode, className: cn("vb-footer", className), "data-variant": "minimal", "aria-label": t("footer"), children: [structured, _jsxs(Container, { className: "flex flex-col gap-6 @4xl:flex-row @4xl:items-center @4xl:justify-between", children: [_jsx(BrandMark, { brand: brand, ctx: ctx }), columns[0]?.links.length ? (_jsx("nav", { "aria-label": t("footerNav"), children: _jsx("ul", { className: "flex flex-wrap gap-x-6 gap-y-2 text-small", children: columns.flatMap((c) => c.links).slice(0, 5).map((l, i) => (_jsx("li", { children: _jsx(FooterLink, { link: l, ctx: ctx }) }, i))) }) })) : null, _jsxs("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-3", children: [_jsx(SocialList, { social: social, ctx: ctx }), _jsx("p", { className: "text-small text-fg-muted", children: copyright })] })] })] }));
|
|
36
60
|
}
|
|
37
61
|
const linkColumns = columns.slice(0, 4).map((c, i) => (_jsxs("nav", { "aria-labelledby": `${base}-col-${i}`, className: "flex flex-col gap-4", children: [_jsx("p", { id: `${base}-col-${i}`, className: "font-mono text-eyebrow uppercase tracking-[0.08em] text-fg-muted", children: c.title }), _jsx("ul", { className: "flex flex-col gap-2.5 pointer-coarse:gap-0", children: c.links.slice(0, 8).map((l, j) => (_jsx("li", { children: _jsx(FooterLink, { link: l, ctx: ctx }) }, j))) })] }, i)));
|
|
38
62
|
const contactBlock = contact ? (_jsxs("div", { className: "flex flex-col gap-2 text-small text-fg-muted", children: [contact.address ? (_jsx("address", { className: "not-italic", children: (typeof contact.address === "string" ? contact.address.split("\n") : addressLines(contact.address, { locale })).map((l, i) => (_jsx("span", { className: "block", children: l }, i))) })) : null, contact.phone ? (_jsx("a", { href: telHref(contact.phone), className: cn(TAP, "self-start text-fg tabular underline decoration-line underline-offset-[0.25em] hover:decoration-current focus-ring rounded-[2px]"), "data-track": "call", children: prettyPhone(contact.phone) })) : null, contact.email ? (_jsx("a", { href: `mailto:${contact.email}`, className: cn(TAP, "self-start text-fg underline decoration-line underline-offset-[0.25em] hover:decoration-current focus-ring rounded-[2px]"), "data-track": "email", children: contact.email })) : null] })) : null;
|
|
39
63
|
const newsletterBlock = newsletter ? (_jsxs("div", { className: "flex flex-col gap-3", children: [_jsx("p", { className: "text-body font-medium text-fg", children: newsletter.title ?? t("newsletter") }), _jsx("p", { className: "text-small text-fg-muted", children: newsletter.hint ?? t("newsletterHint") }), _jsx(ContactFormIsland, { action: newsletter.action, fields: [{ name: "email", required: true, label: t("emailAddress") }], labels: { ...labelTemplates(labels, contactIslandLabelKeys), send: t("subscribe"), sent: t("subscribed") }, locale: locale, layout: "minimal", idBase: `${base}-nl`, className: "vb-footer-newsletter" })] })) : null;
|
|
40
64
|
if (variant === "wordmark") {
|
|
41
|
-
return (_jsxs(Section, { as: "footer", theme: theme, anchor: anchor, blockId: id, blockType: "footer", editMode: editMode, className: cn("vb-footer overflow-hidden pb-0!", className), "data-variant": "wordmark", "aria-label": t("footer"), children: [_jsxs(Container, { className: "flex flex-col gap-12", children: [_jsxs("div", { className: "grid gap-x-(--gutter) gap-y-10 @2xl:grid-cols-2 @4xl:grid-cols-12", children: [_jsxs("div", { className: "flex flex-col gap-5 @4xl:col-span-4", children: [about ? _jsx("p", { className: "max-w-[40ch] text-fg-muted text-pretty", children: about }) : null, contactBlock, _jsx(SocialList, { social: social, ctx: ctx })] }), _jsx("div", { className: "grid grid-cols-2 gap-x-(--gutter) gap-y-10 @2xl:col-span-1 @4xl:col-span-8 @4xl:grid-cols-4", children: linkColumns })] }), newsletterBlock ? _jsx("div", { className: "max-w-xl", children: newsletterBlock }) : null, _jsxs("div", { className: "flex flex-col gap-4 border-t border-line pt-6", children: [companyLine, legalLine] })] }), _jsx("p", { "aria-hidden": true, className: "vb-wordmark select-none whitespace-nowrap px-(--gutter) font-display text-display-2xl leading-[0.78] text-fg",
|
|
65
|
+
return (_jsxs(Section, { as: "footer", theme: theme, anchor: anchor, blockId: id, blockType: "footer", editMode: editMode, className: cn("vb-footer overflow-hidden pb-0!", className), "data-variant": "wordmark", "aria-label": t("footer"), children: [structured, _jsxs(Container, { className: "flex flex-col gap-12", children: [_jsxs("div", { className: "grid gap-x-(--gutter) gap-y-10 @2xl:grid-cols-2 @4xl:grid-cols-12", children: [_jsxs("div", { className: "flex flex-col gap-5 @4xl:col-span-4", children: [about ? _jsx("p", { className: "max-w-[40ch] text-fg-muted text-pretty", children: about }) : null, contactBlock, _jsx(SocialList, { social: social, ctx: ctx })] }), _jsx("div", { className: "grid grid-cols-2 gap-x-(--gutter) gap-y-10 @2xl:col-span-1 @4xl:col-span-8 @4xl:grid-cols-4", children: linkColumns })] }), newsletterBlock ? _jsx("div", { className: "max-w-xl", children: newsletterBlock }) : null, _jsxs("div", { className: "flex flex-col gap-4 border-t border-line pt-6", children: [companyLine, legalLine] })] }), _jsx("p", { "aria-hidden": true, className: "vb-wordmark select-none whitespace-nowrap px-(--gutter) font-display text-display-2xl leading-[0.78] text-fg",
|
|
42
66
|
// Fill the width: a short name at the fixed display size reads as an accidental crop. The
|
|
43
67
|
// size never goes above what fits, so a long name is not cut at the side; wide display
|
|
44
68
|
// faces (Syne 800 and the like) set `--vb-wordmark-em` (average glyph width, default 0.58em).
|
|
45
69
|
style: typeof brand.name === "string" ? { fontSize: `min(calc((100cqi - 2 * var(--gutter, 1.5rem)) / (${Math.max(4, [...brand.name].length)} * var(--vb-wordmark-em, 0.58))), 22rem)` } : undefined, children: brand.name })] }));
|
|
46
70
|
}
|
|
47
|
-
return (
|
|
71
|
+
return (_jsxs(Section, { as: "footer", theme: theme, anchor: anchor, blockId: id, blockType: "footer", editMode: editMode, className: cn("vb-footer", className), "data-variant": "columns", "aria-label": t("footer"), children: [structured, _jsxs(Container, { className: "flex flex-col gap-14", children: [_jsxs("div", { className: "grid gap-x-(--gutter) gap-y-12 @4xl:grid-cols-12", children: [_jsxs("div", { className: "flex flex-col gap-6 @4xl:col-span-4", children: [_jsx(BrandMark, { brand: brand, ctx: ctx }), about ? (_jsx("p", { className: "max-w-[40ch] text-small text-fg-muted text-pretty", ...fieldAttr(editMode, "about"), children: about })) : null, contactBlock, _jsx(SocialList, { social: social, ctx: ctx })] }), _jsx("div", { className: cn("grid grid-cols-2 gap-x-(--gutter) gap-y-10 @4xl:col-span-7 @4xl:col-start-6", columns.length >= 3 && "@2xl:grid-cols-3", columns.length >= 4 && "@6xl:grid-cols-4"), children: linkColumns })] }), newsletterBlock ? _jsx("div", { className: "max-w-xl border-t border-line pt-10", children: newsletterBlock }) : null, _jsxs("div", { className: "flex flex-col gap-4 border-t border-line pt-6", children: [companyLine, legalLine] })] })] }));
|
|
48
72
|
}
|
|
49
73
|
function BrandMark({ brand, ctx }) {
|
|
50
74
|
const mark = isImage(brand.logo) ? (_jsx(BlockImage, { ...brand.logo, alt: brand.logo.alt ?? brand.name, fit: "contain", sizes: "12rem", className: "h-8 w-auto bg-transparent", components: ctx.components })) : ((brand.logo ?? _jsx("span", { className: "font-display text-display-m leading-none text-fg", children: brand.name })));
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// team, blog list, article, contact form, map & hours, menu, gallery, consent, contact dock,
|
|
3
3
|
// footer, 404. Server / admin only — this file imports zod; components never import it.
|
|
4
4
|
import { z, f, defineBlock, createRegistry } from "../schema/index.js";
|
|
5
|
+
import * as React from "react";
|
|
5
6
|
import { PricingTable } from "./pricing-table.js";
|
|
6
7
|
import { ComparisonTable } from "./comparison-table.js";
|
|
7
8
|
import { Testimonials } from "./testimonials.js";
|
|
@@ -518,7 +519,8 @@ export const footerBlock = defineBlock({
|
|
|
518
519
|
},
|
|
519
520
|
jsonLd: (p) => ({ "@type": "Organization", name: p.company?.legalName ?? p.brand.name, telephone: p.contact?.phone, email: p.contact?.email, sameAs: p.social.map((s) => s.href) }),
|
|
520
521
|
lint: (p) => (!p.company ? [{ code: "missing-company-details", severity: "info", message: "Sites that sell online usually must show the legal name and tax / registry numbers in the footer.", path: "props.company" }] : []),
|
|
521
|
-
component
|
|
522
|
+
// The renderer emits the definition's jsonLd once per page; the component must not repeat it.
|
|
523
|
+
component: asBlock((p) => React.createElement(Footer, { ...p, jsonLd: false })),
|
|
522
524
|
});
|
|
523
525
|
/* ------------------------------------------------------------------ 404 */
|
|
524
526
|
export const notFoundBlock = defineBlock({
|
|
@@ -204,6 +204,14 @@ export declare const site2Labels: {
|
|
|
204
204
|
export type Site2Labels = typeof site2Labels;
|
|
205
205
|
/** Turkish dictionary. Legal-flavoured texts are neutral templates — review with counsel. */
|
|
206
206
|
export declare const site2LabelsTr: Site2Labels;
|
|
207
|
+
/** German dictionary. Legal-flavoured texts are neutral templates — review with counsel. */
|
|
208
|
+
export declare const site2LabelsDe: Site2Labels;
|
|
209
|
+
/** French dictionary. Legal-flavoured texts are neutral templates — review with counsel. */
|
|
210
|
+
export declare const site2LabelsFr: Site2Labels;
|
|
211
|
+
/** Spanish dictionary. Legal-flavoured texts are neutral templates — review with counsel. */
|
|
212
|
+
export declare const site2LabelsEs: Site2Labels;
|
|
213
|
+
/** Arabic dictionary (Modern Standard Arabic). Legal-flavoured texts are neutral templates — review with counsel. */
|
|
214
|
+
export declare const site2LabelsAr: Site2Labels;
|
|
207
215
|
/** Labels accepted by every registry-2 block: infrastructure + these keys. */
|
|
208
216
|
export type Site2BlockLabels = Partial<BlockLabels & Site2Labels>;
|
|
209
217
|
export type Site2Key = keyof (BlockLabels & Site2Labels);
|