@bearmenu/ui 0.8.8 → 0.8.10
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 +167 -0
- package/dist/chunk-2XCZJWTV.js +121 -0
- package/dist/chunk-5RWTOT5Y.js +72 -0
- package/dist/chunk-62ES6N32.js +27 -0
- package/dist/chunk-AKQ57NXY.js +58 -0
- package/dist/chunk-CLLY6XB3.js +41 -0
- package/dist/chunk-DTXNDLSE.js +125 -0
- package/dist/chunk-F6FMZJDG.js +113 -0
- package/dist/{chunk-2WDJR6K7.js → chunk-G7IFL4Z4.js} +4 -1
- package/dist/chunk-MZL7CGCL.js +109 -0
- package/dist/chunk-Q6QH52LJ.js +38 -0
- package/dist/chunk-SY6RV476.js +48 -0
- package/dist/chunk-TH6W2PWG.js +213 -0
- package/dist/chunk-UDN7UHJW.js +60 -0
- package/dist/{chunk-TT3WFS6S.js → chunk-YOKHBAIH.js} +11 -11
- package/dist/components/alert.d.ts +2 -2
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/concept-compare-rail.d.ts +50 -0
- package/dist/components/concept-compare-rail.js +5 -0
- package/dist/components/concept-compare.d.ts +110 -0
- package/dist/components/concept-compare.js +238 -0
- package/dist/components/concept-convergence.d.ts +41 -0
- package/dist/components/concept-convergence.js +53 -0
- package/dist/components/convergence.d.ts +25 -0
- package/dist/components/convergence.js +4 -0
- package/dist/components/date-input.d.ts +1 -1
- package/dist/components/event-card.js +1 -1
- package/dist/components/event-compact-row.d.ts +1 -1
- package/dist/components/event-compact-row.js +1 -1
- package/dist/components/event-detail-panel.d.ts +171 -25
- package/dist/components/event-detail-panel.js +472 -175
- package/dist/components/event-index-row.js +1 -1
- package/dist/components/event-list-row-wide.js +2 -2
- package/dist/components/event-list-row.js +2 -2
- package/dist/components/explainer-steps.d.ts +34 -0
- package/dist/components/explainer-steps.js +36 -0
- package/dist/components/glass-ground.d.ts +66 -0
- package/dist/components/glass-ground.js +3 -0
- package/dist/components/hub-surface.d.ts +27 -0
- package/dist/components/hub-surface.js +30 -0
- package/dist/components/hue-chip.d.ts +70 -0
- package/dist/components/hue-chip.js +3 -0
- package/dist/components/kitchen-dossier.d.ts +88 -0
- package/dist/components/kitchen-dossier.js +187 -0
- package/dist/components/menu-dead-end.d.ts +56 -0
- package/dist/components/menu-dead-end.js +49 -0
- package/dist/components/menu-family-block.d.ts +99 -0
- package/dist/components/menu-family-block.js +155 -0
- package/dist/components/menu-family-card.d.ts +65 -0
- package/dist/components/menu-family-card.js +79 -0
- package/dist/components/menu-field.d.ts +57 -0
- package/dist/components/menu-field.js +93 -0
- package/dist/components/menu-filter-chips.d.ts +86 -0
- package/dist/components/menu-filter-chips.js +122 -0
- package/dist/components/menu-group-rows.d.ts +53 -0
- package/dist/components/menu-group-rows.js +67 -0
- package/dist/components/menu-hub-hero.d.ts +65 -0
- package/dist/components/menu-hub-hero.js +103 -0
- package/dist/components/menu-index-header.d.ts +37 -0
- package/dist/components/menu-index-header.js +68 -0
- package/dist/components/menu-index-list.d.ts +48 -0
- package/dist/components/menu-index-list.js +96 -0
- package/dist/components/menu-intent-hero.d.ts +69 -0
- package/dist/components/menu-intent-hero.js +87 -0
- package/dist/components/menu-intent-tiles.d.ts +31 -0
- package/dist/components/menu-intent-tiles.js +50 -0
- package/dist/components/menu-item.d.ts +127 -0
- package/dist/components/menu-item.js +5 -0
- package/dist/components/menu-kitchen-list.d.ts +82 -0
- package/dist/components/menu-kitchen-list.js +5 -0
- package/dist/components/menu-mocks.d.ts +90 -0
- package/dist/components/menu-mocks.js +504 -0
- package/dist/components/menu-types.d.ts +421 -0
- package/dist/components/menu-types.js +1 -0
- package/dist/components/motion-icon-controls.js +2 -2
- package/dist/components/motion-icon-set.js +21 -9
- package/dist/components/motion-icon.d.ts +22 -1
- package/dist/components/motion-icon.js +1 -1
- package/dist/components/open-now-list.d.ts +40 -0
- package/dist/components/open-now-list.js +69 -0
- package/dist/components/photo-ground.d.ts +64 -0
- package/dist/components/photo-ground.js +3 -0
- package/dist/components/place-about-tab.js +2 -2
- package/dist/components/place-details-mobile.js +2 -2
- package/dist/components/place-types.d.ts +112 -1
- package/dist/components/qa-block.d.ts +36 -0
- package/dist/components/qa-block.js +24 -0
- package/dist/components/scroll-fade.js +3 -121
- package/dist/components/signature-chip.d.ts +37 -0
- package/dist/components/signature-chip.js +4 -0
- package/dist/components/snap-rail.d.ts +48 -5
- package/dist/components/snap-rail.js +3 -51
- package/dist/components/stat-banner.d.ts +47 -0
- package/dist/components/stat-banner.js +61 -0
- package/dist/components/story.d.ts +34 -0
- package/dist/components/story.js +3 -0
- package/dist/components/tag.d.ts +2 -2
- package/dist/components/text.d.ts +1 -1
- package/dist/components/top-comparison.d.ts +28 -0
- package/dist/components/top-comparison.js +76 -0
- package/dist/components/top-cross-link.d.ts +34 -0
- package/dist/components/top-cross-link.js +101 -0
- package/dist/components/top-ranking-entry.d.ts +53 -0
- package/dist/components/top-ranking-entry.js +217 -0
- package/dist/components/top-ranking-hero.d.ts +61 -0
- package/dist/components/top-ranking-hero.js +99 -0
- package/dist/components/top-ranking-legend.d.ts +69 -0
- package/dist/components/top-ranking-legend.js +124 -0
- package/dist/components/top-types.d.ts +109 -0
- package/dist/components/top-types.js +1 -0
- package/dist/components/venue-grade-dimensions.d.ts +38 -0
- package/dist/components/venue-grade-dimensions.js +3 -0
- package/dist/components/venue-quotes.d.ts +32 -0
- package/dist/components/venue-quotes.js +3 -0
- package/dist/components/venue-wall.d.ts +41 -0
- package/dist/components/venue-wall.js +118 -0
- package/dist/components/weekday-theme-banner.d.ts +70 -0
- package/dist/components/weekday-theme-banner.js +127 -0
- package/dist/components/weekend-panel.js +2 -2
- package/package.json +1 -1
- package/src/components/colour-dictionary.stories.tsx +227 -0
- package/src/components/concept-compare-rail.tsx +131 -0
- package/src/components/concept-compare.stories.tsx +172 -0
- package/src/components/concept-compare.tsx +443 -0
- package/src/components/concept-convergence.stories.tsx +53 -0
- package/src/components/concept-convergence.tsx +90 -0
- package/src/components/convergence.stories.tsx +54 -0
- package/src/components/convergence.tsx +177 -0
- package/src/components/event-compact-row.tsx +1 -1
- package/src/components/event-detail-panel.stories.tsx +205 -97
- package/src/components/event-detail-panel.test.tsx +181 -0
- package/src/components/event-detail-panel.tsx +703 -185
- package/src/components/explainer-steps.stories.tsx +46 -0
- package/src/components/explainer-steps.tsx +74 -0
- package/src/components/glass-ground.tsx +129 -0
- package/src/components/hub-surface.stories.tsx +68 -0
- package/src/components/hub-surface.tsx +50 -0
- package/src/components/hue-chip.stories.tsx +76 -0
- package/src/components/hue-chip.test.tsx +62 -0
- package/src/components/hue-chip.tsx +99 -0
- package/src/components/kitchen-dossier.stories.tsx +108 -0
- package/src/components/kitchen-dossier.tsx +322 -0
- package/src/components/menu-dead-end.stories.tsx +67 -0
- package/src/components/menu-dead-end.tsx +127 -0
- package/src/components/menu-family-block.stories.tsx +91 -0
- package/src/components/menu-family-block.tsx +314 -0
- package/src/components/menu-family-card.stories.tsx +120 -0
- package/src/components/menu-family-card.tsx +191 -0
- package/src/components/menu-field.stories.tsx +74 -0
- package/src/components/menu-field.tsx +199 -0
- package/src/components/menu-filter-chips.stories.tsx +107 -0
- package/src/components/menu-filter-chips.tsx +238 -0
- package/src/components/menu-group-rows.stories.tsx +54 -0
- package/src/components/menu-group-rows.tsx +133 -0
- package/src/components/menu-hub-hero.stories.tsx +92 -0
- package/src/components/menu-hub-hero.tsx +187 -0
- package/src/components/menu-index-header.stories.tsx +72 -0
- package/src/components/menu-index-header.tsx +125 -0
- package/src/components/menu-index-list.stories.tsx +50 -0
- package/src/components/menu-index-list.tsx +149 -0
- package/src/components/menu-intent-hero.stories.tsx +67 -0
- package/src/components/menu-intent-hero.tsx +189 -0
- package/src/components/menu-intent-tiles.stories.tsx +54 -0
- package/src/components/menu-intent-tiles.tsx +76 -0
- package/src/components/menu-item.tsx +416 -0
- package/src/components/menu-kitchen-list.stories.tsx +67 -0
- package/src/components/menu-kitchen-list.test.tsx +78 -0
- package/src/components/menu-kitchen-list.tsx +284 -0
- package/src/components/menu-mocks.ts +592 -0
- package/src/components/menu-types.ts +442 -0
- package/src/components/motion-icon-controls.tsx +11 -11
- package/src/components/motion-icon-set.tsx +36 -8
- package/src/components/motion-icon.test.tsx +23 -1
- package/src/components/motion-icon.tsx +20 -0
- package/src/components/open-now-list.stories.tsx +76 -0
- package/src/components/open-now-list.tsx +127 -0
- package/src/components/photo-ground.tsx +147 -0
- package/src/components/place-types.ts +112 -0
- package/src/components/qa-block.stories.tsx +43 -0
- package/src/components/qa-block.tsx +60 -0
- package/src/components/signature-chip.tsx +77 -0
- package/src/components/snap-rail.tsx +133 -9
- package/src/components/stat-banner.stories.tsx +100 -0
- package/src/components/stat-banner.tsx +117 -0
- package/src/components/story.tsx +225 -0
- package/src/components/top-comparison.stories.tsx +78 -0
- package/src/components/top-comparison.tsx +151 -0
- package/src/components/top-cross-link.stories.tsx +84 -0
- package/src/components/top-cross-link.tsx +171 -0
- package/src/components/top-ranking-entry.stories.tsx +171 -0
- package/src/components/top-ranking-entry.test.tsx +105 -0
- package/src/components/top-ranking-entry.tsx +425 -0
- package/src/components/top-ranking-hero.stories.tsx +76 -0
- package/src/components/top-ranking-hero.tsx +218 -0
- package/src/components/top-ranking-legend.stories.tsx +78 -0
- package/src/components/top-ranking-legend.tsx +239 -0
- package/src/components/top-types.ts +110 -0
- package/src/components/venue-grade-dimensions.stories.tsx +83 -0
- package/src/components/venue-grade-dimensions.tsx +91 -0
- package/src/components/venue-quotes.stories.tsx +59 -0
- package/src/components/venue-quotes.tsx +64 -0
- package/src/components/venue-wall.stories.tsx +78 -0
- package/src/components/venue-wall.tsx +185 -0
- package/src/components/weekday-theme-banner.stories.tsx +113 -0
- package/src/components/weekday-theme-banner.tsx +231 -0
- package/dist/{chunk-XWMRABZW.js → chunk-HSIYYA2E.js} +1 -1
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { Check, ChevronRight, Clock, MessageSquare, Star } from "lucide-react";
|
|
2
|
+
import { cn } from "../lib/utils";
|
|
3
|
+
import { Separator } from "./separator";
|
|
4
|
+
import { Skeleton } from "./skeleton";
|
|
5
|
+
import type { MenuKitchenPreview, MenuLinkComponent, MenuLinkProps } from "./menu-types";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* MenuKitchenList — the intent page's spine.
|
|
9
|
+
*
|
|
10
|
+
* Venues ranked by how often reviews name their dishes, each row carrying the
|
|
11
|
+
* dish that earned it its place. Not a grid of dishes: a shortlist of rooms you
|
|
12
|
+
* could walk into.
|
|
13
|
+
*
|
|
14
|
+
* ## Two targets, and why this is not `<RankedVenueList>`
|
|
15
|
+
*
|
|
16
|
+
* The row goes to the venue. The dish name opens the item drawer — the same
|
|
17
|
+
* drawer the dish tiles open, listing every kitchen that makes it and for how
|
|
18
|
+
* much. Those are two different destinations inside one row, and the hub's
|
|
19
|
+
* `<RankedVenueList>` wraps its ENTIRE row in a single `LinkComponent`, so it
|
|
20
|
+
* structurally cannot express a second one. That is the reason this exists
|
|
21
|
+
* rather than a variant flag on that component.
|
|
22
|
+
*
|
|
23
|
+
* The mechanism is a stretched overlay, as in `<MenuItem>`: the venue link is
|
|
24
|
+
* an absolutely-positioned sibling at `z-[1]`, and the dish link sits above it
|
|
25
|
+
* at `z-[2]`. Nesting one anchor inside another is invalid HTML and breaks
|
|
26
|
+
* middle-click on both.
|
|
27
|
+
*
|
|
28
|
+
* The dish name is underlined so it reads as a target before it is pressed. The
|
|
29
|
+
* chevron belongs to the venue and stays on the right, away from it — an
|
|
30
|
+
* unmarked second target inside a row that already navigates is a trap.
|
|
31
|
+
*
|
|
32
|
+
* ## The filtered state changes the row's reason for being there
|
|
33
|
+
*
|
|
34
|
+
* With a dish or dietary filter on, each row swaps its most-named dish for the
|
|
35
|
+
* one that actually matched, and the kicker changes with it ("MOST NAMED HERE"
|
|
36
|
+
* → "WHY IT MATCHES"). A filtered list whose rows still advertise their
|
|
37
|
+
* most-named dish is claiming the filter matched something it did not.
|
|
38
|
+
*
|
|
39
|
+
* ## Header
|
|
40
|
+
*
|
|
41
|
+
* Deliberately none. The page composes `<SectionHeader>` above it, the same way
|
|
42
|
+
* the events hub does, because the heading here carries a count and a "see the
|
|
43
|
+
* full ranking" link into `/top` that the list knows nothing about.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/** @deprecated Alias of `MenuLinkProps`; kept for symmetry with the other menu surfaces. */
|
|
47
|
+
export type MenuKitchenListLinkProps = MenuLinkProps;
|
|
48
|
+
|
|
49
|
+
function DefaultLink({ href, ...props }: MenuKitchenListLinkProps) {
|
|
50
|
+
return <a href={href} {...props} />;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type MenuKitchenListLabels = {
|
|
54
|
+
/** Accessible prefix for the row's venue link, e.g. "Open". */
|
|
55
|
+
openVenue: (name: string) => string;
|
|
56
|
+
/** Accessible name for the dish link, e.g. "See Truffle Tagliatelle". */
|
|
57
|
+
openDish: (name: string) => string;
|
|
58
|
+
/** Accessible name for the open-now dot. */
|
|
59
|
+
openNow: string;
|
|
60
|
+
/** Reveals the next page of rows, e.g. "Show 10 more". */
|
|
61
|
+
showMore?: string;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export type MenuKitchenListProps = {
|
|
65
|
+
kitchens: MenuKitchenPreview[];
|
|
66
|
+
labels: MenuKitchenListLabels;
|
|
67
|
+
/**
|
|
68
|
+
* Reveals more rows IN PLACE. The intent page pages ten at a time and never
|
|
69
|
+
* navigates for the eleventh — the list is the page.
|
|
70
|
+
*/
|
|
71
|
+
onShowMore?: () => void;
|
|
72
|
+
linkComponent?: MenuLinkComponent;
|
|
73
|
+
className?: string;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export function MenuKitchenList({
|
|
77
|
+
kitchens,
|
|
78
|
+
labels,
|
|
79
|
+
onShowMore,
|
|
80
|
+
linkComponent = DefaultLink,
|
|
81
|
+
className,
|
|
82
|
+
}: MenuKitchenListProps) {
|
|
83
|
+
return (
|
|
84
|
+
<div className={cn("flex flex-col", className)}>
|
|
85
|
+
<ol>
|
|
86
|
+
{kitchens.map((kitchen, index) => (
|
|
87
|
+
<li key={kitchen.place.slug} className="[&:first-child>div]:pt-0">
|
|
88
|
+
{/* The DS `Separator`, drawn BETWEEN rows rather than a `border-t`
|
|
89
|
+
with a `first:` reset on every row. It lives inside the `<li>`
|
|
90
|
+
because `<ol>` admits only list items, so a sibling element
|
|
91
|
+
between them would be invalid markup. */}
|
|
92
|
+
{index > 0 && <Separator />}
|
|
93
|
+
<KitchenRow kitchen={kitchen} labels={labels} linkComponent={linkComponent} />
|
|
94
|
+
</li>
|
|
95
|
+
))}
|
|
96
|
+
</ol>
|
|
97
|
+
|
|
98
|
+
{onShowMore && labels.showMore && (
|
|
99
|
+
<button
|
|
100
|
+
type="button"
|
|
101
|
+
onClick={onShowMore}
|
|
102
|
+
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"
|
|
103
|
+
>
|
|
104
|
+
{labels.showMore}
|
|
105
|
+
</button>
|
|
106
|
+
)}
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function KitchenRow({
|
|
112
|
+
kitchen,
|
|
113
|
+
labels,
|
|
114
|
+
linkComponent: LinkComponent,
|
|
115
|
+
}: {
|
|
116
|
+
kitchen: MenuKitchenPreview;
|
|
117
|
+
labels: MenuKitchenListLabels;
|
|
118
|
+
linkComponent: MenuLinkComponent;
|
|
119
|
+
}) {
|
|
120
|
+
const { place, dish } = kitchen;
|
|
121
|
+
const openNow = place.open_now === true;
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<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">
|
|
125
|
+
{/* The venue link, stretched. `z-[1]` — the dish link sits above it. */}
|
|
126
|
+
<LinkComponent
|
|
127
|
+
href={kitchen.href}
|
|
128
|
+
aria-label={labels.openVenue(place.name)}
|
|
129
|
+
className="absolute inset-0 z-[1] rounded-xl focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
|
|
130
|
+
/>
|
|
131
|
+
|
|
132
|
+
<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]">
|
|
133
|
+
{place.thumbnail_url && (
|
|
134
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
135
|
+
<img
|
|
136
|
+
src={place.thumbnail_url}
|
|
137
|
+
alt=""
|
|
138
|
+
loading="lazy"
|
|
139
|
+
decoding="async"
|
|
140
|
+
className="h-full w-full object-cover"
|
|
141
|
+
/>
|
|
142
|
+
)}
|
|
143
|
+
<span
|
|
144
|
+
title={openNow ? labels.openNow : undefined}
|
|
145
|
+
className={cn(
|
|
146
|
+
"absolute right-[5px] top-[5px] h-[7px] w-[7px] rounded-full ring-2 ring-white/85",
|
|
147
|
+
openNow ? "bg-[var(--free,oklch(0.55_0.13_155))]" : "bg-[oklch(0.8_0.01_60)]"
|
|
148
|
+
)}
|
|
149
|
+
/>
|
|
150
|
+
</span>
|
|
151
|
+
|
|
152
|
+
<div className="flex min-w-0 flex-1 flex-col gap-0.5 lg:w-[226px] lg:flex-none">
|
|
153
|
+
<span className="truncate text-[14.5px] font-bold tracking-[-0.01em] lg:text-[15.5px]">
|
|
154
|
+
{place.name}
|
|
155
|
+
</span>
|
|
156
|
+
<span className="flex items-center gap-1 truncate text-xs text-muted-foreground">
|
|
157
|
+
{place.rating && (
|
|
158
|
+
<>
|
|
159
|
+
<Star className="h-[11px] w-[11px] shrink-0" aria-hidden />
|
|
160
|
+
{place.rating.rating}
|
|
161
|
+
{kitchen.metaLabel && " · "}
|
|
162
|
+
</>
|
|
163
|
+
)}
|
|
164
|
+
{kitchen.metaLabel}
|
|
165
|
+
</span>
|
|
166
|
+
{kitchen.hoursLabel && (
|
|
167
|
+
<span
|
|
168
|
+
className={cn(
|
|
169
|
+
"mt-[3px] inline-flex h-[21px] w-max items-center gap-[5px] rounded-md px-2 text-[10.5px] font-bold",
|
|
170
|
+
openNow
|
|
171
|
+
? "bg-[oklch(0.96_0.02_155)] text-[var(--free,oklch(0.45_0.13_155))]"
|
|
172
|
+
: "bg-muted text-muted-foreground"
|
|
173
|
+
)}
|
|
174
|
+
>
|
|
175
|
+
<Clock className="h-2.5 w-2.5 shrink-0" aria-hidden />
|
|
176
|
+
{kitchen.hoursLabel}
|
|
177
|
+
</span>
|
|
178
|
+
)}
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
{dish && (
|
|
182
|
+
/* DESKTOP ONLY, where it is a column of its own beside the venue.
|
|
183
|
+
On the phone it wrapped to a third line under the row — kicker, dish,
|
|
184
|
+
mention count — which turned a four-line venue row into a seven-line
|
|
185
|
+
block and, ten rows down, buried the venue names the list exists to
|
|
186
|
+
be scanned for. The dish is not what a reader is choosing here; it is
|
|
187
|
+
one tap away on the venue's own page, with room to state it.
|
|
188
|
+
|
|
189
|
+
`order-5` puts it last in the visual order without moving it in the
|
|
190
|
+
DOM, where it belongs to the venue. */
|
|
191
|
+
<div className="hidden min-w-0 basis-full pl-[57px] lg:order-none lg:block lg:flex-1 lg:basis-auto lg:pl-0">
|
|
192
|
+
<span
|
|
193
|
+
className={cn(
|
|
194
|
+
"flex items-center gap-1.5 text-[9px] font-extrabold uppercase tracking-[0.1em]",
|
|
195
|
+
dish.matched ? "text-accent" : "text-[oklch(0.72_0.01_60)]"
|
|
196
|
+
)}
|
|
197
|
+
>
|
|
198
|
+
{dish.kicker}
|
|
199
|
+
{dish.matched && dish.matchLabel && (
|
|
200
|
+
<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">
|
|
201
|
+
<Check className="h-2.5 w-2.5 shrink-0" aria-hidden />
|
|
202
|
+
{dish.matchLabel}
|
|
203
|
+
</span>
|
|
204
|
+
)}
|
|
205
|
+
</span>
|
|
206
|
+
|
|
207
|
+
{dish.href ? (
|
|
208
|
+
<LinkComponent
|
|
209
|
+
href={dish.href}
|
|
210
|
+
aria-label={labels.openDish(dish.name)}
|
|
211
|
+
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]"
|
|
212
|
+
>
|
|
213
|
+
{dish.name}
|
|
214
|
+
</LinkComponent>
|
|
215
|
+
) : (
|
|
216
|
+
<span className="mt-0.5 block truncate font-serif text-[13.5px] italic lg:text-[15px]">
|
|
217
|
+
{dish.name}
|
|
218
|
+
</span>
|
|
219
|
+
)}
|
|
220
|
+
|
|
221
|
+
{dish.meta && (
|
|
222
|
+
<span className="mt-[3px] flex items-center gap-1 text-[11.5px] text-muted-foreground">
|
|
223
|
+
{!dish.matched && <MessageSquare className="h-2.5 w-2.5 shrink-0" aria-hidden />}
|
|
224
|
+
{dish.meta}
|
|
225
|
+
</span>
|
|
226
|
+
)}
|
|
227
|
+
</div>
|
|
228
|
+
)}
|
|
229
|
+
|
|
230
|
+
<div className="ml-auto flex shrink-0 items-center gap-[11px] lg:ml-0">
|
|
231
|
+
{kitchen.priceLabel && (
|
|
232
|
+
<span className="text-base font-extrabold tabular-nums text-accent">
|
|
233
|
+
{kitchen.priceLabel}
|
|
234
|
+
</span>
|
|
235
|
+
)}
|
|
236
|
+
<ChevronRight className="h-[15px] w-[15px] shrink-0 text-muted-foreground" aria-hidden />
|
|
237
|
+
</div>
|
|
238
|
+
</div>
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ─── Skeleton ───────────────────────────────────────────────────────────────
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* The list's own loading state, at the row's own footprint.
|
|
246
|
+
*
|
|
247
|
+
* It lives HERE, beside the component, and that is the whole point: a skeleton
|
|
248
|
+
* kept in the consuming app drifts the moment the row's padding or thumbnail
|
|
249
|
+
* size changes, and the drift is invisible until a page reflows on load. The
|
|
250
|
+
* measurements below are the same literals the row above uses — change one and
|
|
251
|
+
* the diff shows you the other.
|
|
252
|
+
*/
|
|
253
|
+
export function MenuKitchenListSkeleton({
|
|
254
|
+
rows = 10,
|
|
255
|
+
className,
|
|
256
|
+
}: {
|
|
257
|
+
rows?: number;
|
|
258
|
+
className?: string;
|
|
259
|
+
}) {
|
|
260
|
+
return (
|
|
261
|
+
<div className={cn("flex flex-col", className)} aria-hidden>
|
|
262
|
+
{Array.from({ length: rows }, (_, index) => (
|
|
263
|
+
<div key={index}>
|
|
264
|
+
{index > 0 && <Separator />}
|
|
265
|
+
<div className="flex flex-wrap items-center gap-[11px] py-3 lg:flex-nowrap lg:gap-4 lg:py-3.5">
|
|
266
|
+
<Skeleton className="h-[46px] w-[46px] rounded-[11px] lg:h-[58px] lg:w-[58px] lg:rounded-[13px]" />
|
|
267
|
+
<div className="flex min-w-0 flex-1 flex-col gap-1.5 lg:w-[226px] lg:flex-none">
|
|
268
|
+
<Skeleton className="h-4 w-[60%]" />
|
|
269
|
+
<Skeleton className="h-3 w-[45%]" />
|
|
270
|
+
<Skeleton className="h-[21px] w-[120px] rounded-md" />
|
|
271
|
+
</div>
|
|
272
|
+
{/* Desktop only, as the real row's dish column now is. */}
|
|
273
|
+
<div className="hidden min-w-0 basis-full pl-[57px] lg:order-none lg:block lg:flex-1 lg:basis-auto lg:pl-0">
|
|
274
|
+
<Skeleton className="h-2.5 w-[90px]" />
|
|
275
|
+
<Skeleton className="mt-1.5 h-4 w-[70%]" />
|
|
276
|
+
<Skeleton className="mt-1.5 h-3 w-[40%]" />
|
|
277
|
+
</div>
|
|
278
|
+
<Skeleton className="ml-auto h-5 w-[56px] lg:ml-0" />
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
))}
|
|
282
|
+
</div>
|
|
283
|
+
);
|
|
284
|
+
}
|