@bearmenu/ui 0.8.10 → 0.8.12

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.
Files changed (101) hide show
  1. package/dist/{chunk-UKBNQO6Q.js → chunk-2CXU5WZO.js} +1 -1
  2. package/dist/{chunk-62ES6N32.js → chunk-43RC7MHY.js} +1 -1
  3. package/dist/{chunk-Q6QH52LJ.js → chunk-6TEEY5YA.js} +2 -2
  4. package/dist/{chunk-UDN7UHJW.js → chunk-7A42J73Q.js} +3 -2
  5. package/dist/{chunk-5RWTOT5Y.js → chunk-CNJQUHCU.js} +11 -1
  6. package/dist/{chunk-TH6W2PWG.js → chunk-UDTG3RSE.js} +1 -1
  7. package/dist/{chunk-H3BV4VAG.js → chunk-VAXOQS7W.js} +14 -2
  8. package/dist/{chunk-SY6RV476.js → chunk-WCTHZKU7.js} +10 -21
  9. package/dist/{chunk-AKQ57NXY.js → chunk-ZQ53AGML.js} +2 -2
  10. package/dist/components/alert-dialog.js +1 -1
  11. package/dist/components/badge.js +1 -1
  12. package/dist/components/button.d.ts +2 -2
  13. package/dist/components/button.js +1 -1
  14. package/dist/components/calendar.js +1 -1
  15. package/dist/components/carousel.js +1 -1
  16. package/dist/components/combobox.js +1 -1
  17. package/dist/components/concept-compare-rail.js +2 -2
  18. package/dist/components/concept-compare.d.ts +1 -1
  19. package/dist/components/concept-compare.js +31 -10
  20. package/dist/components/concept-convergence.js +2 -2
  21. package/dist/components/empty-state.js +1 -1
  22. package/dist/components/event-detail-panel.js +1 -1
  23. package/dist/components/event-list-row-wide.js +1 -1
  24. package/dist/components/filter-category-row.js +1 -1
  25. package/dist/components/glass-ground.d.ts +26 -31
  26. package/dist/components/glass-ground.js +1 -1
  27. package/dist/components/haptic-button.js +1 -1
  28. package/dist/components/input-group.d.ts +2 -2
  29. package/dist/components/input.d.ts +1 -1
  30. package/dist/components/item.d.ts +15 -5
  31. package/dist/components/item.js +15 -10
  32. package/dist/components/kitchen-dossier.d.ts +9 -7
  33. package/dist/components/kitchen-dossier.js +31 -25
  34. package/dist/components/link-button.js +1 -1
  35. package/dist/components/menu-family-block.d.ts +22 -17
  36. package/dist/components/menu-family-block.js +62 -61
  37. package/dist/components/menu-family-card.js +2 -4
  38. package/dist/components/menu-family-tiles.d.ts +19 -0
  39. package/dist/components/menu-family-tiles.js +57 -0
  40. package/dist/components/menu-hub-hero.js +18 -11
  41. package/dist/components/menu-index-list.d.ts +31 -12
  42. package/dist/components/menu-index-list.js +68 -31
  43. package/dist/components/menu-intent-hero.d.ts +1 -1
  44. package/dist/components/menu-item.js +3 -3
  45. package/dist/components/menu-mocks.d.ts +10 -3
  46. package/dist/components/menu-mocks.js +21 -9
  47. package/dist/components/menu-types.d.ts +33 -10
  48. package/dist/components/multi-select-combobox.js +2 -2
  49. package/dist/components/pagination.js +1 -1
  50. package/dist/components/photo-ground.d.ts +8 -2
  51. package/dist/components/photo-ground.js +1 -1
  52. package/dist/components/place-details-mobile.js +1 -1
  53. package/dist/components/searchable-select.js +1 -1
  54. package/dist/components/signature-chip.d.ts +2 -2
  55. package/dist/components/signature-chip.js +2 -2
  56. package/dist/components/sliding-panels.js +1 -1
  57. package/dist/components/top-ranking-entry.js +3 -3
  58. package/dist/components/venue-grade-dimensions.js +1 -1
  59. package/dist/components/venue-quotes.d.ts +1 -1
  60. package/dist/components/venue-quotes.js +1 -1
  61. package/dist/components/venue-wall.js +5 -3
  62. package/dist/components/weekday-theme-banner.d.ts +24 -3
  63. package/dist/components/weekday-theme-banner.js +63 -15
  64. package/package.json +1 -1
  65. package/src/components/badge.tsx +1 -1
  66. package/src/components/button.stories.tsx +25 -2
  67. package/src/components/button.tsx +14 -2
  68. package/src/components/colour-dictionary.stories.tsx +1 -1
  69. package/src/components/concept-compare-rail.tsx +2 -1
  70. package/src/components/concept-compare.stories.tsx +3 -3
  71. package/src/components/concept-compare.tsx +50 -14
  72. package/src/components/glass-ground.tsx +31 -56
  73. package/src/components/item.tsx +69 -45
  74. package/src/components/kitchen-dossier.stories.tsx +1 -1
  75. package/src/components/kitchen-dossier.tsx +60 -40
  76. package/src/components/menu-family-block.stories.tsx +3 -3
  77. package/src/components/menu-family-block.tsx +94 -98
  78. package/src/components/menu-family-card.stories.tsx +2 -2
  79. package/src/components/menu-family-card.tsx +6 -13
  80. package/src/components/menu-family-tiles.stories.tsx +54 -0
  81. package/src/components/menu-family-tiles.test.tsx +30 -0
  82. package/src/components/menu-family-tiles.tsx +132 -0
  83. package/src/components/menu-hub-hero.test.tsx +39 -0
  84. package/src/components/menu-hub-hero.tsx +30 -12
  85. package/src/components/menu-index-list.stories.tsx +6 -1
  86. package/src/components/menu-index-list.tsx +101 -54
  87. package/src/components/menu-intent-hero.tsx +1 -1
  88. package/src/components/menu-mocks.ts +32 -9
  89. package/src/components/menu-types.ts +32 -9
  90. package/src/components/photo-ground.tsx +14 -2
  91. package/src/components/signature-chip.tsx +3 -3
  92. package/src/components/venue-grade-dimensions.tsx +9 -2
  93. package/src/components/venue-quotes.stories.tsx +1 -1
  94. package/src/components/venue-quotes.tsx +4 -2
  95. package/src/components/venue-wall.tsx +9 -4
  96. package/src/components/weekday-theme-banner.stories.tsx +43 -4
  97. package/src/components/weekday-theme-banner.tsx +95 -18
  98. package/dist/components/menu-intent-tiles.d.ts +0 -31
  99. package/dist/components/menu-intent-tiles.js +0 -50
  100. package/src/components/menu-intent-tiles.stories.tsx +0 -54
  101. package/src/components/menu-intent-tiles.tsx +0 -76
