@bearmenu/ui 0.8.11 → 0.8.13
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/{chunk-24RFI4RQ.js → chunk-3NMG3KNA.js} +1 -1
- package/dist/{chunk-5RWTOT5Y.js → chunk-CNJQUHCU.js} +11 -1
- package/dist/{chunk-DTXNDLSE.js → chunk-FKNBZF5T.js} +15 -0
- package/dist/{chunk-H3ZZDX5L.js → chunk-P7XTW2CG.js} +2 -2
- package/dist/{chunk-JS3EINZD.js → chunk-VAXOQS7W.js} +12 -0
- package/dist/{chunk-AKQ57NXY.js → chunk-ZQ53AGML.js} +2 -2
- package/dist/components/alert-dialog.js +1 -1
- package/dist/components/alert.d.ts +2 -2
- package/dist/components/avatar.d.ts +3 -3
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/button.d.ts +2 -2
- package/dist/components/button.js +1 -1
- package/dist/components/calendar.js +1 -1
- package/dist/components/card.d.ts +2 -2
- package/dist/components/carousel.js +1 -1
- package/dist/components/combobox.js +1 -1
- package/dist/components/command.d.ts +15 -15
- package/dist/components/concept-compare-rail.js +3 -3
- package/dist/components/concept-compare.d.ts +1 -1
- package/dist/components/concept-compare.js +29 -8
- package/dist/components/concept-convergence.js +1 -1
- package/dist/components/dialog.d.ts +2 -2
- package/dist/components/empty-state.js +1 -1
- package/dist/components/event-detail-panel.js +1 -1
- package/dist/components/event-list-row-wide.js +1 -1
- package/dist/components/haptic-button.js +1 -1
- package/dist/components/input-group.d.ts +4 -4
- package/dist/components/input.d.ts +2 -2
- package/dist/components/item.d.ts +17 -7
- package/dist/components/item.js +15 -10
- package/dist/components/kbd.d.ts +2 -2
- package/dist/components/kitchen-dossier.d.ts +2 -0
- package/dist/components/kitchen-dossier.js +25 -18
- package/dist/components/link-button.js +1 -1
- package/dist/components/menu-family-block.d.ts +15 -9
- package/dist/components/menu-family-block.js +63 -60
- package/dist/components/menu-family-card.js +1 -1
- package/dist/components/menu-family-tiles.d.ts +19 -0
- package/dist/components/menu-family-tiles.js +57 -0
- package/dist/components/menu-hub-hero.js +8 -6
- package/dist/components/menu-index-list.d.ts +31 -12
- package/dist/components/menu-index-list.js +68 -31
- package/dist/components/menu-intent-hero.d.ts +1 -1
- package/dist/components/menu-kitchen-list.js +1 -1
- package/dist/components/menu-mocks.d.ts +10 -3
- package/dist/components/menu-mocks.js +21 -9
- package/dist/components/menu-types.d.ts +33 -10
- package/dist/components/multi-select-combobox.js +1 -1
- package/dist/components/native-select.d.ts +2 -2
- package/dist/components/pagination.js +1 -1
- package/dist/components/photo-ground.d.ts +7 -1
- package/dist/components/photo-ground.js +1 -1
- package/dist/components/searchable-select.js +1 -1
- package/dist/components/select.d.ts +1 -1
- package/dist/components/sliding-panels.js +1 -1
- package/dist/components/snap-rail.d.ts +2 -7
- package/dist/components/snap-rail.js +1 -1
- package/dist/components/spinner.d.ts +4 -4
- package/dist/components/tag.d.ts +4 -4
- package/dist/components/text.d.ts +5 -5
- package/dist/components/toggle.d.ts +1 -1
- package/dist/components/venue-grade-dimensions.js +1 -1
- package/dist/components/weekday-theme-banner.d.ts +24 -3
- package/dist/components/weekday-theme-banner.js +62 -14
- package/package.json +1 -1
- package/src/components/button.stories.tsx +25 -2
- package/src/components/button.tsx +12 -0
- package/src/components/colour-dictionary.stories.tsx +1 -1
- package/src/components/concept-compare.tsx +40 -9
- package/src/components/item.tsx +69 -45
- package/src/components/kitchen-dossier.tsx +45 -24
- package/src/components/menu-family-block.tsx +86 -79
- package/src/components/menu-family-tiles.stories.tsx +54 -0
- package/src/components/menu-family-tiles.test.tsx +30 -0
- package/src/components/menu-family-tiles.tsx +132 -0
- package/src/components/menu-hub-hero.tsx +13 -7
- package/src/components/menu-index-list.stories.tsx +6 -1
- package/src/components/menu-index-list.tsx +101 -54
- package/src/components/menu-intent-hero.tsx +1 -1
- package/src/components/menu-kitchen-list.tsx +4 -1
- package/src/components/menu-mocks.ts +32 -9
- package/src/components/menu-types.ts +32 -9
- package/src/components/photo-ground.tsx +13 -1
- package/src/components/snap-rail.tsx +19 -0
- package/src/components/venue-grade-dimensions.tsx +9 -2
- package/src/components/weekday-theme-banner.stories.tsx +43 -4
- package/src/components/weekday-theme-banner.tsx +94 -17
- package/dist/components/menu-intent-tiles.d.ts +0 -31
- package/dist/components/menu-intent-tiles.js +0 -50
- package/src/components/menu-intent-tiles.stories.tsx +0 -54
- package/src/components/menu-intent-tiles.tsx +0 -76
package/dist/components/kbd.d.ts
CHANGED
|
@@ -3,10 +3,10 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const kbdVariants: (props?: ({
|
|
6
|
-
size?: "
|
|
6
|
+
size?: "default" | "sm" | "lg" | null | undefined;
|
|
7
7
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
8
8
|
declare const Kbd: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & VariantProps<(props?: ({
|
|
9
|
-
size?: "
|
|
9
|
+
size?: "default" | "sm" | "lg" | null | undefined;
|
|
10
10
|
} & class_variance_authority_types.ClassProp) | undefined) => string> & React.RefAttributes<HTMLElement>>;
|
|
11
11
|
declare const KbdGroup: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLSpanElement> & React.RefAttributes<HTMLSpanElement>>;
|
|
12
12
|
|
|
@@ -56,6 +56,8 @@ type KitchenDossierLabels = {
|
|
|
56
56
|
next: string;
|
|
57
57
|
/** Dimension key → translated label. */
|
|
58
58
|
dimensions: Partial<Record<VenueGradeDimensionKey, string>>;
|
|
59
|
+
/** Beside the grade in the title row, e.g. "/10". Omit for the bare numeral. */
|
|
60
|
+
gradeUnit?: string;
|
|
59
61
|
};
|
|
60
62
|
type KitchenDossierProps = {
|
|
61
63
|
place: PlacePreview;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { DIMENSION_ORDER, VenueGradeDimensions } from '../chunk-
|
|
1
|
+
import { DIMENSION_ORDER, VenueGradeDimensions } from '../chunk-ZQ53AGML.js';
|
|
2
2
|
import { VenueQuotes } from '../chunk-43RC7MHY.js';
|
|
3
3
|
import { StoryProvider, StorySegments, StoryPanel } from '../chunk-F6FMZJDG.js';
|
|
4
4
|
import { GlassGround } from '../chunk-WCTHZKU7.js';
|
|
5
5
|
import { Separator } from '../chunk-WSRWFA6K.js';
|
|
6
|
-
import { PhotoGround, PHOTO_GROUND } from '../chunk-
|
|
6
|
+
import { PhotoGround, PHOTO_GROUND } from '../chunk-CNJQUHCU.js';
|
|
7
7
|
import { cn } from '../chunk-FEK5XGZW.js';
|
|
8
8
|
import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
|
|
9
9
|
import { MessageSquareQuote, Star } from 'lucide-react';
|
|
@@ -85,21 +85,18 @@ function KitchenDossier({
|
|
|
85
85
|
var _a2, _b2;
|
|
86
86
|
return ((_a2 = dimensions[b]) != null ? _a2 : 0) - ((_b2 = dimensions[a]) != null ? _b2 : 0);
|
|
87
87
|
}).slice(0, DIMENSION_LIMIT) : [];
|
|
88
|
-
if (
|
|
88
|
+
if (dimensions && strongest.length > 0) {
|
|
89
89
|
parts.push(
|
|
90
|
-
/* @__PURE__ */ jsx(Part, { kicker: labels.theGrade, children: /* @__PURE__ */
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
)
|
|
102
|
-
] }) }, "grade")
|
|
90
|
+
/* @__PURE__ */ jsx(Part, { kicker: labels.theGrade, children: /* @__PURE__ */ jsx(
|
|
91
|
+
VenueGradeDimensions,
|
|
92
|
+
{
|
|
93
|
+
className: "min-w-0",
|
|
94
|
+
dimensions,
|
|
95
|
+
labels: labels.dimensions,
|
|
96
|
+
order: strongest,
|
|
97
|
+
formatScore
|
|
98
|
+
}
|
|
99
|
+
) }, "grade")
|
|
103
100
|
);
|
|
104
101
|
}
|
|
105
102
|
return /* @__PURE__ */ jsxs(
|
|
@@ -153,12 +150,22 @@ function KitchenDossier({
|
|
|
153
150
|
/* @__PURE__ */ jsxs("div", { className: "[text-shadow:0_1px_12px_oklch(0_0_0/0.55)]", children: [
|
|
154
151
|
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-4", children: [
|
|
155
152
|
/* @__PURE__ */ jsx("h3", { className: "min-w-0 font-serif text-[26px] font-semibold leading-tight tracking-[-0.02em] text-white lg:text-[32px]", children: /* @__PURE__ */ jsx(LinkComponent, { href, className: "focus-visible:outline-none focus-visible:underline", children: place.name }) }),
|
|
156
|
-
|
|
153
|
+
(grade == null ? void 0 : grade.overall) ? /* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-baseline gap-1 text-[22px] font-extrabold leading-none tabular-nums text-[oklch(0.82_0.15_85)] lg:text-[26px]", children: [
|
|
154
|
+
grade.overall,
|
|
155
|
+
labels.gradeUnit && /* @__PURE__ */ jsx("span", { className: "text-[11px] font-bold text-white/70", children: labels.gradeUnit })
|
|
156
|
+
] }) : rating !== void 0 && /* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center gap-1 text-[18px] font-extrabold leading-none tabular-nums text-white lg:text-[22px]", children: [
|
|
157
157
|
rating.toFixed(1),
|
|
158
158
|
/* @__PURE__ */ jsx(Star, { className: "h-3.5 w-3.5 lg:h-4 lg:w-4", "aria-hidden": true })
|
|
159
159
|
] })
|
|
160
160
|
] }),
|
|
161
|
-
(meta || labels.reviewCount) && /* @__PURE__ */
|
|
161
|
+
(meta || labels.reviewCount || (grade == null ? void 0 : grade.overall) && rating !== void 0) && /* @__PURE__ */ jsxs("p", { className: "mt-1 flex min-w-0 items-center gap-1 text-[12.5px] text-white/70", children: [
|
|
162
|
+
(meta || labels.reviewCount) && /* @__PURE__ */ jsx("span", { className: "truncate", children: [meta, labels.reviewCount].filter(Boolean).join(" \xB7 ") }),
|
|
163
|
+
(grade == null ? void 0 : grade.overall) && rating !== void 0 && /* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center gap-1 tabular-nums", children: [
|
|
164
|
+
(meta || labels.reviewCount) && /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\xB7" }),
|
|
165
|
+
rating.toFixed(1),
|
|
166
|
+
/* @__PURE__ */ jsx(Star, { className: "h-3 w-3", "aria-hidden": true })
|
|
167
|
+
] })
|
|
168
|
+
] })
|
|
162
169
|
] }),
|
|
163
170
|
parts.length > 0 && /* @__PURE__ */ jsx(
|
|
164
171
|
StoryPanel,
|
|
@@ -5,15 +5,16 @@ import 'react';
|
|
|
5
5
|
import './place-types.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* MenuFamilyBlock — the cuisines index's family card.
|
|
8
|
+
* MenuFamilyBlock — the cuisines index's family card. One photograph is the ground.
|
|
9
9
|
*
|
|
10
10
|
* ## Three layers, and everything floats on them
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* One venue photograph is the background for the ENTIRE card, edge to edge,
|
|
13
|
+
* and the facts sit on it. Three layers do the work:
|
|
14
14
|
*
|
|
15
|
-
* 1. **The
|
|
16
|
-
* `mix-blend-color` layer.
|
|
15
|
+
* 1. **The photograph**, full-bleed, wearing the family's hue through a
|
|
16
|
+
* `mix-blend-color` layer. It was a mosaic of six; the design draws one
|
|
17
|
+
* plate, and six tiles under the ink read as texture rather than a room.
|
|
17
18
|
* 2. **An ink gradient** — absent where the photography is the subject, full
|
|
18
19
|
* where the rows begin. This is what buys the contrast. There used to be a
|
|
19
20
|
* masked backdrop-filter under it; it was removed for the measurement
|
|
@@ -22,10 +23,9 @@ import './place-types.js';
|
|
|
22
23
|
*
|
|
23
24
|
* On the phone the ink runs top to bottom: the name and the action sit on
|
|
24
25
|
* clear photography, the chips and the rows on the inked foot. On desktop the
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* photograph too big to read as texture.
|
|
26
|
+
* photo column on the left (a third) stays clear, and the row column on the
|
|
27
|
+
* right is opaque paper in the card's own dark — three venue rows never sit
|
|
28
|
+
* on a photograph.
|
|
29
29
|
*
|
|
30
30
|
* ## The dark scope
|
|
31
31
|
*
|
|
@@ -67,6 +67,12 @@ type MenuFamilyBlockLabels = {
|
|
|
67
67
|
priceBand: string;
|
|
68
68
|
/** Main action, e.g. "Browse Italian". Sits on the photography — keep it short. */
|
|
69
69
|
browse: string;
|
|
70
|
+
/**
|
|
71
|
+
* The action from `lg`, where the photo column is a third of the card and
|
|
72
|
+
* "Browse Bakeries & patisseries" does not fit — e.g. "Browse". The full
|
|
73
|
+
* `browse` stays the accessible name.
|
|
74
|
+
*/
|
|
75
|
+
browseShort?: string;
|
|
70
76
|
/** Passed through to the venue rows. */
|
|
71
77
|
kitchens: MenuKitchenListLabels;
|
|
72
78
|
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { MenuKitchenList } from '../chunk-
|
|
1
|
+
import { MenuKitchenList } from '../chunk-3NMG3KNA.js';
|
|
2
2
|
import { HueChip } from '../chunk-CLLY6XB3.js';
|
|
3
3
|
import { Separator } from '../chunk-WSRWFA6K.js';
|
|
4
|
-
import { PhotoGround, PHOTO_GROUND } from '../chunk-
|
|
4
|
+
import { PhotoGround, PHOTO_GROUND } from '../chunk-CNJQUHCU.js';
|
|
5
5
|
import { Skeleton } from '../chunk-QXHMPJ35.js';
|
|
6
|
+
import { buttonVariants } from '../chunk-VAXOQS7W.js';
|
|
7
|
+
import '../chunk-R47NEOSI.js';
|
|
6
8
|
import { cn } from '../chunk-FEK5XGZW.js';
|
|
7
9
|
import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
|
|
8
10
|
import { Wallet } from 'lucide-react';
|
|
@@ -12,10 +14,9 @@ function DefaultLink(_a) {
|
|
|
12
14
|
var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
|
|
13
15
|
return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
|
|
14
16
|
}
|
|
15
|
-
var MOSAIC_TILES = 6;
|
|
16
|
-
var PHONE_TILES = 4;
|
|
17
17
|
var GROUND = PHOTO_GROUND;
|
|
18
|
-
var INK = "bg-[linear-gradient(to_bottom,oklch(0.16_0.012_55_/_0.
|
|
18
|
+
var INK = "bg-[linear-gradient(to_bottom,oklch(0.16_0.012_55_/_0.12)_0%,oklch(0.16_0.012_55_/_0.55)_38%,oklch(0.16_0.012_55_/_0.92)_62%,oklch(0.16_0.012_55_/_0.96)_100%)] lg:bg-[linear-gradient(to_right,oklch(0.16_0.012_55_/_0.38)_0%,oklch(0.16_0.012_55_/_0.6)_30%,oklch(0.16_0.012_55_/_0.92)_46%,oklch(0.16_0.012_55_/_0.96)_100%)]";
|
|
19
|
+
var PAPER = "lg:bg-[oklch(0.21_0.012_55)]";
|
|
19
20
|
var TEXT_SCRIM = (
|
|
20
21
|
/* `isolate` + `before:-z-10`: a positioned pseudo-element paints ABOVE the
|
|
21
22
|
column's in-flow text unless the column is its own stacking context and
|
|
@@ -32,11 +33,11 @@ function MenuFamilyBlock({
|
|
|
32
33
|
linkComponent: LinkComponent = DefaultLink,
|
|
33
34
|
className
|
|
34
35
|
}) {
|
|
35
|
-
var _a, _b, _c, _d
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
const
|
|
36
|
+
var _a, _b, _c, _d;
|
|
37
|
+
const [photo] = (_a = family.photoUrls) != null ? _a : [];
|
|
38
|
+
const venues = (_b = family.venues) != null ? _b : [];
|
|
39
|
+
const overflow = Math.max(family.venueCount - venues.length, 0);
|
|
40
|
+
const initial = ((_d = (_c = family.name.match(new RegExp("\\p{L}", "u"))) == null ? void 0 : _c[0]) != null ? _d : "").toLocaleUpperCase();
|
|
40
41
|
return /* @__PURE__ */ jsxs(
|
|
41
42
|
"article",
|
|
42
43
|
{
|
|
@@ -48,54 +49,56 @@ function MenuFamilyBlock({
|
|
|
48
49
|
className
|
|
49
50
|
),
|
|
50
51
|
children: [
|
|
51
|
-
/* @__PURE__ */ jsx(
|
|
52
|
-
PhotoGround,
|
|
53
|
-
{
|
|
54
|
-
photos: photos.length > 0 ? photos : [void 0],
|
|
55
|
-
initials: initial,
|
|
56
|
-
mosaicClassName: photos.length > 0 ? "grid-cols-2 grid-rows-2 lg:grid-cols-3" : "grid-cols-1",
|
|
57
|
-
phoneTiles: PHONE_TILES,
|
|
58
|
-
gradient
|
|
59
|
-
}
|
|
60
|
-
),
|
|
52
|
+
/* @__PURE__ */ jsx(PhotoGround, { photos: [photo], initials: initial, mode: "stack", gradient }),
|
|
61
53
|
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cn("absolute inset-0", INK) }),
|
|
62
|
-
/* @__PURE__ */ jsxs("div", { className: "relative grid grid-cols-1 lg:grid-cols-[
|
|
63
|
-
/* @__PURE__ */ jsxs(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
{
|
|
70
|
-
href: family.href,
|
|
71
|
-
className: "mt-3.5 inline-flex h-10 w-max items-center rounded-full border border-white/20 bg-white/[0.16] px-4 text-[13.5px] font-bold text-white transition-colors hover:bg-white/25 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white motion-reduce:transition-none",
|
|
72
|
-
children: labels.browse
|
|
73
|
-
}
|
|
74
|
-
)
|
|
75
|
-
] }),
|
|
76
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col px-3.5 pb-3.5 lg:p-5", children: [
|
|
77
|
-
/* @__PURE__ */ jsxs("ul", { className: "flex flex-wrap items-center gap-1.5", children: [
|
|
78
|
-
family.priceBandLabel && /* No hue: a fact about money, not about the family. In the dark
|
|
79
|
-
scope `HueChip`'s `--muted` fallback is the dark pill the design
|
|
80
|
-
draws. */
|
|
81
|
-
/* @__PURE__ */ jsx(
|
|
82
|
-
HueChip,
|
|
83
|
-
{
|
|
84
|
-
as: "li",
|
|
85
|
-
className: "font-bold tabular-nums",
|
|
86
|
-
"aria-label": `${labels.priceBand}: ${family.priceBandLabel}`,
|
|
87
|
-
icon: /* @__PURE__ */ jsx(Wallet, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground", "aria-hidden": true }),
|
|
88
|
-
children: family.priceBandLabel
|
|
89
|
-
}
|
|
54
|
+
/* @__PURE__ */ jsxs("div", { className: "relative grid grid-cols-1 lg:grid-cols-[34%_1fr]", children: [
|
|
55
|
+
/* @__PURE__ */ jsxs(
|
|
56
|
+
"div",
|
|
57
|
+
{
|
|
58
|
+
className: cn(
|
|
59
|
+
"relative flex min-h-[220px] flex-col justify-end p-3.5 lg:min-h-[320px] lg:p-5",
|
|
60
|
+
TEXT_SCRIM
|
|
90
61
|
),
|
|
91
|
-
|
|
92
|
-
/*
|
|
93
|
-
|
|
94
|
-
/* @__PURE__ */
|
|
95
|
-
|
|
96
|
-
|
|
62
|
+
children: [
|
|
63
|
+
overflow > 0 && /* @__PURE__ */ jsx("span", { className: "absolute right-3.5 top-3.5 rounded-full bg-[oklch(0.16_0.012_55_/_0.78)] px-2.5 py-1 text-[11px] font-semibold text-white lg:static lg:mb-3 lg:self-start", children: labels.more(overflow) }),
|
|
64
|
+
/* @__PURE__ */ jsx("h3", { className: "text-balance font-serif text-[26px] font-semibold leading-tight tracking-[-0.02em] text-white lg:text-[30px]", children: family.name }),
|
|
65
|
+
/* @__PURE__ */ jsxs("span", { className: "mt-1 flex flex-wrap items-center gap-x-2.5 gap-y-1 text-[13px] font-medium tabular-nums text-white/70", children: [
|
|
66
|
+
labels.venueUnit(family.venueCount),
|
|
67
|
+
family.priceBandLabel && /* @__PURE__ */ jsxs(
|
|
68
|
+
"span",
|
|
69
|
+
{
|
|
70
|
+
className: "inline-flex items-center gap-1",
|
|
71
|
+
"aria-label": `${labels.priceBand}: ${family.priceBandLabel}`,
|
|
72
|
+
children: [
|
|
73
|
+
/* @__PURE__ */ jsx(Wallet, { className: "h-3.5 w-3.5 shrink-0 text-white/60", "aria-hidden": true }),
|
|
74
|
+
family.priceBandLabel
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
] }),
|
|
79
|
+
/* @__PURE__ */ jsx(
|
|
80
|
+
LinkComponent,
|
|
81
|
+
{
|
|
82
|
+
href: family.href,
|
|
83
|
+
"aria-label": labels.browse,
|
|
84
|
+
className: cn(buttonVariants({ variant: "ink", size: "pill" }), "mt-3.5 w-max max-w-full"),
|
|
85
|
+
children: labels.browseShort ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
86
|
+
/* @__PURE__ */ jsx("span", { className: "lg:hidden", children: labels.browse }),
|
|
87
|
+
/* @__PURE__ */ jsx("span", { className: "hidden lg:inline", children: labels.browseShort })
|
|
88
|
+
] }) : labels.browse
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
),
|
|
94
|
+
/* @__PURE__ */ jsxs("div", { className: cn("flex min-w-0 flex-col px-3.5 pb-3.5 lg:p-5", PAPER), children: [
|
|
95
|
+
family.chips && family.chips.length > 0 && /* @__PURE__ */ jsx("ul", { className: "flex flex-wrap items-center gap-1.5 lg:justify-end", children: family.chips.map((chip) => (
|
|
96
|
+
/* Label only. The counts are VENUES beside a dish group's name,
|
|
97
|
+
which every reader takes for dishes. */
|
|
98
|
+
/* @__PURE__ */ jsx(HueChip, { as: "li", hue, children: chip.label }, chip.slug)
|
|
99
|
+
)) }),
|
|
97
100
|
venues.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
98
|
-
/* @__PURE__ */ jsx(Separator, { className: "my-3" }),
|
|
101
|
+
/* @__PURE__ */ jsx(Separator, { className: "my-3 via-white/15" }),
|
|
99
102
|
/* @__PURE__ */ jsx(
|
|
100
103
|
MenuKitchenList,
|
|
101
104
|
{
|
|
@@ -120,12 +123,12 @@ function MenuFamilyBlockSkeleton({
|
|
|
120
123
|
{
|
|
121
124
|
className: cn("dark relative overflow-hidden rounded-[14px]", GROUND, className),
|
|
122
125
|
"aria-hidden": true,
|
|
123
|
-
children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-[
|
|
124
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col p-3.5 lg:min-h-[320px] lg:
|
|
125
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "
|
|
126
|
+
children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-[34%_1fr]", children: [
|
|
127
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex min-h-[220px] flex-col justify-end p-3.5 lg:min-h-[320px] lg:p-5", children: [
|
|
128
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "absolute right-3.5 top-3.5 h-6 w-[72px] rounded-full lg:static lg:mb-3" }),
|
|
126
129
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-[60%]" }),
|
|
127
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-3.5 w-[
|
|
128
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "mt-3.5 h-
|
|
130
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-3.5 w-[150px]" }),
|
|
131
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "mt-3.5 h-11 w-[160px] rounded-full" })
|
|
129
132
|
] }),
|
|
130
133
|
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col px-3.5 pb-3.5 lg:p-5", children: [
|
|
131
134
|
/* @__PURE__ */ jsxs("div", { className: "flex gap-1.5", children: [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HueChip } from '../chunk-CLLY6XB3.js';
|
|
2
|
-
import { PhotoGround, PHOTO_GROUND } from '../chunk-
|
|
2
|
+
import { PhotoGround, PHOTO_GROUND } from '../chunk-CNJQUHCU.js';
|
|
3
3
|
import { cn } from '../chunk-FEK5XGZW.js';
|
|
4
4
|
import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
|
|
5
5
|
import { Wallet } from 'lucide-react';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { MenuFamilyTile, MenuLinkComponent } from './menu-types.js';
|
|
3
|
+
import 'react';
|
|
4
|
+
import './place-types.js';
|
|
5
|
+
|
|
6
|
+
type MenuFamilyTilesProps = {
|
|
7
|
+
tiles: MenuFamilyTile[];
|
|
8
|
+
/**
|
|
9
|
+
* The closing tile: the index behind the seven, drawn exactly like them —
|
|
10
|
+
* its own hue and photograph, `countLabel` as the caption. Only its place in
|
|
11
|
+
* the grid says it is the index. Omit when there is none.
|
|
12
|
+
*/
|
|
13
|
+
all?: MenuFamilyTile;
|
|
14
|
+
linkComponent?: MenuLinkComponent;
|
|
15
|
+
className?: string;
|
|
16
|
+
};
|
|
17
|
+
declare function MenuFamilyTiles({ tiles, all, linkComponent: LinkComponent, className, }: MenuFamilyTilesProps): react_jsx_runtime.JSX.Element;
|
|
18
|
+
|
|
19
|
+
export { MenuFamilyTiles, type MenuFamilyTilesProps };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { PhotoGround } from '../chunk-CNJQUHCU.js';
|
|
2
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
3
|
+
import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
|
|
4
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
function DefaultLink(_a) {
|
|
7
|
+
var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
|
|
8
|
+
return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
|
|
9
|
+
}
|
|
10
|
+
var TILE = "group relative isolate flex aspect-[16/10] min-h-[108px] flex-col justify-end overflow-hidden rounded-2xl bg-muted p-3.5 text-white lg:p-4 transition-[transform,box-shadow] duration-200 hover:-translate-y-0.5 hover:shadow-[var(--shadow-card-hover)] active:translate-y-0 active:scale-[0.99] motion-reduce:transition-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2";
|
|
11
|
+
var POLAROID = "absolute -right-[4%] -top-[8%] z-0 block aspect-square h-[82%] overflow-hidden rounded-[10%] rotate-[8deg] shadow-[0_10px_22px_-6px_oklch(0.16_0.012_55_/_0.65)] transition-transform duration-300 group-hover:rotate-[5deg] motion-reduce:transition-none";
|
|
12
|
+
var SCRIM = "after:pointer-events-none after:absolute after:inset-x-0 after:bottom-0 after:z-0 after:h-3/5 after:bg-gradient-to-t after:from-[oklch(0.16_0.012_55_/_0.55)] after:to-transparent after:content-['']";
|
|
13
|
+
function MenuFamilyTiles({
|
|
14
|
+
tiles,
|
|
15
|
+
all,
|
|
16
|
+
linkComponent: LinkComponent = DefaultLink,
|
|
17
|
+
className
|
|
18
|
+
}) {
|
|
19
|
+
const cells = all ? [...tiles, all] : tiles;
|
|
20
|
+
return /* @__PURE__ */ jsx("div", { className: cn("grid grid-cols-2 gap-3 lg:grid-cols-4 lg:gap-3.5", className), children: cells.map((tile) => /* @__PURE__ */ jsxs(
|
|
21
|
+
LinkComponent,
|
|
22
|
+
{
|
|
23
|
+
href: tile.href,
|
|
24
|
+
className: cn(TILE, SCRIM),
|
|
25
|
+
style: tile.gradient ? { backgroundImage: tile.gradient } : void 0,
|
|
26
|
+
children: [
|
|
27
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: POLAROID, children: tile.photoUrl ? (
|
|
28
|
+
/* Not lazy: the grid sits directly under the hero, and these
|
|
29
|
+
photographs are the first thing the reader looks at. */
|
|
30
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
31
|
+
/* @__PURE__ */ jsx(
|
|
32
|
+
"img",
|
|
33
|
+
{
|
|
34
|
+
src: tile.photoUrl,
|
|
35
|
+
alt: "",
|
|
36
|
+
decoding: "async",
|
|
37
|
+
className: "absolute inset-0 h-full w-full object-cover"
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
) : /* @__PURE__ */ jsx(
|
|
41
|
+
PhotoGround,
|
|
42
|
+
{
|
|
43
|
+
photos: [void 0],
|
|
44
|
+
initials: tile.label.charAt(0),
|
|
45
|
+
mode: "stack",
|
|
46
|
+
glyphClassName: "text-[44px]"
|
|
47
|
+
}
|
|
48
|
+
) }),
|
|
49
|
+
/* @__PURE__ */ jsx("span", { className: "relative z-[1] line-clamp-2 max-w-[55%] text-[14.5px] font-extrabold leading-[1.2] tracking-[-0.015em] lg:text-[16px]", children: tile.label }),
|
|
50
|
+
tile.countLabel && /* @__PURE__ */ jsx("span", { className: "relative z-[1] mt-0.5 max-w-[55%] truncate text-[12px] font-medium leading-[1.35] tabular-nums text-white/80 lg:text-[13px]", children: tile.countLabel })
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
tile.slug
|
|
54
|
+
)) });
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export { MenuFamilyTiles };
|
|
@@ -85,14 +85,16 @@ function MenuHubHero({
|
|
|
85
85
|
kickerIcon,
|
|
86
86
|
kicker
|
|
87
87
|
] }),
|
|
88
|
-
/* @__PURE__ */ jsx("h1", { className: "max-w-[640px] font-serif text-[
|
|
88
|
+
/* @__PURE__ */ jsx("h1", { className: "max-w-[640px] font-serif text-[28px] font-semibold leading-[1.06] tracking-[-0.025em] lg:text-[50px] lg:leading-[1.04]", children: headline }),
|
|
89
89
|
body && /* @__PURE__ */ jsx("p", { className: "hidden max-w-[540px] text-sm leading-[1.6] opacity-[0.84] lg:block lg:text-[15.5px]", children: body }),
|
|
90
|
-
figures && figures.length > 0 && //
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
figures && figures.length > 0 && // One row of four on the phone. It was two by two, which was the
|
|
91
|
+
// taller half of a 500px hero; at 20px the widest figure ("19,090")
|
|
92
|
+
// is ~68px and four of them share a 358px column with room.
|
|
93
|
+
/* @__PURE__ */ jsx("div", { className: "flex justify-between gap-x-3 pt-2 lg:flex-wrap lg:justify-start lg:gap-x-8 lg:gap-y-4 lg:pt-1.5", children: figures.map((figure) => /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
94
|
+
/* @__PURE__ */ jsx("div", { className: "text-xl font-black leading-none tracking-[-0.02em] tabular-nums lg:text-[32px] lg:tracking-[-0.03em]", children: figure.value }),
|
|
95
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1 text-[11px] leading-tight opacity-[0.72] lg:mt-[5px] lg:text-xs", children: figure.label })
|
|
94
96
|
] }, figure.label)) }),
|
|
95
|
-
(proof || action) && /* @__PURE__ */ jsxs("div", { className: "mt-auto flex flex-wrap items-center gap-3 pt-5", children: [
|
|
97
|
+
(proof || action) && /* @__PURE__ */ jsxs("div", { className: "mt-auto flex flex-wrap items-center gap-3 pt-4 lg:pt-5", children: [
|
|
96
98
|
proof && /* @__PURE__ */ jsxs("span", { className: "inline-flex min-h-11 items-center gap-2.5 rounded-full bg-white/[0.14] px-4 py-2 text-[13px]", children: [
|
|
97
99
|
proofIcon,
|
|
98
100
|
proof
|
|
@@ -4,19 +4,24 @@ import 'react';
|
|
|
4
4
|
import './place-types.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* MenuIndexList — the complete set,
|
|
7
|
+
* MenuIndexList — the complete set: one column on a phone, three from `lg`.
|
|
8
8
|
*
|
|
9
9
|
* ## This block is why the page can afford to be progressive
|
|
10
10
|
*
|
|
11
11
|
* It carries a crawlable link to EVERY destination the city has — all
|
|
12
|
-
* thirty-eight cuisines,
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* thirty-eight cuisines, in the markup at every width. That makes it the
|
|
13
|
+
* page's entire link-equity job, which in turn means the rich cards above
|
|
14
|
+
* are free to be a swipe rail on a phone: nothing a crawler needs waits on a
|
|
15
|
+
* swipe, because it is all here.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* The phone's own "show all" is CSS, not markup: every row is in the DOM and
|
|
18
|
+
* the ones past `collapsedCount` are hidden below `lg` until the button is
|
|
19
|
+
* pressed. A list that mounted its tail on tap would have taken twenty-six
|
|
20
|
+
* links out of the page for the crawler that never taps.
|
|
21
|
+
*
|
|
22
|
+
* Get this backwards — mount the rows behind the expander on tap — and the
|
|
23
|
+
* page silently stops linking to twenty-six pages it is supposed to be the
|
|
24
|
+
* index for.
|
|
20
25
|
*
|
|
21
26
|
* ## Ordered by count, and the counts overlap
|
|
22
27
|
*
|
|
@@ -24,6 +29,10 @@ import './place-types.js';
|
|
|
24
29
|
* places, because a trattoria is Italian AND pizza AND international. So this
|
|
25
30
|
* is a ranked list of ways in, never a partition, and no copy near it may total
|
|
26
31
|
* the numbers or call them a breakdown.
|
|
32
|
+
*
|
|
33
|
+
* A client component for the one piece of state the expander needs; the
|
|
34
|
+
* `linkComponent` a server caller hands in must therefore be a client
|
|
35
|
+
* reference (`ClientLink`), not `next/link` itself.
|
|
27
36
|
*/
|
|
28
37
|
/** @deprecated Alias of `MenuLinkProps`; kept for symmetry with the other menu surfaces. */
|
|
29
38
|
type MenuIndexListLinkProps = MenuLinkProps;
|
|
@@ -33,13 +42,23 @@ type MenuIndexListProps = {
|
|
|
33
42
|
title: string;
|
|
34
43
|
/** One line under it, e.g. "Ordered by kitchens — every one has its own page". */
|
|
35
44
|
subtitle?: string;
|
|
36
|
-
/**
|
|
37
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Rows shown on a phone before the expander; the rest are hidden below `lg`
|
|
47
|
+
* until it is pressed. Omit to show every row at every width.
|
|
48
|
+
*/
|
|
49
|
+
collapsedCount?: number;
|
|
50
|
+
/** The expander's labels, e.g. "Show all 38 cuisines" / "Show fewer". */
|
|
51
|
+
expandLabels?: {
|
|
52
|
+
showAll: string;
|
|
53
|
+
showFewer: string;
|
|
54
|
+
};
|
|
55
|
+
/** The colour mark beside each name, keyed by slug. Falls back to the border colour. */
|
|
56
|
+
hues?: Record<string, string>;
|
|
38
57
|
linkComponent?: MenuLinkComponent;
|
|
39
58
|
className?: string;
|
|
40
59
|
};
|
|
41
|
-
declare function MenuIndexList({ entries, title, subtitle,
|
|
42
|
-
/**
|
|
60
|
+
declare function MenuIndexList({ entries, title, subtitle, collapsedCount, expandLabels, hues, linkComponent: LinkComponent, className, }: MenuIndexListProps): react_jsx_runtime.JSX.Element;
|
|
61
|
+
/** One column on a phone, three from `lg` — the grid the list itself renders. */
|
|
43
62
|
declare function MenuIndexListSkeleton({ rows, className, }: {
|
|
44
63
|
rows?: number;
|
|
45
64
|
className?: string;
|