@hyvnt/hyvui 0.2.0 → 0.4.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 (181) hide show
  1. package/README.md +294 -253
  2. package/dist/components/ambient/ArcaneVein.svelte +151 -0
  3. package/dist/components/ambient/ArcaneVein.svelte.d.ts +31 -0
  4. package/dist/components/ambient/BrassFiligree.svelte +109 -0
  5. package/dist/components/ambient/BrassFiligree.svelte.d.ts +20 -0
  6. package/dist/components/ambient/CornerBrackets.svelte +91 -87
  7. package/dist/components/ambient/CornerBrackets.svelte.d.ts +8 -0
  8. package/dist/components/ambient/CrystalShard.svelte +151 -0
  9. package/dist/components/ambient/CrystalShard.svelte.d.ts +19 -0
  10. package/dist/components/ambient/DataStream.svelte +117 -94
  11. package/dist/components/ambient/DataStream.svelte.d.ts +6 -0
  12. package/dist/components/ambient/EnergyArc.svelte +189 -0
  13. package/dist/components/ambient/EnergyArc.svelte.d.ts +32 -0
  14. package/dist/components/ambient/GlyphMark.svelte +75 -69
  15. package/dist/components/ambient/GlyphMark.svelte.d.ts +6 -0
  16. package/dist/components/ambient/GridOverlay.svelte +34 -28
  17. package/dist/components/ambient/GridOverlay.svelte.d.ts +8 -0
  18. package/dist/components/ambient/HexGrid.svelte +119 -0
  19. package/dist/components/ambient/HexGrid.svelte.d.ts +21 -0
  20. package/dist/components/ambient/ParallaxLayer.svelte +45 -41
  21. package/dist/components/ambient/ParallaxLayer.svelte.d.ts +7 -0
  22. package/dist/components/ambient/ScanBand.svelte +103 -91
  23. package/dist/components/ambient/ScanBand.svelte.d.ts +8 -0
  24. package/dist/components/ambient/ShimmerCloud.svelte +180 -0
  25. package/dist/components/ambient/ShimmerCloud.svelte.d.ts +21 -0
  26. package/dist/components/ambient/SignalRing.svelte +106 -100
  27. package/dist/components/ambient/SignalRing.svelte.d.ts +6 -0
  28. package/dist/components/ambient/ThreadLine.svelte +78 -78
  29. package/dist/components/ambient/ThreadLine.svelte.d.ts +7 -0
  30. package/dist/components/ambient/Vignette.svelte +30 -26
  31. package/dist/components/ambient/Vignette.svelte.d.ts +6 -0
  32. package/dist/components/depth/DepthLayer.svelte +30 -27
  33. package/dist/components/depth/DepthLayer.svelte.d.ts +8 -0
  34. package/dist/components/depth/DepthStage.svelte +67 -62
  35. package/dist/components/depth/DepthStage.svelte.d.ts +8 -0
  36. package/dist/components/depth/FloatCard.svelte +129 -104
  37. package/dist/components/depth/FloatCard.svelte.d.ts +8 -0
  38. package/dist/components/depth/HorizonGrid.svelte +241 -160
  39. package/dist/components/depth/HorizonGrid.svelte.d.ts +9 -0
  40. package/dist/components/depth/Plinth.svelte +62 -57
  41. package/dist/components/depth/Plinth.svelte.d.ts +10 -0
  42. package/dist/components/display/Avatar.svelte +69 -69
  43. package/dist/components/display/Avatar.svelte.d.ts +5 -0
  44. package/dist/components/display/Badge.svelte +75 -63
  45. package/dist/components/display/Badge.svelte.d.ts +6 -0
  46. package/dist/components/display/Blockquote.svelte +35 -34
  47. package/dist/components/display/Blockquote.svelte.d.ts +4 -0
  48. package/dist/components/display/CodeBlock.svelte +76 -76
  49. package/dist/components/display/CodeBlock.svelte.d.ts +5 -0
  50. package/dist/components/display/MetricCard.svelte +100 -83
  51. package/dist/components/display/MetricCard.svelte.d.ts +6 -0
  52. package/dist/components/display/Table.svelte +106 -104
  53. package/dist/components/display/Table.svelte.d.ts +7 -0
  54. package/dist/components/feedback/Alert.svelte +95 -76
  55. package/dist/components/feedback/Alert.svelte.d.ts +6 -0
  56. package/dist/components/feedback/EmptyState.svelte +75 -68
  57. package/dist/components/feedback/EmptyState.svelte.d.ts +7 -0
  58. package/dist/components/feedback/ErrorState.svelte +78 -73
  59. package/dist/components/feedback/ErrorState.svelte.d.ts +5 -0
  60. package/dist/components/feedback/Skeleton.svelte +58 -52
  61. package/dist/components/feedback/Skeleton.svelte.d.ts +6 -0
  62. package/dist/components/feedback/StatusDot.svelte +84 -54
  63. package/dist/components/feedback/StatusDot.svelte.d.ts +6 -0
  64. package/dist/components/feedback/StatusLine.svelte +128 -122
  65. package/dist/components/feedback/StatusLine.svelte.d.ts +6 -0
  66. package/dist/components/feedback/Toast.svelte +144 -136
  67. package/dist/components/feedback/Toast.svelte.d.ts +10 -0
  68. package/dist/components/inputs/Button.svelte +310 -237
  69. package/dist/components/inputs/Button.svelte.d.ts +8 -0
  70. package/dist/components/inputs/Checkbox.svelte +109 -105
  71. package/dist/components/inputs/Checkbox.svelte.d.ts +5 -0
  72. package/dist/components/inputs/FileUpload.svelte +170 -163
  73. package/dist/components/inputs/FileUpload.svelte.d.ts +5 -0
  74. package/dist/components/inputs/Input.svelte +153 -147
  75. package/dist/components/inputs/Input.svelte.d.ts +7 -0
  76. package/dist/components/inputs/Select.svelte +164 -150
  77. package/dist/components/inputs/Select.svelte.d.ts +8 -0
  78. package/dist/components/inputs/Textarea.svelte +160 -154
  79. package/dist/components/inputs/Textarea.svelte.d.ts +6 -0
  80. package/dist/components/inputs/Toggle.svelte +125 -120
  81. package/dist/components/inputs/Toggle.svelte.d.ts +5 -0
  82. package/dist/components/layout/Card.svelte +81 -76
  83. package/dist/components/layout/Card.svelte.d.ts +11 -0
  84. package/dist/components/layout/Drawer.svelte +140 -109
  85. package/dist/components/layout/Drawer.svelte.d.ts +6 -0
  86. package/dist/components/layout/Grid.svelte +128 -43
  87. package/dist/components/layout/Grid.svelte.d.ts +18 -2
  88. package/dist/components/layout/Modal.svelte +191 -159
  89. package/dist/components/layout/Modal.svelte.d.ts +10 -0
  90. package/dist/components/layout/Panel.svelte +58 -54
  91. package/dist/components/layout/Panel.svelte.d.ts +9 -0
  92. package/dist/components/layout/Popover.svelte +188 -67
  93. package/dist/components/layout/Popover.svelte.d.ts +19 -1
  94. package/dist/components/layout/Stack.svelte +65 -53
  95. package/dist/components/layout/Stack.svelte.d.ts +12 -0
  96. package/dist/components/navigation/Breadcrumb.svelte +78 -73
  97. package/dist/components/navigation/Breadcrumb.svelte.d.ts +8 -0
  98. package/dist/components/navigation/DropdownMenu.svelte +179 -124
  99. package/dist/components/navigation/DropdownMenu.svelte.d.ts +24 -2
  100. package/dist/components/navigation/SidebarNav.svelte +96 -90
  101. package/dist/components/navigation/SidebarNav.svelte.d.ts +9 -0
  102. package/dist/components/navigation/Tabs.svelte +106 -86
  103. package/dist/components/navigation/Tabs.svelte.d.ts +8 -0
  104. package/dist/components/navigation/Topbar.svelte +94 -85
  105. package/dist/components/navigation/Topbar.svelte.d.ts +9 -0
  106. package/dist/components/patterns/ActionBar.svelte +82 -76
  107. package/dist/components/patterns/ActionBar.svelte.d.ts +10 -0
  108. package/dist/components/patterns/ChapterMark.svelte +152 -0
  109. package/dist/components/patterns/ChapterMark.svelte.d.ts +19 -0
  110. package/dist/components/patterns/ConfirmDialog.svelte +75 -64
  111. package/dist/components/patterns/ConfirmDialog.svelte.d.ts +12 -0
  112. package/dist/components/patterns/DepthPortal.svelte +123 -0
  113. package/dist/components/patterns/DepthPortal.svelte.d.ts +24 -0
  114. package/dist/components/patterns/Manifesto.svelte +171 -0
  115. package/dist/components/patterns/Manifesto.svelte.d.ts +25 -0
  116. package/dist/components/patterns/PageHeader.svelte +117 -114
  117. package/dist/components/patterns/PageHeader.svelte.d.ts +8 -0
  118. package/dist/components/patterns/PullQuote.svelte +145 -0
  119. package/dist/components/patterns/PullQuote.svelte.d.ts +23 -0
  120. package/dist/components/patterns/RegisterSwitcher.svelte +132 -0
  121. package/dist/components/patterns/RegisterSwitcher.svelte.d.ts +21 -0
  122. package/dist/components/patterns/SearchBar.svelte +59 -59
  123. package/dist/components/patterns/SearchBar.svelte.d.ts +5 -0
  124. package/dist/components/patterns/ShowcaseFrame.svelte +117 -0
  125. package/dist/components/patterns/ShowcaseFrame.svelte.d.ts +28 -0
  126. package/dist/components/patterns/TerminalBoot.svelte +118 -104
  127. package/dist/components/patterns/TerminalBoot.svelte.d.ts +12 -0
  128. package/dist/components/primitives/Divider.svelte +56 -29
  129. package/dist/components/primitives/Divider.svelte.d.ts +5 -0
  130. package/dist/components/primitives/Icon.svelte +53 -49
  131. package/dist/components/primitives/Icon.svelte.d.ts +9 -0
  132. package/dist/components/primitives/Label.svelte +45 -44
  133. package/dist/components/primitives/Label.svelte.d.ts +6 -0
  134. package/dist/components/primitives/Surface.svelte +154 -87
  135. package/dist/components/primitives/Surface.svelte.d.ts +7 -0
  136. package/dist/components/primitives/Text.svelte +130 -98
  137. package/dist/components/primitives/Text.svelte.d.ts +7 -0
  138. package/dist/components/scenes/ArchiveScene.svelte +102 -95
  139. package/dist/components/scenes/ArchiveScene.svelte.d.ts +17 -1
  140. package/dist/components/scenes/DepthScene.svelte +128 -0
  141. package/dist/components/scenes/DepthScene.svelte.d.ts +36 -0
  142. package/dist/components/scenes/LogScene.svelte +86 -77
  143. package/dist/components/scenes/LogScene.svelte.d.ts +14 -0
  144. package/dist/components/scenes/NarrativeScene.svelte +100 -92
  145. package/dist/components/scenes/NarrativeScene.svelte.d.ts +9 -0
  146. package/dist/components/scenes/ReadoutScene.svelte +131 -107
  147. package/dist/components/scenes/ReadoutScene.svelte.d.ts +14 -1
  148. package/dist/components/scenes/StageScene.svelte +111 -104
  149. package/dist/components/scenes/StageScene.svelte.d.ts +14 -0
  150. package/dist/components/system/AppShell.svelte +62 -0
  151. package/dist/components/system/AppShell.svelte.d.ts +32 -0
  152. package/dist/examples/ArcaneShard.svelte +364 -0
  153. package/dist/examples/ArcaneShard.svelte.d.ts +3 -0
  154. package/dist/examples/FieldReport.svelte +226 -223
  155. package/dist/examples/HextechForge.svelte +324 -0
  156. package/dist/examples/HextechForge.svelte.d.ts +3 -0
  157. package/dist/examples/ObservationDeck.svelte +333 -317
  158. package/dist/examples/SignalLost.svelte +191 -191
  159. package/dist/index.d.ts +15 -1
  160. package/dist/index.js +16 -1
  161. package/dist/styles.css +115 -0
  162. package/dist/system/actions/echo.js +21 -12
  163. package/dist/system/actions/resolve.js +28 -14
  164. package/dist/system/actions/reveal.js +2 -2
  165. package/dist/system/actions/surface.js +12 -2
  166. package/dist/system/depth/depth.css +49 -49
  167. package/dist/system/depth/depth.js +1 -1
  168. package/dist/system/expressions.css +80 -80
  169. package/dist/system/override-template.css +72 -72
  170. package/dist/system/register.css +74 -74
  171. package/dist/system/register.d.ts +1 -1
  172. package/dist/system/register.js +5 -1
  173. package/dist/system/scroll-lock.d.ts +6 -0
  174. package/dist/system/scroll-lock.js +23 -0
  175. package/dist/tokens/arcane.css +96 -0
  176. package/dist/tokens/hextech.css +96 -0
  177. package/dist/tokens/tokens.css +102 -86
  178. package/dist/tokens/tokens.d.ts +41 -0
  179. package/dist/tokens/tokens.js +44 -3
  180. package/dist/utils/motion.js +1 -1
  181. package/package.json +71 -60