@@ -48,9 +48,10 @@ var Item = React.forwardRef(
48
48
  Item.displayName = "Item";
49
49
  var ItemMedia = React.forwardRef(
50
50
  (_a, ref) => {
51
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
51
+ var _b = _a, { className, asChild } = _b, props = __objRest(_b, ["className", "asChild"]);
52
+ const Comp = asChild ? Slot : "div";
52
53
  return /* @__PURE__ */ jsx(
53
- "div",
54
+ Comp,
54
55
  __spreadValues({
55
56
  ref,
56
57
  "data-slot": "item-media",
@@ -62,9 +63,10 @@ var ItemMedia = React.forwardRef(
62
63
  ItemMedia.displayName = "ItemMedia";
63
64
  var ItemContent = React.forwardRef(
64
65
  (_a, ref) => {
65
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
66
+ var _b = _a, { className, asChild } = _b, props = __objRest(_b, ["className", "asChild"]);
67
+ const Comp = asChild ? Slot : "div";
66
68
  return /* @__PURE__ */ jsx(
67
- "div",
69
+ Comp,
68
70
  __spreadValues({
69
71
  ref,
70
72
  "data-slot": "item-content",
@@ -76,9 +78,10 @@ var ItemContent = React.forwardRef(
76
78
  ItemContent.displayName = "ItemContent";
77
79
  var ItemTitle = React.forwardRef(
78
80
  (_a, ref) => {
79
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
81
+ var _b = _a, { className, asChild } = _b, props = __objRest(_b, ["className", "asChild"]);
82
+ const Comp = asChild ? Slot : "div";
80
83
  return /* @__PURE__ */ jsx(
81
- "div",
84
+ Comp,
82
85
  __spreadValues({
83
86
  ref,
84
87
  "data-slot": "item-title",
@@ -90,9 +93,10 @@ var ItemTitle = React.forwardRef(
90
93
  ItemTitle.displayName = "ItemTitle";
91
94
  var ItemDescription = React.forwardRef(
92
95
  (_a, ref) => {
93
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
96
+ var _b = _a, { className, asChild } = _b, props = __objRest(_b, ["className", "asChild"]);
97
+ const Comp = asChild ? Slot : "div";
94
98
  return /* @__PURE__ */ jsx(
95
- "div",
99
+ Comp,
96
100
  __spreadValues({
97
101
  ref,
98
102
  "data-slot": "item-description",
@@ -104,9 +108,10 @@ var ItemDescription = React.forwardRef(
104
108
  ItemDescription.displayName = "ItemDescription";
105
109
  var ItemActions = React.forwardRef(
106
110
  (_a, ref) => {
107
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
111
+ var _b = _a, { className, asChild } = _b, props = __objRest(_b, ["className", "asChild"]);
112
+ const Comp = asChild ? Slot : "div";
108
113
  return /* @__PURE__ */ jsx(
109
- "div",
114
+ Comp,
110
115
  __spreadValues({
111
116
  ref,
112
117
  "data-slot": "item-actions",
@@ -10,7 +10,7 @@ import { VenueGradeDimensionKey } from './venue-grade-dimensions.js';
10
10
  * The hub used to say this three times: a spotlight with everything the
11
11
  * digest knows, a ranked row with a grade, a card with the signature dish —
12
12
  * and the same kitchen led all three. This is the one card: the venue's
13
- * photograph clear at the top, a frosted caption rising from the foot with
13
+ * photograph clear at the top, an inked caption rising from the foot with
14
14
  * the identity (rating, name, type · area · reviews), and under it a PANEL
15
15
  * that says the three or four things the reviews established one at a time —
16
16
  * the dish it is known for, what people say, the grade — with segments at the
@@ -23,12 +23,12 @@ import { VenueGradeDimensionKey } from './venue-grade-dimensions.js';
23
23
  * bands. This is the reverse — the room is the subject and the facts are its
24
24
  * caption — which is `GlassGround` at its lightest and smallest: anchored to
25
25
  * the CAPTION, not the card, so it covers the identity, the panel and the
26
- * action plus a short lead above them and nothing else; a `sm` blur that
27
- * only takes the edge off the detail; ink that never passes 0.45; a text
28
- * shadow under the identity doing the rest. Everything above the caption is
29
- * the photograph, untouched. The panel is its own glass, so its rule reads
30
- * as a panel and not a hole. The same layout at every width; the desktop
31
- * card is wider, not turned on its side.
26
+ * action plus a short lead above them and nothing else; ink that never
27
+ * passes 0.6; a text shadow under the identity doing the rest. Everything
28
+ * above the caption is the photograph, untouched. The panel is a translucent
29
+ * ink pane (no backdrop blur see `GlassGround` for the measurement that
30
+ * removed it), so its rule reads as a panel and not a hole. The same layout
31
+ * at every width; the desktop card is wider, not turned on its side.
32
32
  *
33
33
  * ## Two targets, and everything else is "next"
34
34
  *
@@ -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-AKQ57NXY.js';
2
- import { VenueQuotes } from '../chunk-62ES6N32.js';
1
+ import { DIMENSION_ORDER, VenueGradeDimensions } from '../chunk-ZQ53AGML.js';
2
+ import { VenueQuotes } from '../chunk-43RC7MHY.js';
3
3
  import { StoryProvider, StorySegments, StoryPanel } from '../chunk-F6FMZJDG.js';
4
- import { GlassGround } from '../chunk-SY6RV476.js';
4
+ import { GlassGround } from '../chunk-WCTHZKU7.js';
5
5
  import { Separator } from '../chunk-WSRWFA6K.js';
6
- import { PhotoGround, PHOTO_GROUND } from '../chunk-5RWTOT5Y.js';
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';
@@ -52,7 +52,7 @@ function KitchenDossier({
52
52
  children: item.name
53
53
  }
54
54
  ) : /* @__PURE__ */ jsx("span", { className: "text-[16px] font-bold leading-tight tracking-[-0.01em] text-white", children: item.name }),
55
- signature.why && /* @__PURE__ */ jsx("p", { className: "mt-1 line-clamp-2 font-serif text-[13px] italic leading-snug text-white/75", children: signature.why }),
55
+ signature.why && /* @__PURE__ */ jsx("p", { className: "mt-1 line-clamp-2 font-serif text-[13px] leading-snug text-white/75", children: signature.why }),
56
56
  (firstEntry || mentions > 0) && /* @__PURE__ */ jsxs(Fragment, { children: [
57
57
  /* @__PURE__ */ jsx(Separator, { className: "my-2.5 via-white/20" }),
58
58
  /* @__PURE__ */ jsxs("div", { className: "flex items-end justify-between gap-3", children: [
@@ -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 (grade && (grade.overall || strongest.length > 0)) {
88
+ if (dimensions && strongest.length > 0) {
89
89
  parts.push(
90
- /* @__PURE__ */ jsx(Part, { kicker: labels.theGrade, children: /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-4", children: [
91
- grade.overall && /* @__PURE__ */ jsx("span", { className: "text-[34px] font-extrabold leading-none tracking-[-0.03em] tabular-nums text-[oklch(0.82_0.15_85)]", children: grade.overall }),
92
- dimensions && strongest.length > 0 && /* @__PURE__ */ jsx(
93
- VenueGradeDimensions,
94
- {
95
- className: "min-w-0 flex-1",
96
- dimensions,
97
- labels: labels.dimensions,
98
- order: strongest,
99
- formatScore
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(
@@ -131,7 +128,7 @@ function KitchenDossier({
131
128
  className: "-mt-1"
132
129
  }
133
130
  ),
134
- /* @__PURE__ */ jsx("div", { className: "relative min-h-[184px] flex-1", children: labels.openUntil && /* @__PURE__ */ jsxs("span", { className: "absolute left-0 top-3 inline-flex h-[30px] items-center gap-[7px] rounded-full bg-[oklch(0.16_0.012_55_/_0.72)] px-3 text-[11.5px] font-bold text-white backdrop-blur-[2px]", children: [
131
+ /* @__PURE__ */ jsx("div", { className: "relative min-h-[184px] flex-1", children: labels.openUntil && /* @__PURE__ */ jsxs("span", { className: "absolute left-0 top-3 inline-flex h-[30px] items-center gap-[7px] rounded-full bg-[oklch(0.16_0.012_55_/_0.78)] px-3 text-[11.5px] font-bold text-white", children: [
135
132
  /* @__PURE__ */ jsx("i", { className: "h-[7px] w-[7px] rounded-full bg-success", "aria-hidden": true }),
136
133
  labels.openUntil
137
134
  ] }) }),
@@ -145,8 +142,7 @@ function KitchenDossier({
145
142
  GlassGround,
146
143
  {
147
144
  stops: { direction: "to bottom", clear: "0px", full: GLASS_LEAD },
148
- peak: 0.4,
149
- blur: "sm"
145
+ peak: 0.6
150
146
  }
151
147
  )
152
148
  }
@@ -154,18 +150,28 @@ function KitchenDossier({
154
150
  /* @__PURE__ */ jsxs("div", { className: "[text-shadow:0_1px_12px_oklch(0_0_0/0.55)]", children: [
155
151
  /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-4", children: [
156
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 }) }),
157
- 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: [
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: [
158
157
  rating.toFixed(1),
159
158
  /* @__PURE__ */ jsx(Star, { className: "h-3.5 w-3.5 lg:h-4 lg:w-4", "aria-hidden": true })
160
159
  ] })
161
160
  ] }),
162
- (meta || labels.reviewCount) && /* @__PURE__ */ jsx("p", { className: "mt-1 truncate text-[12.5px] text-white/70", children: [meta, labels.reviewCount].filter(Boolean).join(" \xB7 ") })
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
+ ] })
163
169
  ] }),
164
170
  parts.length > 0 && /* @__PURE__ */ jsx(
165
171
  StoryPanel,
166
172
  {
167
173
  parts,
168
- className: "rounded-[14px] border border-white/10 bg-[oklch(0.16_0.012_55_/_0.35)] p-4 backdrop-blur-md"
174
+ className: "rounded-[14px] border border-white/10 bg-[oklch(0.16_0.012_55_/_0.62)] p-4"
169
175
  }
170
176
  ),
171
177
  action && /* @__PURE__ */ jsx("div", { className: "flex [&>*]:w-full lg:[&>*]:w-auto", children: action })
@@ -1,4 +1,4 @@
1
- import { Button } from '../chunk-H3BV4VAG.js';
1
+ import { Button } from '../chunk-VAXOQS7W.js';
2
2
  import '../chunk-R47NEOSI.js';
3
3
  import '../chunk-FEK5XGZW.js';
4
4
  import { __objRest, __spreadProps, __spreadValues } from '../chunk-3GWWZKX7.js';
@@ -5,28 +5,27 @@ import 'react';
5
5
  import './place-types.js';
6
6
 
7
7
  /**
8
- * MenuFamilyBlock — the cuisines index's family card. The mosaic is the ground.
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
- * The grid of venue photographs is the background for the ENTIRE card, edge to
13
- * edge, and the facts sit on it. Three layers do the work:
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 mosaic**, full-bleed, wearing the family's hue through a
16
- * `mix-blend-color` layer.
17
- * 2. **A masked backdrop-filter** absent where the photography is the
18
- * subject, full where the rows begin so the pictures stay sharp where
19
- * they are looked at and go soft exactly where they are read over.
20
- * 3. **An ink gradient** over that. This is what actually buys the contrast:
21
- * frost alone blurs without darkening, and blurred mid-tones will not carry
22
- * 16px type.
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.
18
+ * 2. **An ink gradient** absent where the photography is the subject, full
19
+ * where the rows begin. This is what buys the contrast. There used to be a
20
+ * masked backdrop-filter under it; it was removed for the measurement
21
+ * recorded in `GlassGround` (73 blur layers cost `/menu` 9 ms per scrolled
22
+ * frame on a phone).
23
23
  *
24
- * On the phone the frost and ink run top to bottom: the name and the action
25
- * sit on clear photography, the chips and the rows on the frosted foot. On
26
- * desktop the same three layers turn ninety degrees the photo column on the
27
- * left stays clear, the row column on the right is the frosted one. The mosaic
28
- * runs 3×2 there rather than 2×2, because at 1110px a four-tile grid makes each
29
- * photograph too big to read as texture.
24
+ * On the phone the ink runs top to bottom: the name and the action sit on
25
+ * clear photography, the chips and the rows on the inked foot. On desktop the
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.
30
29
  *
31
30
  * ## The dark scope
32
31
  *
@@ -68,6 +67,12 @@ type MenuFamilyBlockLabels = {
68
67
  priceBand: string;
69
68
  /** Main action, e.g. "Browse Italian". Sits on the photography — keep it short. */
70
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;
71
76
  /** Passed through to the venue rows. */
72
77
  kitchens: MenuKitchenListLabels;
73
78
  };
@@ -1,8 +1,10 @@
1
1
  import { MenuKitchenList } from '../chunk-24RFI4RQ.js';
2
2
  import { HueChip } from '../chunk-CLLY6XB3.js';
3
3
  import { Separator } from '../chunk-WSRWFA6K.js';
4
- import { PhotoGround, PHOTO_GROUND } from '../chunk-5RWTOT5Y.js';
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,11 +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 FROST = "backdrop-blur-xl [mask-image:linear-gradient(to_bottom,transparent_0%,black_42%)] lg:[mask-image:linear-gradient(to_right,transparent_36%,black_54%)]";
19
- var INK = "bg-[linear-gradient(to_bottom,oklch(0.16_0.012_55_/_0.42)_0%,oklch(0.16_0.012_55_/_0.6)_30%,oklch(0.16_0.012_55_/_0.9)_48%,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%)]";
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)]";
20
20
  var TEXT_SCRIM = (
21
21
  /* `isolate` + `before:-z-10`: a positioned pseudo-element paints ABOVE the
22
22
  column's in-flow text unless the column is its own stacking context and
@@ -33,11 +33,11 @@ function MenuFamilyBlock({
33
33
  linkComponent: LinkComponent = DefaultLink,
34
34
  className
35
35
  }) {
36
- var _a, _b, _c, _d, _e;
37
- const photos = ((_a = family.photoUrls) != null ? _a : []).slice(0, MOSAIC_TILES);
38
- const overflow = Math.max(family.venueCount - photos.length, 0);
39
- const initial = ((_c = (_b = family.name.match(new RegExp("\\p{L}", "u"))) == null ? void 0 : _b[0]) != null ? _c : "").toLocaleUpperCase();
40
- const venues = (_d = family.venues) != null ? _d : [];
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();
41
41
  return /* @__PURE__ */ jsxs(
42
42
  "article",
43
43
  {
@@ -49,55 +49,56 @@ function MenuFamilyBlock({
49
49
  className
50
50
  ),
51
51
  children: [
52
- /* @__PURE__ */ jsx(
53
- PhotoGround,
54
- {
55
- photos: photos.length > 0 ? photos : [void 0],
56
- initials: initial,
57
- mosaicClassName: photos.length > 0 ? "grid-cols-2 grid-rows-2 lg:grid-cols-3" : "grid-cols-1",
58
- phoneTiles: PHONE_TILES,
59
- gradient
60
- }
61
- ),
62
- /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cn("absolute inset-0", FROST) }),
52
+ /* @__PURE__ */ jsx(PhotoGround, { photos: [photo], initials: initial, mode: "stack", gradient }),
63
53
  /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cn("absolute inset-0", INK) }),
64
- /* @__PURE__ */ jsxs("div", { className: "relative grid grid-cols-1 lg:grid-cols-[38%_1fr]", children: [
65
- /* @__PURE__ */ jsxs("div", { className: cn("relative flex flex-col p-3.5 lg:min-h-[320px] lg:justify-end lg:p-5", TEXT_SCRIM), children: [
66
- overflow > 0 && /* @__PURE__ */ jsx("span", { className: "mb-16 self-end rounded-full bg-[oklch(0.16_0.012_55_/_0.72)] px-2.5 py-1 text-[11px] font-semibold text-white backdrop-blur-[2px] lg:mb-3 lg:self-start", children: labels.more(overflow) }),
67
- /* @__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 }),
68
- /* @__PURE__ */ jsx("span", { className: "mt-0.5 block text-[13px] font-medium tabular-nums text-white/70", children: labels.venueUnit(family.venueCount) }),
69
- /* @__PURE__ */ jsx(
70
- LinkComponent,
71
- {
72
- href: family.href,
73
- className: "mt-3.5 inline-flex h-10 w-max items-center rounded-full border border-white/20 bg-white/[0.12] px-4 text-[13.5px] font-bold text-white backdrop-blur-md transition-colors hover:bg-white/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white motion-reduce:transition-none",
74
- children: labels.browse
75
- }
76
- )
77
- ] }),
78
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col px-3.5 pb-3.5 lg:p-5", children: [
79
- /* @__PURE__ */ jsxs("ul", { className: "flex flex-wrap items-center gap-1.5", children: [
80
- family.priceBandLabel && /* No hue: a fact about money, not about the family. In the dark
81
- scope `HueChip`'s `--muted` fallback is the dark pill the design
82
- draws. */
83
- /* @__PURE__ */ jsx(
84
- HueChip,
85
- {
86
- as: "li",
87
- className: "font-bold tabular-nums",
88
- "aria-label": `${labels.priceBand}: ${family.priceBandLabel}`,
89
- icon: /* @__PURE__ */ jsx(Wallet, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground", "aria-hidden": true }),
90
- children: family.priceBandLabel
91
- }
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
92
61
  ),
93
- (_e = family.chips) == null ? void 0 : _e.map((chip) => (
94
- /* Label only. The counts are VENUES beside a dish group's name,
95
- which every reader takes for dishes. */
96
- /* @__PURE__ */ jsx(HueChip, { as: "li", hue, children: chip.label }, chip.slug)
97
- ))
98
- ] }),
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
+ )) }),
99
100
  venues.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
100
- /* @__PURE__ */ jsx(Separator, { className: "my-3" }),
101
+ /* @__PURE__ */ jsx(Separator, { className: "my-3 via-white/15" }),
101
102
  /* @__PURE__ */ jsx(
102
103
  MenuKitchenList,
103
104
  {
@@ -122,12 +123,12 @@ function MenuFamilyBlockSkeleton({
122
123
  {
123
124
  className: cn("dark relative overflow-hidden rounded-[14px]", GROUND, className),
124
125
  "aria-hidden": true,
125
- children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-[38%_1fr]", children: [
126
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col p-3.5 lg:min-h-[320px] lg:justify-end lg:p-5", children: [
127
- /* @__PURE__ */ jsx(Skeleton, { className: "mb-16 h-6 w-[72px] self-end rounded-full lg:mb-3 lg:self-start" }),
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" }),
128
129
  /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-[60%]" }),
129
- /* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-3.5 w-[90px]" }),
130
- /* @__PURE__ */ jsx(Skeleton, { className: "mt-3.5 h-10 w-[160px] rounded-full" })
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" })
131
132
  ] }),
132
133
  /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col px-3.5 pb-3.5 lg:p-5", children: [
133
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-5RWTOT5Y.js';
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';
@@ -11,7 +11,6 @@ function DefaultLink(_a) {
11
11
  }
12
12
  var MOSAIC_CELLS = 4;
13
13
  var GROUND = PHOTO_GROUND;
14
- var FROST = "backdrop-blur-xl [mask-image:linear-gradient(to_bottom,transparent_28%,black_58%)]";
15
14
  var INK = "bg-[linear-gradient(to_bottom,oklch(0.16_0.012_55_/_0.78)_0%,oklch(0.16_0.012_55_/_0.5)_34%,oklch(0.16_0.012_55_/_0.86)_62%,oklch(0.16_0.012_55_/_0.96)_100%)]";
16
15
  function MenuFamilyCard({
17
16
  family,
@@ -47,7 +46,6 @@ function MenuFamilyCard({
47
46
  gradient
48
47
  }
49
48
  ),
50
- /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cn("absolute inset-0 -z-20", FROST) }),
51
49
  /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cn("absolute inset-0 -z-10", INK) }),
52
50
  /* @__PURE__ */ jsxs("span", { className: "block text-white", children: [
53
51
  /* @__PURE__ */ jsx("b", { className: "block text-[34px] font-extrabold leading-none tracking-[-0.03em] tabular-nums", children: family.venue_count }),
@@ -69,7 +67,7 @@ function MenuFamilyCard({
69
67
  ),
70
68
  (_d = family.chips) == null ? void 0 : _d.map((chip) => /* @__PURE__ */ jsx(HueChip, { hue, children: chip.label }, chip.slug))
71
69
  ] }),
72
- /* @__PURE__ */ jsx("span", { className: "mt-3.5 inline-flex h-10 items-center rounded-full border border-white/20 bg-white/[0.12] px-4 text-[13.5px] font-bold text-white backdrop-blur-md transition-colors group-hover:bg-white/20 motion-reduce:transition-none", children: labels.browse })
70
+ /* @__PURE__ */ jsx("span", { className: "mt-3.5 inline-flex h-10 items-center rounded-full border border-white/20 bg-white/[0.16] px-4 text-[13.5px] font-bold text-white transition-colors group-hover:bg-white/25 motion-reduce:transition-none", children: labels.browse })
73
71
  ] })
74
72
  ]
75
73
  }
@@ -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 };