@bearmenu/ui 0.8.9 → 0.8.11

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 (225) hide show
  1. package/dist/chunk-24RFI4RQ.js +167 -0
  2. package/dist/{chunk-UKBNQO6Q.js → chunk-2CXU5WZO.js} +1 -1
  3. package/dist/chunk-2XCZJWTV.js +121 -0
  4. package/dist/{chunk-62ES6N32.js → chunk-43RC7MHY.js} +1 -1
  5. package/dist/chunk-5RWTOT5Y.js +72 -0
  6. package/dist/{chunk-Q6QH52LJ.js → chunk-6TEEY5YA.js} +2 -2
  7. package/dist/{chunk-AXV5O2IZ.js → chunk-AKQ57NXY.js} +3 -3
  8. package/dist/chunk-CLLY6XB3.js +41 -0
  9. package/dist/chunk-DTXNDLSE.js +125 -0
  10. package/dist/chunk-F6FMZJDG.js +113 -0
  11. package/dist/{chunk-2WDJR6K7.js → chunk-G7IFL4Z4.js} +4 -1
  12. package/dist/chunk-H3ZZDX5L.js +61 -0
  13. package/dist/{chunk-H3BV4VAG.js → chunk-JS3EINZD.js} +2 -2
  14. package/dist/chunk-MZL7CGCL.js +109 -0
  15. package/dist/{chunk-TH6W2PWG.js → chunk-UDTG3RSE.js} +1 -1
  16. package/dist/chunk-WCTHZKU7.js +37 -0
  17. package/dist/{chunk-TT3WFS6S.js → chunk-YOKHBAIH.js} +11 -11
  18. package/dist/components/alert-dialog.js +1 -1
  19. package/dist/components/alert.d.ts +2 -2
  20. package/dist/components/avatar.d.ts +3 -3
  21. package/dist/components/badge.d.ts +1 -1
  22. package/dist/components/badge.js +1 -1
  23. package/dist/components/button.d.ts +2 -2
  24. package/dist/components/button.js +1 -1
  25. package/dist/components/calendar.js +1 -1
  26. package/dist/components/card.d.ts +4 -4
  27. package/dist/components/carousel.js +1 -1
  28. package/dist/components/combobox.js +1 -1
  29. package/dist/components/command.d.ts +2 -2
  30. package/dist/components/concept-compare-rail.d.ts +50 -0
  31. package/dist/components/concept-compare-rail.js +5 -0
  32. package/dist/components/concept-compare.d.ts +75 -38
  33. package/dist/components/concept-compare.js +209 -133
  34. package/dist/components/concept-convergence.d.ts +41 -0
  35. package/dist/components/concept-convergence.js +53 -0
  36. package/dist/components/convergence.d.ts +25 -0
  37. package/dist/components/convergence.js +4 -0
  38. package/dist/components/dialog.d.ts +2 -2
  39. package/dist/components/empty-state.js +1 -1
  40. package/dist/components/event-card.js +1 -1
  41. package/dist/components/event-compact-row.js +1 -1
  42. package/dist/components/event-detail-panel.js +2 -2
  43. package/dist/components/event-index-row.js +1 -1
  44. package/dist/components/event-list-row-wide.js +2 -2
  45. package/dist/components/event-list-row.js +2 -2
  46. package/dist/components/explainer-steps.d.ts +34 -0
  47. package/dist/components/explainer-steps.js +36 -0
  48. package/dist/components/filter-category-row.js +1 -1
  49. package/dist/components/glass-ground.d.ts +61 -0
  50. package/dist/components/glass-ground.js +3 -0
  51. package/dist/components/haptic-button.js +1 -1
  52. package/dist/components/hub-surface.js +11 -1
  53. package/dist/components/hue-chip.d.ts +70 -0
  54. package/dist/components/hue-chip.js +3 -0
  55. package/dist/components/input-group.d.ts +2 -2
  56. package/dist/components/input.d.ts +1 -1
  57. package/dist/components/item.d.ts +4 -4
  58. package/dist/components/kbd.d.ts +2 -2
  59. package/dist/components/kitchen-dossier.d.ts +88 -0
  60. package/dist/components/kitchen-dossier.js +186 -0
  61. package/dist/components/link-button.js +1 -1
  62. package/dist/components/menu-dead-end.d.ts +56 -0
  63. package/dist/components/menu-dead-end.js +49 -0
  64. package/dist/components/menu-family-block.d.ts +98 -0
  65. package/dist/components/menu-family-block.js +153 -0
  66. package/dist/components/menu-family-card.d.ts +33 -27
  67. package/dist/components/menu-family-card.js +41 -85
  68. package/dist/components/menu-field.js +92 -2
  69. package/dist/components/menu-filter-chips.d.ts +86 -0
  70. package/dist/components/menu-filter-chips.js +122 -0
  71. package/dist/components/menu-group-rows.d.ts +53 -0
  72. package/dist/components/menu-group-rows.js +67 -0
  73. package/dist/components/menu-hub-hero.js +10 -5
  74. package/dist/components/menu-index-header.d.ts +37 -0
  75. package/dist/components/menu-index-header.js +68 -0
  76. package/dist/components/menu-index-list.d.ts +48 -0
  77. package/dist/components/menu-index-list.js +96 -0
  78. package/dist/components/menu-intent-hero.d.ts +69 -0
  79. package/dist/components/menu-intent-hero.js +87 -0
  80. package/dist/components/menu-item.js +3 -3
  81. package/dist/components/menu-kitchen-list.d.ts +82 -0
  82. package/dist/components/menu-kitchen-list.js +5 -0
  83. package/dist/components/menu-mocks.d.ts +37 -2
  84. package/dist/components/menu-mocks.js +152 -27
  85. package/dist/components/menu-types.d.ts +182 -6
  86. package/dist/components/motion-icon-controls.js +2 -2
  87. package/dist/components/motion-icon-set.js +6 -6
  88. package/dist/components/motion-icon.d.ts +22 -1
  89. package/dist/components/motion-icon.js +1 -1
  90. package/dist/components/multi-select-combobox.js +2 -2
  91. package/dist/components/native-select.d.ts +2 -2
  92. package/dist/components/pagination.js +1 -1
  93. package/dist/components/photo-ground.d.ts +64 -0
  94. package/dist/components/photo-ground.js +3 -0
  95. package/dist/components/place-about-tab.js +2 -2
  96. package/dist/components/place-details-mobile.js +3 -3
  97. package/dist/components/place-types.d.ts +2 -2
  98. package/dist/components/qa-block.d.ts +36 -0
  99. package/dist/components/qa-block.js +24 -0
  100. package/dist/components/scroll-fade.js +3 -121
  101. package/dist/components/searchable-select.js +1 -1
  102. package/dist/components/select.d.ts +1 -1
  103. package/dist/components/signature-chip.d.ts +2 -2
  104. package/dist/components/signature-chip.js +2 -2
  105. package/dist/components/sliding-panels.js +1 -1
  106. package/dist/components/snap-rail.d.ts +26 -3
  107. package/dist/components/snap-rail.js +3 -109
  108. package/dist/components/spinner.d.ts +4 -4
  109. package/dist/components/story.d.ts +34 -0
  110. package/dist/components/story.js +3 -0
  111. package/dist/components/tag.d.ts +4 -4
  112. package/dist/components/text.d.ts +5 -5
  113. package/dist/components/toggle.d.ts +1 -1
  114. package/dist/components/top-comparison.d.ts +28 -0
  115. package/dist/components/top-comparison.js +76 -0
  116. package/dist/components/top-cross-link.d.ts +34 -0
  117. package/dist/components/top-cross-link.js +101 -0
  118. package/dist/components/top-ranking-entry.d.ts +53 -0
  119. package/dist/components/top-ranking-entry.js +217 -0
  120. package/dist/components/top-ranking-hero.d.ts +61 -0
  121. package/dist/components/top-ranking-hero.js +99 -0
  122. package/dist/components/top-ranking-legend.d.ts +69 -0
  123. package/dist/components/top-ranking-legend.js +124 -0
  124. package/dist/components/top-types.d.ts +109 -0
  125. package/dist/components/top-types.js +1 -0
  126. package/dist/components/venue-grade-dimensions.d.ts +3 -1
  127. package/dist/components/venue-grade-dimensions.js +1 -1
  128. package/dist/components/venue-quotes.d.ts +1 -1
  129. package/dist/components/venue-quotes.js +1 -1
  130. package/dist/components/venue-wall.js +5 -3
  131. package/dist/components/weekday-theme-banner.js +1 -1
  132. package/dist/components/weekend-panel.js +2 -2
  133. package/package.json +1 -1
  134. package/src/components/badge.tsx +1 -1
  135. package/src/components/button.tsx +2 -2
  136. package/src/components/concept-compare-rail.tsx +132 -0
  137. package/src/components/concept-compare.stories.tsx +122 -54
  138. package/src/components/concept-compare.tsx +368 -196
  139. package/src/components/concept-convergence.stories.tsx +53 -0
  140. package/src/components/concept-convergence.tsx +90 -0
  141. package/src/components/convergence.stories.tsx +54 -0
  142. package/src/components/convergence.tsx +177 -0
  143. package/src/components/explainer-steps.stories.tsx +46 -0
  144. package/src/components/explainer-steps.tsx +74 -0
  145. package/src/components/glass-ground.tsx +104 -0
  146. package/src/components/hub-surface.tsx +11 -1
  147. package/src/components/hue-chip.stories.tsx +76 -0
  148. package/src/components/hue-chip.test.tsx +62 -0
  149. package/src/components/hue-chip.tsx +99 -0
  150. package/src/components/kitchen-dossier.stories.tsx +108 -0
  151. package/src/components/kitchen-dossier.tsx +321 -0
  152. package/src/components/menu-dead-end.stories.tsx +67 -0
  153. package/src/components/menu-dead-end.tsx +127 -0
  154. package/src/components/menu-family-block.stories.tsx +91 -0
  155. package/src/components/menu-family-block.tsx +303 -0
  156. package/src/components/menu-family-card.stories.tsx +43 -35
  157. package/src/components/menu-family-card.tsx +115 -142
  158. package/src/components/menu-filter-chips.stories.tsx +107 -0
  159. package/src/components/menu-filter-chips.tsx +238 -0
  160. package/src/components/menu-group-rows.stories.tsx +54 -0
  161. package/src/components/menu-group-rows.tsx +133 -0
  162. package/src/components/menu-hub-hero.test.tsx +39 -0
  163. package/src/components/menu-hub-hero.tsx +17 -5
  164. package/src/components/menu-index-header.stories.tsx +72 -0
  165. package/src/components/menu-index-header.tsx +125 -0
  166. package/src/components/menu-index-list.stories.tsx +50 -0
  167. package/src/components/menu-index-list.tsx +149 -0
  168. package/src/components/menu-intent-hero.stories.tsx +67 -0
  169. package/src/components/menu-intent-hero.tsx +189 -0
  170. package/src/components/menu-kitchen-list.stories.tsx +67 -0
  171. package/src/components/menu-kitchen-list.test.tsx +78 -0
  172. package/src/components/menu-kitchen-list.tsx +284 -0
  173. package/src/components/menu-mocks.ts +198 -23
  174. package/src/components/menu-types.ts +189 -6
  175. package/src/components/motion-icon-controls.tsx +11 -11
  176. package/src/components/motion-icon-set.tsx +6 -5
  177. package/src/components/motion-icon.test.tsx +23 -1
  178. package/src/components/motion-icon.tsx +20 -0
  179. package/src/components/photo-ground.tsx +147 -0
  180. package/src/components/place-types.ts +2 -2
  181. package/src/components/qa-block.stories.tsx +43 -0
  182. package/src/components/qa-block.tsx +60 -0
  183. package/src/components/signature-chip.tsx +3 -3
  184. package/src/components/snap-rail.tsx +58 -15
  185. package/src/components/story.tsx +225 -0
  186. package/src/components/top-comparison.stories.tsx +78 -0
  187. package/src/components/top-comparison.tsx +151 -0
  188. package/src/components/top-cross-link.stories.tsx +84 -0
  189. package/src/components/top-cross-link.tsx +171 -0
  190. package/src/components/top-ranking-entry.stories.tsx +171 -0
  191. package/src/components/top-ranking-entry.test.tsx +105 -0
  192. package/src/components/top-ranking-entry.tsx +425 -0
  193. package/src/components/top-ranking-hero.stories.tsx +76 -0
  194. package/src/components/top-ranking-hero.tsx +218 -0
  195. package/src/components/top-ranking-legend.stories.tsx +78 -0
  196. package/src/components/top-ranking-legend.tsx +239 -0
  197. package/src/components/top-types.ts +110 -0
  198. package/src/components/venue-grade-dimensions.tsx +2 -2
  199. package/src/components/venue-quotes.stories.tsx +1 -1
  200. package/src/components/venue-quotes.tsx +4 -2
  201. package/src/components/venue-wall.tsx +9 -4
  202. package/src/components/weekday-theme-banner.tsx +1 -1
  203. package/dist/chunk-THOVPZNN.js +0 -37
  204. package/dist/chunk-YS6BHKZO.js +0 -92
  205. package/dist/components/ranked-venue-list.d.ts +0 -49
  206. package/dist/components/ranked-venue-list.js +0 -87
  207. package/dist/components/signature-line-list.d.ts +0 -45
  208. package/dist/components/signature-line-list.js +0 -99
  209. package/dist/components/venue-busyness-strip.d.ts +0 -35
  210. package/dist/components/venue-busyness-strip.js +0 -37
  211. package/dist/components/venue-signature-block.d.ts +0 -39
  212. package/dist/components/venue-signature-block.js +0 -6
  213. package/dist/components/venue-spotlight.d.ts +0 -74
  214. package/dist/components/venue-spotlight.js +0 -138
  215. package/src/components/ranked-venue-list.stories.tsx +0 -80
  216. package/src/components/ranked-venue-list.tsx +0 -177
  217. package/src/components/signature-line-list.stories.tsx +0 -85
  218. package/src/components/signature-line-list.tsx +0 -136
  219. package/src/components/venue-busyness-strip.stories.tsx +0 -66
  220. package/src/components/venue-busyness-strip.tsx +0 -64
  221. package/src/components/venue-signature-block.stories.tsx +0 -68
  222. package/src/components/venue-signature-block.tsx +0 -71
  223. package/src/components/venue-spotlight.stories.tsx +0 -141
  224. package/src/components/venue-spotlight.tsx +0 -236
  225. package/dist/{chunk-XWMRABZW.js → chunk-HSIYYA2E.js} +1 -1
