@conatel-sa/react-ui 0.2.3 → 0.2.5
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/README.md +42 -23
- package/dist/cards.d.ts +37 -0
- package/dist/cards.mjs +299 -0
- package/dist/cards.umd.js +346 -0
- package/dist/dialogs.d.ts +25 -0
- package/dist/dialogs.mjs +194 -0
- package/dist/dialogs.umd.js +246 -0
- package/dist/forms.d.ts +104 -0
- package/dist/forms.mjs +585 -0
- package/dist/forms.umd.js +626 -0
- package/dist/icons.d.ts +50 -0
- package/dist/icons.mjs +149 -0
- package/dist/icons.umd.js +187 -0
- package/dist/index.css +214 -0
- package/dist/index.mjs +73 -1
- package/dist/material-symbols.css +20 -0
- package/dist/metrics.d.ts +19 -0
- package/dist/metrics.mjs +94 -0
- package/dist/metrics.umd.js +143 -0
- package/dist/status.d.ts +16 -0
- package/dist/status.mjs +117 -0
- package/dist/status.umd.js +166 -0
- package/package.json +42 -4
package/README.md
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
# @conatel-sa/react-ui
|
|
2
2
|
|
|
3
|
-
Biblioteca de componentes React para productos **Conatel** y **Vivion**.
|
|
3
|
+
Biblioteca de componentes React para productos **Conatel** y **Vivion**. Más de 20 componentes UI listos para usar, con soporte de theming por marca mediante CSS custom properties. Export opcional de iconos (`./icons`).
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Instalación
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install @conatel-sa/react-ui
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
## Uso
|
|
11
|
+
## Uso rápido
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Importá el CSS de tokens **una sola vez** en el entry point de tu aplicación:
|
|
14
14
|
|
|
15
15
|
```tsx
|
|
16
16
|
// main.tsx
|
|
17
17
|
import '@conatel-sa/react-ui/dist/index.css';
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
Luego
|
|
20
|
+
Luego usá los componentes envueltos en un `ThemeProvider`:
|
|
21
21
|
|
|
22
22
|
```tsx
|
|
23
23
|
import { ThemeProvider, Button, Card, Badge } from '@conatel-sa/react-ui';
|
|
@@ -36,12 +36,12 @@ function App() {
|
|
|
36
36
|
|
|
37
37
|
## Theming
|
|
38
38
|
|
|
39
|
-
La
|
|
39
|
+
La librería soporta dos temas de marca que se aplican a todos los componentes:
|
|
40
40
|
|
|
41
41
|
| Tema | Color primario | Uso |
|
|
42
42
|
|---|---|---|
|
|
43
43
|
| `conatel` | `#CC032E` | Productos Conatel |
|
|
44
|
-
| `vivion` | `#
|
|
44
|
+
| `vivion` | `#0098D4` | Productos Vivion |
|
|
45
45
|
|
|
46
46
|
```tsx
|
|
47
47
|
<ThemeProvider theme="vivion">
|
|
@@ -51,7 +51,7 @@ La libreria soporta dos temas de marca que se aplican a todos los componentes:
|
|
|
51
51
|
|
|
52
52
|
## Componentes disponibles
|
|
53
53
|
|
|
54
|
-
###
|
|
54
|
+
### Tipografía
|
|
55
55
|
`Heading` - `Text`
|
|
56
56
|
|
|
57
57
|
### Formularios
|
|
@@ -63,29 +63,48 @@ La libreria soporta dos temas de marca que se aplican a todos los componentes:
|
|
|
63
63
|
### Contenedores
|
|
64
64
|
`Card` - `CardHeader` - `CardBody` - `CardFooter` - `Modal`
|
|
65
65
|
|
|
66
|
-
###
|
|
66
|
+
### Navegación
|
|
67
67
|
`Navbar` - `NavItem` - `Tabs` - `TabList` - `Tab` - `TabPanel`
|
|
68
68
|
|
|
69
69
|
### Datos
|
|
70
70
|
`Table` - `TableHead` - `TableBody` - `TableRow` - `TableCell` - `TableHeaderCell`
|
|
71
71
|
|
|
72
|
-
###
|
|
73
|
-
`Avatar` - `Divider` - `EmptyState` - `Button`
|
|
72
|
+
### Miscelánea
|
|
73
|
+
`Avatar` - `Divider` - `EmptyState` - `Button` - `Sidebar` - `SidebarItem` - `Toast` - `ScoreSelector`
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
### Iconos (subpath `@conatel-sa/react-ui/icons`)
|
|
76
|
+
|
|
77
|
+
Material Symbols y envoltorio opcional para `lucide-react`:
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
import { Icon, IconProvider } from '@conatel-sa/react-ui/icons';
|
|
81
|
+
import '@conatel-sa/react-ui/dist/material-symbols.css';
|
|
82
|
+
|
|
83
|
+
function WithIcons() {
|
|
84
|
+
return (
|
|
85
|
+
<ThemeProvider theme="conatel">
|
|
86
|
+
<IconProvider injectStylesheet defaultSize="md">
|
|
87
|
+
<Icon name="search" size="md" />
|
|
88
|
+
</IconProvider>
|
|
89
|
+
</ThemeProvider>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`lucide-react` es opcional (solo si usás `LucideIcon`).
|
|
76
95
|
|
|
77
|
-
|
|
96
|
+
## Subpaquetes opcionales
|
|
78
97
|
|
|
79
|
-
|
|
98
|
+
| Subpath | Contenido resumido |
|
|
99
|
+
|---------|---------------------|
|
|
100
|
+
| `@conatel-sa/react-ui/forms` | `PasswordInput`, `MultiSelectDropdown` |
|
|
101
|
+
| `@conatel-sa/react-ui/cards` | `ServiceCard`, `FeatureCard`, `ChangelogPanel`, `ArtifactReportCard` |
|
|
102
|
+
| `@conatel-sa/react-ui/dialogs` | `ChangelogDialog` (requiere `react-dom`) |
|
|
103
|
+
| `@conatel-sa/react-ui/metrics` | `StatInline`, `MiniMeter` |
|
|
104
|
+
| `@conatel-sa/react-ui/status` | `StatusSummaryPopover` |
|
|
80
105
|
|
|
81
|
-
|
|
106
|
+
En las demos HTML, `library-gallery-new.html` carga `dist/forms.umd.js`, `cards.umd.js`, `dialogs.umd.js`, `metrics.umd.js`, `status.umd.js` (además de `icons.umd.js`) y fusiona los globales en `window.ReactLibrary`. Ver `docs/SUBPACKAGES.md` en el workspace react-ui.
|
|
82
107
|
|
|
83
|
-
|
|
84
|
-
|---|---|
|
|
85
|
-
| Build de la libreria | `docker compose run --rm app npm run build` |
|
|
86
|
-
| Storybook | `docker compose up storybook` |
|
|
87
|
-
| Dev server | `docker compose up` |
|
|
88
|
-
| Lint | `docker compose run --rm app npm run lint` |
|
|
89
|
-
| Tests | `docker compose run --rm app npm test` |
|
|
108
|
+
## TypeScript
|
|
90
109
|
|
|
91
|
-
|
|
110
|
+
La librería incluye tipos. No se requiere `@types` adicional para este paquete.
|
package/dist/cards.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export type ServiceCardStatus = 'active' | 'degraded' | 'error' | 'info';
|
|
4
|
+
export type ServiceCardProps = {
|
|
5
|
+
icon?: string;
|
|
6
|
+
title: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
status?: ServiceCardStatus;
|
|
9
|
+
count?: number;
|
|
10
|
+
onClick?: () => void;
|
|
11
|
+
};
|
|
12
|
+
export declare function ServiceCard(props: ServiceCardProps): JSX.Element;
|
|
13
|
+
|
|
14
|
+
export type FeatureCardProps = {
|
|
15
|
+
title: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
icon?: string;
|
|
18
|
+
corner?: ReactNode;
|
|
19
|
+
href?: string;
|
|
20
|
+
onClick?: () => void;
|
|
21
|
+
children?: ReactNode;
|
|
22
|
+
style?: CSSProperties;
|
|
23
|
+
className?: string;
|
|
24
|
+
};
|
|
25
|
+
export declare function FeatureCard(props: FeatureCardProps): JSX.Element;
|
|
26
|
+
|
|
27
|
+
export type ChangelogItem = {
|
|
28
|
+
title: string;
|
|
29
|
+
content: ReactNode;
|
|
30
|
+
};
|
|
31
|
+
export type ChangelogPanelProps = { version?: string; items: ChangelogItem[] };
|
|
32
|
+
export declare function ChangelogPanel(props: ChangelogPanelProps): JSX.Element;
|
|
33
|
+
|
|
34
|
+
export type ArtifactStatVariant = 'primary' | 'success' | 'warning' | 'error' | 'info';
|
|
35
|
+
export type ArtifactStat = { label: string; value: number; variant?: ArtifactStatVariant; footer?: ReactNode };
|
|
36
|
+
export type ArtifactReportCardProps = { title?: string; stats: ArtifactStat[] };
|
|
37
|
+
export declare function ArtifactReportCard(props: ArtifactReportCardProps): JSX.Element;
|
package/dist/cards.mjs
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
// src/components/cards/ServiceCard.tsx
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
function statusStyles(status) {
|
|
4
|
+
switch (status) {
|
|
5
|
+
case "active":
|
|
6
|
+
return {
|
|
7
|
+
bg: "var(--color-success-light, rgba(16, 185, 129, 0.1))",
|
|
8
|
+
fg: "var(--color-success, #10b981)",
|
|
9
|
+
label: "OK"
|
|
10
|
+
};
|
|
11
|
+
case "degraded":
|
|
12
|
+
return {
|
|
13
|
+
bg: "var(--color-warning-light, rgba(245, 158, 11, 0.12))",
|
|
14
|
+
fg: "var(--color-warning, #f59e0b)",
|
|
15
|
+
label: "WARN"
|
|
16
|
+
};
|
|
17
|
+
case "error":
|
|
18
|
+
return {
|
|
19
|
+
bg: "var(--color-error-light, rgba(204, 3, 46, 0.12))",
|
|
20
|
+
fg: "var(--color-error, #CC032E)",
|
|
21
|
+
label: "ERROR"
|
|
22
|
+
};
|
|
23
|
+
case "info":
|
|
24
|
+
return {
|
|
25
|
+
bg: "var(--color-info-light, rgba(37, 99, 235, 0.12))",
|
|
26
|
+
fg: "var(--color-info, #2563eb)",
|
|
27
|
+
label: "INFO"
|
|
28
|
+
};
|
|
29
|
+
default:
|
|
30
|
+
return {
|
|
31
|
+
bg: "var(--color-neutral-100, #f5f5f5)",
|
|
32
|
+
fg: "var(--color-text-muted, #6b6b6b)",
|
|
33
|
+
label: "INFO"
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function ServiceCard({
|
|
38
|
+
icon,
|
|
39
|
+
title,
|
|
40
|
+
description,
|
|
41
|
+
status,
|
|
42
|
+
count,
|
|
43
|
+
onClick
|
|
44
|
+
}) {
|
|
45
|
+
const st = statusStyles(status);
|
|
46
|
+
return /* @__PURE__ */ jsxs(
|
|
47
|
+
"div",
|
|
48
|
+
{
|
|
49
|
+
role: onClick ? "button" : void 0,
|
|
50
|
+
tabIndex: onClick ? 0 : void 0,
|
|
51
|
+
onClick,
|
|
52
|
+
onKeyDown: (e) => {
|
|
53
|
+
if (!onClick) return;
|
|
54
|
+
if (e.key === "Enter" || e.key === " ") onClick();
|
|
55
|
+
},
|
|
56
|
+
style: {
|
|
57
|
+
border: "1.5px solid var(--color-border, #e0e0e0)",
|
|
58
|
+
borderRadius: "var(--radius-lg, 8px)",
|
|
59
|
+
background: "var(--color-surface, #ffffff)",
|
|
60
|
+
boxShadow: "var(--shadow-sm, 0 1px 3px rgba(0,0,0,.1))",
|
|
61
|
+
padding: "var(--space-4, 16px)",
|
|
62
|
+
cursor: onClick ? "pointer" : "default"
|
|
63
|
+
},
|
|
64
|
+
children: [
|
|
65
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: "var(--space-3, 12px)" }, children: [
|
|
66
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "var(--space-3, 12px)", flex: 1, minWidth: 0 }, children: [
|
|
67
|
+
icon ? /* @__PURE__ */ jsx(
|
|
68
|
+
"span",
|
|
69
|
+
{
|
|
70
|
+
className: "material-symbols-outlined",
|
|
71
|
+
style: { fontSize: "1.5rem", color: "var(--color-primary, #CC032E)", marginTop: "2px" },
|
|
72
|
+
"aria-hidden": "true",
|
|
73
|
+
children: icon
|
|
74
|
+
}
|
|
75
|
+
) : null,
|
|
76
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "var(--space-1, .25rem)", minWidth: 0 }, children: [
|
|
77
|
+
/* @__PURE__ */ jsx(
|
|
78
|
+
"div",
|
|
79
|
+
{
|
|
80
|
+
style: {
|
|
81
|
+
fontFamily: "var(--font-sans, system-ui)",
|
|
82
|
+
fontSize: "var(--text-base, 15px)",
|
|
83
|
+
fontWeight: "var(--weight-semibold, 600)",
|
|
84
|
+
color: "var(--color-text, #1a1a1a)",
|
|
85
|
+
whiteSpace: "nowrap",
|
|
86
|
+
overflow: "hidden",
|
|
87
|
+
textOverflow: "ellipsis"
|
|
88
|
+
},
|
|
89
|
+
children: title
|
|
90
|
+
}
|
|
91
|
+
),
|
|
92
|
+
description ? /* @__PURE__ */ jsx("div", { style: { fontFamily: "var(--font-sans, system-ui)", fontSize: "var(--text-sm, 13px)", color: "var(--color-text-muted, #757578)", lineHeight: 1.3 }, children: description }) : null
|
|
93
|
+
] })
|
|
94
|
+
] }),
|
|
95
|
+
count != null ? /* @__PURE__ */ jsx(
|
|
96
|
+
"div",
|
|
97
|
+
{
|
|
98
|
+
style: {
|
|
99
|
+
minWidth: "3rem",
|
|
100
|
+
textAlign: "right",
|
|
101
|
+
fontFamily: "var(--font-sans, system-ui)",
|
|
102
|
+
fontSize: "var(--text-sm, 13px)",
|
|
103
|
+
color: "var(--color-text-muted, #757578)",
|
|
104
|
+
fontWeight: "var(--weight-medium, 500)"
|
|
105
|
+
},
|
|
106
|
+
children: count
|
|
107
|
+
}
|
|
108
|
+
) : null
|
|
109
|
+
] }),
|
|
110
|
+
status ? /* @__PURE__ */ jsx("div", { style: { marginTop: "var(--space-3, 12px)" }, children: /* @__PURE__ */ jsx(
|
|
111
|
+
"span",
|
|
112
|
+
{
|
|
113
|
+
style: {
|
|
114
|
+
display: "inline-flex",
|
|
115
|
+
alignItems: "center",
|
|
116
|
+
gap: "var(--space-2, 8px)",
|
|
117
|
+
padding: "var(--space-1, .25rem) var(--space-2, 8px)",
|
|
118
|
+
borderRadius: "var(--radius-full, 9999px)",
|
|
119
|
+
background: st.bg,
|
|
120
|
+
color: st.fg,
|
|
121
|
+
fontFamily: "var(--font-sans, system-ui)",
|
|
122
|
+
fontSize: "var(--text-sm, 13px)",
|
|
123
|
+
fontWeight: "var(--weight-medium, 500)",
|
|
124
|
+
whiteSpace: "nowrap"
|
|
125
|
+
},
|
|
126
|
+
children: st.label
|
|
127
|
+
}
|
|
128
|
+
) }) : null
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// src/components/cards/FeatureCard.tsx
|
|
135
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
136
|
+
var baseCardStyle = {
|
|
137
|
+
position: "relative",
|
|
138
|
+
display: "block",
|
|
139
|
+
border: "1.5px solid var(--color-border, #e0e0e0)",
|
|
140
|
+
borderRadius: "var(--radius-lg, 12px)",
|
|
141
|
+
background: "var(--color-surface, #ffffff)",
|
|
142
|
+
boxShadow: "var(--shadow-sm, 0 1px 3px rgba(0,0,0,.08))",
|
|
143
|
+
padding: "var(--space-4, 16px)",
|
|
144
|
+
textDecoration: "none",
|
|
145
|
+
color: "inherit",
|
|
146
|
+
fontFamily: "var(--font-sans, system-ui)",
|
|
147
|
+
textAlign: "left",
|
|
148
|
+
cursor: "default",
|
|
149
|
+
boxSizing: "border-box"
|
|
150
|
+
};
|
|
151
|
+
function FeatureCard({
|
|
152
|
+
title,
|
|
153
|
+
description,
|
|
154
|
+
icon,
|
|
155
|
+
corner,
|
|
156
|
+
href,
|
|
157
|
+
onClick,
|
|
158
|
+
children,
|
|
159
|
+
style,
|
|
160
|
+
className
|
|
161
|
+
}) {
|
|
162
|
+
const interactive = Boolean(href || onClick);
|
|
163
|
+
const mergedStyle = {
|
|
164
|
+
...baseCardStyle,
|
|
165
|
+
cursor: interactive ? "pointer" : "default",
|
|
166
|
+
...style
|
|
167
|
+
};
|
|
168
|
+
const inner = /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
169
|
+
corner ? /* @__PURE__ */ jsx2(
|
|
170
|
+
"div",
|
|
171
|
+
{
|
|
172
|
+
style: {
|
|
173
|
+
position: "absolute",
|
|
174
|
+
top: "0.75rem",
|
|
175
|
+
right: "0.75rem",
|
|
176
|
+
display: "flex",
|
|
177
|
+
alignItems: "center",
|
|
178
|
+
gap: "0.25rem",
|
|
179
|
+
fontSize: "0.75rem",
|
|
180
|
+
color: "var(--color-text-muted, #757578)"
|
|
181
|
+
},
|
|
182
|
+
children: corner
|
|
183
|
+
}
|
|
184
|
+
) : null,
|
|
185
|
+
icon ? /* @__PURE__ */ jsx2("div", { style: { marginBottom: "var(--space-3, 12px)" }, children: /* @__PURE__ */ jsx2("span", { className: "material-symbols-outlined", style: { fontSize: "2rem", color: "var(--color-primary, #2563eb)" }, "aria-hidden": true, children: icon }) }) : null,
|
|
186
|
+
/* @__PURE__ */ jsx2("div", { style: { fontWeight: 700, fontSize: "var(--text-base, 15px)", color: "var(--color-text, #1a1a1a)", marginBottom: "var(--space-2, 8px)" }, children: title }),
|
|
187
|
+
description ? /* @__PURE__ */ jsx2("div", { style: { fontSize: "var(--text-sm, 13px)", color: "var(--color-text-muted, #757578)", lineHeight: 1.45 }, children: description }) : null,
|
|
188
|
+
children
|
|
189
|
+
] });
|
|
190
|
+
if (href) {
|
|
191
|
+
return /* @__PURE__ */ jsx2("a", { href, className, style: mergedStyle, children: inner });
|
|
192
|
+
}
|
|
193
|
+
if (onClick) {
|
|
194
|
+
return /* @__PURE__ */ jsx2("button", { type: "button", className, style: mergedStyle, onClick, children: inner });
|
|
195
|
+
}
|
|
196
|
+
return /* @__PURE__ */ jsx2("div", { className, style: mergedStyle, children: inner });
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/components/cards/ChangelogPanel.tsx
|
|
200
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
201
|
+
function ChangelogPanel({ version, items }) {
|
|
202
|
+
return /* @__PURE__ */ jsxs3(
|
|
203
|
+
"div",
|
|
204
|
+
{
|
|
205
|
+
style: {
|
|
206
|
+
border: "1.5px solid var(--color-border, #e0e0e0)",
|
|
207
|
+
borderRadius: "var(--radius-lg, 8px)",
|
|
208
|
+
background: "var(--color-surface, #ffffff)",
|
|
209
|
+
boxShadow: "var(--shadow-sm, 0 1px 3px rgba(0,0,0,.1))",
|
|
210
|
+
padding: "var(--space-4, 16px)"
|
|
211
|
+
},
|
|
212
|
+
children: [
|
|
213
|
+
/* @__PURE__ */ jsx3("div", { style: { fontFamily: "var(--font-sans, system-ui)", fontWeight: "var(--weight-semibold, 600)", color: "var(--color-text, #1a1a1a)", fontSize: "var(--text-base, 15px)" }, children: version ? `Changelog ${version}` : "Changelog" }),
|
|
214
|
+
/* @__PURE__ */ jsx3("div", { style: { marginTop: "var(--space-3, 12px)", display: "flex", flexDirection: "column", gap: "var(--space-3, 12px)" }, children: items.map((it, idx) => /* @__PURE__ */ jsxs3("div", { children: [
|
|
215
|
+
/* @__PURE__ */ jsx3("div", { style: { fontFamily: "var(--font-sans, system-ui)", fontWeight: "var(--weight-semibold, 600)", color: "var(--color-text, #1a1a1a)", fontSize: "var(--text-sm, 13px)" }, children: it.title }),
|
|
216
|
+
/* @__PURE__ */ jsx3("div", { style: { fontFamily: "var(--font-sans, system-ui)", color: "var(--color-text-muted, #757578)", fontSize: "var(--text-sm, 13px)", lineHeight: 1.4, marginTop: "var(--space-1, .25rem)" }, children: it.content })
|
|
217
|
+
] }, idx)) })
|
|
218
|
+
]
|
|
219
|
+
}
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/components/cards/ArtifactReportCard.tsx
|
|
224
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
225
|
+
function variantToColors(variant) {
|
|
226
|
+
switch (variant) {
|
|
227
|
+
case "success":
|
|
228
|
+
return { fg: "var(--color-success, #10b981)", bg: "var(--color-success, #10b981)" };
|
|
229
|
+
case "warning":
|
|
230
|
+
return { fg: "var(--color-warning, #f59e0b)", bg: "var(--color-warning, #f59e0b)" };
|
|
231
|
+
case "error":
|
|
232
|
+
return { fg: "var(--color-error, #CC032E)", bg: "var(--color-error, #CC032E)" };
|
|
233
|
+
case "info":
|
|
234
|
+
return { fg: "var(--color-info, #2563eb)", bg: "var(--color-info, #2563eb)" };
|
|
235
|
+
case "primary":
|
|
236
|
+
default:
|
|
237
|
+
return { fg: "var(--color-primary, var(--color-brand, #CC032E))", bg: "var(--color-primary, var(--color-brand, #CC032E))" };
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function ArtifactReportCard({ title, stats }) {
|
|
241
|
+
const max = Math.max(1, ...stats.map((s) => typeof s.value === "number" ? s.value : 0));
|
|
242
|
+
return /* @__PURE__ */ jsxs4(
|
|
243
|
+
"div",
|
|
244
|
+
{
|
|
245
|
+
style: {
|
|
246
|
+
border: "1.5px solid var(--color-border, #e0e0e0)",
|
|
247
|
+
borderRadius: "var(--radius-lg, 8px)",
|
|
248
|
+
background: "var(--color-surface, #ffffff)",
|
|
249
|
+
boxShadow: "var(--shadow-sm, 0 1px 3px rgba(0,0,0,.1))",
|
|
250
|
+
padding: "var(--space-4, 16px)"
|
|
251
|
+
},
|
|
252
|
+
children: [
|
|
253
|
+
title ? /* @__PURE__ */ jsx4("div", { style: { fontFamily: "var(--font-sans, system-ui)", fontWeight: "var(--weight-semibold, 600)", color: "var(--color-text, #1a1a1a)", fontSize: "var(--text-base, 15px)" }, children: title }) : null,
|
|
254
|
+
/* @__PURE__ */ jsx4("div", { style: { marginTop: "var(--space-3, 12px)", display: "flex", flexDirection: "column", gap: "var(--space-3, 12px)" }, children: stats.map((s, idx) => {
|
|
255
|
+
const colors = variantToColors(s.variant);
|
|
256
|
+
const ratio = Math.max(0, Math.min(1, s.value / max));
|
|
257
|
+
return /* @__PURE__ */ jsxs4("div", { style: { display: "flex", flexDirection: "column", gap: "var(--space-2, 8px)" }, children: [
|
|
258
|
+
/* @__PURE__ */ jsxs4("div", { style: { display: "flex", justifyContent: "space-between", gap: "var(--space-2, 8px)" }, children: [
|
|
259
|
+
/* @__PURE__ */ jsx4("div", { style: { fontFamily: "var(--font-sans, system-ui)", color: "var(--color-text-muted, #757578)", fontSize: "var(--text-sm, 13px)", fontWeight: "var(--weight-medium, 500)" }, children: s.label }),
|
|
260
|
+
/* @__PURE__ */ jsx4("div", { style: { fontFamily: "var(--font-sans, system-ui)", color: colors.fg, fontSize: "var(--text-sm, 13px)", fontWeight: "var(--weight-semibold, 600)" }, children: s.value })
|
|
261
|
+
] }),
|
|
262
|
+
/* @__PURE__ */ jsx4(
|
|
263
|
+
"div",
|
|
264
|
+
{
|
|
265
|
+
style: {
|
|
266
|
+
width: "100%",
|
|
267
|
+
height: "10px",
|
|
268
|
+
borderRadius: "var(--radius-full, 9999px)",
|
|
269
|
+
background: "var(--color-neutral-200, rgba(0,0,0,.08))",
|
|
270
|
+
overflow: "hidden"
|
|
271
|
+
},
|
|
272
|
+
"aria-hidden": "true",
|
|
273
|
+
children: /* @__PURE__ */ jsx4(
|
|
274
|
+
"div",
|
|
275
|
+
{
|
|
276
|
+
style: {
|
|
277
|
+
width: `${Math.round(ratio * 100)}%`,
|
|
278
|
+
height: "100%",
|
|
279
|
+
background: colors.bg,
|
|
280
|
+
borderRadius: "inherit",
|
|
281
|
+
transition: "width var(--duration-base, .15s) var(--ease-out, ease) "
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
)
|
|
285
|
+
}
|
|
286
|
+
),
|
|
287
|
+
s.footer ? /* @__PURE__ */ jsx4("div", { style: { fontFamily: "var(--font-sans, system-ui)", color: "var(--color-text-muted, #757578)", fontSize: "var(--text-sm, 13px)", lineHeight: 1.35 }, children: s.footer }) : null
|
|
288
|
+
] }, idx);
|
|
289
|
+
}) })
|
|
290
|
+
]
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
export {
|
|
295
|
+
ArtifactReportCard,
|
|
296
|
+
ChangelogPanel,
|
|
297
|
+
FeatureCard,
|
|
298
|
+
ServiceCard
|
|
299
|
+
};
|