@bearmenu/ui 0.8.9 → 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-AXV5O2IZ.js → chunk-AKQ57NXY.js} +3 -3
- 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-SY6RV476.js +48 -0
- package/dist/chunk-UDN7UHJW.js +60 -0
- package/dist/{chunk-TT3WFS6S.js → chunk-YOKHBAIH.js} +11 -11
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/command.d.ts +7 -7
- 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 +75 -38
- package/dist/components/concept-compare.js +209 -133
- 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.js +1 -1
- package/dist/components/event-detail-panel.js +1 -1
- package/dist/components/event-index-row.js +1 -1
- package/dist/components/event-list-row-wide.js +1 -1
- 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.js +11 -1
- 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 +33 -27
- package/dist/components/menu-family-card.js +43 -85
- package/dist/components/menu-field.js +92 -2
- 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-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-kitchen-list.d.ts +82 -0
- package/dist/components/menu-kitchen-list.js +5 -0
- package/dist/components/menu-mocks.d.ts +37 -2
- package/dist/components/menu-mocks.js +152 -27
- package/dist/components/menu-types.d.ts +182 -6
- package/dist/components/motion-icon-controls.js +2 -2
- package/dist/components/motion-icon-set.js +6 -6
- package/dist/components/motion-icon.d.ts +22 -1
- package/dist/components/motion-icon.js +1 -1
- 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 +2 -2
- 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/snap-rail.d.ts +24 -1
- package/dist/components/snap-rail.js +3 -109
- package/dist/components/spinner.d.ts +2 -2
- package/dist/components/story.d.ts +34 -0
- package/dist/components/story.js +3 -0
- package/dist/components/text.d.ts +3 -3
- 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 +3 -1
- package/dist/components/venue-grade-dimensions.js +1 -1
- package/dist/components/weekend-panel.js +2 -2
- package/package.json +1 -1
- package/src/components/concept-compare-rail.tsx +131 -0
- package/src/components/concept-compare.stories.tsx +122 -54
- package/src/components/concept-compare.tsx +363 -196
- 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/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.tsx +11 -1
- 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 +43 -35
- package/src/components/menu-family-card.tsx +122 -142
- 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-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-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 +198 -23
- package/src/components/menu-types.ts +189 -6
- package/src/components/motion-icon-controls.tsx +11 -11
- package/src/components/motion-icon-set.tsx +6 -5
- package/src/components/motion-icon.test.tsx +23 -1
- package/src/components/motion-icon.tsx +20 -0
- package/src/components/photo-ground.tsx +147 -0
- package/src/components/place-types.ts +2 -2
- package/src/components/qa-block.stories.tsx +43 -0
- package/src/components/qa-block.tsx +60 -0
- package/src/components/snap-rail.tsx +58 -15
- 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.tsx +2 -2
- package/dist/chunk-THOVPZNN.js +0 -37
- package/dist/chunk-YS6BHKZO.js +0 -92
- package/dist/components/ranked-venue-list.d.ts +0 -49
- package/dist/components/ranked-venue-list.js +0 -87
- package/dist/components/signature-line-list.d.ts +0 -45
- package/dist/components/signature-line-list.js +0 -99
- package/dist/components/venue-busyness-strip.d.ts +0 -35
- package/dist/components/venue-busyness-strip.js +0 -37
- package/dist/components/venue-signature-block.d.ts +0 -39
- package/dist/components/venue-signature-block.js +0 -6
- package/dist/components/venue-spotlight.d.ts +0 -74
- package/dist/components/venue-spotlight.js +0 -138
- package/src/components/ranked-venue-list.stories.tsx +0 -80
- package/src/components/ranked-venue-list.tsx +0 -177
- package/src/components/signature-line-list.stories.tsx +0 -85
- package/src/components/signature-line-list.tsx +0 -136
- package/src/components/venue-busyness-strip.stories.tsx +0 -66
- package/src/components/venue-busyness-strip.tsx +0 -64
- package/src/components/venue-signature-block.stories.tsx +0 -68
- package/src/components/venue-signature-block.tsx +0 -71
- package/src/components/venue-spotlight.stories.tsx +0 -141
- package/src/components/venue-spotlight.tsx +0 -236
- package/dist/{chunk-XWMRABZW.js → chunk-HSIYYA2E.js} +1 -1
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { ScrollFade } from '../chunk-2XCZJWTV.js';
|
|
2
|
+
import { Skeleton } from '../chunk-QXHMPJ35.js';
|
|
3
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
4
|
+
import '../chunk-3GWWZKX7.js';
|
|
5
|
+
import { X } from 'lucide-react';
|
|
6
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
function MenuFilterChips({
|
|
9
|
+
chips,
|
|
10
|
+
onToggle,
|
|
11
|
+
unitLabel,
|
|
12
|
+
onMore,
|
|
13
|
+
moreLabel,
|
|
14
|
+
moreIcon,
|
|
15
|
+
onMorePointerDown,
|
|
16
|
+
formatCount = String,
|
|
17
|
+
ariaLabel,
|
|
18
|
+
className
|
|
19
|
+
}) {
|
|
20
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("relative flex items-center gap-2", className), children: [
|
|
21
|
+
unitLabel && /* @__PURE__ */ jsx("span", { className: "hidden shrink-0 pr-0.5 text-[11px] font-extrabold uppercase tracking-[0.1em] text-muted-foreground lg:inline", children: unitLabel }),
|
|
22
|
+
/* @__PURE__ */ jsx(
|
|
23
|
+
ScrollFade,
|
|
24
|
+
{
|
|
25
|
+
orientation: "horizontal",
|
|
26
|
+
size: "sm",
|
|
27
|
+
className: "min-w-0 flex-1",
|
|
28
|
+
scrollClassName: "scrollbar-hide",
|
|
29
|
+
children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", role: "group", "aria-label": ariaLabel, children: chips.map((chip) => /* @__PURE__ */ jsx(
|
|
30
|
+
Chip,
|
|
31
|
+
{
|
|
32
|
+
chip,
|
|
33
|
+
onToggle: () => onToggle(chip.key),
|
|
34
|
+
formatCount
|
|
35
|
+
},
|
|
36
|
+
chip.key
|
|
37
|
+
)) })
|
|
38
|
+
}
|
|
39
|
+
),
|
|
40
|
+
onMore && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
41
|
+
moreIcon && /* @__PURE__ */ jsx(
|
|
42
|
+
"button",
|
|
43
|
+
{
|
|
44
|
+
type: "button",
|
|
45
|
+
onClick: onMore,
|
|
46
|
+
onPointerDown: onMorePointerDown,
|
|
47
|
+
"aria-label": moreLabel,
|
|
48
|
+
"aria-haspopup": "dialog",
|
|
49
|
+
className: "inline-flex size-10 shrink-0 items-center justify-center rounded-full border border-border text-accent transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none lg:hidden",
|
|
50
|
+
children: moreIcon
|
|
51
|
+
}
|
|
52
|
+
),
|
|
53
|
+
/* @__PURE__ */ jsx(
|
|
54
|
+
"button",
|
|
55
|
+
{
|
|
56
|
+
type: "button",
|
|
57
|
+
onClick: onMore,
|
|
58
|
+
className: cn(
|
|
59
|
+
"shrink-0 rounded-md pl-2 text-[12.5px] font-bold text-accent transition-colors hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none",
|
|
60
|
+
moreIcon && "hidden lg:inline"
|
|
61
|
+
),
|
|
62
|
+
children: moreLabel
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
] })
|
|
66
|
+
] });
|
|
67
|
+
}
|
|
68
|
+
function Chip({
|
|
69
|
+
chip,
|
|
70
|
+
onToggle,
|
|
71
|
+
formatCount
|
|
72
|
+
}) {
|
|
73
|
+
return /* @__PURE__ */ jsxs(
|
|
74
|
+
"button",
|
|
75
|
+
{
|
|
76
|
+
type: "button",
|
|
77
|
+
onClick: onToggle,
|
|
78
|
+
"aria-pressed": chip.active,
|
|
79
|
+
className: cn(
|
|
80
|
+
"inline-flex h-9 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full border px-4 text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none",
|
|
81
|
+
chip.active ? "border-accent font-semibold text-accent shadow-[0_1px_2px_oklch(0.51_0.095_45_/_0.08)]" : "border-border bg-card text-foreground hover:border-accent/40",
|
|
82
|
+
// Dimmed, never disabled — pressing it is how the reader finds out
|
|
83
|
+
// which active filter is in the way.
|
|
84
|
+
chip.empty && "opacity-45"
|
|
85
|
+
),
|
|
86
|
+
children: [
|
|
87
|
+
chip.icon,
|
|
88
|
+
chip.label,
|
|
89
|
+
chip.count !== void 0 && /* @__PURE__ */ jsx("span", { className: cn("tabular-nums", chip.active ? "text-accent" : "text-muted-foreground"), children: formatCount(chip.count) }),
|
|
90
|
+
chip.active && /* @__PURE__ */ jsx(X, { className: "h-3 w-3 shrink-0", "aria-hidden": true })
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
function MenuFilterSummary({
|
|
96
|
+
summary,
|
|
97
|
+
clearLabel,
|
|
98
|
+
onClear,
|
|
99
|
+
className
|
|
100
|
+
}) {
|
|
101
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-wrap items-center gap-2.5 pt-3.5", className), children: [
|
|
102
|
+
/* @__PURE__ */ jsx("span", { className: "text-[13px] text-muted-foreground [&_b]:font-bold [&_b]:text-foreground", children: summary }),
|
|
103
|
+
/* @__PURE__ */ jsx(
|
|
104
|
+
"button",
|
|
105
|
+
{
|
|
106
|
+
type: "button",
|
|
107
|
+
onClick: onClear,
|
|
108
|
+
className: "ml-auto shrink-0 rounded-md text-[12.5px] font-bold text-accent transition-colors hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none",
|
|
109
|
+
children: clearLabel
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
] });
|
|
113
|
+
}
|
|
114
|
+
var CHIP_WIDTHS = [128, 104, 96, 148, 112, 88];
|
|
115
|
+
function MenuFilterChipsSkeleton({ className }) {
|
|
116
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2 overflow-hidden", className), "aria-hidden": true, children: [
|
|
117
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-[92px] shrink-0" }),
|
|
118
|
+
CHIP_WIDTHS.map((width, index) => /* @__PURE__ */ jsx(Skeleton, { className: "h-9 shrink-0 rounded-full", style: { width } }, index))
|
|
119
|
+
] });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export { MenuFilterChips, MenuFilterChipsSkeleton, MenuFilterSummary };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { MenuLinkComponent, MenuLinkProps } from './menu-types.js';
|
|
3
|
+
import 'react';
|
|
4
|
+
import './place-types.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* MenuGroupRows — what an intent consists of.
|
|
8
|
+
*
|
|
9
|
+
* On a cuisine page this is the `dish_groups` facet narrowed by the cuisine
|
|
10
|
+
* ("Pizza · 120 kitchens · 30–68"); on a going-out page it is the digest tags
|
|
11
|
+
* and graded strengths ("Cocktails · 63 places"). One component for both,
|
|
12
|
+
* because both are the same object: a facet value, its venue count, and a range.
|
|
13
|
+
*
|
|
14
|
+
* ## The counts are VENUES, and the label has to say so
|
|
15
|
+
*
|
|
16
|
+
* There is no endpoint that counts dishes per cuisine — `/dishes` accepts
|
|
17
|
+
* `cuisine_slugs` and ignores it — so "120" here is a hundred and twenty
|
|
18
|
+
* kitchens that make a pizza, not a hundred and twenty pizzas. The `meta` line
|
|
19
|
+
* is composed by the caller precisely so that it can say which, in a language
|
|
20
|
+
* where the two words differ.
|
|
21
|
+
*
|
|
22
|
+
* ## Not `<ConceptCard>`
|
|
23
|
+
*
|
|
24
|
+
* That one is a cover-led card for a thing with a date and a venue. This is a
|
|
25
|
+
* row in a sidebar: a hue bar, a name, a count and a range. Giving it a cover
|
|
26
|
+
* would mean finding a photograph of "pasta", which is the kind of picture that
|
|
27
|
+
* makes a page look generated.
|
|
28
|
+
*/
|
|
29
|
+
/** @deprecated Alias of `MenuLinkProps`; kept for symmetry with the other menu surfaces. */
|
|
30
|
+
type MenuGroupRowsLinkProps = MenuLinkProps;
|
|
31
|
+
type MenuGroupRow = {
|
|
32
|
+
slug: string;
|
|
33
|
+
name: string;
|
|
34
|
+
/** Venue count line, e.g. "120 kitchens". Pluralised by the caller. */
|
|
35
|
+
meta: string;
|
|
36
|
+
/** Price range, already formatted, e.g. "30—68". Omitted where none is known. */
|
|
37
|
+
rangeLabel?: string;
|
|
38
|
+
href?: string;
|
|
39
|
+
/** Finished CSS gradient for the bar. A missing one falls back to the border colour. */
|
|
40
|
+
gradient?: string;
|
|
41
|
+
};
|
|
42
|
+
type MenuGroupRowsProps = {
|
|
43
|
+
rows: MenuGroupRow[];
|
|
44
|
+
linkComponent?: MenuLinkComponent;
|
|
45
|
+
className?: string;
|
|
46
|
+
};
|
|
47
|
+
declare function MenuGroupRows({ rows, linkComponent: LinkComponent, className, }: MenuGroupRowsProps): react_jsx_runtime.JSX.Element;
|
|
48
|
+
declare function MenuGroupRowsSkeleton({ rows, className, }: {
|
|
49
|
+
rows?: number;
|
|
50
|
+
className?: string;
|
|
51
|
+
}): react_jsx_runtime.JSX.Element;
|
|
52
|
+
|
|
53
|
+
export { type MenuGroupRow, MenuGroupRows, type MenuGroupRowsLinkProps, type MenuGroupRowsProps, MenuGroupRowsSkeleton };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Skeleton } from '../chunk-QXHMPJ35.js';
|
|
2
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
3
|
+
import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
|
|
4
|
+
import { ChevronRight } from 'lucide-react';
|
|
5
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
function DefaultLink(_a) {
|
|
8
|
+
var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
|
|
9
|
+
return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
|
|
10
|
+
}
|
|
11
|
+
function MenuGroupRows({
|
|
12
|
+
rows,
|
|
13
|
+
linkComponent: LinkComponent = DefaultLink,
|
|
14
|
+
className
|
|
15
|
+
}) {
|
|
16
|
+
return /* @__PURE__ */ jsx("ul", { className: cn("flex flex-col", className), children: rows.map((row) => {
|
|
17
|
+
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
18
|
+
/* @__PURE__ */ jsx(
|
|
19
|
+
"span",
|
|
20
|
+
{
|
|
21
|
+
"aria-hidden": true,
|
|
22
|
+
className: cn(
|
|
23
|
+
"h-[34px] w-2 shrink-0 rounded-full",
|
|
24
|
+
!row.gradient && "bg-border"
|
|
25
|
+
),
|
|
26
|
+
style: row.gradient ? { backgroundImage: row.gradient } : void 0
|
|
27
|
+
}
|
|
28
|
+
),
|
|
29
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
|
|
30
|
+
/* @__PURE__ */ jsx("span", { className: "block truncate text-sm font-bold", children: row.name }),
|
|
31
|
+
/* @__PURE__ */ jsx("span", { className: "mt-px block truncate text-[11.5px] text-muted-foreground", children: row.meta })
|
|
32
|
+
] }),
|
|
33
|
+
row.rangeLabel && /* @__PURE__ */ jsx("span", { className: "shrink-0 font-mono text-xs tabular-nums text-muted-foreground", children: row.rangeLabel }),
|
|
34
|
+
/* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground", "aria-hidden": true })
|
|
35
|
+
] });
|
|
36
|
+
return /* @__PURE__ */ jsx("li", { className: "border-t border-border first:border-t-0", children: row.href ? /* @__PURE__ */ jsx(
|
|
37
|
+
LinkComponent,
|
|
38
|
+
{
|
|
39
|
+
href: row.href,
|
|
40
|
+
className: "flex items-center gap-3 py-3 transition-colors hover:bg-muted/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring motion-reduce:transition-none",
|
|
41
|
+
children: body
|
|
42
|
+
}
|
|
43
|
+
) : /* @__PURE__ */ jsx("span", { className: "flex items-center gap-3 py-3", children: body }) }, row.slug);
|
|
44
|
+
}) });
|
|
45
|
+
}
|
|
46
|
+
function MenuGroupRowsSkeleton({
|
|
47
|
+
rows = 5,
|
|
48
|
+
className
|
|
49
|
+
}) {
|
|
50
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col", className), "aria-hidden": true, children: Array.from({ length: rows }, (_, index) => /* @__PURE__ */ jsxs(
|
|
51
|
+
"div",
|
|
52
|
+
{
|
|
53
|
+
className: "flex items-center gap-3 border-t border-border py-3 first:border-t-0",
|
|
54
|
+
children: [
|
|
55
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-[34px] w-2 rounded-full" }),
|
|
56
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
|
|
57
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-[50%]" }),
|
|
58
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-[35%]" })
|
|
59
|
+
] }),
|
|
60
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-[52px]" })
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
index
|
|
64
|
+
)) });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export { MenuGroupRows, MenuGroupRowsSkeleton };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { MenuIndexEntry, MenuLinkComponent } from './menu-types.js';
|
|
3
|
+
import 'react';
|
|
4
|
+
import './place-types.js';
|
|
5
|
+
|
|
6
|
+
type MenuIndexHeaderProps = {
|
|
7
|
+
/** Small caps over the title, e.g. "MENU · CLUJ-NAPOCA". */
|
|
8
|
+
eyebrow?: string;
|
|
9
|
+
title: string;
|
|
10
|
+
/** Sits beside the title, e.g. "38 cuisines". Pluralised by the caller. */
|
|
11
|
+
count?: string;
|
|
12
|
+
subtitle?: string;
|
|
13
|
+
/** The Food / Drinks control. A `<SegmentedNav>`, composed by the caller. */
|
|
14
|
+
scopeSwitch?: React.ReactNode;
|
|
15
|
+
className?: string;
|
|
16
|
+
};
|
|
17
|
+
declare function MenuIndexHeader({ eyebrow, title, count, subtitle, scopeSwitch, className, }: MenuIndexHeaderProps): react_jsx_runtime.JSX.Element;
|
|
18
|
+
/**
|
|
19
|
+
* MenuJumpStrip — the page's contents, as chips.
|
|
20
|
+
*
|
|
21
|
+
* It answers "move between families without going back to the hub", and it
|
|
22
|
+
* doubles as a table of contents: each chip carries the family's mark and its
|
|
23
|
+
* count, so the strip says how long the page is before the reader scrolls it.
|
|
24
|
+
*
|
|
25
|
+
* Only the families drawn in full belong here. A strip listing every value in
|
|
26
|
+
* the index below would be the index, twice.
|
|
27
|
+
*/
|
|
28
|
+
type MenuJumpStripProps = {
|
|
29
|
+
entries: MenuIndexEntry[];
|
|
30
|
+
formatCount?: (value: number) => string;
|
|
31
|
+
ariaLabel?: string;
|
|
32
|
+
linkComponent?: MenuLinkComponent;
|
|
33
|
+
className?: string;
|
|
34
|
+
};
|
|
35
|
+
declare function MenuJumpStrip({ entries, formatCount, ariaLabel, linkComponent: LinkComponent, className, }: MenuJumpStripProps): react_jsx_runtime.JSX.Element;
|
|
36
|
+
|
|
37
|
+
export { MenuIndexHeader, type MenuIndexHeaderProps, MenuJumpStrip, type MenuJumpStripProps };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { ScrollFade } from '../chunk-2XCZJWTV.js';
|
|
2
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
3
|
+
import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
|
|
4
|
+
import { jsxs, jsx } 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
|
+
function MenuIndexHeader({
|
|
11
|
+
eyebrow,
|
|
12
|
+
title,
|
|
13
|
+
count,
|
|
14
|
+
subtitle,
|
|
15
|
+
scopeSwitch,
|
|
16
|
+
className
|
|
17
|
+
}) {
|
|
18
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-4 lg:flex-row lg:items-start lg:gap-8", className), children: [
|
|
19
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
20
|
+
eyebrow && /* @__PURE__ */ jsx("p", { className: "text-[11px] font-bold uppercase tracking-[0.1em] text-muted-foreground", children: eyebrow }),
|
|
21
|
+
/* @__PURE__ */ jsxs("h1", { className: "mt-1.5 text-[30px] font-black leading-[1.05] tracking-[-0.035em] lg:text-[40px]", children: [
|
|
22
|
+
title,
|
|
23
|
+
count && /* @__PURE__ */ jsx("span", { className: "ml-2.5 align-middle text-base font-semibold text-muted-foreground lg:text-lg", children: count })
|
|
24
|
+
] }),
|
|
25
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "mt-2 max-w-[60ch] text-sm text-muted-foreground", children: subtitle })
|
|
26
|
+
] }),
|
|
27
|
+
scopeSwitch && /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-10 -mx-[var(--page-gutter)] bg-background px-[var(--page-gutter)] py-2 lg:static lg:mx-0 lg:bg-transparent lg:px-0 lg:py-0", children: scopeSwitch })
|
|
28
|
+
] });
|
|
29
|
+
}
|
|
30
|
+
function MenuJumpStrip({
|
|
31
|
+
entries,
|
|
32
|
+
formatCount = String,
|
|
33
|
+
ariaLabel,
|
|
34
|
+
linkComponent: LinkComponent = DefaultLink,
|
|
35
|
+
className
|
|
36
|
+
}) {
|
|
37
|
+
return /* @__PURE__ */ jsx(
|
|
38
|
+
ScrollFade,
|
|
39
|
+
{
|
|
40
|
+
orientation: "horizontal",
|
|
41
|
+
size: "sm",
|
|
42
|
+
className,
|
|
43
|
+
scrollClassName: "scrollbar-hide",
|
|
44
|
+
children: /* @__PURE__ */ jsx("nav", { "aria-label": ariaLabel, className: "flex items-center gap-2", children: entries.map((entry) => /* @__PURE__ */ jsxs(
|
|
45
|
+
LinkComponent,
|
|
46
|
+
{
|
|
47
|
+
href: entry.href,
|
|
48
|
+
className: "inline-flex h-9 shrink-0 items-center gap-2 whitespace-nowrap rounded-full border border-border bg-card px-4 text-sm transition-colors hover:border-accent/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none",
|
|
49
|
+
children: [
|
|
50
|
+
/* @__PURE__ */ jsx(
|
|
51
|
+
"span",
|
|
52
|
+
{
|
|
53
|
+
"aria-hidden": true,
|
|
54
|
+
className: cn("h-2.5 w-2.5 shrink-0 rounded-[3px]", !entry.gradient && "bg-border"),
|
|
55
|
+
style: entry.gradient ? { backgroundImage: entry.gradient } : void 0
|
|
56
|
+
}
|
|
57
|
+
),
|
|
58
|
+
entry.name,
|
|
59
|
+
/* @__PURE__ */ jsx("span", { className: "tabular-nums text-muted-foreground", children: formatCount(entry.count) })
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
entry.slug
|
|
63
|
+
)) })
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { MenuIndexHeader, MenuJumpStrip };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { MenuIndexEntry, MenuLinkComponent, MenuLinkProps } from './menu-types.js';
|
|
3
|
+
import 'react';
|
|
4
|
+
import './place-types.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* MenuIndexList — the complete set, four across.
|
|
8
|
+
*
|
|
9
|
+
* ## This block is why the page can afford to be progressive
|
|
10
|
+
*
|
|
11
|
+
* It carries a crawlable link to EVERY destination the city has — all
|
|
12
|
+
* thirty-eight cuisines, not the ten the page draws in full below. That makes
|
|
13
|
+
* it the page's entire link-equity job, which in turn means the rich blocks
|
|
14
|
+
* underneath are free to load ten at a time behind a "show more": nothing a
|
|
15
|
+
* crawler needs is hidden behind that control, because it is all up here.
|
|
16
|
+
*
|
|
17
|
+
* Get this backwards — put the whole set behind the disclosure and only ten
|
|
18
|
+
* links in the markup — and the page silently stops linking to twenty-eight
|
|
19
|
+
* pages it is supposed to be the index for.
|
|
20
|
+
*
|
|
21
|
+
* ## Ordered by count, and the counts overlap
|
|
22
|
+
*
|
|
23
|
+
* Cuisines are non-exclusive tags: Cluj's thirty-eight sum to 3,182 against 767
|
|
24
|
+
* places, because a trattoria is Italian AND pizza AND international. So this
|
|
25
|
+
* is a ranked list of ways in, never a partition, and no copy near it may total
|
|
26
|
+
* the numbers or call them a breakdown.
|
|
27
|
+
*/
|
|
28
|
+
/** @deprecated Alias of `MenuLinkProps`; kept for symmetry with the other menu surfaces. */
|
|
29
|
+
type MenuIndexListLinkProps = MenuLinkProps;
|
|
30
|
+
type MenuIndexListProps = {
|
|
31
|
+
entries: MenuIndexEntry[];
|
|
32
|
+
/** e.g. "All 38 cuisines". Composed and pluralised by the caller. */
|
|
33
|
+
title: string;
|
|
34
|
+
/** One line under it, e.g. "Ordered by kitchens — every one has its own page". */
|
|
35
|
+
subtitle?: string;
|
|
36
|
+
/** Locale-aware integer formatter. Defaults to `String`. */
|
|
37
|
+
formatCount?: (value: number) => string;
|
|
38
|
+
linkComponent?: MenuLinkComponent;
|
|
39
|
+
className?: string;
|
|
40
|
+
};
|
|
41
|
+
declare function MenuIndexList({ entries, title, subtitle, formatCount, linkComponent: LinkComponent, className, }: MenuIndexListProps): react_jsx_runtime.JSX.Element;
|
|
42
|
+
/** Two columns on a phone, four from `lg` — the grid the list itself renders. */
|
|
43
|
+
declare function MenuIndexListSkeleton({ rows, className, }: {
|
|
44
|
+
rows?: number;
|
|
45
|
+
className?: string;
|
|
46
|
+
}): react_jsx_runtime.JSX.Element;
|
|
47
|
+
|
|
48
|
+
export { MenuIndexList, type MenuIndexListLinkProps, type MenuIndexListProps, MenuIndexListSkeleton };
|
|
@@ -0,0 +1,96 @@
|
|
|
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 { ChevronRight } from 'lucide-react';
|
|
6
|
+
import { jsxs, jsx } 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 MenuIndexList({
|
|
13
|
+
entries,
|
|
14
|
+
title,
|
|
15
|
+
subtitle,
|
|
16
|
+
formatCount = String,
|
|
17
|
+
linkComponent: LinkComponent = DefaultLink,
|
|
18
|
+
className
|
|
19
|
+
}) {
|
|
20
|
+
return /* @__PURE__ */ jsxs(
|
|
21
|
+
"section",
|
|
22
|
+
{
|
|
23
|
+
className: cn(
|
|
24
|
+
"rounded-[18px] border border-border bg-card px-3.5 py-4 lg:px-5 lg:py-5",
|
|
25
|
+
className
|
|
26
|
+
),
|
|
27
|
+
children: [
|
|
28
|
+
/* @__PURE__ */ jsxs("div", { className: "pb-2", children: [
|
|
29
|
+
/* @__PURE__ */ jsx("h2", { className: "text-[15px] font-bold tracking-[-0.01em]", children: title }),
|
|
30
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-[12.5px] text-muted-foreground", children: subtitle })
|
|
31
|
+
] }),
|
|
32
|
+
/* @__PURE__ */ jsx("ul", { className: "grid grid-cols-2 gap-x-5 lg:grid-cols-4 lg:gap-x-8", children: entries.map((entry) => /* @__PURE__ */ jsxs("li", { children: [
|
|
33
|
+
/* @__PURE__ */ jsx(Separator, {}),
|
|
34
|
+
/* @__PURE__ */ jsxs(
|
|
35
|
+
LinkComponent,
|
|
36
|
+
{
|
|
37
|
+
href: entry.href,
|
|
38
|
+
className: "group flex items-center gap-2.5 py-2.5 transition-colors hover:text-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring motion-reduce:transition-none",
|
|
39
|
+
children: [
|
|
40
|
+
/* @__PURE__ */ jsx(
|
|
41
|
+
"span",
|
|
42
|
+
{
|
|
43
|
+
"aria-hidden": true,
|
|
44
|
+
className: cn(
|
|
45
|
+
"h-2.5 w-2.5 shrink-0 rounded-[3px]",
|
|
46
|
+
!entry.gradient && "bg-border"
|
|
47
|
+
),
|
|
48
|
+
style: entry.gradient ? { backgroundImage: entry.gradient } : void 0
|
|
49
|
+
}
|
|
50
|
+
),
|
|
51
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-[13.5px]", children: entry.name }),
|
|
52
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-[13px] tabular-nums text-muted-foreground", children: formatCount(entry.count) }),
|
|
53
|
+
/* @__PURE__ */ jsx(
|
|
54
|
+
ChevronRight,
|
|
55
|
+
{
|
|
56
|
+
className: "h-3.5 w-3.5 shrink-0 text-muted-foreground transition-colors group-hover:text-accent motion-reduce:transition-none",
|
|
57
|
+
"aria-hidden": true
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
] }, entry.slug)) })
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
function MenuIndexListSkeleton({
|
|
69
|
+
rows = 24,
|
|
70
|
+
className
|
|
71
|
+
}) {
|
|
72
|
+
return /* @__PURE__ */ jsxs(
|
|
73
|
+
"section",
|
|
74
|
+
{
|
|
75
|
+
className: cn(
|
|
76
|
+
"rounded-[18px] border border-border bg-card px-3.5 py-4 lg:px-5 lg:py-5",
|
|
77
|
+
className
|
|
78
|
+
),
|
|
79
|
+
"aria-hidden": true,
|
|
80
|
+
children: [
|
|
81
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-[15px] w-[140px]" }),
|
|
82
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "mt-1.5 h-3 w-[240px]" }),
|
|
83
|
+
/* @__PURE__ */ jsx("ul", { className: "mt-2 grid grid-cols-2 gap-x-5 lg:grid-cols-4 lg:gap-x-8", children: Array.from({ length: rows }, (_, index) => /* @__PURE__ */ jsxs("li", { children: [
|
|
84
|
+
/* @__PURE__ */ jsx(Separator, {}),
|
|
85
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 py-2.5", children: [
|
|
86
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-2.5 w-2.5 rounded-[3px]" }),
|
|
87
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 flex-1" }),
|
|
88
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-6" })
|
|
89
|
+
] })
|
|
90
|
+
] }, index)) })
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { MenuIndexList, MenuIndexListSkeleton };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { MenuIntentFigure, MenuLinkComponent } from './menu-types.js';
|
|
3
|
+
import 'react';
|
|
4
|
+
import './place-types.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* MenuIntentHero — the head of an intent page (`/menu/cuisines/italian`).
|
|
8
|
+
*
|
|
9
|
+
* The intent page answers "which kitchens, for this, right now", and the hero's
|
|
10
|
+
* job is to make the size of the answer legible before the reader touches a
|
|
11
|
+
* filter: how many kitchens cook this, what they are known for, how many are
|
|
12
|
+
* serving. Every number in it is real and every one of them is a control.
|
|
13
|
+
*
|
|
14
|
+
* ## Distinct from `<MenuHubHero>`
|
|
15
|
+
*
|
|
16
|
+
* The hub's hero introduces a city's whole menu and carries a search field.
|
|
17
|
+
* This one introduces ONE intent and carries figures that filter the list
|
|
18
|
+
* below it. They share a look — a tinted panel with a watermark — and nothing
|
|
19
|
+
* else, so they are two components rather than one with a mode.
|
|
20
|
+
*
|
|
21
|
+
* ## The figures are the first filter
|
|
22
|
+
*
|
|
23
|
+
* "58 open now" is both a fact and the fastest way to act on it, so tapping a
|
|
24
|
+
* figure applies it as a filter rather than scrolling somewhere. A figure with
|
|
25
|
+
* no `onSelect` renders as a plain fact: the total is normally one, because
|
|
26
|
+
* filtering to "all of them" is not a state.
|
|
27
|
+
*
|
|
28
|
+
* They stay four across on the phone. The board proved the row legible at
|
|
29
|
+
* 390px, and a 2×2 costs ~40px of height in the tallest element on the
|
|
30
|
+
* smallest screen; the labels wrap instead.
|
|
31
|
+
*
|
|
32
|
+
* ## The paragraph survives the phone
|
|
33
|
+
*
|
|
34
|
+
* The board hides it under 640px. It is kept here and clamped instead: it is
|
|
35
|
+
* the page's only prose, it is what the description meta is built from, and
|
|
36
|
+
* `display: none` on the one indexed sentence is a cost the extra three lines
|
|
37
|
+
* do not justify.
|
|
38
|
+
*/
|
|
39
|
+
type MenuIntentHeroProps = {
|
|
40
|
+
title: string;
|
|
41
|
+
/**
|
|
42
|
+
* Over the title — the active constraint ("TONIGHT · OPEN NOW OR LATER"), or
|
|
43
|
+
* the intent's kind ("CUISINE") when there is none.
|
|
44
|
+
*/
|
|
45
|
+
kicker?: string;
|
|
46
|
+
/** Icon node for the kicker, resolved by the caller. */
|
|
47
|
+
kickerIcon?: React.ReactNode;
|
|
48
|
+
/** One paragraph of real numbers. Generated by the caller from the facets. */
|
|
49
|
+
description?: string;
|
|
50
|
+
figures?: MenuIntentFigure[];
|
|
51
|
+
/**
|
|
52
|
+
* Finished CSS gradient for the ground, e.g. `linear-gradient(140deg, …)`.
|
|
53
|
+
*
|
|
54
|
+
* A gradient rather than a token name, for the same reason `<MenuField>` and
|
|
55
|
+
* `<MenuIntentTiles>` take one: the hue tables are app-owned, and a component
|
|
56
|
+
* referencing `var(--h-pizza)` renders an unstyled panel in any consumer that
|
|
57
|
+
* does not define it. Missing, the panel falls back to the foreground colour
|
|
58
|
+
* — visibly unstyled rather than white text on white.
|
|
59
|
+
*/
|
|
60
|
+
gradient?: string;
|
|
61
|
+
/** Watermark behind the text, resolved by the caller. */
|
|
62
|
+
icon?: React.ReactNode;
|
|
63
|
+
/** Used for any figure carrying an `href`. Defaults to a plain `<a>`. */
|
|
64
|
+
linkComponent?: MenuLinkComponent;
|
|
65
|
+
className?: string;
|
|
66
|
+
};
|
|
67
|
+
declare function MenuIntentHero({ title, kicker, kickerIcon, description, figures, gradient, icon, linkComponent, className, }: MenuIntentHeroProps): react_jsx_runtime.JSX.Element;
|
|
68
|
+
|
|
69
|
+
export { MenuIntentHero, type MenuIntentHeroProps };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
2
|
+
import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
|
|
3
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
function DefaultLink(_a) {
|
|
6
|
+
var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
|
|
7
|
+
return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
|
|
8
|
+
}
|
|
9
|
+
function MenuIntentHero({
|
|
10
|
+
title,
|
|
11
|
+
kicker,
|
|
12
|
+
kickerIcon,
|
|
13
|
+
description,
|
|
14
|
+
figures,
|
|
15
|
+
gradient,
|
|
16
|
+
icon,
|
|
17
|
+
linkComponent = DefaultLink,
|
|
18
|
+
className
|
|
19
|
+
}) {
|
|
20
|
+
return /* @__PURE__ */ jsxs(
|
|
21
|
+
"div",
|
|
22
|
+
{
|
|
23
|
+
className: cn(
|
|
24
|
+
"relative flex overflow-hidden rounded-[18px] text-white lg:min-h-[210px]",
|
|
25
|
+
!gradient && "bg-foreground",
|
|
26
|
+
className
|
|
27
|
+
),
|
|
28
|
+
children: [
|
|
29
|
+
gradient && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "absolute inset-0", style: { backgroundImage: gradient } }),
|
|
30
|
+
icon && /* @__PURE__ */ jsx(
|
|
31
|
+
"span",
|
|
32
|
+
{
|
|
33
|
+
"aria-hidden": true,
|
|
34
|
+
className: "pointer-events-none absolute -bottom-7 -right-4 opacity-20 [&>svg]:h-[120px] [&>svg]:w-[120px] lg:[&>svg]:h-[170px] lg:[&>svg]:w-[170px]",
|
|
35
|
+
children: icon
|
|
36
|
+
}
|
|
37
|
+
),
|
|
38
|
+
/* @__PURE__ */ jsxs("div", { className: "relative z-[1] flex w-full flex-col gap-2.5 p-5 lg:gap-[11px] lg:px-[26px] lg:py-6", children: [
|
|
39
|
+
kicker && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-[10.5px] font-extrabold uppercase tracking-[0.13em] opacity-[0.82]", children: [
|
|
40
|
+
kickerIcon,
|
|
41
|
+
kicker
|
|
42
|
+
] }),
|
|
43
|
+
/* @__PURE__ */ jsx("h1", { className: "font-serif text-[29px] font-semibold leading-[1.04] tracking-[-0.025em] lg:text-[40px]", children: title }),
|
|
44
|
+
description && /* @__PURE__ */ jsx("p", { className: "line-clamp-3 max-w-[520px] text-[13.5px] leading-[1.55] opacity-85 lg:line-clamp-none lg:text-sm", children: description }),
|
|
45
|
+
figures && figures.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-auto grid grid-cols-4 gap-x-4 gap-y-3 pt-3.5 lg:flex lg:gap-[26px] lg:pt-4", children: figures.map((figure) => /* @__PURE__ */ jsx(Figure, { figure, linkComponent }, figure.key)) })
|
|
46
|
+
] })
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
function Figure({
|
|
52
|
+
figure,
|
|
53
|
+
linkComponent: LinkComponent
|
|
54
|
+
}) {
|
|
55
|
+
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
56
|
+
/* @__PURE__ */ jsx("span", { className: "block text-xl font-black leading-none tracking-[-0.03em] tabular-nums lg:text-2xl", children: figure.value }),
|
|
57
|
+
/* @__PURE__ */ jsx("span", { className: "mt-1 block text-[11px] leading-tight opacity-[0.72]", children: figure.label })
|
|
58
|
+
] });
|
|
59
|
+
const interactive = cn(
|
|
60
|
+
"block min-w-0 rounded-lg text-left transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/70 motion-reduce:transition-none",
|
|
61
|
+
figure.active ? "opacity-100" : "opacity-90"
|
|
62
|
+
);
|
|
63
|
+
if (figure.href) {
|
|
64
|
+
return /* @__PURE__ */ jsx(
|
|
65
|
+
LinkComponent,
|
|
66
|
+
{
|
|
67
|
+
href: figure.href,
|
|
68
|
+
"aria-current": figure.active ? "page" : void 0,
|
|
69
|
+
className: interactive,
|
|
70
|
+
children: body
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
if (!figure.onSelect) return /* @__PURE__ */ jsx("span", { className: "block min-w-0", children: body });
|
|
75
|
+
return /* @__PURE__ */ jsx(
|
|
76
|
+
"button",
|
|
77
|
+
{
|
|
78
|
+
type: "button",
|
|
79
|
+
onClick: figure.onSelect,
|
|
80
|
+
"aria-pressed": figure.active,
|
|
81
|
+
className: interactive,
|
|
82
|
+
children: body
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export { MenuIntentHero };
|