basefn 1.0.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.
- package/README.md +104 -0
- package/package.json +82 -0
- package/rescript.json +32 -0
- package/src/Basefn.css +14 -0
- package/src/Basefn.res +105 -0
- package/src/Basefn.res.mjs +114 -0
- package/src/Basefn__Dom.res +9 -0
- package/src/Basefn__Dom.res.mjs +24 -0
- package/src/Basefn__Utils.res +15 -0
- package/src/Basefn__Utils.res.mjs +32 -0
- package/src/Demo.res +1417 -0
- package/src/Demo.res.mjs +2328 -0
- package/src/Eita.res.mjs +105 -0
- package/src/Eita__Accordion.res.mjs +77 -0
- package/src/Eita__Alert.res.mjs +81 -0
- package/src/Eita__AppLayout.res.mjs +100 -0
- package/src/Eita__Avatar.res.mjs +40 -0
- package/src/Eita__Badge.res.mjs +65 -0
- package/src/Eita__Breadcrumb.res.mjs +53 -0
- package/src/Eita__Button.res.mjs +47 -0
- package/src/Eita__Card.res.mjs +60 -0
- package/src/Eita__Checkbox.res.mjs +36 -0
- package/src/Eita__Dom.res.mjs +16 -0
- package/src/Eita__Drawer.res.mjs +112 -0
- package/src/Eita__Dropdown.res.mjs +96 -0
- package/src/Eita__Grid.res.mjs +24 -0
- package/src/Eita__Input.res.mjs +54 -0
- package/src/Eita__Kbd.res.mjs +42 -0
- package/src/Eita__Label.res.mjs +24 -0
- package/src/Eita__Modal.res.mjs +93 -0
- package/src/Eita__Progress.res.mjs +101 -0
- package/src/Eita__Radio.res.mjs +38 -0
- package/src/Eita__Select.res.mjs +40 -0
- package/src/Eita__Separator.res.mjs +70 -0
- package/src/Eita__Sidebar.res.mjs +103 -0
- package/src/Eita__Slider.res.mjs +89 -0
- package/src/Eita__Spinner.res.mjs +69 -0
- package/src/Eita__Stepper.res.mjs +114 -0
- package/src/Eita__Switch.res.mjs +84 -0
- package/src/Eita__Tabs.res.mjs +57 -0
- package/src/Eita__Textarea.res.mjs +39 -0
- package/src/Eita__Timeline.res.mjs +86 -0
- package/src/Eita__Toast.res.mjs +112 -0
- package/src/Eita__Tooltip.res.mjs +60 -0
- package/src/Eita__Topbar.res.mjs +96 -0
- package/src/Eita__Typography.res.mjs +183 -0
- package/src/Eita__Utils.res.mjs +32 -0
- package/src/Example.res +111 -0
- package/src/Example.res.mjs +176 -0
- package/src/components/Basefn__Accordion.css +70 -0
- package/src/components/Basefn__Accordion.res +79 -0
- package/src/components/Basefn__Accordion.res.mjs +77 -0
- package/src/components/Basefn__Alert.css +79 -0
- package/src/components/Basefn__Alert.res +68 -0
- package/src/components/Basefn__Alert.res.mjs +78 -0
- package/src/components/Basefn__AppLayout.css +100 -0
- package/src/components/Basefn__AppLayout.res +74 -0
- package/src/components/Basefn__AppLayout.res.mjs +100 -0
- package/src/components/Basefn__Avatar.css +25 -0
- package/src/components/Basefn__Avatar.res +23 -0
- package/src/components/Basefn__Avatar.res.mjs +40 -0
- package/src/components/Basefn__Badge.css +71 -0
- package/src/components/Basefn__Badge.res +43 -0
- package/src/components/Basefn__Badge.res.mjs +65 -0
- package/src/components/Basefn__Breadcrumb.css +36 -0
- package/src/components/Basefn__Breadcrumb.res +45 -0
- package/src/components/Basefn__Breadcrumb.res.mjs +53 -0
- package/src/components/Basefn__Button.css +83 -0
- package/src/components/Basefn__Button.res +32 -0
- package/src/components/Basefn__Button.res.mjs +54 -0
- package/src/components/Basefn__Card.css +50 -0
- package/src/components/Basefn__Card.res +45 -0
- package/src/components/Basefn__Card.res.mjs +60 -0
- package/src/components/Basefn__Checkbox.css +72 -0
- package/src/components/Basefn__Checkbox.res +25 -0
- package/src/components/Basefn__Checkbox.res.mjs +36 -0
- package/src/components/Basefn__Drawer.css +168 -0
- package/src/components/Basefn__Drawer.res +86 -0
- package/src/components/Basefn__Drawer.res.mjs +112 -0
- package/src/components/Basefn__Dropdown.css +76 -0
- package/src/components/Basefn__Dropdown.res +85 -0
- package/src/components/Basefn__Dropdown.res.mjs +96 -0
- package/src/components/Basefn__Grid.css +11 -0
- package/src/components/Basefn__Grid.res +296 -0
- package/src/components/Basefn__Grid.res.mjs +263 -0
- package/src/components/Basefn__Icon.css +12 -0
- package/src/components/Basefn__Icon.res +196 -0
- package/src/components/Basefn__Icon.res.mjs +183 -0
- package/src/components/Basefn__Input.css +44 -0
- package/src/components/Basefn__Input.res +48 -0
- package/src/components/Basefn__Input.res.mjs +63 -0
- package/src/components/Basefn__Kbd.css +65 -0
- package/src/components/Basefn__Kbd.res +27 -0
- package/src/components/Basefn__Kbd.res.mjs +42 -0
- package/src/components/Basefn__Label.css +22 -0
- package/src/components/Basefn__Label.res +18 -0
- package/src/components/Basefn__Label.res.mjs +24 -0
- package/src/components/Basefn__Modal.css +100 -0
- package/src/components/Basefn__Modal.res +74 -0
- package/src/components/Basefn__Modal.res.mjs +93 -0
- package/src/components/Basefn__Progress.css +69 -0
- package/src/components/Basefn__Progress.res +88 -0
- package/src/components/Basefn__Progress.res.mjs +101 -0
- package/src/components/Basefn__Radio.css +72 -0
- package/src/components/Basefn__Radio.res +35 -0
- package/src/components/Basefn__Radio.res.mjs +38 -0
- package/src/components/Basefn__Select.css +44 -0
- package/src/components/Basefn__Select.res +33 -0
- package/src/components/Basefn__Select.res.mjs +40 -0
- package/src/components/Basefn__Separator.css +85 -0
- package/src/components/Basefn__Separator.res +45 -0
- package/src/components/Basefn__Separator.res.mjs +70 -0
- package/src/components/Basefn__Sidebar.css +141 -0
- package/src/components/Basefn__Sidebar.res +95 -0
- package/src/components/Basefn__Sidebar.res.mjs +107 -0
- package/src/components/Basefn__Slider.css +97 -0
- package/src/components/Basefn__Slider.res +68 -0
- package/src/components/Basefn__Slider.res.mjs +89 -0
- package/src/components/Basefn__Spinner.css +63 -0
- package/src/components/Basefn__Spinner.res +44 -0
- package/src/components/Basefn__Spinner.res.mjs +69 -0
- package/src/components/Basefn__Stepper.css +141 -0
- package/src/components/Basefn__Stepper.res +86 -0
- package/src/components/Basefn__Stepper.res.mjs +114 -0
- package/src/components/Basefn__Switch.css +80 -0
- package/src/components/Basefn__Switch.res +62 -0
- package/src/components/Basefn__Switch.res.mjs +84 -0
- package/src/components/Basefn__Tabs.css +54 -0
- package/src/components/Basefn__Tabs.res +73 -0
- package/src/components/Basefn__Tabs.res.mjs +57 -0
- package/src/components/Basefn__Textarea.css +41 -0
- package/src/components/Basefn__Textarea.res +28 -0
- package/src/components/Basefn__Textarea.res.mjs +41 -0
- package/src/components/Basefn__ThemeToggle.css +5 -0
- package/src/components/Basefn__ThemeToggle.res +29 -0
- package/src/components/Basefn__ThemeToggle.res.mjs +49 -0
- package/src/components/Basefn__Timeline.css +144 -0
- package/src/components/Basefn__Timeline.res +70 -0
- package/src/components/Basefn__Timeline.res.mjs +86 -0
- package/src/components/Basefn__Toast.css +100 -0
- package/src/components/Basefn__Toast.res +92 -0
- package/src/components/Basefn__Toast.res.mjs +112 -0
- package/src/components/Basefn__Tooltip.css +84 -0
- package/src/components/Basefn__Tooltip.res +42 -0
- package/src/components/Basefn__Tooltip.res.mjs +60 -0
- package/src/components/Basefn__Topbar.css +130 -0
- package/src/components/Basefn__Topbar.res +92 -0
- package/src/components/Basefn__Topbar.res.mjs +91 -0
- package/src/components/Basefn__Typography.css +120 -0
- package/src/components/Basefn__Typography.res +96 -0
- package/src/components/Basefn__Typography.res.mjs +175 -0
- package/src/styles/Basefn__Theme.res +63 -0
- package/src/styles/Basefn__Theme.res.mjs +65 -0
- package/src/styles/variables.css +199 -0
package/src/Demo.res
ADDED
|
@@ -0,0 +1,1417 @@
|
|
|
1
|
+
// Demo application showcasing basefn-UI components
|
|
2
|
+
|
|
3
|
+
%%raw(`import './styles/variables.css'`)
|
|
4
|
+
%%raw(`import './eita.css'`)
|
|
5
|
+
|
|
6
|
+
open Xote
|
|
7
|
+
open Basefn
|
|
8
|
+
|
|
9
|
+
@get external target: Dom.event => Dom.element = "target"
|
|
10
|
+
@set external setValue: (Dom.element, string) => unit = "value"
|
|
11
|
+
@get external key: Dom.event => string = "key"
|
|
12
|
+
|
|
13
|
+
@get external value: Dom.element => string = "value"
|
|
14
|
+
@send external preventDefault: Dom.event => unit = "preventDefault"
|
|
15
|
+
|
|
16
|
+
module Demo = {
|
|
17
|
+
@jsx.component
|
|
18
|
+
let make = () => {
|
|
19
|
+
// Form state using signals
|
|
20
|
+
let name = Signal.make("")
|
|
21
|
+
let email = Signal.make("")
|
|
22
|
+
let password = Signal.make("")
|
|
23
|
+
let message = Signal.make("")
|
|
24
|
+
let agreeToTerms = Signal.make(false)
|
|
25
|
+
let newsletter = Signal.make(false)
|
|
26
|
+
let selectedOption = Signal.make("option1")
|
|
27
|
+
let selectedColor = Signal.make("blue")
|
|
28
|
+
let isSubmitting = Signal.make(false)
|
|
29
|
+
let downloadProgress = Signal.make(65.0)
|
|
30
|
+
|
|
31
|
+
// Tier 3 component states
|
|
32
|
+
let isModalOpen = Signal.make(false)
|
|
33
|
+
let sliderValue = Signal.make(50.0)
|
|
34
|
+
let switchEnabled = Signal.make(false)
|
|
35
|
+
let darkModeSwitch = Signal.make(true)
|
|
36
|
+
let notificationsSwitch = Signal.make(false)
|
|
37
|
+
let toastVisible = Signal.make(false)
|
|
38
|
+
|
|
39
|
+
// Tier 4 component states
|
|
40
|
+
let currentStep = Signal.make(1)
|
|
41
|
+
let isDrawerOpen = Signal.make(false)
|
|
42
|
+
|
|
43
|
+
// Layout component states
|
|
44
|
+
let activeNavItem = Signal.make("home")
|
|
45
|
+
let sidebarCollapsed = Signal.make(false)
|
|
46
|
+
|
|
47
|
+
// Event handlers
|
|
48
|
+
let handleNameChange = evt => {
|
|
49
|
+
let target = Obj.magic(evt)["target"]
|
|
50
|
+
Signal.set(name, target["value"])
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let handleEmailChange = evt => {
|
|
54
|
+
let target = Obj.magic(evt)["target"]
|
|
55
|
+
Signal.set(email, target["value"])
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let handlePasswordChange = evt => {
|
|
59
|
+
let target = Obj.magic(evt)["target"]
|
|
60
|
+
Signal.set(password, target["value"])
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let handleMessageChange = evt => {
|
|
64
|
+
let target = Obj.magic(evt)["target"]
|
|
65
|
+
Signal.set(message, target["value"])
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let handleTermsChange = _evt => {
|
|
69
|
+
Signal.update(agreeToTerms, prev => !prev)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let handleNewsletterChange = _evt => {
|
|
73
|
+
Signal.update(newsletter, prev => !prev)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let handleColorChange = evt => {
|
|
77
|
+
let target = Obj.magic(evt)["target"]
|
|
78
|
+
Signal.set(selectedColor, target["value"])
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
let handleSubmit = _evt => {
|
|
82
|
+
Signal.set(isSubmitting, true)
|
|
83
|
+
Console.log("=== Form Submission ===")
|
|
84
|
+
Console.log(`Name: ${Signal.get(name)}`)
|
|
85
|
+
Console.log(`Email: ${Signal.get(email)}`)
|
|
86
|
+
Console.log(`Password: ${Signal.get(password)}`)
|
|
87
|
+
Console.log(`Message: ${Signal.get(message)}`)
|
|
88
|
+
Console.log(`Selected Option: ${Signal.get(selectedOption)}`)
|
|
89
|
+
Console.log(`Selected Color: ${Signal.get(selectedColor)}`)
|
|
90
|
+
Console.log(`Agree to Terms: ${Signal.get(agreeToTerms)->Bool.toString}`)
|
|
91
|
+
Console.log(`Newsletter: ${Signal.get(newsletter)->Bool.toString}`)
|
|
92
|
+
|
|
93
|
+
// Simulate API call
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
Signal.set(isSubmitting, false)
|
|
96
|
+
Console.log("Form submitted successfully!")
|
|
97
|
+
}, 2000)->ignore
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let handleReset = _evt => {
|
|
101
|
+
Signal.set(name, "")
|
|
102
|
+
Signal.set(email, "")
|
|
103
|
+
Signal.set(password, "")
|
|
104
|
+
Signal.set(message, "")
|
|
105
|
+
Signal.set(agreeToTerms, false)
|
|
106
|
+
Signal.set(newsletter, false)
|
|
107
|
+
Signal.set(selectedOption, "option1")
|
|
108
|
+
Signal.set(selectedColor, "blue")
|
|
109
|
+
Console.log("Form reset")
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
let selectOptions: array<selectOption> = [
|
|
113
|
+
{value: "option1", label: "Web Development"},
|
|
114
|
+
{value: "option2", label: "Mobile Development"},
|
|
115
|
+
{value: "option3", label: "UI/UX Design"},
|
|
116
|
+
{value: "option4", label: "Other"},
|
|
117
|
+
]
|
|
118
|
+
let selectOptionsSignal = Signal.make(selectOptions)
|
|
119
|
+
|
|
120
|
+
<>
|
|
121
|
+
{Component.textSignal(() => Signal.get(selectedOption))}
|
|
122
|
+
<h1> {Component.text("basefn-UI Component Library")} </h1>
|
|
123
|
+
<p style="color: #6b7280; margin-bottom: 2rem;">
|
|
124
|
+
{Component.text(
|
|
125
|
+
"A demonstration of all form components with both static and reactive values.",
|
|
126
|
+
)}
|
|
127
|
+
</p>
|
|
128
|
+
|
|
129
|
+
<Card style="margin-bottom: 2rem;">
|
|
130
|
+
<Grid>
|
|
131
|
+
<Avatar src="https://upload.wikimedia.org/wikipedia/commons/a/ad/Schopfkarakara.jpg" />
|
|
132
|
+
<div>
|
|
133
|
+
<Typography
|
|
134
|
+
text={ReactiveProp.Static("Crested Caracara")}
|
|
135
|
+
variant=Typography.Unstyled
|
|
136
|
+
class="bold"
|
|
137
|
+
/>
|
|
138
|
+
<Typography text={ReactiveProp.Static("Bird of prey")} variant=Typography.Small />
|
|
139
|
+
</div>
|
|
140
|
+
</Grid>
|
|
141
|
+
<br />
|
|
142
|
+
<Grid>
|
|
143
|
+
<Avatar src="https://upload.wikimedia.org/wikipedia/commons/a/ad/Schopfkarakara.jpg" />
|
|
144
|
+
<div>
|
|
145
|
+
<Typography
|
|
146
|
+
text={ReactiveProp.Static("Crested Caracara")} variant=Typography.P class="bold"
|
|
147
|
+
/>
|
|
148
|
+
</div>
|
|
149
|
+
</Grid>
|
|
150
|
+
<br />
|
|
151
|
+
<Grid>
|
|
152
|
+
<Avatar
|
|
153
|
+
src="https://upload.wikimedia.org/wikipedia/commons/a/ad/Schopfkarakara.jpg" size={Sm}
|
|
154
|
+
/>
|
|
155
|
+
<div>
|
|
156
|
+
<Typography
|
|
157
|
+
text={ReactiveProp.Static("Crested Caracara")} variant=Typography.Unstyled
|
|
158
|
+
/>
|
|
159
|
+
</div>
|
|
160
|
+
</Grid>
|
|
161
|
+
<br />
|
|
162
|
+
<Grid gap="1rem">
|
|
163
|
+
<Avatar
|
|
164
|
+
src="https://upload.wikimedia.org/wikipedia/commons/a/ad/Schopfkarakara.jpg" size={Lg}
|
|
165
|
+
/>
|
|
166
|
+
<div>
|
|
167
|
+
<Typography text={ReactiveProp.Static("Crested Caracara")} variant=Typography.H4 />
|
|
168
|
+
<Typography
|
|
169
|
+
text={ReactiveProp.Static("Bird of prey")}
|
|
170
|
+
variant=Typography.H6
|
|
171
|
+
class="muted font-normal"
|
|
172
|
+
/>
|
|
173
|
+
</div>
|
|
174
|
+
</Grid>
|
|
175
|
+
</Card>
|
|
176
|
+
|
|
177
|
+
<Card>
|
|
178
|
+
<Label text="Full Name" required={true} />
|
|
179
|
+
<Input
|
|
180
|
+
value={Reactive(name)}
|
|
181
|
+
onInput={handleNameChange}
|
|
182
|
+
type_={Input.Text}
|
|
183
|
+
placeholder="John Doe"
|
|
184
|
+
/>
|
|
185
|
+
<br />
|
|
186
|
+
<Label text="Email Address" required={true} />
|
|
187
|
+
<Input
|
|
188
|
+
value={Reactive(email)}
|
|
189
|
+
onInput={handleEmailChange}
|
|
190
|
+
type_={Input.Email}
|
|
191
|
+
placeholder="john@example.com"
|
|
192
|
+
/>
|
|
193
|
+
<br />
|
|
194
|
+
<Label text="Password" required={true} />
|
|
195
|
+
<Input
|
|
196
|
+
value={Reactive(password)}
|
|
197
|
+
onInput={handlePasswordChange}
|
|
198
|
+
type_={Input.Password}
|
|
199
|
+
placeholder="Enter a secure password"
|
|
200
|
+
/>
|
|
201
|
+
</Card>
|
|
202
|
+
<br />
|
|
203
|
+
<Card>
|
|
204
|
+
<Label text="Area of Interest" required={false} />
|
|
205
|
+
<Select
|
|
206
|
+
value={selectedOption}
|
|
207
|
+
options={selectOptionsSignal}
|
|
208
|
+
onChange={e => {
|
|
209
|
+
let target = Obj.magic(e)["target"]
|
|
210
|
+
Signal.set(selectedOption, target["value"])
|
|
211
|
+
}}
|
|
212
|
+
/>
|
|
213
|
+
<br />
|
|
214
|
+
<Label text="Favorite Color" required={false} />
|
|
215
|
+
<div style="display: flex; gap: 1rem; margin-top: 0.5rem;">
|
|
216
|
+
<Radio
|
|
217
|
+
checked={Computed.make(() => Signal.get(selectedColor) == "blue")}
|
|
218
|
+
onChange={handleColorChange}
|
|
219
|
+
value="blue"
|
|
220
|
+
label="Blue"
|
|
221
|
+
name="radio"
|
|
222
|
+
/>
|
|
223
|
+
<Radio
|
|
224
|
+
checked={Computed.make(() => Signal.get(selectedColor) == "green")}
|
|
225
|
+
onChange={handleColorChange}
|
|
226
|
+
value="green"
|
|
227
|
+
label="Green"
|
|
228
|
+
name="radio"
|
|
229
|
+
/>
|
|
230
|
+
<Radio
|
|
231
|
+
checked={Computed.make(() => Signal.get(selectedColor) == "red")}
|
|
232
|
+
onChange={handleColorChange}
|
|
233
|
+
value="red"
|
|
234
|
+
label="Red"
|
|
235
|
+
name="radio"
|
|
236
|
+
/>
|
|
237
|
+
</div>
|
|
238
|
+
</Card>
|
|
239
|
+
<br />
|
|
240
|
+
<Card>
|
|
241
|
+
<Label text="Message" required={false} />
|
|
242
|
+
<Textarea
|
|
243
|
+
value={Reactive(message)}
|
|
244
|
+
onInput={handleMessageChange}
|
|
245
|
+
placeholder="Tell us more about yourself..."
|
|
246
|
+
/>
|
|
247
|
+
</Card>
|
|
248
|
+
<br />
|
|
249
|
+
<Card>
|
|
250
|
+
<div style="margin-bottom: 1.5rem;">
|
|
251
|
+
<Checkbox
|
|
252
|
+
checked={agreeToTerms}
|
|
253
|
+
onChange={handleTermsChange}
|
|
254
|
+
label="I agree to the terms and conditions"
|
|
255
|
+
/>
|
|
256
|
+
</div>
|
|
257
|
+
|
|
258
|
+
<div style="margin-bottom: 2rem;">
|
|
259
|
+
<Checkbox
|
|
260
|
+
checked={newsletter}
|
|
261
|
+
onChange={handleNewsletterChange}
|
|
262
|
+
label="Subscribe to our newsletter"
|
|
263
|
+
/>
|
|
264
|
+
</div>
|
|
265
|
+
|
|
266
|
+
<div style="display: flex; gap: 1rem; flex-wrap: wrap;">
|
|
267
|
+
{Component.SignalFragment(
|
|
268
|
+
Computed.make(() => {
|
|
269
|
+
[
|
|
270
|
+
<Button
|
|
271
|
+
label={Signal.get(isSubmitting) ? Static("Submitting...") : Static("Submit Form")}
|
|
272
|
+
onClick={handleSubmit}
|
|
273
|
+
variant={Button.Primary}
|
|
274
|
+
disabled={isSubmitting->ReactiveProp.Reactive}
|
|
275
|
+
/>,
|
|
276
|
+
]
|
|
277
|
+
}),
|
|
278
|
+
)}
|
|
279
|
+
<Button
|
|
280
|
+
label={Static("reset")}
|
|
281
|
+
onClick={handleReset}
|
|
282
|
+
variant={Button.Secondary}
|
|
283
|
+
disabled={isSubmitting->ReactiveProp.Reactive}
|
|
284
|
+
/>
|
|
285
|
+
<Button
|
|
286
|
+
label={Static("Cancel")}
|
|
287
|
+
variant={Button.Ghost}
|
|
288
|
+
disabled={isSubmitting->ReactiveProp.Reactive}
|
|
289
|
+
/>
|
|
290
|
+
</div>
|
|
291
|
+
</Card>
|
|
292
|
+
|
|
293
|
+
<div style="margin-top: 2rem;">
|
|
294
|
+
<Typography text={ReactiveProp.Static("Alerts")} variant={Typography.H4} />
|
|
295
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
296
|
+
{Component.text("Display important messages with different severity levels.")}
|
|
297
|
+
</p>
|
|
298
|
+
<div style="display: flex; flex-direction: column; gap: 1rem;">
|
|
299
|
+
<Alert
|
|
300
|
+
title="Information"
|
|
301
|
+
message={Signal.make("This is an informational alert message.")}
|
|
302
|
+
variant={Alert.Info}
|
|
303
|
+
/>
|
|
304
|
+
<Alert
|
|
305
|
+
title="Success"
|
|
306
|
+
message={Signal.make("Your changes have been saved successfully!")}
|
|
307
|
+
variant={Alert.Success}
|
|
308
|
+
/>
|
|
309
|
+
<Alert
|
|
310
|
+
title="Warning"
|
|
311
|
+
message={Signal.make("Please review your input before proceeding.")}
|
|
312
|
+
variant={Alert.Warning}
|
|
313
|
+
/>
|
|
314
|
+
<Alert
|
|
315
|
+
title="Error"
|
|
316
|
+
message={Signal.make("An error occurred while processing your request.")}
|
|
317
|
+
variant={Alert.Error}
|
|
318
|
+
/>
|
|
319
|
+
<Alert
|
|
320
|
+
message={Signal.make("This is a dismissible alert. Click the X to close it.")}
|
|
321
|
+
variant={Alert.Info}
|
|
322
|
+
dismissible={true}
|
|
323
|
+
/>
|
|
324
|
+
</div>
|
|
325
|
+
</div>
|
|
326
|
+
|
|
327
|
+
<div style="margin-top: 2rem;">
|
|
328
|
+
<Typography text={ReactiveProp.Static("Progress")} variant={Typography.H4} />
|
|
329
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
330
|
+
{Component.text("Show progress indicators for ongoing operations.")}
|
|
331
|
+
</p>
|
|
332
|
+
<div style="display: flex; flex-direction: column; gap: 2rem;">
|
|
333
|
+
<div>
|
|
334
|
+
<Progress value={Signal.make(25.0)} variant={Progress.Primary} showLabel={true} />
|
|
335
|
+
</div>
|
|
336
|
+
<div>
|
|
337
|
+
<Progress
|
|
338
|
+
value={Signal.make(50.0)} variant={Progress.Success} showLabel={true} label="Upload"
|
|
339
|
+
/>
|
|
340
|
+
</div>
|
|
341
|
+
<div>
|
|
342
|
+
<Progress
|
|
343
|
+
value={Signal.make(75.0)}
|
|
344
|
+
variant={Progress.Warning}
|
|
345
|
+
showLabel={true}
|
|
346
|
+
label="Processing"
|
|
347
|
+
/>
|
|
348
|
+
</div>
|
|
349
|
+
<div>
|
|
350
|
+
<Progress
|
|
351
|
+
value={Signal.make(100.0)}
|
|
352
|
+
variant={Progress.Success}
|
|
353
|
+
showLabel={true}
|
|
354
|
+
label="Complete"
|
|
355
|
+
/>
|
|
356
|
+
</div>
|
|
357
|
+
<div>
|
|
358
|
+
<Progress
|
|
359
|
+
value={downloadProgress}
|
|
360
|
+
variant={Progress.Primary}
|
|
361
|
+
showLabel={true}
|
|
362
|
+
label="Dynamic Progress"
|
|
363
|
+
/>
|
|
364
|
+
<Button
|
|
365
|
+
label={Static("Simulate Progress")}
|
|
366
|
+
onClick={_evt => {
|
|
367
|
+
Signal.set(downloadProgress, 0.0)
|
|
368
|
+
let intervalId = ref(None)
|
|
369
|
+
let id = setInterval(() => {
|
|
370
|
+
Signal.update(downloadProgress, prev => {
|
|
371
|
+
let next = prev +. 5.0
|
|
372
|
+
if next >= 100.0 {
|
|
373
|
+
switch intervalId.contents {
|
|
374
|
+
| Some(id) => clearInterval(id)
|
|
375
|
+
| None => ()
|
|
376
|
+
}
|
|
377
|
+
100.0
|
|
378
|
+
} else {
|
|
379
|
+
next
|
|
380
|
+
}
|
|
381
|
+
})
|
|
382
|
+
}, 100)
|
|
383
|
+
intervalId := Some(id)
|
|
384
|
+
}}
|
|
385
|
+
variant={Button.Secondary}
|
|
386
|
+
/>
|
|
387
|
+
</div>
|
|
388
|
+
<div>
|
|
389
|
+
<p style="color: #6b7280; margin-bottom: 0.5rem;">
|
|
390
|
+
{Component.text("Indeterminate progress:")}
|
|
391
|
+
</p>
|
|
392
|
+
<Progress value={Signal.make(0.0)} variant={Progress.Primary} indeterminate={true} />
|
|
393
|
+
</div>
|
|
394
|
+
</div>
|
|
395
|
+
</div>
|
|
396
|
+
|
|
397
|
+
<div style="margin-top: 2rem;">
|
|
398
|
+
<Typography text={ReactiveProp.Static("Tabs")} variant={Typography.H4} />
|
|
399
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
400
|
+
{Component.text("Organize content into tabbed sections.")}
|
|
401
|
+
</p>
|
|
402
|
+
<Tabs
|
|
403
|
+
tabs={[
|
|
404
|
+
{
|
|
405
|
+
value: "account",
|
|
406
|
+
label: "Account",
|
|
407
|
+
content: <div>
|
|
408
|
+
<Typography
|
|
409
|
+
text={ReactiveProp.Static("Account Settings")} variant={Typography.H5}
|
|
410
|
+
/>
|
|
411
|
+
<p style="color: #6b7280; margin-top: 0.5rem;">
|
|
412
|
+
{Component.text(
|
|
413
|
+
"Manage your account settings and preferences here. You can update your profile information, change your password, and configure notification settings.",
|
|
414
|
+
)}
|
|
415
|
+
</p>
|
|
416
|
+
</div>,
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
value: "security",
|
|
420
|
+
label: "Security",
|
|
421
|
+
content: <div>
|
|
422
|
+
<Typography
|
|
423
|
+
text={ReactiveProp.Static("Security Settings")} variant={Typography.H5}
|
|
424
|
+
/>
|
|
425
|
+
<p style="color: #6b7280; margin-top: 0.5rem;">
|
|
426
|
+
{Component.text(
|
|
427
|
+
"Configure your security preferences including two-factor authentication, active sessions, and security logs.",
|
|
428
|
+
)}
|
|
429
|
+
</p>
|
|
430
|
+
<div style="margin-top: 1rem;">
|
|
431
|
+
<Checkbox
|
|
432
|
+
checked={Signal.make(true)}
|
|
433
|
+
onChange={_ => ()}
|
|
434
|
+
label="Enable two-factor authentication"
|
|
435
|
+
/>
|
|
436
|
+
</div>
|
|
437
|
+
</div>,
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
value: "notifications",
|
|
441
|
+
label: "Notifications",
|
|
442
|
+
content: <div>
|
|
443
|
+
<Typography
|
|
444
|
+
text={ReactiveProp.Static("Notification Preferences")} variant={Typography.H5}
|
|
445
|
+
/>
|
|
446
|
+
<p style="color: #6b7280; margin-top: 0.5rem;">
|
|
447
|
+
{Component.text("Choose how you want to receive notifications.")}
|
|
448
|
+
</p>
|
|
449
|
+
<div style="display: flex; flex-direction: column; gap: 0.75rem; margin-top: 1rem;">
|
|
450
|
+
<Checkbox
|
|
451
|
+
checked={Signal.make(true)} onChange={_ => ()} label="Email notifications"
|
|
452
|
+
/>
|
|
453
|
+
<Checkbox
|
|
454
|
+
checked={Signal.make(false)} onChange={_ => ()} label="SMS notifications"
|
|
455
|
+
/>
|
|
456
|
+
<Checkbox
|
|
457
|
+
checked={Signal.make(true)} onChange={_ => ()} label="Push notifications"
|
|
458
|
+
/>
|
|
459
|
+
</div>
|
|
460
|
+
</div>,
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
value: "billing",
|
|
464
|
+
label: "Billing",
|
|
465
|
+
content: <div>
|
|
466
|
+
<Typography
|
|
467
|
+
text={ReactiveProp.Static("Billing Information")} variant={Typography.H5}
|
|
468
|
+
/>
|
|
469
|
+
<p style="color: #6b7280; margin-top: 0.5rem;">
|
|
470
|
+
{Component.text(
|
|
471
|
+
"View and manage your billing information, payment methods, and invoices.",
|
|
472
|
+
)}
|
|
473
|
+
</p>
|
|
474
|
+
</div>,
|
|
475
|
+
disabled: true,
|
|
476
|
+
},
|
|
477
|
+
]}
|
|
478
|
+
/>
|
|
479
|
+
</div>
|
|
480
|
+
|
|
481
|
+
<div style="margin-top: 2rem;">
|
|
482
|
+
<Typography text={ReactiveProp.Static("Accordion")} variant={Typography.H4} />
|
|
483
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
484
|
+
{Component.text("Collapsible content sections with expand/collapse functionality.")}
|
|
485
|
+
</p>
|
|
486
|
+
<Accordion
|
|
487
|
+
items={[
|
|
488
|
+
{
|
|
489
|
+
value: "faq1",
|
|
490
|
+
title: "What is basefn-UI?",
|
|
491
|
+
content: <p>
|
|
492
|
+
{Component.text(
|
|
493
|
+
"basefn-UI is a modern, reactive UI component library built with ReScript and Xote. It provides a comprehensive set of accessible and customizable components for building web applications.",
|
|
494
|
+
)}
|
|
495
|
+
</p>,
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
value: "faq2",
|
|
499
|
+
title: "How do I install basefn-UI?",
|
|
500
|
+
content: <div>
|
|
501
|
+
<p>
|
|
502
|
+
{Component.text(
|
|
503
|
+
"You can install basefn-UI via npm or yarn. Here's how to get started:",
|
|
504
|
+
)}
|
|
505
|
+
</p>
|
|
506
|
+
<br />
|
|
507
|
+
<Typography
|
|
508
|
+
text={ReactiveProp.Static("npm install basefn-ui")} variant={Typography.Code}
|
|
509
|
+
/>
|
|
510
|
+
</div>,
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
value: "faq3",
|
|
514
|
+
title: "Is basefn-UI customizable?",
|
|
515
|
+
content: <p>
|
|
516
|
+
{Component.text(
|
|
517
|
+
"Yes! basefn-UI is fully customizable. You can override the default styles using CSS variables or by providing custom CSS classes. Each component accepts standard HTML attributes including className and style.",
|
|
518
|
+
)}
|
|
519
|
+
</p>,
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
value: "faq4",
|
|
523
|
+
title: "Does basefn-UI support TypeScript?",
|
|
524
|
+
content: <p>
|
|
525
|
+
{Component.text(
|
|
526
|
+
"basefn-UI is built with ReScript, which provides excellent type safety. While it doesn't directly use TypeScript, ReScript's type system is even more robust and catches errors at compile time.",
|
|
527
|
+
)}
|
|
528
|
+
</p>,
|
|
529
|
+
},
|
|
530
|
+
]}
|
|
531
|
+
multiple={true}
|
|
532
|
+
defaultOpen={["faq1"]}
|
|
533
|
+
/>
|
|
534
|
+
</div>
|
|
535
|
+
|
|
536
|
+
<div style="margin-top: 2rem;">
|
|
537
|
+
<Typography text={ReactiveProp.Static("Breadcrumb")} variant={Typography.H4} />
|
|
538
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
539
|
+
{Component.text("Navigation breadcrumbs to show the current page hierarchy.")}
|
|
540
|
+
</p>
|
|
541
|
+
<div style="display: flex; flex-direction: column; gap: 1.5rem;">
|
|
542
|
+
<div>
|
|
543
|
+
<p style="color: #6b7280; margin-bottom: 0.5rem; font-size: 0.875rem;">
|
|
544
|
+
{Component.text("Default separator:")}
|
|
545
|
+
</p>
|
|
546
|
+
<Breadcrumb
|
|
547
|
+
items={[
|
|
548
|
+
{label: "Home", href: Some("#"), onClick: None},
|
|
549
|
+
{label: "Products", href: Some("#"), onClick: None},
|
|
550
|
+
{label: "Electronics", href: Some("#"), onClick: None},
|
|
551
|
+
{label: "Laptops", href: None, onClick: None},
|
|
552
|
+
]}
|
|
553
|
+
/>
|
|
554
|
+
</div>
|
|
555
|
+
<div>
|
|
556
|
+
<p style="color: #6b7280; margin-bottom: 0.5rem; font-size: 0.875rem;">
|
|
557
|
+
{Component.text("Custom separator:")}
|
|
558
|
+
</p>
|
|
559
|
+
<Breadcrumb
|
|
560
|
+
items={[
|
|
561
|
+
{label: "Home", href: Some("#"), onClick: None},
|
|
562
|
+
{label: "Settings", href: Some("#"), onClick: None},
|
|
563
|
+
{label: "Account", href: None, onClick: None},
|
|
564
|
+
]}
|
|
565
|
+
separator=">"
|
|
566
|
+
/>
|
|
567
|
+
</div>
|
|
568
|
+
<div>
|
|
569
|
+
<p style="color: #6b7280; margin-bottom: 0.5rem; font-size: 0.875rem;">
|
|
570
|
+
{Component.text("With onClick handlers:")}
|
|
571
|
+
</p>
|
|
572
|
+
<Breadcrumb
|
|
573
|
+
items={[
|
|
574
|
+
{
|
|
575
|
+
label: "Dashboard",
|
|
576
|
+
href: None,
|
|
577
|
+
onClick: Some(() => Console.log("Navigate to Dashboard")),
|
|
578
|
+
},
|
|
579
|
+
{
|
|
580
|
+
label: "Users",
|
|
581
|
+
href: None,
|
|
582
|
+
onClick: Some(() => Console.log("Navigate to Users")),
|
|
583
|
+
},
|
|
584
|
+
{label: "Profile", href: None, onClick: None},
|
|
585
|
+
]}
|
|
586
|
+
separator="\u2022"
|
|
587
|
+
/>
|
|
588
|
+
</div>
|
|
589
|
+
</div>
|
|
590
|
+
</div>
|
|
591
|
+
|
|
592
|
+
<Separator orientation={Separator.Horizontal} variant={Separator.Solid} label={"Tier 3"} />
|
|
593
|
+
|
|
594
|
+
<div style="margin-top: 3rem;">
|
|
595
|
+
<Typography
|
|
596
|
+
text={ReactiveProp.Static("Interactive Components")}
|
|
597
|
+
variant={Typography.H2}
|
|
598
|
+
align={Typography.Left}
|
|
599
|
+
/>
|
|
600
|
+
<Typography
|
|
601
|
+
text={ReactiveProp.Static("Explore the Tier 3 advanced interactive components below.")}
|
|
602
|
+
variant={Typography.Muted}
|
|
603
|
+
/>
|
|
604
|
+
</div>
|
|
605
|
+
|
|
606
|
+
// Modal Section
|
|
607
|
+
<div style="margin-top: 2rem;">
|
|
608
|
+
<Typography text={ReactiveProp.Static("Modal / Dialog")} variant={Typography.H4} />
|
|
609
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
610
|
+
{Component.text("Display content in an overlay dialog.")}
|
|
611
|
+
</p>
|
|
612
|
+
<Button
|
|
613
|
+
label={Static("Open Modal")}
|
|
614
|
+
onClick={_ => Signal.set(isModalOpen, true)}
|
|
615
|
+
variant={Button.Primary}
|
|
616
|
+
/>
|
|
617
|
+
<Modal
|
|
618
|
+
isOpen={isModalOpen}
|
|
619
|
+
onClose={() => Signal.set(isModalOpen, false)}
|
|
620
|
+
title="Example Modal"
|
|
621
|
+
size={Modal.Md}
|
|
622
|
+
footer={<div style="display: flex; gap: 0.5rem;">
|
|
623
|
+
<Button
|
|
624
|
+
label={Static("Cancel")}
|
|
625
|
+
onClick={_ => Signal.set(isModalOpen, false)}
|
|
626
|
+
variant={Button.Ghost}
|
|
627
|
+
/>
|
|
628
|
+
<Button
|
|
629
|
+
label={Static("Confirm")}
|
|
630
|
+
onClick={_ => {
|
|
631
|
+
Console.log("Confirmed!")
|
|
632
|
+
Signal.set(isModalOpen, false)
|
|
633
|
+
}}
|
|
634
|
+
variant={Button.Primary}
|
|
635
|
+
/>
|
|
636
|
+
</div>}
|
|
637
|
+
>
|
|
638
|
+
<p>
|
|
639
|
+
{Component.text(
|
|
640
|
+
"This is a modal dialog. You can include any content here. Click the backdrop or the close button to dismiss.",
|
|
641
|
+
)}
|
|
642
|
+
</p>
|
|
643
|
+
<p style="margin-top: 1rem;">
|
|
644
|
+
{Component.text("Modals are great for focused user interactions and confirmations.")}
|
|
645
|
+
</p>
|
|
646
|
+
</Modal>
|
|
647
|
+
</div>
|
|
648
|
+
|
|
649
|
+
// Switch Section
|
|
650
|
+
<div style="margin-top: 2rem;">
|
|
651
|
+
<Typography text={ReactiveProp.Static("Switch / Toggle")} variant={Typography.H4} />
|
|
652
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
653
|
+
{Component.text("Binary on/off switches for settings and preferences.")}
|
|
654
|
+
</p>
|
|
655
|
+
<div style="display: flex; flex-direction: column; gap: 1rem;">
|
|
656
|
+
<Switch checked={switchEnabled} label="Enable feature" />
|
|
657
|
+
<Switch checked={darkModeSwitch} label="Dark mode" size={Switch.Lg} />
|
|
658
|
+
<Switch checked={notificationsSwitch} label="Push notifications" size={Switch.Sm} />
|
|
659
|
+
<Switch
|
|
660
|
+
checked={Signal.make(true)} label="Disabled switch" disabled={true} size={Switch.Md}
|
|
661
|
+
/>
|
|
662
|
+
</div>
|
|
663
|
+
</div>
|
|
664
|
+
|
|
665
|
+
// Slider Section
|
|
666
|
+
<div style="margin-top: 2rem;">
|
|
667
|
+
<Typography text={ReactiveProp.Static("Slider")} variant={Typography.H4} />
|
|
668
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
669
|
+
{Component.text("Select a value from a range.")}
|
|
670
|
+
</p>
|
|
671
|
+
<div style="display: flex; flex-direction: column; gap: 2rem;">
|
|
672
|
+
<Slider value={sliderValue} label="Volume" showValue={true} />
|
|
673
|
+
<Slider
|
|
674
|
+
value={Signal.make(25.0)}
|
|
675
|
+
label="Brightness"
|
|
676
|
+
min={0.0}
|
|
677
|
+
max={100.0}
|
|
678
|
+
step={5.0}
|
|
679
|
+
showValue={true}
|
|
680
|
+
/>
|
|
681
|
+
<Slider
|
|
682
|
+
value={Signal.make(3.0)}
|
|
683
|
+
min={0.0}
|
|
684
|
+
max={5.0}
|
|
685
|
+
step={1.0}
|
|
686
|
+
label="Rating"
|
|
687
|
+
showValue={true}
|
|
688
|
+
markers={["0", "1", "2", "3", "4", "5"]}
|
|
689
|
+
/>
|
|
690
|
+
</div>
|
|
691
|
+
</div>
|
|
692
|
+
|
|
693
|
+
// Tooltip Section
|
|
694
|
+
<div style="margin-top: 2rem;">
|
|
695
|
+
<Typography text={ReactiveProp.Static("Tooltip")} variant={Typography.H4} />
|
|
696
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
697
|
+
{Component.text("Show contextual information on hover.")}
|
|
698
|
+
</p>
|
|
699
|
+
<div style="display: flex; gap: 1rem; flex-wrap: wrap;">
|
|
700
|
+
<Tooltip content="This appears on top" position={Tooltip.Top}>
|
|
701
|
+
<Button label={Static("Hover me )(top)")} variant={Button.Secondary} />
|
|
702
|
+
</Tooltip>
|
|
703
|
+
<Tooltip content="This appears on bottom" position={Tooltip.Bottom}>
|
|
704
|
+
<Button label={Static("Hover me )(bottom)")} variant={Button.Secondary} />
|
|
705
|
+
</Tooltip>
|
|
706
|
+
<Tooltip content="This appears on left" position={Tooltip.Left}>
|
|
707
|
+
<Button label={Static("Hover me )(left)")} variant={Button.Secondary} />
|
|
708
|
+
</Tooltip>
|
|
709
|
+
<Tooltip content="This appears on right" position={Tooltip.Right}>
|
|
710
|
+
<Button label={Static("Hover me )(right)")} variant={Button.Secondary} />
|
|
711
|
+
</Tooltip>
|
|
712
|
+
</div>
|
|
713
|
+
</div>
|
|
714
|
+
|
|
715
|
+
// Dropdown Section
|
|
716
|
+
<div style="margin-top: 2rem;">
|
|
717
|
+
<Typography text={ReactiveProp.Static("Dropdown Menu")} variant={Typography.H4} />
|
|
718
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
719
|
+
{Component.text("Contextual menu with actions.")}
|
|
720
|
+
</p>
|
|
721
|
+
<div style="display: flex; gap: 1rem;">
|
|
722
|
+
<Dropdown
|
|
723
|
+
trigger={<Button label={Static("Actions")} variant={Button.Secondary} />}
|
|
724
|
+
items={[
|
|
725
|
+
Dropdown.Item({
|
|
726
|
+
label: "Edit",
|
|
727
|
+
onClick: () => Console.log("Edit clicked"),
|
|
728
|
+
}),
|
|
729
|
+
Dropdown.Item({
|
|
730
|
+
label: "Duplicate",
|
|
731
|
+
onClick: () => Console.log("Duplicate clicked"),
|
|
732
|
+
}),
|
|
733
|
+
Dropdown.Separator,
|
|
734
|
+
Dropdown.Item({
|
|
735
|
+
label: "Archive",
|
|
736
|
+
onClick: () => Console.log("Archive clicked"),
|
|
737
|
+
}),
|
|
738
|
+
Dropdown.Item({
|
|
739
|
+
label: "Delete",
|
|
740
|
+
onClick: () => Console.log("Delete clicked"),
|
|
741
|
+
danger: true,
|
|
742
|
+
}),
|
|
743
|
+
]}
|
|
744
|
+
/>
|
|
745
|
+
<Dropdown
|
|
746
|
+
trigger={<Button label={Static("More options")} variant={Button.Ghost} />}
|
|
747
|
+
items={[
|
|
748
|
+
Dropdown.Item({
|
|
749
|
+
label: "Settings",
|
|
750
|
+
onClick: () => Console.log("Settings"),
|
|
751
|
+
}),
|
|
752
|
+
Dropdown.Item({
|
|
753
|
+
label: "Help",
|
|
754
|
+
onClick: () => Console.log("Help"),
|
|
755
|
+
}),
|
|
756
|
+
Dropdown.Separator,
|
|
757
|
+
Dropdown.Item({
|
|
758
|
+
label: "Disabled item",
|
|
759
|
+
onClick: () => Console.log("Should not fire"),
|
|
760
|
+
disabled: true,
|
|
761
|
+
}),
|
|
762
|
+
]}
|
|
763
|
+
align=#right
|
|
764
|
+
/>
|
|
765
|
+
</div>
|
|
766
|
+
</div>
|
|
767
|
+
|
|
768
|
+
// Toast Section
|
|
769
|
+
<div style="margin-top: 2rem;">
|
|
770
|
+
<Typography text={ReactiveProp.Static("Toast / Notification")} variant={Typography.H4} />
|
|
771
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
772
|
+
{Component.text("Temporary notification messages.")}
|
|
773
|
+
</p>
|
|
774
|
+
<div style="display: flex; gap: 0.75rem; flex-wrap: wrap;">
|
|
775
|
+
<Button
|
|
776
|
+
label={Static("Show Toast")}
|
|
777
|
+
onClick={_ => Signal.set(toastVisible, true)}
|
|
778
|
+
variant={Button.Primary}
|
|
779
|
+
/>
|
|
780
|
+
</div>
|
|
781
|
+
<Toast
|
|
782
|
+
title="Success!"
|
|
783
|
+
message="Your changes have been saved successfully."
|
|
784
|
+
variant={Toast.Success}
|
|
785
|
+
isVisible={toastVisible}
|
|
786
|
+
onClose={() => Console.log("Toast closed")}
|
|
787
|
+
/>
|
|
788
|
+
</div>
|
|
789
|
+
|
|
790
|
+
<Separator orientation={Separator.Horizontal} variant={Separator.Solid} label={"Tier 4"} />
|
|
791
|
+
|
|
792
|
+
<div style="margin-top: 3rem;">
|
|
793
|
+
<Typography
|
|
794
|
+
text={ReactiveProp.Static("Navigation & Layout")}
|
|
795
|
+
variant={Typography.H2}
|
|
796
|
+
align={Typography.Left}
|
|
797
|
+
/>
|
|
798
|
+
<Typography
|
|
799
|
+
text={ReactiveProp.Static("Explore the Tier 4 navigation and layout components below.")}
|
|
800
|
+
variant={Typography.Muted}
|
|
801
|
+
/>
|
|
802
|
+
</div>
|
|
803
|
+
|
|
804
|
+
// Stepper Section
|
|
805
|
+
<div style="margin-top: 2rem;">
|
|
806
|
+
<Typography text={ReactiveProp.Static("Stepper")} variant={Typography.H4} />
|
|
807
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
808
|
+
{Component.text("Multi-step process indicator with progress tracking.")}
|
|
809
|
+
</p>
|
|
810
|
+
<div style="display: flex; flex-direction: column; gap: 2rem;">
|
|
811
|
+
<div>
|
|
812
|
+
<p style="color: #6b7280; margin-bottom: 1rem; font-size: 0.875rem;">
|
|
813
|
+
{Component.text("Horizontal stepper:")}
|
|
814
|
+
</p>
|
|
815
|
+
<Stepper
|
|
816
|
+
steps={[
|
|
817
|
+
{
|
|
818
|
+
title: "Account Info",
|
|
819
|
+
description: Some("Enter your details"),
|
|
820
|
+
status: Stepper.Completed,
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
title: "Verification",
|
|
824
|
+
description: Some("Verify your email"),
|
|
825
|
+
status: Stepper.Active,
|
|
826
|
+
},
|
|
827
|
+
{
|
|
828
|
+
title: "Preferences",
|
|
829
|
+
description: Some("Set your preferences"),
|
|
830
|
+
status: Stepper.Inactive,
|
|
831
|
+
},
|
|
832
|
+
{
|
|
833
|
+
title: "Complete",
|
|
834
|
+
description: Some("All done!"),
|
|
835
|
+
status: Stepper.Inactive,
|
|
836
|
+
},
|
|
837
|
+
]}
|
|
838
|
+
currentStep={currentStep}
|
|
839
|
+
orientation={Stepper.Horizontal}
|
|
840
|
+
onStepClick={step => {
|
|
841
|
+
Signal.set(currentStep, step)
|
|
842
|
+
Console.log2("Step clicked:", step)
|
|
843
|
+
}}
|
|
844
|
+
/>
|
|
845
|
+
</div>
|
|
846
|
+
<div>
|
|
847
|
+
<p style="color: #6b7280; margin-bottom: 1rem; font-size: 0.875rem;">
|
|
848
|
+
{Component.text("Vertical stepper:")}
|
|
849
|
+
</p>
|
|
850
|
+
<Stepper
|
|
851
|
+
steps={[
|
|
852
|
+
{
|
|
853
|
+
title: "Order Placed",
|
|
854
|
+
description: Some("Your order has been confirmed"),
|
|
855
|
+
status: Stepper.Completed,
|
|
856
|
+
},
|
|
857
|
+
{
|
|
858
|
+
title: "Processing",
|
|
859
|
+
description: Some("We are preparing your order"),
|
|
860
|
+
status: Stepper.Completed,
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
title: "Shipped",
|
|
864
|
+
description: Some("Your order is on the way"),
|
|
865
|
+
status: Stepper.Active,
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
title: "Delivered",
|
|
869
|
+
description: Some("Enjoy your purchase!"),
|
|
870
|
+
status: Stepper.Inactive,
|
|
871
|
+
},
|
|
872
|
+
]}
|
|
873
|
+
currentStep={Signal.make(2)}
|
|
874
|
+
orientation={Stepper.Vertical}
|
|
875
|
+
/>
|
|
876
|
+
</div>
|
|
877
|
+
</div>
|
|
878
|
+
</div>
|
|
879
|
+
|
|
880
|
+
// Drawer Section
|
|
881
|
+
<div style="margin-top: 2rem;">
|
|
882
|
+
<Typography text={ReactiveProp.Static("Drawer / Sidebar")} variant={Typography.H4} />
|
|
883
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
884
|
+
{Component.text("Slide-in panels for additional content.")}
|
|
885
|
+
</p>
|
|
886
|
+
<div style="display: flex; gap: 0.75rem; flex-wrap: wrap;">
|
|
887
|
+
<Button
|
|
888
|
+
label={Static("Open Drawer")}
|
|
889
|
+
onClick={_ => Signal.set(isDrawerOpen, true)}
|
|
890
|
+
variant={Button.Primary}
|
|
891
|
+
/>
|
|
892
|
+
</div>
|
|
893
|
+
<Drawer
|
|
894
|
+
isOpen={isDrawerOpen}
|
|
895
|
+
onClose={() => Signal.set(isDrawerOpen, false)}
|
|
896
|
+
title="Drawer Panel"
|
|
897
|
+
position={Drawer.Right}
|
|
898
|
+
size={Drawer.Md}
|
|
899
|
+
footer={<div style="display: flex; gap: 0.5rem; justify-content: flex-end;">
|
|
900
|
+
<Button
|
|
901
|
+
label={Static("Cancel")}
|
|
902
|
+
onClick={_ => Signal.set(isDrawerOpen, false)}
|
|
903
|
+
variant={Button.Ghost}
|
|
904
|
+
/>
|
|
905
|
+
<Button
|
|
906
|
+
label={Static("Save")}
|
|
907
|
+
onClick={_ => {
|
|
908
|
+
Console.log("Saved!")
|
|
909
|
+
Signal.set(isDrawerOpen, false)
|
|
910
|
+
}}
|
|
911
|
+
variant={Button.Primary}
|
|
912
|
+
/>
|
|
913
|
+
</div>}
|
|
914
|
+
>
|
|
915
|
+
<div>
|
|
916
|
+
<Typography text={ReactiveProp.Static("Drawer Content")} variant={Typography.H5} />
|
|
917
|
+
<p style="margin-top: 1rem;">
|
|
918
|
+
{Component.text(
|
|
919
|
+
"This is a drawer panel. You can use it for navigation, forms, or any additional content that doesn't fit in the main view.",
|
|
920
|
+
)}
|
|
921
|
+
</p>
|
|
922
|
+
<div style="margin-top: 1.5rem;">
|
|
923
|
+
<Label text="Name" />
|
|
924
|
+
<Input value={Static("")} type_={Input.Text} placeholder="Enter your name" />
|
|
925
|
+
</div>
|
|
926
|
+
<div style="margin-top: 1rem;">
|
|
927
|
+
<Label text="Email" />
|
|
928
|
+
<Input value={Static("")} type_={Input.Email} placeholder="Enter your email" />
|
|
929
|
+
</div>
|
|
930
|
+
<div style="margin-top: 1rem;">
|
|
931
|
+
<Label text="Message" />
|
|
932
|
+
<Textarea value={ReactiveProp.Static("")} placeholder="Enter a message" />
|
|
933
|
+
</div>
|
|
934
|
+
</div>
|
|
935
|
+
</Drawer>
|
|
936
|
+
</div>
|
|
937
|
+
|
|
938
|
+
// Timeline Section
|
|
939
|
+
<div style="margin-top: 2rem;">
|
|
940
|
+
<Typography text={ReactiveProp.Static("Timeline")} variant={Typography.H4} />
|
|
941
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
942
|
+
{Component.text("Display chronological events in a visual timeline.")}
|
|
943
|
+
</p>
|
|
944
|
+
<div style="display: flex; flex-direction: column; gap: 2rem;">
|
|
945
|
+
<div>
|
|
946
|
+
<p style="color: #6b7280; margin-bottom: 1rem; font-size: 0.875rem;">
|
|
947
|
+
{Component.text("Vertical timeline:")}
|
|
948
|
+
</p>
|
|
949
|
+
<Timeline
|
|
950
|
+
items={[
|
|
951
|
+
{
|
|
952
|
+
title: "Project Created",
|
|
953
|
+
timestamp: Some("2 hours ago"),
|
|
954
|
+
description: Some("Initial project setup and configuration"),
|
|
955
|
+
variant: Timeline.Success,
|
|
956
|
+
icon: Some("\u2713"),
|
|
957
|
+
},
|
|
958
|
+
{
|
|
959
|
+
title: "First Commit",
|
|
960
|
+
timestamp: Some("1 hour ago"),
|
|
961
|
+
description: Some("Added base components and styling"),
|
|
962
|
+
variant: Timeline.Success,
|
|
963
|
+
icon: Some("\u2713"),
|
|
964
|
+
},
|
|
965
|
+
{
|
|
966
|
+
title: "Code Review",
|
|
967
|
+
timestamp: Some("30 minutes ago"),
|
|
968
|
+
description: Some("Team reviewing the implementation"),
|
|
969
|
+
variant: Timeline.Primary,
|
|
970
|
+
icon: None,
|
|
971
|
+
},
|
|
972
|
+
{
|
|
973
|
+
title: "Deployment",
|
|
974
|
+
timestamp: Some("Pending"),
|
|
975
|
+
description: Some("Awaiting approval for production deployment"),
|
|
976
|
+
variant: Timeline.Default,
|
|
977
|
+
icon: None,
|
|
978
|
+
},
|
|
979
|
+
]}
|
|
980
|
+
orientation={Timeline.Vertical}
|
|
981
|
+
/>
|
|
982
|
+
</div>
|
|
983
|
+
<div>
|
|
984
|
+
<p style="color: #6b7280; margin-bottom: 1rem; font-size: 0.875rem;">
|
|
985
|
+
{Component.text("With different variants:")}
|
|
986
|
+
</p>
|
|
987
|
+
<Timeline
|
|
988
|
+
items={[
|
|
989
|
+
{
|
|
990
|
+
title: "Success Event",
|
|
991
|
+
timestamp: None,
|
|
992
|
+
description: Some("Operation completed successfully"),
|
|
993
|
+
variant: Timeline.Success,
|
|
994
|
+
icon: Some("\u2713"),
|
|
995
|
+
},
|
|
996
|
+
{
|
|
997
|
+
title: "Warning Event",
|
|
998
|
+
timestamp: None,
|
|
999
|
+
description: Some("Requires attention"),
|
|
1000
|
+
variant: Timeline.Warning,
|
|
1001
|
+
icon: Some("!"),
|
|
1002
|
+
},
|
|
1003
|
+
{
|
|
1004
|
+
title: "Error Event",
|
|
1005
|
+
timestamp: None,
|
|
1006
|
+
description: Some("Operation failed"),
|
|
1007
|
+
variant: Timeline.Error,
|
|
1008
|
+
icon: Some("\u00d7"),
|
|
1009
|
+
},
|
|
1010
|
+
]}
|
|
1011
|
+
orientation={Timeline.Vertical}
|
|
1012
|
+
/>
|
|
1013
|
+
</div>
|
|
1014
|
+
</div>
|
|
1015
|
+
</div>
|
|
1016
|
+
|
|
1017
|
+
<Separator
|
|
1018
|
+
orientation={Separator.Horizontal} variant={Separator.Solid} label={"App Layouts"}
|
|
1019
|
+
/>
|
|
1020
|
+
|
|
1021
|
+
<div style="margin-top: 3rem;">
|
|
1022
|
+
<Typography
|
|
1023
|
+
text={ReactiveProp.Static("Application Layouts")}
|
|
1024
|
+
variant={Typography.H2}
|
|
1025
|
+
align={Typography.Left}
|
|
1026
|
+
/>
|
|
1027
|
+
<Typography
|
|
1028
|
+
text={ReactiveProp.Static(
|
|
1029
|
+
"Complete application layout structures with sidebar and topbar combinations.",
|
|
1030
|
+
)}
|
|
1031
|
+
variant={Typography.Muted}
|
|
1032
|
+
/>
|
|
1033
|
+
</div>
|
|
1034
|
+
|
|
1035
|
+
// Layout Examples Section
|
|
1036
|
+
<div style="margin-top: 2rem;">
|
|
1037
|
+
<Typography text={ReactiveProp.Static("Layout Variants")} variant={Typography.H4} />
|
|
1038
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
1039
|
+
{Component.text("Different application layout configurations.")}
|
|
1040
|
+
</p>
|
|
1041
|
+
<div style="display: flex; flex-direction: column; gap: 2rem;">
|
|
1042
|
+
// Sidebar Only Example
|
|
1043
|
+
<div>
|
|
1044
|
+
<Typography text={ReactiveProp.Static("Sidebar Only Layout")} variant={Typography.H5} />
|
|
1045
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0; font-size: 0.875rem;">
|
|
1046
|
+
{Component.text("Application with sidebar navigation")}
|
|
1047
|
+
</p>
|
|
1048
|
+
<div
|
|
1049
|
+
style="border: 2px solid #e5e7eb; border-radius: 0.5rem; overflow: hidden; height: 400px;"
|
|
1050
|
+
>
|
|
1051
|
+
<AppLayout
|
|
1052
|
+
sidebar={<Sidebar
|
|
1053
|
+
logo={Component.text("eita UI")}
|
|
1054
|
+
sections={[
|
|
1055
|
+
{
|
|
1056
|
+
title: Some("Main"),
|
|
1057
|
+
items: [
|
|
1058
|
+
{
|
|
1059
|
+
label: "Dashboard",
|
|
1060
|
+
icon: Some("\u2302"),
|
|
1061
|
+
active: Signal.get(activeNavItem) == "home",
|
|
1062
|
+
url: "/profile",
|
|
1063
|
+
},
|
|
1064
|
+
{
|
|
1065
|
+
label: "Analytics",
|
|
1066
|
+
icon: Some("\u{1F4CA}"),
|
|
1067
|
+
active: Signal.get(activeNavItem) == "analytics",
|
|
1068
|
+
url: "/profile",
|
|
1069
|
+
},
|
|
1070
|
+
],
|
|
1071
|
+
},
|
|
1072
|
+
{
|
|
1073
|
+
title: Some("Settings"),
|
|
1074
|
+
items: [
|
|
1075
|
+
{
|
|
1076
|
+
label: "Profile",
|
|
1077
|
+
icon: Some("\u{1F464}"),
|
|
1078
|
+
active: Signal.get(activeNavItem) == "profile",
|
|
1079
|
+
url: "/profile",
|
|
1080
|
+
},
|
|
1081
|
+
{
|
|
1082
|
+
label: "Settings",
|
|
1083
|
+
icon: Some("\u2699"),
|
|
1084
|
+
active: Signal.get(activeNavItem) == "settings",
|
|
1085
|
+
url: "/profile",
|
|
1086
|
+
},
|
|
1087
|
+
],
|
|
1088
|
+
},
|
|
1089
|
+
]}
|
|
1090
|
+
size={Sidebar.Md}
|
|
1091
|
+
/>}
|
|
1092
|
+
>
|
|
1093
|
+
<div style="padding: 2rem;">
|
|
1094
|
+
<Typography
|
|
1095
|
+
text={ReactiveProp.Static("Main Content Area")} variant={Typography.H3}
|
|
1096
|
+
/>
|
|
1097
|
+
<p style="margin-top: 1rem;">
|
|
1098
|
+
{Component.text(
|
|
1099
|
+
"This is the main content area. The sidebar provides persistent navigation.",
|
|
1100
|
+
)}
|
|
1101
|
+
</p>
|
|
1102
|
+
</div>
|
|
1103
|
+
</AppLayout>
|
|
1104
|
+
</div>
|
|
1105
|
+
</div>
|
|
1106
|
+
|
|
1107
|
+
// Topbar Only Example
|
|
1108
|
+
<div>
|
|
1109
|
+
<Typography text={ReactiveProp.Static("Topbar Only Layout")} variant={Typography.H5} />
|
|
1110
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0; font-size: 0.875rem;">
|
|
1111
|
+
{Component.text("Application with top navigation bar")}
|
|
1112
|
+
</p>
|
|
1113
|
+
<div
|
|
1114
|
+
style="border: 2px solid #e5e7eb; border-radius: 0.5rem; overflow: hidden; height: 300px;"
|
|
1115
|
+
>
|
|
1116
|
+
<AppLayout
|
|
1117
|
+
topbar={<Topbar
|
|
1118
|
+
logo={Component.text("eita UI")}
|
|
1119
|
+
navItems={[
|
|
1120
|
+
{
|
|
1121
|
+
label: "Home",
|
|
1122
|
+
active: Signal.get(activeNavItem) == "home",
|
|
1123
|
+
onClick: () => Signal.set(activeNavItem, "home"),
|
|
1124
|
+
},
|
|
1125
|
+
{
|
|
1126
|
+
label: "Products",
|
|
1127
|
+
active: Signal.get(activeNavItem) == "products",
|
|
1128
|
+
onClick: () => Signal.set(activeNavItem, "products"),
|
|
1129
|
+
},
|
|
1130
|
+
{
|
|
1131
|
+
label: "About",
|
|
1132
|
+
active: Signal.get(activeNavItem) == "about",
|
|
1133
|
+
onClick: () => Signal.set(activeNavItem, "about"),
|
|
1134
|
+
},
|
|
1135
|
+
]}
|
|
1136
|
+
rightContent={<div style="display: flex; gap: 0.5rem;">
|
|
1137
|
+
<Button label={Static("Sign In")} variant={Button.Ghost} />
|
|
1138
|
+
<Button label={Static("Sign Up")} variant={Button.Primary} />
|
|
1139
|
+
</div>}
|
|
1140
|
+
/>}
|
|
1141
|
+
>
|
|
1142
|
+
<div style="padding: 2rem;">
|
|
1143
|
+
<Typography
|
|
1144
|
+
text={ReactiveProp.Static("Main Content Area")} variant={Typography.H3}
|
|
1145
|
+
/>
|
|
1146
|
+
<p style="margin-top: 1rem;">
|
|
1147
|
+
{Component.text("This layout uses only a top navigation bar.")}
|
|
1148
|
+
</p>
|
|
1149
|
+
</div>
|
|
1150
|
+
</AppLayout>
|
|
1151
|
+
</div>
|
|
1152
|
+
</div>
|
|
1153
|
+
|
|
1154
|
+
// Sidebar + Topbar Example
|
|
1155
|
+
<div>
|
|
1156
|
+
<Typography
|
|
1157
|
+
text={ReactiveProp.Static("Sidebar + Topbar Layout")} variant={Typography.H5}
|
|
1158
|
+
/>
|
|
1159
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0; font-size: 0.875rem;">
|
|
1160
|
+
{Component.text("Full application layout with both sidebar and topbar")}
|
|
1161
|
+
</p>
|
|
1162
|
+
<div
|
|
1163
|
+
style="border: 2px solid #e5e7eb; border-radius: 0.5rem; overflow: hidden; height: 500px;"
|
|
1164
|
+
>
|
|
1165
|
+
<AppLayout
|
|
1166
|
+
sidebar={<Sidebar
|
|
1167
|
+
logo={Component.text("basefn")}
|
|
1168
|
+
sections={[
|
|
1169
|
+
{
|
|
1170
|
+
title: Some("Navigation"),
|
|
1171
|
+
items: [
|
|
1172
|
+
{
|
|
1173
|
+
label: "Dashboard",
|
|
1174
|
+
icon: Some("\u2302"),
|
|
1175
|
+
active: true,
|
|
1176
|
+
url: "/",
|
|
1177
|
+
},
|
|
1178
|
+
{
|
|
1179
|
+
label: "Projects",
|
|
1180
|
+
icon: Some("\u{1F4C1}"),
|
|
1181
|
+
active: false,
|
|
1182
|
+
url: "/",
|
|
1183
|
+
},
|
|
1184
|
+
{
|
|
1185
|
+
label: "Tasks",
|
|
1186
|
+
icon: Some("\u2713"),
|
|
1187
|
+
active: false,
|
|
1188
|
+
url: "/",
|
|
1189
|
+
},
|
|
1190
|
+
],
|
|
1191
|
+
},
|
|
1192
|
+
]}
|
|
1193
|
+
size={Sidebar.Md}
|
|
1194
|
+
collapsed={Signal.get(sidebarCollapsed)}
|
|
1195
|
+
/>}
|
|
1196
|
+
topbar={<Topbar
|
|
1197
|
+
onMenuClick={() => Signal.update(sidebarCollapsed, prev => !prev)}
|
|
1198
|
+
rightContent={<div style="display: flex; align-items: center; gap: 1rem;">
|
|
1199
|
+
<Badge label={Signal.make("3")} variant={Badge.Primary} />
|
|
1200
|
+
<Avatar src="https://ui-avatars.com/api/?name=John+Doe" size={Avatar.Sm} />
|
|
1201
|
+
</div>}
|
|
1202
|
+
/>}
|
|
1203
|
+
sidebarSize={"md"}
|
|
1204
|
+
sidebarCollapsed={Signal.get(sidebarCollapsed)}
|
|
1205
|
+
>
|
|
1206
|
+
<div style="padding: 2rem;">
|
|
1207
|
+
<Typography text={ReactiveProp.Static("Dashboard")} variant={Typography.H3} />
|
|
1208
|
+
<p style="margin-top: 1rem;">
|
|
1209
|
+
{Component.text(
|
|
1210
|
+
"This is a complete application layout with both sidebar and topbar. Click the menu button in the topbar to toggle the sidebar.",
|
|
1211
|
+
)}
|
|
1212
|
+
</p>
|
|
1213
|
+
<div
|
|
1214
|
+
style="margin-top: 2rem; display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem;"
|
|
1215
|
+
>
|
|
1216
|
+
<Card>
|
|
1217
|
+
<Typography
|
|
1218
|
+
text={ReactiveProp.Static("Total Users")} variant={Typography.H6}
|
|
1219
|
+
/>
|
|
1220
|
+
<Typography
|
|
1221
|
+
text={ReactiveProp.Static("1,234")}
|
|
1222
|
+
variant={Typography.H2}
|
|
1223
|
+
class="text-primary"
|
|
1224
|
+
/>
|
|
1225
|
+
</Card>
|
|
1226
|
+
<Card>
|
|
1227
|
+
<Typography
|
|
1228
|
+
text={ReactiveProp.Static("Active Projects")} variant={Typography.H6}
|
|
1229
|
+
/>
|
|
1230
|
+
<Typography text={ReactiveProp.Static("45")} variant={Typography.H2} />
|
|
1231
|
+
</Card>
|
|
1232
|
+
<Card>
|
|
1233
|
+
<Typography
|
|
1234
|
+
text={ReactiveProp.Static("Completed Tasks")} variant={Typography.H6}
|
|
1235
|
+
/>
|
|
1236
|
+
<Typography text={ReactiveProp.Static("892")} variant={Typography.H2} />
|
|
1237
|
+
</Card>
|
|
1238
|
+
</div>
|
|
1239
|
+
</div>
|
|
1240
|
+
</AppLayout>
|
|
1241
|
+
</div>
|
|
1242
|
+
</div>
|
|
1243
|
+
</div>
|
|
1244
|
+
</div>
|
|
1245
|
+
|
|
1246
|
+
<Separator
|
|
1247
|
+
orientation={Separator.Horizontal} variant={Separator.Dashed} label={"Foundational"}
|
|
1248
|
+
/>
|
|
1249
|
+
|
|
1250
|
+
<div style="margin-top: 3rem;">
|
|
1251
|
+
<Typography
|
|
1252
|
+
text={ReactiveProp.Static("Foundation Components")}
|
|
1253
|
+
variant={Typography.H2}
|
|
1254
|
+
align={Typography.Left}
|
|
1255
|
+
/>
|
|
1256
|
+
<Typography
|
|
1257
|
+
text={ReactiveProp.Static("Explore the Tier 1 foundation components below.")}
|
|
1258
|
+
variant={Typography.Muted}
|
|
1259
|
+
/>
|
|
1260
|
+
</div>
|
|
1261
|
+
|
|
1262
|
+
// Badges Section
|
|
1263
|
+
<div style="margin-top: 2rem;">
|
|
1264
|
+
<Typography text={ReactiveProp.Static("Badges")} variant={Typography.H4} />
|
|
1265
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
1266
|
+
{Component.text("Display status indicators and labels with various styles.")}
|
|
1267
|
+
</p>
|
|
1268
|
+
<div style="display: flex; gap: 0.75rem; flex-wrap: wrap; align-items: center;">
|
|
1269
|
+
<Badge label={Signal.make("Default")} variant={Badge.Default} />
|
|
1270
|
+
<Badge label={Signal.make("Primary")} variant={Badge.Primary} />
|
|
1271
|
+
<Badge label={Signal.make("Secondary")} variant={Badge.Secondary} />
|
|
1272
|
+
<Badge label={Signal.make("Success")} variant={Badge.Success} />
|
|
1273
|
+
<Badge label={Signal.make("Warning")} variant={Badge.Warning} />
|
|
1274
|
+
<Badge label={Signal.make("Error")} variant={Badge.Error} />
|
|
1275
|
+
</div>
|
|
1276
|
+
<div
|
|
1277
|
+
style="display: flex; gap: 0.75rem; flex-wrap: wrap; align-items: center; margin-top: 1rem;"
|
|
1278
|
+
>
|
|
1279
|
+
<Badge label={Signal.make("Small")} variant={Badge.Primary} size={Badge.Sm} />
|
|
1280
|
+
<Badge label={Signal.make("Medium")} variant={Badge.Primary} size={Badge.Md} />
|
|
1281
|
+
<Badge label={Signal.make("Large")} variant={Badge.Primary} size={Badge.Lg} />
|
|
1282
|
+
<Badge label={Signal.make("Online")} variant={Badge.Success} dot={true} />
|
|
1283
|
+
<Badge label={Signal.make("Away")} variant={Badge.Warning} dot={true} />
|
|
1284
|
+
</div>
|
|
1285
|
+
</div>
|
|
1286
|
+
|
|
1287
|
+
<Separator orientation={Separator.Horizontal} variant={Separator.Dashed} label={"Spinners"} />
|
|
1288
|
+
|
|
1289
|
+
// Spinners Section
|
|
1290
|
+
<div style="margin-top: 2rem;">
|
|
1291
|
+
<Typography text={ReactiveProp.Static("Spinners")} variant={Typography.H4} />
|
|
1292
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
1293
|
+
{Component.text("Loading indicators in different sizes and colors.")}
|
|
1294
|
+
</p>
|
|
1295
|
+
<div style="display: flex; gap: 2rem; flex-wrap: wrap; align-items: center;">
|
|
1296
|
+
<Spinner size={Spinner.Sm} variant={Spinner.Default} />
|
|
1297
|
+
<Spinner size={Spinner.Md} variant={Spinner.Primary} />
|
|
1298
|
+
<Spinner size={Spinner.Lg} variant={Spinner.Secondary} />
|
|
1299
|
+
<Spinner size={Spinner.Xl} variant={Spinner.Primary} />
|
|
1300
|
+
</div>
|
|
1301
|
+
<div style="display: flex; gap: 2rem; flex-wrap: wrap; margin-top: 1.5rem;">
|
|
1302
|
+
<Spinner size={Spinner.Md} variant={Spinner.Primary} label="Loading..." />
|
|
1303
|
+
<Spinner
|
|
1304
|
+
size={Spinner.Lg}
|
|
1305
|
+
variant={Spinner.Default}
|
|
1306
|
+
label={Signal.get(isSubmitting) ? "Submitting..." : "Ready"}
|
|
1307
|
+
/>
|
|
1308
|
+
</div>
|
|
1309
|
+
</div>
|
|
1310
|
+
|
|
1311
|
+
<Separator orientation={Separator.Horizontal} variant={Separator.Dotted} />
|
|
1312
|
+
|
|
1313
|
+
// Keyboard Shortcuts Section
|
|
1314
|
+
<div style="margin-top: 2rem;">
|
|
1315
|
+
<Typography text={ReactiveProp.Static("Keyboard Shortcuts")} variant={Typography.H4} />
|
|
1316
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
1317
|
+
{Component.text("Display keyboard shortcuts in a visually appealing way.")}
|
|
1318
|
+
</p>
|
|
1319
|
+
<div style="display: flex; gap: 1.5rem; flex-wrap: wrap; align-items: center;">
|
|
1320
|
+
<div>
|
|
1321
|
+
<span style="color: #6b7280; margin-right: 0.5rem;"> {Component.text("Copy:")} </span>
|
|
1322
|
+
<Kbd keys={Signal.make(["Ctrl", "C"])} size={Kbd.Md} />
|
|
1323
|
+
</div>
|
|
1324
|
+
<div>
|
|
1325
|
+
<span style="color: #6b7280; margin-right: 0.5rem;"> {Component.text("Paste:")} </span>
|
|
1326
|
+
<Kbd keys={Signal.make(["Ctrl", "V"])} size={Kbd.Md} />
|
|
1327
|
+
</div>
|
|
1328
|
+
<div>
|
|
1329
|
+
<span style="color: #6b7280; margin-right: 0.5rem;"> {Component.text("Save:")} </span>
|
|
1330
|
+
<Kbd keys={Signal.make(["Ctrl", "S"])} size={Kbd.Md} />
|
|
1331
|
+
</div>
|
|
1332
|
+
<div>
|
|
1333
|
+
<span style="color: #6b7280; margin-right: 0.5rem;">
|
|
1334
|
+
{Component.text("Select All:")}
|
|
1335
|
+
</span>
|
|
1336
|
+
<Kbd keys={Signal.make(["Ctrl", "A"])} size={Kbd.Md} />
|
|
1337
|
+
</div>
|
|
1338
|
+
</div>
|
|
1339
|
+
<div style="margin-top: 1rem;">
|
|
1340
|
+
<Kbd keys={Signal.make(["Shift", "Alt", "F"])} size={Kbd.Sm} />
|
|
1341
|
+
<span style="color: #6b7280; margin-left: 0.5rem;">
|
|
1342
|
+
{Component.text("Format Document")}
|
|
1343
|
+
</span>
|
|
1344
|
+
</div>
|
|
1345
|
+
</div>
|
|
1346
|
+
|
|
1347
|
+
<Separator orientation={Separator.Horizontal} variant={Separator.Solid} />
|
|
1348
|
+
|
|
1349
|
+
// Typography Section
|
|
1350
|
+
<div style="margin-top: 2rem;">
|
|
1351
|
+
<Typography text={ReactiveProp.Static("Typography")} variant={Typography.H4} />
|
|
1352
|
+
<p style="color: #6b7280; margin: 0.5rem 0 1rem 0;">
|
|
1353
|
+
{Component.text("Consistent text styling across your application.")}
|
|
1354
|
+
</p>
|
|
1355
|
+
<div style="display: flex; flex-direction: column; gap: 1rem;">
|
|
1356
|
+
<Typography text={ReactiveProp.Static("Heading 1")} variant={Typography.H1} />
|
|
1357
|
+
<Typography text={ReactiveProp.Static("Heading 2")} variant={Typography.H2} />
|
|
1358
|
+
<Typography text={ReactiveProp.Static("Heading 3")} variant={Typography.H3} />
|
|
1359
|
+
<Typography text={ReactiveProp.Static("Heading 4")} variant={Typography.H4} />
|
|
1360
|
+
<Typography text={ReactiveProp.Static("Heading 5")} variant={Typography.H5} />
|
|
1361
|
+
<Typography text={ReactiveProp.Static("Heading 6")} variant={Typography.H6} />
|
|
1362
|
+
<Separator orientation={Separator.Horizontal} variant={Separator.Dashed} />
|
|
1363
|
+
<Typography
|
|
1364
|
+
text={ReactiveProp.Static(
|
|
1365
|
+
"This is a regular paragraph with normal text styling and comfortable line height.",
|
|
1366
|
+
)}
|
|
1367
|
+
variant={Typography.P}
|
|
1368
|
+
/>
|
|
1369
|
+
<Typography
|
|
1370
|
+
text={ReactiveProp.Static(
|
|
1371
|
+
"This is a lead paragraph that stands out with larger text and is perfect for introductions.",
|
|
1372
|
+
)}
|
|
1373
|
+
variant={Typography.Lead}
|
|
1374
|
+
/>
|
|
1375
|
+
<Typography
|
|
1376
|
+
text={ReactiveProp.Static("This is small text, useful for captions and helper text.")}
|
|
1377
|
+
variant={Typography.Small}
|
|
1378
|
+
/>
|
|
1379
|
+
<Typography
|
|
1380
|
+
text={ReactiveProp.Static("This is muted text with reduced emphasis.")}
|
|
1381
|
+
variant={Typography.Muted}
|
|
1382
|
+
/>
|
|
1383
|
+
<Typography
|
|
1384
|
+
text={ReactiveProp.Static("const hello = 'world'")} variant={Typography.Code}
|
|
1385
|
+
/>
|
|
1386
|
+
</div>
|
|
1387
|
+
</div>
|
|
1388
|
+
|
|
1389
|
+
<div
|
|
1390
|
+
style="margin-top: 3rem; padding: 1rem; background-color: #f3f4f6; border-radius: 0.5rem;"
|
|
1391
|
+
>
|
|
1392
|
+
<h3 style="margin-top: 0; color: #374151;"> {Component.text("Form State (Real-time)")} </h3>
|
|
1393
|
+
<pre
|
|
1394
|
+
style="background-color: #1f2937; color: #f9fafb; padding: 1rem; border-radius: 0.25rem; overflow-x: auto; font-size: 0.875rem;"
|
|
1395
|
+
>
|
|
1396
|
+
{Component.textSignal(() => {
|
|
1397
|
+
`Name: ${Signal.get(name)}
|
|
1398
|
+
Email: ${Signal.get(email)}
|
|
1399
|
+
Password: ${"*"->String.repeat(Signal.get(password)->String.length)}
|
|
1400
|
+
Interest: ${Signal.get(selectedOption)}
|
|
1401
|
+
Color: ${Signal.get(selectedColor)}
|
|
1402
|
+
Message: ${Signal.get(message)->String.slice(~start=0, ~end=50)}${Signal.get(
|
|
1403
|
+
message,
|
|
1404
|
+
)->String.length > 50
|
|
1405
|
+
? "..."
|
|
1406
|
+
: ""}
|
|
1407
|
+
Terms: ${Signal.get(agreeToTerms)->Bool.toString}
|
|
1408
|
+
Newsletter: ${Signal.get(newsletter)->Bool.toString}`
|
|
1409
|
+
})}
|
|
1410
|
+
</pre>
|
|
1411
|
+
</div>
|
|
1412
|
+
</>
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
// Mount the demo application
|
|
1417
|
+
Component.mountById(<Demo />, "root")
|