@alpic-ai/ui 0.0.0 → 1.111.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/dist/components/alert.d.mts +1 -1
- package/dist/components/avatar.d.mts +1 -1
- package/dist/components/badge.d.mts +1 -1
- package/dist/components/button.d.mts +2 -2
- package/dist/components/combobox.mjs +1 -1
- package/dist/components/dialog.mjs +2 -2
- package/dist/components/form.d.mts +119 -0
- package/dist/components/form.mjs +192 -0
- package/dist/components/input.d.mts +2 -0
- package/dist/components/input.mjs +19 -10
- package/dist/components/select-trigger-variants.mjs +1 -0
- package/dist/components/select.d.mts +1 -9
- package/dist/components/select.mjs +8 -28
- package/dist/components/sidebar.d.mts +1 -1
- package/dist/components/sidebar.mjs +6 -6
- package/dist/components/spinner.d.mts +1 -1
- package/dist/components/status-dot.d.mts +1 -1
- package/dist/components/tabs.d.mts +1 -1
- package/dist/components/textarea.d.mts +2 -0
- package/dist/components/textarea.mjs +19 -10
- package/dist/components/toggle-group.d.mts +1 -1
- package/package.json +31 -40
- package/src/components/combobox.tsx +1 -1
- package/src/components/dialog.tsx +2 -2
- package/src/components/form.tsx +343 -0
- package/src/components/input.tsx +12 -0
- package/src/components/select-trigger-variants.ts +1 -0
- package/src/components/select.tsx +2 -35
- package/src/components/sidebar.tsx +8 -10
- package/src/components/textarea.tsx +12 -1
- package/src/stories/accordion-card.stories.tsx +53 -0
- package/src/stories/accordion.stories.tsx +65 -0
- package/src/stories/alert.stories.tsx +58 -0
- package/src/stories/attachment-tile.stories.tsx +37 -0
- package/src/stories/avatar.stories.tsx +54 -0
- package/src/stories/badge.stories.tsx +50 -0
- package/src/stories/breadcrumb.stories.tsx +107 -0
- package/src/stories/button.stories.tsx +342 -0
- package/src/stories/card.stories.tsx +89 -0
- package/src/stories/checkbox.stories.tsx +56 -0
- package/src/stories/collapsible.stories.tsx +69 -0
- package/src/stories/combobox.stories.tsx +214 -0
- package/src/stories/command.stories.tsx +95 -0
- package/src/stories/copyable.stories.tsx +29 -0
- package/src/stories/description-list.stories.tsx +71 -0
- package/src/stories/dialog.stories.tsx +135 -0
- package/src/stories/dropdown-menu.stories.tsx +191 -0
- package/src/stories/form.stories.tsx +91 -0
- package/src/stories/input-group.stories.tsx +63 -0
- package/src/stories/input.stories.tsx +72 -0
- package/src/stories/label.stories.tsx +26 -0
- package/src/stories/ladle.css +3 -0
- package/src/stories/pagination.stories.tsx +35 -0
- package/src/stories/popover.stories.tsx +34 -0
- package/src/stories/radio-group.stories.tsx +59 -0
- package/src/stories/scroll-area.stories.tsx +43 -0
- package/src/stories/select.stories.tsx +95 -0
- package/src/stories/separator.stories.tsx +36 -0
- package/src/stories/sheet.stories.tsx +76 -0
- package/src/stories/sidebar.stories.tsx +255 -0
- package/src/stories/skeleton.stories.tsx +47 -0
- package/src/stories/sonner.stories.tsx +91 -0
- package/src/stories/spinner.stories.tsx +66 -0
- package/src/stories/status-dot.stories.tsx +27 -0
- package/src/stories/switch.stories.tsx +46 -0
- package/src/stories/table.stories.tsx +242 -0
- package/src/stories/tabs.stories.tsx +169 -0
- package/src/stories/tag.stories.tsx +82 -0
- package/src/stories/textarea.stories.tsx +60 -0
- package/src/stories/toggle-group.stories.tsx +142 -0
- package/src/stories/tooltip-icon-button.stories.tsx +59 -0
- package/src/stories/tooltip.stories.tsx +54 -0
|
@@ -316,21 +316,19 @@ function SidebarHeader({ className, icon, title, children, ...props }: SidebarHe
|
|
|
316
316
|
<div
|
|
317
317
|
data-slot="sidebar-header"
|
|
318
318
|
data-sidebar="header"
|
|
319
|
-
className={cn("flex flex-col gap-2 p-2
|
|
319
|
+
className={cn("flex flex-col gap-2 p-2", className)}
|
|
320
320
|
{...props}
|
|
321
321
|
>
|
|
322
|
-
<div className="flex h-8 items-center gap-2 px-
|
|
322
|
+
<div className="flex h-8 items-center gap-2 px-3">
|
|
323
323
|
<div className="relative shrink-0">
|
|
324
324
|
<span className="transition-opacity group-data-[collapsible=icon]:group-hover:opacity-0">{icon}</span>
|
|
325
325
|
<div className="absolute inset-0 flex items-center justify-center opacity-0 transition-opacity group-data-[collapsible=icon]:group-hover:opacity-100">
|
|
326
|
-
<SidebarTrigger
|
|
326
|
+
<SidebarTrigger />
|
|
327
327
|
</div>
|
|
328
328
|
</div>
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
</span>
|
|
333
|
-
)}
|
|
329
|
+
<span className="text-foreground text-md min-w-0 truncate font-medium group-data-[collapsible=icon]:hidden">
|
|
330
|
+
{title}
|
|
331
|
+
</span>
|
|
334
332
|
<SidebarTrigger className="ml-auto shrink-0 group-data-[collapsible=icon]:hidden" />
|
|
335
333
|
</div>
|
|
336
334
|
{children}
|
|
@@ -376,7 +374,7 @@ function SidebarGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
376
374
|
<div
|
|
377
375
|
data-slot="sidebar-group"
|
|
378
376
|
data-sidebar="group"
|
|
379
|
-
className={cn("relative flex w-full min-w-0 flex-col
|
|
377
|
+
className={cn("relative flex w-full min-w-0 flex-col", className)}
|
|
380
378
|
{...props}
|
|
381
379
|
/>
|
|
382
380
|
);
|
|
@@ -453,7 +451,7 @@ function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) {
|
|
|
453
451
|
<li
|
|
454
452
|
data-slot="sidebar-menu-item"
|
|
455
453
|
data-sidebar="menu-item"
|
|
456
|
-
className={cn("group/menu-item relative", className)}
|
|
454
|
+
className={cn("group/menu-item relative px-3", className)}
|
|
457
455
|
{...props}
|
|
458
456
|
/>
|
|
459
457
|
);
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import { Info } from "lucide-react";
|
|
3
4
|
import * as React from "react";
|
|
4
5
|
|
|
5
6
|
import { cn } from "../lib/cn";
|
|
6
7
|
import { Label } from "./label";
|
|
8
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip";
|
|
7
9
|
|
|
8
10
|
interface TextareaProps extends React.ComponentProps<"textarea"> {
|
|
9
11
|
label?: string;
|
|
10
12
|
required?: boolean;
|
|
11
13
|
hint?: string;
|
|
12
14
|
error?: string;
|
|
15
|
+
tooltip?: string;
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
function Textarea({ className, id, label, required, hint, error, ...props }: TextareaProps) {
|
|
18
|
+
function Textarea({ className, id, label, required, hint, error, tooltip, ...props }: TextareaProps) {
|
|
16
19
|
const generatedId = React.useId();
|
|
17
20
|
const fieldId = id ?? generatedId;
|
|
18
21
|
|
|
@@ -51,6 +54,14 @@ function Textarea({ className, id, label, required, hint, error, ...props }: Tex
|
|
|
51
54
|
*
|
|
52
55
|
</span>
|
|
53
56
|
)}
|
|
57
|
+
{tooltip && (
|
|
58
|
+
<Tooltip>
|
|
59
|
+
<TooltipTrigger asChild>
|
|
60
|
+
<Info className="size-4 text-muted-foreground" />
|
|
61
|
+
</TooltipTrigger>
|
|
62
|
+
<TooltipContent>{tooltip}</TooltipContent>
|
|
63
|
+
</Tooltip>
|
|
64
|
+
)}
|
|
54
65
|
</div>
|
|
55
66
|
)}
|
|
56
67
|
{textarea}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Story } from "@ladle/react";
|
|
2
|
+
import {
|
|
3
|
+
AccordionCard,
|
|
4
|
+
AccordionCardContent,
|
|
5
|
+
AccordionCardHeader,
|
|
6
|
+
AccordionCardTitle,
|
|
7
|
+
} from "../components/accordion-card";
|
|
8
|
+
|
|
9
|
+
export const AllVariants: Story = () => (
|
|
10
|
+
<div className="flex flex-col gap-6 max-w-md">
|
|
11
|
+
<div className="flex flex-col gap-1.5">
|
|
12
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Default (collapsed)</p>
|
|
13
|
+
<AccordionCard>
|
|
14
|
+
<AccordionCardHeader>
|
|
15
|
+
<AccordionCardTitle>Logs</AccordionCardTitle>
|
|
16
|
+
</AccordionCardHeader>
|
|
17
|
+
<AccordionCardContent>Content inside the accordion card.</AccordionCardContent>
|
|
18
|
+
</AccordionCard>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<div className="flex flex-col gap-1.5">
|
|
22
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Default open</p>
|
|
23
|
+
<AccordionCard defaultOpen>
|
|
24
|
+
<AccordionCardHeader>
|
|
25
|
+
<AccordionCardTitle>Build settings</AccordionCardTitle>
|
|
26
|
+
</AccordionCardHeader>
|
|
27
|
+
<AccordionCardContent>
|
|
28
|
+
This card starts open. The chevron rotates to indicate the open state.
|
|
29
|
+
</AccordionCardContent>
|
|
30
|
+
</AccordionCard>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div className="flex flex-col gap-1.5">
|
|
34
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Without title component</p>
|
|
35
|
+
<AccordionCard>
|
|
36
|
+
<AccordionCardHeader>
|
|
37
|
+
<span className="type-text-sm font-medium">Environment Variables</span>
|
|
38
|
+
</AccordionCardHeader>
|
|
39
|
+
<AccordionCardContent>Header text can be any element, not just AccordionCardTitle.</AccordionCardContent>
|
|
40
|
+
</AccordionCard>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div className="flex flex-col gap-1.5">
|
|
44
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Disabled</p>
|
|
45
|
+
<AccordionCard disabled>
|
|
46
|
+
<AccordionCardHeader>
|
|
47
|
+
<AccordionCardTitle>Disabled card</AccordionCardTitle>
|
|
48
|
+
</AccordionCardHeader>
|
|
49
|
+
<AccordionCardContent>Cannot be opened.</AccordionCardContent>
|
|
50
|
+
</AccordionCard>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { Story } from "@ladle/react";
|
|
2
|
+
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "../components/accordion";
|
|
3
|
+
|
|
4
|
+
export const AllVariants: Story = () => (
|
|
5
|
+
<div className="flex flex-col gap-10 max-w-md">
|
|
6
|
+
<div className="flex flex-col gap-1.5">
|
|
7
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Single (collapsible)</p>
|
|
8
|
+
<Accordion type="single" collapsible>
|
|
9
|
+
<AccordionItem value="item-1">
|
|
10
|
+
<AccordionTrigger>What is Alpic?</AccordionTrigger>
|
|
11
|
+
<AccordionContent>
|
|
12
|
+
Alpic is a multi-tenant SaaS platform for deploying MCP servers. It handles infrastructure, scaling, and
|
|
13
|
+
distribution so you can focus on building.
|
|
14
|
+
</AccordionContent>
|
|
15
|
+
</AccordionItem>
|
|
16
|
+
<AccordionItem value="item-2">
|
|
17
|
+
<AccordionTrigger>How do I deploy?</AccordionTrigger>
|
|
18
|
+
<AccordionContent>
|
|
19
|
+
Use the Alpic CLI to deploy your MCP server with a single command. The platform handles containerization,
|
|
20
|
+
routing, and scaling automatically.
|
|
21
|
+
</AccordionContent>
|
|
22
|
+
</AccordionItem>
|
|
23
|
+
<AccordionItem value="item-3">
|
|
24
|
+
<AccordionTrigger>What languages are supported?</AccordionTrigger>
|
|
25
|
+
<AccordionContent>
|
|
26
|
+
Any language that can run in a container. TypeScript, Python, Go, Rust, and more are all supported out of
|
|
27
|
+
the box with pre-built runtime images.
|
|
28
|
+
</AccordionContent>
|
|
29
|
+
</AccordionItem>
|
|
30
|
+
</Accordion>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div className="flex flex-col gap-1.5">
|
|
34
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Multiple</p>
|
|
35
|
+
<Accordion type="multiple" defaultValue={["item-1", "item-3"]}>
|
|
36
|
+
<AccordionItem value="item-1">
|
|
37
|
+
<AccordionTrigger>First item (open by default)</AccordionTrigger>
|
|
38
|
+
<AccordionContent>Content for the first item. Multiple items can be open at the same time.</AccordionContent>
|
|
39
|
+
</AccordionItem>
|
|
40
|
+
<AccordionItem value="item-2">
|
|
41
|
+
<AccordionTrigger>Second item</AccordionTrigger>
|
|
42
|
+
<AccordionContent>Content for the second item.</AccordionContent>
|
|
43
|
+
</AccordionItem>
|
|
44
|
+
<AccordionItem value="item-3">
|
|
45
|
+
<AccordionTrigger>Third item (open by default)</AccordionTrigger>
|
|
46
|
+
<AccordionContent>Content for the third item.</AccordionContent>
|
|
47
|
+
</AccordionItem>
|
|
48
|
+
</Accordion>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<div className="flex flex-col gap-1.5">
|
|
52
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Disabled</p>
|
|
53
|
+
<Accordion type="single" collapsible>
|
|
54
|
+
<AccordionItem value="item-1">
|
|
55
|
+
<AccordionTrigger>Enabled item</AccordionTrigger>
|
|
56
|
+
<AccordionContent>This item can be toggled.</AccordionContent>
|
|
57
|
+
</AccordionItem>
|
|
58
|
+
<AccordionItem value="item-2" disabled>
|
|
59
|
+
<AccordionTrigger>Disabled item</AccordionTrigger>
|
|
60
|
+
<AccordionContent>This content cannot be reached.</AccordionContent>
|
|
61
|
+
</AccordionItem>
|
|
62
|
+
</Accordion>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Story } from "@ladle/react";
|
|
2
|
+
import { AlertCircle, AlertTriangle, CheckCircle2, Info } from "lucide-react";
|
|
3
|
+
|
|
4
|
+
import { Alert, AlertDescription, AlertTitle, ErrorAlert, WarningAlert } from "../components/alert";
|
|
5
|
+
|
|
6
|
+
export const AllVariants: Story = () => (
|
|
7
|
+
<div className="flex flex-col gap-4 max-w-xl p-6">
|
|
8
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Default</p>
|
|
9
|
+
<Alert>
|
|
10
|
+
<Info />
|
|
11
|
+
<AlertTitle>Best on desktop</AlertTitle>
|
|
12
|
+
<AlertDescription>
|
|
13
|
+
This site isn't optimised for small screens. For the best experience we recommend using a desktop or tablet.
|
|
14
|
+
</AlertDescription>
|
|
15
|
+
</Alert>
|
|
16
|
+
|
|
17
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Destructive</p>
|
|
18
|
+
<Alert variant="destructive">
|
|
19
|
+
<AlertCircle />
|
|
20
|
+
<AlertTitle>Clone failed</AlertTitle>
|
|
21
|
+
<AlertDescription>Unable to clone the repository. Check your credentials and try again.</AlertDescription>
|
|
22
|
+
</Alert>
|
|
23
|
+
|
|
24
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Warning</p>
|
|
25
|
+
<Alert variant="warning">
|
|
26
|
+
<AlertTriangle />
|
|
27
|
+
<AlertTitle>API key expiring soon</AlertTitle>
|
|
28
|
+
<AlertDescription>Your API key expires in 3 days. Rotate it to avoid service interruption.</AlertDescription>
|
|
29
|
+
</Alert>
|
|
30
|
+
|
|
31
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Success</p>
|
|
32
|
+
<Alert variant="success">
|
|
33
|
+
<CheckCircle2 />
|
|
34
|
+
<AlertTitle>Deployment complete</AlertTitle>
|
|
35
|
+
<AlertDescription>Your project was deployed successfully and is now live.</AlertDescription>
|
|
36
|
+
</Alert>
|
|
37
|
+
|
|
38
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Description only (no title)</p>
|
|
39
|
+
<Alert variant="destructive">
|
|
40
|
+
<AlertCircle />
|
|
41
|
+
<AlertDescription>
|
|
42
|
+
This is the only time you'll be able to see this API key. Make sure to copy it and store it securely.
|
|
43
|
+
</AlertDescription>
|
|
44
|
+
</Alert>
|
|
45
|
+
|
|
46
|
+
<p className="type-text-xs font-medium text-subtle-foreground">ErrorAlert (pre-composed)</p>
|
|
47
|
+
<ErrorAlert />
|
|
48
|
+
|
|
49
|
+
<p className="type-text-xs font-medium text-subtle-foreground">ErrorAlert (custom)</p>
|
|
50
|
+
<ErrorAlert title="Error loading projects" description="Failed to fetch your projects. Please refresh the page." />
|
|
51
|
+
|
|
52
|
+
<p className="type-text-xs font-medium text-subtle-foreground">WarningAlert</p>
|
|
53
|
+
<WarningAlert
|
|
54
|
+
title="Save your API key"
|
|
55
|
+
description="This is the only time you'll be able to see this API key. Make sure to copy it and store it securely."
|
|
56
|
+
/>
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Story } from "@ladle/react";
|
|
2
|
+
import { AttachmentTile } from "../components/attachment-tile";
|
|
3
|
+
|
|
4
|
+
export const AllVariants: Story = () => (
|
|
5
|
+
<div className="flex flex-col gap-10 p-10">
|
|
6
|
+
<div className="flex flex-col gap-1.5">
|
|
7
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Image attachment (with remove)</p>
|
|
8
|
+
<div className="flex gap-3">
|
|
9
|
+
<AttachmentTile
|
|
10
|
+
src="https://picsum.photos/seed/a/200/200"
|
|
11
|
+
isImage
|
|
12
|
+
onRemove={() => alert("Remove clicked")}
|
|
13
|
+
onClick={() => alert("Preview clicked")}
|
|
14
|
+
/>
|
|
15
|
+
<AttachmentTile
|
|
16
|
+
src="https://picsum.photos/seed/b/200/200"
|
|
17
|
+
isImage
|
|
18
|
+
onRemove={() => alert("Remove clicked")}
|
|
19
|
+
onClick={() => alert("Preview clicked")}
|
|
20
|
+
/>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div className="flex flex-col gap-1.5">
|
|
25
|
+
<p className="type-text-xs font-medium text-subtle-foreground">File attachment (fallback icon)</p>
|
|
26
|
+
<AttachmentTile onRemove={() => alert("Remove clicked")} onClick={() => alert("Preview clicked")} />
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<div className="flex flex-col gap-1.5">
|
|
30
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Read-only (no remove button)</p>
|
|
31
|
+
<div className="flex gap-3">
|
|
32
|
+
<AttachmentTile src="https://picsum.photos/seed/c/200/200" isImage />
|
|
33
|
+
<AttachmentTile />
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Story } from "@ladle/react";
|
|
2
|
+
import { Avatar, AvatarFallback, AvatarImage, AvatarLabelGroup } from "../components/avatar";
|
|
3
|
+
|
|
4
|
+
const DEMO_SRC = "https://i.pravatar.cc/150";
|
|
5
|
+
const SIZES = ["xs", "sm", "md", "lg", "xl"] as const;
|
|
6
|
+
|
|
7
|
+
export const AllVariants: Story = () => (
|
|
8
|
+
<div className="flex flex-col gap-8 p-6 bg-background">
|
|
9
|
+
<div className="flex flex-col gap-3">
|
|
10
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Sizes — with image</p>
|
|
11
|
+
<div className="flex items-center gap-4">
|
|
12
|
+
{SIZES.map((size) => (
|
|
13
|
+
<Avatar key={size} size={size}>
|
|
14
|
+
<AvatarImage src={DEMO_SRC} alt="User" />
|
|
15
|
+
<AvatarFallback>JD</AvatarFallback>
|
|
16
|
+
</Avatar>
|
|
17
|
+
))}
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<div className="flex flex-col gap-3">
|
|
22
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Sizes — fallback (no image)</p>
|
|
23
|
+
<div className="flex items-center gap-4">
|
|
24
|
+
{SIZES.map((size) => (
|
|
25
|
+
<Avatar key={size} size={size}>
|
|
26
|
+
<AvatarFallback>OR</AvatarFallback>
|
|
27
|
+
</Avatar>
|
|
28
|
+
))}
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<div className="flex flex-col gap-3">
|
|
33
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Online status indicator</p>
|
|
34
|
+
<div className="flex items-center gap-4">
|
|
35
|
+
{SIZES.map((size) => (
|
|
36
|
+
<Avatar key={size} size={size} status="online">
|
|
37
|
+
<AvatarImage src={DEMO_SRC} alt="User" />
|
|
38
|
+
<AvatarFallback>JD</AvatarFallback>
|
|
39
|
+
</Avatar>
|
|
40
|
+
))}
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div className="flex flex-col gap-3">
|
|
45
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Label group</p>
|
|
46
|
+
<div className="flex flex-col gap-4">
|
|
47
|
+
<AvatarLabelGroup size="sm" src={DEMO_SRC} name="Alice Martin" label="alice@example.com" />
|
|
48
|
+
<AvatarLabelGroup size="md" src={DEMO_SRC} name="Bob Dupont" label="bob@example.com" />
|
|
49
|
+
<AvatarLabelGroup size="md" src={DEMO_SRC} name="Charly Bernard" label="charly@example.com" status="online" />
|
|
50
|
+
<AvatarLabelGroup size="md" name="Daniel Wilson" label="daniel@example.com" />
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Story } from "@ladle/react";
|
|
2
|
+
import { AlertTriangle, CheckCircle2, XCircle } from "lucide-react";
|
|
3
|
+
|
|
4
|
+
import { Badge } from "../components/badge";
|
|
5
|
+
|
|
6
|
+
export const AllVariants: Story = () => (
|
|
7
|
+
<div className="flex flex-col gap-6">
|
|
8
|
+
<div className="flex flex-col gap-1.5">
|
|
9
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Medium (default)</p>
|
|
10
|
+
<div className="flex items-center gap-2">
|
|
11
|
+
<Badge variant="primary">Primary</Badge>
|
|
12
|
+
<Badge>Secondary</Badge>
|
|
13
|
+
<Badge variant="success">
|
|
14
|
+
<CheckCircle2 />
|
|
15
|
+
Success
|
|
16
|
+
</Badge>
|
|
17
|
+
<Badge variant="warning">
|
|
18
|
+
<AlertTriangle />
|
|
19
|
+
Warning
|
|
20
|
+
</Badge>
|
|
21
|
+
<Badge variant="error">
|
|
22
|
+
<XCircle />
|
|
23
|
+
Error
|
|
24
|
+
</Badge>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div className="flex flex-col gap-1.5">
|
|
29
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Small</p>
|
|
30
|
+
<div className="flex items-center gap-2">
|
|
31
|
+
<Badge size="sm" variant="primary">
|
|
32
|
+
Primary
|
|
33
|
+
</Badge>
|
|
34
|
+
<Badge size="sm">Secondary</Badge>
|
|
35
|
+
<Badge size="sm" variant="success">
|
|
36
|
+
<CheckCircle2 />
|
|
37
|
+
Success
|
|
38
|
+
</Badge>
|
|
39
|
+
<Badge size="sm" variant="warning">
|
|
40
|
+
<AlertTriangle />
|
|
41
|
+
Warning
|
|
42
|
+
</Badge>
|
|
43
|
+
<Badge size="sm" variant="error">
|
|
44
|
+
<XCircle />
|
|
45
|
+
Error
|
|
46
|
+
</Badge>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { Story } from "@ladle/react";
|
|
2
|
+
import { Home } from "lucide-react";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import {
|
|
5
|
+
Breadcrumb,
|
|
6
|
+
BreadcrumbChevron,
|
|
7
|
+
BreadcrumbItem,
|
|
8
|
+
BreadcrumbLink,
|
|
9
|
+
BreadcrumbList,
|
|
10
|
+
BreadcrumbPage,
|
|
11
|
+
BreadcrumbSeparator,
|
|
12
|
+
} from "../components/breadcrumb";
|
|
13
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../components/dropdown-menu";
|
|
14
|
+
|
|
15
|
+
const TREE: Record<string, string[]> = {
|
|
16
|
+
Home: ["Projects", "Settings", "Billing"],
|
|
17
|
+
Projects: ["my-mcp-server", "weather-api", "slack-bot"],
|
|
18
|
+
"my-mcp-server": ["Deployments", "Logs", "Environment"],
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const AllVariants: Story = () => {
|
|
22
|
+
const [trail, setTrail] = useState(["Home", "Projects", "my-mcp-server"]);
|
|
23
|
+
|
|
24
|
+
function handleSelect(index: number, option: string) {
|
|
25
|
+
setTrail([...trail.slice(0, index + 1), option]);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div className="flex flex-col gap-10">
|
|
30
|
+
<div className="flex flex-col gap-1.5">
|
|
31
|
+
<p className="type-text-xs font-medium text-subtle-foreground">
|
|
32
|
+
Interactive — click items to navigate, click chevrons for dropdown
|
|
33
|
+
</p>
|
|
34
|
+
<Breadcrumb>
|
|
35
|
+
<BreadcrumbList>
|
|
36
|
+
{trail.map((page, index) => {
|
|
37
|
+
const isLast = index === trail.length - 1;
|
|
38
|
+
const children = TREE[page];
|
|
39
|
+
return (
|
|
40
|
+
<li key={page} className="contents">
|
|
41
|
+
{index > 0 && <BreadcrumbSeparator />}
|
|
42
|
+
<DropdownMenu>
|
|
43
|
+
<DropdownMenuTrigger asChild>
|
|
44
|
+
<BreadcrumbItem className="cursor-pointer focus-visible:ring-2 focus-visible:ring-ring outline-none">
|
|
45
|
+
{isLast ? (
|
|
46
|
+
<BreadcrumbPage>{page}</BreadcrumbPage>
|
|
47
|
+
) : (
|
|
48
|
+
<span className="type-text-sm font-medium text-subtle-foreground">{page}</span>
|
|
49
|
+
)}
|
|
50
|
+
{children && <BreadcrumbChevron />}
|
|
51
|
+
</BreadcrumbItem>
|
|
52
|
+
</DropdownMenuTrigger>
|
|
53
|
+
{children && (
|
|
54
|
+
<DropdownMenuContent align="start">
|
|
55
|
+
{children.map((child) => (
|
|
56
|
+
<DropdownMenuItem key={child} onSelect={() => handleSelect(index, child)}>
|
|
57
|
+
{child}
|
|
58
|
+
</DropdownMenuItem>
|
|
59
|
+
))}
|
|
60
|
+
</DropdownMenuContent>
|
|
61
|
+
)}
|
|
62
|
+
</DropdownMenu>
|
|
63
|
+
</li>
|
|
64
|
+
);
|
|
65
|
+
})}
|
|
66
|
+
</BreadcrumbList>
|
|
67
|
+
</Breadcrumb>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div className="flex flex-col gap-1.5">
|
|
71
|
+
<p className="type-text-xs font-medium text-subtle-foreground">With home icon (static)</p>
|
|
72
|
+
<Breadcrumb>
|
|
73
|
+
<BreadcrumbList>
|
|
74
|
+
<BreadcrumbItem>
|
|
75
|
+
<BreadcrumbLink href="#">
|
|
76
|
+
<Home className="size-5" />
|
|
77
|
+
</BreadcrumbLink>
|
|
78
|
+
</BreadcrumbItem>
|
|
79
|
+
<BreadcrumbSeparator />
|
|
80
|
+
<BreadcrumbItem>
|
|
81
|
+
<BreadcrumbLink href="#">Projects</BreadcrumbLink>
|
|
82
|
+
</BreadcrumbItem>
|
|
83
|
+
<BreadcrumbSeparator />
|
|
84
|
+
<BreadcrumbItem>
|
|
85
|
+
<BreadcrumbPage>my-mcp-server</BreadcrumbPage>
|
|
86
|
+
</BreadcrumbItem>
|
|
87
|
+
</BreadcrumbList>
|
|
88
|
+
</Breadcrumb>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<div className="flex flex-col gap-1.5">
|
|
92
|
+
<p className="type-text-xs font-medium text-subtle-foreground">Simple — two levels</p>
|
|
93
|
+
<Breadcrumb>
|
|
94
|
+
<BreadcrumbList>
|
|
95
|
+
<BreadcrumbItem>
|
|
96
|
+
<BreadcrumbLink href="#">Projects</BreadcrumbLink>
|
|
97
|
+
</BreadcrumbItem>
|
|
98
|
+
<BreadcrumbSeparator />
|
|
99
|
+
<BreadcrumbItem>
|
|
100
|
+
<BreadcrumbPage>my-mcp-server</BreadcrumbPage>
|
|
101
|
+
</BreadcrumbItem>
|
|
102
|
+
</BreadcrumbList>
|
|
103
|
+
</Breadcrumb>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
};
|