@silvery/examples 0.5.6 → 0.17.4
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/dist/UPNG-Cy7ViL8f.mjs +5074 -0
- package/dist/__vite-browser-external-2447137e-BML7CYau.mjs +4 -0
- package/dist/_banner-DLPxCqVy.mjs +44 -0
- package/dist/ansi-CCE2pVS0.mjs +16397 -0
- package/dist/apng-HhhBjRGt.mjs +68 -0
- package/dist/apng-mwUQbTTF.mjs +3 -0
- package/dist/apps/aichat/index.mjs +1299 -0
- package/dist/apps/app-todo.mjs +139 -0
- package/dist/apps/async-data.mjs +204 -0
- package/dist/apps/cli-wizard.mjs +339 -0
- package/dist/apps/clipboard.mjs +198 -0
- package/dist/apps/components.mjs +864 -0
- package/dist/apps/data-explorer.mjs +483 -0
- package/dist/apps/dev-tools.mjs +397 -0
- package/dist/apps/explorer.mjs +698 -0
- package/dist/apps/gallery.mjs +766 -0
- package/dist/apps/inline-bench.mjs +115 -0
- package/dist/apps/kanban.mjs +280 -0
- package/dist/apps/layout-ref.mjs +187 -0
- package/dist/apps/outline.mjs +203 -0
- package/dist/apps/paste-demo.mjs +189 -0
- package/dist/apps/scroll.mjs +86 -0
- package/dist/apps/search-filter.mjs +287 -0
- package/dist/apps/selection.mjs +355 -0
- package/dist/apps/spatial-focus-demo.mjs +388 -0
- package/dist/apps/task-list.mjs +258 -0
- package/dist/apps/terminal-caps-demo.mjs +315 -0
- package/dist/apps/terminal.mjs +872 -0
- package/dist/apps/text-selection-demo.mjs +254 -0
- package/dist/apps/textarea.mjs +178 -0
- package/dist/apps/theme.mjs +661 -0
- package/dist/apps/transform.mjs +215 -0
- package/dist/apps/virtual-10k.mjs +422 -0
- package/dist/assets/resvgjs.darwin-arm64-BtufyGW1.node +0 -0
- package/dist/backends-Bahh9mKN.mjs +1179 -0
- package/dist/backends-CCtCDQ94.mjs +3 -0
- package/dist/{cli.mjs → bin/cli.mjs} +21 -25
- package/dist/chunk-BSw8zbkd.mjs +37 -0
- package/dist/components/counter.mjs +48 -0
- package/dist/components/hello.mjs +31 -0
- package/dist/components/progress-bar.mjs +59 -0
- package/dist/components/select-list.mjs +85 -0
- package/dist/components/spinner.mjs +57 -0
- package/dist/components/text-input.mjs +62 -0
- package/dist/components/virtual-list.mjs +51 -0
- package/dist/flexily-zero-adapter-UB-ra8fR.mjs +3374 -0
- package/dist/gif-BZaqPPVX.mjs +3 -0
- package/dist/gif-BtnXuxLF.mjs +71 -0
- package/dist/gifenc-CLRW41dk.mjs +728 -0
- package/dist/jsx-runtime-dMs_8fNu.mjs +241 -0
- package/dist/key-mapping-5oYQdAQE.mjs +3 -0
- package/dist/key-mapping-D4LR1go6.mjs +130 -0
- package/dist/layout/dashboard.mjs +1204 -0
- package/dist/layout/live-resize.mjs +303 -0
- package/dist/layout/overflow.mjs +70 -0
- package/dist/layout/text-layout.mjs +335 -0
- package/dist/node-NuJ94BWl.mjs +1083 -0
- package/dist/plugins-D1KtkT4a.mjs +3057 -0
- package/dist/resvg-js-C_8Wps1F.mjs +201 -0
- package/dist/src-BTEVGpd9.mjs +23538 -0
- package/dist/src-CUUOuRH6.mjs +5322 -0
- package/dist/src-CzfRafCQ.mjs +814 -0
- package/dist/usingCtx-CsEf0xO3.mjs +57 -0
- package/dist/yoga-adapter-BVtQ5OJR.mjs +237 -0
- package/package.json +19 -14
- package/_banner.tsx +0 -60
- package/apps/aichat/components.tsx +0 -469
- package/apps/aichat/index.tsx +0 -220
- package/apps/aichat/script.ts +0 -460
- package/apps/aichat/state.ts +0 -325
- package/apps/aichat/types.ts +0 -19
- package/apps/app-todo.tsx +0 -201
- package/apps/async-data.tsx +0 -196
- package/apps/cli-wizard.tsx +0 -332
- package/apps/clipboard.tsx +0 -183
- package/apps/components.tsx +0 -658
- package/apps/data-explorer.tsx +0 -490
- package/apps/dev-tools.tsx +0 -395
- package/apps/explorer.tsx +0 -731
- package/apps/gallery.tsx +0 -653
- package/apps/inline-bench.tsx +0 -138
- package/apps/kanban.tsx +0 -265
- package/apps/layout-ref.tsx +0 -173
- package/apps/outline.tsx +0 -160
- package/apps/panes/index.tsx +0 -203
- package/apps/paste-demo.tsx +0 -185
- package/apps/scroll.tsx +0 -77
- package/apps/search-filter.tsx +0 -240
- package/apps/selection.tsx +0 -342
- package/apps/spatial-focus-demo.tsx +0 -368
- package/apps/task-list.tsx +0 -271
- package/apps/terminal-caps-demo.tsx +0 -334
- package/apps/terminal.tsx +0 -800
- package/apps/text-selection-demo.tsx +0 -189
- package/apps/textarea.tsx +0 -155
- package/apps/theme.tsx +0 -515
- package/apps/transform.tsx +0 -229
- package/apps/virtual-10k.tsx +0 -405
- package/apps/vterm-demo/index.tsx +0 -216
- package/components/counter.tsx +0 -45
- package/components/hello.tsx +0 -34
- package/components/progress-bar.tsx +0 -48
- package/components/select-list.tsx +0 -50
- package/components/spinner.tsx +0 -40
- package/components/text-input.tsx +0 -57
- package/components/virtual-list.tsx +0 -52
- package/dist/cli.d.mts +0 -1
- package/dist/cli.mjs.map +0 -1
- package/layout/dashboard.tsx +0 -953
- package/layout/live-resize.tsx +0 -282
- package/layout/overflow.tsx +0 -51
- package/layout/text-layout.tsx +0 -283
package/apps/components.tsx
DELETED
|
@@ -1,658 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Components Showcase
|
|
3
|
-
*
|
|
4
|
-
* A UI component gallery demonstrating silvery's built-in components:
|
|
5
|
-
* - Typography: H1-H3, Strong, Muted, Small, Lead, Code, Blockquote, lists
|
|
6
|
-
* - Inputs: TextInput, TextArea, SelectList, Toggle with focus cycling
|
|
7
|
-
* - Display: ProgressBar, Spinner, Badge, border styles, ModalDialog
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import React, { useState, useCallback } from "react"
|
|
11
|
-
import {
|
|
12
|
-
render,
|
|
13
|
-
Box,
|
|
14
|
-
Text,
|
|
15
|
-
Muted,
|
|
16
|
-
useInput,
|
|
17
|
-
useApp,
|
|
18
|
-
createTerm,
|
|
19
|
-
// Typography
|
|
20
|
-
H1,
|
|
21
|
-
H2,
|
|
22
|
-
H3,
|
|
23
|
-
P,
|
|
24
|
-
Lead,
|
|
25
|
-
Small,
|
|
26
|
-
Strong,
|
|
27
|
-
Em,
|
|
28
|
-
Code,
|
|
29
|
-
Blockquote,
|
|
30
|
-
CodeBlock,
|
|
31
|
-
HR,
|
|
32
|
-
UL,
|
|
33
|
-
OL,
|
|
34
|
-
LI,
|
|
35
|
-
// Inputs
|
|
36
|
-
TextInput,
|
|
37
|
-
TextArea,
|
|
38
|
-
SelectList,
|
|
39
|
-
Toggle,
|
|
40
|
-
Button,
|
|
41
|
-
// Display
|
|
42
|
-
ProgressBar,
|
|
43
|
-
Spinner,
|
|
44
|
-
Badge,
|
|
45
|
-
Divider,
|
|
46
|
-
Kbd,
|
|
47
|
-
ModalDialog,
|
|
48
|
-
type Key,
|
|
49
|
-
} from "silvery"
|
|
50
|
-
import { ExampleBanner, type ExampleMeta } from "../_banner.js"
|
|
51
|
-
|
|
52
|
-
export const meta: ExampleMeta = {
|
|
53
|
-
name: "Components",
|
|
54
|
-
description: "UI component gallery with typography, inputs, and dialogs",
|
|
55
|
-
demo: true,
|
|
56
|
-
features: ["Typography", "TextInput", "SelectList", "ModalDialog", "ProgressBar", "focus ring"],
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// ============================================================================
|
|
60
|
-
// Typography Tab
|
|
61
|
-
// ============================================================================
|
|
62
|
-
|
|
63
|
-
function TypographyTab({ scrollOffset }: { scrollOffset?: number }) {
|
|
64
|
-
return (
|
|
65
|
-
<Box flexDirection="column" gap={1} paddingX={1} overflow="scroll" scrollOffset={scrollOffset} flexGrow={1}>
|
|
66
|
-
<Box flexDirection="column">
|
|
67
|
-
<H1>Getting Started with Silvery</H1>
|
|
68
|
-
<Lead>Build modern terminal UIs with React — layout feedback, semantic theming, and 30+ components.</Lead>
|
|
69
|
-
</Box>
|
|
70
|
-
|
|
71
|
-
<HR />
|
|
72
|
-
|
|
73
|
-
<Box flexDirection="row" gap={2}>
|
|
74
|
-
<Box flexDirection="column" flexGrow={1} flexBasis={0}>
|
|
75
|
-
<H2>Typography</H2>
|
|
76
|
-
<Box flexDirection="column">
|
|
77
|
-
<Text bold color="$primary">
|
|
78
|
-
H1 — Page Title (bold, $primary)
|
|
79
|
-
</Text>
|
|
80
|
-
<Text bold color="$accent">
|
|
81
|
-
H2 — Section Heading (bold, $accent)
|
|
82
|
-
</Text>
|
|
83
|
-
<Text color="$primary">H3 — Group Heading ($primary)</Text>
|
|
84
|
-
<P>P — Body paragraph text</P>
|
|
85
|
-
<Lead>Lead — Introductory italic text</Lead>
|
|
86
|
-
<Muted>Muted — Secondary information</Muted>
|
|
87
|
-
<Small>Small — Fine print and captions</Small>
|
|
88
|
-
</Box>
|
|
89
|
-
</Box>
|
|
90
|
-
<Box flexDirection="column" flexGrow={1} flexBasis={0}>
|
|
91
|
-
<H2>Inline Styles</H2>
|
|
92
|
-
<Box flexDirection="column">
|
|
93
|
-
<Text>
|
|
94
|
-
<Strong>Strong</Strong> — bold emphasis
|
|
95
|
-
</Text>
|
|
96
|
-
<Text>
|
|
97
|
-
<Em>Em</Em> — italic emphasis
|
|
98
|
-
</Text>
|
|
99
|
-
<Text>
|
|
100
|
-
<Strong>
|
|
101
|
-
<Em>Strong + Em</Em>
|
|
102
|
-
</Strong>{" "}
|
|
103
|
-
— bold italic
|
|
104
|
-
</Text>
|
|
105
|
-
<Text>
|
|
106
|
-
<Text underline>Underline</Text> — underlined text
|
|
107
|
-
</Text>
|
|
108
|
-
<Text>
|
|
109
|
-
<Text strikethrough>Strikethrough</Text> — deleted text
|
|
110
|
-
</Text>
|
|
111
|
-
<Text>
|
|
112
|
-
<Code>Code</Code> — inline code span
|
|
113
|
-
</Text>
|
|
114
|
-
<Text>
|
|
115
|
-
<Kbd>Kbd</Kbd> — keyboard shortcut
|
|
116
|
-
</Text>
|
|
117
|
-
</Box>
|
|
118
|
-
</Box>
|
|
119
|
-
</Box>
|
|
120
|
-
|
|
121
|
-
<HR />
|
|
122
|
-
|
|
123
|
-
<H2>Semantic Colors</H2>
|
|
124
|
-
<Box flexDirection="column">
|
|
125
|
-
<Box gap={1}>
|
|
126
|
-
<Text backgroundColor="$primary" color="$primary-fg" bold>
|
|
127
|
-
{" $primary "}
|
|
128
|
-
</Text>
|
|
129
|
-
<Text backgroundColor="$accent" color="$accent-fg" bold>
|
|
130
|
-
{" $accent "}
|
|
131
|
-
</Text>
|
|
132
|
-
<Text backgroundColor="$success" color="$success-fg" bold>
|
|
133
|
-
{" $success "}
|
|
134
|
-
</Text>
|
|
135
|
-
<Text backgroundColor="$warning" color="$warning-fg" bold>
|
|
136
|
-
{" $warning "}
|
|
137
|
-
</Text>
|
|
138
|
-
<Text backgroundColor="$error" color="$error-fg" bold>
|
|
139
|
-
{" $error "}
|
|
140
|
-
</Text>
|
|
141
|
-
</Box>
|
|
142
|
-
<Box gap={1} marginTop={1}>
|
|
143
|
-
<Text color="$primary">{"████"} primary</Text>
|
|
144
|
-
<Text color="$accent">{"████"} accent</Text>
|
|
145
|
-
<Text color="$success">{"████"} success</Text>
|
|
146
|
-
<Text color="$warning">{"████"} warning</Text>
|
|
147
|
-
<Text color="$error">{"████"} error</Text>
|
|
148
|
-
<Text color="$muted">{"████"} muted</Text>
|
|
149
|
-
</Box>
|
|
150
|
-
</Box>
|
|
151
|
-
|
|
152
|
-
<HR />
|
|
153
|
-
|
|
154
|
-
<H2>Block Elements</H2>
|
|
155
|
-
<Blockquote>
|
|
156
|
-
The best color code is no color code — most components already use the right semantic tokens.
|
|
157
|
-
</Blockquote>
|
|
158
|
-
<CodeBlock>{"bun add silvery # install\nbun run dev # start dev server"}</CodeBlock>
|
|
159
|
-
|
|
160
|
-
<H2>Lists</H2>
|
|
161
|
-
<Box flexDirection="row" gap={4}>
|
|
162
|
-
<Box flexDirection="column" flexGrow={1} flexBasis={0}>
|
|
163
|
-
<H3>Unordered</H3>
|
|
164
|
-
<UL>
|
|
165
|
-
<LI>
|
|
166
|
-
<Strong>SelectList</Strong> — j/k navigation, scroll
|
|
167
|
-
</LI>
|
|
168
|
-
<LI>
|
|
169
|
-
<Strong>TextInput</Strong> — full readline support
|
|
170
|
-
</LI>
|
|
171
|
-
<LI>
|
|
172
|
-
<Strong>ModalDialog</Strong> — overlay with input blocking
|
|
173
|
-
</LI>
|
|
174
|
-
<LI>
|
|
175
|
-
<Strong>ProgressBar</Strong> — determinate + indeterminate
|
|
176
|
-
</LI>
|
|
177
|
-
</UL>
|
|
178
|
-
</Box>
|
|
179
|
-
<Box flexDirection="column" flexGrow={1} flexBasis={0}>
|
|
180
|
-
<H3>Ordered</H3>
|
|
181
|
-
<OL>
|
|
182
|
-
<LI>
|
|
183
|
-
Install with <Code>bun add silvery</Code>
|
|
184
|
-
</LI>
|
|
185
|
-
<LI>
|
|
186
|
-
Use <Code>$tokens</Code> for semantic colors
|
|
187
|
-
</LI>
|
|
188
|
-
<LI>
|
|
189
|
-
Layout with <Code>flexbox</Code> via Flexily
|
|
190
|
-
</LI>
|
|
191
|
-
<LI>
|
|
192
|
-
Test with <Code>createTermless()</Code>
|
|
193
|
-
</LI>
|
|
194
|
-
</OL>
|
|
195
|
-
</Box>
|
|
196
|
-
</Box>
|
|
197
|
-
|
|
198
|
-
<Small>silvery v0.0.1 — 38 palettes, 30+ components — silvery.dev</Small>
|
|
199
|
-
</Box>
|
|
200
|
-
)
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// ============================================================================
|
|
204
|
-
// Inputs Tab
|
|
205
|
-
// ============================================================================
|
|
206
|
-
|
|
207
|
-
const frameworkItems = [
|
|
208
|
-
{ label: "Silvery", value: "silvery" },
|
|
209
|
-
{ label: "Ink", value: "ink" },
|
|
210
|
-
{ label: "Blessed", value: "blessed", disabled: true },
|
|
211
|
-
{ label: "Terminal Kit", value: "terminal-kit" },
|
|
212
|
-
{ label: "React Curse", value: "react-curse" },
|
|
213
|
-
]
|
|
214
|
-
|
|
215
|
-
function InputsTab() {
|
|
216
|
-
const [textValue, setTextValue] = useState("")
|
|
217
|
-
const [areaValue, setAreaValue] = useState("")
|
|
218
|
-
const [selectedFramework, setSelectedFramework] = useState(0)
|
|
219
|
-
const [darkMode, setDarkMode] = useState(true)
|
|
220
|
-
const [notifications, setNotifications] = useState(false)
|
|
221
|
-
const [autoSave, setAutoSave] = useState(true)
|
|
222
|
-
const [focusIndex, setFocusIndex] = useState(0)
|
|
223
|
-
|
|
224
|
-
const focusableCount = 5
|
|
225
|
-
|
|
226
|
-
useInput((_input: string, key: Key) => {
|
|
227
|
-
if (key.tab && !key.shift) {
|
|
228
|
-
setFocusIndex((prev) => (prev + 1) % focusableCount)
|
|
229
|
-
}
|
|
230
|
-
if (key.tab && key.shift) {
|
|
231
|
-
setFocusIndex((prev) => (prev - 1 + focusableCount) % focusableCount)
|
|
232
|
-
}
|
|
233
|
-
})
|
|
234
|
-
|
|
235
|
-
const resetAll = useCallback(() => {
|
|
236
|
-
setTextValue("")
|
|
237
|
-
setAreaValue("")
|
|
238
|
-
setSelectedFramework(0)
|
|
239
|
-
setDarkMode(true)
|
|
240
|
-
setNotifications(false)
|
|
241
|
-
setAutoSave(true)
|
|
242
|
-
}, [])
|
|
243
|
-
|
|
244
|
-
return (
|
|
245
|
-
<Box flexDirection="column" gap={1} paddingX={1} overflow="scroll" flexGrow={1}>
|
|
246
|
-
<Box flexDirection="row" gap={2} flexGrow={1}>
|
|
247
|
-
{/* Left column: Input controls */}
|
|
248
|
-
<Box flexDirection="column" gap={1} flexGrow={1} flexBasis={0}>
|
|
249
|
-
<H2>Text Input</H2>
|
|
250
|
-
<TextInput
|
|
251
|
-
value={textValue}
|
|
252
|
-
onChange={setTextValue}
|
|
253
|
-
onSubmit={() => setTextValue("")}
|
|
254
|
-
placeholder="Type something..."
|
|
255
|
-
prompt="search: "
|
|
256
|
-
borderStyle="round"
|
|
257
|
-
isActive={focusIndex === 0}
|
|
258
|
-
/>
|
|
259
|
-
|
|
260
|
-
<H2>Text Area</H2>
|
|
261
|
-
<TextArea
|
|
262
|
-
value={areaValue}
|
|
263
|
-
onChange={setAreaValue}
|
|
264
|
-
placeholder="Write your thoughts..."
|
|
265
|
-
height={4}
|
|
266
|
-
borderStyle="round"
|
|
267
|
-
isActive={focusIndex === 1}
|
|
268
|
-
/>
|
|
269
|
-
|
|
270
|
-
<H2>Select List</H2>
|
|
271
|
-
<Box borderStyle="round" borderColor={focusIndex === 2 ? "$focusborder" : "$border"} paddingX={1}>
|
|
272
|
-
<SelectList
|
|
273
|
-
items={frameworkItems}
|
|
274
|
-
highlightedIndex={selectedFramework}
|
|
275
|
-
onHighlight={setSelectedFramework}
|
|
276
|
-
isActive={focusIndex === 2}
|
|
277
|
-
/>
|
|
278
|
-
</Box>
|
|
279
|
-
</Box>
|
|
280
|
-
|
|
281
|
-
{/* Right column: Toggles + Summary */}
|
|
282
|
-
<Box flexDirection="column" gap={1} flexGrow={1} flexBasis={0}>
|
|
283
|
-
<H2>Toggles</H2>
|
|
284
|
-
<Box
|
|
285
|
-
flexDirection="column"
|
|
286
|
-
borderStyle="round"
|
|
287
|
-
borderColor={focusIndex === 3 ? "$focusborder" : "$border"}
|
|
288
|
-
paddingX={1}
|
|
289
|
-
paddingY={1}
|
|
290
|
-
gap={1}
|
|
291
|
-
>
|
|
292
|
-
<Toggle value={darkMode} onChange={setDarkMode} label="Dark mode" isActive={focusIndex === 3} />
|
|
293
|
-
<Toggle value={notifications} onChange={setNotifications} label="Notifications" isActive={false} />
|
|
294
|
-
<Toggle value={autoSave} onChange={setAutoSave} label="Auto-save" isActive={false} />
|
|
295
|
-
</Box>
|
|
296
|
-
|
|
297
|
-
<H2>Button</H2>
|
|
298
|
-
<Button label="Reset All" onPress={resetAll} isActive={focusIndex === 4} />
|
|
299
|
-
|
|
300
|
-
<HR />
|
|
301
|
-
|
|
302
|
-
<H2>Current Values</H2>
|
|
303
|
-
<Box flexDirection="column" backgroundColor="$surfacebg" paddingX={1} paddingY={1} borderStyle="round">
|
|
304
|
-
<Text color="$surface">
|
|
305
|
-
<Strong>Text:</Strong> {textValue || <Muted>(empty)</Muted>}
|
|
306
|
-
</Text>
|
|
307
|
-
<Text color="$surface">
|
|
308
|
-
<Strong>Area:</Strong>{" "}
|
|
309
|
-
{areaValue ? areaValue.split("\n")[0] + (areaValue.includes("\n") ? "..." : "") : <Muted>(empty)</Muted>}
|
|
310
|
-
</Text>
|
|
311
|
-
<Text color="$surface">
|
|
312
|
-
<Strong>Framework:</Strong> {frameworkItems[selectedFramework]?.label}
|
|
313
|
-
</Text>
|
|
314
|
-
<Text color="$surface">
|
|
315
|
-
<Strong>Dark mode:</Strong> {darkMode ? "on" : "off"}
|
|
316
|
-
</Text>
|
|
317
|
-
<Text color="$surface">
|
|
318
|
-
<Strong>Notifications:</Strong> {notifications ? "on" : "off"}
|
|
319
|
-
</Text>
|
|
320
|
-
<Text color="$surface">
|
|
321
|
-
<Strong>Auto-save:</Strong> {autoSave ? "on" : "off"}
|
|
322
|
-
</Text>
|
|
323
|
-
</Box>
|
|
324
|
-
</Box>
|
|
325
|
-
</Box>
|
|
326
|
-
|
|
327
|
-
{/* keyboard hints removed for static screenshots */}
|
|
328
|
-
</Box>
|
|
329
|
-
)
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// ============================================================================
|
|
333
|
-
// Display Tab
|
|
334
|
-
// ============================================================================
|
|
335
|
-
|
|
336
|
-
function DisplayTab({ scrollOffset }: { scrollOffset?: number }) {
|
|
337
|
-
const [showModal, setShowModal] = useState(false)
|
|
338
|
-
const [selectedBorder, setSelectedBorder] = useState(0)
|
|
339
|
-
|
|
340
|
-
const borderStyles = ["round", "bold", "single", "double", "classic"] as const
|
|
341
|
-
|
|
342
|
-
useInput((input: string, key: Key) => {
|
|
343
|
-
if (key.return && !showModal) {
|
|
344
|
-
setShowModal(true)
|
|
345
|
-
}
|
|
346
|
-
if ((key.escape || input === "q") && showModal) {
|
|
347
|
-
setShowModal(false)
|
|
348
|
-
}
|
|
349
|
-
if (input === "j" && !showModal) {
|
|
350
|
-
setSelectedBorder((prev) => Math.min(prev + 1, borderStyles.length - 1))
|
|
351
|
-
}
|
|
352
|
-
if (input === "k" && !showModal) {
|
|
353
|
-
setSelectedBorder((prev) => Math.max(prev - 1, 0))
|
|
354
|
-
}
|
|
355
|
-
})
|
|
356
|
-
|
|
357
|
-
const cell = {
|
|
358
|
-
flexGrow: 1,
|
|
359
|
-
flexBasis: 0,
|
|
360
|
-
borderStyle: "round" as const,
|
|
361
|
-
borderColor: "$border",
|
|
362
|
-
paddingX: 1,
|
|
363
|
-
paddingY: 1,
|
|
364
|
-
flexDirection: "column" as const,
|
|
365
|
-
gap: 1,
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
return (
|
|
369
|
-
<Box flexDirection="column" gap={1} paddingX={1}>
|
|
370
|
-
{/* Row 1 */}
|
|
371
|
-
<Box flexDirection="row" gap={1}>
|
|
372
|
-
<Box {...cell}>
|
|
373
|
-
<Text color="$primary">
|
|
374
|
-
<Strong>Progress Bars</Strong>
|
|
375
|
-
</Text>
|
|
376
|
-
<Box flexDirection="column">
|
|
377
|
-
<Box>
|
|
378
|
-
<Text color="$muted">{"Build "}</Text>
|
|
379
|
-
<Box flexGrow={1}>
|
|
380
|
-
<ProgressBar value={1.0} label="✓" />
|
|
381
|
-
</Box>
|
|
382
|
-
</Box>
|
|
383
|
-
<Box>
|
|
384
|
-
<Text color="$muted">{"Test "}</Text>
|
|
385
|
-
<Box flexGrow={1}>
|
|
386
|
-
<ProgressBar value={0.73} />
|
|
387
|
-
</Box>
|
|
388
|
-
</Box>
|
|
389
|
-
<Box>
|
|
390
|
-
<Text color="$muted">{"Deploy "}</Text>
|
|
391
|
-
<Box flexGrow={1}>
|
|
392
|
-
<ProgressBar value={0.35} />
|
|
393
|
-
</Box>
|
|
394
|
-
</Box>
|
|
395
|
-
<Box>
|
|
396
|
-
<Text color="$muted">{"Install "}</Text>
|
|
397
|
-
<Box flexGrow={1}>
|
|
398
|
-
<ProgressBar />
|
|
399
|
-
</Box>
|
|
400
|
-
</Box>
|
|
401
|
-
</Box>
|
|
402
|
-
<Box flexDirection="column">
|
|
403
|
-
<Spinner type="dots" label="Loading packages..." />
|
|
404
|
-
<Spinner type="line" label="Compiling..." />
|
|
405
|
-
<Spinner type="arc" label="Optimizing bundle..." />
|
|
406
|
-
</Box>
|
|
407
|
-
</Box>
|
|
408
|
-
<Box {...cell}>
|
|
409
|
-
<Text color="$primary">
|
|
410
|
-
<Strong>Input Controls</Strong>
|
|
411
|
-
</Text>
|
|
412
|
-
<Box flexDirection="column" gap={1}>
|
|
413
|
-
<Box gap={1}>
|
|
414
|
-
<Muted>Search:</Muted>
|
|
415
|
-
<Box flexGrow={1}>
|
|
416
|
-
<TextInput value="flutter widgets" onChange={() => {}} showUnderline underlineWidth={25} />
|
|
417
|
-
</Box>
|
|
418
|
-
</Box>
|
|
419
|
-
<Box gap={2} wrap="truncate">
|
|
420
|
-
<Toggle label="Dark mode" value={true} onChange={() => {}} />
|
|
421
|
-
<Toggle label="Notifications" value={false} onChange={() => {}} />
|
|
422
|
-
</Box>
|
|
423
|
-
</Box>
|
|
424
|
-
<SelectList
|
|
425
|
-
items={[
|
|
426
|
-
{ label: "React", value: "react" },
|
|
427
|
-
{ label: "Vue", value: "vue" },
|
|
428
|
-
{ label: "Svelte", value: "svelte" },
|
|
429
|
-
{ label: "Angular", value: "angular" },
|
|
430
|
-
]}
|
|
431
|
-
highlightedIndex={0}
|
|
432
|
-
onHighlight={() => {}}
|
|
433
|
-
isActive={false}
|
|
434
|
-
/>
|
|
435
|
-
</Box>
|
|
436
|
-
</Box>
|
|
437
|
-
|
|
438
|
-
{/* Row 2: Border Styles | Design Tokens | Modal Dialog */}
|
|
439
|
-
<Box flexDirection="row" gap={1}>
|
|
440
|
-
{/* Left half: two stacked boxes */}
|
|
441
|
-
<Box flexDirection="column" gap={1} flexGrow={1} flexBasis={0}>
|
|
442
|
-
<Box {...cell} flexGrow={1} flexBasis={0}>
|
|
443
|
-
<Text color="$primary">
|
|
444
|
-
<Strong>Border Styles</Strong>
|
|
445
|
-
</Text>
|
|
446
|
-
<Box flexDirection="column" gap={0}>
|
|
447
|
-
{borderStyles.map((style, i) => (
|
|
448
|
-
<Box
|
|
449
|
-
key={style}
|
|
450
|
-
borderStyle={style as any}
|
|
451
|
-
borderColor={i === selectedBorder ? "$primary" : "$border"}
|
|
452
|
-
borderLeft={true}
|
|
453
|
-
borderRight={true}
|
|
454
|
-
borderTop={i === 0}
|
|
455
|
-
borderBottom={true}
|
|
456
|
-
paddingX={1}
|
|
457
|
-
>
|
|
458
|
-
<Text bold={i === selectedBorder}>
|
|
459
|
-
{i === selectedBorder ? "▸ " : " "}
|
|
460
|
-
{style}
|
|
461
|
-
</Text>
|
|
462
|
-
</Box>
|
|
463
|
-
))}
|
|
464
|
-
</Box>
|
|
465
|
-
</Box>
|
|
466
|
-
<Box {...cell} flexGrow={1} flexBasis={0}>
|
|
467
|
-
<Text color="$primary">
|
|
468
|
-
<Strong>Design Tokens</Strong>
|
|
469
|
-
</Text>
|
|
470
|
-
<Box flexDirection="row" gap={2}>
|
|
471
|
-
<Box flexDirection="column" width={14}>
|
|
472
|
-
<Text color="$success">
|
|
473
|
-
{"●"} {"$success".padEnd(10)}
|
|
474
|
-
</Text>
|
|
475
|
-
<Text color="$warning">
|
|
476
|
-
{"●"} {"$warning".padEnd(10)}
|
|
477
|
-
</Text>
|
|
478
|
-
<Text color="$error">
|
|
479
|
-
{"●"} {"$error".padEnd(10)}
|
|
480
|
-
</Text>
|
|
481
|
-
<Text color="$info">
|
|
482
|
-
{"●"} {"$info".padEnd(10)}
|
|
483
|
-
</Text>
|
|
484
|
-
<Text color="$primary">
|
|
485
|
-
{"●"} {"$primary".padEnd(10)}
|
|
486
|
-
</Text>
|
|
487
|
-
<Muted>
|
|
488
|
-
{"●"} {"$muted".padEnd(10)}
|
|
489
|
-
</Muted>
|
|
490
|
-
</Box>
|
|
491
|
-
<Box flexDirection="column">
|
|
492
|
-
<Text backgroundColor="$primary" color="$primary-fg">
|
|
493
|
-
{" $primary "}
|
|
494
|
-
</Text>
|
|
495
|
-
<Text backgroundColor="$fg" color="$bg">
|
|
496
|
-
{" $inverse "}
|
|
497
|
-
</Text>
|
|
498
|
-
<Text backgroundColor="$muted-bg" color="$fg">
|
|
499
|
-
{" $surface "}
|
|
500
|
-
</Text>
|
|
501
|
-
<Text backgroundColor="$surfacebg" color="$surface">
|
|
502
|
-
{" $surfacebg "}
|
|
503
|
-
</Text>
|
|
504
|
-
</Box>
|
|
505
|
-
</Box>
|
|
506
|
-
</Box>
|
|
507
|
-
</Box>
|
|
508
|
-
{/* Right half: Modal Dialog */}
|
|
509
|
-
<Box {...cell} backgroundColor="$surfacebg" paddingRight={2}>
|
|
510
|
-
<Box justifyContent="space-between" paddingBottom={1}>
|
|
511
|
-
<Text color="$primary">
|
|
512
|
-
<Strong>Modal Dialog</Strong>
|
|
513
|
-
</Text>
|
|
514
|
-
<Small color="$muted">Esc to close</Small>
|
|
515
|
-
</Box>
|
|
516
|
-
<Box flexDirection="column" gap={1}>
|
|
517
|
-
<Box gap={1}>
|
|
518
|
-
<Muted>Branch:</Muted>
|
|
519
|
-
<TextInput value="main" onChange={() => {}} showUnderline underlineWidth={25} isActive={true} />
|
|
520
|
-
</Box>
|
|
521
|
-
<Box flexDirection="column">
|
|
522
|
-
<Text>
|
|
523
|
-
<Text color="$success">{"✓"}</Text> All checks passed
|
|
524
|
-
</Text>
|
|
525
|
-
<Text>
|
|
526
|
-
<Text color="$success">{"✓"}</Text> Tests: 247 passed
|
|
527
|
-
</Text>
|
|
528
|
-
<Text>
|
|
529
|
-
<Text color="$warning">{"⚠"}</Text> 2 deprecation warnings
|
|
530
|
-
</Text>
|
|
531
|
-
<Text>
|
|
532
|
-
<Text color="$muted">{"ℹ"}</Text> Deploy target: us-east-1
|
|
533
|
-
</Text>
|
|
534
|
-
</Box>
|
|
535
|
-
<Box gap={2}>
|
|
536
|
-
<Text backgroundColor="$primary" color="$primary-fg">
|
|
537
|
-
{" Deploy "}
|
|
538
|
-
</Text>
|
|
539
|
-
<Text backgroundColor="$muted-bg" color="$fg">
|
|
540
|
-
{" Cancel "}
|
|
541
|
-
</Text>
|
|
542
|
-
</Box>
|
|
543
|
-
</Box>
|
|
544
|
-
</Box>
|
|
545
|
-
</Box>
|
|
546
|
-
|
|
547
|
-
{showModal && (
|
|
548
|
-
<Box position="absolute" display="flex" justifyContent="center" alignItems="center" width="100%" height="100%">
|
|
549
|
-
<ModalDialog title="Component Gallery" width={50} footer="ESC or q to close">
|
|
550
|
-
<Box flexDirection="column" gap={1}>
|
|
551
|
-
<P>
|
|
552
|
-
This gallery demonstrates <Strong>silvery</Strong>'s built-in UI components. Every component uses
|
|
553
|
-
semantic theme tokens — they adapt to any of the 38 built-in palettes automatically.
|
|
554
|
-
</P>
|
|
555
|
-
<HR />
|
|
556
|
-
<Box flexDirection="column">
|
|
557
|
-
<Text color="$success">{"✓ Typography presets (H1-H3, Lead, Muted, Code)"}</Text>
|
|
558
|
-
<Text color="$success">{"✓ Input components (TextInput, TextArea, SelectList)"}</Text>
|
|
559
|
-
<Text color="$success">{"✓ Display widgets (ProgressBar, Spinner, Badge)"}</Text>
|
|
560
|
-
<Text color="$success">{"✓ Layout primitives (Box, Divider, border styles)"}</Text>
|
|
561
|
-
<Text color="$success">{"✓ Dialog system (ModalDialog with input blocking)"}</Text>
|
|
562
|
-
</Box>
|
|
563
|
-
</Box>
|
|
564
|
-
</ModalDialog>
|
|
565
|
-
</Box>
|
|
566
|
-
)}
|
|
567
|
-
</Box>
|
|
568
|
-
)
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
// ============================================================================
|
|
572
|
-
// App
|
|
573
|
-
// ============================================================================
|
|
574
|
-
|
|
575
|
-
export function ComponentsApp() {
|
|
576
|
-
const { exit } = useApp()
|
|
577
|
-
const [activeTab, setActiveTab] = useState("display")
|
|
578
|
-
const [scrollOffset, setScrollOffset] = useState(0)
|
|
579
|
-
|
|
580
|
-
// Reset scroll when switching tabs
|
|
581
|
-
const handleTabChange = useCallback((tab: string) => {
|
|
582
|
-
setActiveTab(tab)
|
|
583
|
-
setScrollOffset(0)
|
|
584
|
-
}, [])
|
|
585
|
-
|
|
586
|
-
const tabs = ["display", "inputs", "typography"] as const
|
|
587
|
-
|
|
588
|
-
useInput((input: string, key: Key) => {
|
|
589
|
-
// Only quit with q when not on the inputs tab (where user may be typing)
|
|
590
|
-
if (input === "q" && activeTab !== "inputs") {
|
|
591
|
-
exit()
|
|
592
|
-
}
|
|
593
|
-
if (key.escape && activeTab !== "display") {
|
|
594
|
-
exit()
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// Tab switching with h/l
|
|
598
|
-
if (input === "l" && activeTab !== "inputs") {
|
|
599
|
-
const idx = tabs.indexOf(activeTab as (typeof tabs)[number])
|
|
600
|
-
handleTabChange(tabs[(idx + 1) % tabs.length]!)
|
|
601
|
-
return
|
|
602
|
-
}
|
|
603
|
-
if (input === "h" && activeTab !== "inputs") {
|
|
604
|
-
const idx = tabs.indexOf(activeTab as (typeof tabs)[number])
|
|
605
|
-
handleTabChange(tabs[(idx - 1 + tabs.length) % tabs.length]!)
|
|
606
|
-
return
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
// Arrow keys / j/k scroll the active tab content (typography and display tabs)
|
|
610
|
-
if (activeTab !== "inputs") {
|
|
611
|
-
if (key.downArrow || (activeTab === "typography" && input === "j")) {
|
|
612
|
-
setScrollOffset((prev) => prev + 1)
|
|
613
|
-
}
|
|
614
|
-
if (key.upArrow || (activeTab === "typography" && input === "k")) {
|
|
615
|
-
setScrollOffset((prev) => Math.max(0, prev - 1))
|
|
616
|
-
}
|
|
617
|
-
if (key.pageDown) {
|
|
618
|
-
setScrollOffset((prev) => prev + 10)
|
|
619
|
-
}
|
|
620
|
-
if (key.pageUp) {
|
|
621
|
-
setScrollOffset((prev) => Math.max(0, prev - 10))
|
|
622
|
-
}
|
|
623
|
-
if (key.home || (activeTab === "typography" && input === "g")) {
|
|
624
|
-
setScrollOffset(0)
|
|
625
|
-
}
|
|
626
|
-
if (key.end || (activeTab === "typography" && input === "G")) {
|
|
627
|
-
setScrollOffset(999) // will be clamped by scroll phase
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
})
|
|
631
|
-
|
|
632
|
-
return (
|
|
633
|
-
<Box flexDirection="column" flexGrow={1} padding={1}>
|
|
634
|
-
{activeTab === "display" && <DisplayTab scrollOffset={scrollOffset} />}
|
|
635
|
-
{activeTab === "inputs" && <InputsTab />}
|
|
636
|
-
{activeTab === "typography" && <TypographyTab scrollOffset={scrollOffset} />}
|
|
637
|
-
</Box>
|
|
638
|
-
)
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
// ============================================================================
|
|
642
|
-
// Main
|
|
643
|
-
// ============================================================================
|
|
644
|
-
|
|
645
|
-
export async function main() {
|
|
646
|
-
using term = createTerm()
|
|
647
|
-
const { waitUntilExit } = await render(
|
|
648
|
-
<ExampleBanner meta={meta} controls="h/l tab Tab cycle inputs j/k navigate Enter modal Esc/q quit">
|
|
649
|
-
<ComponentsApp />
|
|
650
|
-
</ExampleBanner>,
|
|
651
|
-
term,
|
|
652
|
-
)
|
|
653
|
-
await waitUntilExit()
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
if (import.meta.main) {
|
|
657
|
-
main().catch(console.error)
|
|
658
|
-
}
|