@lindaui/blocks 0.0.2
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/LICENSE +21 -0
- package/README.md +41 -0
- package/dist/area-chart.d.ts +11 -0
- package/dist/area-chart.d.ts.map +1 -0
- package/dist/area-chart.js +65 -0
- package/dist/auth-layout.d.ts +26 -0
- package/dist/auth-layout.d.ts.map +1 -0
- package/dist/auth-layout.js +85 -0
- package/dist/auth-provider.d.ts +13 -0
- package/dist/auth-provider.d.ts.map +1 -0
- package/dist/auth-provider.js +20 -0
- package/dist/bar-chart.d.ts +11 -0
- package/dist/bar-chart.d.ts.map +1 -0
- package/dist/bar-chart.js +64 -0
- package/dist/chart-card.d.ts +11 -0
- package/dist/chart-card.d.ts.map +1 -0
- package/dist/chart-card.js +43 -0
- package/dist/confirm-dialog.d.ts +19 -0
- package/dist/confirm-dialog.d.ts.map +1 -0
- package/dist/confirm-dialog.js +57 -0
- package/dist/detail-panel.d.ts +25 -0
- package/dist/detail-panel.d.ts.map +1 -0
- package/dist/detail-panel.js +116 -0
- package/dist/document-panel.d.ts +15 -0
- package/dist/document-panel.d.ts.map +1 -0
- package/dist/document-panel.js +80 -0
- package/dist/document-reader.d.ts +5 -0
- package/dist/document-reader.d.ts.map +1 -0
- package/dist/document-reader.js +27 -0
- package/dist/field-array-form.d.ts +30 -0
- package/dist/field-array-form.d.ts.map +1 -0
- package/dist/field-array-form.js +132 -0
- package/dist/image-viewer.d.ts +14 -0
- package/dist/image-viewer.d.ts.map +1 -0
- package/dist/image-viewer.js +108 -0
- package/dist/line-chart.d.ts +11 -0
- package/dist/line-chart.d.ts.map +1 -0
- package/dist/line-chart.js +44 -0
- package/dist/list-item.d.ts +16 -0
- package/dist/list-item.d.ts.map +1 -0
- package/dist/list-item.js +50 -0
- package/dist/list-pane.d.ts +27 -0
- package/dist/list-pane.d.ts.map +1 -0
- package/dist/list-pane.js +136 -0
- package/dist/login-form.d.ts +18 -0
- package/dist/login-form.d.ts.map +1 -0
- package/dist/login-form.js +109 -0
- package/dist/pie-chart.d.ts +12 -0
- package/dist/pie-chart.d.ts.map +1 -0
- package/dist/pie-chart.js +49 -0
- package/dist/radar-chart.d.ts +11 -0
- package/dist/radar-chart.d.ts.map +1 -0
- package/dist/radar-chart.js +37 -0
- package/dist/radial-chart.d.ts +12 -0
- package/dist/radial-chart.d.ts.map +1 -0
- package/dist/radial-chart.js +91 -0
- package/dist/recording-overlay.d.ts +13 -0
- package/dist/recording-overlay.d.ts.map +1 -0
- package/dist/recording-overlay.js +128 -0
- package/dist/split-workspace.d.ts +9 -0
- package/dist/split-workspace.d.ts.map +1 -0
- package/dist/split-workspace.js +50 -0
- package/dist/stat-card.d.ts +27 -0
- package/dist/stat-card.d.ts.map +1 -0
- package/dist/stat-card.js +166 -0
- package/dist/stats-grid.d.ts +8 -0
- package/dist/stats-grid.d.ts.map +1 -0
- package/dist/stats-grid.js +15 -0
- package/package.json +149 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { AlertCircle, Mic } from 'lucide-react';
|
|
4
|
+
|
|
5
|
+
function fmtTime(sec) {
|
|
6
|
+
const m = Math.floor(sec / 60);
|
|
7
|
+
const s = sec % 60;
|
|
8
|
+
return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
|
|
9
|
+
}
|
|
10
|
+
function Waveform() {
|
|
11
|
+
return /*#__PURE__*/ jsx("div", {
|
|
12
|
+
className: "flex items-end justify-center gap-[3px]",
|
|
13
|
+
style: {
|
|
14
|
+
height: 48,
|
|
15
|
+
width: "min(80%, 280px)"
|
|
16
|
+
},
|
|
17
|
+
children: Array.from({
|
|
18
|
+
length: 40
|
|
19
|
+
}).map((_, i)=>{
|
|
20
|
+
const seed = Math.abs(Math.sin(i * 12.9898) * 43758.5453) % 1;
|
|
21
|
+
const max = Math.max(6, (0.18 + seed * 0.82) * 48);
|
|
22
|
+
return /*#__PURE__*/ jsx("span", {
|
|
23
|
+
className: "rounded-full bg-destructive",
|
|
24
|
+
style: {
|
|
25
|
+
width: 3,
|
|
26
|
+
animation: `ti-wf 0.9s ease-in-out ${i % 11 * 0.07}s infinite`,
|
|
27
|
+
"--wfmax": `${max}px`
|
|
28
|
+
}
|
|
29
|
+
}, i);
|
|
30
|
+
})
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function RecordingOverlay({ label, description, elapsed, error, onStop, onCancel, stopLabel = "Detener", errorTitle = "No se pudo acceder al micrófono", backLabel = "Volver" }) {
|
|
34
|
+
if (error) {
|
|
35
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
36
|
+
className: "absolute inset-0 z-[60] flex flex-col items-center justify-center gap-5 bg-[oklch(0.16_0.02_240)] p-8 text-center",
|
|
37
|
+
children: [
|
|
38
|
+
/*#__PURE__*/ jsx("div", {
|
|
39
|
+
className: "grid h-16 w-16 place-items-center rounded-full bg-destructive/15 text-destructive",
|
|
40
|
+
children: /*#__PURE__*/ jsx(AlertCircle, {
|
|
41
|
+
className: "h-8 w-8"
|
|
42
|
+
})
|
|
43
|
+
}),
|
|
44
|
+
/*#__PURE__*/ jsxs("div", {
|
|
45
|
+
className: "max-w-[280px]",
|
|
46
|
+
children: [
|
|
47
|
+
/*#__PURE__*/ jsx("p", {
|
|
48
|
+
className: "text-base font-semibold text-white",
|
|
49
|
+
children: errorTitle
|
|
50
|
+
}),
|
|
51
|
+
/*#__PURE__*/ jsx("p", {
|
|
52
|
+
className: "mt-2 text-sm text-white/65",
|
|
53
|
+
children: error
|
|
54
|
+
})
|
|
55
|
+
]
|
|
56
|
+
}),
|
|
57
|
+
/*#__PURE__*/ jsx("button", {
|
|
58
|
+
type: "button",
|
|
59
|
+
onClick: onCancel,
|
|
60
|
+
className: "h-12 rounded-2xl bg-white px-6 text-[15px] font-semibold text-[oklch(0.16_0.02_240)]",
|
|
61
|
+
children: backLabel
|
|
62
|
+
})
|
|
63
|
+
]
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
67
|
+
className: "absolute inset-0 z-[60] flex flex-col items-center justify-center gap-5 bg-[oklch(0.16_0.02_240)] text-[oklch(0.9_0.01_220)] sm:gap-7",
|
|
68
|
+
children: [
|
|
69
|
+
/*#__PURE__*/ jsxs("div", {
|
|
70
|
+
className: "relative grid h-[132px] w-[132px] place-items-center sm:h-[168px] sm:w-[168px]",
|
|
71
|
+
children: [
|
|
72
|
+
/*#__PURE__*/ jsx("span", {
|
|
73
|
+
className: "ti-rec-pulse absolute h-[132px] w-[132px] rounded-full bg-destructive/15 sm:h-[168px] sm:w-[168px]"
|
|
74
|
+
}),
|
|
75
|
+
/*#__PURE__*/ jsx("span", {
|
|
76
|
+
className: "ti-rec-pulse absolute h-[132px] w-[132px] rounded-full bg-destructive/15 sm:h-[168px] sm:w-[168px]",
|
|
77
|
+
style: {
|
|
78
|
+
animationDelay: "0.9s"
|
|
79
|
+
}
|
|
80
|
+
}),
|
|
81
|
+
/*#__PURE__*/ jsx("div", {
|
|
82
|
+
className: "grid h-[84px] w-[84px] place-items-center rounded-full bg-destructive text-white shadow-[0_10px_30px_-6px_var(--destructive)] sm:h-[108px] sm:w-[108px]",
|
|
83
|
+
children: /*#__PURE__*/ jsx(Mic, {
|
|
84
|
+
className: "h-8 w-8 sm:h-[42px] sm:w-[42px]"
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
]
|
|
88
|
+
}),
|
|
89
|
+
/*#__PURE__*/ jsxs("div", {
|
|
90
|
+
className: "text-center",
|
|
91
|
+
children: [
|
|
92
|
+
/*#__PURE__*/ jsxs("div", {
|
|
93
|
+
className: "inline-flex items-center gap-2",
|
|
94
|
+
children: [
|
|
95
|
+
/*#__PURE__*/ jsx("span", {
|
|
96
|
+
className: "ti-rec-blink h-2.5 w-2.5 rounded-full bg-destructive"
|
|
97
|
+
}),
|
|
98
|
+
/*#__PURE__*/ jsx("span", {
|
|
99
|
+
className: "text-sm font-semibold tracking-wide text-[oklch(0.72_0.16_18)]",
|
|
100
|
+
children: label
|
|
101
|
+
})
|
|
102
|
+
]
|
|
103
|
+
}),
|
|
104
|
+
/*#__PURE__*/ jsx("div", {
|
|
105
|
+
className: "mt-2 font-mono text-4xl font-medium tabular-nums text-white sm:text-[46px]",
|
|
106
|
+
children: fmtTime(elapsed)
|
|
107
|
+
})
|
|
108
|
+
]
|
|
109
|
+
}),
|
|
110
|
+
/*#__PURE__*/ jsx(Waveform, {}),
|
|
111
|
+
description && /*#__PURE__*/ jsx("p", {
|
|
112
|
+
className: "max-w-[270px] text-center text-sm leading-relaxed text-white/70",
|
|
113
|
+
children: description
|
|
114
|
+
}),
|
|
115
|
+
/*#__PURE__*/ jsx("button", {
|
|
116
|
+
type: "button",
|
|
117
|
+
onClick: onStop,
|
|
118
|
+
className: "mt-1.5 grid h-16 w-16 place-items-center rounded-full bg-white shadow-[0_6px_20px_-4px_rgba(0,0,0,0.5)]",
|
|
119
|
+
"aria-label": stopLabel,
|
|
120
|
+
children: /*#__PURE__*/ jsx("span", {
|
|
121
|
+
className: "h-6 w-6 rounded-md bg-destructive"
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
]
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export { RecordingOverlay };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface SplitWorkspaceProps {
|
|
3
|
+
media: ReactNode;
|
|
4
|
+
panel: ReactNode;
|
|
5
|
+
overlay?: ReactNode;
|
|
6
|
+
back?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export declare function SplitWorkspace({ media, panel, overlay, back, }: SplitWorkspaceProps): import("react").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=split-workspace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"split-workspace.d.ts","sourceRoot":"","sources":["../src/split-workspace.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,KAAK,EACL,OAAO,EACP,IAAI,GACL,EAAE,mBAAmB,+BAuCrB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { useIsDesktop } from '@lindaui/ui/use-media-query';
|
|
4
|
+
|
|
5
|
+
function SplitWorkspace({ media, panel, overlay, back }) {
|
|
6
|
+
const isDesktop = useIsDesktop();
|
|
7
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
8
|
+
className: "relative flex-1 min-h-0 overflow-hidden",
|
|
9
|
+
children: [
|
|
10
|
+
isDesktop ? /* Desktop: two-column grid */ /*#__PURE__*/ jsxs("div", {
|
|
11
|
+
className: "grid grid-cols-2 h-full",
|
|
12
|
+
children: [
|
|
13
|
+
/*#__PURE__*/ jsx("div", {
|
|
14
|
+
className: "relative border-r overflow-hidden",
|
|
15
|
+
style: {
|
|
16
|
+
borderColor: "var(--viewer-border)"
|
|
17
|
+
},
|
|
18
|
+
children: media
|
|
19
|
+
}),
|
|
20
|
+
/*#__PURE__*/ jsx("div", {
|
|
21
|
+
className: "flex flex-col bg-background h-full min-h-0 overflow-hidden px-0 sm:px-0",
|
|
22
|
+
children: panel
|
|
23
|
+
})
|
|
24
|
+
]
|
|
25
|
+
}) : /* Mobile: media top, panel stacked below */ /*#__PURE__*/ jsxs("div", {
|
|
26
|
+
className: "flex flex-col h-full",
|
|
27
|
+
children: [
|
|
28
|
+
/*#__PURE__*/ jsx("div", {
|
|
29
|
+
className: "relative min-h-[40%] flex-1 min-h-0 overflow-hidden",
|
|
30
|
+
children: media
|
|
31
|
+
}),
|
|
32
|
+
/*#__PURE__*/ jsx("div", {
|
|
33
|
+
className: "rounded-t-2xl bg-background shadow-lg overflow-y-auto max-h-[65%] sm:max-h-[60%]",
|
|
34
|
+
children: panel
|
|
35
|
+
})
|
|
36
|
+
]
|
|
37
|
+
}),
|
|
38
|
+
back && /*#__PURE__*/ jsx("div", {
|
|
39
|
+
className: "absolute left-3.5 top-3 z-40",
|
|
40
|
+
children: back
|
|
41
|
+
}),
|
|
42
|
+
overlay && /*#__PURE__*/ jsx("div", {
|
|
43
|
+
className: "absolute inset-0 z-[60]",
|
|
44
|
+
children: overlay
|
|
45
|
+
})
|
|
46
|
+
]
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export { SplitWorkspace };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface StatCardDelta {
|
|
3
|
+
value: string;
|
|
4
|
+
trend: "up" | "down" | "neutral";
|
|
5
|
+
}
|
|
6
|
+
export interface StatCardSparkline {
|
|
7
|
+
data: Array<Record<string, number>>;
|
|
8
|
+
dataKey: string;
|
|
9
|
+
color?: string;
|
|
10
|
+
}
|
|
11
|
+
export type StatCardTone = "primary" | "success" | "warning" | "danger" | "neutral";
|
|
12
|
+
export interface StatCardProps {
|
|
13
|
+
label: ReactNode;
|
|
14
|
+
value: ReactNode;
|
|
15
|
+
delta?: StatCardDelta;
|
|
16
|
+
description?: ReactNode;
|
|
17
|
+
icon?: ReactNode;
|
|
18
|
+
sparkline?: StatCardSparkline;
|
|
19
|
+
/** "featured" = icono prominente arriba-izquierda + delta arriba-derecha +
|
|
20
|
+
* valor grande + label abajo (estilo dashboard). Default = icono inline. */
|
|
21
|
+
variant?: "default" | "featured";
|
|
22
|
+
/** Tinte del icon box (y del valor en featured). Solo aplica a featured. */
|
|
23
|
+
tone?: StatCardTone;
|
|
24
|
+
className?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function StatCard({ label, value, delta, description, icon, sparkline, variant, tone, className, }: StatCardProps): import("react").JSX.Element;
|
|
27
|
+
//# sourceMappingURL=stat-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stat-card.d.ts","sourceRoot":"","sources":["../src/stat-card.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAOvC,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEpF,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B;iFAC6E;IAC7E,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACjC,4EAA4E;IAC5E,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAsDD,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,KAAK,EACL,KAAK,EACL,WAAW,EACX,IAAI,EACJ,SAAS,EACT,OAAmB,EACnB,IAAgB,EAChB,SAAc,GACf,EAAE,aAAa,+BA6Cf"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import { Minus, TrendingDown, TrendingUp } from 'lucide-react';
|
|
4
|
+
import { Card, CardContent, CardHeader, CardTitle } from '@lindaui/ui/card';
|
|
5
|
+
import { Badge } from '@lindaui/ui/badge';
|
|
6
|
+
import { ChartContainer } from '@lindaui/ui/chart';
|
|
7
|
+
import { LineChart, Line } from 'recharts';
|
|
8
|
+
|
|
9
|
+
const trendIcon = {
|
|
10
|
+
up: /*#__PURE__*/ jsx(TrendingUp, {
|
|
11
|
+
className: "h-3 w-3"
|
|
12
|
+
}),
|
|
13
|
+
down: /*#__PURE__*/ jsx(TrendingDown, {
|
|
14
|
+
className: "h-3 w-3"
|
|
15
|
+
}),
|
|
16
|
+
neutral: /*#__PURE__*/ jsx(Minus, {
|
|
17
|
+
className: "h-3 w-3"
|
|
18
|
+
})
|
|
19
|
+
};
|
|
20
|
+
const trendVariant = {
|
|
21
|
+
up: "success",
|
|
22
|
+
down: "danger",
|
|
23
|
+
neutral: "default"
|
|
24
|
+
};
|
|
25
|
+
// Tonos via arbitrary values sobre los tokens canónicos (robustos: no dependen
|
|
26
|
+
// de que HeroUI exponga text-success/text-warning como utilities).
|
|
27
|
+
const toneStyles = {
|
|
28
|
+
primary: {
|
|
29
|
+
box: "bg-[var(--primary)]/10 text-[var(--primary)]",
|
|
30
|
+
value: "text-[var(--primary)]"
|
|
31
|
+
},
|
|
32
|
+
success: {
|
|
33
|
+
box: "bg-[var(--success)]/12 text-[var(--success)]",
|
|
34
|
+
value: "text-[var(--success)]"
|
|
35
|
+
},
|
|
36
|
+
warning: {
|
|
37
|
+
box: "bg-[var(--warning)]/12 text-[var(--warning)]",
|
|
38
|
+
value: "text-[var(--warning)]"
|
|
39
|
+
},
|
|
40
|
+
danger: {
|
|
41
|
+
box: "bg-[var(--destructive)]/10 text-[var(--destructive)]",
|
|
42
|
+
value: "text-[var(--destructive)]"
|
|
43
|
+
},
|
|
44
|
+
neutral: {
|
|
45
|
+
box: "bg-secondary text-muted-foreground",
|
|
46
|
+
value: "text-foreground"
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
function DeltaBadge({ delta }) {
|
|
50
|
+
return /*#__PURE__*/ jsx(Badge, {
|
|
51
|
+
variant: trendVariant[delta.trend],
|
|
52
|
+
children: /*#__PURE__*/ jsxs("span", {
|
|
53
|
+
className: "flex items-center gap-0.5",
|
|
54
|
+
children: [
|
|
55
|
+
trendIcon[delta.trend],
|
|
56
|
+
delta.value
|
|
57
|
+
]
|
|
58
|
+
})
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function Sparkline({ sparkline }) {
|
|
62
|
+
const config = {
|
|
63
|
+
[sparkline.dataKey]: {
|
|
64
|
+
color: sparkline.color ?? "var(--chart-1)"
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
return /*#__PURE__*/ jsx(ChartContainer, {
|
|
68
|
+
config: config,
|
|
69
|
+
className: "mt-3 h-12 w-full",
|
|
70
|
+
children: /*#__PURE__*/ jsx(LineChart, {
|
|
71
|
+
data: sparkline.data,
|
|
72
|
+
children: /*#__PURE__*/ jsx(Line, {
|
|
73
|
+
type: "monotone",
|
|
74
|
+
dataKey: sparkline.dataKey,
|
|
75
|
+
stroke: sparkline.color ?? "var(--chart-1)",
|
|
76
|
+
strokeWidth: 2,
|
|
77
|
+
dot: false
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function StatCard({ label, value, delta, description, icon, sparkline, variant = "default", tone = "neutral", className = "" }) {
|
|
83
|
+
if (variant === "featured") {
|
|
84
|
+
const t = toneStyles[tone];
|
|
85
|
+
return /*#__PURE__*/ jsx(Card, {
|
|
86
|
+
className: className,
|
|
87
|
+
children: /*#__PURE__*/ jsxs(CardContent, {
|
|
88
|
+
className: "p-5",
|
|
89
|
+
children: [
|
|
90
|
+
/*#__PURE__*/ jsxs("div", {
|
|
91
|
+
className: "flex items-start justify-between gap-2",
|
|
92
|
+
children: [
|
|
93
|
+
icon && /*#__PURE__*/ jsx("div", {
|
|
94
|
+
className: `grid size-11 shrink-0 place-items-center rounded-xl ${t.box}`,
|
|
95
|
+
children: icon
|
|
96
|
+
}),
|
|
97
|
+
delta && /*#__PURE__*/ jsx(DeltaBadge, {
|
|
98
|
+
delta: delta
|
|
99
|
+
})
|
|
100
|
+
]
|
|
101
|
+
}),
|
|
102
|
+
/*#__PURE__*/ jsx("div", {
|
|
103
|
+
className: `mt-4 text-3xl font-semibold tabular-nums ${t.value}`,
|
|
104
|
+
children: value
|
|
105
|
+
}),
|
|
106
|
+
/*#__PURE__*/ jsx("div", {
|
|
107
|
+
className: "mt-1 text-sm text-muted-foreground",
|
|
108
|
+
children: label
|
|
109
|
+
}),
|
|
110
|
+
description && /*#__PURE__*/ jsx("p", {
|
|
111
|
+
className: "mt-1.5 text-xs text-muted-foreground",
|
|
112
|
+
children: description
|
|
113
|
+
}),
|
|
114
|
+
sparkline && /*#__PURE__*/ jsx(Sparkline, {
|
|
115
|
+
sparkline: sparkline
|
|
116
|
+
})
|
|
117
|
+
]
|
|
118
|
+
})
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return /*#__PURE__*/ jsxs(Card, {
|
|
122
|
+
className: className,
|
|
123
|
+
children: [
|
|
124
|
+
/*#__PURE__*/ jsx(CardHeader, {
|
|
125
|
+
className: "pb-2",
|
|
126
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
127
|
+
className: "flex items-center justify-between gap-2",
|
|
128
|
+
children: [
|
|
129
|
+
/*#__PURE__*/ jsx(CardTitle, {
|
|
130
|
+
className: "text-sm font-medium text-muted-foreground",
|
|
131
|
+
children: label
|
|
132
|
+
}),
|
|
133
|
+
icon && /*#__PURE__*/ jsx("div", {
|
|
134
|
+
className: "h-4 w-4 text-muted-foreground",
|
|
135
|
+
children: icon
|
|
136
|
+
})
|
|
137
|
+
]
|
|
138
|
+
})
|
|
139
|
+
}),
|
|
140
|
+
/*#__PURE__*/ jsxs(CardContent, {
|
|
141
|
+
className: "pt-0",
|
|
142
|
+
children: [
|
|
143
|
+
/*#__PURE__*/ jsx("div", {
|
|
144
|
+
className: "text-2xl font-semibold tabular-nums sm:text-3xl",
|
|
145
|
+
children: value
|
|
146
|
+
}),
|
|
147
|
+
delta && /*#__PURE__*/ jsx("div", {
|
|
148
|
+
className: "mt-1 flex items-center gap-1",
|
|
149
|
+
children: /*#__PURE__*/ jsx(DeltaBadge, {
|
|
150
|
+
delta: delta
|
|
151
|
+
})
|
|
152
|
+
}),
|
|
153
|
+
description && /*#__PURE__*/ jsx("p", {
|
|
154
|
+
className: "mt-1.5 text-xs text-muted-foreground",
|
|
155
|
+
children: description
|
|
156
|
+
}),
|
|
157
|
+
sparkline && /*#__PURE__*/ jsx(Sparkline, {
|
|
158
|
+
sparkline: sparkline
|
|
159
|
+
})
|
|
160
|
+
]
|
|
161
|
+
})
|
|
162
|
+
]
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export { StatCard };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface StatsGridProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
columns?: 2 | 3 | 4;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function StatsGrid({ children, columns, className }: StatsGridProps): import("react").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=stats-grid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats-grid.d.ts","sourceRoot":"","sources":["../src/stats-grid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAQD,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,OAAW,EAAE,SAAc,EAAE,EAAE,cAAc,+BAQlF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
const lgColsClass = {
|
|
4
|
+
2: "lg:grid-cols-2",
|
|
5
|
+
3: "lg:grid-cols-3",
|
|
6
|
+
4: "lg:grid-cols-4"
|
|
7
|
+
};
|
|
8
|
+
function StatsGrid({ children, columns = 4, className = "" }) {
|
|
9
|
+
return /*#__PURE__*/ jsx("div", {
|
|
10
|
+
className: `grid gap-4 grid-cols-1 sm:grid-cols-2 ${lgColsClass[columns]} ${className}`,
|
|
11
|
+
children: children
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { StatsGrid };
|
package/package.json
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lindaui/blocks",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Composed UI sections (auth, lists, master-detail, charts) built on @lindaui/ui — importable npm package, not a copy-paste registry.",
|
|
5
|
+
"author": "Franco Carballar <francocarballar@gmail.com>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/francocarballar/ts-design-system.git",
|
|
10
|
+
"directory": "packages/blocks"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"sideEffects": false,
|
|
16
|
+
"type": "module",
|
|
17
|
+
"exports": {
|
|
18
|
+
"./login-form": {
|
|
19
|
+
"types": "./dist/login-form.d.ts",
|
|
20
|
+
"import": "./dist/login-form.js"
|
|
21
|
+
},
|
|
22
|
+
"./list-item": {
|
|
23
|
+
"types": "./dist/list-item.d.ts",
|
|
24
|
+
"import": "./dist/list-item.js"
|
|
25
|
+
},
|
|
26
|
+
"./list-pane": {
|
|
27
|
+
"types": "./dist/list-pane.d.ts",
|
|
28
|
+
"import": "./dist/list-pane.js"
|
|
29
|
+
},
|
|
30
|
+
"./detail-panel": {
|
|
31
|
+
"types": "./dist/detail-panel.d.ts",
|
|
32
|
+
"import": "./dist/detail-panel.js"
|
|
33
|
+
},
|
|
34
|
+
"./confirm-dialog": {
|
|
35
|
+
"types": "./dist/confirm-dialog.d.ts",
|
|
36
|
+
"import": "./dist/confirm-dialog.js"
|
|
37
|
+
},
|
|
38
|
+
"./image-viewer": {
|
|
39
|
+
"types": "./dist/image-viewer.d.ts",
|
|
40
|
+
"import": "./dist/image-viewer.js"
|
|
41
|
+
},
|
|
42
|
+
"./split-workspace": {
|
|
43
|
+
"types": "./dist/split-workspace.d.ts",
|
|
44
|
+
"import": "./dist/split-workspace.js"
|
|
45
|
+
},
|
|
46
|
+
"./document-panel": {
|
|
47
|
+
"types": "./dist/document-panel.d.ts",
|
|
48
|
+
"import": "./dist/document-panel.js"
|
|
49
|
+
},
|
|
50
|
+
"./document-reader": {
|
|
51
|
+
"types": "./dist/document-reader.d.ts",
|
|
52
|
+
"import": "./dist/document-reader.js"
|
|
53
|
+
},
|
|
54
|
+
"./recording-overlay": {
|
|
55
|
+
"types": "./dist/recording-overlay.d.ts",
|
|
56
|
+
"import": "./dist/recording-overlay.js"
|
|
57
|
+
},
|
|
58
|
+
"./field-array-form": {
|
|
59
|
+
"types": "./dist/field-array-form.d.ts",
|
|
60
|
+
"import": "./dist/field-array-form.js"
|
|
61
|
+
},
|
|
62
|
+
"./auth-provider": {
|
|
63
|
+
"types": "./dist/auth-provider.d.ts",
|
|
64
|
+
"import": "./dist/auth-provider.js"
|
|
65
|
+
},
|
|
66
|
+
"./auth-layout": {
|
|
67
|
+
"types": "./dist/auth-layout.d.ts",
|
|
68
|
+
"import": "./dist/auth-layout.js"
|
|
69
|
+
},
|
|
70
|
+
"./area-chart": {
|
|
71
|
+
"types": "./dist/area-chart.d.ts",
|
|
72
|
+
"import": "./dist/area-chart.js"
|
|
73
|
+
},
|
|
74
|
+
"./bar-chart": {
|
|
75
|
+
"types": "./dist/bar-chart.d.ts",
|
|
76
|
+
"import": "./dist/bar-chart.js"
|
|
77
|
+
},
|
|
78
|
+
"./line-chart": {
|
|
79
|
+
"types": "./dist/line-chart.d.ts",
|
|
80
|
+
"import": "./dist/line-chart.js"
|
|
81
|
+
},
|
|
82
|
+
"./pie-chart": {
|
|
83
|
+
"types": "./dist/pie-chart.d.ts",
|
|
84
|
+
"import": "./dist/pie-chart.js"
|
|
85
|
+
},
|
|
86
|
+
"./radar-chart": {
|
|
87
|
+
"types": "./dist/radar-chart.d.ts",
|
|
88
|
+
"import": "./dist/radar-chart.js"
|
|
89
|
+
},
|
|
90
|
+
"./radial-chart": {
|
|
91
|
+
"types": "./dist/radial-chart.d.ts",
|
|
92
|
+
"import": "./dist/radial-chart.js"
|
|
93
|
+
},
|
|
94
|
+
"./stat-card": {
|
|
95
|
+
"types": "./dist/stat-card.d.ts",
|
|
96
|
+
"import": "./dist/stat-card.js"
|
|
97
|
+
},
|
|
98
|
+
"./chart-card": {
|
|
99
|
+
"types": "./dist/chart-card.d.ts",
|
|
100
|
+
"import": "./dist/chart-card.js"
|
|
101
|
+
},
|
|
102
|
+
"./stats-grid": {
|
|
103
|
+
"types": "./dist/stats-grid.d.ts",
|
|
104
|
+
"import": "./dist/stats-grid.js"
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"files": [
|
|
108
|
+
"dist",
|
|
109
|
+
"LICENSE",
|
|
110
|
+
"README.md"
|
|
111
|
+
],
|
|
112
|
+
"peerDependencies": {
|
|
113
|
+
"react": ">=19",
|
|
114
|
+
"react-dom": ">=19",
|
|
115
|
+
"react-hook-form": ">=7",
|
|
116
|
+
"lucide-react": ">=0.4",
|
|
117
|
+
"recharts": ">=3",
|
|
118
|
+
"@lindaui/ui": "*",
|
|
119
|
+
"@lindaui/tokens": "*"
|
|
120
|
+
},
|
|
121
|
+
"devDependencies": {
|
|
122
|
+
"bunchee": "^6.0.0",
|
|
123
|
+
"vitest": "^2.0.0",
|
|
124
|
+
"vite": "^6.4.3",
|
|
125
|
+
"@vitejs/plugin-react": "^4.3.0",
|
|
126
|
+
"@testing-library/react": "^16.0.0",
|
|
127
|
+
"@testing-library/user-event": "^14.5.0",
|
|
128
|
+
"@testing-library/jest-dom": "^6.4.0",
|
|
129
|
+
"jsdom": "^24.0.0",
|
|
130
|
+
"react": "^19.0.0",
|
|
131
|
+
"react-dom": "^19.0.0",
|
|
132
|
+
"@types/react": "^19.0.0",
|
|
133
|
+
"@types/react-dom": "^19.0.0",
|
|
134
|
+
"react-hook-form": "^7.53.0",
|
|
135
|
+
"lucide-react": "^0.460.0",
|
|
136
|
+
"recharts": "^3.9.0",
|
|
137
|
+
"zod": "^3.23.0",
|
|
138
|
+
"@hookform/resolvers": "^3.9.0",
|
|
139
|
+
"typescript": "^6.0.3",
|
|
140
|
+
"@lindaui/ui": "0.0.2",
|
|
141
|
+
"@lindaui/tokens": "0.0.2"
|
|
142
|
+
},
|
|
143
|
+
"scripts": {
|
|
144
|
+
"build": "bunchee --no-dts && tsc -p tsconfig.build.json",
|
|
145
|
+
"dev": "bunchee --watch",
|
|
146
|
+
"test": "vitest run",
|
|
147
|
+
"test:watch": "vitest"
|
|
148
|
+
}
|
|
149
|
+
}
|