@siyahi/ui 0.1.9-next.35 → 0.1.9-next.36
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/DESIGN.md +37 -21
- package/README.md +7 -9
- package/THIRD_PARTY_NOTICES.md +10 -11
- package/agents/examples/chart-panels.tsx +0 -4
- package/agents/examples/{section-cards-select.tsx → metric-strip-select.tsx} +5 -5
- package/agents/examples/metric-strip-trend.tsx +33 -0
- package/agents/examples/overview-dashboard.tsx +4 -4
- package/agents/examples/scatter-chart.tsx +0 -1
- package/agents/examples/stale-blocks.tsx +9 -9
- package/agents/examples/surfaces.tsx +2 -3
- package/agents/manifest.json +27 -47
- package/dist/components/registry/dashboardcn/kpi-row-card.d.ts +14 -6
- package/dist/components/registry/dashboardcn/kpi-row-card.js +49 -32
- package/dist/components/siyahi/panel-grid.d.ts +5 -6
- package/dist/components/siyahi/panel-grid.js +10 -9
- package/dist/components/siyahi/scatter-chart.d.ts +3 -3
- package/dist/components/siyahi/scatter-chart.js +5 -2
- package/dist/components/siyahi/siyahi-provider.d.ts +5 -6
- package/dist/components/siyahi/siyahi-provider.js +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.js +2 -2
- package/dist/lib/chart-frame.d.ts +1 -1
- package/dist/lib/chart-frame.js +3 -1
- package/dist/lib/chart-series.d.ts +10 -2
- package/dist/lib/chart-series.js +10 -0
- package/package.json +1 -1
- package/registry.lock.json +0 -8
- package/styles/siyahi.css +60 -63
- package/agents/examples/section-cards-trend.tsx +0 -32
- package/agents/examples/section-cards.tsx +0 -48
- package/dist/components/registry/dashboard-01/section-cards.d.ts +0 -30
- package/dist/components/registry/dashboard-01/section-cards.js +0 -74
package/styles/siyahi.css
CHANGED
|
@@ -175,7 +175,7 @@
|
|
|
175
175
|
--chart-1: oklch(0.4 0.17 275);
|
|
176
176
|
--chart-2: oklch(0.66 0.13 70);
|
|
177
177
|
--chart-3: oklch(0.38 0.13 335);
|
|
178
|
-
--chart-4: oklch(0.
|
|
178
|
+
--chart-4: oklch(0.64 0.11 235);
|
|
179
179
|
--chart-5: oklch(0.36 0.06 205);
|
|
180
180
|
--sidebar: oklch(0.985 0 0);
|
|
181
181
|
--sidebar-foreground: oklch(0.145 0 0);
|
|
@@ -189,8 +189,8 @@
|
|
|
189
189
|
@variant dark {
|
|
190
190
|
/*
|
|
191
191
|
* The canvas lifts just off black and text sits a step below white:
|
|
192
|
-
* near-white on near-black (19:1) blurs for many readers, and
|
|
193
|
-
*
|
|
192
|
+
* near-white on near-black (19:1) blurs for many readers, and on an open
|
|
193
|
+
* page, where cards have no fill, the canvas is what text sits on.
|
|
194
194
|
* Claude Code (#181818, about #e8e8e8 text) and T3 Code (#0a0a0a, about
|
|
195
195
|
* #bebebe) both narrow that gap; this sits between them, at 14.9:1.
|
|
196
196
|
* Cards sit one step above the canvas, so data reads as raised, as the
|
|
@@ -325,7 +325,7 @@
|
|
|
325
325
|
|
|
326
326
|
/*
|
|
327
327
|
* A component that lifts a part of itself with a z-index is a stacking context
|
|
328
|
-
* of its own:
|
|
328
|
+
* of its own: MetricStrip's picker buttons, an avatar's badge, a calendar's
|
|
329
329
|
* days, a focused toggle, a code block's buttons, a price chart's layers. The
|
|
330
330
|
* lifted part then ranks only against the rest of its component, and can never
|
|
331
331
|
* sit over, or take a tap from, a page's sticky header or section strip (also
|
|
@@ -757,13 +757,13 @@ svg :is(rect, circle, path)[tabindex]:focus-visible,
|
|
|
757
757
|
}
|
|
758
758
|
|
|
759
759
|
/*
|
|
760
|
-
* An exception the page marks, a
|
|
761
|
-
*
|
|
762
|
-
*
|
|
763
|
-
*
|
|
764
|
-
*
|
|
760
|
+
* An exception the page marks, a MetricStrip figure (its item's tone) or a
|
|
761
|
+
* table row (<TableRow data-tone="negative">, a DataTableBody's getRowTone),
|
|
762
|
+
* takes a faint wash of its colour over the card, and a figure an outline of
|
|
763
|
+
* it, so the one figure needing attention stands out of a run of neutral
|
|
764
|
+
* ones. Unlayered, to outrank a row's hover band.
|
|
765
765
|
*/
|
|
766
|
-
:is([data-slot="
|
|
766
|
+
:is([data-slot="metric-strip-item"], [data-slot="table-row"]) {
|
|
767
767
|
&[data-tone="negative"] {
|
|
768
768
|
--exception: var(--negative);
|
|
769
769
|
}
|
|
@@ -771,24 +771,22 @@ svg :is(rect, circle, path)[tabindex]:focus-visible,
|
|
|
771
771
|
--exception: var(--warning);
|
|
772
772
|
}
|
|
773
773
|
}
|
|
774
|
-
:is([data-slot="card"], [data-slot="metric-strip-item"]):is([data-tone="negative"], [data-tone="warning"]) {
|
|
775
|
-
background-color: color-mix(in oklab, var(--exception) var(--wash), var(--card));
|
|
776
|
-
}
|
|
777
|
-
[data-slot="card"]:is([data-tone="negative"], [data-tone="warning"]) {
|
|
778
|
-
--tw-ring-color: color-mix(in oklab, var(--exception) var(--wash-edge), transparent);
|
|
779
|
-
}
|
|
780
774
|
/*
|
|
781
|
-
* A figure
|
|
782
|
-
*
|
|
775
|
+
* A MetricStrip figure has no padding of its own, so its text lines up with its neighbours'; its wash and outline
|
|
776
|
+
* reach 8px past it, into the gap, as a picked figure's outline does. --figure-wash is the wash the whole box takes.
|
|
783
777
|
*/
|
|
784
|
-
[data-slot="metric-strip-item"]
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
778
|
+
[data-slot="metric-strip-item"] {
|
|
779
|
+
--figure-reach: calc(var(--spacing) * 2);
|
|
780
|
+
&:is([data-tone="negative"], [data-tone="warning"]) {
|
|
781
|
+
--figure-wash: color-mix(in oklab, var(--exception) var(--wash), var(--card));
|
|
782
|
+
background-color: var(--figure-wash);
|
|
783
|
+
box-shadow: 0 0 0 var(--figure-reach) var(--figure-wash);
|
|
784
|
+
outline: 1px solid color-mix(in oklab, var(--exception) var(--wash-edge), transparent);
|
|
785
|
+
outline-offset: var(--figure-reach);
|
|
786
|
+
}
|
|
787
|
+
&[data-picked] {
|
|
788
|
+
outline: 2px solid var(--primary);
|
|
789
|
+
outline-offset: var(--figure-reach);
|
|
792
790
|
}
|
|
793
791
|
}
|
|
794
792
|
/* A pinned cell paints the card under itself (niko-table's lib/styles), so it lays the row's wash over that. */
|
|
@@ -830,11 +828,10 @@ svg :is(rect, circle, path)[tabindex]:focus-visible,
|
|
|
830
828
|
}
|
|
831
829
|
|
|
832
830
|
/*
|
|
833
|
-
* A data table inside a card drops its own border: the card's ring
|
|
834
|
-
*
|
|
835
|
-
* it keeps its border.
|
|
831
|
+
* A data table inside a boxed card drops its own border: the card's ring
|
|
832
|
+
* already frames it. On an open page, with no frame, it keeps its border.
|
|
836
833
|
*/
|
|
837
|
-
@scope (
|
|
834
|
+
@scope ([data-surface="card"]) to ([data-surface="open"]) {
|
|
838
835
|
[data-slot="card"] [data-slot="table-container"] {
|
|
839
836
|
border-color: transparent;
|
|
840
837
|
}
|
|
@@ -888,21 +885,22 @@ svg :is(rect, circle, path)[tabindex]:focus-visible,
|
|
|
888
885
|
}
|
|
889
886
|
|
|
890
887
|
/*
|
|
891
|
-
* A block the page marks stale (stale on a chart card or a
|
|
892
|
-
* loses its colour: its chart, sparkline and badge turn grey, and a
|
|
893
|
-
*
|
|
888
|
+
* A block the page marks stale (stale on a chart card or a MetricStrip figure)
|
|
889
|
+
* loses its colour: its chart, sparkline and badge turn grey, and a figure
|
|
890
|
+
* turns muted. The chart and sparkline also draw at 65%, so a
|
|
894
891
|
* dark slot's line does not read heavier than a fresh one: a stale block is
|
|
895
892
|
* meant to be harder to read, so its marks are exempt from the 3:1 mark bar.
|
|
896
893
|
* The small "Stale · 3 Nov" note under the title and the figure keep their
|
|
897
894
|
* text contrast.
|
|
898
895
|
*/
|
|
899
|
-
|
|
896
|
+
:is([data-slot="card"], [data-slot="metric-strip-item"])[data-stale]
|
|
897
|
+
:is([data-slot="chart"], [data-slot="sparkline"], [data-slot="badge"], [data-slot="delta"]) {
|
|
900
898
|
filter: grayscale(1);
|
|
901
899
|
}
|
|
902
|
-
[data-slot="card"][data-stale] :is([data-slot="chart"], [data-slot="sparkline"]) {
|
|
900
|
+
:is([data-slot="card"], [data-slot="metric-strip-item"])[data-stale] :is([data-slot="chart"], [data-slot="sparkline"]) {
|
|
903
901
|
opacity: 0.65;
|
|
904
902
|
}
|
|
905
|
-
[data-slot="
|
|
903
|
+
[data-slot="metric-strip-item"][data-stale] [data-slot="metric-strip-value"] {
|
|
906
904
|
color: var(--muted-foreground);
|
|
907
905
|
}
|
|
908
906
|
|
|
@@ -1002,40 +1000,39 @@ div[data-slot="sidebar"]:not([data-side], [data-mobile]) {
|
|
|
1002
1000
|
}
|
|
1003
1001
|
|
|
1004
1002
|
/*
|
|
1005
|
-
* Surfaces, from SiyahiProvider's surface prop.
|
|
1006
|
-
* every
|
|
1007
|
-
*
|
|
1008
|
-
*
|
|
1009
|
-
*
|
|
1010
|
-
*
|
|
1011
|
-
*
|
|
1012
|
-
*
|
|
1013
|
-
* and no padding, so a block's content sits level with the page's text. Each
|
|
1014
|
-
* scope stops at a provider that says otherwise. Unlayered, like the rules
|
|
1015
|
-
* above, to outrank the core components' utility classes; a picked
|
|
1016
|
-
* SectionCards tile keeps its ring, which is important, and an exception
|
|
1017
|
-
* keeps its outline, which is more specific.
|
|
1003
|
+
* Surfaces, from SiyahiProvider's surface prop. Open, the default, takes the
|
|
1004
|
+
* box off every core Card: no fill, no ring, no tinted footer band, and no
|
|
1005
|
+
* padding, so a block's content sits level with the page's text and space,
|
|
1006
|
+
* not a box or a rule, parts it from the next. Card is a filled square card
|
|
1007
|
+
* with a hairline ring and no shadow, 8px from the next, for a page of
|
|
1008
|
+
* separate blocks. Each scope stops at a provider that says otherwise.
|
|
1009
|
+
* Unlayered, like the rules above, to outrank the core components' utility
|
|
1010
|
+
* classes.
|
|
1018
1011
|
*/
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
) {
|
|
1030
|
-
border-block: 1px solid var(--border);
|
|
1031
|
-
}
|
|
1012
|
+
/*
|
|
1013
|
+
* An open card renames --card to the page colour for everything inside it, and a custom property inherits past a
|
|
1014
|
+
* scope's end, so a card provider nested in an open card would fill its boxes with the page colour. --card-fill keeps
|
|
1015
|
+
* the theme's card colour, set once at the root, and each card provider takes it back.
|
|
1016
|
+
*/
|
|
1017
|
+
:root {
|
|
1018
|
+
--card-fill: var(--card);
|
|
1019
|
+
}
|
|
1020
|
+
[data-surface="card"] {
|
|
1021
|
+
--card: var(--card-fill);
|
|
1032
1022
|
}
|
|
1033
1023
|
|
|
1034
|
-
@scope ([data-surface="open"]) to ([data-surface="
|
|
1024
|
+
@scope (:root, [data-surface="open"]) to ([data-surface="card"]) {
|
|
1035
1025
|
[data-slot="table-container"] {
|
|
1036
1026
|
--table-fill: var(--background);
|
|
1037
1027
|
}
|
|
1028
|
+
/*
|
|
1029
|
+
* With no fill, what lies under a card's marks is the page, so --card names the page colour inside it: a forecast's
|
|
1030
|
+
* halos, a dot's ring, a bar's tint and an exception's wash mix into the canvas, not into a grey no box shows.
|
|
1031
|
+
*/
|
|
1038
1032
|
[data-slot="card"] {
|
|
1033
|
+
--card: var(--background);
|
|
1034
|
+
/* No box, so no edge to clip at: a figure's wash or picker reaching past its text into the gap stays whole. */
|
|
1035
|
+
overflow: visible;
|
|
1039
1036
|
background: none;
|
|
1040
1037
|
--tw-ring-color: transparent;
|
|
1041
1038
|
--card-spacing: 0px;
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { Delta, SectionCards, Sparkline, useFormat, type SectionCard } from "@siyahi/ui";
|
|
2
|
-
|
|
3
|
-
export default function SectionCardsTrendExample() {
|
|
4
|
-
const { money, moneyCompact } = useFormat();
|
|
5
|
-
const items: SectionCard[] = [
|
|
6
|
-
{
|
|
7
|
-
label: "Revenue",
|
|
8
|
-
value: money(4512300),
|
|
9
|
-
badge: <Delta value={0.031} />,
|
|
10
|
-
trend: <Sparkline data={[3820000, 3950000, 4110000, 4020000, 4380000, 4512300]} />,
|
|
11
|
-
detail: "Month-end, last six months",
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
label: "Cash flow this year",
|
|
15
|
-
value: moneyCompact(-61200),
|
|
16
|
-
badge: <Delta value={-61200} format="money" />,
|
|
17
|
-
// A run of losses: the meaning colour, not a chart slot.
|
|
18
|
-
trend: <Sparkline data={[0, -8200, -14100, -30400, -52800, -61200]} color="var(--negative)" />,
|
|
19
|
-
detail: "Running total since April",
|
|
20
|
-
// The one figure on the page that needs a look, marked by the page: a falling cost would not be.
|
|
21
|
-
tone: "negative",
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
label: "Gift cards this year",
|
|
25
|
-
value: moneyCompact(38400),
|
|
26
|
-
badge: <Delta value={0.18} />,
|
|
27
|
-
trend: <Sparkline data={[4100, 0, 12800, 3300, 9900, 8300]} variant="line" curve="linear" />,
|
|
28
|
-
detail: "Sold each month",
|
|
29
|
-
},
|
|
30
|
-
];
|
|
31
|
-
return <SectionCards items={items} />;
|
|
32
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { Delta, SectionCards, type SectionCard, useFormat } from "@siyahi/ui";
|
|
2
|
-
|
|
3
|
-
export default function SectionCardsExample() {
|
|
4
|
-
const { money, moneyCompact } = useFormat();
|
|
5
|
-
const items: SectionCard[] = [
|
|
6
|
-
{
|
|
7
|
-
label: "Revenue",
|
|
8
|
-
value: money(4512300),
|
|
9
|
-
badge: <Delta value={0.031} />,
|
|
10
|
-
headline: "Up for the third month",
|
|
11
|
-
detail: "Paid orders, less refunds",
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
label: "Target",
|
|
15
|
-
value: money(4025000),
|
|
16
|
-
headline: "Set at the start of the quarter",
|
|
17
|
-
detail: "Across 4 stores",
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
label: "Ahead of target",
|
|
21
|
-
value: moneyCompact(487300),
|
|
22
|
-
badge: <Delta value={0.121} />,
|
|
23
|
-
headline: "Gross margin 14.2%",
|
|
24
|
-
detail: "Since April",
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
label: "Cash flow this year",
|
|
28
|
-
value: moneyCompact(-61200),
|
|
29
|
-
badge: <Delta value={-61200} format="money" />,
|
|
30
|
-
headline: "Two large inventory buys",
|
|
31
|
-
detail: "Before tax",
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
label: "Gift cards this year",
|
|
35
|
-
value: moneyCompact(38400),
|
|
36
|
-
badge: <Delta value={0.18} />,
|
|
37
|
-
headline: "Sold in 11 stores",
|
|
38
|
-
detail: "Paid at purchase",
|
|
39
|
-
},
|
|
40
|
-
];
|
|
41
|
-
return (
|
|
42
|
-
<div className="flex flex-col gap-6">
|
|
43
|
-
<SectionCards items={items.slice(0, 3)} />
|
|
44
|
-
<SectionCards items={items.slice(0, 4)} />
|
|
45
|
-
<SectionCards items={items} />
|
|
46
|
-
</div>
|
|
47
|
-
);
|
|
48
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import * as React$1 from "react";
|
|
2
|
-
//#region src/components/registry/dashboard-01/section-cards.d.ts
|
|
3
|
-
export interface SectionCard {
|
|
4
|
-
/** Muted label above the value. */
|
|
5
|
-
label: string;
|
|
6
|
-
value: React$1.ReactNode;
|
|
7
|
-
/** Outline badge, top right; usually a <Delta />. */
|
|
8
|
-
badge?: React$1.ReactNode;
|
|
9
|
-
/** A small chart under the value, usually a <Sparkline /> of the recent run. */
|
|
10
|
-
trend?: React$1.ReactNode;
|
|
11
|
-
/** Bold first footer line. */
|
|
12
|
-
headline?: React$1.ReactNode;
|
|
13
|
-
/** Muted second footer line. */
|
|
14
|
-
detail?: React$1.ReactNode;
|
|
15
|
-
/** In a picker, a tile that cannot be picked, such as one with nothing in it: faded, and its button disabled. */
|
|
16
|
-
disabled?: boolean | undefined;
|
|
17
|
-
/** Marks the tile as the exception on the page: a faint wash of the colour and an outline of it. */
|
|
18
|
-
tone?: "negative" | "warning" | undefined;
|
|
19
|
-
/** Marks the tile's data as old, with since when, such as "3 Nov": the tile greys out and says so. */
|
|
20
|
-
stale?: React$1.ReactNode;
|
|
21
|
-
}
|
|
22
|
-
export interface SectionCardsProps {
|
|
23
|
-
items: SectionCard[];
|
|
24
|
-
/** The label of the picked tile. */
|
|
25
|
-
selected?: string | undefined;
|
|
26
|
-
/** Makes each tile one button, so keep tile content non-interactive; gets the label of the tile picked. */
|
|
27
|
-
onSelect?: ((label: string) => void) | undefined;
|
|
28
|
-
}
|
|
29
|
-
export declare function SectionCards({ items, selected, onSelect }: SectionCardsProps): React$1.JSX.Element;
|
|
30
|
-
//#endregion
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { Badge } from "../../ui/badge.js";
|
|
3
|
-
import { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "../../ui/card.js";
|
|
4
|
-
import { cn } from "../../../lib/utils.js";
|
|
5
|
-
import { StaleNote } from "../../siyahi/stale-note.js";
|
|
6
|
-
import { useSurface } from "../../siyahi/siyahi-provider.js";
|
|
7
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
-
import "react";
|
|
9
|
-
//#region src/components/registry/dashboard-01/section-cards.tsx
|
|
10
|
-
const COLUMNS = {
|
|
11
|
-
2: "@xl/main:grid-cols-2",
|
|
12
|
-
3: "@3xl/main:grid-cols-3",
|
|
13
|
-
4: "@xl/main:grid-cols-2 @5xl/main:grid-cols-4",
|
|
14
|
-
5: "@3xl/main:grid-cols-3 @7xl/main:grid-cols-5",
|
|
15
|
-
6: "@3xl/main:grid-cols-3"
|
|
16
|
-
};
|
|
17
|
-
function SectionCards({ items, selected, onSelect }) {
|
|
18
|
-
const surface = useSurface();
|
|
19
|
-
const ruled = surface === "ruled";
|
|
20
|
-
return /* @__PURE__ */ jsx("div", {
|
|
21
|
-
"data-surface": surface,
|
|
22
|
-
className: cn("@container/main", ruled && "overflow-hidden border-y"),
|
|
23
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
24
|
-
className: cn("grid grid-cols-1", ruled ? "-me-px -mb-px bg-card" : surface === "open" ? "gap-4" : "gap-2", COLUMNS[items.length] ?? COLUMNS[4]),
|
|
25
|
-
children: items.map((item) => /* @__PURE__ */ jsx("div", {
|
|
26
|
-
"data-slot": "section-card",
|
|
27
|
-
className: cn("min-w-0", ruled && "border-e border-b"),
|
|
28
|
-
children: /* @__PURE__ */ jsxs(Card, {
|
|
29
|
-
"data-tone": item.tone,
|
|
30
|
-
"data-stale": item.stale ? "" : void 0,
|
|
31
|
-
className: cn("@container/card h-full [--card-spacing:--spacing(3)]", onSelect && "relative", item.label === selected && "ring-2 ring-primary!", item.label === selected && ruled && "ring-inset", onSelect && item.disabled && "opacity-60"),
|
|
32
|
-
children: [
|
|
33
|
-
onSelect && /* @__PURE__ */ jsx("button", {
|
|
34
|
-
type: "button",
|
|
35
|
-
"aria-label": item.label,
|
|
36
|
-
"aria-pressed": item.label === selected,
|
|
37
|
-
disabled: item.disabled,
|
|
38
|
-
onClick: () => onSelect(item.label),
|
|
39
|
-
className: "absolute inset-0 z-10 rounded-[inherit] outline-none focus-visible:ring-3 focus-visible:ring-ring focus-visible:ring-inset"
|
|
40
|
-
}),
|
|
41
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
42
|
-
/* @__PURE__ */ jsx(CardDescription, {
|
|
43
|
-
className: "font-mono text-2xs tracking-wider uppercase",
|
|
44
|
-
children: item.label
|
|
45
|
-
}),
|
|
46
|
-
item.stale && /* @__PURE__ */ jsx(StaleNote, { since: item.stale }),
|
|
47
|
-
/* @__PURE__ */ jsx(CardTitle, {
|
|
48
|
-
className: "text-2xl font-semibold tabular-nums",
|
|
49
|
-
children: item.value
|
|
50
|
-
}),
|
|
51
|
-
item.badge && /* @__PURE__ */ jsx(CardAction, { children: /* @__PURE__ */ jsx(Badge, {
|
|
52
|
-
variant: "outline",
|
|
53
|
-
children: item.badge
|
|
54
|
-
}) })
|
|
55
|
-
] }),
|
|
56
|
-
item.trend && /* @__PURE__ */ jsx(CardContent, { children: item.trend }),
|
|
57
|
-
(item.headline || item.detail) && /* @__PURE__ */ jsxs(CardFooter, {
|
|
58
|
-
className: "flex-col items-start gap-1 font-mono text-2xs tracking-wider uppercase",
|
|
59
|
-
children: [item.headline && /* @__PURE__ */ jsx("div", {
|
|
60
|
-
className: "flex flex-wrap gap-2 font-medium",
|
|
61
|
-
children: item.headline
|
|
62
|
-
}), item.detail && /* @__PURE__ */ jsx("div", {
|
|
63
|
-
className: "text-muted-foreground",
|
|
64
|
-
children: item.detail
|
|
65
|
-
})]
|
|
66
|
-
})
|
|
67
|
-
]
|
|
68
|
-
})
|
|
69
|
-
}, item.label))
|
|
70
|
-
})
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
//#endregion
|
|
74
|
-
export { SectionCards };
|