@sentropic/design-system-svelte 0.34.50 → 0.34.52
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 +62 -0
- package/dist/AnomalySwimLaneChart.svelte +10 -1
- package/dist/AnomalySwimLaneChart.svelte.d.ts +2 -0
- package/dist/AnomalySwimLaneChart.svelte.d.ts.map +1 -1
- package/dist/CalendarHeatmapChart.svelte +11 -1
- package/dist/CalendarHeatmapChart.svelte.d.ts +2 -0
- package/dist/CalendarHeatmapChart.svelte.d.ts.map +1 -1
- package/dist/Combobox.svelte +5 -1
- package/dist/Combobox.svelte.d.ts.map +1 -1
- package/dist/ContourChart.svelte +76 -13
- package/dist/ContourChart.svelte.d.ts +3 -1
- package/dist/ContourChart.svelte.d.ts.map +1 -1
- package/dist/CopyButton.svelte +9 -3
- package/dist/CopyButton.svelte.d.ts +1 -0
- package/dist/CopyButton.svelte.d.ts.map +1 -1
- package/dist/Dashboard.svelte +155 -0
- package/dist/Dashboard.svelte.d.ts +21 -0
- package/dist/Dashboard.svelte.d.ts.map +1 -0
- package/dist/DashboardGrid.svelte +237 -0
- package/dist/DashboardGrid.svelte.d.ts +24 -0
- package/dist/DashboardGrid.svelte.d.ts.map +1 -0
- package/dist/DataTable.svelte +3 -1
- package/dist/DataTable.svelte.d.ts +1 -0
- package/dist/DataTable.svelte.d.ts.map +1 -1
- package/dist/DatePicker.svelte +33 -28
- package/dist/DatePicker.svelte.d.ts.map +1 -1
- package/dist/Density2DChart.svelte +10 -1
- package/dist/Density2DChart.svelte.d.ts +2 -0
- package/dist/Density2DChart.svelte.d.ts.map +1 -1
- package/dist/Dropdown.svelte +40 -11
- package/dist/Dropdown.svelte.d.ts +1 -0
- package/dist/Dropdown.svelte.d.ts.map +1 -1
- package/dist/EventFeedPanel.svelte +3 -3
- package/dist/EventFeedPanel.svelte.d.ts +1 -1
- package/dist/EventFeedPanel.svelte.d.ts.map +1 -1
- package/dist/FileUploader.svelte +7 -3
- package/dist/Footer.svelte +75 -11
- package/dist/Footer.svelte.d.ts +16 -6
- package/dist/Footer.svelte.d.ts.map +1 -1
- package/dist/ForceGraph.svelte +9 -3
- package/dist/ForceGraph.svelte.d.ts +4 -0
- package/dist/ForceGraph.svelte.d.ts.map +1 -1
- package/dist/HeatmapChart.svelte +39 -3
- package/dist/HeatmapChart.svelte.d.ts +4 -1
- package/dist/HeatmapChart.svelte.d.ts.map +1 -1
- package/dist/KanbanBoard.svelte +144 -0
- package/dist/KanbanBoard.svelte.d.ts +23 -0
- package/dist/KanbanBoard.svelte.d.ts.map +1 -0
- package/dist/ListReportPage.svelte +184 -0
- package/dist/ListReportPage.svelte.d.ts +46 -0
- package/dist/ListReportPage.svelte.d.ts.map +1 -0
- package/dist/MasterDetail.svelte +267 -0
- package/dist/MasterDetail.svelte.d.ts +35 -0
- package/dist/MasterDetail.svelte.d.ts.map +1 -0
- package/dist/MultiSelect.svelte +20 -11
- package/dist/MultiSelect.svelte.d.ts +1 -0
- package/dist/MultiSelect.svelte.d.ts.map +1 -1
- package/dist/NavItem.svelte +6 -6
- package/dist/ObjectPage.svelte +222 -0
- package/dist/ObjectPage.svelte.d.ts +46 -0
- package/dist/ObjectPage.svelte.d.ts.map +1 -0
- package/dist/OrderedList.svelte +7 -12
- package/dist/OrderedList.svelte.d.ts.map +1 -1
- package/dist/PaginationNav.svelte +10 -4
- package/dist/PaginationNav.svelte.d.ts +1 -0
- package/dist/PaginationNav.svelte.d.ts.map +1 -1
- package/dist/PointAndFigureChart.svelte +18 -11
- package/dist/PointAndFigureChart.svelte.d.ts +1 -1
- package/dist/PointAndFigureChart.svelte.d.ts.map +1 -1
- package/dist/RenkoChart.svelte +40 -13
- package/dist/RenkoChart.svelte.d.ts +1 -1
- package/dist/RenkoChart.svelte.d.ts.map +1 -1
- package/dist/VectorFieldChart.svelte +5 -5
- package/dist/VectorFieldChart.svelte.d.ts +1 -1
- package/dist/VectorFieldChart.svelte.d.ts.map +1 -1
- package/dist/WindBarbChart.svelte +5 -5
- package/dist/WindBarbChart.svelte.d.ts +1 -1
- package/dist/WindBarbChart.svelte.d.ts.map +1 -1
- package/dist/Wizard.svelte +125 -0
- package/dist/Wizard.svelte.d.ts +25 -0
- package/dist/Wizard.svelte.d.ts.map +1 -0
- package/dist/index.d.ts +24 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# `@sentropic/design-system-svelte`
|
|
2
|
+
|
|
3
|
+
Svelte implementation of the Sentropic design-system component catalog. The package ships ESM JavaScript, TypeScript declarations, and the shared component CSS.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @sentropic/design-system-svelte @sentropic/design-system-themes
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Svelte is a peer dependency:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install svelte
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
Import the package CSS once at the app or preview boundary, then render components inside `ThemeProvider`.
|
|
20
|
+
|
|
21
|
+
```svelte
|
|
22
|
+
<script>
|
|
23
|
+
import { Button, Card, ThemeProvider } from "@sentropic/design-system-svelte";
|
|
24
|
+
import "@sentropic/design-system-svelte/styles.css";
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<ThemeProvider>
|
|
28
|
+
<Card>
|
|
29
|
+
<strong>Release plan</strong>
|
|
30
|
+
<Button>Open plan</Button>
|
|
31
|
+
</Card>
|
|
32
|
+
</ThemeProvider>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`ThemeProvider` defaults to the Sent Tech theme. Tenant themes can be supplied from `@sentropic/design-system-themes`, `@sentropic/design-system-theme-dsfr`, or `@sentropic/design-system-theme-carbon`.
|
|
36
|
+
|
|
37
|
+
```svelte
|
|
38
|
+
<script>
|
|
39
|
+
import { ThemeProvider } from "@sentropic/design-system-svelte";
|
|
40
|
+
import { carbonTheme } from "@sentropic/design-system-theme-carbon";
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<ThemeProvider theme={carbonTheme}>
|
|
44
|
+
<!-- your content -->
|
|
45
|
+
</ThemeProvider>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Exports
|
|
49
|
+
|
|
50
|
+
- `@sentropic/design-system-svelte`: all public Svelte components and TypeScript props.
|
|
51
|
+
- `@sentropic/design-system-svelte/styles.css`: component CSS consumed by every theme.
|
|
52
|
+
|
|
53
|
+
The package includes declarations through `dist/index.d.ts` and marks `dist/styles.css` as a side effect so bundlers keep the stylesheet import.
|
|
54
|
+
|
|
55
|
+
## Build
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npm --workspace @sentropic/design-system-svelte run build
|
|
59
|
+
npm --workspace @sentropic/design-system-svelte run test
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Publishing is handled by `.github/workflows/svelte-publish.yml` with a `svelte-v*` tag.
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
| "category1" | "category2" | "category3" | "category4"
|
|
24
24
|
| "category5" | "category6" | "category7" | "category8";
|
|
25
25
|
|
|
26
|
+
export type AnomalySwimLaneChartScale = "categorical" | "sequential";
|
|
27
|
+
|
|
26
28
|
export type AnomalySwimLaneBucket = {
|
|
27
29
|
at: number;
|
|
28
30
|
score: number;
|
|
@@ -40,6 +42,7 @@
|
|
|
40
42
|
type AnomalySwimLaneChartProps = {
|
|
41
43
|
data: AnomalySwimLaneSeries[];
|
|
42
44
|
max?: number;
|
|
45
|
+
scale?: AnomalySwimLaneChartScale;
|
|
43
46
|
label?: string;
|
|
44
47
|
width?: number;
|
|
45
48
|
height?: number;
|
|
@@ -50,6 +53,7 @@
|
|
|
50
53
|
let {
|
|
51
54
|
data = [],
|
|
52
55
|
max,
|
|
56
|
+
scale = "sequential",
|
|
53
57
|
label,
|
|
54
58
|
width,
|
|
55
59
|
height = 300,
|
|
@@ -73,6 +77,10 @@
|
|
|
73
77
|
return TONES[index];
|
|
74
78
|
}
|
|
75
79
|
|
|
80
|
+
function normalizedScale(value: AnomalySwimLaneChartScale | undefined): AnomalySwimLaneChartScale {
|
|
81
|
+
return value === "categorical" ? "categorical" : "sequential";
|
|
82
|
+
}
|
|
83
|
+
|
|
76
84
|
// Tronque une étiquette à la largeur de la marge gauche (approx. par char).
|
|
77
85
|
function ellipsize(text: string, maxChars: number): string {
|
|
78
86
|
if (text.length <= maxChars) return text;
|
|
@@ -87,6 +95,7 @@
|
|
|
87
95
|
}
|
|
88
96
|
|
|
89
97
|
let hoveredKey: string | null = $state(null);
|
|
98
|
+
const resolvedScale = $derived(normalizedScale(scale));
|
|
90
99
|
|
|
91
100
|
const plotWidth = $derived(Math.max(resolvedWidth - MARGIN.left - MARGIN.right, 1));
|
|
92
101
|
const plotHeight = $derived(Math.max(height - MARGIN.top - MARGIN.bottom, 1));
|
|
@@ -190,7 +199,7 @@
|
|
|
190
199
|
return null;
|
|
191
200
|
});
|
|
192
201
|
|
|
193
|
-
const classes = () => ["st-anomalySwimLaneChart", className].filter(Boolean).join(" ");
|
|
202
|
+
const classes = () => ["st-anomalySwimLaneChart", `st-anomalySwimLaneChart--${resolvedScale}`, className].filter(Boolean).join(" ");
|
|
194
203
|
</script>
|
|
195
204
|
|
|
196
205
|
<div class={classes()}>
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
* class string
|
|
20
20
|
*/
|
|
21
21
|
export type AnomalySwimLaneTone = "category1" | "category2" | "category3" | "category4" | "category5" | "category6" | "category7" | "category8";
|
|
22
|
+
export type AnomalySwimLaneChartScale = "categorical" | "sequential";
|
|
22
23
|
export type AnomalySwimLaneBucket = {
|
|
23
24
|
at: number;
|
|
24
25
|
score: number;
|
|
@@ -30,6 +31,7 @@ export type AnomalySwimLaneSeries = {
|
|
|
30
31
|
type AnomalySwimLaneChartProps = {
|
|
31
32
|
data: AnomalySwimLaneSeries[];
|
|
32
33
|
max?: number;
|
|
34
|
+
scale?: AnomalySwimLaneChartScale;
|
|
33
35
|
label?: string;
|
|
34
36
|
width?: number;
|
|
35
37
|
height?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnomalySwimLaneChart.svelte.d.ts","sourceRoot":"","sources":["../src/lib/AnomalySwimLaneChart.svelte.ts"],"names":[],"mappings":"AAGE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,mBAAmB,GAC3B,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,GACrD,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;AAE1D,MAAM,MAAM,qBAAqB,GAAG;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,qBAAqB,EAAE,CAAC;CAClC,CAAC;AAMF,KAAK,yBAAyB,GAAG;IAC/B,IAAI,EAAE,qBAAqB,EAAE,CAAC;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;
|
|
1
|
+
{"version":3,"file":"AnomalySwimLaneChart.svelte.d.ts","sourceRoot":"","sources":["../src/lib/AnomalySwimLaneChart.svelte.ts"],"names":[],"mappings":"AAGE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,mBAAmB,GAC3B,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,GACrD,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;AAE1D,MAAM,MAAM,yBAAyB,GAAG,aAAa,GAAG,YAAY,CAAC;AAErE,MAAM,MAAM,qBAAqB,GAAG;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,qBAAqB,EAAE,CAAC;CAClC,CAAC;AAMF,KAAK,yBAAyB,GAAG;IAC/B,IAAI,EAAE,qBAAqB,EAAE,CAAC;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,yBAAyB,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAqNJ,QAAA,MAAM,oBAAoB,+DAAwC,CAAC;AACnE,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACpE,eAAe,oBAAoB,CAAC"}
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
date: string;
|
|
17
17
|
value: number;
|
|
18
18
|
};
|
|
19
|
+
|
|
20
|
+
export type CalendarHeatmapChartScale = "categorical" | "sequential";
|
|
19
21
|
</script>
|
|
20
22
|
|
|
21
23
|
<script lang="ts">
|
|
@@ -29,6 +31,7 @@
|
|
|
29
31
|
type CalendarHeatmapChartProps = {
|
|
30
32
|
data: CalendarHeatmapChartDatum[];
|
|
31
33
|
label: string;
|
|
34
|
+
scale?: CalendarHeatmapChartScale;
|
|
32
35
|
width?: number;
|
|
33
36
|
height?: number;
|
|
34
37
|
class?: string;
|
|
@@ -37,6 +40,7 @@
|
|
|
37
40
|
let {
|
|
38
41
|
data = [],
|
|
39
42
|
label,
|
|
43
|
+
scale = "sequential",
|
|
40
44
|
width = 480,
|
|
41
45
|
height = 140,
|
|
42
46
|
class: className
|
|
@@ -75,6 +79,12 @@
|
|
|
75
79
|
return Math.round((tsB - tsA) / 86400000);
|
|
76
80
|
}
|
|
77
81
|
|
|
82
|
+
function normalizedScale(value: CalendarHeatmapChartScale | undefined): CalendarHeatmapChartScale {
|
|
83
|
+
return value === "categorical" ? "categorical" : "sequential";
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const resolvedScale = $derived(normalizedScale(scale));
|
|
87
|
+
|
|
78
88
|
// Group data by week and day-of-week
|
|
79
89
|
const grid = $derived.by(() => {
|
|
80
90
|
if (data.length === 0) return { cells: [], weeks: 0, monthLabels: [] };
|
|
@@ -187,7 +197,7 @@
|
|
|
187
197
|
hoveredDate = target.getAttribute("data-chart-date") ?? null;
|
|
188
198
|
}
|
|
189
199
|
|
|
190
|
-
const classes = () => ["st-calendarHeatmapChart", className].filter(Boolean).join(" ");
|
|
200
|
+
const classes = () => ["st-calendarHeatmapChart", `st-calendarHeatmapChart--${resolvedScale}`, className].filter(Boolean).join(" ");
|
|
191
201
|
</script>
|
|
192
202
|
|
|
193
203
|
<div class={classes()}>
|
|
@@ -15,9 +15,11 @@ export type CalendarHeatmapChartDatum = {
|
|
|
15
15
|
date: string;
|
|
16
16
|
value: number;
|
|
17
17
|
};
|
|
18
|
+
export type CalendarHeatmapChartScale = "categorical" | "sequential";
|
|
18
19
|
type CalendarHeatmapChartProps = {
|
|
19
20
|
data: CalendarHeatmapChartDatum[];
|
|
20
21
|
label: string;
|
|
22
|
+
scale?: CalendarHeatmapChartScale;
|
|
21
23
|
width?: number;
|
|
22
24
|
height?: number;
|
|
23
25
|
class?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CalendarHeatmapChart.svelte.d.ts","sourceRoot":"","sources":["../src/lib/CalendarHeatmapChart.svelte.ts"],"names":[],"mappings":"AAGE;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;
|
|
1
|
+
{"version":3,"file":"CalendarHeatmapChart.svelte.d.ts","sourceRoot":"","sources":["../src/lib/CalendarHeatmapChart.svelte.ts"],"names":[],"mappings":"AAGE;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,aAAa,GAAG,YAAY,CAAC;AAMrE,KAAK,yBAAyB,GAAG;IAC/B,IAAI,EAAE,yBAAyB,EAAE,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,yBAAyB,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAuNJ,QAAA,MAAM,oBAAoB,+DAAwC,CAAC;AACnE,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACpE,eAAe,oBAAoB,CAAC"}
|
package/dist/Combobox.svelte
CHANGED
|
@@ -56,6 +56,8 @@
|
|
|
56
56
|
let expanded = $state(false);
|
|
57
57
|
let activeIndex = $state(-1);
|
|
58
58
|
|
|
59
|
+
const inputId = $derived((rest as { id?: string }).id ?? `st-combobox-${Math.random().toString(36).slice(2, 9)}`);
|
|
60
|
+
|
|
59
61
|
const fieldClasses = () => ["st-field", className].filter(Boolean).join(" ");
|
|
60
62
|
const groupClasses = () => ["st-combobox", `st-combobox--${size}`].join(" ");
|
|
61
63
|
const isInvalid = () => invalid || Boolean(errorText);
|
|
@@ -93,6 +95,7 @@
|
|
|
93
95
|
|
|
94
96
|
function clear() {
|
|
95
97
|
value = "";
|
|
98
|
+
activeIndex = -1;
|
|
96
99
|
onchange?.("");
|
|
97
100
|
}
|
|
98
101
|
|
|
@@ -131,11 +134,12 @@
|
|
|
131
134
|
</script>
|
|
132
135
|
|
|
133
136
|
<div class={fieldClasses()}>
|
|
134
|
-
<label class="st-field__control">
|
|
137
|
+
<label class="st-field__control" for={inputId}>
|
|
135
138
|
{#if label}<span class="st-field__label">{label}</span>{/if}
|
|
136
139
|
<span class={groupClasses()}>
|
|
137
140
|
<input
|
|
138
141
|
{...rest}
|
|
142
|
+
id={inputId}
|
|
139
143
|
type="text"
|
|
140
144
|
class="st-combobox__control"
|
|
141
145
|
role="combobox"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Combobox.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Combobox.svelte.ts"],"names":[],"mappings":"AAGE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAGzD,KAAK,aAAa,GAAG,IAAI,CACvB,mBAAmB,EACnB,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,CACjD,GAAG;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC,CAAC;
|
|
1
|
+
{"version":3,"file":"Combobox.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Combobox.svelte.ts"],"names":[],"mappings":"AAGE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAGzD,KAAK,aAAa,GAAG,IAAI,CACvB,mBAAmB,EACnB,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,CACjD,GAAG;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC,CAAC;AAyJJ,QAAA,MAAM,QAAQ,wDAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
package/dist/ContourChart.svelte
CHANGED
|
@@ -27,30 +27,34 @@
|
|
|
27
27
|
| "category1" | "category2" | "category3" | "category4"
|
|
28
28
|
| "category5" | "category6" | "category7" | "category8";
|
|
29
29
|
|
|
30
|
+
export type ContourChartScale = "categorical" | "sequential";
|
|
31
|
+
|
|
30
32
|
export type ContourChartDatum = {
|
|
31
33
|
x: number;
|
|
32
34
|
y: number;
|
|
33
35
|
/** Valeur scalaire de la cellule : pilote la bande de couleur. */
|
|
34
36
|
value: number;
|
|
35
37
|
};
|
|
36
|
-
</script>
|
|
37
|
-
|
|
38
|
-
<script lang="ts">
|
|
39
|
-
import ChartDataList from "./ChartDataList.svelte";
|
|
40
38
|
|
|
41
|
-
type ContourChartProps = {
|
|
39
|
+
export type ContourChartProps = {
|
|
42
40
|
data: ContourChartDatum[];
|
|
43
41
|
levels?: number;
|
|
42
|
+
scale?: ContourChartScale;
|
|
44
43
|
label?: string;
|
|
45
44
|
width?: number;
|
|
46
45
|
height?: number;
|
|
47
46
|
size?: number;
|
|
48
47
|
class?: string;
|
|
49
48
|
};
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<script lang="ts">
|
|
52
|
+
import ChartDataList from "./ChartDataList.svelte";
|
|
50
53
|
|
|
51
54
|
let {
|
|
52
55
|
data = [],
|
|
53
56
|
levels = 6,
|
|
57
|
+
scale = "sequential",
|
|
54
58
|
label,
|
|
55
59
|
width = 640,
|
|
56
60
|
height = 320,
|
|
@@ -90,12 +94,17 @@
|
|
|
90
94
|
return r0 + ((v - d0) * (r1 - r0)) / (d1 - d0);
|
|
91
95
|
}
|
|
92
96
|
|
|
97
|
+
function normalizedScale(value: ContourChartScale | undefined): ContourChartScale {
|
|
98
|
+
return value === "categorical" ? "categorical" : "sequential";
|
|
99
|
+
}
|
|
100
|
+
|
|
93
101
|
function fmt(v: number): string {
|
|
94
102
|
if (Math.abs(v) >= 1000) return `${(v / 1000).toFixed(v % 1000 === 0 ? 0 : 1)}k`;
|
|
95
103
|
return Number.isInteger(v) ? String(v) : v.toFixed(1);
|
|
96
104
|
}
|
|
97
105
|
|
|
98
106
|
let hoveredKey: string | null = $state(null);
|
|
107
|
+
const resolvedScale = $derived(normalizedScale(scale));
|
|
99
108
|
|
|
100
109
|
// Points valides : coordonnées finies, valeur finie.
|
|
101
110
|
const validData = $derived(
|
|
@@ -120,13 +129,17 @@
|
|
|
120
129
|
return { min, max };
|
|
121
130
|
});
|
|
122
131
|
|
|
132
|
+
function toneForBand(band: number): ContourChartTone {
|
|
133
|
+
const toneIndex = Math.max(0, Math.min(TONES.length - 1, Math.floor((band / Math.max(levelCount - 1, 1)) * (TONES.length - 1))));
|
|
134
|
+
return TONES[toneIndex];
|
|
135
|
+
}
|
|
136
|
+
|
|
123
137
|
// Palier (0..levelCount-1) puis ton catégoriel : valeur normalisée 0..1 → bande.
|
|
124
138
|
function bandOf(value: number): { band: number; tone: ContourChartTone } {
|
|
125
139
|
const { min, max } = valueRange;
|
|
126
140
|
const ratio = max > min ? (value - min) / (max - min) : 0;
|
|
127
141
|
const band = Math.max(0, Math.min(levelCount - 1, Math.floor(ratio * levelCount)));
|
|
128
|
-
|
|
129
|
-
return { band, tone: TONES[toneIndex] };
|
|
142
|
+
return { band, tone: toneForBand(band) };
|
|
130
143
|
}
|
|
131
144
|
|
|
132
145
|
const scales = $derived.by(() => {
|
|
@@ -157,17 +170,22 @@
|
|
|
157
170
|
|
|
158
171
|
// Une bande rectangulaire par cellule de grille, peinte selon sa value.
|
|
159
172
|
const cells = $derived.by(() => {
|
|
160
|
-
const { xMin, xMax, yMin, yMax, plotW, plotH } = scales;
|
|
173
|
+
const { xMin, xMax, yMin, yMax, plotW, plotH, xValues, yValues } = scales;
|
|
161
174
|
const { dx, dy } = cellSpan;
|
|
175
|
+
const xIndexByValue = new Map(xValues.map((value, index) => [value, index]));
|
|
176
|
+
const yIndexByValue = new Map(yValues.map((value, index) => [value, index]));
|
|
162
177
|
return validData.map((d, i) => {
|
|
163
178
|
const left = MARGIN.left + scaleLinear(d.x - dx / 2, xMin, xMax, 0, plotW);
|
|
164
179
|
const right = MARGIN.left + scaleLinear(d.x + dx / 2, xMin, xMax, 0, plotW);
|
|
165
180
|
const top = MARGIN.top + scaleLinear(d.y + dy / 2, yMin, yMax, plotH, 0);
|
|
166
181
|
const bottom = MARGIN.top + scaleLinear(d.y - dy / 2, yMin, yMax, plotH, 0);
|
|
167
|
-
const { tone } = bandOf(d.value);
|
|
182
|
+
const { band, tone } = bandOf(d.value);
|
|
168
183
|
return {
|
|
169
184
|
key: `${i}`,
|
|
170
185
|
datum: d,
|
|
186
|
+
band,
|
|
187
|
+
col: xIndexByValue.get(d.x) ?? 0,
|
|
188
|
+
row: yIndexByValue.get(d.y) ?? 0,
|
|
171
189
|
x: Math.min(left, right),
|
|
172
190
|
y: Math.min(top, bottom),
|
|
173
191
|
width: Math.abs(right - left),
|
|
@@ -179,14 +197,41 @@
|
|
|
179
197
|
});
|
|
180
198
|
});
|
|
181
199
|
|
|
200
|
+
const contourSegments = $derived.by(() => {
|
|
201
|
+
const byGrid = new Map(cells.map((cell) => [`${cell.col}:${cell.row}`, cell]));
|
|
202
|
+
const segments = [];
|
|
203
|
+
for (const cell of cells) {
|
|
204
|
+
const right = byGrid.get(`${cell.col + 1}:${cell.row}`);
|
|
205
|
+
if (right && right.band !== cell.band) {
|
|
206
|
+
segments.push({
|
|
207
|
+
key: `${cell.key}:right`,
|
|
208
|
+
x1: cell.x + cell.width,
|
|
209
|
+
y1: cell.y,
|
|
210
|
+
x2: cell.x + cell.width,
|
|
211
|
+
y2: cell.y + cell.height
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
const upper = byGrid.get(`${cell.col}:${cell.row + 1}`);
|
|
215
|
+
if (upper && upper.band !== cell.band) {
|
|
216
|
+
segments.push({
|
|
217
|
+
key: `${cell.key}:top`,
|
|
218
|
+
x1: cell.x,
|
|
219
|
+
y1: cell.y,
|
|
220
|
+
x2: cell.x + cell.width,
|
|
221
|
+
y2: cell.y
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return segments;
|
|
226
|
+
});
|
|
227
|
+
|
|
182
228
|
const dataValueItems = $derived(
|
|
183
229
|
validData.map((d) => `x ${d.x}, y ${d.y} · ${fmt(d.value)}`)
|
|
184
230
|
);
|
|
185
231
|
|
|
186
232
|
const legendItems = $derived(
|
|
187
233
|
Array.from({ length: levelCount }, (_, band) => {
|
|
188
|
-
|
|
189
|
-
return { band, tone: TONES[toneIndex] };
|
|
234
|
+
return { band, tone: toneForBand(band) };
|
|
190
235
|
})
|
|
191
236
|
);
|
|
192
237
|
const hasLegend = $derived(validData.length > 0);
|
|
@@ -205,7 +250,7 @@
|
|
|
205
250
|
return cells.find((c) => c.key === hoveredKey) ?? null;
|
|
206
251
|
});
|
|
207
252
|
|
|
208
|
-
const classes = () => ["st-contourChart", className].filter(Boolean).join(" ");
|
|
253
|
+
const classes = () => ["st-contourChart", `st-contourChart--${resolvedScale}`, className].filter(Boolean).join(" ");
|
|
209
254
|
</script>
|
|
210
255
|
|
|
211
256
|
<div class={classes()}>
|
|
@@ -237,6 +282,16 @@
|
|
|
237
282
|
/>
|
|
238
283
|
{/each}
|
|
239
284
|
|
|
285
|
+
{#each contourSegments as segment (segment.key)}
|
|
286
|
+
<line
|
|
287
|
+
class="st-contourChart__isoline"
|
|
288
|
+
x1={segment.x1}
|
|
289
|
+
y1={segment.y1}
|
|
290
|
+
x2={segment.x2}
|
|
291
|
+
y2={segment.y2}
|
|
292
|
+
/>
|
|
293
|
+
{/each}
|
|
294
|
+
|
|
240
295
|
<!-- gridlines + ticks Y -->
|
|
241
296
|
{#each scales.yTicks as t (t)}
|
|
242
297
|
{@const y = MARGIN.top + scaleLinear(t, scales.yMin, scales.yMax, scales.plotH, 0)}
|
|
@@ -319,7 +374,7 @@
|
|
|
319
374
|
|
|
320
375
|
.st-contourChart__cell {
|
|
321
376
|
cursor: pointer;
|
|
322
|
-
stroke: var(--st-semantic-surface-default
|
|
377
|
+
stroke: var(--st-semantic-surface-default);
|
|
323
378
|
stroke-width: 0.5;
|
|
324
379
|
transition: opacity 120ms ease;
|
|
325
380
|
}
|
|
@@ -328,6 +383,14 @@
|
|
|
328
383
|
opacity: 0.35;
|
|
329
384
|
}
|
|
330
385
|
|
|
386
|
+
.st-contourChart__isoline {
|
|
387
|
+
pointer-events: none;
|
|
388
|
+
stroke: var(--st-semantic-border-strong);
|
|
389
|
+
stroke-linecap: round;
|
|
390
|
+
stroke-linejoin: round;
|
|
391
|
+
stroke-width: 1.5;
|
|
392
|
+
}
|
|
393
|
+
|
|
331
394
|
.st-contourChart__cell--category1 { fill: var(--st-semantic-data-category1); }
|
|
332
395
|
.st-contourChart__cell--category2 { fill: var(--st-semantic-data-category2); }
|
|
333
396
|
.st-contourChart__cell--category3 { fill: var(--st-semantic-data-category3); }
|
|
@@ -23,15 +23,17 @@
|
|
|
23
23
|
* class string
|
|
24
24
|
*/
|
|
25
25
|
export type ContourChartTone = "category1" | "category2" | "category3" | "category4" | "category5" | "category6" | "category7" | "category8";
|
|
26
|
+
export type ContourChartScale = "categorical" | "sequential";
|
|
26
27
|
export type ContourChartDatum = {
|
|
27
28
|
x: number;
|
|
28
29
|
y: number;
|
|
29
30
|
/** Valeur scalaire de la cellule : pilote la bande de couleur. */
|
|
30
31
|
value: number;
|
|
31
32
|
};
|
|
32
|
-
type ContourChartProps = {
|
|
33
|
+
export type ContourChartProps = {
|
|
33
34
|
data: ContourChartDatum[];
|
|
34
35
|
levels?: number;
|
|
36
|
+
scale?: ContourChartScale;
|
|
35
37
|
label?: string;
|
|
36
38
|
width?: number;
|
|
37
39
|
height?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContourChart.svelte.d.ts","sourceRoot":"","sources":["../src/lib/ContourChart.svelte.ts"],"names":[],"mappings":"AAGE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,MAAM,gBAAgB,GACxB,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,GACrD,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;AAE1D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;
|
|
1
|
+
{"version":3,"file":"ContourChart.svelte.d.ts","sourceRoot":"","sources":["../src/lib/ContourChart.svelte.ts"],"names":[],"mappings":"AAGE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,MAAM,gBAAgB,GACxB,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,GACrD,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;AAE1D,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG,YAAY,CAAC;AAE7D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,iBAAiB,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AA6QJ,QAAA,MAAM,YAAY,uDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
package/dist/CopyButton.svelte
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
type CopyButtonProps = Omit<HTMLButtonAttributes, "class" | "type"> & {
|
|
6
6
|
value: string;
|
|
7
|
+
locale?: string;
|
|
7
8
|
label?: string;
|
|
8
9
|
copiedLabel?: string;
|
|
9
10
|
feedbackTimeoutMs?: number;
|
|
@@ -15,8 +16,9 @@
|
|
|
15
16
|
|
|
16
17
|
let {
|
|
17
18
|
value,
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
locale = "fr-FR",
|
|
20
|
+
label,
|
|
21
|
+
copiedLabel,
|
|
20
22
|
feedbackTimeoutMs = 1500,
|
|
21
23
|
size = "md",
|
|
22
24
|
onCopied,
|
|
@@ -26,6 +28,10 @@
|
|
|
26
28
|
...rest
|
|
27
29
|
}: CopyButtonProps = $props();
|
|
28
30
|
|
|
31
|
+
const isFr = $derived(locale.toLowerCase().startsWith("fr"));
|
|
32
|
+
const resolvedLabel = $derived(label ?? (isFr ? "Copier" : "Copy"));
|
|
33
|
+
const resolvedCopiedLabel = $derived(copiedLabel ?? (isFr ? "Copié" : "Copied"));
|
|
34
|
+
|
|
29
35
|
let copied = $state(false);
|
|
30
36
|
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
31
37
|
|
|
@@ -65,7 +71,7 @@
|
|
|
65
71
|
<Copy size={14} strokeWidth={2} aria-hidden="true" />
|
|
66
72
|
{/if}
|
|
67
73
|
</span>
|
|
68
|
-
<span class="st-copyButton__label">{copied ?
|
|
74
|
+
<span class="st-copyButton__label">{copied ? resolvedCopiedLabel : resolvedLabel}</span>
|
|
69
75
|
</button>
|
|
70
76
|
|
|
71
77
|
<style>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CopyButton.svelte.d.ts","sourceRoot":"","sources":["../src/lib/CopyButton.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAI1D,KAAK,eAAe,GAAG,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,MAAM,CAAC,GAAG;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;
|
|
1
|
+
{"version":3,"file":"CopyButton.svelte.d.ts","sourceRoot":"","sources":["../src/lib/CopyButton.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAI1D,KAAK,eAAe,GAAG,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,MAAM,CAAC,GAAG;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AA+DJ,QAAA,MAAM,UAAU,qDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import type { SideNavItem } from "./SideNav.svelte";
|
|
4
|
+
|
|
5
|
+
export interface DashboardNavItem extends SideNavItem {}
|
|
6
|
+
|
|
7
|
+
export interface DashboardKpi {
|
|
8
|
+
label: string;
|
|
9
|
+
value: string;
|
|
10
|
+
unit?: string;
|
|
11
|
+
trend?: "up" | "down" | "flat";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type DashboardProps = {
|
|
15
|
+
appTitle: string;
|
|
16
|
+
navItems?: DashboardNavItem[];
|
|
17
|
+
pageTitle: string;
|
|
18
|
+
kpis?: DashboardKpi[];
|
|
19
|
+
children?: Snippet;
|
|
20
|
+
};
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<script lang="ts">
|
|
24
|
+
import SideNav from "./SideNav.svelte";
|
|
25
|
+
|
|
26
|
+
let {
|
|
27
|
+
appTitle,
|
|
28
|
+
navItems = [],
|
|
29
|
+
pageTitle,
|
|
30
|
+
kpis = [],
|
|
31
|
+
children,
|
|
32
|
+
}: DashboardProps = $props();
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<div class="st-dash">
|
|
36
|
+
<header class="st-dash__header">
|
|
37
|
+
<span class="st-dash__appTitle">{appTitle}</span>
|
|
38
|
+
</header>
|
|
39
|
+
<div class="st-dash__body">
|
|
40
|
+
{#if navItems.length > 0}
|
|
41
|
+
<aside class="st-dash__aside">
|
|
42
|
+
<SideNav items={navItems} />
|
|
43
|
+
</aside>
|
|
44
|
+
{/if}
|
|
45
|
+
<main class="st-dash__main">
|
|
46
|
+
<h1 class="st-dash__pageTitle">{pageTitle}</h1>
|
|
47
|
+
{#if kpis.length > 0}
|
|
48
|
+
<div class="st-dash__kpi-row">
|
|
49
|
+
{#each kpis as kpi}
|
|
50
|
+
<div class="st-dash__kpi">
|
|
51
|
+
<span class="st-dash__kpiLabel">{kpi.label}</span>
|
|
52
|
+
<span class="st-dash__kpiValue">
|
|
53
|
+
{kpi.value}{#if kpi.unit}<span class="st-dash__kpiUnit"> {kpi.unit}</span>{/if}
|
|
54
|
+
</span>
|
|
55
|
+
{#if kpi.trend}
|
|
56
|
+
<span class="st-dash__kpiTrend st-dash__kpiTrend--{kpi.trend}" aria-label="Tendance {kpi.trend}">
|
|
57
|
+
{#if kpi.trend === "up"}↑{:else if kpi.trend === "down"}↓{:else}→{/if}
|
|
58
|
+
</span>
|
|
59
|
+
{/if}
|
|
60
|
+
</div>
|
|
61
|
+
{/each}
|
|
62
|
+
</div>
|
|
63
|
+
{/if}
|
|
64
|
+
{#if children}
|
|
65
|
+
<div class="st-dash__content">
|
|
66
|
+
{@render children()}
|
|
67
|
+
</div>
|
|
68
|
+
{/if}
|
|
69
|
+
</main>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<style>
|
|
74
|
+
.st-dash {
|
|
75
|
+
display: grid;
|
|
76
|
+
grid-template-rows: auto 1fr;
|
|
77
|
+
min-block-size: 100vh;
|
|
78
|
+
background: var(--st-semantic-surface-default);
|
|
79
|
+
color: var(--st-semantic-text-primary);
|
|
80
|
+
}
|
|
81
|
+
.st-dash__header {
|
|
82
|
+
border-block-end: 1px solid var(--st-semantic-border-subtle);
|
|
83
|
+
padding: var(--st-spacing-3, 0.75rem) var(--st-spacing-6, 1.5rem);
|
|
84
|
+
display: flex;
|
|
85
|
+
align-items: center;
|
|
86
|
+
}
|
|
87
|
+
.st-dash__appTitle {
|
|
88
|
+
font-weight: 700;
|
|
89
|
+
font-size: 1rem;
|
|
90
|
+
}
|
|
91
|
+
.st-dash__body {
|
|
92
|
+
display: grid;
|
|
93
|
+
grid-template-columns: 220px 1fr;
|
|
94
|
+
overflow: hidden;
|
|
95
|
+
}
|
|
96
|
+
.st-dash__aside {
|
|
97
|
+
border-inline-end: 1px solid var(--st-semantic-border-subtle);
|
|
98
|
+
background: var(--st-semantic-surface-raised);
|
|
99
|
+
overflow-y: auto;
|
|
100
|
+
}
|
|
101
|
+
.st-dash__main {
|
|
102
|
+
display: flex;
|
|
103
|
+
flex-direction: column;
|
|
104
|
+
gap: var(--st-spacing-6, 1.5rem);
|
|
105
|
+
padding: var(--st-spacing-6, 1.5rem);
|
|
106
|
+
overflow-y: auto;
|
|
107
|
+
}
|
|
108
|
+
.st-dash__pageTitle {
|
|
109
|
+
font-size: 1.5rem;
|
|
110
|
+
font-weight: 700;
|
|
111
|
+
margin: 0;
|
|
112
|
+
}
|
|
113
|
+
.st-dash__kpi-row {
|
|
114
|
+
display: grid;
|
|
115
|
+
grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
|
|
116
|
+
gap: var(--st-spacing-4, 1rem);
|
|
117
|
+
}
|
|
118
|
+
.st-dash__kpi {
|
|
119
|
+
display: flex;
|
|
120
|
+
flex-direction: column;
|
|
121
|
+
gap: var(--st-spacing-1, 0.25rem);
|
|
122
|
+
padding: var(--st-spacing-4, 1rem) var(--st-spacing-5, 1.25rem);
|
|
123
|
+
background: var(--st-semantic-surface-raised);
|
|
124
|
+
border: 1px solid var(--st-semantic-border-subtle);
|
|
125
|
+
border-radius: var(--st-radius-md, 0.5rem);
|
|
126
|
+
}
|
|
127
|
+
.st-dash__kpiLabel {
|
|
128
|
+
font-size: 0.75rem;
|
|
129
|
+
color: var(--st-semantic-text-secondary);
|
|
130
|
+
text-transform: uppercase;
|
|
131
|
+
letter-spacing: 0.05em;
|
|
132
|
+
}
|
|
133
|
+
.st-dash__kpiValue {
|
|
134
|
+
font-size: 1.75rem;
|
|
135
|
+
font-weight: 700;
|
|
136
|
+
line-height: 1;
|
|
137
|
+
}
|
|
138
|
+
.st-dash__kpiUnit {
|
|
139
|
+
font-size: 0.875rem;
|
|
140
|
+
font-weight: 400;
|
|
141
|
+
color: var(--st-semantic-text-secondary);
|
|
142
|
+
}
|
|
143
|
+
.st-dash__kpiTrend {
|
|
144
|
+
font-size: 0.875rem;
|
|
145
|
+
font-weight: 600;
|
|
146
|
+
}
|
|
147
|
+
.st-dash__kpiTrend--up { color: var(--st-semantic-color-success, #16a34a); }
|
|
148
|
+
.st-dash__kpiTrend--down { color: var(--st-semantic-color-error, #dc2626); }
|
|
149
|
+
.st-dash__kpiTrend--flat { color: var(--st-semantic-text-secondary); }
|
|
150
|
+
.st-dash__content {
|
|
151
|
+
display: flex;
|
|
152
|
+
flex-direction: column;
|
|
153
|
+
gap: var(--st-spacing-4, 1rem);
|
|
154
|
+
}
|
|
155
|
+
</style>
|