@syscore/ui-library 1.27.3 → 2.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/client/components/ui/app-bar.tsx +299 -0
- package/client/components/ui/banner.tsx +108 -0
- package/client/components/ui/bottom-navigation.tsx +223 -0
- package/client/components/ui/card.tsx +108 -26
- package/client/components/ui/date-picker.tsx +188 -0
- package/client/components/ui/empty-state.tsx +197 -0
- package/client/components/ui/file-upload.tsx +214 -0
- package/client/components/ui/footer.tsx +179 -0
- package/client/components/ui/layout.tsx +381 -0
- package/client/components/ui/stepper.tsx +148 -0
- package/client/components/ui/system-bar.tsx +119 -0
- package/client/components/ui/timeline.tsx +181 -0
- package/client/global.css +2304 -41
- package/client/ui/AppBar/app-bar.stories.tsx +280 -0
- package/client/ui/Banner/banner.stories.tsx +238 -0
- package/client/ui/BottomNavigation/bottom-navigation.stories.tsx +285 -0
- package/client/ui/Card.stories.tsx +285 -168
- package/client/ui/DatePicker/DatePicker.stories.tsx +293 -0
- package/client/ui/EmptyState/empty-state.stories.tsx +251 -0
- package/client/ui/FileUpload/FileUpload.stories.tsx +218 -0
- package/client/ui/Footer/footer.stories.tsx +194 -0
- package/client/ui/Layout.stories.tsx +1481 -0
- package/client/ui/Stepper/Stepper.stories.tsx +344 -0
- package/client/ui/SystemBar/system-bar.stories.tsx +179 -0
- package/client/ui/Timeline/timeline.stories.tsx +404 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +219 -0
- package/dist/index.es.js +1430 -24
- package/package.json +1 -1
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { Stepper } from "../../components/ui/stepper";
|
|
4
|
+
import { Button } from "../../components/ui/button";
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
title: "UI/Stepper",
|
|
8
|
+
component: Stepper,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: "padded",
|
|
12
|
+
docs: {
|
|
13
|
+
description: {
|
|
14
|
+
component: [
|
|
15
|
+
"A step indicator for multi-step flows — registration wizards, certification processes, onboarding.",
|
|
16
|
+
"",
|
|
17
|
+
"**Import:**",
|
|
18
|
+
"```tsx",
|
|
19
|
+
`import { Stepper } from "@syscore/ui-library"`,
|
|
20
|
+
"```",
|
|
21
|
+
"",
|
|
22
|
+
"**Key props:**",
|
|
23
|
+
"",
|
|
24
|
+
"| Prop | Type | Default | Effect |",
|
|
25
|
+
"|------|------|---------|--------|",
|
|
26
|
+
"| `steps` | `{ title, description? }[]` | — | The step definitions |",
|
|
27
|
+
"| `currentStep` | number | — | 0-indexed active step |",
|
|
28
|
+
"| `orientation` | `\"horizontal\"` \\| `\"vertical\"` | `\"horizontal\"` | Layout direction |",
|
|
29
|
+
"| `variant` | `\"default\"` \\| `\"outlined\"` | `\"default\"` | Filled vs outlined indicators |",
|
|
30
|
+
"| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` | `\"md\"` | Size of indicators and labels |",
|
|
31
|
+
"| `onStepClick` | `(index) => void` | — | Makes completed steps clickable |",
|
|
32
|
+
].join("\n"),
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
args: {
|
|
37
|
+
steps: [
|
|
38
|
+
{ title: "Project details", description: "Basic information" },
|
|
39
|
+
{ title: "Documents", description: "Upload required files" },
|
|
40
|
+
{ title: "Review", description: "Check your submission" },
|
|
41
|
+
{ title: "Submit", description: "Complete registration" },
|
|
42
|
+
],
|
|
43
|
+
currentStep: 1,
|
|
44
|
+
},
|
|
45
|
+
} satisfies Meta<typeof Stepper>;
|
|
46
|
+
|
|
47
|
+
export default meta;
|
|
48
|
+
type Story = StoryObj<typeof meta>;
|
|
49
|
+
|
|
50
|
+
const REGISTRATION_STEPS = [
|
|
51
|
+
{ title: "Project details", description: "Basic information" },
|
|
52
|
+
{ title: "Documents", description: "Upload required files" },
|
|
53
|
+
{ title: "Review", description: "Check your submission" },
|
|
54
|
+
{ title: "Submit", description: "Complete registration" },
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const SIMPLE_STEPS = [
|
|
58
|
+
{ title: "Account" },
|
|
59
|
+
{ title: "Profile" },
|
|
60
|
+
{ title: "Preferences" },
|
|
61
|
+
{ title: "Done" },
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
export const Default: Story = {
|
|
67
|
+
parameters: {
|
|
68
|
+
docs: {
|
|
69
|
+
source: {
|
|
70
|
+
code: `import { Stepper } from "@syscore/ui-library"
|
|
71
|
+
|
|
72
|
+
const steps = [
|
|
73
|
+
{ title: "Project details", description: "Basic information" },
|
|
74
|
+
{ title: "Documents", description: "Upload required files" },
|
|
75
|
+
{ title: "Review", description: "Check your submission" },
|
|
76
|
+
{ title: "Submit", description: "Complete registration" },
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
<Stepper steps={steps} currentStep={1} />`,
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
render: () => (
|
|
84
|
+
<Stepper steps={REGISTRATION_STEPS} currentStep={1} />
|
|
85
|
+
),
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const AllStepsState: Story = {
|
|
89
|
+
name: "Step states",
|
|
90
|
+
parameters: {
|
|
91
|
+
docs: {
|
|
92
|
+
source: {
|
|
93
|
+
code: `import { Stepper } from "@syscore/ui-library"
|
|
94
|
+
|
|
95
|
+
// currentStep=0 → all upcoming
|
|
96
|
+
<Stepper steps={steps} currentStep={0} />
|
|
97
|
+
|
|
98
|
+
// currentStep=2 → 2 complete, 1 current, 1 upcoming
|
|
99
|
+
<Stepper steps={steps} currentStep={2} />
|
|
100
|
+
|
|
101
|
+
// currentStep=4 → all complete
|
|
102
|
+
<Stepper steps={steps} currentStep={4} />`,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
render: () => (
|
|
107
|
+
<div className="flex flex-col gap-10 w-full">
|
|
108
|
+
<div className="flex flex-col gap-2">
|
|
109
|
+
<span className="text-xs text-gray-400 font-medium">Not started (currentStep=0)</span>
|
|
110
|
+
<Stepper steps={SIMPLE_STEPS} currentStep={0} />
|
|
111
|
+
</div>
|
|
112
|
+
<div className="flex flex-col gap-2">
|
|
113
|
+
<span className="text-xs text-gray-400 font-medium">In progress (currentStep=2)</span>
|
|
114
|
+
<Stepper steps={SIMPLE_STEPS} currentStep={2} />
|
|
115
|
+
</div>
|
|
116
|
+
<div className="flex flex-col gap-2">
|
|
117
|
+
<span className="text-xs text-gray-400 font-medium">Complete (currentStep=4)</span>
|
|
118
|
+
<Stepper steps={SIMPLE_STEPS} currentStep={4} />
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
),
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const Vertical: Story = {
|
|
125
|
+
parameters: {
|
|
126
|
+
docs: {
|
|
127
|
+
source: {
|
|
128
|
+
code: `import { Stepper } from "@syscore/ui-library"
|
|
129
|
+
|
|
130
|
+
<Stepper
|
|
131
|
+
steps={steps}
|
|
132
|
+
currentStep={1}
|
|
133
|
+
orientation="vertical"
|
|
134
|
+
/>`,
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
render: () => (
|
|
139
|
+
<div className="max-w-xs">
|
|
140
|
+
<Stepper
|
|
141
|
+
steps={REGISTRATION_STEPS}
|
|
142
|
+
currentStep={1}
|
|
143
|
+
orientation="vertical"
|
|
144
|
+
/>
|
|
145
|
+
</div>
|
|
146
|
+
),
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export const Outlined: Story = {
|
|
150
|
+
parameters: {
|
|
151
|
+
docs: {
|
|
152
|
+
source: {
|
|
153
|
+
code: `import { Stepper } from "@syscore/ui-library"
|
|
154
|
+
|
|
155
|
+
<Stepper steps={steps} currentStep={2} variant="outlined" />`,
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
render: () => (
|
|
160
|
+
<Stepper steps={REGISTRATION_STEPS} currentStep={2} variant="outlined" />
|
|
161
|
+
),
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export const Sizes: Story = {
|
|
165
|
+
parameters: {
|
|
166
|
+
docs: {
|
|
167
|
+
source: {
|
|
168
|
+
code: `import { Stepper } from "@syscore/ui-library"
|
|
169
|
+
|
|
170
|
+
<Stepper steps={steps} currentStep={1} size="sm" />
|
|
171
|
+
<Stepper steps={steps} currentStep={1} size="md" />
|
|
172
|
+
<Stepper steps={steps} currentStep={1} size="lg" />`,
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
render: () => (
|
|
177
|
+
<div className="flex flex-col gap-10 w-full">
|
|
178
|
+
{(["sm", "md", "lg"] as const).map((size) => (
|
|
179
|
+
<div key={size} className="flex flex-col gap-2">
|
|
180
|
+
<span className="text-xs text-gray-400 font-medium">size="{size}"</span>
|
|
181
|
+
<Stepper steps={SIMPLE_STEPS} currentStep={1} size={size} />
|
|
182
|
+
</div>
|
|
183
|
+
))}
|
|
184
|
+
</div>
|
|
185
|
+
),
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export const Clickable: Story = {
|
|
189
|
+
name: "Clickable steps",
|
|
190
|
+
parameters: {
|
|
191
|
+
docs: {
|
|
192
|
+
source: {
|
|
193
|
+
code: `import { Stepper } from "@syscore/ui-library"
|
|
194
|
+
import { useState } from "react"
|
|
195
|
+
|
|
196
|
+
const [currentStep, setCurrentStep] = useState(2)
|
|
197
|
+
|
|
198
|
+
{/* Completed steps are clickable — lets users go back */}
|
|
199
|
+
<Stepper
|
|
200
|
+
steps={steps}
|
|
201
|
+
currentStep={currentStep}
|
|
202
|
+
onStepClick={setCurrentStep}
|
|
203
|
+
/>`,
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
render: () => {
|
|
208
|
+
const [currentStep, setCurrentStep] = useState(2);
|
|
209
|
+
return (
|
|
210
|
+
<div className="flex flex-col gap-6 w-full">
|
|
211
|
+
<Stepper
|
|
212
|
+
steps={REGISTRATION_STEPS}
|
|
213
|
+
currentStep={currentStep}
|
|
214
|
+
onStepClick={setCurrentStep}
|
|
215
|
+
/>
|
|
216
|
+
<p className="text-sm text-gray-500 text-center">
|
|
217
|
+
Click a completed step (green) to go back
|
|
218
|
+
</p>
|
|
219
|
+
</div>
|
|
220
|
+
);
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
export const WithNavigation: Story = {
|
|
225
|
+
name: "With next / back buttons",
|
|
226
|
+
parameters: {
|
|
227
|
+
docs: {
|
|
228
|
+
source: {
|
|
229
|
+
code: `import { Stepper } from "@syscore/ui-library"
|
|
230
|
+
import { Button, Stack } from "@syscore/ui-library"
|
|
231
|
+
import { useState } from "react"
|
|
232
|
+
|
|
233
|
+
const [currentStep, setCurrentStep] = useState(0)
|
|
234
|
+
|
|
235
|
+
<Stack gap={6}>
|
|
236
|
+
<Stepper steps={steps} currentStep={currentStep} />
|
|
237
|
+
|
|
238
|
+
<Stack direction="horizontal" justify="between">
|
|
239
|
+
<Button
|
|
240
|
+
variant="secondary-light"
|
|
241
|
+
size="large"
|
|
242
|
+
disabled={currentStep === 0}
|
|
243
|
+
onClick={() => setCurrentStep(s => s - 1)}
|
|
244
|
+
>
|
|
245
|
+
Back
|
|
246
|
+
</Button>
|
|
247
|
+
<Button
|
|
248
|
+
variant="primary-dark"
|
|
249
|
+
size="large"
|
|
250
|
+
disabled={currentStep === steps.length}
|
|
251
|
+
onClick={() => setCurrentStep(s => s + 1)}
|
|
252
|
+
>
|
|
253
|
+
{currentStep === steps.length - 1 ? "Submit" : "Next"}
|
|
254
|
+
</Button>
|
|
255
|
+
</Stack>
|
|
256
|
+
</Stack>`,
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
render: () => {
|
|
261
|
+
const [currentStep, setCurrentStep] = useState(0);
|
|
262
|
+
const steps = REGISTRATION_STEPS;
|
|
263
|
+
|
|
264
|
+
return (
|
|
265
|
+
<div className="w-full max-w-2xl border border-gray-100 rounded-xl p-8 flex flex-col gap-8">
|
|
266
|
+
<Stepper steps={steps} currentStep={currentStep} />
|
|
267
|
+
|
|
268
|
+
{/* Step content placeholder */}
|
|
269
|
+
<div className="min-h-[120px] flex items-center justify-center rounded-lg border border-dashed border-gray-200 bg-gray-50">
|
|
270
|
+
<span className="text-sm text-gray-400">
|
|
271
|
+
{currentStep < steps.length
|
|
272
|
+
? `${steps[currentStep].title} — step content goes here`
|
|
273
|
+
: "All steps complete!"}
|
|
274
|
+
</span>
|
|
275
|
+
</div>
|
|
276
|
+
|
|
277
|
+
{/* Navigation */}
|
|
278
|
+
<div className="flex justify-between">
|
|
279
|
+
<Button
|
|
280
|
+
variant="secondary-light"
|
|
281
|
+
size="large"
|
|
282
|
+
disabled={currentStep === 0}
|
|
283
|
+
onClick={() => setCurrentStep((s) => s - 1)}
|
|
284
|
+
>
|
|
285
|
+
Back
|
|
286
|
+
</Button>
|
|
287
|
+
<Button
|
|
288
|
+
variant="primary-dark"
|
|
289
|
+
size="large"
|
|
290
|
+
disabled={currentStep >= steps.length}
|
|
291
|
+
onClick={() => setCurrentStep((s) => s + 1)}
|
|
292
|
+
>
|
|
293
|
+
{currentStep === steps.length - 1 ? "Submit" : "Next"}
|
|
294
|
+
</Button>
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
);
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
export const CertificationWizard: Story = {
|
|
302
|
+
name: "WELL certification wizard",
|
|
303
|
+
parameters: {
|
|
304
|
+
docs: {
|
|
305
|
+
source: {
|
|
306
|
+
code: `import { Stepper } from "@syscore/ui-library"
|
|
307
|
+
|
|
308
|
+
const certificationSteps = [
|
|
309
|
+
{ title: "Registration", description: "Project & team details" },
|
|
310
|
+
{ title: "Documentation", description: "Upload project files" },
|
|
311
|
+
{ title: "Assessment", description: "WELL scorecard review" },
|
|
312
|
+
{ title: "Verification", description: "On-site performance tests" },
|
|
313
|
+
{ title: "Certification", description: "Award & seal issuance" },
|
|
314
|
+
]
|
|
315
|
+
|
|
316
|
+
<Stepper
|
|
317
|
+
steps={certificationSteps}
|
|
318
|
+
currentStep={2}
|
|
319
|
+
orientation="vertical"
|
|
320
|
+
size="lg"
|
|
321
|
+
/>`,
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
render: () => {
|
|
326
|
+
const certificationSteps = [
|
|
327
|
+
{ title: "Registration", description: "Project & team details" },
|
|
328
|
+
{ title: "Documentation", description: "Upload project files" },
|
|
329
|
+
{ title: "Assessment", description: "WELL scorecard review" },
|
|
330
|
+
{ title: "Verification", description: "On-site performance tests" },
|
|
331
|
+
{ title: "Certification", description: "Award & seal issuance" },
|
|
332
|
+
];
|
|
333
|
+
return (
|
|
334
|
+
<div className="max-w-xs border border-gray-100 rounded-xl p-6">
|
|
335
|
+
<Stepper
|
|
336
|
+
steps={certificationSteps}
|
|
337
|
+
currentStep={2}
|
|
338
|
+
orientation="vertical"
|
|
339
|
+
size="lg"
|
|
340
|
+
/>
|
|
341
|
+
</div>
|
|
342
|
+
);
|
|
343
|
+
},
|
|
344
|
+
};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import {
|
|
3
|
+
SystemBar,
|
|
4
|
+
SystemBarSpacer,
|
|
5
|
+
SystemBarIcon,
|
|
6
|
+
SystemBarAction,
|
|
7
|
+
} from "../../components/ui/system-bar";
|
|
8
|
+
|
|
9
|
+
// ─── Inline SVG icons ─────────────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
function IconWifi({ strength = 4 }: { strength?: 1 | 2 | 3 | 4 }) {
|
|
12
|
+
// Simple wifi icon — bars filled based on strength
|
|
13
|
+
const bars = [1, 2, 3, 4];
|
|
14
|
+
return (
|
|
15
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
16
|
+
{strength >= 1 && <path d="M1 9l2 2c5-5 13-5 18 0l2-2C16.93 2.93 7.08 2.93 1 9z" opacity={strength === 1 ? 1 : 0.4} />}
|
|
17
|
+
{strength >= 2 && <path d="M5 13l2 2a7 7 0 0 1 10 0l2-2C15.14 9.14 8.87 9.14 5 13z" opacity={strength === 2 ? 1 : 0.6} />}
|
|
18
|
+
{strength >= 3 && <path d="M9 17l3 3 3-3a4.237 4.237 0 0 0-6 0z" />}
|
|
19
|
+
<circle cx="12" cy="20" r="1" />
|
|
20
|
+
</svg>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function IconSignal() {
|
|
25
|
+
return (
|
|
26
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
27
|
+
<rect x="2" y="16" width="3" height="6" rx="0.5" />
|
|
28
|
+
<rect x="7" y="12" width="3" height="10" rx="0.5" />
|
|
29
|
+
<rect x="12" y="8" width="3" height="14" rx="0.5" />
|
|
30
|
+
<rect x="17" y="4" width="3" height="18" rx="0.5" opacity="0.3" />
|
|
31
|
+
</svg>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function IconBattery() {
|
|
36
|
+
return (
|
|
37
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
38
|
+
<rect x="2" y="7" width="18" height="11" rx="2" stroke="currentColor" strokeWidth="1.5" fill="none" />
|
|
39
|
+
<rect x="3.5" y="8.5" width="12" height="8" rx="1" />
|
|
40
|
+
<path d="M20 10h2v5h-2z" />
|
|
41
|
+
</svg>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function IconMessage() {
|
|
46
|
+
return (
|
|
47
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
48
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
|
|
49
|
+
</svg>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function IconMinus() {
|
|
54
|
+
return (
|
|
55
|
+
<svg width="12" height="12" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2" fill="none" aria-hidden="true">
|
|
56
|
+
<line x1="5" y1="12" x2="19" y2="12" />
|
|
57
|
+
</svg>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function IconMaximize() {
|
|
62
|
+
return (
|
|
63
|
+
<svg width="12" height="12" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2" fill="none" aria-hidden="true">
|
|
64
|
+
<rect x="3" y="3" width="18" height="18" rx="1" />
|
|
65
|
+
</svg>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function IconClose() {
|
|
70
|
+
return (
|
|
71
|
+
<svg width="12" height="12" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2" fill="none" aria-hidden="true">
|
|
72
|
+
<line x1="18" y1="6" x2="6" y2="18" />
|
|
73
|
+
<line x1="6" y1="6" x2="18" y2="18" />
|
|
74
|
+
</svg>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
const meta = {
|
|
81
|
+
title: "UI/SystemBar",
|
|
82
|
+
component: SystemBar,
|
|
83
|
+
tags: ["autodocs"],
|
|
84
|
+
parameters: {
|
|
85
|
+
layout: "fullscreen",
|
|
86
|
+
},
|
|
87
|
+
argTypes: {
|
|
88
|
+
color: { control: "color" },
|
|
89
|
+
window: { control: "boolean" },
|
|
90
|
+
},
|
|
91
|
+
} satisfies Meta<typeof SystemBar>;
|
|
92
|
+
|
|
93
|
+
export default meta;
|
|
94
|
+
|
|
95
|
+
type Story = StoryObj<typeof meta>;
|
|
96
|
+
|
|
97
|
+
// ─── Default ─────────────────────────────────────────────────────────────────
|
|
98
|
+
// Android-style status bar with wifi, signal, battery and a clock.
|
|
99
|
+
|
|
100
|
+
export const Default: Story = {
|
|
101
|
+
render: () => (
|
|
102
|
+
<SystemBar>
|
|
103
|
+
<SystemBarIcon>
|
|
104
|
+
<IconWifi strength={4} />
|
|
105
|
+
</SystemBarIcon>
|
|
106
|
+
<SystemBarIcon>
|
|
107
|
+
<IconSignal />
|
|
108
|
+
</SystemBarIcon>
|
|
109
|
+
<SystemBarIcon>
|
|
110
|
+
<IconBattery />
|
|
111
|
+
</SystemBarIcon>
|
|
112
|
+
<SystemBarSpacer />
|
|
113
|
+
<span className="system-bar-time">3:13 PM</span>
|
|
114
|
+
</SystemBar>
|
|
115
|
+
),
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// ─── Colors ───────────────────────────────────────────────────────────────────
|
|
119
|
+
// Three bars with different background colors — text/icons auto-switch to white.
|
|
120
|
+
|
|
121
|
+
export const Colors: Story = {
|
|
122
|
+
render: () => (
|
|
123
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "0.5rem" }}>
|
|
124
|
+
{/* Primary blue */}
|
|
125
|
+
<SystemBar color="#0284c7">
|
|
126
|
+
<SystemBarIcon><IconWifi strength={4} /></SystemBarIcon>
|
|
127
|
+
<SystemBarIcon><IconSignal /></SystemBarIcon>
|
|
128
|
+
<SystemBarIcon><IconBattery /></SystemBarIcon>
|
|
129
|
+
<SystemBarSpacer />
|
|
130
|
+
<span className="system-bar-time">08:30</span>
|
|
131
|
+
</SystemBar>
|
|
132
|
+
|
|
133
|
+
{/* Red */}
|
|
134
|
+
<SystemBar color="#f87171">
|
|
135
|
+
<SystemBarIcon><IconWifi strength={2} /></SystemBarIcon>
|
|
136
|
+
<SystemBarIcon><IconSignal /></SystemBarIcon>
|
|
137
|
+
<SystemBarIcon><IconBattery /></SystemBarIcon>
|
|
138
|
+
<SystemBarSpacer />
|
|
139
|
+
<span className="system-bar-time">18:30</span>
|
|
140
|
+
</SystemBar>
|
|
141
|
+
|
|
142
|
+
{/* Indigo */}
|
|
143
|
+
<SystemBar color="#3730a3">
|
|
144
|
+
<SystemBarIcon><IconWifi strength={3} /></SystemBarIcon>
|
|
145
|
+
<SystemBarIcon><IconSignal /></SystemBarIcon>
|
|
146
|
+
<SystemBarIcon><IconBattery /></SystemBarIcon>
|
|
147
|
+
<SystemBarSpacer />
|
|
148
|
+
<span className="system-bar-time">13:24</span>
|
|
149
|
+
</SystemBar>
|
|
150
|
+
</div>
|
|
151
|
+
),
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// ─── Window ───────────────────────────────────────────────────────────────────
|
|
155
|
+
// Desktop-style title bar: message on the left, window controls on the right.
|
|
156
|
+
|
|
157
|
+
export const Window: Story = {
|
|
158
|
+
render: () => (
|
|
159
|
+
<SystemBar window>
|
|
160
|
+
<SystemBarIcon>
|
|
161
|
+
<IconMessage />
|
|
162
|
+
</SystemBarIcon>
|
|
163
|
+
<span className="system-bar-label">10 unread messages</span>
|
|
164
|
+
<SystemBarSpacer />
|
|
165
|
+
<SystemBarAction aria-label="Minimise window">
|
|
166
|
+
<IconMinus />
|
|
167
|
+
</SystemBarAction>
|
|
168
|
+
<SystemBarAction aria-label="Maximise window">
|
|
169
|
+
<IconMaximize />
|
|
170
|
+
</SystemBarAction>
|
|
171
|
+
<SystemBarAction
|
|
172
|
+
aria-label="Close window"
|
|
173
|
+
className="system-bar-action--close"
|
|
174
|
+
>
|
|
175
|
+
<IconClose />
|
|
176
|
+
</SystemBarAction>
|
|
177
|
+
</SystemBar>
|
|
178
|
+
),
|
|
179
|
+
};
|