@zorgo/next 1.3.0 → 2.0.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/dist/cli.d.mts +9 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.js +44 -66
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +43 -65
- package/dist/cli.mjs.map +1 -1
- package/dist/components.d.mts +735 -5
- package/dist/components.d.ts +735 -5
- package/dist/components.js +3692 -525
- package/dist/components.js.map +1 -1
- package/dist/components.mjs +3663 -540
- package/dist/components.mjs.map +1 -1
- package/dist/images.d.mts +25 -13
- package/dist/images.d.ts +25 -13
- package/dist/images.js +18 -8
- package/dist/images.js.map +1 -1
- package/dist/images.mjs +15 -8
- package/dist/images.mjs.map +1 -1
- package/dist/index.d.mts +315 -9
- package/dist/index.d.ts +315 -9
- package/dist/index.js +58 -52
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +58 -52
- package/dist/index.mjs.map +1 -1
- package/dist/item-page.d.mts +6 -0
- package/dist/item-page.d.ts +6 -0
- package/dist/item-page.js +4 -2
- package/dist/item-page.js.map +1 -1
- package/dist/item-page.mjs +4 -2
- package/dist/item-page.mjs.map +1 -1
- package/dist/legal.d.mts +31 -0
- package/dist/legal.d.ts +31 -0
- package/dist/legal.js +322 -0
- package/dist/legal.js.map +1 -0
- package/dist/legal.mjs +293 -0
- package/dist/legal.mjs.map +1 -0
- package/dist/seo.d.mts +56 -1
- package/dist/seo.d.ts +56 -1
- package/dist/seo.js +111 -2
- package/dist/seo.js.map +1 -1
- package/dist/seo.mjs +106 -1
- package/dist/seo.mjs.map +1 -1
- package/dist/server.d.mts +27 -1
- package/dist/server.d.ts +27 -1
- package/dist/server.js +322 -102
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +322 -104
- package/dist/server.mjs.map +1 -1
- package/dist/slugs.d.mts +2 -1
- package/dist/slugs.d.ts +2 -1
- package/dist/slugs.js +2 -0
- package/dist/slugs.js.map +1 -1
- package/dist/slugs.mjs +1 -0
- package/dist/tree/README.md +2 -2
- package/dist/tree/app/error.tsx +12 -3
- package/dist/tree/app/global-error.tsx +21 -4
- package/dist/tree/app/globals.css +41 -0
- package/dist/tree/app/not-found.tsx +17 -3
- package/dist/tree/app/privacy/page.tsx.gen.ts +28 -9
- package/dist/tree/app/terms/page.tsx.gen.ts +26 -10
- package/dist/tree/gitignore +6 -1
- package/dist/tree/next.config.ts +6 -5
- package/dist/tree/open-next.config.ts +7 -0
- package/dist/tree/package.json.gen.ts +8 -2
- package/package.json +7 -2
- package/dist/tree/app/globals.css.gen.ts +0 -124
package/dist/components.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { ReactNode } from 'react';
|
|
3
|
+
import { ReactNode, AnchorHTMLAttributes, ButtonHTMLAttributes } from 'react';
|
|
4
4
|
|
|
5
5
|
declare function CookieConsent(): react_jsx_runtime.JSX.Element | null;
|
|
6
6
|
|
|
@@ -26,6 +26,8 @@ interface Location {
|
|
|
26
26
|
franchise_id: number;
|
|
27
27
|
name: string;
|
|
28
28
|
address?: string;
|
|
29
|
+
/** Public storefront number, as staff typed it. Display only. */
|
|
30
|
+
phone?: string;
|
|
29
31
|
force_close?: boolean;
|
|
30
32
|
status?: LocationStatus | null;
|
|
31
33
|
lat?: number | null;
|
|
@@ -52,6 +54,7 @@ interface Category {
|
|
|
52
54
|
name: string;
|
|
53
55
|
is_catering?: boolean;
|
|
54
56
|
rules: Rule[];
|
|
57
|
+
sort_index?: number | null;
|
|
55
58
|
active_promo_id?: number;
|
|
56
59
|
}
|
|
57
60
|
interface ItemVariant {
|
|
@@ -63,6 +66,7 @@ interface ItemVariant {
|
|
|
63
66
|
rules?: Rule[];
|
|
64
67
|
portion_scheme_id?: number | null;
|
|
65
68
|
portion_scheme?: PortionScheme | null;
|
|
69
|
+
sort_index?: number | null;
|
|
66
70
|
display_price?: number;
|
|
67
71
|
active_promo_id?: number;
|
|
68
72
|
}
|
|
@@ -85,6 +89,7 @@ interface MenuItem {
|
|
|
85
89
|
variants: ItemVariant[];
|
|
86
90
|
rules: Rule[];
|
|
87
91
|
description?: string | null;
|
|
92
|
+
sort_index?: number | null;
|
|
88
93
|
active_promo_id?: number;
|
|
89
94
|
is_catering?: boolean;
|
|
90
95
|
}
|
|
@@ -120,6 +125,7 @@ interface Rule {
|
|
|
120
125
|
max_selection?: number;
|
|
121
126
|
included_quantity: number;
|
|
122
127
|
is_portionable?: boolean;
|
|
128
|
+
sort_index?: number | null;
|
|
123
129
|
items?: RuleItem[];
|
|
124
130
|
components?: RuleComponent[];
|
|
125
131
|
}
|
|
@@ -130,6 +136,7 @@ interface RuleItem {
|
|
|
130
136
|
upcharge_price: number;
|
|
131
137
|
description?: string | null;
|
|
132
138
|
behavior?: ScalingBehavior;
|
|
139
|
+
sort_index?: number | null;
|
|
133
140
|
}
|
|
134
141
|
interface RuleComponent {
|
|
135
142
|
component_id: number;
|
|
@@ -139,6 +146,7 @@ interface RuleComponent {
|
|
|
139
146
|
description?: string | null;
|
|
140
147
|
behavior?: ScalingBehavior;
|
|
141
148
|
serving_weight?: number;
|
|
149
|
+
sort_index?: number | null;
|
|
142
150
|
}
|
|
143
151
|
interface CustomizationOption {
|
|
144
152
|
key: string;
|
|
@@ -215,8 +223,70 @@ interface Selection {
|
|
|
215
223
|
serving_weight?: number;
|
|
216
224
|
measurement_type?: "weight" | "count";
|
|
217
225
|
display_unit?: string;
|
|
226
|
+
/** Only populated when type === "item" and the item has its own recipe (item_components). */
|
|
227
|
+
components?: OrderComponent[];
|
|
218
228
|
}
|
|
219
229
|
|
|
230
|
+
interface Menu {
|
|
231
|
+
items: MenuItem[];
|
|
232
|
+
categories: Category[];
|
|
233
|
+
components: Component[];
|
|
234
|
+
rules: Rule[];
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Per-slot Tailwind classes for a single item card. */
|
|
238
|
+
type ItemCardItemClasses = Partial<{
|
|
239
|
+
card: string;
|
|
240
|
+
imageBox: string;
|
|
241
|
+
image: string;
|
|
242
|
+
placeholder: string;
|
|
243
|
+
textContainer: string;
|
|
244
|
+
name: string;
|
|
245
|
+
price: string;
|
|
246
|
+
oldPrice: string;
|
|
247
|
+
}>;
|
|
248
|
+
/**
|
|
249
|
+
* Structural / theme defaults. Merged with `itemClasses` via
|
|
250
|
+
* {@link mergeItemCardItemClasses}.
|
|
251
|
+
*/
|
|
252
|
+
declare const ITEM_CARD_DEFAULT_ITEM_CLASSES: Required<ItemCardItemClasses>;
|
|
253
|
+
declare function mergeItemCardItemClasses(overrides?: ItemCardItemClasses): {
|
|
254
|
+
card: string;
|
|
255
|
+
imageBox: string;
|
|
256
|
+
image: string;
|
|
257
|
+
placeholder: string;
|
|
258
|
+
textContainer: string;
|
|
259
|
+
name: string;
|
|
260
|
+
price: string;
|
|
261
|
+
oldPrice: string;
|
|
262
|
+
};
|
|
263
|
+
type ItemCardProps = {
|
|
264
|
+
itemClasses?: ItemCardItemClasses;
|
|
265
|
+
/** Widest slot the card occupies, per breakpoint. */
|
|
266
|
+
sizes?: string;
|
|
267
|
+
priority?: boolean;
|
|
268
|
+
/** Overrides the `/menu/[slug]` target — see {@link CategoryTiles}. */
|
|
269
|
+
href?: string;
|
|
270
|
+
/** Overrides the displayed name and the no-image tile's text. */
|
|
271
|
+
label?: string;
|
|
272
|
+
/** Emit this dish's MenuItem JSON-LD beside the card. Off by default: the
|
|
273
|
+
* site-wide Restaurant node already carries every item under `hasMenu`. */
|
|
274
|
+
jsonLd?: boolean;
|
|
275
|
+
} & ({
|
|
276
|
+
item: MenuItem;
|
|
277
|
+
} | {
|
|
278
|
+
menu: Menu;
|
|
279
|
+
bid: number;
|
|
280
|
+
});
|
|
281
|
+
/**
|
|
282
|
+
* One clickable dish: photo (or a typographic tile when there is none), name,
|
|
283
|
+
* price — linking to that item's page. Pass `item` directly, or `menu` + `bid`
|
|
284
|
+
* to pick a base item out of the prebuilt menu.
|
|
285
|
+
*
|
|
286
|
+
* Renders nothing for a bid the menu does not contain.
|
|
287
|
+
*/
|
|
288
|
+
declare function ItemCard({ itemClasses, sizes, priority, href, label, jsonLd, ...source }: ItemCardProps): react_jsx_runtime.JSX.Element | null;
|
|
289
|
+
|
|
220
290
|
/** Per-slot Tailwind classes for the grid menu layout. */
|
|
221
291
|
type GridMenuItemClasses = Partial<{
|
|
222
292
|
baseContainer: string;
|
|
@@ -262,6 +332,9 @@ type AccordionMenuItemClasses = Partial<{
|
|
|
262
332
|
categoryIndicator: string;
|
|
263
333
|
itemsContainer: string;
|
|
264
334
|
itemCard: string;
|
|
335
|
+
itemCardFeatured: string;
|
|
336
|
+
itemCardImageBox: string;
|
|
337
|
+
itemCardImage: string;
|
|
265
338
|
itemCardTextContainer: string;
|
|
266
339
|
itemCardName: string;
|
|
267
340
|
itemCardDescription: string;
|
|
@@ -282,6 +355,9 @@ declare function mergeAccordionMenuItemClasses(overrides?: AccordionMenuItemClas
|
|
|
282
355
|
categoryIndicator: string;
|
|
283
356
|
itemsContainer: string;
|
|
284
357
|
itemCard: string;
|
|
358
|
+
itemCardFeatured: string;
|
|
359
|
+
itemCardImageBox: string;
|
|
360
|
+
itemCardImage: string;
|
|
285
361
|
itemCardTextContainer: string;
|
|
286
362
|
itemCardName: string;
|
|
287
363
|
itemCardDescription: string;
|
|
@@ -289,10 +365,16 @@ declare function mergeAccordionMenuItemClasses(overrides?: AccordionMenuItemClas
|
|
|
289
365
|
itemCardPrice: string;
|
|
290
366
|
itemCardOldPrice: string;
|
|
291
367
|
};
|
|
292
|
-
declare function AccordionMenu({ items, categories, itemClasses,
|
|
368
|
+
declare function AccordionMenu({ items, categories, itemClasses,
|
|
369
|
+
/** MN-07: small square thumb left of the name/description. Off by default so a menu with no item images (nothing in base_item_images yet) doesn't render a grid of empty placeholders. */
|
|
370
|
+
showImages,
|
|
371
|
+
/** MN-03: base_item_ids to render with the reserved featured (red panel) variant instead of the default card. */
|
|
372
|
+
featuredBaseItemIds, }: {
|
|
293
373
|
items: MenuItem[];
|
|
294
374
|
categories: Category[];
|
|
295
375
|
itemClasses?: AccordionMenuItemClasses;
|
|
376
|
+
showImages?: boolean;
|
|
377
|
+
featuredBaseItemIds?: number[];
|
|
296
378
|
}): react_jsx_runtime.JSX.Element;
|
|
297
379
|
|
|
298
380
|
declare function money(cents: number): string;
|
|
@@ -512,6 +594,173 @@ interface PortionPickerProps extends PortionShapeProps {
|
|
|
512
594
|
*/
|
|
513
595
|
declare function PortionPicker({ scheme, divisions, active, covered, onSelect, onDivisionsChange, className, }: PortionPickerProps): react_jsx_runtime.JSX.Element;
|
|
514
596
|
|
|
597
|
+
/** Per-slot Tailwind classes for the status pill. */
|
|
598
|
+
type OpenStatusItemClasses = Partial<{
|
|
599
|
+
root: string;
|
|
600
|
+
dot: string;
|
|
601
|
+
dotOpen: string;
|
|
602
|
+
dotClosed: string;
|
|
603
|
+
label: string;
|
|
604
|
+
}>;
|
|
605
|
+
/**
|
|
606
|
+
* Structural / theme defaults. Merged with `itemClasses` via
|
|
607
|
+
* {@link mergeOpenStatusItemClasses}.
|
|
608
|
+
*/
|
|
609
|
+
declare const OPEN_STATUS_DEFAULT_ITEM_CLASSES: Required<OpenStatusItemClasses>;
|
|
610
|
+
declare function mergeOpenStatusItemClasses(overrides?: OpenStatusItemClasses): {
|
|
611
|
+
root: string;
|
|
612
|
+
dot: string;
|
|
613
|
+
dotOpen: string;
|
|
614
|
+
dotClosed: string;
|
|
615
|
+
label: string;
|
|
616
|
+
};
|
|
617
|
+
/**
|
|
618
|
+
* Whether `location` is serving at `now`, and the sentence that says so —
|
|
619
|
+
* "Open until 11pm" / "Closed · opens 11am Tuesday". Pure: every branch is
|
|
620
|
+
* decided by the location's fourteen day-fields and the instant passed in.
|
|
621
|
+
*/
|
|
622
|
+
declare function openStatus(location: Location, now: Date): {
|
|
623
|
+
open: boolean;
|
|
624
|
+
label: string;
|
|
625
|
+
};
|
|
626
|
+
type OpenStatusProps = {
|
|
627
|
+
location: Location | null | undefined;
|
|
628
|
+
/**
|
|
629
|
+
* Pin the instant to judge against. Left unset the component reads the
|
|
630
|
+
* visitor's clock after mount and re-checks every minute, so a page built
|
|
631
|
+
* hours ago never claims to be open once the kitchen has closed.
|
|
632
|
+
*/
|
|
633
|
+
now?: Date;
|
|
634
|
+
itemClasses?: OpenStatusItemClasses;
|
|
635
|
+
};
|
|
636
|
+
/**
|
|
637
|
+
* Open/closed pill for one location.
|
|
638
|
+
*
|
|
639
|
+
* Renders nothing until the visitor's clock is known — the server and the first
|
|
640
|
+
* client render must agree, and a statically built page has no instant that is
|
|
641
|
+
* still true when it is served. The hours themselves reach crawlers through the
|
|
642
|
+
* page's JSON-LD, not through this pill.
|
|
643
|
+
*/
|
|
644
|
+
declare function OpenStatus({ location, now, itemClasses }: OpenStatusProps): react_jsx_runtime.JSX.Element | null;
|
|
645
|
+
|
|
646
|
+
/** Franchise-level facts for the Restaurant node. Everything but `name` is
|
|
647
|
+
* optional so the schema degrades gracefully when a field is missing. */
|
|
648
|
+
interface RestaurantInfo {
|
|
649
|
+
name: string;
|
|
650
|
+
url?: string;
|
|
651
|
+
image?: string;
|
|
652
|
+
description?: string;
|
|
653
|
+
servesCuisine?: string[];
|
|
654
|
+
/** Public locations from `lib/generated/locations.ts`. One location's facts
|
|
655
|
+
* land on the Restaurant node itself; several become linked branches. */
|
|
656
|
+
locations?: Location[];
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/** Per-slot Tailwind classes for a location card and the section that lists them. */
|
|
660
|
+
type LocationCardItemClasses = Partial<{
|
|
661
|
+
section: string;
|
|
662
|
+
title: string;
|
|
663
|
+
grid: string;
|
|
664
|
+
card: string;
|
|
665
|
+
cardWide: string;
|
|
666
|
+
body: string;
|
|
667
|
+
header: string;
|
|
668
|
+
name: string;
|
|
669
|
+
status: string;
|
|
670
|
+
rows: string;
|
|
671
|
+
row: string;
|
|
672
|
+
rowIcon: string;
|
|
673
|
+
rowText: string;
|
|
674
|
+
map: string;
|
|
675
|
+
mapFrame: string;
|
|
676
|
+
}>;
|
|
677
|
+
/**
|
|
678
|
+
* Structural / theme defaults. Merged with `itemClasses` via
|
|
679
|
+
* {@link mergeLocationCardItemClasses}.
|
|
680
|
+
*/
|
|
681
|
+
declare const LOCATION_CARD_DEFAULT_ITEM_CLASSES: Required<LocationCardItemClasses>;
|
|
682
|
+
declare function mergeLocationCardItemClasses(overrides?: LocationCardItemClasses): {
|
|
683
|
+
section: string;
|
|
684
|
+
title: string;
|
|
685
|
+
grid: string;
|
|
686
|
+
card: string;
|
|
687
|
+
cardWide: string;
|
|
688
|
+
body: string;
|
|
689
|
+
header: string;
|
|
690
|
+
name: string;
|
|
691
|
+
status: string;
|
|
692
|
+
rows: string;
|
|
693
|
+
row: string;
|
|
694
|
+
rowIcon: string;
|
|
695
|
+
rowText: string;
|
|
696
|
+
map: string;
|
|
697
|
+
mapFrame: string;
|
|
698
|
+
};
|
|
699
|
+
/**
|
|
700
|
+
* The map pane's `src` and the address row's `href`, which are not the same URL
|
|
701
|
+
* and cannot be derived from each other:
|
|
702
|
+
*
|
|
703
|
+
* - A site-supplied `mapUrl` is normally a share link to the real Place listing
|
|
704
|
+
* — reviews, photos, the pin on the right unit of a shared plaza. Google turns
|
|
705
|
+
* any such link into an iframe with `output=embed`, and a `/maps/embed?pb=`
|
|
706
|
+
* URL already is one. That form has no place page behind it, so it is a `src`
|
|
707
|
+
* only and the row falls back to the coordinate search.
|
|
708
|
+
* - With no `mapUrl` the pane is derived from the address (or coordinates), which
|
|
709
|
+
* is enough for "where is it" and needs no API key. `null` is the one way to
|
|
710
|
+
* say "no map here" — `undefined` cannot be, since that is also what a caller
|
|
711
|
+
* passing nothing sends.
|
|
712
|
+
*/
|
|
713
|
+
declare function locationMap(location: Location, mapUrl?: string | null): {
|
|
714
|
+
src?: string;
|
|
715
|
+
href?: string;
|
|
716
|
+
};
|
|
717
|
+
/** A card carrying a map takes the full container width; a plain one shares an auto-fit row. */
|
|
718
|
+
declare function locationGridClass(wide: boolean): string;
|
|
719
|
+
type LocationCardProps = {
|
|
720
|
+
location: Location | null | undefined;
|
|
721
|
+
/** That location's own page, when the site has one. */
|
|
722
|
+
href?: string;
|
|
723
|
+
/**
|
|
724
|
+
* This location on Google Maps — a share link to its Place listing, or an
|
|
725
|
+
* embed URL. Omitted, the card derives one from the address; `null` drops
|
|
726
|
+
* the map pane and keeps the narrow card.
|
|
727
|
+
*/
|
|
728
|
+
mapUrl?: string | null;
|
|
729
|
+
/** Pins the open/closed clock — see {@link OpenStatus}. */
|
|
730
|
+
now?: Date;
|
|
731
|
+
/**
|
|
732
|
+
* Franchise facts. Supplied, the card also emits this location's branch
|
|
733
|
+
* JSON-LD — only worth doing on the page that *is* this location's, since
|
|
734
|
+
* the parent node already carries a lone location's facts.
|
|
735
|
+
*/
|
|
736
|
+
info?: RestaurantInfo;
|
|
737
|
+
itemClasses?: LocationCardItemClasses;
|
|
738
|
+
};
|
|
739
|
+
/**
|
|
740
|
+
* One location: name and live open/closed up top, then a stack of tappable
|
|
741
|
+
* rows — address opens the map, phone dials, and the last row leads to that
|
|
742
|
+
* location's page — beside a map of where it actually is. Every field is
|
|
743
|
+
* optional in the data, so each row drops out on its own rather than leaving an
|
|
744
|
+
* empty line behind.
|
|
745
|
+
*/
|
|
746
|
+
declare function LocationCard({ location, href, mapUrl, now, info, itemClasses, }: LocationCardProps): react_jsx_runtime.JSX.Element | null;
|
|
747
|
+
type LocationsSectionProps = Omit<LocationCardProps, "location" | "href" | "mapUrl"> & {
|
|
748
|
+
locations: Location[];
|
|
749
|
+
title?: string;
|
|
750
|
+
/** Builds each card's page link; omit when the site has no location pages. */
|
|
751
|
+
href?: (location: Location) => string;
|
|
752
|
+
/**
|
|
753
|
+
* Pins each card's Google Maps URL, either as a `location_id` → URL lookup —
|
|
754
|
+
* the usual shape, since the locations themselves come from the database and
|
|
755
|
+
* the Place links are hand-collected — or as a builder. A location the lookup
|
|
756
|
+
* has no entry for derives its map from its address, as it would with no
|
|
757
|
+
* `mapUrl` at all; `null` is how a site says "no map on this one".
|
|
758
|
+
*/
|
|
759
|
+
mapUrl?: Record<number, string | null> | ((location: Location) => string | null | undefined);
|
|
760
|
+
};
|
|
761
|
+
/** The homepage/locations grid of {@link LocationCard}s. Nothing when empty. */
|
|
762
|
+
declare function LocationsSection({ locations, title, href, mapUrl, itemClasses, ...card }: LocationsSectionProps): react_jsx_runtime.JSX.Element | null;
|
|
763
|
+
|
|
515
764
|
/** Per-slot Tailwind classes for the find-location layout. */
|
|
516
765
|
type FindLocationItemClasses = Partial<{
|
|
517
766
|
baseContainer: string;
|
|
@@ -622,6 +871,28 @@ declare function mergeCheckoutFormItemClasses(overrides?: CheckoutFormItemClasse
|
|
|
622
871
|
*/
|
|
623
872
|
type CheckoutFormSlots = Required<CheckoutFormItemClasses>;
|
|
624
873
|
declare const CHECKOUT_FORM_SLOTS: CheckoutFormSlots;
|
|
874
|
+
/**
|
|
875
|
+
* Copy for a card *hold* — a Stripe SetupIntent rather than a PaymentIntent.
|
|
876
|
+
* The server issues one when the order is catering (create-payment-intent.ts
|
|
877
|
+
* branches on order.is_catering): the card is saved and nothing is charged
|
|
878
|
+
* until a manager confirms. Without this, checkout told the customer they had
|
|
879
|
+
* paid when no money had moved.
|
|
880
|
+
*
|
|
881
|
+
* Defaulted and overridable: the wording is catering-shaped today, but holding
|
|
882
|
+
* a card is not a catering-only idea.
|
|
883
|
+
*/
|
|
884
|
+
interface CheckoutHoldCopy {
|
|
885
|
+
submitLabel: string;
|
|
886
|
+
submitLoadingLabel: string;
|
|
887
|
+
successTitle: string;
|
|
888
|
+
/**
|
|
889
|
+
* Called with the formatted amount, or `null` when it isn't known — the
|
|
890
|
+
* Stripe return URL only carries one if we put it there, and a hold panel
|
|
891
|
+
* that promises to charge "$0.00" is worse than one that names no figure.
|
|
892
|
+
*/
|
|
893
|
+
successMessage: (amount: string | null) => string;
|
|
894
|
+
}
|
|
895
|
+
declare const CHECKOUT_HOLD_COPY: CheckoutHoldCopy;
|
|
625
896
|
|
|
626
897
|
/**
|
|
627
898
|
* The stock checkout flow: cart + customer details, then Stripe payment.
|
|
@@ -631,11 +902,24 @@ declare const CHECKOUT_FORM_SLOTS: CheckoutFormSlots;
|
|
|
631
902
|
* The order + payment intent are created on details submit (not on mount),
|
|
632
903
|
* so the collected customer and any applied promo are baked into the charge.
|
|
633
904
|
*/
|
|
634
|
-
declare function CheckoutForm({ itemClasses, homeHref, menuHref, checkoutHref, }: {
|
|
905
|
+
declare function CheckoutForm({ itemClasses, homeHref, menuHref, checkoutHref, holdCopy, successAction, }: {
|
|
635
906
|
itemClasses?: CheckoutFormItemClasses;
|
|
636
907
|
homeHref?: string;
|
|
637
908
|
menuHref?: string;
|
|
638
909
|
checkoutHref?: string;
|
|
910
|
+
holdCopy?: Partial<CheckoutHoldCopy>;
|
|
911
|
+
/**
|
|
912
|
+
* Replaces the "Back home" button on the success panel.
|
|
913
|
+
*
|
|
914
|
+
* Takes the order id and its read token when the return URL carried them —
|
|
915
|
+
* enough to link the customer straight to their own order. Both are absent
|
|
916
|
+
* whenever the mint before the redirect failed, so an implementation has to
|
|
917
|
+
* render something sensible without them.
|
|
918
|
+
*/
|
|
919
|
+
successAction?: (context: {
|
|
920
|
+
orderId?: number;
|
|
921
|
+
orderToken?: string;
|
|
922
|
+
}) => ReactNode;
|
|
639
923
|
}): react_jsx_runtime.JSX.Element;
|
|
640
924
|
|
|
641
925
|
/** Page wrapper + title every checkout state renders inside. */
|
|
@@ -708,9 +992,455 @@ declare function DetailsStep({ slots, }: {
|
|
|
708
992
|
}): react_jsx_runtime.JSX.Element;
|
|
709
993
|
|
|
710
994
|
/** Step 2: the Stripe payment element. Must be rendered inside `<Elements>`. */
|
|
711
|
-
declare function PaymentStep({ slots, checkoutHref, }: {
|
|
995
|
+
declare function PaymentStep({ slots, checkoutHref, holdCopy, }: {
|
|
712
996
|
slots?: CheckoutFormSlots;
|
|
713
997
|
checkoutHref?: string;
|
|
998
|
+
holdCopy?: Partial<CheckoutHoldCopy>;
|
|
714
999
|
}): react_jsx_runtime.JSX.Element;
|
|
715
1000
|
|
|
716
|
-
|
|
1001
|
+
type ButtonVariant = "primary" | "secondary";
|
|
1002
|
+
/** "auto" caps the button at its label + padding (FT-02); "full" stretches, but only below the sm breakpoint — a button should never stretch to ~1200px for two words on desktop. */
|
|
1003
|
+
type ButtonWidth = "auto" | "full";
|
|
1004
|
+
/** Per-slot Tailwind classes for a button. */
|
|
1005
|
+
type ButtonItemClasses = Partial<{
|
|
1006
|
+
base: string;
|
|
1007
|
+
primary: string;
|
|
1008
|
+
secondary: string;
|
|
1009
|
+
}>;
|
|
1010
|
+
/**
|
|
1011
|
+
* Structural / theme defaults. Merged with `itemClasses` via
|
|
1012
|
+
* {@link mergeButtonItemClasses}.
|
|
1013
|
+
*
|
|
1014
|
+
* min-h-11 (44px) is Tailwind's stock h-11 step and also the standard
|
|
1015
|
+
* touch-target floor (MB-02) — no separate constant needed for it.
|
|
1016
|
+
*
|
|
1017
|
+
* Brand-specific button geometry (Zestia's pill radius, uppercase Gotham Black,
|
|
1018
|
+
* wider tracking) is a per-site decision, so it goes through `itemClasses` at
|
|
1019
|
+
* the call site rather than into this default — every value the Zestia guide
|
|
1020
|
+
* names has an exact stock Tailwind step (`rounded-full`, `font-black`,
|
|
1021
|
+
* `tracking-wider`, `px-6`, `py-3`), so no arbitrary value is needed for it.
|
|
1022
|
+
*/
|
|
1023
|
+
declare const BUTTON_DEFAULT_ITEM_CLASSES: Required<ButtonItemClasses>;
|
|
1024
|
+
declare function mergeButtonItemClasses(overrides?: ButtonItemClasses): {
|
|
1025
|
+
base: string;
|
|
1026
|
+
primary: string;
|
|
1027
|
+
secondary: string;
|
|
1028
|
+
};
|
|
1029
|
+
/** FT-02's width rule as a pure decision: only "full" may stretch, and only on mobile. */
|
|
1030
|
+
declare function buttonWidthClass(width: ButtonWidth): string;
|
|
1031
|
+
type SharedProps = {
|
|
1032
|
+
variant?: ButtonVariant;
|
|
1033
|
+
width?: ButtonWidth;
|
|
1034
|
+
itemClasses?: ButtonItemClasses;
|
|
1035
|
+
children: ReactNode;
|
|
1036
|
+
};
|
|
1037
|
+
type ButtonProps = SharedProps & (({
|
|
1038
|
+
href: string;
|
|
1039
|
+
} & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "href" | "className">) | ({
|
|
1040
|
+
href?: undefined;
|
|
1041
|
+
} & Omit<ButtonHTMLAttributes<HTMLButtonElement>, "className">));
|
|
1042
|
+
/** One clickable action: a link when `href` is passed, a `<button>` otherwise. Same width/variant rules either way. */
|
|
1043
|
+
declare function Button({ variant, width, itemClasses, children, href, ...rest }: ButtonProps): react_jsx_runtime.JSX.Element;
|
|
1044
|
+
|
|
1045
|
+
/** A button's own slots plus the bar it pins to on mobile. */
|
|
1046
|
+
type StickyButtonItemClasses = ButtonItemClasses & Partial<{
|
|
1047
|
+
bar: string;
|
|
1048
|
+
}>;
|
|
1049
|
+
/**
|
|
1050
|
+
* The bar is only a bar below `sm`: `sm:contents` drops the wrapper out of the
|
|
1051
|
+
* layout entirely, so from that breakpoint up the button is an ordinary flex or
|
|
1052
|
+
* inline child of whatever holds it — which is the whole point of the
|
|
1053
|
+
* component, and why `Button`'s `full` width (`w-full sm:w-fit`) switches at the
|
|
1054
|
+
* same step.
|
|
1055
|
+
*/
|
|
1056
|
+
declare const STICKY_BUTTON_DEFAULT_BAR_CLASS = "fixed inset-x-0 bottom-0 z-40 flex justify-center border-t border-foreground/10 bg-background p-4 sm:contents";
|
|
1057
|
+
/**
|
|
1058
|
+
* Omitted `stickyOn` pins on every route; an empty list pins on none. Route
|
|
1059
|
+
* matching is {@link isNavLinkActive}'s — "/" exact, everything else its own
|
|
1060
|
+
* subtree — so the routes read the same here as they do in a nav.
|
|
1061
|
+
*/
|
|
1062
|
+
declare function isStickyRoute(pathname: string | null, stickyOn?: string[]): boolean;
|
|
1063
|
+
type StickyButtonProps = ButtonProps & {
|
|
1064
|
+
/** Routes where this pins to the bottom of the viewport on mobile. */
|
|
1065
|
+
stickyOn?: string[];
|
|
1066
|
+
/**
|
|
1067
|
+
* Reserves the bar's height in the flow. Wanted where the component sits at
|
|
1068
|
+
* the end of a page (nothing should hide under the bar); not wanted in a
|
|
1069
|
+
* header, where the bar's height is nowhere near the button's own place.
|
|
1070
|
+
*/
|
|
1071
|
+
spacer?: boolean;
|
|
1072
|
+
itemClasses?: StickyButtonItemClasses;
|
|
1073
|
+
};
|
|
1074
|
+
/**
|
|
1075
|
+
* One CTA that is an ordinary {@link Button} on desktop and a pinned
|
|
1076
|
+
* bottom-of-screen bar on mobile, per route. Width is owned here rather than
|
|
1077
|
+
* taken as a prop: pinned is always full-width (FT-02's mobile-only exception),
|
|
1078
|
+
* inline is always capped at its label.
|
|
1079
|
+
*/
|
|
1080
|
+
declare function StickyButton({ stickyOn, spacer, itemClasses, width: _width, ...rest }: StickyButtonProps): react_jsx_runtime.JSX.Element;
|
|
1081
|
+
|
|
1082
|
+
/**
|
|
1083
|
+
* Class slots an accordion section needs. Each consumer maps its own slot
|
|
1084
|
+
* names onto these — see {@link AccordionMenu} and {@link FaqAccordion}.
|
|
1085
|
+
*/
|
|
1086
|
+
type AccordionSectionSlots = Partial<{
|
|
1087
|
+
container: string;
|
|
1088
|
+
trigger: string;
|
|
1089
|
+
indicator: string;
|
|
1090
|
+
body: string;
|
|
1091
|
+
}>;
|
|
1092
|
+
/**
|
|
1093
|
+
* One expandable section: a trigger with a chevron over a body. The body stays
|
|
1094
|
+
* in the markup while collapsed — `hidden`, not unmounted — so its content is
|
|
1095
|
+
* still there for crawlers.
|
|
1096
|
+
*
|
|
1097
|
+
* `title` is a node rather than a string so the caller supplies its own
|
|
1098
|
+
* heading level.
|
|
1099
|
+
*/
|
|
1100
|
+
declare function AccordionSection({ title, slots, defaultOpen, id, children, }: {
|
|
1101
|
+
title: ReactNode;
|
|
1102
|
+
slots: AccordionSectionSlots;
|
|
1103
|
+
defaultOpen?: boolean;
|
|
1104
|
+
/** Anchor target, so a link can address this section. */
|
|
1105
|
+
id?: string;
|
|
1106
|
+
children: ReactNode;
|
|
1107
|
+
}): react_jsx_runtime.JSX.Element;
|
|
1108
|
+
|
|
1109
|
+
/** One site-authored question and its answer. */
|
|
1110
|
+
type Faq = {
|
|
1111
|
+
question: string;
|
|
1112
|
+
answer: string;
|
|
1113
|
+
};
|
|
1114
|
+
/** Per-slot Tailwind classes for the FAQ accordion. */
|
|
1115
|
+
type FaqAccordionItemClasses = Partial<{
|
|
1116
|
+
section: string;
|
|
1117
|
+
title: string;
|
|
1118
|
+
list: string;
|
|
1119
|
+
item: string;
|
|
1120
|
+
trigger: string;
|
|
1121
|
+
question: string;
|
|
1122
|
+
indicator: string;
|
|
1123
|
+
answer: string;
|
|
1124
|
+
}>;
|
|
1125
|
+
/**
|
|
1126
|
+
* Structural / theme defaults. Merged with `itemClasses` via
|
|
1127
|
+
* {@link mergeFaqAccordionItemClasses}.
|
|
1128
|
+
*/
|
|
1129
|
+
declare const FAQ_ACCORDION_DEFAULT_ITEM_CLASSES: Required<FaqAccordionItemClasses>;
|
|
1130
|
+
declare function mergeFaqAccordionItemClasses(overrides?: FaqAccordionItemClasses): {
|
|
1131
|
+
section: string;
|
|
1132
|
+
title: string;
|
|
1133
|
+
list: string;
|
|
1134
|
+
item: string;
|
|
1135
|
+
trigger: string;
|
|
1136
|
+
question: string;
|
|
1137
|
+
indicator: string;
|
|
1138
|
+
answer: string;
|
|
1139
|
+
};
|
|
1140
|
+
type FaqAccordionProps = {
|
|
1141
|
+
faqs: Faq[];
|
|
1142
|
+
title?: string;
|
|
1143
|
+
/** Index of the one question open on arrival — none by default. */
|
|
1144
|
+
defaultOpen?: number;
|
|
1145
|
+
itemClasses?: FaqAccordionItemClasses;
|
|
1146
|
+
};
|
|
1147
|
+
/**
|
|
1148
|
+
* Site-authored Q&A. Answers stay in the markup while collapsed, which is the
|
|
1149
|
+
* whole point of the block — AI answer engines quote them. Deliberately emits
|
|
1150
|
+
* no `FAQPage` JSON-LD: Google removed FAQ rich results from Search in May
|
|
1151
|
+
* 2026, so the markup would buy nothing.
|
|
1152
|
+
*/
|
|
1153
|
+
declare function FaqAccordion({ faqs, title, defaultOpen, itemClasses, }: FaqAccordionProps): react_jsx_runtime.JSX.Element | null;
|
|
1154
|
+
|
|
1155
|
+
/**
|
|
1156
|
+
* One site-authored photo, served from the site's own `public/`. These are not
|
|
1157
|
+
* in the data pipeline — unlike item photos there is no prebuild step that
|
|
1158
|
+
* localizes them.
|
|
1159
|
+
*/
|
|
1160
|
+
type GalleryImage = {
|
|
1161
|
+
src: string;
|
|
1162
|
+
alt: string;
|
|
1163
|
+
};
|
|
1164
|
+
/** Per-slot Tailwind classes for the photo gallery. */
|
|
1165
|
+
type GalleryItemClasses = Partial<{
|
|
1166
|
+
section: string;
|
|
1167
|
+
title: string;
|
|
1168
|
+
list: string;
|
|
1169
|
+
figure: string;
|
|
1170
|
+
image: string;
|
|
1171
|
+
}>;
|
|
1172
|
+
/**
|
|
1173
|
+
* Structural / theme defaults. Merged with `itemClasses` via
|
|
1174
|
+
* {@link mergeGalleryItemClasses}.
|
|
1175
|
+
*/
|
|
1176
|
+
declare const GALLERY_DEFAULT_ITEM_CLASSES: Required<GalleryItemClasses>;
|
|
1177
|
+
declare function mergeGalleryItemClasses(overrides?: GalleryItemClasses): {
|
|
1178
|
+
section: string;
|
|
1179
|
+
title: string;
|
|
1180
|
+
list: string;
|
|
1181
|
+
figure: string;
|
|
1182
|
+
image: string;
|
|
1183
|
+
};
|
|
1184
|
+
type GalleryProps = {
|
|
1185
|
+
images: GalleryImage[];
|
|
1186
|
+
title?: string;
|
|
1187
|
+
/** Widest slot one photo occupies, per breakpoint. */
|
|
1188
|
+
sizes?: string;
|
|
1189
|
+
itemClasses?: GalleryItemClasses;
|
|
1190
|
+
};
|
|
1191
|
+
/**
|
|
1192
|
+
* Interior and food photos, authored by the site under `public/`. The row
|
|
1193
|
+
* grows to fill whatever it is given, so two photos read as deliberate rather
|
|
1194
|
+
* than as ten that failed to load.
|
|
1195
|
+
*/
|
|
1196
|
+
declare function Gallery({ images, title, sizes, itemClasses, }: GalleryProps): react_jsx_runtime.JSX.Element | null;
|
|
1197
|
+
|
|
1198
|
+
/**
|
|
1199
|
+
* One first-party testimonial: something a customer said to the restaurant,
|
|
1200
|
+
* published with their permission.
|
|
1201
|
+
*
|
|
1202
|
+
* First-party is the whole design. Reprinting reviews off Google or Yelp is two
|
|
1203
|
+
* problems the component cannot solve for a site — the review text is the
|
|
1204
|
+
* reviewer's own copyrighted writing, and the platforms' terms restrict
|
|
1205
|
+
* republishing it — so there is no `source: "google"` field here to invite it.
|
|
1206
|
+
* A site that wants platform reviews on the page embeds that platform's own
|
|
1207
|
+
* widget, which carries its licence with it.
|
|
1208
|
+
*
|
|
1209
|
+
* `name` is required rather than optional on purpose. An unattributed quote is
|
|
1210
|
+
* the exact shape of a testimonial nobody can check, and the FTC's Rule on the
|
|
1211
|
+
* Use of Consumer Reviews and Testimonials (16 CFR 465, in force since October
|
|
1212
|
+
* 21 2024) puts civil penalties behind fabricated ones. A first name and a city
|
|
1213
|
+
* is plenty; what matters is that a real person said it and the restaurant can
|
|
1214
|
+
* show they did.
|
|
1215
|
+
*/
|
|
1216
|
+
type Testimonial = {
|
|
1217
|
+
/** Verbatim. Trim it and you are editing what someone said into something they did not. */
|
|
1218
|
+
quote: string;
|
|
1219
|
+
/** Attribution, as the customer agreed to it being published — "Marisa T." is fine. */
|
|
1220
|
+
name: string;
|
|
1221
|
+
/** Optional colour under the name: a city, "catering customer", "regular since 2019". */
|
|
1222
|
+
detail?: string;
|
|
1223
|
+
/** `YYYY-MM-DD`. Rendered as month + year, and machine-readable in `datetime`. */
|
|
1224
|
+
date?: string;
|
|
1225
|
+
/** 1–5. Omit it rather than inventing one. */
|
|
1226
|
+
rating?: number;
|
|
1227
|
+
/**
|
|
1228
|
+
* Required by the FTC whenever the reviewer got anything of value for the
|
|
1229
|
+
* review — a discount, a free meal, a gift card, entry into a drawing — and
|
|
1230
|
+
* whenever they are staff, family or an owner. Rendered with the quote, not
|
|
1231
|
+
* in a page footer: the disclosure has to be where the claim is.
|
|
1232
|
+
* e.g. "Received a free meal in exchange for this review."
|
|
1233
|
+
*/
|
|
1234
|
+
disclosure?: string;
|
|
1235
|
+
};
|
|
1236
|
+
/** Per-slot Tailwind classes for the testimonials block. */
|
|
1237
|
+
type TestimonialsItemClasses = Partial<{
|
|
1238
|
+
section: string;
|
|
1239
|
+
title: string;
|
|
1240
|
+
list: string;
|
|
1241
|
+
card: string;
|
|
1242
|
+
stars: string;
|
|
1243
|
+
star: string;
|
|
1244
|
+
starEmpty: string;
|
|
1245
|
+
quote: string;
|
|
1246
|
+
attribution: string;
|
|
1247
|
+
name: string;
|
|
1248
|
+
detail: string;
|
|
1249
|
+
disclosure: string;
|
|
1250
|
+
}>;
|
|
1251
|
+
/**
|
|
1252
|
+
* Structural / theme defaults. Merged with `itemClasses` via
|
|
1253
|
+
* {@link mergeTestimonialsItemClasses}.
|
|
1254
|
+
*
|
|
1255
|
+
* No line clamp on `quote`, deliberately: a card that cuts a testimonial off
|
|
1256
|
+
* mid-sentence is publishing an edit of it. Long quotes make a taller card,
|
|
1257
|
+
* which is the correct outcome.
|
|
1258
|
+
*/
|
|
1259
|
+
declare const TESTIMONIALS_DEFAULT_ITEM_CLASSES: Required<TestimonialsItemClasses>;
|
|
1260
|
+
declare function mergeTestimonialsItemClasses(overrides?: TestimonialsItemClasses): {
|
|
1261
|
+
section: string;
|
|
1262
|
+
title: string;
|
|
1263
|
+
list: string;
|
|
1264
|
+
card: string;
|
|
1265
|
+
stars: string;
|
|
1266
|
+
star: string;
|
|
1267
|
+
starEmpty: string;
|
|
1268
|
+
quote: string;
|
|
1269
|
+
attribution: string;
|
|
1270
|
+
name: string;
|
|
1271
|
+
detail: string;
|
|
1272
|
+
disclosure: string;
|
|
1273
|
+
};
|
|
1274
|
+
type TestimonialsProps = {
|
|
1275
|
+
testimonials: Testimonial[];
|
|
1276
|
+
title?: string;
|
|
1277
|
+
itemClasses?: TestimonialsItemClasses;
|
|
1278
|
+
};
|
|
1279
|
+
/**
|
|
1280
|
+
* What customers said, in their own words, attributed.
|
|
1281
|
+
*
|
|
1282
|
+
* Deliberately emits no `Review` or `AggregateRating` JSON-LD. Since 2019
|
|
1283
|
+
* Google ignores reviews a business collects about itself on its own site —
|
|
1284
|
+
* they are ineligible for review rich results either way — so the markup buys
|
|
1285
|
+
* no stars in search and only adds a structured-data policy surface to get
|
|
1286
|
+
* wrong. The stars here are for the reader.
|
|
1287
|
+
*/
|
|
1288
|
+
declare function Testimonials({ testimonials, title, itemClasses }: TestimonialsProps): react_jsx_runtime.JSX.Element | null;
|
|
1289
|
+
|
|
1290
|
+
/** Per-slot Tailwind classes for the category tile grid. */
|
|
1291
|
+
type CategoryTilesItemClasses = Partial<{
|
|
1292
|
+
baseContainer: string;
|
|
1293
|
+
title: string;
|
|
1294
|
+
tiles: string;
|
|
1295
|
+
tile: string;
|
|
1296
|
+
tileImage: string;
|
|
1297
|
+
tileName: string;
|
|
1298
|
+
}>;
|
|
1299
|
+
/**
|
|
1300
|
+
* Structural / theme defaults. Merged with `itemClasses` via
|
|
1301
|
+
* {@link mergeCategoryTilesItemClasses}.
|
|
1302
|
+
*/
|
|
1303
|
+
declare const CATEGORY_TILES_DEFAULT_ITEM_CLASSES: Required<CategoryTilesItemClasses>;
|
|
1304
|
+
declare function mergeCategoryTilesItemClasses(overrides?: CategoryTilesItemClasses): {
|
|
1305
|
+
baseContainer: string;
|
|
1306
|
+
title: string;
|
|
1307
|
+
tiles: string;
|
|
1308
|
+
tile: string;
|
|
1309
|
+
tileImage: string;
|
|
1310
|
+
tileName: string;
|
|
1311
|
+
};
|
|
1312
|
+
/** The `/menu#pizzas` anchor for a category — the same id the menu page's
|
|
1313
|
+
* category sections carry. */
|
|
1314
|
+
declare function categoryAnchor(name: string): string;
|
|
1315
|
+
type CategoryTilesProps = {
|
|
1316
|
+
menu: Menu;
|
|
1317
|
+
title?: string;
|
|
1318
|
+
/** Menu page the anchors point at. */
|
|
1319
|
+
menuHref?: string;
|
|
1320
|
+
itemClasses?: CategoryTilesItemClasses;
|
|
1321
|
+
sizes?: string;
|
|
1322
|
+
};
|
|
1323
|
+
/**
|
|
1324
|
+
* One tile per menu category, linking to that category on the menu page. Each
|
|
1325
|
+
* tile borrows the photo of the first item in the category that has one, so a
|
|
1326
|
+
* category of photo-less items still renders as a typographic tile.
|
|
1327
|
+
*
|
|
1328
|
+
* Empty categories are skipped; nothing renders when none are left.
|
|
1329
|
+
*/
|
|
1330
|
+
declare function CategoryTiles({ menu, title, menuHref, itemClasses, sizes, }: CategoryTilesProps): react_jsx_runtime.JSX.Element | null;
|
|
1331
|
+
|
|
1332
|
+
/** Per-slot Tailwind classes for a page section. */
|
|
1333
|
+
type SectionItemClasses = Partial<{
|
|
1334
|
+
container: string;
|
|
1335
|
+
eyebrow: string;
|
|
1336
|
+
}>;
|
|
1337
|
+
/**
|
|
1338
|
+
* Structural / theme defaults. Merged with `itemClasses` via
|
|
1339
|
+
* {@link mergeSectionItemClasses}.
|
|
1340
|
+
*
|
|
1341
|
+
* SP-01/02: one spacing scale and one container width for every section, so
|
|
1342
|
+
* left edges line up while scrolling instead of each section picking its own.
|
|
1343
|
+
* SP-03: the eyebrow gets full padding above (it's the top of a new section)
|
|
1344
|
+
* and a tight gap below (it labels what follows, not what came before).
|
|
1345
|
+
*/
|
|
1346
|
+
declare const SECTION_DEFAULT_ITEM_CLASSES: Required<SectionItemClasses>;
|
|
1347
|
+
declare function mergeSectionItemClasses(overrides?: SectionItemClasses): {
|
|
1348
|
+
container: string;
|
|
1349
|
+
eyebrow: string;
|
|
1350
|
+
};
|
|
1351
|
+
type SectionProps = {
|
|
1352
|
+
itemClasses?: SectionItemClasses;
|
|
1353
|
+
/** e.g. "BY DEFAULT, OUR TRUCK INCLUDES" — rendered above `children`, inside the same padded container so it never floats free of what it labels. */
|
|
1354
|
+
eyebrow?: ReactNode;
|
|
1355
|
+
children: ReactNode;
|
|
1356
|
+
id?: string;
|
|
1357
|
+
};
|
|
1358
|
+
/** One page section: consistent container width and vertical rhythm, with an optional eyebrow label. */
|
|
1359
|
+
declare function Section({ itemClasses, eyebrow, children, id }: SectionProps): react_jsx_runtime.JSX.Element;
|
|
1360
|
+
|
|
1361
|
+
type PageHeroSize = "sm" | "md" | "lg";
|
|
1362
|
+
/** Per-slot Tailwind classes for a page hero. */
|
|
1363
|
+
type PageHeroItemClasses = Partial<{
|
|
1364
|
+
container: string;
|
|
1365
|
+
imageBox: string;
|
|
1366
|
+
image: string;
|
|
1367
|
+
titleContainer: string;
|
|
1368
|
+
title: string;
|
|
1369
|
+
}>;
|
|
1370
|
+
/**
|
|
1371
|
+
* Structural / theme defaults. Merged with `itemClasses` via
|
|
1372
|
+
* {@link mergePageHeroItemClasses}.
|
|
1373
|
+
*/
|
|
1374
|
+
declare const PAGE_HERO_DEFAULT_ITEM_CLASSES: Required<PageHeroItemClasses>;
|
|
1375
|
+
declare function mergePageHeroItemClasses(overrides?: PageHeroItemClasses): {
|
|
1376
|
+
container: string;
|
|
1377
|
+
imageBox: string;
|
|
1378
|
+
image: string;
|
|
1379
|
+
titleContainer: string;
|
|
1380
|
+
title: string;
|
|
1381
|
+
};
|
|
1382
|
+
/**
|
|
1383
|
+
* HD-01/02: a real height scale instead of the ~240px letterbox every hero on
|
|
1384
|
+
* the old site collapsed to (which read as a divider, not a hero). Tailwind's
|
|
1385
|
+
* default spacing scale only — no arbitrary pixel/vh values, which is the
|
|
1386
|
+
* exact smell this checklist exists to cure.
|
|
1387
|
+
*/
|
|
1388
|
+
declare function heroHeightClass(size: PageHeroSize): string;
|
|
1389
|
+
/**
|
|
1390
|
+
* MB-03: a title over a small hero needs its own mobile step, not the desktop
|
|
1391
|
+
* size scaled down with `clamp()` — each size gets a dedicated mobile/desktop
|
|
1392
|
+
* pair from the type scale.
|
|
1393
|
+
*/
|
|
1394
|
+
declare function heroTitleTypeClass(size: PageHeroSize): string;
|
|
1395
|
+
type PageHeroProps = {
|
|
1396
|
+
size?: PageHeroSize;
|
|
1397
|
+
image: {
|
|
1398
|
+
src: string;
|
|
1399
|
+
alt: string;
|
|
1400
|
+
};
|
|
1401
|
+
/** HD-03: photography carries the top of the page by default. Pass a title only for the rare page that needs text over the hero. */
|
|
1402
|
+
title?: ReactNode;
|
|
1403
|
+
priority?: boolean;
|
|
1404
|
+
itemClasses?: PageHeroItemClasses;
|
|
1405
|
+
};
|
|
1406
|
+
/** A page-top hero: an art-directed photo with a defined bottom edge and, by default, no title competing with it. */
|
|
1407
|
+
declare function PageHero({ size, image, title, priority, itemClasses }: PageHeroProps): react_jsx_runtime.JSX.Element;
|
|
1408
|
+
|
|
1409
|
+
/** Per-slot Tailwind classes for a nav link. */
|
|
1410
|
+
type NavLinkItemClasses = Partial<{
|
|
1411
|
+
base: string;
|
|
1412
|
+
active: string;
|
|
1413
|
+
inactive: string;
|
|
1414
|
+
}>;
|
|
1415
|
+
/**
|
|
1416
|
+
* Structural / theme defaults. Merged with `itemClasses` via
|
|
1417
|
+
* {@link mergeNavLinkItemClasses}.
|
|
1418
|
+
*
|
|
1419
|
+
* NV-01: links default to `text-foreground` (the derived near-black/near-white
|
|
1420
|
+
* token every franchise already gets), not a second hardcoded gray — the
|
|
1421
|
+
* checklist's "near-black" is what that token already resolves to on a light
|
|
1422
|
+
* background. Red is reserved for hover/active so the one red "Order Online"
|
|
1423
|
+
* pill stays the visually distinct primary action.
|
|
1424
|
+
*/
|
|
1425
|
+
declare const NAV_LINK_DEFAULT_ITEM_CLASSES: Required<NavLinkItemClasses>;
|
|
1426
|
+
declare function mergeNavLinkItemClasses(overrides?: NavLinkItemClasses): {
|
|
1427
|
+
base: string;
|
|
1428
|
+
inactive: string;
|
|
1429
|
+
active: string;
|
|
1430
|
+
};
|
|
1431
|
+
/**
|
|
1432
|
+
* NV-02: the current page gets the active indicator, nothing else does.
|
|
1433
|
+
* "/" gets an exact match — every pathname starts with "/", so a prefix match
|
|
1434
|
+
* would leave the home link permanently active. Everything else is a prefix
|
|
1435
|
+
* match so a link to /menu also lights up on /menu/gyro.
|
|
1436
|
+
*/
|
|
1437
|
+
declare function isNavLinkActive(pathname: string, href: string): boolean;
|
|
1438
|
+
type NavLinkProps = {
|
|
1439
|
+
href: string;
|
|
1440
|
+
itemClasses?: NavLinkItemClasses;
|
|
1441
|
+
children: ReactNode;
|
|
1442
|
+
} & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "href" | "className">;
|
|
1443
|
+
/** A header nav link: near-black by default, red on hover or on the active page, with an active-page indicator. */
|
|
1444
|
+
declare function NavLink({ href, itemClasses, children, ...rest }: NavLinkProps): react_jsx_runtime.JSX.Element;
|
|
1445
|
+
|
|
1446
|
+
export { ACCORDION_MENU_DEFAULT_ITEM_CLASSES, AccordionMenu, type AccordionMenuItemClasses, AccordionSection, type AccordionSectionSlots, BREADCRUMBS_DEFAULT_ITEM_CLASSES, BUTTON_DEFAULT_ITEM_CLASSES, type BreadcrumbItem, Breadcrumbs, type BreadcrumbsItemClasses, Button, type ButtonItemClasses, type ButtonProps, type ButtonVariant, type ButtonWidth, CATEGORY_TILES_DEFAULT_ITEM_CLASSES, CHECKOUT_FORM_DEFAULT_ITEM_CLASSES, CHECKOUT_FORM_SLOTS, CHECKOUT_HOLD_COPY, CLIENT_ITEM_FORM_DEFAULT_ITEM_CLASSES, CLIENT_ITEM_FORM_SLOTS, CategoryTiles, type CategoryTilesItemClasses, type CategoryTilesProps, CheckoutForm, type CheckoutFormItemClasses, type CheckoutFormSlots, type CheckoutHoldCopy, CheckoutShell, CheckoutSteps, ClientItemForm, type ClientItemFormItemClasses, type ClientItemFormSlots, CommentsSection, ComponentsSection, ConsentFields, ContactFields, CookieConsent, DetailsStep, FAQ_ACCORDION_DEFAULT_ITEM_CLASSES, FIND_LOCATION_DEFAULT_ITEM_CLASSES, type Faq, FaqAccordion, type FaqAccordionItemClasses, type FaqAccordionProps, FindLocation, type FindLocationItemClasses, GALLERY_DEFAULT_ITEM_CLASSES, GRID_MENU_DEFAULT_ITEM_CLASSES, Gallery, type GalleryImage, type GalleryItemClasses, type GalleryProps, GridMenu, type GridMenuItemClasses, ITEM_CARD_DEFAULT_ITEM_CLASSES, CLIENT_ITEM_FORM_DEFAULT_ITEM_CLASSES as ITEM_CUSTOMIZATION_FORM_DEFAULT_ITEM_CLASSES, ItemCard, type ItemCardItemClasses, type ItemCardProps, ClientItemForm as ItemCustomizationClient, ClientItemForm as ItemCustomizationForm, type ClientItemFormItemClasses as ItemCustomizationFormItemClasses, LOCATION_CARD_DEFAULT_ITEM_CLASSES, LocationCard, type LocationCardItemClasses, type LocationCardProps, LocationsSection, type LocationsSectionProps, NAV_LINK_DEFAULT_ITEM_CLASSES, NavLink, type NavLinkItemClasses, type NavLinkProps, OPEN_STATUS_DEFAULT_ITEM_CLASSES, OpenStatus, type OpenStatusItemClasses, type OpenStatusProps, OptionButton, OrderLine, OrderLines, OrderTotals, PAGE_HERO_DEFAULT_ITEM_CLASSES, PageHero, type PageHeroItemClasses, type PageHeroProps, type PageHeroSize, PaymentStep, PortionPicker, type PortionPickerProps, PortionSection, type PortionShapeProps, PromoCode, QuantitySection, RuleSection, SECTION_DEFAULT_ITEM_CLASSES, STICKY_BUTTON_DEFAULT_BAR_CLASS, Section, type SectionItemClasses, type SectionProps, StatusPanel, StickyButton, type StickyButtonItemClasses, type StickyButtonProps, SubmitButton, TESTIMONIALS_DEFAULT_ITEM_CLASSES, type Testimonial, Testimonials, type TestimonialsItemClasses, type TestimonialsProps, VariantSection, buttonWidthClass, categoryAnchor, heroHeightClass, heroTitleTypeClass, isNavLinkActive, isStickyRoute, locationGridClass, locationMap, mergeAccordionMenuItemClasses, mergeBreadcrumbsItemClasses, mergeButtonItemClasses, mergeCategoryTilesItemClasses, mergeCheckoutFormItemClasses, mergeClientItemFormItemClasses, mergeFaqAccordionItemClasses, mergeFindLocationItemClasses, mergeGalleryItemClasses, mergeGridMenuItemClasses, mergeItemCardItemClasses, mergeClientItemFormItemClasses as mergeItemCustomizationFormItemClasses, mergeLocationCardItemClasses, mergeNavLinkItemClasses, mergeOpenStatusItemClasses, mergePageHeroItemClasses, mergeSectionItemClasses, mergeTestimonialsItemClasses, money, openStatus };
|