@w5-ui/svelte 0.1.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.
Files changed (195) hide show
  1. package/README.md +8 -0
  2. package/package.json +57 -0
  3. package/src/lib/components/Accordion.svelte +3 -0
  4. package/src/lib/components/AccordionItem.svelte +40 -0
  5. package/src/lib/components/ActionMenu.svelte +96 -0
  6. package/src/lib/components/ActivityFeed.svelte +60 -0
  7. package/src/lib/components/Alert.svelte +19 -0
  8. package/src/lib/components/AnnotatedTimeSeries.svelte +90 -0
  9. package/src/lib/components/ArcDiagram.svelte +74 -0
  10. package/src/lib/components/AreaChart.svelte +64 -0
  11. package/src/lib/components/Avatar.svelte +30 -0
  12. package/src/lib/components/AvatarGroup.svelte +35 -0
  13. package/src/lib/components/Badge.svelte +25 -0
  14. package/src/lib/components/Banner.svelte +37 -0
  15. package/src/lib/components/BarChart.svelte +52 -0
  16. package/src/lib/components/BeeswarmChart.svelte +88 -0
  17. package/src/lib/components/BoxPlot.svelte +66 -0
  18. package/src/lib/components/Breadcrumb.svelte +31 -0
  19. package/src/lib/components/BubbleChart.svelte +69 -0
  20. package/src/lib/components/BulletChart.svelte +70 -0
  21. package/src/lib/components/BumpChart.svelte +109 -0
  22. package/src/lib/components/Button.svelte +25 -0
  23. package/src/lib/components/CIDRInput.svelte +142 -0
  24. package/src/lib/components/CalendarHeatmap.svelte +86 -0
  25. package/src/lib/components/Callout.svelte +38 -0
  26. package/src/lib/components/CandlestickChart.svelte +66 -0
  27. package/src/lib/components/Card.svelte +11 -0
  28. package/src/lib/components/Carousel.svelte +64 -0
  29. package/src/lib/components/Checkbox.svelte +45 -0
  30. package/src/lib/components/ChordDiagram.svelte +90 -0
  31. package/src/lib/components/CirclePacking.svelte +119 -0
  32. package/src/lib/components/CodeBlock.svelte +49 -0
  33. package/src/lib/components/ColorPicker.svelte +91 -0
  34. package/src/lib/components/ColumnToggle.svelte +96 -0
  35. package/src/lib/components/Combobox.svelte +138 -0
  36. package/src/lib/components/CommandPalette.svelte +152 -0
  37. package/src/lib/components/ConfirmDialog.svelte +84 -0
  38. package/src/lib/components/ContextMenu.svelte +107 -0
  39. package/src/lib/components/ContextualHelp.svelte +73 -0
  40. package/src/lib/components/ContourPlot.svelte +164 -0
  41. package/src/lib/components/CopyButton.svelte +33 -0
  42. package/src/lib/components/CorrelationMatrix.svelte +90 -0
  43. package/src/lib/components/CountUp.svelte +49 -0
  44. package/src/lib/components/CumulativeDistribution.svelte +67 -0
  45. package/src/lib/components/DatePicker.svelte +201 -0
  46. package/src/lib/components/DateRangePicker.svelte +249 -0
  47. package/src/lib/components/Dendrogram.svelte +128 -0
  48. package/src/lib/components/Donut.svelte +49 -0
  49. package/src/lib/components/DotPlot.svelte +121 -0
  50. package/src/lib/components/Drawer.svelte +60 -0
  51. package/src/lib/components/DualAxisChart.svelte +80 -0
  52. package/src/lib/components/DumbbellChart.svelte +56 -0
  53. package/src/lib/components/DurationInput.svelte +118 -0
  54. package/src/lib/components/EmptyState.svelte +21 -0
  55. package/src/lib/components/ErrorBandChart.svelte +69 -0
  56. package/src/lib/components/ExpandableRow.svelte +42 -0
  57. package/src/lib/components/Field.svelte +40 -0
  58. package/src/lib/components/FileUpload.svelte +96 -0
  59. package/src/lib/components/FilterBuilder.svelte +160 -0
  60. package/src/lib/components/FlameGraph.svelte +88 -0
  61. package/src/lib/components/ForceGraph.svelte +104 -0
  62. package/src/lib/components/FunnelChart.svelte +50 -0
  63. package/src/lib/components/GanttChart.svelte +49 -0
  64. package/src/lib/components/Gauge.svelte +53 -0
  65. package/src/lib/components/GroupedList.svelte +87 -0
  66. package/src/lib/components/HealthBar.svelte +19 -0
  67. package/src/lib/components/HeatMap.svelte +64 -0
  68. package/src/lib/components/HexbinChart.svelte +100 -0
  69. package/src/lib/components/Histogram.svelte +93 -0
  70. package/src/lib/components/HorizonChart.svelte +71 -0
  71. package/src/lib/components/HoverCard.svelte +45 -0
  72. package/src/lib/components/IPInput.svelte +103 -0
  73. package/src/lib/components/IcicleChart.svelte +87 -0
  74. package/src/lib/components/IconButton.svelte +19 -0
  75. package/src/lib/components/InlineEdit.svelte +72 -0
  76. package/src/lib/components/Input.svelte +18 -0
  77. package/src/lib/components/InputGroup.svelte +14 -0
  78. package/src/lib/components/JsonViewer.svelte +15 -0
  79. package/src/lib/components/JsonViewerNode.svelte +59 -0
  80. package/src/lib/components/KVTable.svelte +18 -0
  81. package/src/lib/components/KanbanBoard.svelte +141 -0
  82. package/src/lib/components/Kbd.svelte +16 -0
  83. package/src/lib/components/LineChart.svelte +67 -0
  84. package/src/lib/components/LogViewer.svelte +84 -0
  85. package/src/lib/components/LollipopChart.svelte +79 -0
  86. package/src/lib/components/MACInput.svelte +98 -0
  87. package/src/lib/components/MarimekkoChart.svelte +108 -0
  88. package/src/lib/components/MatrixChart.svelte +55 -0
  89. package/src/lib/components/Menubar.svelte +131 -0
  90. package/src/lib/components/MirroredBarChart.svelte +120 -0
  91. package/src/lib/components/Modal.svelte +90 -0
  92. package/src/lib/components/MultiSelect.svelte +165 -0
  93. package/src/lib/components/NightingaleChart.svelte +63 -0
  94. package/src/lib/components/NotificationPanel.svelte +170 -0
  95. package/src/lib/components/NumberInput.svelte +93 -0
  96. package/src/lib/components/OTPInput.svelte +94 -0
  97. package/src/lib/components/Pagination.svelte +58 -0
  98. package/src/lib/components/ParallelCoordinates.svelte +98 -0
  99. package/src/lib/components/ParetoChart.svelte +88 -0
  100. package/src/lib/components/PasswordInput.svelte +62 -0
  101. package/src/lib/components/PieChart.svelte +91 -0
  102. package/src/lib/components/Pill.svelte +12 -0
  103. package/src/lib/components/PolarHeatmap.svelte +85 -0
  104. package/src/lib/components/Popover.svelte +89 -0
  105. package/src/lib/components/ProgressBar.svelte +29 -0
  106. package/src/lib/components/PunchCard.svelte +73 -0
  107. package/src/lib/components/QuadrantChart.svelte +122 -0
  108. package/src/lib/components/RadarChart.svelte +71 -0
  109. package/src/lib/components/RadialBarChart.svelte +76 -0
  110. package/src/lib/components/RadioGroup.svelte +48 -0
  111. package/src/lib/components/RangeSlider.svelte +68 -0
  112. package/src/lib/components/RankedList.svelte +49 -0
  113. package/src/lib/components/ResizablePanel.svelte +77 -0
  114. package/src/lib/components/RidgelinePlot.svelte +103 -0
  115. package/src/lib/components/RowToggle.svelte +19 -0
  116. package/src/lib/components/SankeyDiagram.svelte +100 -0
  117. package/src/lib/components/ScatterPlot.svelte +54 -0
  118. package/src/lib/components/SearchBox.svelte +11 -0
  119. package/src/lib/components/SegmentedControl.svelte +51 -0
  120. package/src/lib/components/Select.svelte +110 -0
  121. package/src/lib/components/SelectionToolbar.svelte +42 -0
  122. package/src/lib/components/Sidebar.svelte +44 -0
  123. package/src/lib/components/Signal.svelte +12 -0
  124. package/src/lib/components/Skeleton.svelte +23 -0
  125. package/src/lib/components/SkipLink.svelte +9 -0
  126. package/src/lib/components/Slider.svelte +48 -0
  127. package/src/lib/components/SlopeChart.svelte +91 -0
  128. package/src/lib/components/SortHeader.svelte +19 -0
  129. package/src/lib/components/SortableList.svelte +87 -0
  130. package/src/lib/components/Sparkline.svelte +32 -0
  131. package/src/lib/components/SparklineMatrix.svelte +84 -0
  132. package/src/lib/components/Spinner.svelte +6 -0
  133. package/src/lib/components/SplitButton.svelte +102 -0
  134. package/src/lib/components/Spoiler.svelte +41 -0
  135. package/src/lib/components/StackedBarChart.svelte +83 -0
  136. package/src/lib/components/StackedProgress.svelte +32 -0
  137. package/src/lib/components/StarRating.svelte +64 -0
  138. package/src/lib/components/Stat.svelte +24 -0
  139. package/src/lib/components/StatusIndicator.svelte +10 -0
  140. package/src/lib/components/StepChart.svelte +74 -0
  141. package/src/lib/components/Stepper.svelte +40 -0
  142. package/src/lib/components/StreamGraph.svelte +93 -0
  143. package/src/lib/components/StripeChart.svelte +52 -0
  144. package/src/lib/components/SunburstChart.svelte +80 -0
  145. package/src/lib/components/SwitchPortGrid.svelte +45 -0
  146. package/src/lib/components/TabPanel.svelte +17 -0
  147. package/src/lib/components/Tabs.svelte +45 -0
  148. package/src/lib/components/Tag.svelte +19 -0
  149. package/src/lib/components/TagInput.svelte +92 -0
  150. package/src/lib/components/Textarea.svelte +31 -0
  151. package/src/lib/components/ThresholdAreaChart.svelte +72 -0
  152. package/src/lib/components/TimePicker.svelte +116 -0
  153. package/src/lib/components/TimeRange.svelte +104 -0
  154. package/src/lib/components/Timeline.svelte +32 -0
  155. package/src/lib/components/Toast.svelte +52 -0
  156. package/src/lib/components/Toggle.svelte +23 -0
  157. package/src/lib/components/ToggleGroup.svelte +32 -0
  158. package/src/lib/components/Tooltip.svelte +16 -0
  159. package/src/lib/components/Topbar.svelte +63 -0
  160. package/src/lib/components/TransferList.svelte +184 -0
  161. package/src/lib/components/TreeItem.svelte +61 -0
  162. package/src/lib/components/TreeMap.svelte +90 -0
  163. package/src/lib/components/TreeView.svelte +130 -0
  164. package/src/lib/components/UptimeTimeline.svelte +86 -0
  165. package/src/lib/components/VennDiagram.svelte +91 -0
  166. package/src/lib/components/ViolinPlot.svelte +114 -0
  167. package/src/lib/components/VirtualList.svelte +38 -0
  168. package/src/lib/components/WaffleChart.svelte +68 -0
  169. package/src/lib/components/WaterfallChart.svelte +96 -0
  170. package/src/lib/components/WordCloud.svelte +103 -0
  171. package/src/lib/icons/AlarmIcon.svelte +5 -0
  172. package/src/lib/icons/BellIcon.svelte +6 -0
  173. package/src/lib/icons/CaretIcon.svelte +8 -0
  174. package/src/lib/icons/ClientsIcon.svelte +5 -0
  175. package/src/lib/icons/CloseIcon.svelte +6 -0
  176. package/src/lib/icons/DashboardIcon.svelte +7 -0
  177. package/src/lib/icons/DevicesIcon.svelte +5 -0
  178. package/src/lib/icons/DownloadIcon.svelte +6 -0
  179. package/src/lib/icons/HelpIcon.svelte +7 -0
  180. package/src/lib/icons/InfraIcon.svelte +7 -0
  181. package/src/lib/icons/IntegrationsIcon.svelte +5 -0
  182. package/src/lib/icons/LogsIcon.svelte +6 -0
  183. package/src/lib/icons/PlusIcon.svelte +6 -0
  184. package/src/lib/icons/PortsIcon.svelte +6 -0
  185. package/src/lib/icons/SearchIcon.svelte +10 -0
  186. package/src/lib/icons/SecurityIcon.svelte +4 -0
  187. package/src/lib/icons/SettingsIcon.svelte +5 -0
  188. package/src/lib/icons/TopologyIcon.svelte +7 -0
  189. package/src/lib/icons/UpdatesIcon.svelte +6 -0
  190. package/src/lib/icons/VpnIcon.svelte +5 -0
  191. package/src/lib/icons/WifiIcon.svelte +5 -0
  192. package/src/lib/icons/WirelessIcon.svelte +4 -0
  193. package/src/lib/icons.ts +22 -0
  194. package/src/lib/index.ts +275 -0
  195. package/src/lib/styles.css +2 -0
