aural-ui 4.1.0 → 4.2.3
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 +8 -1
- package/dist/components/tabs/Tabs.stories.tsx +217 -173
- package/dist/components/tabs/index.tsx +100 -16
- package/dist/index.cjs +90 -90
- package/dist/index.js +90 -90
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -114,6 +114,13 @@ aural-ui update
|
|
|
114
114
|
|
|
115
115
|
The **aural-ui MCP server** exposes the design system by reading from aural-ui source (components, icons, source and story files). No Storybook process is required.
|
|
116
116
|
|
|
117
|
+
### Run the MCP server locally
|
|
118
|
+
|
|
119
|
+
1. Copy [`mcp/.env.example`](mcp/.env.example) to `mcp/.env` and fill in the values (Google OAuth client, redirect URL, issuer base URL, JWT secret). That file is the canonical list of variables; it stays next to the server code so it does not drift.
|
|
120
|
+
2. From the repo root: `npx tsx mcp/src/index.ts` (listens on port `3000` by default).
|
|
121
|
+
|
|
122
|
+
For OAuth flow details, see [`mcp/docs/auth.md`](mcp/docs/auth.md).
|
|
123
|
+
|
|
117
124
|
### Setup in Cursor
|
|
118
125
|
|
|
119
126
|
Add the server in `.cursor/mcp.json` (or Cursor Settings → MCP). Start the MCP server first (e.g. `npx tsx mcp/src/index.ts` from the aural-ui repo root, or run the Docker image), then point Cursor at the streamable HTTP endpoint:
|
|
@@ -131,7 +138,7 @@ Add the server in `.cursor/mcp.json` (or Cursor Settings → MCP). Start the MCP
|
|
|
131
138
|
|
|
132
139
|
The server identifies as **aural-ui** so agents match user phrases like "add aural-ui btn". Use the same URL when the server runs in Docker or elsewhere (e.g. `http://your-host:3000/mcp`).
|
|
133
140
|
|
|
134
|
-
- **Config:**
|
|
141
|
+
- **Config:** Non-secret defaults and limits live in `mcp/src/lib/env.ts`. OAuth and JWT values must come from the environment; for local dev, use `mcp/.env` (start from [`mcp/.env.example`](mcp/.env.example)).
|
|
135
142
|
|
|
136
143
|
**HTTP / Docker:** When running the MCP server over HTTP (e.g. in Docker):
|
|
137
144
|
- **GET /health** — Returns `200` and `{ "ok": true, "server": "aural-ui" }` for load balancers and orchestrators (no MCP session required).
|
|
@@ -29,22 +29,22 @@ const meta: Meta<typeof Tabs> = {
|
|
|
29
29
|
docs: {
|
|
30
30
|
description: {
|
|
31
31
|
component:
|
|
32
|
-
"A compound tabs component built on Radix UI Tabs with gradient glow effects on active triggers, smooth fade animations, and three size variants. Supports bottom
|
|
32
|
+
"A compound tabs component built on Radix UI Tabs with gradient glow effects on active triggers, smooth fade animations, and three size variants. Supports four glow directions (bottom, top, left, right) and per-trigger size overrides via a shared size context.",
|
|
33
33
|
},
|
|
34
34
|
page: () => (
|
|
35
35
|
<AuralComponentDocsPage
|
|
36
36
|
features={[
|
|
37
37
|
{
|
|
38
|
-
title: "
|
|
39
|
-
description: "
|
|
38
|
+
title: "Accessible by Default",
|
|
39
|
+
description: "Auto ARIA wiring",
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
|
-
title: "
|
|
43
|
-
description: "
|
|
42
|
+
title: "4 Glow Directions",
|
|
43
|
+
description: "bottom, top, left, right",
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
|
-
title: "
|
|
47
|
-
description: "
|
|
46
|
+
title: "3 Sizes",
|
|
47
|
+
description: "sm, md, lg via context",
|
|
48
48
|
},
|
|
49
49
|
]}
|
|
50
50
|
/>
|
|
@@ -154,24 +154,58 @@ export const AllVariants: Story = {
|
|
|
154
154
|
</div>
|
|
155
155
|
|
|
156
156
|
<div className="space-y-2 text-center">
|
|
157
|
-
<
|
|
158
|
-
<
|
|
159
|
-
<
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
</Tabs>
|
|
170
|
-
</div>
|
|
157
|
+
<Tabs defaultValue="active" size="md">
|
|
158
|
+
<TabsList>
|
|
159
|
+
<TabsTrigger value="active" glowDirection="top">
|
|
160
|
+
Active
|
|
161
|
+
</TabsTrigger>
|
|
162
|
+
<TabsTrigger value="other" glowDirection="top">
|
|
163
|
+
Inactive
|
|
164
|
+
</TabsTrigger>
|
|
165
|
+
</TabsList>
|
|
166
|
+
<TabsContent value="active" />
|
|
167
|
+
<TabsContent value="other" />
|
|
168
|
+
</Tabs>
|
|
171
169
|
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
172
170
|
Glow Top
|
|
173
171
|
</p>
|
|
174
172
|
</div>
|
|
173
|
+
|
|
174
|
+
<div className="space-y-2 text-center">
|
|
175
|
+
<Tabs defaultValue="active" size="md">
|
|
176
|
+
<TabsList>
|
|
177
|
+
<TabsTrigger value="active" glowDirection="left">
|
|
178
|
+
Active
|
|
179
|
+
</TabsTrigger>
|
|
180
|
+
<TabsTrigger value="other" glowDirection="left">
|
|
181
|
+
Inactive
|
|
182
|
+
</TabsTrigger>
|
|
183
|
+
</TabsList>
|
|
184
|
+
<TabsContent value="active" />
|
|
185
|
+
<TabsContent value="other" />
|
|
186
|
+
</Tabs>
|
|
187
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
188
|
+
Glow Left
|
|
189
|
+
</p>
|
|
190
|
+
</div>
|
|
191
|
+
|
|
192
|
+
<div className="space-y-2 text-center">
|
|
193
|
+
<Tabs defaultValue="active" size="md">
|
|
194
|
+
<TabsList className="gap-6">
|
|
195
|
+
<TabsTrigger value="active" glowDirection="right">
|
|
196
|
+
Active
|
|
197
|
+
</TabsTrigger>
|
|
198
|
+
<TabsTrigger value="other" glowDirection="right">
|
|
199
|
+
Inactive
|
|
200
|
+
</TabsTrigger>
|
|
201
|
+
</TabsList>
|
|
202
|
+
<TabsContent value="active" />
|
|
203
|
+
<TabsContent value="other" />
|
|
204
|
+
</Tabs>
|
|
205
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
206
|
+
Glow Right
|
|
207
|
+
</p>
|
|
208
|
+
</div>
|
|
175
209
|
</div>
|
|
176
210
|
</div>
|
|
177
211
|
</div>
|
|
@@ -180,7 +214,7 @@ export const AllVariants: Story = {
|
|
|
180
214
|
docs: {
|
|
181
215
|
description: {
|
|
182
216
|
story:
|
|
183
|
-
"All three size variants (sm, md, lg) and
|
|
217
|
+
"All three size variants (sm, md, lg) and all four glow direction options (bottom, top, left, right) shown as labeled item cards.",
|
|
184
218
|
},
|
|
185
219
|
},
|
|
186
220
|
},
|
|
@@ -287,6 +321,39 @@ export const Configurations: Story = {
|
|
|
287
321
|
</Tabs>
|
|
288
322
|
</div>
|
|
289
323
|
|
|
324
|
+
{/* Hover state */}
|
|
325
|
+
<div className="space-y-4">
|
|
326
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
327
|
+
Hover State
|
|
328
|
+
</h4>
|
|
329
|
+
<Tabs defaultValue="songs" size="md" className="w-full max-w-lg">
|
|
330
|
+
<TabsList>
|
|
331
|
+
<TabsTrigger value="songs">Songs</TabsTrigger>
|
|
332
|
+
<TabsTrigger value="albums">Albums</TabsTrigger>
|
|
333
|
+
<TabsTrigger value="artists">Artists</TabsTrigger>
|
|
334
|
+
</TabsList>
|
|
335
|
+
<TabsContent value="songs" className="mt-4">
|
|
336
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
|
|
337
|
+
<p className="text-fm-secondary font-fm-text text-fm-md leading-fm-xl">
|
|
338
|
+
Hover over inactive tabs to see the distinct hover state — text
|
|
339
|
+
shifts from{" "}
|
|
340
|
+
<code className="text-fm-primary font-(--font-fm-mono)">
|
|
341
|
+
text-fm-tertiary
|
|
342
|
+
</code>{" "}
|
|
343
|
+
to{" "}
|
|
344
|
+
<code className="text-fm-primary font-(--font-fm-mono)">
|
|
345
|
+
text-fm-primary
|
|
346
|
+
</code>
|
|
347
|
+
, providing a clear visual cue that is distinct from both the
|
|
348
|
+
default and active states.
|
|
349
|
+
</p>
|
|
350
|
+
</div>
|
|
351
|
+
</TabsContent>
|
|
352
|
+
<TabsContent value="albums" className="mt-4" />
|
|
353
|
+
<TabsContent value="artists" className="mt-4" />
|
|
354
|
+
</Tabs>
|
|
355
|
+
</div>
|
|
356
|
+
|
|
290
357
|
{/* Different content panels */}
|
|
291
358
|
<div className="space-y-4">
|
|
292
359
|
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
@@ -393,7 +460,7 @@ export const Configurations: Story = {
|
|
|
393
460
|
docs: {
|
|
394
461
|
description: {
|
|
395
462
|
story:
|
|
396
|
-
"Configuration axes: tabs with icons, individual per-trigger size overrides
|
|
463
|
+
"Configuration axes: hover state behavior, tabs with icons, individual per-trigger size overrides, and rich differentiated content panels.",
|
|
397
464
|
},
|
|
398
465
|
},
|
|
399
466
|
},
|
|
@@ -434,170 +501,147 @@ export const Interactive: Story = {
|
|
|
434
501
|
|
|
435
502
|
return (
|
|
436
503
|
<div className="w-full p-8">
|
|
437
|
-
<div className="mx-auto max-w-
|
|
438
|
-
<div className="
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
const Icon = tab.icon
|
|
447
|
-
return (
|
|
448
|
-
<button
|
|
449
|
-
key={tab.value}
|
|
450
|
-
onClick={() => setActiveTab(tab.value)}
|
|
451
|
-
className={`font-fm-text text-fm-sm leading-fm-sm flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left transition-colors ${
|
|
452
|
-
activeTab === tab.value
|
|
453
|
-
? "bg-fm-surface-primary text-fm-primary"
|
|
454
|
-
: "text-fm-secondary hover:text-fm-primary"
|
|
455
|
-
}`}
|
|
456
|
-
>
|
|
457
|
-
<Icon className="h-4 w-4 shrink-0" />
|
|
458
|
-
{tab.label}
|
|
459
|
-
</button>
|
|
460
|
-
)
|
|
461
|
-
})}
|
|
462
|
-
</div>
|
|
463
|
-
<div className="border-fm-divider-secondary border-t pt-4" />
|
|
464
|
-
<div className="border-fm-divider-secondary bg-fm-surface-primary rounded-lg border px-4 py-3">
|
|
465
|
-
<code className="text-fm-secondary text-fm-md leading-fm-md font-(--font-fm-mono)">
|
|
466
|
-
value="{activeTab}"
|
|
467
|
-
</code>
|
|
468
|
-
</div>
|
|
504
|
+
<div className="mx-auto max-w-xl space-y-4">
|
|
505
|
+
<div className="flex items-center justify-between">
|
|
506
|
+
<p className="text-fm-primary font-fm-brand text-fm-md leading-fm-md font-semibold">
|
|
507
|
+
My Library
|
|
508
|
+
</p>
|
|
509
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border px-3 py-1.5">
|
|
510
|
+
<code className="text-fm-secondary text-fm-sm leading-fm-sm font-(--font-fm-mono)">
|
|
511
|
+
value="{activeTab}"
|
|
512
|
+
</code>
|
|
469
513
|
</div>
|
|
514
|
+
</div>
|
|
470
515
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
})}
|
|
493
|
-
</TabsList>
|
|
516
|
+
<Tabs
|
|
517
|
+
value={activeTab}
|
|
518
|
+
onValueChange={setActiveTab}
|
|
519
|
+
size="md"
|
|
520
|
+
className="w-full"
|
|
521
|
+
>
|
|
522
|
+
<TabsList className="w-full">
|
|
523
|
+
{tabs.map((tab) => {
|
|
524
|
+
const Icon = tab.icon
|
|
525
|
+
return (
|
|
526
|
+
<TabsTrigger
|
|
527
|
+
key={tab.value}
|
|
528
|
+
value={tab.value}
|
|
529
|
+
className="gap-1.5"
|
|
530
|
+
>
|
|
531
|
+
<Icon className="h-4 w-4" />
|
|
532
|
+
{tab.label}
|
|
533
|
+
</TabsTrigger>
|
|
534
|
+
)
|
|
535
|
+
})}
|
|
536
|
+
</TabsList>
|
|
494
537
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
</div>
|
|
514
|
-
</div>
|
|
515
|
-
<span className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm">
|
|
516
|
-
{song.duration}
|
|
517
|
-
</span>
|
|
538
|
+
<TabsContent value="songs" className="mt-4">
|
|
539
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary space-y-1 rounded-lg border p-2">
|
|
540
|
+
{songs.map((song) => (
|
|
541
|
+
<div
|
|
542
|
+
key={song.title}
|
|
543
|
+
className="hover:bg-fm-surface-primary flex items-center justify-between rounded-md px-3 py-2 transition-colors"
|
|
544
|
+
>
|
|
545
|
+
<div className="flex items-center gap-3">
|
|
546
|
+
<div className="bg-fm-surface-primary border-fm-divider-secondary flex h-9 w-9 shrink-0 items-center justify-center rounded-md border">
|
|
547
|
+
<MusicalNoteIcon className="text-fm-secondary h-4 w-4" />
|
|
548
|
+
</div>
|
|
549
|
+
<div>
|
|
550
|
+
<p className="text-fm-primary font-fm-text text-fm-md leading-fm-md">
|
|
551
|
+
{song.title}
|
|
552
|
+
</p>
|
|
553
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
554
|
+
{song.artist}
|
|
555
|
+
</p>
|
|
518
556
|
</div>
|
|
519
|
-
|
|
557
|
+
</div>
|
|
558
|
+
<span className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm tabular-nums">
|
|
559
|
+
{song.duration}
|
|
560
|
+
</span>
|
|
520
561
|
</div>
|
|
521
|
-
|
|
562
|
+
))}
|
|
563
|
+
</div>
|
|
564
|
+
</TabsContent>
|
|
522
565
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
</div>
|
|
542
|
-
</div>
|
|
543
|
-
<div className="text-right">
|
|
544
|
-
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
545
|
-
{album.tracks} tracks
|
|
546
|
-
</p>
|
|
547
|
-
<p className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm">
|
|
548
|
-
{album.year}
|
|
549
|
-
</p>
|
|
550
|
-
</div>
|
|
566
|
+
<TabsContent value="albums" className="mt-4">
|
|
567
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary space-y-1 rounded-lg border p-2">
|
|
568
|
+
{albums.map((album) => (
|
|
569
|
+
<div
|
|
570
|
+
key={album.title}
|
|
571
|
+
className="hover:bg-fm-surface-primary flex items-center justify-between rounded-md px-3 py-2 transition-colors"
|
|
572
|
+
>
|
|
573
|
+
<div className="flex items-center gap-3">
|
|
574
|
+
<div className="bg-fm-surface-primary border-fm-divider-secondary flex h-9 w-9 shrink-0 items-center justify-center rounded-md border">
|
|
575
|
+
<StarIcon className="text-fm-secondary h-4 w-4" />
|
|
576
|
+
</div>
|
|
577
|
+
<div>
|
|
578
|
+
<p className="text-fm-primary font-fm-text text-fm-md leading-fm-md">
|
|
579
|
+
{album.title}
|
|
580
|
+
</p>
|
|
581
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
582
|
+
{album.artist}
|
|
583
|
+
</p>
|
|
551
584
|
</div>
|
|
552
|
-
|
|
585
|
+
</div>
|
|
586
|
+
<span className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm tabular-nums">
|
|
587
|
+
{album.tracks} tracks
|
|
588
|
+
</span>
|
|
553
589
|
</div>
|
|
554
|
-
|
|
590
|
+
))}
|
|
591
|
+
</div>
|
|
592
|
+
</TabsContent>
|
|
555
593
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
</div>
|
|
575
|
-
</div>
|
|
576
|
-
<span className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm">
|
|
577
|
-
{artist.listeners}
|
|
578
|
-
</span>
|
|
594
|
+
<TabsContent value="artists" className="mt-4">
|
|
595
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary space-y-1 rounded-lg border p-2">
|
|
596
|
+
{artists.map((artist) => (
|
|
597
|
+
<div
|
|
598
|
+
key={artist.name}
|
|
599
|
+
className="hover:bg-fm-surface-primary flex items-center justify-between rounded-md px-3 py-2 transition-colors"
|
|
600
|
+
>
|
|
601
|
+
<div className="flex items-center gap-3">
|
|
602
|
+
<div className="bg-fm-surface-primary border-fm-divider-secondary flex h-9 w-9 shrink-0 items-center justify-center rounded-full border">
|
|
603
|
+
<HeartIcon className="text-fm-secondary h-4 w-4" />
|
|
604
|
+
</div>
|
|
605
|
+
<div>
|
|
606
|
+
<p className="text-fm-primary font-fm-text text-fm-md leading-fm-md">
|
|
607
|
+
{artist.name}
|
|
608
|
+
</p>
|
|
609
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
610
|
+
{artist.genre}
|
|
611
|
+
</p>
|
|
579
612
|
</div>
|
|
580
|
-
|
|
613
|
+
</div>
|
|
614
|
+
<span className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm tabular-nums">
|
|
615
|
+
{artist.listeners}
|
|
616
|
+
</span>
|
|
581
617
|
</div>
|
|
582
|
-
|
|
618
|
+
))}
|
|
619
|
+
</div>
|
|
620
|
+
</TabsContent>
|
|
583
621
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
622
|
+
<TabsContent value="about" className="mt-4">
|
|
623
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary space-y-1 rounded-lg border p-2">
|
|
624
|
+
{[
|
|
625
|
+
{ label: "Version", value: "2.4.1" },
|
|
626
|
+
{ label: "Last updated", value: "April 2026" },
|
|
627
|
+
{ label: "Audio quality", value: "Lossless" },
|
|
628
|
+
{ label: "Cache size", value: "1.2 GB" },
|
|
629
|
+
].map((row) => (
|
|
630
|
+
<div
|
|
631
|
+
key={row.label}
|
|
632
|
+
className="flex items-center justify-between rounded-md px-3 py-2"
|
|
633
|
+
>
|
|
634
|
+
<p className="text-fm-secondary font-fm-text text-fm-md leading-fm-md">
|
|
635
|
+
{row.label}
|
|
636
|
+
</p>
|
|
637
|
+
<p className="text-fm-primary font-fm-text text-fm-md leading-fm-md">
|
|
638
|
+
{row.value}
|
|
590
639
|
</p>
|
|
591
|
-
<div className="border-fm-divider-secondary bg-fm-surface-primary rounded-lg border px-4 py-3">
|
|
592
|
-
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-xl">
|
|
593
|
-
Version 2.4.1 · Last updated April 2026
|
|
594
|
-
</p>
|
|
595
|
-
</div>
|
|
596
640
|
</div>
|
|
597
|
-
|
|
598
|
-
</
|
|
599
|
-
</
|
|
600
|
-
</
|
|
641
|
+
))}
|
|
642
|
+
</div>
|
|
643
|
+
</TabsContent>
|
|
644
|
+
</Tabs>
|
|
601
645
|
</div>
|
|
602
646
|
</div>
|
|
603
647
|
)
|