@@ -1,317 +1,333 @@
1
- <!--
2
- EXAMPLE: Observation Deck
3
- REGISTER: mission-control
4
- CONCEPT: a deep-space monitoring dashboard operated by someone who has been watching for months
5
- DEMONSTRATES: ReadoutScene, DepthStage, HorizonGrid, FloatCard, Table, SidebarNav, Topbar, StatusDot, Alert, MetricCard, Label, Text expressions, TerminalBoot, DataStream, GlyphMark
6
- INSPIRED BY: the third hour of a night watch on a research vessel bridge
7
- -->
8
- <script lang="ts">
9
- import {
10
- Text,
11
- Label,
12
- StatusDot,
13
- Alert,
14
- MetricCard,
15
- Table,
16
- SidebarNav,
17
- Topbar,
18
- ReadoutScene,
19
- DepthStage,
20
- DepthLayer,
21
- FloatCard,
22
- HorizonGrid,
23
- DataStream,
24
- GlyphMark,
25
- Grid,
26
- Stack,
27
- Divider,
28
- applyRegister,
29
- } from '../index.js';
30
- import { onMount } from 'svelte';
31
-
32
- let elapsed = $state(0);
33
- let statusCycle = $state<'ok' | 'pend' | 'warn' | 'fail'>('ok');
34
- let intervalId: ReturnType<typeof setInterval> | undefined;
35
- let cycleId: ReturnType<typeof setInterval> | undefined;
36
-
37
- const statuses: ('ok' | 'pend' | 'warn' | 'fail')[] = ['ok', 'ok', 'ok', 'pend', 'ok', 'warn', 'ok'];
38
- let cycleIndex = $state(0);
39
-
40
- const elapsedFormatted = $derived(() => {
41
- const h = Math.floor(elapsed / 3600);
42
- const m = Math.floor((elapsed % 3600) / 60);
43
- const s = elapsed % 60;
44
- return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
45
- });
46
-
47
- const navItems = [
48
- { label: 'overview', href: '#', active: true },
49
- { label: 'telemetry', href: '#' },
50
- { label: 'signal log', href: '#' },
51
- { label: 'thermal map', href: '#' },
52
- { label: 'diagnostics', href: '#' },
53
- ];
54
-
55
- const metricsData = [
56
- { label: 'signal strength', value: '-42 dbm' },
57
- { label: 'thermal variance', value: '0.003 K' },
58
- { label: 'distance', value: '4.2 ly' },
59
- { label: 'cycle count', value: '1,847' },
60
- { label: 'uptime', value: '99.97%' },
61
- { label: 'queue depth', value: '12' },
62
- ];
63
-
64
- const eventLog = [
65
- { time: '03:42:18', event: 'frequency sweep completed', status: 'ok' },
66
- { time: '03:38:04', event: 'sector 7 beacon refresh', status: 'ok' },
67
- { time: '03:31:55', event: 'thermal anomaly logged', status: 'warn' },
68
- { time: '03:24:12', event: 'handshake with relay 9', status: 'ok' },
69
- { time: '03:18:40', event: 'particle density spike', status: 'pend' },
70
- { time: '03:12:07', event: 'calibration cycle 1847', status: 'ok' },
71
- { time: '03:04:33', event: 'sector 4 unresponsive', status: 'fail' },
72
- { time: '02:58:19', event: 'backup frequency locked', status: 'ok' },
73
- ];
74
-
75
- const eventColumns = [
76
- { key: 'time', label: 'time' },
77
- { key: 'event', label: 'event' },
78
- { key: 'status', label: 'status' },
79
- ];
80
-
81
- const bootLines: { status: 'ok' | 'pend' | 'warn' | 'fail'; message: string }[] = [
82
- { status: 'ok', message: 'observation array initialized' },
83
- { status: 'ok', message: 'frequency lock acquired' },
84
- { status: 'ok', message: 'telemetry streams active' },
85
- { status: 'ok', message: 'thermal sensors calibrated' },
86
- { status: 'pend', message: 'awaiting sector 4 response' },
87
- ];
88
-
89
- onMount(() => {
90
- applyRegister('mission-control');
91
-
92
- intervalId = setInterval(() => {
93
- elapsed += 1;
94
- }, 1000);
95
-
96
- cycleId = setInterval(() => {
97
- cycleIndex = (cycleIndex + 1) % statuses.length;
98
- statusCycle = statuses[cycleIndex];
99
- }, 4000);
100
-
101
- elapsed = 3 * 3600 + 44 * 60 + 12;
102
-
103
- return () => {
104
- document.body.removeAttribute('data-register');
105
- if (intervalId) clearInterval(intervalId);
106
- if (cycleId) clearInterval(cycleId);
107
- };
108
- });
109
- </script>
110
-
111
- <div class="obs-deck">
112
- <Topbar class="obs-deck-topbar">
113
- {#snippet left()}
114
- <Stack direction="horizontal" gap="0.75rem" align="center">
115
- <StatusDot status={statusCycle} size={7} />
116
- <Text expression="readout" as="span">deep field observatory</Text>
117
- </Stack>
118
- {/snippet}
119
- {#snippet center()}
120
- <GlyphMark variant="reticle" size={16} color="var(--signal)" />
121
- {/snippet}
122
- {#snippet right()}
123
- <Stack direction="horizontal" gap="1rem" align="center">
124
- <Label color="muted">elapsed</Label>
125
- <Text expression="readout" as="span" color="signal">{elapsedFormatted()}</Text>
126
- </Stack>
127
- {/snippet}
128
- </Topbar>
129
-
130
- <div class="obs-deck-body">
131
- <aside class="obs-deck-sidebar">
132
- <SidebarNav items={navItems} />
133
- <Divider />
134
- <Stack direction="vertical" gap="0.5rem">
135
- <Alert variant="ok" title="particle density nominal">
136
- <Text expression="readout">within expected parameters for sector</Text>
137
- </Alert>
138
- <Alert variant="warn" title="sector 7 unresponsive">
139
- <Text expression="readout">last contact 26 minutes ago</Text>
140
- </Alert>
141
- <Alert variant="info" title="calibration window approaching">
142
- <Text expression="readout">next cycle in 14 minutes</Text>
143
- </Alert>
144
- </Stack>
145
- <div class="obs-deck-stream" aria-hidden="true">
146
- <DataStream active speed="slow" />
147
- <DataStream active speed="medium" />
148
- </div>
149
- </aside>
150
-
151
- <main class="obs-deck-main">
152
- <DepthStage perspective="mid" class="obs-deck-depth">
153
- <DepthLayer level="ground" class="obs-deck-horizon">
154
- <HorizonGrid rows={18} cols={10} vanishY={0.35} />
155
- </DepthLayer>
156
-
157
- <DepthLayer level="raised" class="obs-deck-content">
158
- <div class="obs-deck-metrics">
159
- <Grid cols={3} gap="0.75rem">
160
- {#each metricsData as m}
161
- <FloatCard tiltMax={4}>
162
- <div class="obs-deck-metric-inner">
163
- <Label color="muted">{m.label}</Label>
164
- <Text variant="heading" as="span" color="primary">{m.value}</Text>
165
- </div>
166
- </FloatCard>
167
- {/each}
168
- </Grid>
169
- </div>
170
-
171
- <DepthLayer level="ground" class="obs-deck-table-layer">
172
- <div class="obs-deck-table-section">
173
- <Text expression="chapter" as="span">recent events</Text>
174
- <Table columns={eventColumns} rows={eventLog} />
175
- </div>
176
- </DepthLayer>
177
-
178
- <div class="obs-deck-boot">
179
- <Text expression="chapter" as="span">initialization log</Text>
180
- <div class="obs-deck-boot-lines">
181
- {#each bootLines as line}
182
- <div class="obs-deck-boot-line">
183
- <span class="obs-deck-boot-glyph" style:color={
184
- line.status === 'ok' ? 'var(--status-ok)' :
185
- line.status === 'pend' ? 'var(--status-pend)' :
186
- line.status === 'warn' ? 'var(--status-warn)' :
187
- 'var(--status-fail)'
188
- }>
189
- {line.status === 'ok' ? '[ OK ]' :
190
- line.status === 'pend' ? '[ .. ]' :
191
- line.status === 'warn' ? '[WARN]' : '[FAIL]'}
192
- </span>
193
- <span class="obs-deck-boot-msg">{line.message}</span>
194
- </div>
195
- {/each}
196
- </div>
197
- </div>
198
- </DepthLayer>
199
- </DepthStage>
200
- </main>
201
- </div>
202
- </div>
203
-
204
- <style>
205
- .obs-deck {
206
- min-height: 100dvh;
207
- display: flex;
208
- flex-direction: column;
209
- background-color: var(--bg);
210
- }
211
-
212
- :global(.obs-deck-topbar) {
213
- flex-shrink: 0;
214
- }
215
-
216
- .obs-deck-body {
217
- display: grid;
218
- grid-template-columns: 220px 1fr;
219
- flex: 1;
220
- min-height: 0;
221
- }
222
-
223
- .obs-deck-sidebar {
224
- padding: 1.25rem 1rem;
225
- display: flex;
226
- flex-direction: column;
227
- gap: 1rem;
228
- border-right: 1px solid var(--line);
229
- overflow-y: auto;
230
- }
231
-
232
- .obs-deck-stream {
233
- display: flex;
234
- gap: 0.5rem;
235
- justify-content: center;
236
- margin-top: auto;
237
- padding-top: 1rem;
238
- opacity: 0.6;
239
- }
240
-
241
- .obs-deck-main {
242
- position: relative;
243
- overflow-y: auto;
244
- padding: 1.5rem;
245
- }
246
-
247
- :global(.obs-deck-depth) {
248
- min-height: 100%;
249
- }
250
-
251
- :global(.obs-deck-horizon) {
252
- position: absolute;
253
- inset: 0;
254
- opacity: 0.4;
255
- pointer-events: none;
256
- }
257
-
258
- :global(.obs-deck-content) {
259
- position: relative;
260
- display: flex;
261
- flex-direction: column;
262
- gap: 2rem;
263
- }
264
-
265
- .obs-deck-metric-inner {
266
- display: flex;
267
- flex-direction: column;
268
- gap: 0.25rem;
269
- }
270
-
271
- .obs-deck-table-section {
272
- display: flex;
273
- flex-direction: column;
274
- gap: 0.75rem;
275
- }
276
-
277
- .obs-deck-boot {
278
- display: flex;
279
- flex-direction: column;
280
- gap: 0.5rem;
281
- border-left: 2px solid rgba(121, 166, 163, 0.14);
282
- padding-left: 1.25rem;
283
- }
284
-
285
- .obs-deck-boot-lines {
286
- display: flex;
287
- flex-direction: column;
288
- gap: 0.25rem;
289
- }
290
-
291
- .obs-deck-boot-line {
292
- display: flex;
293
- align-items: baseline;
294
- gap: 0.75rem;
295
- font-family: var(--font-mono);
296
- font-size: 0.82rem;
297
- }
298
-
299
- .obs-deck-boot-glyph {
300
- white-space: nowrap;
301
- flex-shrink: 0;
302
- }
303
-
304
- .obs-deck-boot-msg {
305
- color: var(--text-soft);
306
- }
307
-
308
- @media (max-width: 768px) {
309
- .obs-deck-body {
310
- grid-template-columns: 1fr;
311
- }
312
-
313
- .obs-deck-sidebar {
314
- display: none;
315
- }
316
- }
317
- </style>
1
+ <!--
2
+ EXAMPLE: Observation Deck
3
+ REGISTER: mission-control
4
+ CONCEPT: a deep-space monitoring dashboard operated by someone who has been watching for months
5
+ DEMONSTRATES: ReadoutScene, DepthStage, HorizonGrid, FloatCard, Table, SidebarNav, Topbar, StatusDot, Alert, MetricCard, Label, Text expressions, TerminalBoot, DataStream, GlyphMark
6
+ INSPIRED BY: the third hour of a night watch on a research vessel bridge
7
+ -->
8
+ <script lang="ts">
9
+ import {
10
+ Text,
11
+ Label,
12
+ StatusDot,
13
+ Alert,
14
+ MetricCard,
15
+ Table,
16
+ SidebarNav,
17
+ Topbar,
18
+ ReadoutScene,
19
+ DepthStage,
20
+ DepthLayer,
21
+ FloatCard,
22
+ HorizonGrid,
23
+ DataStream,
24
+ GlyphMark,
25
+ Grid,
26
+ Stack,
27
+ Divider,
28
+ applyRegister
29
+ } from '../index.js';
30
+ import { onMount } from 'svelte';
31
+
32
+ let elapsed = $state(0);
33
+ let statusCycle = $state<'ok' | 'pend' | 'warn' | 'fail'>('ok');
34
+ let intervalId: ReturnType<typeof setInterval> | undefined;
35
+ let cycleId: ReturnType<typeof setInterval> | undefined;
36
+
37
+ const statuses: ('ok' | 'pend' | 'warn' | 'fail')[] = [
38
+ 'ok',
39
+ 'ok',
40
+ 'ok',
41
+ 'pend',
42
+ 'ok',
43
+ 'warn',
44
+ 'ok'
45
+ ];
46
+ let cycleIndex = $state(0);
47
+
48
+ const elapsedFormatted = $derived(() => {
49
+ const h = Math.floor(elapsed / 3600);
50
+ const m = Math.floor((elapsed % 3600) / 60);
51
+ const s = elapsed % 60;
52
+ return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
53
+ });
54
+
55
+ const navItems = [
56
+ { label: 'overview', href: '#', active: true },
57
+ { label: 'telemetry', href: '#' },
58
+ { label: 'signal log', href: '#' },
59
+ { label: 'thermal map', href: '#' },
60
+ { label: 'diagnostics', href: '#' }
61
+ ];
62
+
63
+ const metricsData = [
64
+ { label: 'signal strength', value: '-42 dbm' },
65
+ { label: 'thermal variance', value: '0.003 K' },
66
+ { label: 'distance', value: '4.2 ly' },
67
+ { label: 'cycle count', value: '1,847' },
68
+ { label: 'uptime', value: '99.97%' },
69
+ { label: 'queue depth', value: '12' }
70
+ ];
71
+
72
+ const eventLog = [
73
+ { time: '03:42:18', event: 'frequency sweep completed', status: 'ok' },
74
+ { time: '03:38:04', event: 'sector 7 beacon refresh', status: 'ok' },
75
+ { time: '03:31:55', event: 'thermal anomaly logged', status: 'warn' },
76
+ { time: '03:24:12', event: 'handshake with relay 9', status: 'ok' },
77
+ { time: '03:18:40', event: 'particle density spike', status: 'pend' },
78
+ { time: '03:12:07', event: 'calibration cycle 1847', status: 'ok' },
79
+ { time: '03:04:33', event: 'sector 4 unresponsive', status: 'fail' },
80
+ { time: '02:58:19', event: 'backup frequency locked', status: 'ok' }
81
+ ];
82
+
83
+ const eventColumns = [
84
+ { key: 'time', label: 'time' },
85
+ { key: 'event', label: 'event' },
86
+ { key: 'status', label: 'status' }
87
+ ];
88
+
89
+ const bootLines: { status: 'ok' | 'pend' | 'warn' | 'fail'; message: string }[] = [
90
+ { status: 'ok', message: 'observation array initialized' },
91
+ { status: 'ok', message: 'frequency lock acquired' },
92
+ { status: 'ok', message: 'telemetry streams active' },
93
+ { status: 'ok', message: 'thermal sensors calibrated' },
94
+ { status: 'pend', message: 'awaiting sector 4 response' }
95
+ ];
96
+
97
+ onMount(() => {
98
+ applyRegister('mission-control');
99
+
100
+ intervalId = setInterval(() => {
101
+ elapsed += 1;
102
+ }, 1000);
103
+
104
+ cycleId = setInterval(() => {
105
+ cycleIndex = (cycleIndex + 1) % statuses.length;
106
+ statusCycle = statuses[cycleIndex];
107
+ }, 4000);
108
+
109
+ elapsed = 3 * 3600 + 44 * 60 + 12;
110
+
111
+ return () => {
112
+ document.body.removeAttribute('data-register');
113
+ if (intervalId) clearInterval(intervalId);
114
+ if (cycleId) clearInterval(cycleId);
115
+ };
116
+ });
117
+ </script>
118
+
119
+ <div class="obs-deck">
120
+ <Topbar class="obs-deck-topbar">
121
+ {#snippet left()}
122
+ <Stack direction="horizontal" gap="0.75rem" align="center">
123
+ <StatusDot status={statusCycle} size={7} />
124
+ <Text expression="readout" as="span">deep field observatory</Text>
125
+ </Stack>
126
+ {/snippet}
127
+ {#snippet center()}
128
+ <GlyphMark variant="reticle" size={16} color="var(--signal)" />
129
+ {/snippet}
130
+ {#snippet right()}
131
+ <Stack direction="horizontal" gap="1rem" align="center">
132
+ <Label color="muted">elapsed</Label>
133
+ <Text expression="readout" as="span" color="signal">{elapsedFormatted()}</Text>
134
+ </Stack>
135
+ {/snippet}
136
+ </Topbar>
137
+
138
+ <div class="obs-deck-body">
139
+ <aside class="obs-deck-sidebar">
140
+ <SidebarNav items={navItems} />
141
+ <Divider />
142
+ <Stack direction="vertical" gap="0.5rem">
143
+ <Alert variant="ok" title="particle density nominal">
144
+ <Text expression="readout">within expected parameters for sector</Text>
145
+ </Alert>
146
+ <Alert variant="warn" title="sector 7 unresponsive">
147
+ <Text expression="readout">last contact 26 minutes ago</Text>
148
+ </Alert>
149
+ <Alert variant="info" title="calibration window approaching">
150
+ <Text expression="readout">next cycle in 14 minutes</Text>
151
+ </Alert>
152
+ </Stack>
153
+ <div class="obs-deck-stream" aria-hidden="true">
154
+ <DataStream active speed="slow" />
155
+ <DataStream active speed="medium" />
156
+ </div>
157
+ </aside>
158
+
159
+ <main class="obs-deck-main">
160
+ <DepthStage perspective="mid" class="obs-deck-depth">
161
+ <DepthLayer level="ground" class="obs-deck-horizon">
162
+ <HorizonGrid rows={18} cols={10} vanishY={0.35} />
163
+ </DepthLayer>
164
+
165
+ <DepthLayer level="raised" class="obs-deck-content">
166
+ <div class="obs-deck-metrics">
167
+ <Grid cols={3} gap="0.75rem">
168
+ {#each metricsData as m}
169
+ <FloatCard tiltMax={4}>
170
+ <div class="obs-deck-metric-inner">
171
+ <Label color="muted">{m.label}</Label>
172
+ <Text variant="heading" as="span" color="primary">{m.value}</Text>
173
+ </div>
174
+ </FloatCard>
175
+ {/each}
176
+ </Grid>
177
+ </div>
178
+
179
+ <DepthLayer level="ground" class="obs-deck-table-layer">
180
+ <div class="obs-deck-table-section">
181
+ <Text expression="chapter" as="span">recent events</Text>
182
+ <Table columns={eventColumns} rows={eventLog} />
183
+ </div>
184
+ </DepthLayer>
185
+
186
+ <div class="obs-deck-boot">
187
+ <Text expression="chapter" as="span">initialization log</Text>
188
+ <div class="obs-deck-boot-lines">
189
+ {#each bootLines as line}
190
+ <div class="obs-deck-boot-line">
191
+ <span
192
+ class="obs-deck-boot-glyph"
193
+ style:color={line.status === 'ok'
194
+ ? 'var(--status-ok)'
195
+ : line.status === 'pend'
196
+ ? 'var(--status-pend)'
197
+ : line.status === 'warn'
198
+ ? 'var(--status-warn)'
199
+ : 'var(--status-fail)'}
200
+ >
201
+ {line.status === 'ok'
202
+ ? '[ OK ]'
203
+ : line.status === 'pend'
204
+ ? '[ .. ]'
205
+ : line.status === 'warn'
206
+ ? '[WARN]'
207
+ : '[FAIL]'}
208
+ </span>
209
+ <span class="obs-deck-boot-msg">{line.message}</span>
210
+ </div>
211
+ {/each}
212
+ </div>
213
+ </div>
214
+ </DepthLayer>
215
+ </DepthStage>
216
+ </main>
217
+ </div>
218
+ </div>
219
+
220
+ <style>
221
+ .obs-deck {
222
+ min-height: 100dvh;
223
+ display: flex;
224
+ flex-direction: column;
225
+ background-color: var(--bg);
226
+ }
227
+
228
+ :global(.obs-deck-topbar) {
229
+ flex-shrink: 0;
230
+ }
231
+
232
+ .obs-deck-body {
233
+ display: grid;
234
+ grid-template-columns: 220px 1fr;
235
+ flex: 1;
236
+ min-height: 0;
237
+ }
238
+
239
+ .obs-deck-sidebar {
240
+ padding: 1.25rem 1rem;
241
+ display: flex;
242
+ flex-direction: column;
243
+ gap: 1rem;
244
+ border-right: 1px solid var(--line);
245
+ overflow-y: auto;
246
+ }
247
+
248
+ .obs-deck-stream {
249
+ display: flex;
250
+ gap: 0.5rem;
251
+ justify-content: center;
252
+ margin-top: auto;
253
+ padding-top: 1rem;
254
+ opacity: 0.6;
255
+ }
256
+
257
+ .obs-deck-main {
258
+ position: relative;
259
+ overflow-y: auto;
260
+ padding: 1.5rem;
261
+ }
262
+
263
+ :global(.obs-deck-depth) {
264
+ min-height: 100%;
265
+ }
266
+
267
+ :global(.obs-deck-horizon) {
268
+ position: absolute;
269
+ inset: 0;
270
+ opacity: 0.4;
271
+ pointer-events: none;
272
+ }
273
+
274
+ :global(.obs-deck-content) {
275
+ position: relative;
276
+ display: flex;
277
+ flex-direction: column;
278
+ gap: 2rem;
279
+ }
280
+
281
+ .obs-deck-metric-inner {
282
+ display: flex;
283
+ flex-direction: column;
284
+ gap: 0.25rem;
285
+ }
286
+
287
+ .obs-deck-table-section {
288
+ display: flex;
289
+ flex-direction: column;
290
+ gap: 0.75rem;
291
+ }
292
+
293
+ .obs-deck-boot {
294
+ display: flex;
295
+ flex-direction: column;
296
+ gap: 0.5rem;
297
+ border-left: 2px solid rgba(121, 166, 163, 0.14);
298
+ padding-left: 1.25rem;
299
+ }
300
+
301
+ .obs-deck-boot-lines {
302
+ display: flex;
303
+ flex-direction: column;
304
+ gap: 0.25rem;
305
+ }
306
+
307
+ .obs-deck-boot-line {
308
+ display: flex;
309
+ align-items: baseline;
310
+ gap: 0.75rem;
311
+ font-family: var(--font-mono);
312
+ font-size: 0.82rem;
313
+ }
314
+
315
+ .obs-deck-boot-glyph {
316
+ white-space: nowrap;
317
+ flex-shrink: 0;
318
+ }
319
+
320
+ .obs-deck-boot-msg {
321
+ color: var(--text-soft);
322
+ }
323
+
324
+ @media (max-width: 768px) {
325
+ .obs-deck-body {
326
+ grid-template-columns: 1fr;
327
+ }
328
+
329
+ .obs-deck-sidebar {
330
+ display: none;
331
+ }
332
+ }
333
+ </style>