@bearmenu/ui 0.8.6 → 0.8.8
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-637L7XQ3.js → chunk-3TNPSN4D.js} +28 -9
- package/dist/chunk-AHL45DD2.js +145 -0
- package/dist/chunk-IYDH5IU6.js +66 -0
- package/dist/chunk-OPVKL4VS.js +18 -0
- package/dist/components/alert.d.ts +2 -2
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/card.d.ts +2 -2
- package/dist/components/category-deck.js +10 -1
- package/dist/components/command.d.ts +15 -15
- package/dist/components/coverflow.d.ts +11 -3
- package/dist/components/coverflow.js +34 -51
- package/dist/components/drift-rail.d.ts +24 -10
- package/dist/components/drift-rail.js +1 -1
- package/dist/components/event-card.d.ts +8 -0
- package/dist/components/event-card.js +68 -35
- package/dist/components/event-compact-row.d.ts +34 -6
- package/dist/components/event-compact-row.js +120 -38
- package/dist/components/event-day-header.js +3 -1
- package/dist/components/event-day-separator.d.ts +7 -1
- package/dist/components/event-day-separator.js +3 -2
- package/dist/components/event-hub-hero.d.ts +25 -4
- package/dist/components/event-hub-hero.js +89 -19
- package/dist/components/event-list-row.d.ts +19 -6
- package/dist/components/event-list-row.js +78 -34
- package/dist/components/event-types.d.ts +5 -1
- package/dist/components/hour-band.d.ts +38 -40
- package/dist/components/hour-band.js +55 -27
- package/dist/components/hour-group.js +1 -1
- package/dist/components/item.d.ts +2 -2
- package/dist/components/poster-tape.js +1 -1
- package/dist/components/poster-wall.d.ts +3 -3
- package/dist/components/poster-wall.js +73 -17
- package/dist/components/section-header.d.ts +16 -1
- package/dist/components/section-header.js +26 -7
- package/dist/components/snap-rail.d.ts +34 -0
- package/dist/components/snap-rail.js +51 -0
- package/dist/components/spinner.d.ts +2 -2
- package/dist/components/tag.d.ts +2 -2
- package/dist/components/text.d.ts +3 -3
- package/dist/components/timeline-band.d.ts +20 -2
- package/dist/components/timeline-band.js +1 -1
- package/dist/components/timeline-playhead.d.ts +26 -0
- package/dist/components/timeline-playhead.js +25 -0
- package/dist/components/weekend-panel.d.ts +5 -4
- package/dist/components/weekend-panel.js +85 -71
- package/dist/hooks/use-drag-swipe.d.ts +44 -0
- package/dist/hooks/use-drag-swipe.js +2 -0
- package/dist/hooks/use-media-query.d.ts +17 -0
- package/dist/hooks/use-media-query.js +2 -0
- package/package.json +1 -1
- package/src/components/category-deck.tsx +19 -8
- package/src/components/coverflow.test.tsx +28 -1
- package/src/components/coverflow.tsx +37 -43
- package/src/components/drift-rail.tsx +167 -42
- package/src/components/event-card.test.tsx +11 -0
- package/src/components/event-card.tsx +67 -14
- package/src/components/event-compact-row.stories.tsx +30 -0
- package/src/components/event-compact-row.test.tsx +100 -0
- package/src/components/event-compact-row.tsx +166 -40
- package/src/components/event-day-header.tsx +3 -1
- package/src/components/event-day-separator.tsx +8 -1
- package/src/components/event-hub-hero.stories.tsx +30 -0
- package/src/components/event-hub-hero.tsx +102 -30
- package/src/components/event-list-row.stories.tsx +34 -0
- package/src/components/event-list-row.test.tsx +53 -0
- package/src/components/event-list-row.tsx +135 -87
- package/src/components/event-types.ts +5 -1
- package/src/components/hour-band.stories.tsx +28 -5
- package/src/components/hour-band.tsx +90 -70
- package/src/components/poster-wall.test.tsx +28 -0
- package/src/components/poster-wall.tsx +96 -23
- package/src/components/section-header.stories.tsx +24 -0
- package/src/components/section-header.test.tsx +28 -0
- package/src/components/section-header.tsx +45 -7
- package/src/components/snap-rail.stories.tsx +79 -0
- package/src/components/snap-rail.test.tsx +18 -0
- package/src/components/snap-rail.tsx +67 -0
- package/src/components/timeline-band.tsx +52 -12
- package/src/components/timeline-playhead.stories.tsx +30 -0
- package/src/components/timeline-playhead.test.tsx +11 -0
- package/src/components/timeline-playhead.tsx +46 -0
- package/src/components/weekend-panel.test.tsx +43 -0
- package/src/components/weekend-panel.tsx +142 -108
- package/src/hooks/use-drag-swipe.test.tsx +66 -0
- package/src/hooks/use-drag-swipe.ts +105 -0
- package/src/hooks/use-media-query.ts +31 -0
- package/dist/chunk-GPH6L4DX.js +0 -55
|
@@ -2,22 +2,36 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* DriftRail — an infinite horizontal marquee for logos, tag chips or small
|
|
5
|
-
* poster tiles. The caller passes one set of
|
|
6
|
-
* a second, `aria-hidden` copy right after it
|
|
7
|
-
* seamless. Because the loop depends on the duplicate being
|
|
8
|
-
* to the first pass, keep `children` a fixed, ordered list —
|
|
9
|
-
* randomisation.
|
|
5
|
+
* poster tiles that the reader can take hold of. The caller passes one set of
|
|
6
|
+
* children; the component renders a second, `aria-hidden` copy right after it
|
|
7
|
+
* so the loop is seamless. Because the loop depends on the duplicate being
|
|
8
|
+
* pixel-identical to the first pass, keep `children` a fixed, ordered list —
|
|
9
|
+
* no per-render randomisation.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* IT IS A SCROLLER THAT DRIFTS, NOT AN ANIMATION. It used to be a CSS
|
|
12
|
+
* `translateX` keyframe, which is cheap but cannot be grabbed: a finger on it
|
|
13
|
+
* did nothing, and a marquee that ignores the hand on it reads as a broken
|
|
14
|
+
* scroller. Now the rail is a real horizontal scroll container with the
|
|
15
|
+
* scrollbar hidden, and a `requestAnimationFrame` loop advances `scrollLeft`
|
|
16
|
+
* at `width / durationSeconds` per second. When the scroll position passes
|
|
17
|
+
* the first copy it is wrapped back by exactly one copy's width — the two
|
|
18
|
+
* copies are identical, so the jump is invisible — and the same wrap holds
|
|
19
|
+
* while the reader scrolls, in either direction, so there is no end to hit.
|
|
20
|
+
*
|
|
21
|
+
* THE READER WINS. A touch scrolls natively (momentum and all); a mouse drag
|
|
22
|
+
* scrolls the rail by the drag distance; a wheel works because it is a
|
|
23
|
+
* scroller. Any of those stops the drift, and it resumes a few seconds after
|
|
24
|
+
* the last interaction. Hover pauses it too (`pauseOnHover`), and an
|
|
25
|
+
* `IntersectionObserver` stops the loop off-screen so the page is not doing
|
|
26
|
+
* work nobody can see. `prefers-reduced-motion` removes the drift entirely;
|
|
27
|
+
* the rail stays scrollable by hand, which is more than the static strip it
|
|
28
|
+
* used to collapse to.
|
|
16
29
|
*/
|
|
17
30
|
type DriftRailProps = {
|
|
18
31
|
children: React.ReactNode;
|
|
19
32
|
/** Runs the loop right-to-left instead of left-to-right. */
|
|
20
33
|
reverse?: boolean;
|
|
34
|
+
/** Seconds for one full pass of the children. */
|
|
21
35
|
durationSeconds?: number;
|
|
22
36
|
/** Pauses the loop while the pointer hovers the rail. */
|
|
23
37
|
pauseOnHover?: boolean;
|
|
@@ -61,6 +61,14 @@ type EventCardProps = {
|
|
|
61
61
|
liveStatus?: string;
|
|
62
62
|
/** Hide the day/time line — the timeline supplies its own hour heading. */
|
|
63
63
|
hideWhen?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Already over — dims the poster, mutes the title and shows the `endedLabel`
|
|
66
|
+
* chip. Never row-level opacity, which composites the text below AA. Same
|
|
67
|
+
* contract as `EventCompactRow`.
|
|
68
|
+
*/
|
|
69
|
+
isEnded?: boolean;
|
|
70
|
+
/** Chip text for an ended event, e.g. "Ended". Required to render the chip. */
|
|
71
|
+
endedLabel?: string;
|
|
64
72
|
/** Overrides the day label when the card appears outside its own day section. */
|
|
65
73
|
dayLabel?: string;
|
|
66
74
|
/** Append the entry fee to the meta line. Off by default, matching the design's base card. */
|
|
@@ -25,6 +25,8 @@ var EventCard = memo(function EventCard2({
|
|
|
25
25
|
tags,
|
|
26
26
|
liveStatus,
|
|
27
27
|
hideWhen,
|
|
28
|
+
isEnded,
|
|
29
|
+
endedLabel,
|
|
28
30
|
dayLabel,
|
|
29
31
|
showPrice,
|
|
30
32
|
href,
|
|
@@ -36,6 +38,8 @@ var EventCard = memo(function EventCard2({
|
|
|
36
38
|
}) {
|
|
37
39
|
var _a;
|
|
38
40
|
const [imgError, setImgError] = useState(false);
|
|
41
|
+
const showEnded = isEnded && !!endedLabel;
|
|
42
|
+
const time = hideWhen ? "" : formatters.time(event.starts_at);
|
|
39
43
|
const fee = resolveEventEntryFee(event);
|
|
40
44
|
const showPoster = !!event.poster_url && !imgError;
|
|
41
45
|
const venue = (_a = event.place_name) != null ? _a : event.location;
|
|
@@ -45,6 +49,7 @@ var EventCard = memo(function EventCard2({
|
|
|
45
49
|
{
|
|
46
50
|
className: cn(
|
|
47
51
|
"relative overflow-hidden rounded-xl bg-muted",
|
|
52
|
+
isEnded && "opacity-45",
|
|
48
53
|
posterAspect === "3/4" ? "aspect-[3/4]" : posterAspect === "4/5" ? "aspect-[4/5]" : "aspect-[4/3]"
|
|
49
54
|
),
|
|
50
55
|
children: [
|
|
@@ -65,10 +70,19 @@ var EventCard = memo(function EventCard2({
|
|
|
65
70
|
) : fallback,
|
|
66
71
|
/* @__PURE__ */ jsxs("div", { className: "absolute inset-x-2 top-2 flex items-start justify-between gap-2", children: [
|
|
67
72
|
badge ? /* @__PURE__ */ jsx("span", { className: cn(PILL_BASE, "bg-black/55 text-white"), children: badge }) : /* @__PURE__ */ jsx("span", {}),
|
|
68
|
-
fee.kind === "free" && /* @__PURE__ */ jsxs(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
fee.kind === "free" && /* @__PURE__ */ jsxs(
|
|
74
|
+
"span",
|
|
75
|
+
{
|
|
76
|
+
className: cn(
|
|
77
|
+
PILL_BASE,
|
|
78
|
+
"bg-success font-bold text-success-foreground"
|
|
79
|
+
),
|
|
80
|
+
children: [
|
|
81
|
+
/* @__PURE__ */ jsx(Gift, { className: "h-3 w-3", "aria-hidden": true }),
|
|
82
|
+
labels.free
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
)
|
|
72
86
|
] }),
|
|
73
87
|
tagLabel && /* @__PURE__ */ jsx("div", { className: "absolute inset-x-2 bottom-2 flex gap-1", children: /* @__PURE__ */ jsx("span", { className: cn(PILL_BASE, "bg-black/55 text-white"), children: tagLabel }) })
|
|
74
88
|
]
|
|
@@ -79,7 +93,8 @@ var EventCard = memo(function EventCard2({
|
|
|
79
93
|
{
|
|
80
94
|
className: cn(
|
|
81
95
|
"mt-2.5 leading-[1.35]",
|
|
82
|
-
emphasis ? "text-lg font-bold tracking-[-0.02em]" : "text-sm font-semibold"
|
|
96
|
+
emphasis ? "text-lg font-bold tracking-[-0.02em]" : "text-sm font-semibold",
|
|
97
|
+
isEnded && "text-muted-foreground"
|
|
83
98
|
),
|
|
84
99
|
children: event.title
|
|
85
100
|
}
|
|
@@ -90,8 +105,10 @@ var EventCard = memo(function EventCard2({
|
|
|
90
105
|
] }),
|
|
91
106
|
!hideWhen && /* @__PURE__ */ jsxs("div", { className: "mt-[3px] flex items-center gap-1.5 text-xs text-muted-foreground", children: [
|
|
92
107
|
/* @__PURE__ */ jsx("span", { children: dayLabel != null ? dayLabel : formatters.day(event.starts_at) }),
|
|
93
|
-
/* @__PURE__ */
|
|
94
|
-
|
|
108
|
+
time && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
109
|
+
/* @__PURE__ */ jsx("span", { className: "text-border", "aria-hidden": true, children: "\xB7" }),
|
|
110
|
+
/* @__PURE__ */ jsx("span", { children: time })
|
|
111
|
+
] }),
|
|
95
112
|
showPrice && fee.kind === "paid" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
96
113
|
/* @__PURE__ */ jsx("span", { className: "text-border", "aria-hidden": true, children: "\xB7" }),
|
|
97
114
|
/* @__PURE__ */ jsx("span", { children: formatters.price(fee.amountRon) })
|
|
@@ -101,7 +118,8 @@ var EventCard = memo(function EventCard2({
|
|
|
101
118
|
liveStatus && /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-1.5 text-xs font-bold text-success", children: [
|
|
102
119
|
/* @__PURE__ */ jsx(Radio, { className: "h-3 w-3 shrink-0", "aria-hidden": true }),
|
|
103
120
|
liveStatus
|
|
104
|
-
] })
|
|
121
|
+
] }),
|
|
122
|
+
showEnded && /* @__PURE__ */ jsx("div", { className: "mt-1.5", children: /* @__PURE__ */ jsx(Tag, { size: "sm", variant: "default", className: "font-extrabold", children: endedLabel }) })
|
|
105
123
|
] });
|
|
106
124
|
const rootClasses = cn(
|
|
107
125
|
"flex min-w-0 flex-col text-left",
|
|
@@ -120,7 +138,15 @@ var EventCard = memo(function EventCard2({
|
|
|
120
138
|
);
|
|
121
139
|
}
|
|
122
140
|
if (onClick) {
|
|
123
|
-
return /* @__PURE__ */ jsx(
|
|
141
|
+
return /* @__PURE__ */ jsx(
|
|
142
|
+
"button",
|
|
143
|
+
{
|
|
144
|
+
type: "button",
|
|
145
|
+
className: rootClasses,
|
|
146
|
+
onClick: (e) => onClick(event, e),
|
|
147
|
+
children: body
|
|
148
|
+
}
|
|
149
|
+
);
|
|
124
150
|
}
|
|
125
151
|
return /* @__PURE__ */ jsx("div", { className: rootClasses, children: body });
|
|
126
152
|
});
|
|
@@ -130,32 +156,39 @@ function EventCardSkeleton({
|
|
|
130
156
|
hideWhen,
|
|
131
157
|
className
|
|
132
158
|
}) {
|
|
133
|
-
return /* @__PURE__ */ jsxs(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
+
return /* @__PURE__ */ jsxs(
|
|
160
|
+
"div",
|
|
161
|
+
{
|
|
162
|
+
"aria-hidden": "true",
|
|
163
|
+
className: cn("flex min-w-0 flex-col text-left", className),
|
|
164
|
+
children: [
|
|
165
|
+
/* @__PURE__ */ jsx(
|
|
166
|
+
Skeleton,
|
|
167
|
+
{
|
|
168
|
+
className: cn(
|
|
169
|
+
posterAspect === "3/4" ? "aspect-[3/4]" : posterAspect === "4/5" ? "aspect-[4/5]" : "aspect-[4/3]"
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
),
|
|
173
|
+
emphasis ? /* @__PURE__ */ jsxs("div", { className: "mt-2.5 space-y-2", children: [
|
|
174
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-full" }),
|
|
175
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-full" }),
|
|
176
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-1/2" })
|
|
177
|
+
] }) : /* @__PURE__ */ jsxs("div", { className: "mt-2.5 space-y-1.5", children: [
|
|
178
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-full" }),
|
|
179
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-2/3" })
|
|
180
|
+
] }),
|
|
181
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-0.5 flex items-center gap-1", children: [
|
|
182
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-3 shrink-0 rounded-full" }),
|
|
183
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" })
|
|
184
|
+
] }),
|
|
185
|
+
!hideWhen && /* @__PURE__ */ jsxs("div", { className: "mt-[3px] flex items-center gap-1.5", children: [
|
|
186
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-16" }),
|
|
187
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-10" })
|
|
188
|
+
] })
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
);
|
|
159
192
|
}
|
|
160
193
|
|
|
161
194
|
export { EventCard, EventCardSkeleton };
|
|
@@ -14,10 +14,25 @@ import { EventPreview, EventCardLabels, EventFormatters } from './event-types.js
|
|
|
14
14
|
*
|
|
15
15
|
* THIS ROW DOES NOT DRAW DIVIDERS; ITS CONTAINER DOES. `<HourGroup>` already
|
|
16
16
|
* draws the rule under the hour heading, so a row-level top separator here
|
|
17
|
-
* doubled it directly beneath every hour
|
|
18
|
-
* `<EventListRowWide>` are different:
|
|
19
|
-
* other rule around them, so their own top
|
|
20
|
-
* do not carry this rule over to them.
|
|
17
|
+
* doubled it directly beneath every hour; `<HourBand>` rules between its rows
|
|
18
|
+
* with a wrapper. `<EventListRow>` and `<EventListRowWide>` are different:
|
|
19
|
+
* they stack in a plain list with no other rule around them, so their own top
|
|
20
|
+
* separator is the only one there — do not carry this rule over to them.
|
|
21
|
+
*
|
|
22
|
+
* STATE LIVES ON THE META LINE. `isLive` adds the on-air chip and `isEnded`
|
|
23
|
+
* the ended chip beside the time and venue, so a row's state is read in the
|
|
24
|
+
* same glance as its facts. Ended dims the POSTER and moves the title to
|
|
25
|
+
* `--muted-foreground` — never row-level opacity, which composites the text
|
|
26
|
+
* below AA.
|
|
27
|
+
*
|
|
28
|
+
* THE PRICE IS ON THE LAST ROW, right-aligned beside the tags, not on the
|
|
29
|
+
* title line. Two bold things on one line compete — the title and a price
|
|
30
|
+
* both in 700 read as one shout — and the title is the thing the reader is
|
|
31
|
+
* scanning for. `showPrice` renders it (free in `--success`, paid in
|
|
32
|
+
* `--foreground`); without it the row keeps its trailing free pill for the
|
|
33
|
+
* hub's venue block. This is ONE row for the timeline and the list view:
|
|
34
|
+
* the list used to have its own, and the reader met two anatomies for the
|
|
35
|
+
* same object.
|
|
21
36
|
*
|
|
22
37
|
* Same contract as the rest: DS-owned view model, injected labels/formatters,
|
|
23
38
|
* plain `<img>`, anchor whenever `href` is given.
|
|
@@ -32,7 +47,8 @@ type EventCompactRowProps = {
|
|
|
32
47
|
event: EventPreview;
|
|
33
48
|
labels: EventCardLabels;
|
|
34
49
|
formatters: EventFormatters;
|
|
35
|
-
/** Drops the leading time from the sub line.
|
|
50
|
+
/** Drops the leading time from the sub line. An empty `formatters.time`
|
|
51
|
+
* result (hour unknown) drops it the same way, without the prop. */
|
|
36
52
|
hideTime?: boolean;
|
|
37
53
|
/**
|
|
38
54
|
* Replaces the default "time · venue" sub-line entirely. For surfaces where
|
|
@@ -50,6 +66,18 @@ type EventCompactRowProps = {
|
|
|
50
66
|
* rather than truncate, so a chip's own text is never cut mid-word. Cap
|
|
51
67
|
* the count at the call site — this row does not. */
|
|
52
68
|
tags?: string[];
|
|
69
|
+
/** Currently running — adds the `labels.liveNow` chip to the meta line. */
|
|
70
|
+
isLive?: boolean;
|
|
71
|
+
/** Already over — dims the poster, mutes the title, adds the `endedLabel` chip. */
|
|
72
|
+
isEnded?: boolean;
|
|
73
|
+
/** Chip text for an ended event, e.g. "Ended". Required to render the chip. */
|
|
74
|
+
endedLabel?: string;
|
|
75
|
+
/**
|
|
76
|
+
* Prints the fee on the meta line — `labels.free` in `--success`, a paid
|
|
77
|
+
* amount via `formatters.price` — instead of the trailing free pill. An
|
|
78
|
+
* unknown fee prints nothing, same as every sibling row.
|
|
79
|
+
*/
|
|
80
|
+
showPrice?: boolean;
|
|
53
81
|
size?: "sm" | "default";
|
|
54
82
|
href?: string;
|
|
55
83
|
linkComponent?: React.ComponentType<EventCompactRowLinkProps>;
|
|
@@ -67,6 +95,6 @@ type EventCompactRowSkeletonProps = {
|
|
|
67
95
|
className?: string;
|
|
68
96
|
};
|
|
69
97
|
/** Mirrors `<EventCompactRow>`'s geometry exactly so nothing shifts when data lands. */
|
|
70
|
-
declare function EventCompactRowSkeleton({ size, className }: EventCompactRowSkeletonProps): react_jsx_runtime.JSX.Element;
|
|
98
|
+
declare function EventCompactRowSkeleton({ size, className, }: EventCompactRowSkeletonProps): react_jsx_runtime.JSX.Element;
|
|
71
99
|
|
|
72
100
|
export { EventCompactRow, type EventCompactRowLinkProps, type EventCompactRowProps, EventCompactRowSkeleton, type EventCompactRowSkeletonProps };
|
|
@@ -6,6 +6,7 @@ import { Skeleton } from '../chunk-QXHMPJ35.js';
|
|
|
6
6
|
import { cn } from '../chunk-FEK5XGZW.js';
|
|
7
7
|
import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
|
|
8
8
|
import { memo, useState } from 'react';
|
|
9
|
+
import { Radio } from 'lucide-react';
|
|
9
10
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
10
11
|
|
|
11
12
|
function DefaultLink(_a) {
|
|
@@ -19,6 +20,10 @@ var EventCompactRow = memo(function EventCompactRow2({
|
|
|
19
20
|
hideTime,
|
|
20
21
|
subtitle,
|
|
21
22
|
tags,
|
|
23
|
+
isLive,
|
|
24
|
+
isEnded,
|
|
25
|
+
endedLabel,
|
|
26
|
+
showPrice,
|
|
22
27
|
size = "default",
|
|
23
28
|
href,
|
|
24
29
|
linkComponent: LinkComponent = DefaultLink,
|
|
@@ -33,50 +38,108 @@ var EventCompactRow = memo(function EventCompactRow2({
|
|
|
33
38
|
const fee = resolveEventEntryFee(event);
|
|
34
39
|
const showPoster = !!event.poster_url && !imgError;
|
|
35
40
|
const venue = (_a = event.place_name) != null ? _a : event.location;
|
|
41
|
+
const time = formatters.time(event.starts_at);
|
|
42
|
+
const priceText = fee.kind === "free" ? labels.free : fee.kind === "paid" ? formatters.price(fee.amountRon) : void 0;
|
|
43
|
+
const showEnded = isEnded && !!endedLabel;
|
|
44
|
+
const separator = /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "text-border", children: "\xB7" });
|
|
36
45
|
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
37
|
-
/* @__PURE__ */ jsx(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
/* @__PURE__ */ jsx(
|
|
47
|
+
"div",
|
|
48
|
+
{
|
|
49
|
+
className: cn(
|
|
50
|
+
"relative aspect-[4/5] w-16 shrink-0 overflow-hidden rounded-[10px] bg-muted",
|
|
51
|
+
isEnded && "opacity-45"
|
|
52
|
+
),
|
|
53
|
+
children: showPoster ? (
|
|
54
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
55
|
+
/* @__PURE__ */ jsx(
|
|
56
|
+
"img",
|
|
57
|
+
{
|
|
58
|
+
src: event.poster_url,
|
|
59
|
+
alt: "",
|
|
60
|
+
loading: priority ? "eager" : "lazy",
|
|
61
|
+
decoding: "async",
|
|
62
|
+
className: "h-full w-full object-cover",
|
|
63
|
+
onError: () => setImgError(true)
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
) : (
|
|
67
|
+
// A bare `bg-muted` rectangle was survivable at 34px. At 58x72 beside
|
|
68
|
+
// real posters it reads as a broken image rather than an absent one —
|
|
69
|
+
// so this row finally joins every sibling in the family in having a
|
|
70
|
+
// designed fallback.
|
|
71
|
+
fallback
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
),
|
|
57
75
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
58
76
|
/* @__PURE__ */ jsx(
|
|
59
77
|
"div",
|
|
60
78
|
{
|
|
61
79
|
className: cn(
|
|
62
|
-
"
|
|
80
|
+
"leading-[1.3]",
|
|
63
81
|
"transition-colors duration-150 motion-reduce:transition-none",
|
|
64
|
-
isSm ? "text-[13.5px]" : "text-[13px]",
|
|
82
|
+
isSm ? "text-[14.5px] lg:text-[13.5px]" : "text-[14px] lg:text-[13px]",
|
|
83
|
+
isEnded ? "font-semibold text-muted-foreground" : "font-bold text-foreground lg:font-semibold",
|
|
65
84
|
(href || onClick) && "group-hover:text-primary"
|
|
66
85
|
),
|
|
67
86
|
children: event.title
|
|
68
87
|
}
|
|
69
88
|
),
|
|
70
|
-
/* @__PURE__ */
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
89
|
+
/* @__PURE__ */ jsxs(
|
|
90
|
+
"div",
|
|
91
|
+
{
|
|
92
|
+
className: cn(
|
|
93
|
+
"mt-1 flex items-center gap-1.5 text-[11.5px] text-muted-foreground",
|
|
94
|
+
isLive || showEnded ? "flex-wrap" : "truncate"
|
|
95
|
+
),
|
|
96
|
+
children: [
|
|
97
|
+
subtitle ? subtitle : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
98
|
+
!hideTime && time && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
99
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono tabular-nums", children: time }),
|
|
100
|
+
separator
|
|
101
|
+
] }),
|
|
102
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: venue })
|
|
103
|
+
] }),
|
|
104
|
+
isLive && /* @__PURE__ */ jsxs(
|
|
105
|
+
Tag,
|
|
106
|
+
{
|
|
107
|
+
size: "sm",
|
|
108
|
+
variant: "success",
|
|
109
|
+
className: "shrink-0 whitespace-nowrap font-extrabold",
|
|
110
|
+
children: [
|
|
111
|
+
/* @__PURE__ */ jsx(Radio, { className: "h-2.5 w-2.5", "aria-hidden": true }),
|
|
112
|
+
labels.liveNow
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
),
|
|
116
|
+
showEnded && /* @__PURE__ */ jsx(
|
|
117
|
+
Tag,
|
|
118
|
+
{
|
|
119
|
+
size: "sm",
|
|
120
|
+
variant: "default",
|
|
121
|
+
className: "shrink-0 whitespace-nowrap font-extrabold",
|
|
122
|
+
children: endedLabel
|
|
123
|
+
}
|
|
124
|
+
)
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
),
|
|
128
|
+
(tags && tags.length > 0 || showPrice && priceText) && /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex items-center gap-2", children: [
|
|
129
|
+
tags && tags.length > 0 ? /* @__PURE__ */ jsx(TagGroup, { className: "min-w-0 flex-1", children: tags.map((tag) => /* @__PURE__ */ jsx(Tag, { size: "sm", variant: "quiet", children: tag }, tag)) }) : /* @__PURE__ */ jsx("span", { className: "flex-1" }),
|
|
130
|
+
showPrice && priceText && /* @__PURE__ */ jsx(
|
|
131
|
+
"span",
|
|
132
|
+
{
|
|
133
|
+
className: cn(
|
|
134
|
+
"shrink-0 text-[13px] tabular-nums",
|
|
135
|
+
fee.kind === "free" ? "font-semibold text-success" : "font-bold text-foreground"
|
|
136
|
+
),
|
|
137
|
+
children: priceText
|
|
138
|
+
}
|
|
139
|
+
)
|
|
140
|
+
] })
|
|
78
141
|
] }),
|
|
79
|
-
fee.kind === "free" && /* @__PURE__ */ jsx(
|
|
142
|
+
!showPrice && fee.kind === "free" && /* @__PURE__ */ jsx(
|
|
80
143
|
"span",
|
|
81
144
|
{
|
|
82
145
|
className: cn(
|
|
@@ -88,7 +151,7 @@ var EventCompactRow = memo(function EventCompactRow2({
|
|
|
88
151
|
)
|
|
89
152
|
] });
|
|
90
153
|
const rootClasses = cn(
|
|
91
|
-
"group relative -mx-2.5 flex w-full items-start gap-
|
|
154
|
+
"group relative -mx-2.5 flex w-full items-start gap-3 rounded-lg px-2.5 py-[11px] text-left lg:gap-[11px] lg:py-2",
|
|
92
155
|
"transition-colors duration-150 motion-reduce:transition-none",
|
|
93
156
|
(href || onClick) && "cursor-pointer hover:bg-foreground/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
94
157
|
className
|
|
@@ -105,25 +168,44 @@ var EventCompactRow = memo(function EventCompactRow2({
|
|
|
105
168
|
);
|
|
106
169
|
}
|
|
107
170
|
if (onClick) {
|
|
108
|
-
return /* @__PURE__ */ jsx(
|
|
171
|
+
return /* @__PURE__ */ jsx(
|
|
172
|
+
"button",
|
|
173
|
+
{
|
|
174
|
+
type: "button",
|
|
175
|
+
className: rootClasses,
|
|
176
|
+
onClick: (e) => onClick(event, e),
|
|
177
|
+
children: body
|
|
178
|
+
}
|
|
179
|
+
);
|
|
109
180
|
}
|
|
110
181
|
return /* @__PURE__ */ jsx("div", { className: rootClasses, children: body });
|
|
111
182
|
});
|
|
112
|
-
function EventCompactRowSkeleton({
|
|
183
|
+
function EventCompactRowSkeleton({
|
|
184
|
+
size = "default",
|
|
185
|
+
className
|
|
186
|
+
}) {
|
|
113
187
|
const isSm = size === "sm";
|
|
114
188
|
return /* @__PURE__ */ jsxs(
|
|
115
189
|
"div",
|
|
116
190
|
{
|
|
117
191
|
"aria-hidden": "true",
|
|
118
192
|
className: cn(
|
|
119
|
-
"relative -mx-2.5 flex w-full items-start gap-
|
|
193
|
+
"relative -mx-2.5 flex w-full items-start gap-3 rounded-lg px-2.5 py-[11px] text-left lg:gap-[11px] lg:py-2",
|
|
120
194
|
className
|
|
121
195
|
),
|
|
122
196
|
children: [
|
|
123
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "aspect-[4/5] w-16 shrink-0 rounded-[
|
|
197
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "aspect-[4/5] w-16 shrink-0 rounded-[10px]" }),
|
|
124
198
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
125
|
-
/* @__PURE__ */ jsx(
|
|
126
|
-
|
|
199
|
+
/* @__PURE__ */ jsx(
|
|
200
|
+
Skeleton,
|
|
201
|
+
{
|
|
202
|
+
className: cn(
|
|
203
|
+
isSm ? "h-[14.5px] lg:h-[13.5px]" : "h-[14px] lg:h-[13px]",
|
|
204
|
+
"w-3/5"
|
|
205
|
+
)
|
|
206
|
+
}
|
|
207
|
+
),
|
|
208
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "mt-1 h-[11.5px] w-1/3" })
|
|
127
209
|
] })
|
|
128
210
|
]
|
|
129
211
|
}
|
|
@@ -27,7 +27,9 @@ function EventDayHeader({
|
|
|
27
27
|
{
|
|
28
28
|
className: cn(
|
|
29
29
|
"font-black leading-[0.82] tracking-[-0.05em] tabular-nums",
|
|
30
|
-
|
|
30
|
+
// `sm` is the phone scale: 30px, the design's app day head. 40px
|
|
31
|
+
// was a page-scale number that took a third of a 390px row.
|
|
32
|
+
large ? "text-[58px]" : "text-[30px] leading-[0.86]"
|
|
31
33
|
),
|
|
32
34
|
children: dayNumber
|
|
33
35
|
}
|
|
@@ -25,6 +25,12 @@ import { ElementType } from 'react';
|
|
|
25
25
|
* `<Separator>` above the label), not the weight.
|
|
26
26
|
*/
|
|
27
27
|
type EventDaySeparatorProps = {
|
|
28
|
+
/**
|
|
29
|
+
* `always` (default) draws the trailing rule at every width. `lg` drops it
|
|
30
|
+
* below `lg`, where the list is an app sheet whose day heads are bold
|
|
31
|
+
* labels alone — the rows below rule themselves — and keeps it from `lg`.
|
|
32
|
+
*/
|
|
33
|
+
rule?: "always" | "lg";
|
|
28
34
|
label: string;
|
|
29
35
|
count?: string;
|
|
30
36
|
size?: "sm" | "default";
|
|
@@ -32,7 +38,7 @@ type EventDaySeparatorProps = {
|
|
|
32
38
|
as?: ElementType;
|
|
33
39
|
className?: string;
|
|
34
40
|
};
|
|
35
|
-
declare function EventDaySeparator({ label, count, size, as: Tag, className, }: EventDaySeparatorProps): react_jsx_runtime.JSX.Element;
|
|
41
|
+
declare function EventDaySeparator({ label, count, size, as: Tag, className, rule, }: EventDaySeparatorProps): react_jsx_runtime.JSX.Element;
|
|
36
42
|
type EventDaySeparatorSkeletonProps = {
|
|
37
43
|
/** Matches `EventDaySeparatorProps["size"]`. */
|
|
38
44
|
size?: "sm" | "default";
|
|
@@ -9,7 +9,8 @@ function EventDaySeparator({
|
|
|
9
9
|
count,
|
|
10
10
|
size = "default",
|
|
11
11
|
as: Tag = "h2",
|
|
12
|
-
className
|
|
12
|
+
className,
|
|
13
|
+
rule = "always"
|
|
13
14
|
}) {
|
|
14
15
|
return /* @__PURE__ */ jsxs(
|
|
15
16
|
"div",
|
|
@@ -22,7 +23,7 @@ function EventDaySeparator({
|
|
|
22
23
|
children: [
|
|
23
24
|
/* @__PURE__ */ jsx(Tag, { className: cn("font-semibold", size === "sm" ? "text-[13px]" : "text-sm"), children: label }),
|
|
24
25
|
count && /* @__PURE__ */ jsx("span", { className: cn("text-muted-foreground", size === "sm" ? "text-[11.5px]" : "text-xs"), children: count }),
|
|
25
|
-
/* @__PURE__ */ jsx(Separator, { className: "flex-1" })
|
|
26
|
+
/* @__PURE__ */ jsx(Separator, { className: cn("flex-1", rule === "lg" && "hidden lg:block") })
|
|
26
27
|
]
|
|
27
28
|
}
|
|
28
29
|
);
|
|
@@ -2,9 +2,20 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* EventHubHero — the hub's opening block: an eyebrow, a big
|
|
6
|
-
* intro
|
|
7
|
-
* stack, in the source design) on the right.
|
|
5
|
+
* EventHubHero — the hub's opening block. On desktop: an eyebrow, a big
|
|
6
|
+
* headline, an intro paragraph and a stats row on the left; an arbitrary slot
|
|
7
|
+
* (the poster stack, in the source design) on the right.
|
|
8
|
+
*
|
|
9
|
+
* BELOW `lg` IT IS A MASTHEAD, NOT A HERO. One headline line, the eyebrow
|
|
10
|
+
* demoted to a sub-line beneath it, no intro, and the figures as a swipeable
|
|
11
|
+
* rail of chips that bleeds to the screen edge. The first real content lands
|
|
12
|
+
* roughly 250px sooner than under the web-shaped hero — on a phone the page
|
|
13
|
+
* should show, not narrate. Same markup at every width; only the classes
|
|
14
|
+
* change, so the copy is authored once.
|
|
15
|
+
*
|
|
16
|
+
* A stat with `tone: "live"` is the one that is happening right now: its
|
|
17
|
+
* chip takes a `--success` border and value, the same live colour every
|
|
18
|
+
* events surface uses.
|
|
8
19
|
*
|
|
9
20
|
* All copy and stat values arrive pre-formatted — the DS holds no `Intl`
|
|
10
21
|
* locale and does not format numbers.
|
|
@@ -12,6 +23,8 @@ import * as React from 'react';
|
|
|
12
23
|
type EventHubHeroStat = {
|
|
13
24
|
value: string;
|
|
14
25
|
label: string;
|
|
26
|
+
/** `live` marks the figure that is happening right now. */
|
|
27
|
+
tone?: "default" | "live";
|
|
15
28
|
};
|
|
16
29
|
type EventHubHeroProps = {
|
|
17
30
|
/** Small caps-style label above the title, e.g. "Updated today". */
|
|
@@ -19,11 +32,19 @@ type EventHubHeroProps = {
|
|
|
19
32
|
title: string;
|
|
20
33
|
intro: string;
|
|
21
34
|
stats: EventHubHeroStat[];
|
|
35
|
+
/**
|
|
36
|
+
* Accessible name for the stats rail, e.g. "Key figures". When given, the
|
|
37
|
+
* rail is a named, focusable region so a keyboard can reach chips clipped
|
|
38
|
+
* by the phone's edge. Optional so existing consumers keep compiling — but
|
|
39
|
+
* pass it: without a name the rail cannot be focusable, and a phone reader
|
|
40
|
+
* on a keyboard cannot reach the last figures.
|
|
41
|
+
*/
|
|
42
|
+
statsLabel?: string;
|
|
22
43
|
/** The right-column slot — the poster stack in the source design. */
|
|
23
44
|
aside?: React.ReactNode;
|
|
24
45
|
className?: string;
|
|
25
46
|
};
|
|
26
|
-
declare function EventHubHero({ eyebrow, title, intro, stats, aside, className }: EventHubHeroProps): react_jsx_runtime.JSX.Element;
|
|
47
|
+
declare function EventHubHero({ eyebrow, title, intro, stats, statsLabel, aside, className, }: EventHubHeroProps): react_jsx_runtime.JSX.Element;
|
|
27
48
|
type EventHubHeroSkeletonProps = {
|
|
28
49
|
/** The right-column slot, e.g. a `PosterStack`-shaped placeholder. Mirrors `aside` on the real component. */
|
|
29
50
|
aside?: React.ReactNode;
|