@@ -0,0 +1,167 @@
1
+ import { Separator } from './chunk-WSRWFA6K.js';
2
+ import { Skeleton } from './chunk-QXHMPJ35.js';
3
+ import { cn } from './chunk-FEK5XGZW.js';
4
+ import { __objRest, __spreadValues } from './chunk-3GWWZKX7.js';
5
+ import { Star, Clock, Check, MessageSquare, ChevronRight } from 'lucide-react';
6
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
+
8
+ function DefaultLink(_a) {
9
+ var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
10
+ return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
11
+ }
12
+ function MenuKitchenList({
13
+ kitchens,
14
+ labels,
15
+ onShowMore,
16
+ linkComponent = DefaultLink,
17
+ className
18
+ }) {
19
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col", className), children: [
20
+ /* @__PURE__ */ jsx("ol", { children: kitchens.map((kitchen, index) => /* @__PURE__ */ jsxs("li", { className: "[&:first-child>div]:pt-0", children: [
21
+ index > 0 && /* @__PURE__ */ jsx(Separator, {}),
22
+ /* @__PURE__ */ jsx(KitchenRow, { kitchen, labels, linkComponent })
23
+ ] }, kitchen.place.slug)) }),
24
+ onShowMore && labels.showMore && /* @__PURE__ */ jsx(
25
+ "button",
26
+ {
27
+ type: "button",
28
+ onClick: onShowMore,
29
+ className: "mt-2 self-start rounded-md py-2 text-[13px] font-bold text-accent transition-colors hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none",
30
+ children: labels.showMore
31
+ }
32
+ )
33
+ ] });
34
+ }
35
+ function KitchenRow({
36
+ kitchen,
37
+ labels,
38
+ linkComponent: LinkComponent
39
+ }) {
40
+ const { place, dish } = kitchen;
41
+ const openNow = place.open_now === true;
42
+ return /* @__PURE__ */ jsxs("div", { className: "relative flex flex-wrap items-center gap-[11px] py-3 transition-colors hover:bg-muted/30 motion-reduce:transition-none lg:flex-nowrap lg:gap-4 lg:py-3.5", children: [
43
+ /* @__PURE__ */ jsx(
44
+ LinkComponent,
45
+ {
46
+ href: kitchen.href,
47
+ "aria-label": labels.openVenue(place.name),
48
+ className: "absolute inset-0 z-[1] rounded-xl focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
49
+ }
50
+ ),
51
+ /* @__PURE__ */ jsxs("span", { className: "relative h-[46px] w-[46px] shrink-0 overflow-hidden rounded-[11px] bg-[repeating-linear-gradient(135deg,oklch(0.78_0.018_55)_0_8px,oklch(0.84_0.012_58)_8px_16px)] lg:h-[58px] lg:w-[58px] lg:rounded-[13px]", children: [
52
+ place.thumbnail_url && // eslint-disable-next-line @next/next/no-img-element
53
+ /* @__PURE__ */ jsx(
54
+ "img",
55
+ {
56
+ src: place.thumbnail_url,
57
+ alt: "",
58
+ loading: "lazy",
59
+ decoding: "async",
60
+ className: "h-full w-full object-cover"
61
+ }
62
+ ),
63
+ /* @__PURE__ */ jsx(
64
+ "span",
65
+ {
66
+ title: openNow ? labels.openNow : void 0,
67
+ className: cn(
68
+ "absolute right-[5px] top-[5px] h-[7px] w-[7px] rounded-full ring-2 ring-white/85",
69
+ openNow ? "bg-[var(--free,oklch(0.55_0.13_155))]" : "bg-[oklch(0.8_0.01_60)]"
70
+ )
71
+ }
72
+ )
73
+ ] }),
74
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5 lg:w-[226px] lg:flex-none", children: [
75
+ /* @__PURE__ */ jsx("span", { className: "truncate text-[14.5px] font-bold tracking-[-0.01em] lg:text-[15.5px]", children: place.name }),
76
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 truncate text-xs text-muted-foreground", children: [
77
+ place.rating && /* @__PURE__ */ jsxs(Fragment, { children: [
78
+ /* @__PURE__ */ jsx(Star, { className: "h-[11px] w-[11px] shrink-0", "aria-hidden": true }),
79
+ place.rating.rating,
80
+ kitchen.metaLabel && " \xB7 "
81
+ ] }),
82
+ kitchen.metaLabel
83
+ ] }),
84
+ kitchen.hoursLabel && /* @__PURE__ */ jsxs(
85
+ "span",
86
+ {
87
+ className: cn(
88
+ "mt-[3px] inline-flex h-[21px] w-max items-center gap-[5px] rounded-md px-2 text-[10.5px] font-bold",
89
+ openNow ? "bg-[oklch(0.96_0.02_155)] text-[var(--free,oklch(0.45_0.13_155))]" : "bg-muted text-muted-foreground"
90
+ ),
91
+ children: [
92
+ /* @__PURE__ */ jsx(Clock, { className: "h-2.5 w-2.5 shrink-0", "aria-hidden": true }),
93
+ kitchen.hoursLabel
94
+ ]
95
+ }
96
+ )
97
+ ] }),
98
+ dish && /* DESKTOP ONLY, where it is a column of its own beside the venue.
99
+ On the phone it wrapped to a third line under the row — kicker, dish,
100
+ mention count — which turned a four-line venue row into a seven-line
101
+ block and, ten rows down, buried the venue names the list exists to
102
+ be scanned for. The dish is not what a reader is choosing here; it is
103
+ one tap away on the venue's own page, with room to state it.
104
+
105
+ `order-5` puts it last in the visual order without moving it in the
106
+ DOM, where it belongs to the venue. */
107
+ /* @__PURE__ */ jsxs("div", { className: "hidden min-w-0 basis-full pl-[57px] lg:order-none lg:block lg:flex-1 lg:basis-auto lg:pl-0", children: [
108
+ /* @__PURE__ */ jsxs(
109
+ "span",
110
+ {
111
+ className: cn(
112
+ "flex items-center gap-1.5 text-[9px] font-extrabold uppercase tracking-[0.1em]",
113
+ dish.matched ? "text-accent" : "text-[oklch(0.72_0.01_60)]"
114
+ ),
115
+ children: [
116
+ dish.kicker,
117
+ dish.matched && dish.matchLabel && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 rounded-[5px] bg-accent-subtle px-1.5 py-px text-[10.5px] font-bold normal-case tracking-normal text-accent", children: [
118
+ /* @__PURE__ */ jsx(Check, { className: "h-2.5 w-2.5 shrink-0", "aria-hidden": true }),
119
+ dish.matchLabel
120
+ ] })
121
+ ]
122
+ }
123
+ ),
124
+ dish.href ? /* @__PURE__ */ jsx(
125
+ LinkComponent,
126
+ {
127
+ href: dish.href,
128
+ "aria-label": labels.openDish(dish.name),
129
+ className: "relative z-[2] mt-0.5 block truncate font-serif text-[13.5px] italic underline decoration-[oklch(0.84_0.01_60)] decoration-1 underline-offset-[3px] transition-colors hover:text-accent hover:decoration-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none lg:text-[15px]",
130
+ children: dish.name
131
+ }
132
+ ) : /* @__PURE__ */ jsx("span", { className: "mt-0.5 block truncate font-serif text-[13.5px] italic lg:text-[15px]", children: dish.name }),
133
+ dish.meta && /* @__PURE__ */ jsxs("span", { className: "mt-[3px] flex items-center gap-1 text-[11.5px] text-muted-foreground", children: [
134
+ !dish.matched && /* @__PURE__ */ jsx(MessageSquare, { className: "h-2.5 w-2.5 shrink-0", "aria-hidden": true }),
135
+ dish.meta
136
+ ] })
137
+ ] }),
138
+ /* @__PURE__ */ jsxs("div", { className: "ml-auto flex shrink-0 items-center gap-[11px] lg:ml-0", children: [
139
+ kitchen.priceLabel && /* @__PURE__ */ jsx("span", { className: "text-base font-extrabold tabular-nums text-accent", children: kitchen.priceLabel }),
140
+ /* @__PURE__ */ jsx(ChevronRight, { className: "h-[15px] w-[15px] shrink-0 text-muted-foreground", "aria-hidden": true })
141
+ ] })
142
+ ] });
143
+ }
144
+ function MenuKitchenListSkeleton({
145
+ rows = 10,
146
+ className
147
+ }) {
148
+ return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col", className), "aria-hidden": true, children: Array.from({ length: rows }, (_, index) => /* @__PURE__ */ jsxs("div", { children: [
149
+ index > 0 && /* @__PURE__ */ jsx(Separator, {}),
150
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-[11px] py-3 lg:flex-nowrap lg:gap-4 lg:py-3.5", children: [
151
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[46px] w-[46px] rounded-[11px] lg:h-[58px] lg:w-[58px] lg:rounded-[13px]" }),
152
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5 lg:w-[226px] lg:flex-none", children: [
153
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-[60%]" }),
154
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-[45%]" }),
155
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-[21px] w-[120px] rounded-md" })
156
+ ] }),
157
+ /* @__PURE__ */ jsxs("div", { className: "hidden min-w-0 basis-full pl-[57px] lg:order-none lg:block lg:flex-1 lg:basis-auto lg:pl-0", children: [
158
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-2.5 w-[90px]" }),
159
+ /* @__PURE__ */ jsx(Skeleton, { className: "mt-1.5 h-4 w-[70%]" }),
160
+ /* @__PURE__ */ jsx(Skeleton, { className: "mt-1.5 h-3 w-[40%]" })
161
+ ] }),
162
+ /* @__PURE__ */ jsx(Skeleton, { className: "ml-auto h-5 w-[56px] lg:ml-0" })
163
+ ] })
164
+ ] }, index)) });
165
+ }
166
+
167
+ export { MenuKitchenList, MenuKitchenListSkeleton };
@@ -12,7 +12,7 @@ var badgeVariants = cva(
12
12
  secondary: "border-transparent bg-secondary text-secondary-foreground",
13
13
  destructive: "border-transparent bg-destructive text-destructive-foreground",
14
14
  outline: "text-foreground border-border",
15
- overlay: "border-transparent bg-foreground/70 text-background backdrop-blur-sm",
15
+ overlay: "border-transparent bg-foreground/80 text-background",
16
16
  glass: "glass text-foreground border-border/50",
17
17
  success: "border-transparent bg-success text-success-foreground",
18
18
  warning: "border-transparent bg-warning text-warning-foreground",
@@ -0,0 +1,121 @@
1
+ import { cn } from './chunk-FEK5XGZW.js';
2
+ import { __objRest, __spreadProps, __spreadValues } from './chunk-3GWWZKX7.js';
3
+ import * as React from 'react';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
5
+
6
+ var fromMap = {
7
+ background: "from-background",
8
+ card: "from-card",
9
+ muted: "from-muted"
10
+ };
11
+ var sizeMap = {
12
+ vertical: { sm: "h-6", md: "h-12", lg: "h-20" },
13
+ horizontal: { sm: "w-8", md: "w-16", lg: "w-28" }
14
+ };
15
+ var ScrollFade = React.forwardRef(
16
+ (_a, ref) => {
17
+ var _b = _a, {
18
+ orientation = "vertical",
19
+ fadeColor = "background",
20
+ size = "md",
21
+ className,
22
+ scrollClassName,
23
+ children
24
+ } = _b, props = __objRest(_b, [
25
+ "orientation",
26
+ "fadeColor",
27
+ "size",
28
+ "className",
29
+ "scrollClassName",
30
+ "children"
31
+ ]);
32
+ const innerRef = React.useRef(null);
33
+ React.useImperativeHandle(ref, () => innerRef.current);
34
+ const [atStart, setAtStart] = React.useState(true);
35
+ const [atEnd, setAtEnd] = React.useState(true);
36
+ const update = React.useCallback(() => {
37
+ const el = innerRef.current;
38
+ if (!el) return;
39
+ if (orientation === "vertical") {
40
+ const overflow = el.scrollHeight - el.clientHeight;
41
+ setAtStart(el.scrollTop <= 1);
42
+ setAtEnd(overflow <= 1 || el.scrollTop >= overflow - 1);
43
+ } else {
44
+ const overflow = el.scrollWidth - el.clientWidth;
45
+ setAtStart(el.scrollLeft <= 1);
46
+ setAtEnd(overflow <= 1 || el.scrollLeft >= overflow - 1);
47
+ }
48
+ }, [orientation]);
49
+ React.useEffect(() => {
50
+ const el = innerRef.current;
51
+ if (!el) return;
52
+ update();
53
+ el.addEventListener("scroll", update, { passive: true });
54
+ const ro = new ResizeObserver(update);
55
+ ro.observe(el);
56
+ return () => {
57
+ el.removeEventListener("scroll", update);
58
+ ro.disconnect();
59
+ };
60
+ }, [update]);
61
+ const fromClass = fromMap[fadeColor];
62
+ const fadeSize = sizeMap[orientation][size];
63
+ return /* @__PURE__ */ jsxs(
64
+ "div",
65
+ {
66
+ className: cn(
67
+ "relative isolate flex",
68
+ orientation === "vertical" ? "flex-col" : "flex-row",
69
+ className
70
+ ),
71
+ children: [
72
+ /* @__PURE__ */ jsx(
73
+ "div",
74
+ __spreadProps(__spreadValues({
75
+ ref: innerRef,
76
+ className: cn(
77
+ "min-h-0 min-w-0 flex-1",
78
+ orientation === "vertical" ? "overflow-y-auto" : "overflow-x-auto",
79
+ scrollClassName
80
+ )
81
+ }, props), {
82
+ children
83
+ })
84
+ ),
85
+ /* @__PURE__ */ jsx(
86
+ "div",
87
+ {
88
+ "aria-hidden": true,
89
+ className: cn(
90
+ "pointer-events-none absolute z-10 transition-opacity duration-300",
91
+ // `from-30%` adds a solid plateau before the gradient starts
92
+ // fading — without it the gradient is a pure linear ramp and only
93
+ // the very top pixel reads as solid, leaving the cut edge visible.
94
+ // -4px inset pulls the fade past the container edge so the very
95
+ // edge of clipped content is covered by the solid plateau.
96
+ orientation === "vertical" ? `inset-x-0 -top-1 ${fadeSize} bg-gradient-to-b from-30%` : `inset-y-0 -left-1 ${fadeSize} bg-gradient-to-r from-30%`,
97
+ fromClass,
98
+ atStart ? "opacity-0" : "opacity-100"
99
+ )
100
+ }
101
+ ),
102
+ /* @__PURE__ */ jsx(
103
+ "div",
104
+ {
105
+ "aria-hidden": true,
106
+ className: cn(
107
+ "pointer-events-none absolute z-10 transition-opacity duration-300",
108
+ orientation === "vertical" ? `inset-x-0 -bottom-1 ${fadeSize} bg-gradient-to-t from-30%` : `inset-y-0 -right-1 ${fadeSize} bg-gradient-to-l from-30%`,
109
+ fromClass,
110
+ atEnd ? "opacity-0" : "opacity-100"
111
+ )
112
+ }
113
+ )
114
+ ]
115
+ }
116
+ );
117
+ }
118
+ );
119
+ ScrollFade.displayName = "ScrollFade";
120
+
121
+ export { ScrollFade };
@@ -8,7 +8,7 @@ function VenueQuotes({ quotes, onCite, citeLabel, limit, className }) {
8
8
  var _a, _b;
9
9
  const citations = (_b = (_a = quote.review_ids) == null ? void 0 : _a.length) != null ? _b : 0;
10
10
  const canCite = !!onCite && citations > 0;
11
- const text = /* @__PURE__ */ jsx("blockquote", { className: "border-l-2 border-border pl-3 font-serif text-[13px] italic leading-[1.45] text-muted-foreground", children: `\u201C${quote.text}\u201D` });
11
+ const text = /* @__PURE__ */ jsx("blockquote", { className: "border-l-2 border-border pl-3 font-serif text-[13px] leading-[1.45] text-muted-foreground", children: `\u201C${quote.text}\u201D` });
12
12
  if (!canCite) return /* @__PURE__ */ jsx("div", { children: text }, index);
13
13
  return /* @__PURE__ */ jsx(
14
14
  "button",
@@ -0,0 +1,72 @@
1
+ import { cn } from './chunk-FEK5XGZW.js';
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+
4
+ var PHOTO_GROUND = "bg-[oklch(0.21_0.012_55)]";
5
+ var OVERLAY = "absolute inset-0 bg-[oklch(0.16_0.012_55_/_0.5)]";
6
+ function PhotoGround({
7
+ photos,
8
+ initials,
9
+ mode = "mosaic",
10
+ active = 0,
11
+ mosaicClassName,
12
+ phoneTiles,
13
+ gradient,
14
+ overlay,
15
+ overlayClassName,
16
+ loading = "lazy",
17
+ className
18
+ }) {
19
+ const initialOf = (index) => {
20
+ var _a, _b;
21
+ return typeof initials === "string" ? initials : (_b = (_a = initials[index]) != null ? _a : initials[0]) != null ? _b : "";
22
+ };
23
+ const hasAnyPhoto = photos.some(Boolean);
24
+ const slot = (index, extra) => {
25
+ const src = photos[index];
26
+ return /* @__PURE__ */ jsx("span", { className: cn("relative block overflow-hidden", extra), children: src ? (
27
+ // eslint-disable-next-line @next/next/no-img-element
28
+ /* @__PURE__ */ jsx(
29
+ "img",
30
+ {
31
+ src,
32
+ alt: "",
33
+ loading: index === 0 ? loading : "lazy",
34
+ decoding: "async",
35
+ className: "absolute inset-0 h-full w-full object-cover"
36
+ }
37
+ )
38
+ ) : (
39
+ /* Never a grey box: the ground with the venue's initial. A missing
40
+ photograph is not a broken image, and drawing one as a placeholder
41
+ makes a real city look unfinished. */
42
+ /* @__PURE__ */ jsx("span", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "font-serif text-[64px] font-semibold leading-none text-white/15", children: initialOf(index) }) })
43
+ ) }, index);
44
+ };
45
+ return /* @__PURE__ */ jsxs("span", { "aria-hidden": true, className: cn("absolute inset-0 block", PHOTO_GROUND, className), children: [
46
+ mode === "mosaic" ? /* @__PURE__ */ jsx("span", { className: cn("absolute inset-0 grid gap-px", mosaicClassName), children: photos.map(
47
+ (_, index) => slot(index, phoneTiles !== void 0 && index >= phoneTiles ? "hidden lg:block" : void 0)
48
+ ) }) : (
49
+ /* Stacked, not swapped, so the change is a cross-fade and not a flash
50
+ of ground between two images. */
51
+ photos.map(
52
+ (_, index) => slot(
53
+ index,
54
+ cn(
55
+ "absolute inset-0 transition-opacity duration-500 motion-reduce:transition-none",
56
+ index === active ? "opacity-100" : "opacity-0"
57
+ )
58
+ )
59
+ )
60
+ ),
61
+ gradient && hasAnyPhoto && /* @__PURE__ */ jsx(
62
+ "span",
63
+ {
64
+ className: "absolute inset-0 opacity-[0.85] mix-blend-color",
65
+ style: { backgroundImage: gradient }
66
+ }
67
+ ),
68
+ overlay && /* @__PURE__ */ jsx("span", { className: cn(OVERLAY, overlayClassName) })
69
+ ] });
70
+ }
71
+
72
+ export { PHOTO_GROUND, PhotoGround };
@@ -1,4 +1,4 @@
1
- import { Badge } from './chunk-UKBNQO6Q.js';
1
+ import { Badge } from './chunk-2CXU5WZO.js';
2
2
  import { cn } from './chunk-FEK5XGZW.js';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
 
