@sentropic/design-system-svelte 0.34.49 → 0.34.51

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.
Files changed (97) hide show
  1. package/README.md +62 -0
  2. package/dist/AnomalySwimLaneChart.svelte +10 -1
  3. package/dist/AnomalySwimLaneChart.svelte.d.ts +2 -0
  4. package/dist/AnomalySwimLaneChart.svelte.d.ts.map +1 -1
  5. package/dist/AppShell.svelte +284 -28
  6. package/dist/AppShell.svelte.d.ts +23 -3
  7. package/dist/AppShell.svelte.d.ts.map +1 -1
  8. package/dist/CalendarHeatmapChart.svelte +11 -1
  9. package/dist/CalendarHeatmapChart.svelte.d.ts +2 -0
  10. package/dist/CalendarHeatmapChart.svelte.d.ts.map +1 -1
  11. package/dist/Combobox.svelte +5 -1
  12. package/dist/Combobox.svelte.d.ts.map +1 -1
  13. package/dist/ContextPanel.svelte +86 -0
  14. package/dist/ContextPanel.svelte.d.ts +14 -0
  15. package/dist/ContextPanel.svelte.d.ts.map +1 -0
  16. package/dist/ContourChart.svelte +76 -13
  17. package/dist/ContourChart.svelte.d.ts +3 -1
  18. package/dist/ContourChart.svelte.d.ts.map +1 -1
  19. package/dist/Dashboard.svelte +155 -0
  20. package/dist/Dashboard.svelte.d.ts +21 -0
  21. package/dist/Dashboard.svelte.d.ts.map +1 -0
  22. package/dist/DashboardGrid.svelte +237 -0
  23. package/dist/DashboardGrid.svelte.d.ts +24 -0
  24. package/dist/DashboardGrid.svelte.d.ts.map +1 -0
  25. package/dist/DataTable.svelte +3 -1
  26. package/dist/DataTable.svelte.d.ts +1 -0
  27. package/dist/DataTable.svelte.d.ts.map +1 -1
  28. package/dist/DatePicker.svelte +33 -28
  29. package/dist/DatePicker.svelte.d.ts.map +1 -1
  30. package/dist/Density2DChart.svelte +10 -1
  31. package/dist/Density2DChart.svelte.d.ts +2 -0
  32. package/dist/Density2DChart.svelte.d.ts.map +1 -1
  33. package/dist/Dropdown.svelte +33 -9
  34. package/dist/Dropdown.svelte.d.ts.map +1 -1
  35. package/dist/EventFeedPanel.svelte +3 -3
  36. package/dist/EventFeedPanel.svelte.d.ts +1 -1
  37. package/dist/EventFeedPanel.svelte.d.ts.map +1 -1
  38. package/dist/FileUploader.svelte +7 -3
  39. package/dist/Footer.svelte +75 -11
  40. package/dist/Footer.svelte.d.ts +16 -6
  41. package/dist/Footer.svelte.d.ts.map +1 -1
  42. package/dist/ForceGraph.svelte +9 -3
  43. package/dist/ForceGraph.svelte.d.ts +4 -0
  44. package/dist/ForceGraph.svelte.d.ts.map +1 -1
  45. package/dist/HeatmapChart.svelte +39 -3
  46. package/dist/HeatmapChart.svelte.d.ts +4 -1
  47. package/dist/HeatmapChart.svelte.d.ts.map +1 -1
  48. package/dist/KanbanBoard.svelte +144 -0
  49. package/dist/KanbanBoard.svelte.d.ts +23 -0
  50. package/dist/KanbanBoard.svelte.d.ts.map +1 -0
  51. package/dist/ListReportPage.svelte +184 -0
  52. package/dist/ListReportPage.svelte.d.ts +46 -0
  53. package/dist/ListReportPage.svelte.d.ts.map +1 -0
  54. package/dist/MasterDetail.svelte +267 -0
  55. package/dist/MasterDetail.svelte.d.ts +35 -0
  56. package/dist/MasterDetail.svelte.d.ts.map +1 -0
  57. package/dist/NavDrawer.svelte +46 -0
  58. package/dist/NavDrawer.svelte.d.ts +17 -0
  59. package/dist/NavDrawer.svelte.d.ts.map +1 -0
  60. package/dist/NavItem.svelte +3 -5
  61. package/dist/NavItem.svelte.d.ts.map +1 -1
  62. package/dist/NavRail.svelte +147 -0
  63. package/dist/NavRail.svelte.d.ts +23 -0
  64. package/dist/NavRail.svelte.d.ts.map +1 -0
  65. package/dist/NavShell.svelte +218 -0
  66. package/dist/NavShell.svelte.d.ts +38 -0
  67. package/dist/NavShell.svelte.d.ts.map +1 -0
  68. package/dist/ObjectPage.svelte +222 -0
  69. package/dist/ObjectPage.svelte.d.ts +46 -0
  70. package/dist/ObjectPage.svelte.d.ts.map +1 -0
  71. package/dist/OrderedList.svelte +7 -12
  72. package/dist/OrderedList.svelte.d.ts.map +1 -1
  73. package/dist/PointAndFigureChart.svelte +18 -11
  74. package/dist/PointAndFigureChart.svelte.d.ts +1 -1
  75. package/dist/PointAndFigureChart.svelte.d.ts.map +1 -1
  76. package/dist/RenkoChart.svelte +40 -13
  77. package/dist/RenkoChart.svelte.d.ts +1 -1
  78. package/dist/RenkoChart.svelte.d.ts.map +1 -1
  79. package/dist/SelectableRow.svelte +16 -5
  80. package/dist/SelectableRow.svelte.d.ts +2 -0
  81. package/dist/SelectableRow.svelte.d.ts.map +1 -1
  82. package/dist/UtilityPanel.svelte +89 -0
  83. package/dist/UtilityPanel.svelte.d.ts +18 -0
  84. package/dist/UtilityPanel.svelte.d.ts.map +1 -0
  85. package/dist/VectorFieldChart.svelte +5 -5
  86. package/dist/VectorFieldChart.svelte.d.ts +1 -1
  87. package/dist/VectorFieldChart.svelte.d.ts.map +1 -1
  88. package/dist/WindBarbChart.svelte +5 -5
  89. package/dist/WindBarbChart.svelte.d.ts +1 -1
  90. package/dist/WindBarbChart.svelte.d.ts.map +1 -1
  91. package/dist/Wizard.svelte +125 -0
  92. package/dist/Wizard.svelte.d.ts +25 -0
  93. package/dist/Wizard.svelte.d.ts.map +1 -0
  94. package/dist/index.d.ts +35 -10
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +12 -0
  97. package/package.json +5 -5
