@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { beats, returnTransition, MotionIcon } from './chunk-
|
|
1
|
+
import { beats, returnTransition, MotionIcon, pivot } from './chunk-G7IFL4Z4.js';
|
|
2
2
|
import { __spreadProps, __spreadValues } from './chunk-3GWWZKX7.js';
|
|
3
3
|
import { motion } from 'framer-motion';
|
|
4
4
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
@@ -19,7 +19,7 @@ function MotionHeart(props) {
|
|
|
19
19
|
motion.path,
|
|
20
20
|
{
|
|
21
21
|
variants: heartBody,
|
|
22
|
-
style:
|
|
22
|
+
style: pivot(12, 13),
|
|
23
23
|
fill: "currentColor",
|
|
24
24
|
fillOpacity: 0,
|
|
25
25
|
d: "M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5"
|
|
@@ -43,7 +43,7 @@ function MotionBookmark(props) {
|
|
|
43
43
|
motion.path,
|
|
44
44
|
{
|
|
45
45
|
variants: bookmarkBody,
|
|
46
|
-
style:
|
|
46
|
+
style: pivot(12, 21),
|
|
47
47
|
fill: "currentColor",
|
|
48
48
|
fillOpacity: 0,
|
|
49
49
|
d: "M17 3a2 2 0 0 1 2 2v15a1 1 0 0 1-1.496.868l-4.512-2.578a2 2 0 0 0-1.984 0l-4.512 2.578A1 1 0 0 1 5 20V5a2 2 0 0 1 2-2z"
|
|
@@ -89,7 +89,7 @@ var found = {
|
|
|
89
89
|
}
|
|
90
90
|
};
|
|
91
91
|
function MotionSearch(props) {
|
|
92
|
-
return /* @__PURE__ */ jsx(MotionIcon, __spreadProps(__spreadValues({}, props), { children: /* @__PURE__ */ jsxs(motion.g, { variants: lens, style:
|
|
92
|
+
return /* @__PURE__ */ jsx(MotionIcon, __spreadProps(__spreadValues({}, props), { children: /* @__PURE__ */ jsxs(motion.g, { variants: lens, style: pivot(21, 21), children: [
|
|
93
93
|
/* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "8" }),
|
|
94
94
|
/* @__PURE__ */ jsx("path", { d: "m21 21-4.34-4.34" }),
|
|
95
95
|
/* @__PURE__ */ jsx(
|
|
@@ -97,7 +97,7 @@ function MotionSearch(props) {
|
|
|
97
97
|
{
|
|
98
98
|
variants: found,
|
|
99
99
|
opacity: 0,
|
|
100
|
-
style:
|
|
100
|
+
style: pivot(11, 11),
|
|
101
101
|
fill: "currentColor",
|
|
102
102
|
cx: "11",
|
|
103
103
|
cy: "11",
|
|
@@ -207,7 +207,7 @@ var crescent = {
|
|
|
207
207
|
}
|
|
208
208
|
};
|
|
209
209
|
function MotionTheme(props) {
|
|
210
|
-
const origin =
|
|
210
|
+
const origin = pivot(12, 12);
|
|
211
211
|
return /* @__PURE__ */ jsxs(MotionIcon, __spreadProps(__spreadValues({}, props), { children: [
|
|
212
212
|
/* @__PURE__ */ jsx(motion.g, { variants: rays, style: origin, children: SUN_RAYS.map((d) => /* @__PURE__ */ jsx("path", { d }, d)) }),
|
|
213
213
|
/* @__PURE__ */ jsx(motion.circle, { variants: disc, style: origin, cx: "12", cy: "12", r: "4" }),
|
|
@@ -232,7 +232,7 @@ var chevron = {
|
|
|
232
232
|
}
|
|
233
233
|
};
|
|
234
234
|
function MotionChevron(props) {
|
|
235
|
-
return /* @__PURE__ */ jsx(MotionIcon, __spreadProps(__spreadValues({}, props), { children: /* @__PURE__ */ jsx(motion.path, { variants: chevron, style:
|
|
235
|
+
return /* @__PURE__ */ jsx(MotionIcon, __spreadProps(__spreadValues({}, props), { children: /* @__PURE__ */ jsx(motion.path, { variants: chevron, style: pivot(12, 12), d: "m6 9 6 6 6-6" }) }));
|
|
236
236
|
}
|
|
237
237
|
var PLAYPAUSE_TIMES = [0, 0.24, 0.72, 1];
|
|
238
238
|
var playHead = {
|
|
@@ -255,7 +255,7 @@ function pauseBar(dx) {
|
|
|
255
255
|
var barLeft = pauseBar(5);
|
|
256
256
|
var barRight = pauseBar(-5);
|
|
257
257
|
function MotionPlayPause(props) {
|
|
258
|
-
const origin =
|
|
258
|
+
const origin = pivot(12, 12);
|
|
259
259
|
return /* @__PURE__ */ jsxs(MotionIcon, __spreadProps(__spreadValues({}, props), { children: [
|
|
260
260
|
/* @__PURE__ */ jsx(
|
|
261
261
|
motion.path,
|
|
@@ -290,7 +290,7 @@ var slash = {
|
|
|
290
290
|
}
|
|
291
291
|
};
|
|
292
292
|
function MotionEye(props) {
|
|
293
|
-
const origin =
|
|
293
|
+
const origin = pivot(12, 12);
|
|
294
294
|
return /* @__PURE__ */ jsxs(MotionIcon, __spreadProps(__spreadValues({}, props), { children: [
|
|
295
295
|
/* @__PURE__ */ jsx(
|
|
296
296
|
motion.path,
|
|
@@ -320,7 +320,7 @@ function MotionStar(props) {
|
|
|
320
320
|
motion.path,
|
|
321
321
|
{
|
|
322
322
|
variants: starBody,
|
|
323
|
-
style:
|
|
323
|
+
style: pivot(12, 12),
|
|
324
324
|
fill: "currentColor",
|
|
325
325
|
fillOpacity: 0,
|
|
326
326
|
d: "M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"
|
|
@@ -368,7 +368,7 @@ var refreshRing = {
|
|
|
368
368
|
}
|
|
369
369
|
};
|
|
370
370
|
function MotionRefresh(props) {
|
|
371
|
-
return /* @__PURE__ */ jsx(MotionIcon, __spreadProps(__spreadValues({}, props), { children: /* @__PURE__ */ jsxs(motion.g, { variants: refreshRing, style:
|
|
371
|
+
return /* @__PURE__ */ jsx(MotionIcon, __spreadProps(__spreadValues({}, props), { children: /* @__PURE__ */ jsxs(motion.g, { variants: refreshRing, style: pivot(12, 12), children: [
|
|
372
372
|
/* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" }),
|
|
373
373
|
/* @__PURE__ */ jsx("path", { d: "M21 3v5h-5" }),
|
|
374
374
|
/* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" }),
|
|
@@ -3,10 +3,10 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const alertVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
6
|
+
variant?: "default" | "destructive" | "success" | "warning" | null | undefined;
|
|
7
7
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
8
8
|
declare const Alert: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & VariantProps<(props?: ({
|
|
9
|
-
variant?: "
|
|
9
|
+
variant?: "default" | "destructive" | "success" | "warning" | null | undefined;
|
|
10
10
|
} & class_variance_authority_types.ClassProp) | undefined) => string> & React.RefAttributes<HTMLDivElement>>;
|
|
11
11
|
declare const AlertTitle: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLHeadingElement> & React.RefAttributes<HTMLParagraphElement>>;
|
|
12
12
|
declare const AlertDescription: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>>;
|
|
@@ -4,7 +4,7 @@ import * as React from 'react';
|
|
|
4
4
|
import { VariantProps } from 'class-variance-authority';
|
|
5
5
|
|
|
6
6
|
declare const badgeVariants: (props?: ({
|
|
7
|
-
variant?: "
|
|
7
|
+
variant?: "default" | "destructive" | "outline" | "secondary" | "glass" | "overlay" | "brown" | "success" | "warning" | null | undefined;
|
|
8
8
|
live?: boolean | null | undefined;
|
|
9
9
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
10
10
|
interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ConceptCompareRail — the rooms as a rail, the card's backdrop following the
|
|
6
|
+
* active room, and the foot band that carries the page dots.
|
|
7
|
+
*
|
|
8
|
+
* On the phone the card IS the current room's photograph: the head, the rail
|
|
9
|
+
* and the foot all sit on it, and it cross-fades to the next room as the
|
|
10
|
+
* reader swipes. That needs the rail's active index, which is state — so this
|
|
11
|
+
* is the one client boundary in `ConceptCompare`. It takes only what can cross
|
|
12
|
+
* that boundary: photograph URLs, initials, and the pre-rendered rooms and
|
|
13
|
+
* foot as children. `labels`, `formatPrice` and the rest stay server-side.
|
|
14
|
+
*
|
|
15
|
+
* ## Why the backdrop lives here and not in each slide
|
|
16
|
+
*
|
|
17
|
+
* A slide carrying its own photograph is a boxed card sliding over a dark
|
|
18
|
+
* ground; the backdrop changing under a transparent slide is the reader
|
|
19
|
+
* turning to look at the next room. The second is the smoother thing, and it
|
|
20
|
+
* is also cheaper to look at — one photograph at a time instead of the edge of
|
|
21
|
+
* the next one peeking in.
|
|
22
|
+
*
|
|
23
|
+
* ## Why the foot is here too
|
|
24
|
+
*
|
|
25
|
+
* The dots need the rail's state, and on the phone they belong INSIDE the foot
|
|
26
|
+
* band's glass — under the rail they sat on a strip of bare photograph between
|
|
27
|
+
* the room's scrim and the foot's. So the foot renders here, with the dots as
|
|
28
|
+
* its first row below `lg`, and `ConceptCompare` hands it the foot's content.
|
|
29
|
+
*
|
|
30
|
+
* Desktop ignores the backdrop and the dots (`lg:hidden`); each room carries
|
|
31
|
+
* its own photograph there, side by side, and the foot is an absolute glass
|
|
32
|
+
* band over them.
|
|
33
|
+
*/
|
|
34
|
+
type ConceptCompareBackdrop = {
|
|
35
|
+
/** The room's photograph. Absent: the ground with the venue's initial. */
|
|
36
|
+
src?: string;
|
|
37
|
+
/** The venue's first letter, for the no-photograph fallback. */
|
|
38
|
+
initial: string;
|
|
39
|
+
};
|
|
40
|
+
type ConceptCompareRailProps = {
|
|
41
|
+
backdrops: ConceptCompareBackdrop[];
|
|
42
|
+
/** Classes for the rail itself — the desktop grid lives here. */
|
|
43
|
+
railClassName?: string;
|
|
44
|
+
/** The foot's content: the note and the action. Omit for no foot. */
|
|
45
|
+
foot?: React.ReactNode;
|
|
46
|
+
children: React.ReactNode;
|
|
47
|
+
};
|
|
48
|
+
declare function ConceptCompareRail({ backdrops, railClassName, foot, children, }: ConceptCompareRailProps): react_jsx_runtime.JSX.Element;
|
|
49
|
+
|
|
50
|
+
export { type ConceptCompareBackdrop, ConceptCompareRail, type ConceptCompareRailProps };
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { MenuConceptPreview, MenuLinkComponent, MenuLinkProps } from './menu-types.js';
|
|
3
|
+
import 'react';
|
|
4
|
+
import './place-types.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* ConceptCompare — one dish or drink across the kitchens that make it, under
|
|
8
|
+
* whatever name each of them uses. No surfaces at all.
|
|
9
|
+
*
|
|
10
|
+
* The keystone module: a single menu can list papanași, only a catalogue can
|
|
11
|
+
* say that forty-five kitchens make them under eight names between 29 and 52
|
|
12
|
+
* lei. Each kitchen's own wording is the evidence that these are matched rows
|
|
13
|
+
* rather than one row repeated.
|
|
14
|
+
*
|
|
15
|
+
* ## The card IS the rooms
|
|
16
|
+
*
|
|
17
|
+
* Every panel is gone. Each room is a VENUE photograph — real and licensed
|
|
18
|
+
* where an item's would be generated — with the kitchen's line floating over
|
|
19
|
+
* it, and the three readable things sit on glass: the identity in a band
|
|
20
|
+
* across the top, each kitchen's line over its own photograph, the foot along
|
|
21
|
+
* the bottom.
|
|
22
|
+
*
|
|
23
|
+
* ## Read across on desktop, one at a time on the phone
|
|
24
|
+
*
|
|
25
|
+
* From `lg` the rooms stand side by side — four kitchens, each with its own
|
|
26
|
+
* name for the dish and its own price, so comparing is a horizontal glance —
|
|
27
|
+
* and the head and foot are ABSOLUTE glass bands over them, so the photographs
|
|
28
|
+
* run the full height of the card beneath both. The head's glass fades out
|
|
29
|
+
* downward on the same curve as its mask; the foot's fades out upward the same
|
|
30
|
+
* way. It was the ink stopping short of the mask that drew a line where a band
|
|
31
|
+
* ended.
|
|
32
|
+
*
|
|
33
|
+
* Below `lg` four rooms in a 2×2 was too much happening in one card, so the
|
|
34
|
+
* rooms become a `SnapRail`: one room per swipe, page dots under it, the head
|
|
35
|
+
* and foot static on the card's ground above and below. The dots are the
|
|
36
|
+
* rail's own — the same object the hub's other rails use.
|
|
37
|
+
*
|
|
38
|
+
* ## The dark overlay, and the hover that lifts it
|
|
39
|
+
*
|
|
40
|
+
* Four busy interiors are four competing subjects, and type over them had
|
|
41
|
+
* nothing to sit on but its own local scrim — the eye could not settle. Every
|
|
42
|
+
* photograph carries a uniform dark overlay so the words lead and the picture
|
|
43
|
+
* supports; hovering a room lifts the overlay off THAT room only, so the reader
|
|
44
|
+
* can look at the place they are about to open.
|
|
45
|
+
*
|
|
46
|
+
* ## Light and dark
|
|
47
|
+
*
|
|
48
|
+
* There is nothing in it to theme. Photographs and their scrims are identical
|
|
49
|
+
* in both, because text over an image needs the same treatment either way —
|
|
50
|
+
* the content is `.dark`-scoped for exactly that. What adapts is the card's
|
|
51
|
+
* EDGE: a soft shadow and hairline on light, a deeper shadow and a light
|
|
52
|
+
* hairline on dark. The edge lives on the outer wrapper, outside the scope.
|
|
53
|
+
*
|
|
54
|
+
* ## No room here is a room that does not serve it
|
|
55
|
+
*
|
|
56
|
+
* The earlier card led with an AI-generated picture of the dish, and a
|
|
57
|
+
* generated image at the head of a block whose whole argument is "we counted
|
|
58
|
+
* real menus" undercut the argument. The rooms are real.
|
|
59
|
+
*/
|
|
60
|
+
/** @deprecated Alias of `MenuLinkProps`; kept so existing imports keep working. */
|
|
61
|
+
type ConceptCompareLinkProps = MenuLinkProps;
|
|
62
|
+
type ConceptCompareFigure = {
|
|
63
|
+
/** Pre-formatted, e.g. "44" or "29–52". */
|
|
64
|
+
value: string;
|
|
65
|
+
label: string;
|
|
66
|
+
/** Draws the value in amber — the spread, which is the number the card is about. */
|
|
67
|
+
accent?: boolean;
|
|
68
|
+
};
|
|
69
|
+
type ConceptCompareLabels = {
|
|
70
|
+
/** Small caps kicker, e.g. "DISH CONCEPT". */
|
|
71
|
+
kind: string;
|
|
72
|
+
/** The badge on the lowest-priced room, e.g. "CHEAPEST". */
|
|
73
|
+
cheapest: string;
|
|
74
|
+
/** The badge on every other room, e.g. "#2". Defaults to `#${rank}`. */
|
|
75
|
+
rank?: (rank: number) => string;
|
|
76
|
+
/** Beside each price, e.g. "12 mentions". Pluralised by the caller. */
|
|
77
|
+
mentions: (count: number) => string;
|
|
78
|
+
/** Accessible name for a room's link, e.g. "Papanași at Casa Maramureșeană". */
|
|
79
|
+
openRoom: (alias: string, venue: string) => string;
|
|
80
|
+
};
|
|
81
|
+
type ConceptCompareProps = {
|
|
82
|
+
concept: MenuConceptPreview;
|
|
83
|
+
labels: ConceptCompareLabels;
|
|
84
|
+
/** One line under the title, e.g. "45 kitchens make it, and they do not agree on the name". */
|
|
85
|
+
lede?: string;
|
|
86
|
+
formatPrice: (amount: number) => string;
|
|
87
|
+
figures?: ConceptCompareFigure[];
|
|
88
|
+
/** Destination per room, keyed by place slug. A room without one is inert. */
|
|
89
|
+
hrefs?: Record<string, string>;
|
|
90
|
+
/** The provenance note in the foot. */
|
|
91
|
+
footnote?: string;
|
|
92
|
+
/** The action in the foot — pass a rendered link or button. */
|
|
93
|
+
actions?: React.ReactNode;
|
|
94
|
+
linkComponent?: MenuLinkComponent;
|
|
95
|
+
className?: string;
|
|
96
|
+
};
|
|
97
|
+
declare function ConceptCompare({ concept, labels, lede, formatPrice, figures, hrefs, footnote, actions, linkComponent: LinkComponent, className, }: ConceptCompareProps): react_jsx_runtime.JSX.Element | null;
|
|
98
|
+
/**
|
|
99
|
+
* The card's own loading state, at the card's footprint.
|
|
100
|
+
*
|
|
101
|
+
* The ground is the card's own dark surface, so the placeholder is already
|
|
102
|
+
* what the photographs will land on and nothing flashes from paper to ink.
|
|
103
|
+
* The phone shape is one room tall with the head above and the foot below;
|
|
104
|
+
* from `lg` it is the four-room row with the head and foot laid over it.
|
|
105
|
+
*/
|
|
106
|
+
declare function ConceptCompareSkeleton({ className }: {
|
|
107
|
+
className?: string;
|
|
108
|
+
}): react_jsx_runtime.JSX.Element;
|
|
109
|
+
|
|
110
|
+
export { ConceptCompare, type ConceptCompareFigure, type ConceptCompareLabels, type ConceptCompareLinkProps, type ConceptCompareProps, ConceptCompareSkeleton };
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { Separator } from '../chunk-WSRWFA6K.js';
|
|
2
|
+
import { ConceptCompareRail } from '../chunk-UDN7UHJW.js';
|
|
3
|
+
import '../chunk-DTXNDLSE.js';
|
|
4
|
+
import { PhotoGround, PHOTO_GROUND } from '../chunk-5RWTOT5Y.js';
|
|
5
|
+
import { Skeleton } from '../chunk-QXHMPJ35.js';
|
|
6
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
7
|
+
import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
|
|
8
|
+
import { ArrowDown, MapPin, Star } from 'lucide-react';
|
|
9
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
10
|
+
|
|
11
|
+
function DefaultLink(_a) {
|
|
12
|
+
var _b = _a, { href } = _b, props = __objRest(_b, ["href"]);
|
|
13
|
+
return /* @__PURE__ */ jsx("a", __spreadValues({ href }, props));
|
|
14
|
+
}
|
|
15
|
+
var MAX_ROOMS = 4;
|
|
16
|
+
var initialOf = (name) => {
|
|
17
|
+
var _a, _b;
|
|
18
|
+
return ((_b = (_a = name.match(new RegExp("\\p{L}", "u"))) == null ? void 0 : _a[0]) != null ? _b : "").toLocaleUpperCase();
|
|
19
|
+
};
|
|
20
|
+
var GROUND = PHOTO_GROUND;
|
|
21
|
+
var PHOTO_OVERLAY_HOVER = "transition-opacity duration-300 group-hover/room:opacity-0 motion-reduce:transition-none";
|
|
22
|
+
var ROOM_SCRIM = "absolute inset-0 bg-[linear-gradient(to_bottom,oklch(0.16_0.012_55_/_0)_0%,oklch(0.16_0.012_55_/_0)_30%,oklch(0.16_0.012_55_/_0.55)_58%,oklch(0.16_0.012_55_/_0.9)_100%)]";
|
|
23
|
+
var HEAD_GLASS = "before:pointer-events-none before:absolute before:inset-0 before:-z-10 before:content-[''] before:backdrop-blur-lg before:[mask-image:linear-gradient(to_bottom,black_35%,transparent_100%)] before:bg-[linear-gradient(to_bottom,oklch(0.16_0.012_55_/_0.8)_0%,oklch(0.16_0.012_55_/_0.6)_35%,oklch(0.16_0.012_55_/_0.22)_75%,oklch(0.16_0.012_55_/_0)_100%)]";
|
|
24
|
+
var COLUMNS = {
|
|
25
|
+
1: "lg:grid-cols-1",
|
|
26
|
+
2: "lg:grid-cols-2",
|
|
27
|
+
3: "lg:grid-cols-3",
|
|
28
|
+
4: "lg:grid-cols-4"
|
|
29
|
+
};
|
|
30
|
+
var DESKTOP_FOOT_CLEARANCE = "lg:pb-[104px]";
|
|
31
|
+
function ConceptCompare({
|
|
32
|
+
concept,
|
|
33
|
+
labels,
|
|
34
|
+
lede,
|
|
35
|
+
formatPrice,
|
|
36
|
+
figures,
|
|
37
|
+
hrefs,
|
|
38
|
+
footnote,
|
|
39
|
+
actions,
|
|
40
|
+
linkComponent: LinkComponent = DefaultLink,
|
|
41
|
+
className
|
|
42
|
+
}) {
|
|
43
|
+
var _a, _b, _c;
|
|
44
|
+
const rooms = ((_a = concept.rows) != null ? _a : []).slice(0, MAX_ROOMS);
|
|
45
|
+
const count = rooms.length;
|
|
46
|
+
if (count === 0) return null;
|
|
47
|
+
const cheapest = rooms.reduce(
|
|
48
|
+
(lowest, room) => lowest === void 0 || room.price < lowest ? room.price : lowest,
|
|
49
|
+
void 0
|
|
50
|
+
);
|
|
51
|
+
const rankOf = (_b = labels.rank) != null ? _b : ((rank) => `#${rank}`);
|
|
52
|
+
const hasFoot = Boolean(footnote || actions);
|
|
53
|
+
return /* @__PURE__ */ jsx(
|
|
54
|
+
"div",
|
|
55
|
+
{
|
|
56
|
+
className: cn(
|
|
57
|
+
/* The edge, OUTSIDE the dark scope — the one thing about this card
|
|
58
|
+
that belongs to the page it sits on. */
|
|
59
|
+
"overflow-hidden rounded-[18px] border border-border shadow-[var(--shadow-card)]",
|
|
60
|
+
className
|
|
61
|
+
),
|
|
62
|
+
children: /* @__PURE__ */ jsxs("div", { className: cn("dark relative isolate flex flex-col text-foreground", GROUND), children: [
|
|
63
|
+
/* @__PURE__ */ jsxs(
|
|
64
|
+
"div",
|
|
65
|
+
{
|
|
66
|
+
className: cn(
|
|
67
|
+
"relative isolate flex flex-col gap-3 px-4 pb-5 pt-4",
|
|
68
|
+
"lg:absolute lg:inset-x-0 lg:top-0 lg:z-10 lg:flex-row lg:items-start lg:justify-between lg:gap-6 lg:px-5 lg:pb-12 lg:pt-5",
|
|
69
|
+
HEAD_GLASS
|
|
70
|
+
),
|
|
71
|
+
children: [
|
|
72
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
73
|
+
/* @__PURE__ */ jsx("span", { className: "block text-[10.5px] font-extrabold uppercase tracking-[0.13em] text-white/70", children: labels.kind }),
|
|
74
|
+
/* @__PURE__ */ jsx("h3", { className: "mt-1 font-serif text-[28px] font-semibold leading-tight tracking-[-0.02em] text-white lg:text-[32px]", children: concept.title }),
|
|
75
|
+
lede && /* @__PURE__ */ jsx("p", { className: "mt-1 text-[13px] leading-snug text-white/75", children: lede })
|
|
76
|
+
] }),
|
|
77
|
+
figures && figures.length > 0 && /* @__PURE__ */ jsx("dl", { className: "flex shrink-0 flex-wrap gap-x-5 gap-y-2 lg:gap-x-6", children: figures.map((figure) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start lg:items-center", children: [
|
|
78
|
+
/* @__PURE__ */ jsx(
|
|
79
|
+
"dd",
|
|
80
|
+
{
|
|
81
|
+
className: cn(
|
|
82
|
+
"text-[22px] font-bold leading-none tabular-nums tracking-[-0.02em]",
|
|
83
|
+
figure.accent ? "text-[oklch(0.82_0.15_85)]" : "text-white"
|
|
84
|
+
),
|
|
85
|
+
children: figure.value
|
|
86
|
+
}
|
|
87
|
+
),
|
|
88
|
+
/* @__PURE__ */ jsx("dt", { className: "mt-1 text-[11px] text-white/65", children: figure.label })
|
|
89
|
+
] }, figure.label)) })
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
),
|
|
93
|
+
/* @__PURE__ */ jsx(
|
|
94
|
+
ConceptCompareRail,
|
|
95
|
+
{
|
|
96
|
+
backdrops: rooms.map((room) => ({
|
|
97
|
+
src: room.place_thumbnail_url,
|
|
98
|
+
initial: initialOf(room.place_name)
|
|
99
|
+
})),
|
|
100
|
+
railClassName: cn(
|
|
101
|
+
"lg:grid lg:gap-px lg:overflow-visible lg:[&>*]:w-auto",
|
|
102
|
+
(_c = COLUMNS[count]) != null ? _c : COLUMNS[4]
|
|
103
|
+
),
|
|
104
|
+
foot: hasFoot ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
105
|
+
footnote && /* @__PURE__ */ jsx("p", { className: "min-w-0 flex-1 text-[12px] leading-relaxed text-white/70", children: footnote }),
|
|
106
|
+
actions && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 [&>*]:w-full lg:[&>*]:w-auto", children: actions })
|
|
107
|
+
] }) : void 0,
|
|
108
|
+
children: rooms.map((room, index) => {
|
|
109
|
+
const href = hrefs == null ? void 0 : hrefs[room.place_slug];
|
|
110
|
+
const isCheapest = room.price === cheapest;
|
|
111
|
+
const roomClass = cn(
|
|
112
|
+
/* Transparent on the phone — the card behind it is the room's
|
|
113
|
+
photograph — with only its scrim and its line. A photograph of
|
|
114
|
+
its own from `lg`, where four stand side by side. */
|
|
115
|
+
"group/room relative isolate flex aspect-[4/3] flex-col justify-end overflow-hidden p-4",
|
|
116
|
+
"lg:aspect-auto lg:min-h-[440px] lg:p-4",
|
|
117
|
+
DESKTOP_FOOT_CLEARANCE
|
|
118
|
+
);
|
|
119
|
+
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
120
|
+
/* @__PURE__ */ jsxs("span", { "aria-hidden": true, className: "absolute inset-0 -z-10", children: [
|
|
121
|
+
/* @__PURE__ */ jsx(
|
|
122
|
+
PhotoGround,
|
|
123
|
+
{
|
|
124
|
+
className: "hidden lg:block",
|
|
125
|
+
photos: [room.place_thumbnail_url],
|
|
126
|
+
initials: initialOf(room.place_name),
|
|
127
|
+
mosaicClassName: "grid-cols-1",
|
|
128
|
+
overlay: true,
|
|
129
|
+
overlayClassName: PHOTO_OVERLAY_HOVER
|
|
130
|
+
}
|
|
131
|
+
),
|
|
132
|
+
/* @__PURE__ */ jsx("span", { className: ROOM_SCRIM })
|
|
133
|
+
] }),
|
|
134
|
+
/* @__PURE__ */ jsxs(
|
|
135
|
+
"span",
|
|
136
|
+
{
|
|
137
|
+
className: cn(
|
|
138
|
+
"inline-flex h-[22px] w-max items-center gap-1 rounded-full px-2 text-[10px] font-extrabold uppercase tracking-[0.08em]",
|
|
139
|
+
isCheapest ? "bg-success text-white" : "bg-white/15 text-white/85 backdrop-blur-[2px]"
|
|
140
|
+
),
|
|
141
|
+
children: [
|
|
142
|
+
isCheapest && /* @__PURE__ */ jsx(ArrowDown, { className: "h-3 w-3 shrink-0", "aria-hidden": true }),
|
|
143
|
+
isCheapest ? labels.cheapest : rankOf(index + 1)
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
),
|
|
147
|
+
/* @__PURE__ */ jsxs("span", { className: "mt-2.5 flex items-center gap-1.5 text-white", children: [
|
|
148
|
+
/* @__PURE__ */ jsx(MapPin, { className: "h-3.5 w-3.5 shrink-0 text-white/70", "aria-hidden": true }),
|
|
149
|
+
/* @__PURE__ */ jsx("b", { className: "min-w-0 flex-1 truncate text-[15px] font-bold leading-tight", children: room.place_name }),
|
|
150
|
+
room.rating !== void 0 && /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1 text-[12px] text-white/70", children: [
|
|
151
|
+
/* @__PURE__ */ jsx(Star, { className: "h-3 w-3 shrink-0", "aria-hidden": true }),
|
|
152
|
+
/* @__PURE__ */ jsx("span", { className: "tabular-nums", children: room.rating })
|
|
153
|
+
] })
|
|
154
|
+
] }),
|
|
155
|
+
room.place_area && /* @__PURE__ */ jsx("span", { className: "mt-0.5 block text-[12px] text-white/70", children: room.place_area }),
|
|
156
|
+
/* @__PURE__ */ jsx("span", { className: "mt-2 block truncate font-serif text-[14px] italic text-white/90", children: room.alias }),
|
|
157
|
+
/* @__PURE__ */ jsx(Separator, { className: "my-2.5 via-white/20" }),
|
|
158
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-baseline gap-2", children: [
|
|
159
|
+
/* @__PURE__ */ jsx(
|
|
160
|
+
"b",
|
|
161
|
+
{
|
|
162
|
+
className: cn(
|
|
163
|
+
"text-[19px] font-bold leading-none tabular-nums tracking-[-0.02em]",
|
|
164
|
+
isCheapest ? "text-success" : "text-white"
|
|
165
|
+
),
|
|
166
|
+
children: formatPrice(room.price)
|
|
167
|
+
}
|
|
168
|
+
),
|
|
169
|
+
room.mentions !== void 0 && room.mentions > 0 && /* @__PURE__ */ jsx("span", { className: "text-[11.5px] text-white/65", children: labels.mentions(room.mentions) })
|
|
170
|
+
] })
|
|
171
|
+
] });
|
|
172
|
+
return href ? /* @__PURE__ */ jsx(
|
|
173
|
+
LinkComponent,
|
|
174
|
+
{
|
|
175
|
+
href,
|
|
176
|
+
"aria-label": labels.openRoom(room.alias, room.place_name),
|
|
177
|
+
className: cn(
|
|
178
|
+
roomClass,
|
|
179
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-white"
|
|
180
|
+
),
|
|
181
|
+
children: body
|
|
182
|
+
},
|
|
183
|
+
room.place_slug
|
|
184
|
+
) : /* @__PURE__ */ jsx("div", { className: roomClass, children: body }, room.place_slug);
|
|
185
|
+
})
|
|
186
|
+
}
|
|
187
|
+
)
|
|
188
|
+
] })
|
|
189
|
+
}
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
function ConceptCompareSkeleton({ className }) {
|
|
193
|
+
return /* @__PURE__ */ jsx(
|
|
194
|
+
"div",
|
|
195
|
+
{
|
|
196
|
+
className: cn(
|
|
197
|
+
"overflow-hidden rounded-[18px] border border-border shadow-[var(--shadow-card)]",
|
|
198
|
+
className
|
|
199
|
+
),
|
|
200
|
+
"aria-hidden": true,
|
|
201
|
+
children: /* @__PURE__ */ jsxs("div", { className: cn("dark relative flex flex-col text-foreground", GROUND), children: [
|
|
202
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 px-4 pb-5 pt-4 lg:absolute lg:inset-x-0 lg:top-0 lg:z-10 lg:flex-row lg:justify-between lg:px-5 lg:pt-5", children: [
|
|
203
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
204
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-2.5 w-[90px] bg-white/15" }),
|
|
205
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-8 w-[160px] bg-white/15" }),
|
|
206
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-3.5 w-[240px] bg-white/15" })
|
|
207
|
+
] }),
|
|
208
|
+
/* @__PURE__ */ jsx("div", { className: "flex gap-5", children: Array.from({ length: 4 }, (_, index) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start gap-1.5 lg:items-center", children: [
|
|
209
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-8 bg-white/15" }),
|
|
210
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-2.5 w-12 bg-white/15" })
|
|
211
|
+
] }, index)) })
|
|
212
|
+
] }),
|
|
213
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 lg:grid-cols-4 lg:gap-px", children: Array.from({ length: 4 }, (_, index) => /* @__PURE__ */ jsxs(
|
|
214
|
+
"div",
|
|
215
|
+
{
|
|
216
|
+
className: cn(
|
|
217
|
+
"flex aspect-[4/3] flex-col justify-end p-4 lg:aspect-auto lg:min-h-[440px] lg:pb-[104px]",
|
|
218
|
+
index > 0 && "hidden lg:flex"
|
|
219
|
+
),
|
|
220
|
+
children: [
|
|
221
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-[22px] w-[72px] rounded-full bg-white/15" }),
|
|
222
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "mt-2.5 h-4 w-[60%] bg-white/15" }),
|
|
223
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-3.5 w-[50%] bg-white/15" }),
|
|
224
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "mt-4 h-5 w-[80px] bg-white/15" })
|
|
225
|
+
]
|
|
226
|
+
},
|
|
227
|
+
index
|
|
228
|
+
)) }),
|
|
229
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 px-4 pb-4 pt-3 lg:absolute lg:inset-x-0 lg:bottom-0 lg:flex-row lg:items-center lg:gap-5 lg:px-5 lg:pb-4 lg:pt-6", children: [
|
|
230
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-full bg-white/15 lg:flex-1" }),
|
|
231
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full rounded-full bg-white/15 lg:w-[120px]" })
|
|
232
|
+
] })
|
|
233
|
+
] })
|
|
234
|
+
}
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export { ConceptCompare, ConceptCompareSkeleton };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ConceptConvergence — many names, one dish, drawn on a dark stage.
|
|
5
|
+
*
|
|
6
|
+
* The explainer's proof: the kitchens' OWN spellings of a dish, each with its
|
|
7
|
+
* price, converging on the one concept they were matched into. Five visibly
|
|
8
|
+
* different strings under one photograph with one price column say what a
|
|
9
|
+
* paragraph about "matching" cannot.
|
|
10
|
+
*
|
|
11
|
+
* Drawn for the explainer's dark stage, and only there: the chips are white
|
|
12
|
+
* on ink, not a family's hue — the tint was doing no work once the stage
|
|
13
|
+
* went dark, and the spellings are the point, not the kitchens' cuisines.
|
|
14
|
+
* The concept card is the venue's real photograph, never the item's (which
|
|
15
|
+
* is generated), on the same ground as every photographed card.
|
|
16
|
+
*/
|
|
17
|
+
type ConceptConvergenceAlias = {
|
|
18
|
+
/** The kitchen's spelling, verbatim. */
|
|
19
|
+
label: string;
|
|
20
|
+
/** Pre-formatted, e.g. "32 lei". */
|
|
21
|
+
price: string;
|
|
22
|
+
};
|
|
23
|
+
type ConceptConvergenceProps = {
|
|
24
|
+
aliases: ConceptConvergenceAlias[];
|
|
25
|
+
concept: {
|
|
26
|
+
title: string;
|
|
27
|
+
/** A room's photograph — venue photography only. */
|
|
28
|
+
photoUrl?: string;
|
|
29
|
+
/** "32 names" — the badge on the card. */
|
|
30
|
+
badge: string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Low, middle and high of the ruler under the diagram, e.g.
|
|
34
|
+
* `["8 lei", "45 kitchens", "44 lei"]`. All three, or none.
|
|
35
|
+
*/
|
|
36
|
+
scale?: [string, string, string];
|
|
37
|
+
className?: string;
|
|
38
|
+
};
|
|
39
|
+
declare function ConceptConvergence({ aliases, concept, scale, className }: ConceptConvergenceProps): react_jsx_runtime.JSX.Element;
|
|
40
|
+
|
|
41
|
+
export { ConceptConvergence, type ConceptConvergenceAlias, type ConceptConvergenceProps };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { PhotoGround } from '../chunk-5RWTOT5Y.js';
|
|
2
|
+
import { Convergence } from '../chunk-MZL7CGCL.js';
|
|
3
|
+
import '../chunk-LEAYBICI.js';
|
|
4
|
+
import { Badge } from '../chunk-UKBNQO6Q.js';
|
|
5
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
6
|
+
import '../chunk-3GWWZKX7.js';
|
|
7
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
8
|
+
|
|
9
|
+
function ConceptConvergence({ aliases, concept, scale, className }) {
|
|
10
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3 text-white", className), children: [
|
|
11
|
+
/* @__PURE__ */ jsx(
|
|
12
|
+
Convergence,
|
|
13
|
+
{
|
|
14
|
+
linesClassName: "text-white/30",
|
|
15
|
+
sources: aliases.map((alias, index) => /* @__PURE__ */ jsxs(
|
|
16
|
+
"span",
|
|
17
|
+
{
|
|
18
|
+
className: "inline-flex h-7 max-w-full items-center gap-1.5 rounded-full bg-white/10 px-2.5 text-[11.5px] text-white",
|
|
19
|
+
children: [
|
|
20
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: alias.label }),
|
|
21
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 tabular-nums text-white/60", children: alias.price })
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
index
|
|
25
|
+
)),
|
|
26
|
+
target: /* @__PURE__ */ jsxs("span", { className: "relative isolate block aspect-[4/5] w-[112px] overflow-hidden rounded-[16px] shadow-[0_8px_24px_oklch(0_0_0/0.35)]", children: [
|
|
27
|
+
/* @__PURE__ */ jsx(
|
|
28
|
+
PhotoGround,
|
|
29
|
+
{
|
|
30
|
+
className: "-z-10",
|
|
31
|
+
mode: "stack",
|
|
32
|
+
photos: [concept.photoUrl],
|
|
33
|
+
initials: concept.title.charAt(0).toLocaleUpperCase(),
|
|
34
|
+
overlay: true,
|
|
35
|
+
loading: "eager"
|
|
36
|
+
}
|
|
37
|
+
),
|
|
38
|
+
/* @__PURE__ */ jsx(Badge, { variant: "overlay", className: "absolute left-2 top-2", children: concept.badge }),
|
|
39
|
+
/* @__PURE__ */ jsx("span", { className: "absolute inset-x-2 bottom-2 block text-balance font-serif text-[17px] font-semibold leading-tight tracking-[-0.02em] [text-shadow:0_1px_8px_oklch(0_0_0/0.5)]", children: concept.title })
|
|
40
|
+
] })
|
|
41
|
+
}
|
|
42
|
+
),
|
|
43
|
+
scale && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-[11px] tabular-nums text-white/60", children: [
|
|
44
|
+
/* @__PURE__ */ jsx("span", { children: scale[0] }),
|
|
45
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "h-px flex-1 bg-white/20" }),
|
|
46
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold text-white", children: scale[1] }),
|
|
47
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "h-px flex-1 bg-white/20" }),
|
|
48
|
+
/* @__PURE__ */ jsx("span", { children: scale[2] })
|
|
49
|
+
] })
|
|
50
|
+
] });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { ConceptConvergence };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type ConvergeLinesProps = {
|
|
5
|
+
/** How many sources the lines leave from. */
|
|
6
|
+
count: number;
|
|
7
|
+
/** Draw the curves in, source by source. Off: drawn already. */
|
|
8
|
+
animate?: boolean;
|
|
9
|
+
className?: string;
|
|
10
|
+
};
|
|
11
|
+
declare function ConvergeLines({ count, animate, className }: ConvergeLinesProps): react_jsx_runtime.JSX.Element;
|
|
12
|
+
type ConvergenceProps = {
|
|
13
|
+
/** The many. One node each; the stack fans slightly so it reads as a spread, not a list. */
|
|
14
|
+
sources: ReactNode[];
|
|
15
|
+
/** The one. */
|
|
16
|
+
target: ReactNode;
|
|
17
|
+
/** The entrance choreography. Off for static reuse; the reader's reduced-motion setting is honoured either way. */
|
|
18
|
+
animate?: boolean;
|
|
19
|
+
/** The curves' colour, e.g. `"text-white/30"` on a dark stage. Defaults to the border. */
|
|
20
|
+
linesClassName?: string;
|
|
21
|
+
className?: string;
|
|
22
|
+
};
|
|
23
|
+
declare function Convergence({ sources, target, animate, linesClassName, className, }: ConvergenceProps): react_jsx_runtime.JSX.Element;
|
|
24
|
+
|
|
25
|
+
export { ConvergeLines, type ConvergeLinesProps, Convergence, type ConvergenceProps };
|