@@ -25,7 +25,7 @@ function SignatureChip({
25
25
  className: cn(
26
26
  shared,
27
27
  "inline-flex items-center rounded-full border border-dashed",
28
- onImage ? "border-background/70 bg-foreground/70 text-background backdrop-blur-sm hover:bg-foreground/85" : "border-accent/40 text-accent hover:bg-accent/10",
28
+ onImage ? "border-background/70 bg-foreground/80 text-background hover:bg-foreground/90" : "border-accent/40 text-accent hover:bg-accent/10",
29
29
  "focus-visible:outline-none focus-visible:ring-2",
30
30
  onImage ? "focus-visible:ring-background/70" : "focus-visible:ring-accent/40",
31
31
  className
@@ -1,7 +1,7 @@
1
1
  import { cn } from './chunk-FEK5XGZW.js';
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
3
 
4
- var DEFAULT_ORDER = [
4
+ var DIMENSION_ORDER = [
5
5
  "food",
6
6
  "coffee_quality",
7
7
  "drinks_quality",
@@ -15,7 +15,7 @@ var DEFAULT_ORDER = [
15
15
  function VenueGradeDimensions({
16
16
  dimensions,
17
17
  labels,
18
- order = DEFAULT_ORDER,
18
+ order = DIMENSION_ORDER,
19
19
  formatScore,
20
20
  className
21
21
  }) {
@@ -55,4 +55,4 @@ function VenueGradeDimensions({
55
55
  );
56
56
  }
57
57
 
58
- export { VenueGradeDimensions };
58
+ export { DIMENSION_ORDER, VenueGradeDimensions };
@@ -0,0 +1,41 @@
1
+ import { cn } from './chunk-FEK5XGZW.js';
2
+ import { jsxs } from 'react/jsx-runtime';
3
+
4
+ var STRENGTH = {
5
+ /** A labelled facet: readable at 11.5px, still clearly the family's colour. */
6
+ chip: 20,
7
+ /** A quieter wash, for a chip that sits beside a stronger one. */
8
+ subtle: 12
9
+ };
10
+ function hueTint(hue, tone = "chip", base = "var(--card)") {
11
+ return `color-mix(in oklab, ${hue} ${STRENGTH[tone]}%, ${base})`;
12
+ }
13
+ function HueChip({
14
+ hue,
15
+ tone = "chip",
16
+ base = "var(--card)",
17
+ icon,
18
+ as: Tag = "span",
19
+ children,
20
+ className,
21
+ "aria-label": ariaLabel
22
+ }) {
23
+ return /* @__PURE__ */ jsxs(
24
+ Tag,
25
+ {
26
+ "aria-label": ariaLabel,
27
+ className: cn(
28
+ "inline-flex h-7 items-center gap-1.5 rounded-full px-2.5 text-[11.5px] text-foreground",
29
+ !hue && "bg-muted",
30
+ className
31
+ ),
32
+ style: hue ? { backgroundColor: hueTint(hue, tone, base) } : void 0,
33
+ children: [
34
+ icon,
35
+ children
36
+ ]
37
+ }
38
+ );
39
+ }
40
+
41
+ export { HueChip, hueTint };
@@ -0,0 +1,125 @@
1
+ import { cn } from './chunk-FEK5XGZW.js';
2
+ import { __objRest, __spreadProps, __spreadValues } from './chunk-3GWWZKX7.js';
3
+ import * as React from 'react';
4
+ import { cva } from 'class-variance-authority';
5
+ import { jsx, jsxs } from 'react/jsx-runtime';
6
+
7
+ var snapRailVariants = cva(
8
+ cn(
9
+ "flex snap-x snap-mandatory overflow-x-auto pb-0.5 scrollbar-hide",
10
+ "[&>*]:shrink-0 [&>*]:snap-start"
11
+ ),
12
+ {
13
+ variants: {
14
+ itemWidth: {
15
+ sm: "[&>*]:w-[46%]",
16
+ md: "[&>*]:w-[60%]",
17
+ lg: "[&>*]:w-[80%]",
18
+ /** One card per view — pair with `dots` so the reader knows there is more. */
19
+ full: "[&>*]:w-full"
20
+ },
21
+ gap: {
22
+ sm: "gap-2",
23
+ default: "gap-3"
24
+ },
25
+ bleed: {
26
+ none: "",
27
+ card: "-mx-3.5 px-3.5 scroll-px-3.5",
28
+ page: "-mx-4 px-4 scroll-px-4"
29
+ }
30
+ },
31
+ defaultVariants: {
32
+ itemWidth: "sm",
33
+ gap: "default",
34
+ bleed: "none"
35
+ }
36
+ }
37
+ );
38
+ var SnapRail = React.forwardRef(
39
+ (_a, ref) => {
40
+ var _b = _a, { className, itemWidth, gap, bleed, dots, dotsClassName, onActiveChange, children } = _b, props = __objRest(_b, ["className", "itemWidth", "gap", "bleed", "dots", "dotsClassName", "onActiveChange", "children"]);
41
+ const railRef = React.useRef(null);
42
+ const [active, setActive] = React.useState(0);
43
+ const count = React.Children.count(children);
44
+ const tracks = Boolean(dots || onActiveChange);
45
+ const onActiveChangeRef = React.useRef(onActiveChange);
46
+ onActiveChangeRef.current = onActiveChange;
47
+ const setRefs = React.useCallback(
48
+ (node) => {
49
+ railRef.current = node;
50
+ if (typeof ref === "function") ref(node);
51
+ else if (ref) ref.current = node;
52
+ },
53
+ [ref]
54
+ );
55
+ React.useEffect(() => {
56
+ if (!tracks) return;
57
+ const rail2 = railRef.current;
58
+ if (!rail2) return;
59
+ let frame = 0;
60
+ let last = -1;
61
+ const sync = () => {
62
+ var _a2;
63
+ frame = 0;
64
+ const origin = rail2.scrollLeft + (parseFloat(getComputedStyle(rail2).scrollPaddingLeft) || 0);
65
+ let best = 0;
66
+ let bestDistance = Number.POSITIVE_INFINITY;
67
+ Array.from(rail2.children).forEach((child, index) => {
68
+ const distance = Math.abs(child.offsetLeft - origin);
69
+ if (distance < bestDistance) {
70
+ bestDistance = distance;
71
+ best = index;
72
+ }
73
+ });
74
+ setActive(best);
75
+ if (best !== last) {
76
+ last = best;
77
+ (_a2 = onActiveChangeRef.current) == null ? void 0 : _a2.call(onActiveChangeRef, best);
78
+ }
79
+ };
80
+ const onScroll = () => {
81
+ if (!frame) frame = requestAnimationFrame(sync);
82
+ };
83
+ sync();
84
+ rail2.addEventListener("scroll", onScroll, { passive: true });
85
+ return () => {
86
+ if (frame) cancelAnimationFrame(frame);
87
+ rail2.removeEventListener("scroll", onScroll);
88
+ };
89
+ }, [tracks, count]);
90
+ const rail = /* @__PURE__ */ jsx(
91
+ "div",
92
+ __spreadProps(__spreadValues({
93
+ ref: setRefs,
94
+ "data-slot": "snap-rail",
95
+ className: cn(snapRailVariants({ itemWidth, gap, bleed }), className)
96
+ }, props), {
97
+ children
98
+ })
99
+ );
100
+ if (!dots) return rail;
101
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
102
+ rail,
103
+ /* @__PURE__ */ jsx(SnapRailDots, { count, active, className: dotsClassName })
104
+ ] });
105
+ }
106
+ );
107
+ SnapRail.displayName = "SnapRail";
108
+ function SnapRailDots({
109
+ count,
110
+ active,
111
+ className
112
+ }) {
113
+ return /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: cn("flex justify-center gap-1.5", className), children: Array.from({ length: count }, (_, index) => /* @__PURE__ */ jsx(
114
+ "span",
115
+ {
116
+ className: cn(
117
+ "h-1.5 rounded-full transition-[width,background-color] duration-200 motion-reduce:transition-none",
118
+ index === active ? "w-4 bg-foreground" : "w-1.5 bg-foreground/25"
119
+ )
120
+ },
121
+ index
122
+ )) });
123
+ }
124
+
125
+ export { SnapRail, SnapRailDots };