@@ -0,0 +1,88 @@
1
+ <script lang="ts">
2
+ export interface FlameNode {
3
+ label: string;
4
+ value?: number;
5
+ color?: string;
6
+ children?: FlameNode[];
7
+ }
8
+
9
+ export let root: FlameNode;
10
+ export let height = 160;
11
+ export let ariaLabel = 'Flame graph';
12
+
13
+ const PALETTE = ['#006FFF', '#FF7B2E', '#F5A623', '#FB923C', '#F97316', '#EF4444', '#A78BFA'];
14
+ const VW = 340;
15
+ const GAP = 1.5;
16
+
17
+ interface FlatCell {
18
+ x: number; y: number; w: number; h: number;
19
+ label: string; color: string; depth: number;
20
+ }
21
+
22
+ function nodeValue(node: FlameNode): number {
23
+ if (node.children?.length) return node.children.reduce((s, c) => s + nodeValue(c), 0);
24
+ return node.value ?? 1;
25
+ }
26
+
27
+ function treeDepth(node: FlameNode): number {
28
+ if (!node.children?.length) return 0;
29
+ return 1 + Math.max(...node.children.map(treeDepth));
30
+ }
31
+
32
+ function flatten(node: FlameNode, x: number, depth: number, w: number, levelH: number, totalHeight: number, inheritColor: string, colorIdx: { n: number }): FlatCell[] {
33
+ let color = node.color ?? '';
34
+ if (!color) {
35
+ if (depth === 0) color = 'rgba(255,255,255,0.10)';
36
+ else if (depth === 1) color = PALETTE[colorIdx.n++ % PALETTE.length];
37
+ else color = inheritColor;
38
+ }
39
+ const y = totalHeight - (depth + 1) * levelH;
40
+ const cells: FlatCell[] = [{ x, y, w, h: levelH, label: node.label, color, depth }];
41
+ if (node.children?.length && w > 0) {
42
+ const total = nodeValue(node);
43
+ let cx = x;
44
+ for (const child of node.children) {
45
+ const cw = total > 0 ? (nodeValue(child) / total) * w : 0;
46
+ cells.push(...flatten(child, cx, depth + 1, cw, levelH, totalHeight, color, colorIdx));
47
+ cx += cw;
48
+ }
49
+ }
50
+ return cells;
51
+ }
52
+
53
+ $: depth = treeDepth(root);
54
+ $: levelH = height / (depth + 1);
55
+ $: cells = flatten(root, 0, 0, VW, levelH, height, PALETTE[0], { n: 0 });
56
+ </script>
57
+
58
+ {#if cells.length > 0}
59
+ <div role="img" aria-label={ariaLabel} style="width:100%;">
60
+ <svg viewBox="0 0 {VW} {height}" style="width:100%;height:auto;display:block;" aria-hidden="true" focusable="false">
61
+ {#each cells as cell, i (i)}
62
+ {#if cell.w > GAP * 2}
63
+ <g>
64
+ <rect
65
+ x={cell.x + GAP / 2}
66
+ y={cell.y + GAP / 2}
67
+ width={Math.max(0, cell.w - GAP)}
68
+ height={Math.max(0, cell.h - GAP)}
69
+ fill={cell.color}
70
+ fill-opacity={cell.depth === 0 ? 1 : cell.depth === 1 ? 0.7 : 0.85}
71
+ rx={2}
72
+ />
73
+ {#if cell.w > 32}
74
+ <text
75
+ x={cell.x + cell.w / 2}
76
+ y={cell.y + cell.h / 2 + 4}
77
+ text-anchor="middle"
78
+ font-size={Math.min(10, (cell.w - GAP) / 6, cell.h - 4)}
79
+ fill="#fff"
80
+ font-family="inherit"
81
+ >{cell.label}</text>
82
+ {/if}
83
+ </g>
84
+ {/if}
85
+ {/each}
86
+ </svg>
87
+ </div>
88
+ {/if}
@@ -0,0 +1,104 @@
1
+ <script lang="ts">
2
+ export interface FDNode {
3
+ id: string;
4
+ label?: string;
5
+ color?: string;
6
+ r?: number;
7
+ }
8
+ export interface FDLink {
9
+ source: string;
10
+ target: string;
11
+ }
12
+
13
+ export let nodes: FDNode[] = [];
14
+ export let links: FDLink[] = [];
15
+ export let height = 260;
16
+ export let ariaLabel = 'Force-directed network graph';
17
+
18
+ const PALETTE = ['#006FFF', '#00C875', '#FF7B7B', '#F5C26B', '#A78BFA', '#34D399'];
19
+ const VW = 340;
20
+ const ITERS = 300;
21
+
22
+ type State = { x: number; y: number; vx: number; vy: number };
23
+
24
+ function layout(W: number, H: number): { x: number; y: number }[] {
25
+ const idxById: Record<string, number> = {};
26
+ nodes.forEach((n, i) => { idxById[n.id] = i; });
27
+ const edges = links
28
+ .map((l) => [idxById[l.source], idxById[l.target]] as [number, number])
29
+ .filter(([a, b]) => a !== undefined && b !== undefined);
30
+
31
+ const cx = W / 2;
32
+ const cy = H / 2;
33
+ const step = (2 * Math.PI) / nodes.length;
34
+ const r0 = Math.min(W, H) * 0.35;
35
+
36
+ const state: State[] = nodes.map((_, i) => ({
37
+ x: cx + r0 * Math.cos(i * step),
38
+ y: cy + r0 * Math.sin(i * step),
39
+ vx: 0,
40
+ vy: 0,
41
+ }));
42
+
43
+ for (let iter = 0; iter < ITERS; iter++) {
44
+ for (const [a, b] of edges) {
45
+ const dx = state[b].x - state[a].x;
46
+ const dy = state[b].y - state[a].y;
47
+ const d = Math.sqrt(dx * dx + dy * dy) || 1;
48
+ const f = 0.04 * (d - 80) / d;
49
+ state[a].vx += dx * f;
50
+ state[a].vy += dy * f;
51
+ state[b].vx -= dx * f;
52
+ state[b].vy -= dy * f;
53
+ }
54
+ for (let i = 0; i < state.length; i++) {
55
+ for (let j = i + 1; j < state.length; j++) {
56
+ const dx = state[j].x - state[i].x;
57
+ const dy = state[j].y - state[i].y;
58
+ const d2 = dx * dx + dy * dy || 1;
59
+ const d = Math.sqrt(d2);
60
+ const f = 600 / d2;
61
+ state[i].vx -= (dx / d) * f;
62
+ state[i].vy -= (dy / d) * f;
63
+ state[j].vx += (dx / d) * f;
64
+ state[j].vy += (dy / d) * f;
65
+ }
66
+ }
67
+ for (const s of state) {
68
+ s.vx += (cx - s.x) * 0.008;
69
+ s.vy += (cy - s.y) * 0.008;
70
+ s.vx *= 0.85;
71
+ s.vy *= 0.85;
72
+ s.x += s.vx;
73
+ s.y += s.vy;
74
+ }
75
+ }
76
+
77
+ return state.map((s) => ({ x: s.x, y: s.y }));
78
+ }
79
+
80
+ $: pos = nodes.length > 0 ? layout(VW, height) : [];
81
+ $: idxById = Object.fromEntries(nodes.map((n, i) => [n.id, i]));
82
+ </script>
83
+
84
+ {#if nodes.length > 0}
85
+ <div role="img" aria-label={ariaLabel} style="width:100%;">
86
+ <svg viewBox="0 0 {VW} {height}" style="width:100%;height:auto;display:block;" aria-hidden="true" focusable="false">
87
+ {#each links as l, li (li)}
88
+ {@const si = idxById[l.source]}
89
+ {@const ti = idxById[l.target]}
90
+ {#if si !== undefined && ti !== undefined}
91
+ <line x1={pos[si].x} y1={pos[si].y} x2={pos[ti].x} y2={pos[ti].y} stroke="rgba(255,255,255,0.12)" stroke-width="1.5" />
92
+ {/if}
93
+ {/each}
94
+ {#each nodes as n, ni (ni)}
95
+ {@const r = n.r ?? 10}
96
+ {@const color = n.color ?? PALETTE[ni % PALETTE.length]}
97
+ <g>
98
+ <circle cx={pos[ni].x} cy={pos[ni].y} r={r} fill={color} fill-opacity="0.85" />
99
+ <text x={pos[ni].x} y={pos[ni].y + r + 11} fill="#A4A7B5" font-size="8" text-anchor="middle" font-family="inherit">{n.label ?? n.id}</text>
100
+ </g>
101
+ {/each}
102
+ </svg>
103
+ </div>
104
+ {/if}
@@ -0,0 +1,50 @@
1
+ <script lang="ts">
2
+ export interface FunnelSegment {
3
+ label: string;
4
+ value: number;
5
+ color?: string;
6
+ }
7
+
8
+ export let segments: FunnelSegment[] = [];
9
+ export let height: number = 160;
10
+ export let ariaLabel: string = 'Funnel chart';
11
+
12
+ const VW = 320;
13
+ const PAD = { t: 4, r: 8, b: 4, l: 8 };
14
+ const SEP = 2;
15
+ const DEFAULT_COLORS = ['#006FFF', '#0092FF', '#00B4C2', '#00C875', '#F5A623'];
16
+
17
+ $: maxVal = segments.length ? Math.max(...segments.map((s) => s.value)) : 1;
18
+ $: n = segments.length;
19
+ $: chartH = height - PAD.t - PAD.b;
20
+ $: slotH = n > 0 ? (chartH - SEP * (n - 1)) / n : chartH;
21
+ $: chartW = VW - PAD.l - PAD.r;
22
+ $: cx = PAD.l + chartW / 2;
23
+ $: widths = segments.map((s) => (s.value / (maxVal || 1)) * chartW);
24
+
25
+ $: shapes = segments.map((s, i) => {
26
+ const tw = widths[i];
27
+ const bw = i + 1 < n ? widths[i + 1] : widths[i] * 0.7;
28
+ const y0 = PAD.t + i * (slotH + SEP);
29
+ const y1 = y0 + slotH;
30
+ return {
31
+ points: `${(cx - tw / 2).toFixed(1)},${y0.toFixed(1)} ${(cx + tw / 2).toFixed(1)},${y0.toFixed(1)} ${(cx + bw / 2).toFixed(1)},${y1.toFixed(1)} ${(cx - bw / 2).toFixed(1)},${y1.toFixed(1)}`,
32
+ color: s.color ?? DEFAULT_COLORS[i % DEFAULT_COLORS.length],
33
+ label: s.label,
34
+ value: s.value,
35
+ cx: cx.toFixed(1),
36
+ cy: ((y0 + y1) / 2).toFixed(1),
37
+ };
38
+ });
39
+ </script>
40
+
41
+ <div role="img" aria-label={ariaLabel} style="width:100%;">
42
+ <svg viewBox="0 0 {VW} {height}" style="width:100%;height:auto;display:block;" aria-hidden="true" focusable="false">
43
+ {#each shapes as s, i (i)}
44
+ <polygon points={s.points} fill={s.color} fill-opacity="0.75" />
45
+ <text x={s.cx} y={s.cy} text-anchor="middle" dominant-baseline="central" fill="rgba(255,255,255,0.9)" font-size="10" font-family="inherit" font-weight="500">
46
+ {s.label} · {s.value}
47
+ </text>
48
+ {/each}
49
+ </svg>
50
+ </div>
@@ -0,0 +1,49 @@
1
+ <script lang="ts">
2
+ export interface GanttTask {
3
+ label: string;
4
+ start: number;
5
+ end: number;
6
+ color?: string;
7
+ }
8
+
9
+ export let tasks: GanttTask[] = [];
10
+ export let xLabels: string[] = [];
11
+ export let ariaLabel: string = 'Gantt chart';
12
+
13
+ const VW = 340;
14
+ const LABEL_W = 100;
15
+ const PAD_R = 8;
16
+ const TRACK_W = VW - LABEL_W - PAD_R;
17
+ const ROW_H = 28;
18
+ const BAR_H = 14;
19
+ const PAD_T = 6;
20
+ const AXIS_H = 18;
21
+
22
+ $: svgH = PAD_T + tasks.length * ROW_H + AXIS_H;
23
+ $: ticks = xLabels.map((lbl, i) => ({
24
+ x: LABEL_W + (i / (xLabels.length - 1 || 1)) * TRACK_W,
25
+ lbl,
26
+ }));
27
+
28
+ function tx(v: number): number {
29
+ return LABEL_W + v * TRACK_W;
30
+ }
31
+ </script>
32
+
33
+ <div role="img" aria-label={ariaLabel} style="width:100%;">
34
+ <svg viewBox="0 0 {VW} {svgH}" style="width:100%;height:auto;display:block;" aria-hidden="true" focusable="false">
35
+ {#each ticks as { x, lbl }, i}
36
+ <line x1={x} y1={PAD_T} x2={x} y2={PAD_T + tasks.length * ROW_H} stroke="rgba(255,255,255,0.06)" stroke-width="1" />
37
+ <text x={x} y={PAD_T + tasks.length * ROW_H + 13} fill="#6E7079" font-size="9" text-anchor="middle" font-family="inherit">{lbl}</text>
38
+ {/each}
39
+ {#each tasks as task, i}
40
+ {@const cy = PAD_T + i * ROW_H + ROW_H / 2}
41
+ {@const x1 = tx(task.start)}
42
+ {@const x2 = tx(task.end)}
43
+ {@const barW = Math.max(x2 - x1, 4)}
44
+ {@const color = task.color ?? '#006FFF'}
45
+ <text x={LABEL_W - 6} y={cy + 4} fill="#A4A7B5" font-size="10" text-anchor="end" font-family="inherit">{task.label}</text>
46
+ <rect x={x1} y={cy - BAR_H / 2} width={barW} height={BAR_H} rx="3" fill={color} opacity="0.85" />
47
+ {/each}
48
+ </svg>
49
+ </div>
@@ -0,0 +1,53 @@
1
+ <script lang="ts">
2
+ export let value: number = 0;
3
+ export let label: string = '';
4
+ export let color: string = '#006FFF';
5
+ export let size: number = 120;
6
+ export let ariaLabel: string | undefined = undefined;
7
+
8
+ $: sw = 10;
9
+ $: cx = size / 2;
10
+ $: cy = size / 2;
11
+ $: r = cx - sw / 2 - 2;
12
+ $: svgH = Math.round(size * 0.7);
13
+ $: pathLen = Math.PI * r;
14
+ $: fillLen = (Math.min(100, Math.max(0, value)) / 100) * pathLen;
15
+ $: d = `M ${cx - r},${cy} A ${r},${r} 0 1 1 ${cx + r},${cy}`;
16
+ $: valY = cy + Math.round(size * 0.06);
17
+ $: lblY = valY + Math.round(size * 0.13) + 2;
18
+ $: a11yLabel = ariaLabel ?? `${label} ${value}%`;
19
+ </script>
20
+
21
+ <div
22
+ role="meter"
23
+ aria-valuenow={value}
24
+ aria-valuemin={0}
25
+ aria-valuemax={100}
26
+ aria-label={a11yLabel}
27
+ style="display:inline-flex;flex-direction:column;align-items:center;"
28
+ >
29
+ <svg width={size} height={svgH} aria-hidden="true" focusable="false">
30
+ <path {d} fill="none" stroke="rgba(255,255,255,0.08)" stroke-width={sw} stroke-linecap="round" />
31
+ <path
32
+ {d}
33
+ fill="none"
34
+ stroke={color}
35
+ stroke-width={sw}
36
+ stroke-linecap="round"
37
+ stroke-dasharray="{fillLen} {pathLen}"
38
+ />
39
+ <text
40
+ x={cx}
41
+ y={valY}
42
+ text-anchor="middle"
43
+ fill="#fff"
44
+ font-size={Math.round(size * 0.2)}
45
+ font-weight={600}
46
+ >
47
+ {value}%
48
+ </text>
49
+ <text x={cx} y={lblY} text-anchor="middle" fill="#6E7079" font-size={Math.round(size * 0.1)}>
50
+ {label}
51
+ </text>
52
+ </svg>
53
+ </div>
@@ -0,0 +1,87 @@
1
+ <script context="module" lang="ts">
2
+ export type GroupedListItemStatus = 'danger' | 'warn' | 'success' | 'info' | 'neutral';
3
+
4
+ export interface GroupedListItem {
5
+ label: string;
6
+ sublabel?: string;
7
+ meta?: string;
8
+ status?: GroupedListItemStatus;
9
+ }
10
+
11
+ export interface GroupedListGroup {
12
+ label: string;
13
+ items: GroupedListItem[];
14
+ defaultOpen?: boolean;
15
+ color?: string;
16
+ }
17
+ </script>
18
+
19
+ <script lang="ts">
20
+ export let groups: GroupedListGroup[];
21
+ export let collapsible: boolean = true;
22
+ export let ariaLabel: string = 'Grouped list';
23
+
24
+ const STATUS_COLORS: Record<GroupedListItemStatus, string> = {
25
+ danger: '#F03A3A',
26
+ warn: '#F5A623',
27
+ success: '#00B070',
28
+ info: '#006FFF',
29
+ neutral: '#6E7079',
30
+ };
31
+
32
+ const uid = Math.random().toString(36).slice(2, 9);
33
+ let open: boolean[] = groups.map(g => g.defaultOpen !== false);
34
+
35
+ function toggle(i: number) { open[i] = !open[i]; open = [...open]; }
36
+ </script>
37
+
38
+ <div class="gl" aria-label={ariaLabel}>
39
+ {#each groups as group, gi}
40
+ {@const isOpen = open[gi]}
41
+ {@const panelId = `${uid}-gl-${gi}`}
42
+ <div class="gl-group">
43
+ {#if collapsible}
44
+ <button
45
+ type="button"
46
+ class="gl-header"
47
+ aria-expanded={isOpen}
48
+ aria-controls={panelId}
49
+ on:click={() => toggle(gi)}
50
+ >
51
+ {#if group.color}<span class="gl-color-dot" style="background:{group.color}" aria-hidden="true"></span>{/if}
52
+ <span class="gl-title">{group.label}</span>
53
+ <span class="gl-count">{group.items.length}</span>
54
+ <svg
55
+ class="gl-chevron{isOpen ? ' gl-chevron--open' : ''}"
56
+ width="12" height="12" viewBox="0 0 12 12"
57
+ aria-hidden="true" focusable="false"
58
+ >
59
+ <path d="M2 4l4 4 4-4" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
60
+ </svg>
61
+ </button>
62
+ {:else}
63
+ <div class="gl-header gl-header--static">
64
+ {#if group.color}<span class="gl-color-dot" style="background:{group.color}" aria-hidden="true"></span>{/if}
65
+ <span class="gl-title">{group.label}</span>
66
+ <span class="gl-count">{group.items.length}</span>
67
+ </div>
68
+ {/if}
69
+ {#if !collapsible || isOpen}
70
+ <ul id={panelId} class="gl-items" role="list">
71
+ {#each group.items as item}
72
+ <li class="gl-item">
73
+ {#if item.status}
74
+ <span class="gl-item-dot" style="background:{STATUS_COLORS[item.status]}" aria-label={item.status}></span>
75
+ {/if}
76
+ <div class="gl-item-body">
77
+ <div class="gl-item-label">{item.label}</div>
78
+ {#if item.sublabel}<div class="gl-item-sublabel">{item.sublabel}</div>{/if}
79
+ </div>
80
+ {#if item.meta}<span class="gl-item-meta">{item.meta}</span>{/if}
81
+ </li>
82
+ {/each}
83
+ </ul>
84
+ {/if}
85
+ </div>
86
+ {/each}
87
+ </div>
@@ -0,0 +1,19 @@
1
+ <script lang="ts">
2
+ export let value: number;
3
+ export let fillStyle: string = '';
4
+ export let label: string | undefined = undefined;
5
+ export let valueText: string | undefined = undefined;
6
+ $: clamped = Math.max(0, Math.min(100, value));
7
+ </script>
8
+
9
+ <div
10
+ class="hb"
11
+ role="progressbar"
12
+ aria-valuenow={Math.round(clamped)}
13
+ aria-valuemin={0}
14
+ aria-valuemax={100}
15
+ aria-label={label}
16
+ aria-valuetext={valueText}
17
+ >
18
+ <div class="hb-fill" style="width:{clamped}%; {fillStyle}"></div>
19
+ </div>
@@ -0,0 +1,64 @@
1
+ <script lang="ts">
2
+ export let data: number[][] = [];
3
+ export let colors: string[] = ['#1B2D5A', '#3F7BC4', '#7FB6FF', '#F5C26B', '#F5A623', '#FF7B7B'];
4
+ export let xLabels: string[] = [];
5
+ export let height: number = 160;
6
+ export let cellGap: number = 1;
7
+ export let ariaLabel: string = 'Heat map';
8
+
9
+ const VW = 400;
10
+ const PAD_BASE = { t: 4, r: 4, l: 4 };
11
+
12
+ function hexToRgb(hex: string): [number, number, number] {
13
+ const n = parseInt(hex.slice(1), 16);
14
+ return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
15
+ }
16
+
17
+ function interpolateColor(cs: string[], t: number): string {
18
+ if (cs.length === 1) return cs[0];
19
+ const scaled = Math.max(0, Math.min(1, t)) * (cs.length - 1);
20
+ const i = Math.min(Math.floor(scaled), cs.length - 2);
21
+ const f = scaled - i;
22
+ const [r1, g1, b1] = hexToRgb(cs[i]);
23
+ const [r2, g2, b2] = hexToRgb(cs[i + 1]);
24
+ return `rgb(${Math.round(r1 + f * (r2 - r1))},${Math.round(g1 + f * (g2 - g1))},${Math.round(b1 + f * (b2 - b1))})`;
25
+ }
26
+
27
+ $: rows = data.length;
28
+ $: cols = data[0]?.length ?? 0;
29
+ $: padB = xLabels.length ? 16 : 4;
30
+ $: chartW = VW - PAD_BASE.l - PAD_BASE.r;
31
+ $: chartH = height - PAD_BASE.t - padB;
32
+ $: cellW = cols > 0 ? (chartW - (cols - 1) * cellGap) / cols : 0;
33
+ $: cellH = rows > 0 ? (chartH - (rows - 1) * cellGap) / rows : 0;
34
+
35
+ $: rects = rows > 0 && cols > 0
36
+ ? data.flatMap((rowData, row) =>
37
+ rowData.map((val, col) => ({
38
+ key: `${row}-${col}`,
39
+ x: (PAD_BASE.l + col * (cellW + cellGap)).toFixed(2),
40
+ y: (PAD_BASE.t + row * (cellH + cellGap)).toFixed(2),
41
+ w: cellW.toFixed(2),
42
+ h: cellH.toFixed(2),
43
+ fill: interpolateColor(colors, val),
44
+ }))
45
+ )
46
+ : [];
47
+
48
+ $: labelNodes = xLabels.map((lbl, i) => ({
49
+ lbl,
50
+ x: (PAD_BASE.l + (xLabels.length > 1 ? (i / (xLabels.length - 1)) * chartW : chartW / 2)).toFixed(1),
51
+ y: height - 2,
52
+ }));
53
+ </script>
54
+
55
+ <div role="img" aria-label={ariaLabel} style="width:100%;">
56
+ <svg viewBox="0 0 {VW} {height}" style="width:100%;height:auto;display:block;" aria-hidden="true" focusable="false">
57
+ {#each rects as r (r.key)}
58
+ <rect x={r.x} y={r.y} width={r.w} height={r.h} fill={r.fill} />
59
+ {/each}
60
+ {#each labelNodes as { lbl, x, y }}
61
+ <text {x} {y} text-anchor="middle" fill="#6E7079" font-size="9">{lbl}</text>
62
+ {/each}
63
+ </svg>
64
+ </div>
@@ -0,0 +1,100 @@
1
+ <script lang="ts">
2
+ export interface HexbinPoint {
3
+ x: number;
4
+ y: number;
5
+ }
6
+
7
+ export let points: HexbinPoint[] = [];
8
+ export let xRange: [number, number] | undefined = undefined;
9
+ export let yRange: [number, number] | undefined = undefined;
10
+ export let height = 200;
11
+ export let hexRadius = 10;
12
+ export let ariaLabel = 'Hexbin chart';
13
+
14
+ const ROOT3 = Math.sqrt(3);
15
+ const VW = 340;
16
+ const PAD_L = 28;
17
+ const PAD_R = 8;
18
+ const PAD_T = 8;
19
+ const PAD_B = 20;
20
+
21
+ function pixelToHex(px: number, py: number, R: number): [number, number] {
22
+ const q = (ROOT3 / 3 * px - 1 / 3 * py) / R;
23
+ const r = (2 / 3 * py) / R;
24
+ const s = -q - r;
25
+ let rq = Math.round(q), rr = Math.round(r), rs = Math.round(s);
26
+ const dq = Math.abs(rq - q), dr = Math.abs(rr - r), ds = Math.abs(rs - s);
27
+ if (dq > dr && dq > ds) rq = -rr - rs;
28
+ else if (dr > ds) rr = -rq - rs;
29
+ else rs = -rq - rr;
30
+ void rs;
31
+ return [rq, rr];
32
+ }
33
+
34
+ function hexCenter(q: number, r: number, R: number, ox: number, oy: number): [number, number] {
35
+ return [ROOT3 * R * (q + r / 2) + ox, 1.5 * R * r + oy];
36
+ }
37
+
38
+ function hexPath(cx: number, cy: number, R: number): string {
39
+ const pts = Array.from({ length: 6 }, (_, k) => {
40
+ const a = Math.PI / 6 + (Math.PI / 3) * k;
41
+ return `${(cx + R * Math.cos(a)).toFixed(2)},${(cy + R * Math.sin(a)).toFixed(2)}`;
42
+ });
43
+ return `M${pts.join('L')}Z`;
44
+ }
45
+
46
+ $: PLOT_W = VW - PAD_L - PAD_R;
47
+ $: PLOT_H = height - PAD_T - PAD_B;
48
+ $: xs = points.map((p) => p.x);
49
+ $: ys = points.map((p) => p.y);
50
+ $: xMin = xRange ? xRange[0] : (xs.length ? Math.min(...xs) : 0);
51
+ $: xMax = xRange ? xRange[1] : (xs.length ? Math.max(...xs) : 1);
52
+ $: yMin = yRange ? yRange[0] : (ys.length ? Math.min(...ys) : 0);
53
+ $: yMax = yRange ? yRange[1] : (ys.length ? Math.max(...ys) : 1);
54
+ $: xSpan = xMax - xMin || 1;
55
+ $: ySpan = yMax - yMin || 1;
56
+
57
+ $: bins = (() => {
58
+ const map = new Map<string, { q: number; r: number; count: number }>();
59
+ for (const pt of points) {
60
+ const px = ((pt.x - xMin) / xSpan) * PLOT_W;
61
+ const py = (1 - (pt.y - yMin) / ySpan) * PLOT_H;
62
+ const [q, r] = pixelToHex(px, py, hexRadius);
63
+ const key = `${q},${r}`;
64
+ const bin = map.get(key);
65
+ if (bin) bin.count++;
66
+ else map.set(key, { q, r, count: 1 });
67
+ }
68
+ return [...map.values()];
69
+ })();
70
+
71
+ $: maxCount = bins.length ? Math.max(...bins.map((b) => b.count)) : 1;
72
+ $: yTicks = [yMin, (yMin + yMax) / 2, yMax];
73
+ $: xTicks = [xMin, (xMin + xMax) / 2, xMax];
74
+
75
+ function ty(v: number): number { return PAD_T + (1 - (v - yMin) / ySpan) * PLOT_H; }
76
+ function tx(v: number): number { return PAD_L + ((v - xMin) / xSpan) * PLOT_W; }
77
+ </script>
78
+
79
+ {#if points.length > 0}
80
+ <div role="img" aria-label={ariaLabel} style="width:100%;">
81
+ <svg viewBox="0 0 {VW} {height}" style="width:100%;height:auto;display:block;" aria-hidden="true" focusable="false">
82
+ {#each yTicks as v, i (i)}
83
+ <line x1={PAD_L} y1={ty(v)} x2={PAD_L + PLOT_W} y2={ty(v)} stroke="rgba(255,255,255,0.06)" stroke-width="1" />
84
+ <text x={PAD_L - 4} y={ty(v) + 3} fill="#6E7079" font-size="8" text-anchor="end" font-family="inherit">{Math.round(v)}</text>
85
+ {/each}
86
+
87
+ {#each bins as { q, r, count } (`${q},${r}`)}
88
+ {@const [cx, cy] = hexCenter(q, r, hexRadius, PAD_L, PAD_T)}
89
+ {#if cx >= PAD_L - hexRadius * 2 && cx <= PAD_L + PLOT_W + hexRadius * 2 && cy >= PAD_T - hexRadius * 2 && cy <= PAD_T + PLOT_H + hexRadius * 2}
90
+ {@const alpha = (0.15 + 0.85 * (count / maxCount)).toFixed(3)}
91
+ <path d={hexPath(cx, cy, hexRadius - 0.5)} fill="rgba(0,111,255,{alpha})" stroke="rgba(0,111,255,0.2)" stroke-width="0.5" />
92
+ {/if}
93
+ {/each}
94
+
95
+ {#each xTicks as v, i (i)}
96
+ <text x={tx(v)} y={height - 4} fill="#6E7079" font-size="8" text-anchor="middle" font-family="inherit">{Math.round(v)}</text>
97
+ {/each}
98
+ </svg>
99
+ </div>
100
+ {/if}