@bearmenu/ui 0.8.51 → 0.8.53
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-GIJGVFGC.js +177 -0
- package/dist/chunk-H4ORZT2D.js +14 -0
- package/dist/chunk-RKNPPYRU.js +86 -0
- package/dist/{chunk-S5GDARLW.js → chunk-WY2FP76J.js} +28 -5
- package/dist/components/category-deck.d.ts +6 -1
- package/dist/components/category-deck.js +39 -35
- package/dist/components/event-card.d.ts +7 -0
- package/dist/components/event-card.js +9 -0
- package/dist/components/event-compact-row.d.ts +6 -0
- package/dist/components/event-compact-row.js +5 -3
- package/dist/components/event-hub-hero.d.ts +5 -0
- package/dist/components/event-hub-hero.js +14 -3
- package/dist/components/event-list-row-wide.d.ts +6 -0
- package/dist/components/event-list-row-wide.js +5 -3
- package/dist/components/event-tonight-strip.d.ts +3 -1
- package/dist/components/event-tonight-strip.js +3 -2
- package/dist/components/facet-group.d.ts +9 -2
- package/dist/components/facet-group.js +108 -10
- package/dist/components/featured-rail-item.d.ts +3 -1
- package/dist/components/featured-rail-item.js +3 -1
- package/dist/components/filter-option-chip.d.ts +15 -0
- package/dist/components/filter-option-chip.js +3 -0
- package/dist/components/filter-option-group.d.ts +37 -0
- package/dist/components/filter-option-group.js +10 -0
- package/dist/components/filter-panel-footer.d.ts +15 -0
- package/dist/components/filter-panel-footer.js +63 -0
- package/dist/components/kitchen-dossier.d.ts +7 -1
- package/dist/components/kitchen-dossier.js +2 -1
- package/dist/components/menu-hub-hero.d.ts +7 -1
- package/dist/components/menu-hub-hero.js +2 -0
- package/dist/components/place-card.d.ts +7 -0
- package/dist/components/place-card.js +11 -3
- package/dist/components/poster-stack.d.ts +2 -0
- package/dist/components/poster-stack.js +2 -1
- package/dist/components/section-header.d.ts +6 -1
- package/dist/components/section-header.js +4 -2
- package/dist/components/timeline-day.js +1 -1
- package/dist/components/timeline-hour.d.ts +13 -1
- package/dist/components/timeline-hour.js +1 -1
- package/package.json +6 -6
- package/src/components/category-deck.tsx +11 -0
- package/src/components/event-card.test.tsx +6 -0
- package/src/components/event-card.tsx +17 -0
- package/src/components/event-compact-row.tsx +34 -24
- package/src/components/event-hub-hero.tsx +15 -1
- package/src/components/event-list-row-wide.tsx +25 -15
- package/src/components/event-tonight-strip.test.tsx +12 -0
- package/src/components/event-tonight-strip.tsx +8 -1
- package/src/components/facet-group.tsx +153 -54
- package/src/components/featured-rail-item.tsx +5 -0
- package/src/components/filter-option-chip.test.tsx +50 -0
- package/src/components/filter-option-chip.tsx +81 -0
- package/src/components/filter-option-group.stories.tsx +250 -0
- package/src/components/filter-option-group.test.tsx +100 -0
- package/src/components/filter-option-group.tsx +231 -0
- package/src/components/filter-panel-footer.tsx +63 -0
- package/src/components/kitchen-dossier.tsx +14 -1
- package/src/components/menu-hub-hero.tsx +13 -0
- package/src/components/place-card.stories.tsx +10 -0
- package/src/components/place-card.test.tsx +31 -0
- package/src/components/place-card.tsx +22 -6
- package/src/components/poster-stack.tsx +3 -0
- package/src/components/section-header.tsx +8 -1
- package/src/components/timeline-day.stories.tsx +30 -0
- package/src/components/timeline-day.test.tsx +24 -0
- package/src/components/timeline-hour.tsx +40 -6
- package/src/lib/poster-overlay-frame.tsx +26 -0
|
@@ -46,6 +46,15 @@ import * as React from 'react';
|
|
|
46
46
|
* label, a rule, the count) at both widths, after the day's
|
|
47
47
|
* real programme.
|
|
48
48
|
*
|
|
49
|
+
* `tone="live"` (with `unscheduled` only) is the same off-axis group for
|
|
50
|
+
* events that are ON NOW but have no slot on today's axis — last night's set
|
|
51
|
+
* still running at 02:00, day three of a festival. It leads the day, so the
|
|
52
|
+
* quiet mono heading ("time to be confirmed") would dress "on right now" as
|
|
53
|
+
* "we don't know when": the label goes sans, semibold and success-tinted
|
|
54
|
+
* behind a pulsing dot, the rule takes the live hairline's tint, and the
|
|
55
|
+
* phone keeps the hours' gutter inset so its cards line up with the cards
|
|
56
|
+
* below instead of running 70px wider and reading as the day's feature.
|
|
57
|
+
*
|
|
49
58
|
* `layout`: `cards` stacks posters with a gap (a card is its own frame, a
|
|
50
59
|
* hairline between two posters reads as a third object) and from `lg` lays
|
|
51
60
|
* them on a two/three-up grid; `rows` is the same gapped stack on the phone
|
|
@@ -60,6 +69,9 @@ type TimelineHourProps = {
|
|
|
60
69
|
* the caller's label for the group ("Time to be confirmed"). */
|
|
61
70
|
time: string;
|
|
62
71
|
role?: TimelineHourRole;
|
|
72
|
+
/** `live`: an `unscheduled` group whose events are on now. Ignored on
|
|
73
|
+
* other roles, which say "live" through `isLive`. */
|
|
74
|
+
tone?: "default" | "live";
|
|
63
75
|
/** Marks this as the hour currently in progress. */
|
|
64
76
|
isLive?: boolean;
|
|
65
77
|
/** Under the station when live, e.g. "NOW ON"; screen-reader-only in the chip. */
|
|
@@ -81,7 +93,7 @@ type TimelineHourProps = {
|
|
|
81
93
|
overflow?: React.ReactNode;
|
|
82
94
|
className?: string;
|
|
83
95
|
};
|
|
84
|
-
declare function TimelineHour({ time, role, isLive, liveLabel, countLabel, note, layout, children, overflow, className, }: TimelineHourProps): react_jsx_runtime.JSX.Element;
|
|
96
|
+
declare function TimelineHour({ time, role, tone, isLive, liveLabel, countLabel, note, layout, children, overflow, className, }: TimelineHourProps): react_jsx_runtime.JSX.Element;
|
|
85
97
|
type TimelineHourSkeletonProps = {
|
|
86
98
|
/** Cards to reserve space for. */
|
|
87
99
|
cardCount?: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bearmenu/ui",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.53",
|
|
4
4
|
"description": "BearMenu design system — shared UI tokens, primitives, and components",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
@@ -100,10 +100,10 @@
|
|
|
100
100
|
"@radix-ui/react-toggle": "^1.1.10",
|
|
101
101
|
"@radix-ui/react-toggle-group": "^1.1.11",
|
|
102
102
|
"@radix-ui/react-tooltip": "^1.2.8",
|
|
103
|
-
"@storybook/addon-a11y": "^10.
|
|
104
|
-
"@storybook/addon-docs": "^10.
|
|
105
|
-
"@storybook/react": "^10.
|
|
106
|
-
"@storybook/react-vite": "^10.
|
|
103
|
+
"@storybook/addon-a11y": "^10.6.5",
|
|
104
|
+
"@storybook/addon-docs": "^10.6.5",
|
|
105
|
+
"@storybook/react": "^10.6.5",
|
|
106
|
+
"@storybook/react-vite": "^10.6.5",
|
|
107
107
|
"@tailwindcss/postcss": "^4.2.4",
|
|
108
108
|
"@tailwindcss/vite": "^4.2.4",
|
|
109
109
|
"@testing-library/jest-dom": "^6.9.1",
|
|
@@ -129,7 +129,7 @@
|
|
|
129
129
|
"react-markdown": "^10.1.0",
|
|
130
130
|
"remark-gfm": "^4.0.1",
|
|
131
131
|
"sonner": "^2.0.7",
|
|
132
|
-
"storybook": "^10.
|
|
132
|
+
"storybook": "^10.6.5",
|
|
133
133
|
"tailwind-merge": "^3.5.0",
|
|
134
134
|
"tailwindcss": "^4.2.4",
|
|
135
135
|
"tsup": "^8.5.0",
|
|
@@ -105,6 +105,11 @@ export type CategoryDeckProps = {
|
|
|
105
105
|
/** Defaults to a plain `<a>`. Pass `next/link` in a Next app. */
|
|
106
106
|
linkComponent?: React.ComponentType<CategoryDeckLinkProps>;
|
|
107
107
|
onClick?: (mouseEvent: React.MouseEvent) => void;
|
|
108
|
+
/**
|
|
109
|
+
* Decoration laid over the fan's box, unclipped (it may cross the box's
|
|
110
|
+
* edge), above the cards. Absolutely positioned, `aria-hidden`, no layout.
|
|
111
|
+
*/
|
|
112
|
+
overlay?: React.ReactNode;
|
|
108
113
|
className?: string;
|
|
109
114
|
};
|
|
110
115
|
|
|
@@ -115,6 +120,7 @@ export function CategoryDeck({
|
|
|
115
120
|
href,
|
|
116
121
|
linkComponent: LinkComponent = DefaultLink,
|
|
117
122
|
onClick,
|
|
123
|
+
overlay,
|
|
118
124
|
className,
|
|
119
125
|
}: CategoryDeckProps) {
|
|
120
126
|
const slots = Array.from(
|
|
@@ -160,6 +166,11 @@ export function CategoryDeck({
|
|
|
160
166
|
</div>
|
|
161
167
|
);
|
|
162
168
|
})}
|
|
169
|
+
{overlay && (
|
|
170
|
+
<span className="pointer-events-none absolute inset-0 z-[3] block" aria-hidden>
|
|
171
|
+
{overlay}
|
|
172
|
+
</span>
|
|
173
|
+
)}
|
|
163
174
|
</div>
|
|
164
175
|
|
|
165
176
|
<div className="flex items-center gap-[9px] pt-3.5">
|
|
@@ -185,4 +185,10 @@ describe("EventCard", () => {
|
|
|
185
185
|
renderCard({ liveStatus: "Live now · ends around 23:00" });
|
|
186
186
|
expect(screen.getByText("Live now · ends around 23:00")).toBeInTheDocument();
|
|
187
187
|
});
|
|
188
|
+
|
|
189
|
+
it("renders posterOverlay inside a real, pointer-transparent box over the poster", () => {
|
|
190
|
+
renderCard({ posterOverlay: <i data-testid="overlay" /> });
|
|
191
|
+
const box = screen.getByTestId("overlay").parentElement;
|
|
192
|
+
expect(box).toHaveClass("absolute", "inset-0", "pointer-events-none");
|
|
193
|
+
});
|
|
188
194
|
});
|
|
@@ -75,6 +75,13 @@ export type EventCardProps = {
|
|
|
75
75
|
badge?: React.ReactNode;
|
|
76
76
|
/** Bottom-left overlay pill naming the category. Include its icon. */
|
|
77
77
|
tagLabel?: React.ReactNode;
|
|
78
|
+
/**
|
|
79
|
+
* Decorative overlay inside the poster box (which is `relative` and clips),
|
|
80
|
+
* for a caller's absolutely positioned ornament. Rendered after the pills,
|
|
81
|
+
* hidden on the compact row's 64px poster. Must be `aria-hidden` and
|
|
82
|
+
* pointer-transparent; it never takes layout.
|
|
83
|
+
*/
|
|
84
|
+
posterOverlay?: React.ReactNode;
|
|
78
85
|
/**
|
|
79
86
|
* Caller-supplied display labels, rendered as small chips in the text area
|
|
80
87
|
* beneath the venue/meta line. `EventPreview.tags` is taxonomy coordinates
|
|
@@ -132,6 +139,7 @@ export const EventCard = memo(function EventCard({
|
|
|
132
139
|
density = "card",
|
|
133
140
|
badge,
|
|
134
141
|
tagLabel,
|
|
142
|
+
posterOverlay,
|
|
135
143
|
tags,
|
|
136
144
|
liveStatus,
|
|
137
145
|
hideWhen,
|
|
@@ -228,6 +236,15 @@ export const EventCard = memo(function EventCard({
|
|
|
228
236
|
</span>
|
|
229
237
|
</div>
|
|
230
238
|
)}
|
|
239
|
+
|
|
240
|
+
{posterOverlay && (
|
|
241
|
+
<div
|
|
242
|
+
className={cn("pointer-events-none absolute inset-0", isRowLg && "lg:hidden")}
|
|
243
|
+
aria-hidden="true"
|
|
244
|
+
>
|
|
245
|
+
{posterOverlay}
|
|
246
|
+
</div>
|
|
247
|
+
)}
|
|
231
248
|
</div>
|
|
232
249
|
|
|
233
250
|
{/* The text column — a wrapper so `row-lg` can lay it beside the poster. */}
|
|
@@ -4,6 +4,7 @@ import { memo, useState } from "react";
|
|
|
4
4
|
import { Radio } from "lucide-react";
|
|
5
5
|
import { cn } from "../lib/utils";
|
|
6
6
|
import { EventPosterFallback } from "./event-poster-fallback";
|
|
7
|
+
import { PosterOverlayFrame } from "../lib/poster-overlay-frame";
|
|
7
8
|
import { Skeleton } from "./skeleton";
|
|
8
9
|
import { Tag } from "./tag";
|
|
9
10
|
import { TagGroup } from "./tag-group";
|
|
@@ -105,6 +106,12 @@ export type EventCompactRowProps = {
|
|
|
105
106
|
priority?: boolean;
|
|
106
107
|
/** Rendered in place of the poster when it is absent or fails to load. Defaults to `<EventPosterFallback />`. */
|
|
107
108
|
fallback?: React.ReactNode;
|
|
109
|
+
/**
|
|
110
|
+
* Decoration laid over the poster's box, unclipped (it may cross the
|
|
111
|
+
* poster's edge), above the row. Absolutely positioned, `aria-hidden`,
|
|
112
|
+
* pointer-transparent; it takes no layout.
|
|
113
|
+
*/
|
|
114
|
+
posterOverlay?: React.ReactNode;
|
|
108
115
|
};
|
|
109
116
|
|
|
110
117
|
export const EventCompactRow = memo(function EventCompactRow({
|
|
@@ -125,6 +132,7 @@ export const EventCompactRow = memo(function EventCompactRow({
|
|
|
125
132
|
className,
|
|
126
133
|
priority,
|
|
127
134
|
fallback = <EventPosterFallback />,
|
|
135
|
+
posterOverlay,
|
|
128
136
|
}: EventCompactRowProps) {
|
|
129
137
|
const [imgError, setImgError] = useState(false);
|
|
130
138
|
const isSm = size === "sm";
|
|
@@ -169,30 +177,32 @@ export const EventCompactRow = memo(function EventCompactRow({
|
|
|
169
177
|
phone-scoped: a 14px bold title and 11px of vertical padding below
|
|
170
178
|
`lg`; from `lg` the 13px semibold title and 8px padding the desktop
|
|
171
179
|
timeline and the hub's venue block already had. */}
|
|
172
|
-
<
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
180
|
+
<PosterOverlayFrame overlay={posterOverlay}>
|
|
181
|
+
<div
|
|
182
|
+
className={cn(
|
|
183
|
+
"relative aspect-[4/5] w-16 shrink-0 overflow-hidden rounded-[10px] bg-muted",
|
|
184
|
+
isEnded && "opacity-45",
|
|
185
|
+
)}
|
|
186
|
+
>
|
|
187
|
+
{showPoster ? (
|
|
188
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
189
|
+
<img
|
|
190
|
+
src={event.poster_url}
|
|
191
|
+
alt=""
|
|
192
|
+
loading={priority ? "eager" : "lazy"}
|
|
193
|
+
decoding="async"
|
|
194
|
+
className="h-full w-full object-cover"
|
|
195
|
+
onError={() => setImgError(true)}
|
|
196
|
+
/>
|
|
197
|
+
) : (
|
|
198
|
+
// A bare `bg-muted` rectangle was survivable at 34px. At 58x72 beside
|
|
199
|
+
// real posters it reads as a broken image rather than an absent one —
|
|
200
|
+
// so this row finally joins every sibling in the family in having a
|
|
201
|
+
// designed fallback.
|
|
202
|
+
fallback
|
|
203
|
+
)}
|
|
204
|
+
</div>
|
|
205
|
+
</PosterOverlayFrame>
|
|
196
206
|
|
|
197
207
|
<div className="min-w-0 flex-1">
|
|
198
208
|
{/* The title wraps in full — never truncated, in this row or any of
|
|
@@ -29,6 +29,11 @@ export type EventHubHeroStat = {
|
|
|
29
29
|
label: string;
|
|
30
30
|
/** `live` marks the figure that is happening right now. */
|
|
31
31
|
tone?: "default" | "live";
|
|
32
|
+
/**
|
|
33
|
+
* Decoration beside the figure, absolutely positioned just past its right
|
|
34
|
+
* edge: no layout. Decorative and `aria-hidden`.
|
|
35
|
+
*/
|
|
36
|
+
adornment?: React.ReactNode;
|
|
32
37
|
};
|
|
33
38
|
|
|
34
39
|
export type EventHubHeroProps = {
|
|
@@ -131,10 +136,19 @@ export function EventHubHero({
|
|
|
131
136
|
className={cn(
|
|
132
137
|
"text-[19px] font-black leading-none tracking-[-0.02em] tabular-nums",
|
|
133
138
|
isLive ? "text-success" : "text-foreground",
|
|
134
|
-
"lg:text-[30px] lg:tracking-[-0.03em]"
|
|
139
|
+
"lg:text-[30px] lg:tracking-[-0.03em]",
|
|
140
|
+
stat.adornment && "relative w-fit"
|
|
135
141
|
)}
|
|
136
142
|
>
|
|
137
143
|
{stat.value}
|
|
144
|
+
{stat.adornment && (
|
|
145
|
+
<span
|
|
146
|
+
className="pointer-events-none absolute left-full top-1/2 ml-1.5 -translate-y-1/2"
|
|
147
|
+
aria-hidden
|
|
148
|
+
>
|
|
149
|
+
{stat.adornment}
|
|
150
|
+
</span>
|
|
151
|
+
)}
|
|
138
152
|
</span>
|
|
139
153
|
<span className="mt-0.5 text-[11px] text-muted-foreground lg:mt-[5px] lg:text-[12.5px]">
|
|
140
154
|
{stat.label}
|
|
@@ -6,6 +6,7 @@ import { MapPin, Radio } from "lucide-react";
|
|
|
6
6
|
import { cn } from "../lib/utils";
|
|
7
7
|
import { buttonVariants } from "./button";
|
|
8
8
|
import { EventPosterFallback } from "./event-poster-fallback";
|
|
9
|
+
import { PosterOverlayFrame } from "../lib/poster-overlay-frame";
|
|
9
10
|
import { Separator } from "./separator";
|
|
10
11
|
import { Skeleton } from "./skeleton";
|
|
11
12
|
import { Tag } from "./tag";
|
|
@@ -106,6 +107,12 @@ export type EventListRowWideProps = {
|
|
|
106
107
|
* line. Same prop and same reason as `EventIndexRow`.
|
|
107
108
|
*/
|
|
108
109
|
hideRule?: boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Decoration laid over the thumbnail's box, unclipped (it may cross the
|
|
112
|
+
* thumbnail's edge). Absolutely positioned, `aria-hidden`,
|
|
113
|
+
* pointer-transparent; it takes no layout.
|
|
114
|
+
*/
|
|
115
|
+
posterOverlay?: ReactNode;
|
|
109
116
|
};
|
|
110
117
|
|
|
111
118
|
export const EventListRowWide = memo(function EventListRowWide({
|
|
@@ -123,6 +130,7 @@ export const EventListRowWide = memo(function EventListRowWide({
|
|
|
123
130
|
priority,
|
|
124
131
|
fallback = <EventPosterFallback />,
|
|
125
132
|
hideRule,
|
|
133
|
+
posterOverlay,
|
|
126
134
|
}: EventListRowWideProps) {
|
|
127
135
|
const [imgError, setImgError] = useState(false);
|
|
128
136
|
|
|
@@ -178,21 +186,23 @@ export const EventListRowWide = memo(function EventListRowWide({
|
|
|
178
186
|
</div>
|
|
179
187
|
</div>
|
|
180
188
|
|
|
181
|
-
<
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
189
|
+
<PosterOverlayFrame overlay={posterOverlay}>
|
|
190
|
+
<div className="aspect-square w-[104px] shrink-0 overflow-hidden rounded-[10px] bg-muted">
|
|
191
|
+
{showPoster ? (
|
|
192
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
193
|
+
<img
|
|
194
|
+
src={event.poster_url}
|
|
195
|
+
alt=""
|
|
196
|
+
loading={priority ? "eager" : "lazy"}
|
|
197
|
+
decoding="async"
|
|
198
|
+
className="h-full w-full object-cover"
|
|
199
|
+
onError={() => setImgError(true)}
|
|
200
|
+
/>
|
|
201
|
+
) : (
|
|
202
|
+
fallback
|
|
203
|
+
)}
|
|
204
|
+
</div>
|
|
205
|
+
</PosterOverlayFrame>
|
|
196
206
|
|
|
197
207
|
<div className="min-w-0 flex-1">
|
|
198
208
|
<div className="flex flex-wrap items-center gap-2">
|
|
@@ -21,6 +21,18 @@ describe("EventTonightStrip", () => {
|
|
|
21
21
|
);
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
+
it("draws the live indicator in place of the pulsing dot", () => {
|
|
25
|
+
render(
|
|
26
|
+
<EventTonightStrip
|
|
27
|
+
tone="live"
|
|
28
|
+
lead="3 live now"
|
|
29
|
+
href="/events/schedule"
|
|
30
|
+
liveIndicator={<i data-testid="flame" />}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
expect(screen.getByTestId("flame")).toBeInTheDocument();
|
|
34
|
+
});
|
|
35
|
+
|
|
24
36
|
it("renders a status line, not a link, when there is nothing to open", () => {
|
|
25
37
|
render(<EventTonightStrip tone="none" lead="Nothing scheduled" />);
|
|
26
38
|
expect(screen.queryByRole("link")).toBeNull();
|
|
@@ -51,6 +51,8 @@ export type EventTonightStripProps = {
|
|
|
51
51
|
href?: string;
|
|
52
52
|
/** Defaults to a plain `<a>`. Pass `next/link` in a Next app. */
|
|
53
53
|
linkComponent?: React.ComponentType<EventTonightStripLinkProps>;
|
|
54
|
+
/** Replaces the pulsing dot of the `live` tone, in the dot's own slot. Decorative. */
|
|
55
|
+
liveIndicator?: React.ReactNode;
|
|
54
56
|
className?: string;
|
|
55
57
|
};
|
|
56
58
|
|
|
@@ -61,12 +63,17 @@ export function EventTonightStrip({
|
|
|
61
63
|
actionLabel,
|
|
62
64
|
href,
|
|
63
65
|
linkComponent: LinkComponent = DefaultLink,
|
|
66
|
+
liveIndicator,
|
|
64
67
|
className,
|
|
65
68
|
}: EventTonightStripProps) {
|
|
66
69
|
const interactive = !!href;
|
|
67
70
|
|
|
68
71
|
const mark =
|
|
69
|
-
tone === "live" ? (
|
|
72
|
+
tone === "live" && liveIndicator ? (
|
|
73
|
+
<span className="flex h-4 w-4 items-center justify-center" aria-hidden>
|
|
74
|
+
{liveIndicator}
|
|
75
|
+
</span>
|
|
76
|
+
) : tone === "live" ? (
|
|
70
77
|
<span className="relative flex h-2.5 w-2.5" aria-hidden>
|
|
71
78
|
<span className="absolute inline-flex h-full w-full rounded-full bg-success/40 motion-live-pulse motion-reduce:animate-none" />
|
|
72
79
|
<span className="relative inline-flex h-2.5 w-2.5 rounded-full bg-success" />
|