@@ -0,0 +1,86 @@
1
+ <script lang="ts" module>
2
+ import type { Snippet } from "svelte";
3
+
4
+ export interface ContextPanelProps {
5
+ title?: string;
6
+ subtitle?: string;
7
+ label?: string;
8
+ actions?: Snippet;
9
+ footer?: Snippet;
10
+ children?: Snippet;
11
+ class?: string;
12
+ }
13
+ </script>
14
+
15
+ <script lang="ts">
16
+ let { title, subtitle, label, actions, footer, children, class: className }: ContextPanelProps = $props();
17
+ const classes = $derived(["st-contextPanel", className].filter(Boolean).join(" "));
18
+ </script>
19
+
20
+ <aside class={classes} aria-label={label ?? title ?? "Context panel"}>
21
+ {#if title || subtitle || actions}
22
+ <header class="st-contextPanel__header">
23
+ <div class="st-contextPanel__heading">
24
+ {#if title}<h2 class="st-contextPanel__title">{title}</h2>{/if}
25
+ {#if subtitle}<p class="st-contextPanel__subtitle">{subtitle}</p>{/if}
26
+ </div>
27
+ {#if actions}<div class="st-contextPanel__actions">{@render actions()}</div>{/if}
28
+ </header>
29
+ {/if}
30
+ <div class="st-contextPanel__body">{@render children?.()}</div>
31
+ {#if footer}<footer class="st-contextPanel__footer">{@render footer()}</footer>{/if}
32
+ </aside>
33
+
34
+ <style>
35
+ .st-contextPanel {
36
+ background: var(--st-component-contextPanel-surface, var(--st-semantic-surface-raised));
37
+ color: var(--st-semantic-text-primary);
38
+ display: grid;
39
+ grid-template-rows: auto 1fr auto;
40
+ block-size: 100%;
41
+ min-block-size: 0;
42
+ }
43
+
44
+ .st-contextPanel__header,
45
+ .st-contextPanel__footer {
46
+ border-color: var(--st-component-contextPanel-border, var(--st-semantic-border-subtle));
47
+ padding: var(--st-spacing-4, 1rem);
48
+ }
49
+
50
+ .st-contextPanel__header {
51
+ align-items: start;
52
+ border-block-end-style: solid;
53
+ border-block-end-width: 1px;
54
+ display: flex;
55
+ gap: var(--st-spacing-3, 0.75rem);
56
+ justify-content: space-between;
57
+ }
58
+
59
+ .st-contextPanel__footer {
60
+ border-block-start-style: solid;
61
+ border-block-start-width: 1px;
62
+ }
63
+
64
+ .st-contextPanel__title,
65
+ .st-contextPanel__subtitle {
66
+ margin: 0;
67
+ }
68
+
69
+ .st-contextPanel__title {
70
+ font-size: 1rem;
71
+ line-height: 1.3;
72
+ }
73
+
74
+ .st-contextPanel__subtitle {
75
+ color: var(--st-semantic-text-secondary);
76
+ font-size: 0.8125rem;
77
+ line-height: 1.4;
78
+ margin-block-start: var(--st-spacing-1, 0.25rem);
79
+ }
80
+
81
+ .st-contextPanel__body {
82
+ min-block-size: 0;
83
+ overflow: auto;
84
+ padding: var(--st-spacing-4, 1rem);
85
+ }
86
+ </style>
@@ -0,0 +1,14 @@
1
+ import type { Snippet } from "svelte";
2
+ export interface ContextPanelProps {
3
+ title?: string;
4
+ subtitle?: string;
5
+ label?: string;
6
+ actions?: Snippet;
7
+ footer?: Snippet;
8
+ children?: Snippet;
9
+ class?: string;
10
+ }
11
+ declare const ContextPanel: import("svelte").Component<ContextPanelProps, {}, "">;
12
+ type ContextPanel = ReturnType<typeof ContextPanel>;
13
+ export default ContextPanel;
14
+ //# sourceMappingURL=ContextPanel.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ContextPanel.svelte.d.ts","sourceRoot":"","sources":["../src/lib/ContextPanel.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA2BH,QAAA,MAAM,YAAY,uDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -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
- const toneIndex = Math.max(0, Math.min(TONES.length - 1, Math.floor((band / Math.max(levelCount - 1, 1)) * (TONES.length - 1))));
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
- const toneIndex = Math.max(0, Math.min(TONES.length - 1, Math.floor((band / Math.max(levelCount - 1, 1)) * (TONES.length - 1))));
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, Canvas);
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;AAMF,KAAK,iBAAiB,GAAG;IACvB,IAAI,EAAE,iBAAiB,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,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;AA4NJ,QAAA,MAAM,YAAY,uDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,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"}
@@ -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>
@@ -0,0 +1,21 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { SideNavItem } from "./SideNav.svelte";
3
+ export interface DashboardNavItem extends SideNavItem {
4
+ }
5
+ export interface DashboardKpi {
6
+ label: string;
7
+ value: string;
8
+ unit?: string;
9
+ trend?: "up" | "down" | "flat";
10
+ }
11
+ export type DashboardProps = {
12
+ appTitle: string;
13
+ navItems?: DashboardNavItem[];
14
+ pageTitle: string;
15
+ kpis?: DashboardKpi[];
16
+ children?: Snippet;
17
+ };
18
+ declare const Dashboard: import("svelte").Component<DashboardProps, {}, "">;
19
+ type Dashboard = ReturnType<typeof Dashboard>;
20
+ export default Dashboard;
21
+ //# sourceMappingURL=Dashboard.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dashboard.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Dashboard.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,WAAW,gBAAiB,SAAQ,WAAW;CAAG;AAExD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;CAChC;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,YAAY,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AA6DJ,QAAA,MAAM,SAAS,oDAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}