@sia-ui/cli 0.2.1 → 0.3.0
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 -21
- package/dist/index.js +2 -0
- package/dist/registry/package/components/Alert/index.tsx +7 -0
- package/dist/registry/package/components/AmountDisplay/index.tsx +8 -0
- package/dist/registry/package/components/AppShell/index.tsx +413 -3
- package/dist/registry/package/components/AppShell/styles.css +259 -7
- package/dist/registry/package/components/AppShell/tab-bar.tsx +134 -0
- package/dist/registry/package/components/AsyncState/index.tsx +7 -0
- package/dist/registry/package/components/AuditMeta/index.tsx +8 -0
- package/dist/registry/package/components/AuthLayout/index.tsx +7 -0
- package/dist/registry/package/components/Autocomplete/index.tsx +7 -0
- package/dist/registry/package/components/Avatar/index.tsx +333 -12
- package/dist/registry/package/components/Avatar/styles.css +236 -5
- package/dist/registry/package/components/Badge/index.tsx +7 -0
- package/dist/registry/package/components/Button/index.tsx +7 -0
- package/dist/registry/package/components/Calendar/index.tsx +11 -0
- package/dist/registry/package/components/Card/index.tsx +8 -0
- package/dist/registry/package/components/Checkbox/index.tsx +8 -0
- package/dist/registry/package/components/ColorPicker/index.tsx +7 -0
- package/dist/registry/package/components/CommandPalette/index.tsx +7 -0
- package/dist/registry/package/components/ConfirmDialog/index.tsx +7 -0
- package/dist/registry/package/components/Container/index.tsx +7 -0
- package/dist/registry/package/components/Countdown/index.tsx +7 -0
- package/dist/registry/package/components/CrudPage/dialogs.tsx +230 -0
- package/dist/registry/package/components/CrudPage/index.tsx +546 -5
- package/dist/registry/package/components/CrudPage/styles.css +25 -1
- package/dist/registry/package/components/CurrencyInput/index.tsx +7 -0
- package/dist/registry/package/components/DataTable/index.tsx +548 -200
- package/dist/registry/package/components/DataTable/query.ts +68 -0
- package/dist/registry/package/components/DataTable/row-actions.tsx +158 -0
- package/dist/registry/package/components/DataTable/styles.css +285 -73
- package/dist/registry/package/components/DataTable/types.ts +194 -0
- package/dist/registry/package/components/DataTable/values.ts +28 -0
- package/dist/registry/package/components/DatePicker/index.tsx +7 -0
- package/dist/registry/package/components/DateRangeFilter/index.tsx +7 -0
- package/dist/registry/package/components/DateRangePicker/index.tsx +7 -0
- package/dist/registry/package/components/DateTimePicker/index.tsx +7 -0
- package/dist/registry/package/components/Descriptions/index.tsx +7 -0
- package/dist/registry/package/components/Divider/index.tsx +7 -0
- package/dist/registry/package/components/Drawer/index.tsx +8 -0
- package/dist/registry/package/components/DurationDisplay/index.tsx +6 -0
- package/dist/registry/package/components/EmptyState/index.tsx +7 -0
- package/dist/registry/package/components/EntityMeta/index.tsx +7 -0
- package/dist/registry/package/components/ErrorState/index.tsx +8 -0
- package/dist/registry/package/components/EventCalendar/index.tsx +7 -0
- package/dist/registry/package/components/Field/index.tsx +12 -0
- package/dist/registry/package/components/FileUpload/index.tsx +7 -0
- package/dist/registry/package/components/FiltersBar/index.tsx +7 -0
- package/dist/registry/package/components/HoverCard/index.tsx +14 -37
- package/dist/registry/package/components/IconButton/index.tsx +8 -0
- package/dist/registry/package/components/Icons/index.tsx +15 -0
- package/dist/registry/package/components/ImageUpload/index.tsx +7 -0
- package/dist/registry/package/components/Input/index.tsx +7 -0
- package/dist/registry/package/components/JsonEditor/index.tsx +7 -0
- package/dist/registry/package/components/KpiGrid/index.tsx +7 -0
- package/dist/registry/package/components/Label/index.tsx +7 -0
- package/dist/registry/package/components/MarkdownEditor/index.tsx +7 -0
- package/dist/registry/package/components/MiniCalendar/index.tsx +7 -0
- package/dist/registry/package/components/Modal/index.tsx +8 -0
- package/dist/registry/package/components/MonthPicker/index.tsx +7 -0
- package/dist/registry/package/components/MultiSelect/index.tsx +7 -0
- package/dist/registry/package/components/OtpInput/index.tsx +7 -0
- package/dist/registry/package/components/Overlay/index.tsx +34 -24
- package/dist/registry/package/components/PageHeader/index.tsx +7 -0
- package/dist/registry/package/components/PermissionGate/index.tsx +6 -0
- package/dist/registry/package/components/Popover/index.tsx +7 -0
- package/dist/registry/package/components/QrCode/index.tsx +7 -0
- package/dist/registry/package/components/RadioGroup/index.tsx +7 -0
- package/dist/registry/package/components/Rating/index.tsx +6 -0
- package/dist/registry/package/components/ReferenceSelect/index.tsx +7 -0
- package/dist/registry/package/components/RelativeTime/index.tsx +6 -0
- package/dist/registry/package/components/ResizablePanel/index.tsx +7 -0
- package/dist/registry/package/components/Resource/index.tsx +514 -0
- package/dist/registry/package/components/RichTextEditor/index.tsx +7 -0
- package/dist/registry/package/components/SearchInput/index.tsx +8 -0
- package/dist/registry/package/components/Select/index.tsx +11 -0
- package/dist/registry/package/components/Sidebar/index.tsx +489 -113
- package/dist/registry/package/components/Sidebar/styles.css +96 -4
- package/dist/registry/package/components/Skeleton/index.tsx +7 -0
- package/dist/registry/package/components/Spinner/index.tsx +7 -0
- package/dist/registry/package/components/StatCard/index.tsx +7 -0
- package/dist/registry/package/components/Statistic/index.tsx +7 -0
- package/dist/registry/package/components/Switch/index.tsx +7 -0
- package/dist/registry/package/components/Tabs/index.tsx +7 -0
- package/dist/registry/package/components/TagsInput/index.tsx +7 -0
- package/dist/registry/package/components/Textarea/index.tsx +7 -0
- package/dist/registry/package/components/TimePicker/index.tsx +7 -0
- package/dist/registry/package/components/TimeRangePicker/index.tsx +6 -0
- package/dist/registry/package/components/Timeline/index.tsx +7 -0
- package/dist/registry/package/components/Timer/index.tsx +7 -0
- package/dist/registry/package/components/Tour/index.tsx +7 -0
- package/dist/registry/package/components/Transfer/index.tsx +7 -0
- package/dist/registry/package/components/Tree/index.tsx +7 -0
- package/dist/registry/package/components/TreeSelect/index.tsx +7 -0
- package/dist/registry/package/components/Typography/index.tsx +8 -0
- package/dist/registry/package/components/UnsavedChangesGuard/index.tsx +8 -0
- package/dist/registry/package/components/WeekPicker/index.tsx +7 -0
- package/dist/registry/package/components/YearPicker/index.tsx +7 -0
- package/dist/registry/registry.json +69 -14
- package/package.json +14 -14
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import {
|
|
3
|
+
useTableQuery,
|
|
4
|
+
type TableQuery,
|
|
5
|
+
type TableQueryState,
|
|
6
|
+
type TableQueryStorage,
|
|
7
|
+
} from "@sia-ui/headless";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* L'état du tableau dans la barre d'adresse.
|
|
11
|
+
*
|
|
12
|
+
* `history.replaceState` plutôt que `pushState` : trier une colonne trois
|
|
13
|
+
* fois de suite ne doit pas demander trois retours en arrière pour revenir
|
|
14
|
+
* d'où l'on vient.
|
|
15
|
+
*/
|
|
16
|
+
export function createUrlTableStorage(
|
|
17
|
+
mode: "replace" | "push" = "replace",
|
|
18
|
+
): TableQueryStorage {
|
|
19
|
+
return {
|
|
20
|
+
read: () => (typeof window === "undefined" ? "" : window.location.search),
|
|
21
|
+
write: (value) => {
|
|
22
|
+
if (typeof window === "undefined") return;
|
|
23
|
+
const url = `${window.location.pathname}${value ? `?${value}` : ""}${window.location.hash}`;
|
|
24
|
+
if (mode === "push") window.history.pushState(null, "", url);
|
|
25
|
+
else window.history.replaceState(null, "", url);
|
|
26
|
+
},
|
|
27
|
+
subscribe: (listener) => {
|
|
28
|
+
if (typeof window === "undefined") return () => {};
|
|
29
|
+
window.addEventListener("popstate", listener);
|
|
30
|
+
return () => window.removeEventListener("popstate", listener);
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface UseDataTableQueryOptions {
|
|
36
|
+
defaultState?: Partial<TableQueryState>;
|
|
37
|
+
/** `false` garde l'état en mémoire — utile dans une modale. */
|
|
38
|
+
syncUrl?: boolean;
|
|
39
|
+
/** Empile une entrée d'historique à chaque changement. */
|
|
40
|
+
history?: "replace" | "push";
|
|
41
|
+
/** Préfixe des clés, pour deux tableaux sur la même page. */
|
|
42
|
+
prefix?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Tri, filtres et pagination d'un tableau, synchronisés avec l'URL.
|
|
47
|
+
*
|
|
48
|
+
* Le calcul vit dans `@sia-ui/headless`; il n'y a ici que le branchement sur
|
|
49
|
+
* la barre d'adresse, qui est la seule partie propre au navigateur.
|
|
50
|
+
*/
|
|
51
|
+
export function useDataTableQuery(
|
|
52
|
+
options: UseDataTableQueryOptions = {},
|
|
53
|
+
): TableQuery {
|
|
54
|
+
const { defaultState, syncUrl = true, history = "replace", prefix } = options;
|
|
55
|
+
|
|
56
|
+
// Créé une fois : un objet reconstruit à chaque rendu réabonnerait
|
|
57
|
+
// l'écouteur `popstate` en boucle.
|
|
58
|
+
const storage = useMemo(
|
|
59
|
+
() => (syncUrl ? createUrlTableStorage(history) : undefined),
|
|
60
|
+
[history, syncUrl],
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return useTableQuery({
|
|
64
|
+
...(defaultState ? { defaultState } : {}),
|
|
65
|
+
...(storage ? { storage } : {}),
|
|
66
|
+
...(prefix ? { prefix } : {}),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { useState, type ReactNode } from "react";
|
|
2
|
+
import { cn } from "@sia-ui/utils";
|
|
3
|
+
import type { PermissionRule } from "@sia-ui/headless";
|
|
4
|
+
import { Button } from "../Button";
|
|
5
|
+
import { IconButton } from "../IconButton";
|
|
6
|
+
import { DropdownMenu } from "../DropdownMenu";
|
|
7
|
+
import { ConfirmDialog } from "../ConfirmDialog";
|
|
8
|
+
import { MoreHorizontalIcon } from "../Icons";
|
|
9
|
+
import type { RowAction } from "./types";
|
|
10
|
+
|
|
11
|
+
interface RowActionsProps<T> {
|
|
12
|
+
row: T;
|
|
13
|
+
index: number;
|
|
14
|
+
actions: Array<RowAction<T>>;
|
|
15
|
+
inlineLimit: number;
|
|
16
|
+
display: "icon" | "label";
|
|
17
|
+
can: ((rule: PermissionRule) => boolean) | undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Ce qu'on peut faire d'une ligne.
|
|
22
|
+
*
|
|
23
|
+
* Trois choses se décident ici, et aucune n'est cosmétique : ce que la
|
|
24
|
+
* session a le droit de faire, ce qui demande confirmation, et ce qui ne
|
|
25
|
+
* tient plus dans la largeur et doit passer en menu.
|
|
26
|
+
*/
|
|
27
|
+
export function RowActions<T>({
|
|
28
|
+
row,
|
|
29
|
+
index,
|
|
30
|
+
actions,
|
|
31
|
+
inlineLimit,
|
|
32
|
+
display,
|
|
33
|
+
can,
|
|
34
|
+
}: RowActionsProps<T>) {
|
|
35
|
+
// Une confirmation en attente. Une seule à la fois : deux dialogues
|
|
36
|
+
// superposés sur la même ligne n'ont aucun sens.
|
|
37
|
+
const [enAttente, setEnAttente] = useState<RowAction<T> | null>(null);
|
|
38
|
+
|
|
39
|
+
const visibles = actions.filter((action) => {
|
|
40
|
+
if (action.permission !== undefined && can && !can(action.permission)) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
return !action.hidden?.(row, index);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (visibles.length === 0) return null;
|
|
47
|
+
|
|
48
|
+
const declencher = (action: RowAction<T>) => {
|
|
49
|
+
if (action.confirm) {
|
|
50
|
+
setEnAttente(action);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
void action.onSelect(row, index);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const enLigne = visibles.slice(0, inlineLimit);
|
|
57
|
+
const dansLeMenu = visibles.slice(inlineLimit);
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div className="sia-table__actions" onClick={(e) => e.stopPropagation()}>
|
|
61
|
+
{enLigne.map((action) => {
|
|
62
|
+
const desactivee = action.disabled?.(row, index) ?? false;
|
|
63
|
+
const nom =
|
|
64
|
+
typeof action.label === "string" ? action.label : action.key;
|
|
65
|
+
|
|
66
|
+
// Sans icône, on retombe sur le libellé : un bouton vide ne se clique
|
|
67
|
+
// pas, quelle que soit la consigne d'affichage.
|
|
68
|
+
return display === "icon" && action.icon ? (
|
|
69
|
+
<IconButton
|
|
70
|
+
key={action.key}
|
|
71
|
+
label={nom}
|
|
72
|
+
icon={action.icon}
|
|
73
|
+
variant="ghost"
|
|
74
|
+
size="sm"
|
|
75
|
+
disabled={desactivee}
|
|
76
|
+
tooltip={{ content: action.label }}
|
|
77
|
+
onClick={() => declencher(action)}
|
|
78
|
+
/>
|
|
79
|
+
) : (
|
|
80
|
+
<Button
|
|
81
|
+
key={action.key}
|
|
82
|
+
variant="ghost"
|
|
83
|
+
size="sm"
|
|
84
|
+
{...(action.tone ? { tone: action.tone } : {})}
|
|
85
|
+
disabled={desactivee}
|
|
86
|
+
onClick={() => declencher(action)}
|
|
87
|
+
>
|
|
88
|
+
{action.icon}
|
|
89
|
+
{action.label}
|
|
90
|
+
</Button>
|
|
91
|
+
);
|
|
92
|
+
})}
|
|
93
|
+
|
|
94
|
+
{dansLeMenu.length > 0 && (
|
|
95
|
+
<DropdownMenu
|
|
96
|
+
placement="bottom-end"
|
|
97
|
+
items={dansLeMenu.map((action) => ({
|
|
98
|
+
key: action.key,
|
|
99
|
+
label: action.label,
|
|
100
|
+
...(action.icon ? { icon: action.icon } : {}),
|
|
101
|
+
disabled: action.disabled?.(row, index) ?? false,
|
|
102
|
+
danger: action.tone === "danger",
|
|
103
|
+
onSelect: () => declencher(action),
|
|
104
|
+
}))}
|
|
105
|
+
>
|
|
106
|
+
<IconButton
|
|
107
|
+
label="Autres actions"
|
|
108
|
+
icon={<MoreHorizontalIcon />}
|
|
109
|
+
variant="ghost"
|
|
110
|
+
size="sm"
|
|
111
|
+
/>
|
|
112
|
+
</DropdownMenu>
|
|
113
|
+
)}
|
|
114
|
+
|
|
115
|
+
{enAttente?.confirm && (
|
|
116
|
+
<ConfirmDialog
|
|
117
|
+
open
|
|
118
|
+
onOpenChange={(ouvert) => {
|
|
119
|
+
if (!ouvert) setEnAttente(null);
|
|
120
|
+
}}
|
|
121
|
+
title={enAttente.confirm.title}
|
|
122
|
+
{...(enAttente.confirm.description
|
|
123
|
+
? { description: enAttente.confirm.description }
|
|
124
|
+
: {})}
|
|
125
|
+
{...(enAttente.confirm.confirmLabel
|
|
126
|
+
? { confirmLabel: enAttente.confirm.confirmLabel }
|
|
127
|
+
: {})}
|
|
128
|
+
{...(enAttente.confirm.cancelLabel
|
|
129
|
+
? { cancelLabel: enAttente.confirm.cancelLabel }
|
|
130
|
+
: {})}
|
|
131
|
+
tone={enAttente.confirm.destructive ? "danger" : "primary"}
|
|
132
|
+
onConfirm={async () => {
|
|
133
|
+
await enAttente.onSelect(row, index);
|
|
134
|
+
setEnAttente(null);
|
|
135
|
+
}}
|
|
136
|
+
/>
|
|
137
|
+
)}
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Une cellule de carte : libellé au-dessus, valeur en dessous. */
|
|
143
|
+
export function CardMeta({
|
|
144
|
+
label,
|
|
145
|
+
value,
|
|
146
|
+
className,
|
|
147
|
+
}: {
|
|
148
|
+
label: ReactNode;
|
|
149
|
+
value: ReactNode;
|
|
150
|
+
className?: string;
|
|
151
|
+
}) {
|
|
152
|
+
return (
|
|
153
|
+
<div className={cn("sia-table-card__meta", className)}>
|
|
154
|
+
<span className="sia-table-card__label">{label}</span>
|
|
155
|
+
<span className="sia-table-card__value">{value}</span>
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
@@ -1,98 +1,310 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Le tableau de données.
|
|
3
|
+
*
|
|
4
|
+
* Une variable porte la hauteur de ligne — `--sia-table-row-height` — et les
|
|
5
|
+
* trois densités ne font que la redéfinir. Le reste du fichier ne la connaît
|
|
6
|
+
* pas : changer de densité ne touche donc à aucune autre règle.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
.sia-table {
|
|
10
|
+
--sia-table-row-height: 3rem;
|
|
11
|
+
--sia-table-pad-y: .75rem;
|
|
12
|
+
--sia-table-pad-x: .875rem;
|
|
13
|
+
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
gap: .75rem;
|
|
17
|
+
min-width: 0;
|
|
18
|
+
font-size: .875rem;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.sia-table--compact {
|
|
22
|
+
--sia-table-row-height: 2.375rem;
|
|
23
|
+
--sia-table-pad-y: .45rem;
|
|
24
|
+
font-size: .825rem;
|
|
25
|
+
}
|
|
26
|
+
.sia-table--comfortable {
|
|
27
|
+
--sia-table-row-height: 3.75rem;
|
|
28
|
+
--sia-table-pad-y: 1.05rem;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* ── L'en-tête ──────────────────────────────────────────────────────────── */
|
|
32
|
+
|
|
33
|
+
.sia-table__header {
|
|
34
|
+
display: flex;
|
|
35
|
+
align-items: flex-end;
|
|
36
|
+
justify-content: space-between;
|
|
37
|
+
gap: 1rem;
|
|
38
|
+
flex-wrap: wrap;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.sia-table__heading { min-width: 0; display: grid; gap: .15rem; }
|
|
42
|
+
.sia-table__title { margin: 0; font-size: 1.05rem; font-weight: 650; }
|
|
43
|
+
.sia-table__description { margin: 0; color: var(--sia-muted); font-size: .85rem; }
|
|
44
|
+
|
|
45
|
+
.sia-table__tools {
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
gap: .5rem;
|
|
49
|
+
flex-wrap: wrap;
|
|
50
|
+
margin-left: auto;
|
|
51
|
+
}
|
|
52
|
+
.sia-table__actions-bar { display: flex; align-items: center; gap: .5rem; }
|
|
53
|
+
|
|
54
|
+
/* Deux boutons dans un même sillon, avec un repère qui glisse dessous. */
|
|
55
|
+
.sia-table__views {
|
|
56
|
+
display: inline-flex;
|
|
57
|
+
padding: .2rem;
|
|
58
|
+
border: 1px solid var(--sia-border);
|
|
59
|
+
border-radius: var(--sia-radius);
|
|
60
|
+
background: var(--sia-surface);
|
|
61
|
+
}
|
|
62
|
+
.sia-table__view {
|
|
63
|
+
display: grid;
|
|
64
|
+
place-items: center;
|
|
65
|
+
width: 1.9rem;
|
|
66
|
+
height: 1.9rem;
|
|
67
|
+
border: 0;
|
|
68
|
+
border-radius: calc(var(--sia-radius) - .15rem);
|
|
69
|
+
background: transparent;
|
|
70
|
+
color: var(--sia-muted);
|
|
71
|
+
cursor: pointer;
|
|
72
|
+
transition:
|
|
73
|
+
background-color var(--sia-duration-fast) var(--sia-easing-standard),
|
|
74
|
+
color var(--sia-duration-fast) var(--sia-easing-standard);
|
|
75
|
+
}
|
|
76
|
+
.sia-table__view--active {
|
|
77
|
+
background: var(--sia-background);
|
|
78
|
+
color: var(--sia-foreground);
|
|
79
|
+
box-shadow: 0 1px 2px rgb(15 23 42 / .08);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* ── La barre de sélection ──────────────────────────────────────────────── */
|
|
83
|
+
|
|
84
|
+
.sia-table__selection {
|
|
85
|
+
display: flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
gap: .75rem;
|
|
88
|
+
padding: .5rem .875rem;
|
|
89
|
+
border: 1px solid color-mix(in srgb, var(--sia-primary) 30%, transparent);
|
|
90
|
+
border-radius: var(--sia-radius);
|
|
91
|
+
background: color-mix(in srgb, var(--sia-primary) 8%, var(--sia-background));
|
|
92
|
+
/* Elle se glisse entre l'en-tête et le corps : la voir apparaître d'un bloc
|
|
93
|
+
donnerait l'impression que la page a sauté. */
|
|
94
|
+
animation: sia-table-selection var(--sia-duration-base) var(--sia-easing-spring);
|
|
95
|
+
}
|
|
96
|
+
@keyframes sia-table-selection {
|
|
97
|
+
from { opacity: 0; transform: translateY(-.35rem); }
|
|
98
|
+
}
|
|
99
|
+
.sia-table__selection-count {
|
|
100
|
+
color: var(--sia-primary);
|
|
101
|
+
font-weight: 600;
|
|
102
|
+
font-variant-numeric: tabular-nums;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* ── Le tableau ─────────────────────────────────────────────────────────── */
|
|
106
|
+
|
|
107
|
+
.sia-table__scroll {
|
|
108
|
+
min-width: 0;
|
|
109
|
+
overflow: auto;
|
|
110
|
+
border-radius: var(--sia-radius);
|
|
111
|
+
}
|
|
112
|
+
.sia-table--bordered .sia-table__scroll { border: 1px solid var(--sia-border); }
|
|
113
|
+
|
|
114
|
+
.sia-table__table {
|
|
115
|
+
width: 100%;
|
|
116
|
+
border-collapse: separate;
|
|
117
|
+
border-spacing: 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.sia-table__table th {
|
|
121
|
+
padding: var(--sia-table-pad-y) var(--sia-table-pad-x);
|
|
122
|
+
border-bottom: 1px solid var(--sia-border);
|
|
123
|
+
background: var(--sia-surface);
|
|
124
|
+
color: var(--sia-muted);
|
|
125
|
+
font-size: .75rem;
|
|
126
|
+
font-weight: 600;
|
|
127
|
+
letter-spacing: .03em;
|
|
128
|
+
text-align: left;
|
|
129
|
+
text-transform: uppercase;
|
|
130
|
+
white-space: nowrap;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.sia-table__scroll--sticky th {
|
|
134
|
+
position: sticky;
|
|
135
|
+
top: 0;
|
|
136
|
+
z-index: 2;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.sia-table__table td {
|
|
140
|
+
height: var(--sia-table-row-height);
|
|
141
|
+
padding: var(--sia-table-pad-y) var(--sia-table-pad-x);
|
|
142
|
+
border-bottom: 1px solid var(--sia-border);
|
|
143
|
+
vertical-align: middle;
|
|
144
|
+
}
|
|
145
|
+
.sia-table__table tbody tr:last-child td { border-bottom: 0; }
|
|
146
|
+
|
|
147
|
+
.sia-table--striped tbody tr:nth-child(even) td {
|
|
148
|
+
background: color-mix(in srgb, var(--sia-surface) 55%, transparent);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.sia-table__table tbody tr {
|
|
13
152
|
transition: background-color var(--sia-duration-fast) var(--sia-easing-standard);
|
|
14
153
|
}
|
|
154
|
+
.sia-table__table tbody tr:hover td {
|
|
155
|
+
background: color-mix(in srgb, var(--sia-primary) 4%, var(--sia-surface));
|
|
156
|
+
}
|
|
15
157
|
|
|
16
|
-
.sia-
|
|
17
|
-
|
|
158
|
+
.sia-table__row--clickable { cursor: pointer; }
|
|
159
|
+
.sia-table__row--selected td {
|
|
160
|
+
background: color-mix(in srgb, var(--sia-primary) 7%, transparent);
|
|
18
161
|
}
|
|
19
162
|
|
|
20
|
-
.sia-
|
|
21
|
-
|
|
163
|
+
.sia-table__cell--center { text-align: center; }
|
|
164
|
+
.sia-table__cell--end { text-align: right; }
|
|
165
|
+
.sia-table__cell--truncate {
|
|
166
|
+
max-width: 1px;
|
|
167
|
+
overflow: hidden;
|
|
168
|
+
text-overflow: ellipsis;
|
|
169
|
+
white-space: nowrap;
|
|
22
170
|
}
|
|
23
171
|
|
|
172
|
+
.sia-table__cell--select { width: 1px; padding-right: 0; }
|
|
173
|
+
.sia-table__cell--actions { width: 1px; white-space: nowrap; text-align: right; }
|
|
174
|
+
|
|
175
|
+
.sia-table__actions {
|
|
176
|
+
display: inline-flex;
|
|
177
|
+
align-items: center;
|
|
178
|
+
gap: .15rem;
|
|
179
|
+
justify-content: flex-end;
|
|
180
|
+
}
|
|
24
181
|
|
|
25
|
-
/*
|
|
182
|
+
/* Les actions n'apparaissent qu'au survol de leur ligne : une colonne pleine
|
|
183
|
+
de boutons attire l'œil plus que les données. Elles restent visibles au
|
|
184
|
+
clavier, et sur tactile, où il n'y a pas de survol. */
|
|
185
|
+
@media (hover: hover) and (pointer: fine) {
|
|
186
|
+
.sia-table__table tbody .sia-table__actions {
|
|
187
|
+
opacity: .35;
|
|
188
|
+
transition: opacity var(--sia-duration-fast) var(--sia-easing-standard);
|
|
189
|
+
}
|
|
190
|
+
.sia-table__table tbody tr:hover .sia-table__actions,
|
|
191
|
+
.sia-table__table tbody .sia-table__actions:focus-within { opacity: 1; }
|
|
192
|
+
}
|
|
26
193
|
|
|
27
|
-
|
|
194
|
+
/* ── Le tri ─────────────────────────────────────────────────────────────── */
|
|
28
195
|
|
|
29
|
-
.sia-
|
|
196
|
+
.sia-table__sort {
|
|
30
197
|
display: inline-flex;
|
|
31
198
|
align-items: center;
|
|
32
|
-
gap: .
|
|
199
|
+
gap: .3rem;
|
|
33
200
|
padding: 0;
|
|
34
201
|
border: 0;
|
|
35
|
-
background:
|
|
202
|
+
background: none;
|
|
36
203
|
color: inherit;
|
|
37
204
|
font: inherit;
|
|
38
|
-
text-transform: inherit;
|
|
39
205
|
letter-spacing: inherit;
|
|
206
|
+
text-transform: inherit;
|
|
40
207
|
cursor: pointer;
|
|
41
|
-
transition: color var(--sia-duration-fast) var(--sia-easing-standard);
|
|
42
208
|
}
|
|
43
|
-
.sia-
|
|
44
|
-
.sia-
|
|
45
|
-
|
|
46
|
-
/* La flèche n'apparaît qu'au survol ou quand le tri est actif : trois
|
|
47
|
-
chevrons gris en permanence dans un entête n'aident personne. */
|
|
48
|
-
.sia-data-table__arrow {
|
|
209
|
+
.sia-table__sort:hover { color: var(--sia-foreground); }
|
|
210
|
+
.sia-table__sort-icon {
|
|
49
211
|
display: grid;
|
|
50
212
|
place-items: center;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
213
|
+
opacity: .35;
|
|
214
|
+
font-size: .7rem;
|
|
215
|
+
transition: opacity var(--sia-duration-fast) var(--sia-easing-standard);
|
|
216
|
+
}
|
|
217
|
+
.sia-table__sort:hover .sia-table__sort-icon { opacity: .7; }
|
|
218
|
+
[aria-sort] .sia-table__sort { color: var(--sia-primary); }
|
|
219
|
+
[aria-sort] .sia-table__sort-icon { opacity: 1; }
|
|
220
|
+
|
|
221
|
+
/* ── L'apparition des lignes ────────────────────────────────────────────── */
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Chaque ligne arrive quelques millisecondes après la précédente.
|
|
225
|
+
*
|
|
226
|
+
* Le décalage est plafonné : au-delà d'une dizaine de lignes, l'escalier
|
|
227
|
+
* devient une attente. Les suivantes arrivent ensemble, et personne ne le
|
|
228
|
+
* remarque — on ne regarde jamais la vingtième ligne en premier.
|
|
229
|
+
*/
|
|
230
|
+
.sia-table__table tbody tr,
|
|
231
|
+
.sia-table-card {
|
|
232
|
+
animation: sia-table-row var(--sia-duration-base) var(--sia-easing-standard) backwards;
|
|
233
|
+
animation-delay: calc(min(var(--sia-table-row, 0), 10) * 22ms);
|
|
234
|
+
}
|
|
235
|
+
@keyframes sia-table-row {
|
|
236
|
+
from { opacity: 0; transform: translateY(.35rem); }
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.sia-table__row--skeleton { animation: none; }
|
|
240
|
+
|
|
241
|
+
/* ── Les cartes ─────────────────────────────────────────────────────────── */
|
|
242
|
+
|
|
243
|
+
.sia-table__cards {
|
|
244
|
+
display: grid;
|
|
245
|
+
gap: .75rem;
|
|
246
|
+
grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.sia-table-card {
|
|
250
|
+
display: flex;
|
|
251
|
+
flex-direction: column;
|
|
252
|
+
gap: .6rem;
|
|
253
|
+
padding: .875rem 1rem;
|
|
254
|
+
border: 1px solid var(--sia-border);
|
|
255
|
+
border-radius: calc(var(--sia-radius) * 1.25);
|
|
256
|
+
background: var(--sia-background);
|
|
54
257
|
transition:
|
|
55
|
-
|
|
56
|
-
|
|
258
|
+
border-color var(--sia-duration-fast) var(--sia-easing-standard),
|
|
259
|
+
box-shadow var(--sia-duration-base) var(--sia-easing-standard),
|
|
260
|
+
transform var(--sia-duration-fast) var(--sia-easing-standard);
|
|
261
|
+
}
|
|
262
|
+
.sia-table-card--clickable { cursor: pointer; }
|
|
263
|
+
.sia-table-card--clickable:hover {
|
|
264
|
+
border-color: color-mix(in srgb, var(--sia-primary) 35%, var(--sia-border));
|
|
265
|
+
box-shadow: 0 6px 20px rgb(15 23 42 / .07);
|
|
266
|
+
transform: translateY(-2px);
|
|
57
267
|
}
|
|
58
|
-
.sia-data-table__sort:hover .sia-data-table__arrow { opacity: .45; transform: none; }
|
|
59
|
-
.sia-data-table__sort[data-active] .sia-data-table__arrow { opacity: 1; transform: none; }
|
|
60
268
|
|
|
61
|
-
.sia-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
269
|
+
.sia-table-card__title {
|
|
270
|
+
font-weight: 650;
|
|
271
|
+
font-size: .95rem;
|
|
272
|
+
overflow: hidden;
|
|
273
|
+
text-overflow: ellipsis;
|
|
274
|
+
white-space: nowrap;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.sia-table-card__body {
|
|
278
|
+
display: grid;
|
|
279
|
+
gap: .4rem .875rem;
|
|
280
|
+
grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.sia-table-card__meta { display: grid; gap: .1rem; min-width: 0; }
|
|
284
|
+
.sia-table-card__label {
|
|
285
|
+
color: var(--sia-muted);
|
|
286
|
+
font-size: .68rem;
|
|
287
|
+
letter-spacing: .03em;
|
|
288
|
+
text-transform: uppercase;
|
|
289
|
+
}
|
|
290
|
+
.sia-table-card__value {
|
|
291
|
+
overflow: hidden;
|
|
292
|
+
text-overflow: ellipsis;
|
|
293
|
+
white-space: nowrap;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.sia-table-card__footer {
|
|
297
|
+
display: flex;
|
|
298
|
+
justify-content: flex-end;
|
|
299
|
+
padding-top: .35rem;
|
|
300
|
+
border-top: 1px solid var(--sia-border);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.sia-table-card--skeleton { gap: .5rem; }
|
|
304
|
+
|
|
305
|
+
@media (prefers-reduced-motion: reduce) {
|
|
306
|
+
.sia-table__table tbody tr,
|
|
307
|
+
.sia-table-card,
|
|
308
|
+
.sia-table__selection { animation: none; }
|
|
309
|
+
.sia-table-card--clickable:hover { transform: none; }
|
|
98
310
|
}
|