feat: move away from carbon components and TinyMCE (#597)
* feat: remove tinymce & replace org sidebar * chore: PR Fixes * chore: move ui font into src dir * remove files in vite config * use google font import for loading font * remove custom font * more fonts update * remove font bold * more removals of font bold * fix import * checkpoint * chore: checkpoint (add course & lms shadcn sidebar) * minor css improvements and try out font sans * chore: replace carbon components with shadcn's * chore: replace carbon components with shadcn _ v3 * chore: ui fixes & storybook update * feat: UI cleanup * fix: quick ui fixes * chore: update pnpm-lock.yaml with new dependencies and versions; fix output.css formatting * chore: add isloading to button * feat: add loading state to button stories * chore: feedback fixes * fix: feedback fixes * chore: remove console * fix: PR comments * fix: PR comments --------- Co-authored-by: Rotimi Best <best@classroomio.com>
This commit is contained in:
co-authored by
Rotimi Best
parent
2145782385
commit
cbf6ae7e63
@@ -0,0 +1,98 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import * as Accordion from '@cio/ui/base/accordion';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Accordion',
|
||||
component: Accordion.Root,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Accordion.Root type="single" class="w-[450px]">
|
||||
<Accordion.Item value="item-1">
|
||||
<Accordion.Trigger>Is it accessible?</Accordion.Trigger>
|
||||
<Accordion.Content>
|
||||
Yes. It adheres to the WAI-ARIA design pattern and includes proper keyboard navigation support.
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
<Accordion.Item value="item-2">
|
||||
<Accordion.Trigger>Is it styled?</Accordion.Trigger>
|
||||
<Accordion.Content>
|
||||
Yes. It comes with default styles that matches the other components' aesthetic.
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
<Accordion.Item value="item-3">
|
||||
<Accordion.Trigger>Is it animated?</Accordion.Trigger>
|
||||
<Accordion.Content>Yes. It's animated by default, but you can disable it if you prefer.</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
</Accordion.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Single Expanded">
|
||||
{#snippet template()}
|
||||
<Accordion.Root type="single" class="w-[450px]">
|
||||
<Accordion.Item value="item-1">
|
||||
<Accordion.Trigger>What is ClassroomIO?</Accordion.Trigger>
|
||||
<Accordion.Content>
|
||||
ClassroomIO is an open-source learning management system designed to help educators create and manage online
|
||||
courses efficiently.
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
<Accordion.Item value="item-2">
|
||||
<Accordion.Trigger>How do I get started?</Accordion.Trigger>
|
||||
<Accordion.Content>
|
||||
You can get started by creating an account, setting up your organization, and creating your first course. Our
|
||||
documentation provides step-by-step guides.
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
<Accordion.Item value="item-3">
|
||||
<Accordion.Trigger>Is it free to use?</Accordion.Trigger>
|
||||
<Accordion.Content>
|
||||
Yes! ClassroomIO is open-source and free to use. We also offer premium features for organizations that need
|
||||
additional capabilities.
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
</Accordion.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Multiple Expanded">
|
||||
{#snippet template()}
|
||||
<Accordion.Root type="multiple" class="w-[450px]">
|
||||
<Accordion.Item value="features">
|
||||
<Accordion.Trigger>Features</Accordion.Trigger>
|
||||
<Accordion.Content>
|
||||
<ul class="list-disc space-y-1 pl-4">
|
||||
<li>Course management</li>
|
||||
<li>Student analytics</li>
|
||||
<li>AI-powered grading</li>
|
||||
<li>Custom certificates</li>
|
||||
</ul>
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
<Accordion.Item value="pricing">
|
||||
<Accordion.Trigger>Pricing</Accordion.Trigger>
|
||||
<Accordion.Content>
|
||||
We offer flexible pricing plans for individuals, teams, and enterprises. Contact us for more information.
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
<Accordion.Item value="support">
|
||||
<Accordion.Trigger>Support</Accordion.Trigger>
|
||||
<Accordion.Content>
|
||||
We provide email support, documentation, and community forums to help you succeed.
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
</Accordion.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,12 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Accordion } from '@cio/ui/base/accordion';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Accordion>)[] = [
|
||||
'type',
|
||||
'value',
|
||||
'onValueChange',
|
||||
'disabled',
|
||||
'name',
|
||||
'loop',
|
||||
'orientation'
|
||||
];
|
||||
@@ -0,0 +1,44 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Avatar, AvatarImage, AvatarFallback } from '@cio/ui/base/avatar';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Avatar',
|
||||
component: Avatar,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Avatar>
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Fallback">
|
||||
{#snippet template()}
|
||||
<Avatar>
|
||||
<AvatarImage src="https://invalid-url.com/image.png" alt="@user" />
|
||||
<AvatarFallback>AB</AvatarFallback>
|
||||
</Avatar>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Custom Size">
|
||||
{#snippet template()}
|
||||
<Avatar class="h-20 w-20">
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,4 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Avatar } from '@cio/ui/base/avatar';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Avatar>)[] = ['loadingStatus', 'onLoadingStatusChange', 'delayMs'];
|
||||
@@ -0,0 +1,48 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Badge } from '@cio/ui/base/badge';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Badge',
|
||||
component: Badge,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Badge>Default Badge</Badge>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Secondary">
|
||||
{#snippet template()}
|
||||
<Badge variant="secondary">Secondary</Badge>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Destructive">
|
||||
{#snippet template()}
|
||||
<Badge variant="destructive">Destructive</Badge>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Outline">
|
||||
{#snippet template()}
|
||||
<Badge variant="outline">Outline</Badge>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Multiple Badges">
|
||||
{#snippet template()}
|
||||
<div class="flex gap-2">
|
||||
<Badge>Default</Badge>
|
||||
<Badge variant="secondary">Secondary</Badge>
|
||||
<Badge variant="destructive">Destructive</Badge>
|
||||
<Badge variant="outline">Outline</Badge>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,65 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbEllipsis,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator
|
||||
} from '@cio/ui/base/breadcrumb';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Breadcrumb',
|
||||
component: Breadcrumb,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="/">Home</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="/components">Components</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Ellipsis">
|
||||
{#snippet template()}
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="/">Home</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbEllipsis />
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="/components">Components</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -70,6 +70,12 @@
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Loading">
|
||||
{#snippet template(args)}
|
||||
<Button {...args} isLoading>Loading Button</Button>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="As Link">
|
||||
{#snippet template(args)}
|
||||
<Button {...args} href="#">Link Button</Button>
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Checkbox } from '@cio/ui/base/checkbox';
|
||||
import { Label } from '@cio/ui/base/label';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Checkbox',
|
||||
component: Checkbox,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Checkbox />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Label">
|
||||
{#snippet template()}
|
||||
<div class="flex items-center space-x-2">
|
||||
<Checkbox id="terms" />
|
||||
<Label for="terms">Accept terms and conditions</Label>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Checked">
|
||||
{#snippet template()}
|
||||
<div class="flex items-center space-x-2">
|
||||
<Checkbox checked={true} />
|
||||
<Label>Checked by default</Label>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Disabled">
|
||||
{#snippet template()}
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex items-center space-x-2">
|
||||
<Checkbox disabled />
|
||||
<Label>Disabled unchecked</Label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<Checkbox disabled checked={true} />
|
||||
<Label>Disabled checked</Label>
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,11 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Checkbox } from '@cio/ui/base/checkbox';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Checkbox>)[] = [
|
||||
'checked',
|
||||
'onCheckedChange',
|
||||
'disabled',
|
||||
'name',
|
||||
'value',
|
||||
'required'
|
||||
];
|
||||
@@ -0,0 +1,52 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@cio/ui/base/collapsible';
|
||||
import { Button } from '@cio/ui';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Collapsible',
|
||||
component: Collapsible,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Collapsible class="w-[350px] space-y-2">
|
||||
<div class="flex items-center justify-between space-x-4 px-4">
|
||||
<h4 class="text-sm font-semibold">@peduarte starred 3 repositories</h4>
|
||||
<CollapsibleTrigger>
|
||||
<Button.Root variant="ghost" size="sm" class="w-9 p-0">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="h-4 w-4"
|
||||
>
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
<span class="sr-only">Toggle</span>
|
||||
</Button.Root>
|
||||
</CollapsibleTrigger>
|
||||
</div>
|
||||
<div class="rounded-md border px-4 py-3 font-mono text-sm">@radix-ui/primitives</div>
|
||||
<CollapsibleContent class="space-y-2">
|
||||
<div class="rounded-md border px-4 py-3 font-mono text-sm">@radix-ui/colors</div>
|
||||
<div class="rounded-md border px-4 py-3 font-mono text-sm">@stitches/react</div>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,9 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Collapsible } from '@cio/ui/base/collapsible';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Collapsible>)[] = [
|
||||
'open',
|
||||
'onOpenChange',
|
||||
'onOpenChangeComplete',
|
||||
'disabled'
|
||||
];
|
||||
@@ -0,0 +1,54 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Command } from '@cio/ui';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Command',
|
||||
component: Command.Root,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Command.Root class="rounded-lg border shadow-md">
|
||||
<Command.CommandInput placeholder="Type a command or search..." />
|
||||
<Command.CommandList>
|
||||
<Command.CommandEmpty>No results found.</Command.CommandEmpty>
|
||||
<Command.CommandGroup heading="Suggestions">
|
||||
<Command.CommandItem>
|
||||
<span>Calendar</span>
|
||||
</Command.CommandItem>
|
||||
<Command.CommandItem>
|
||||
<span>Search Emoji</span>
|
||||
</Command.CommandItem>
|
||||
<Command.CommandItem>
|
||||
<span>Calculator</span>
|
||||
</Command.CommandItem>
|
||||
</Command.CommandGroup>
|
||||
<Command.CommandSeparator />
|
||||
<Command.CommandGroup heading="Settings">
|
||||
<Command.CommandItem>
|
||||
<span>Profile</span>
|
||||
<Command.CommandShortcut>⌘P</Command.CommandShortcut>
|
||||
</Command.CommandItem>
|
||||
<Command.CommandItem>
|
||||
<span>Billing</span>
|
||||
<Command.CommandShortcut>⌘B</Command.CommandShortcut>
|
||||
</Command.CommandItem>
|
||||
<Command.CommandItem>
|
||||
<span>Settings</span>
|
||||
<Command.CommandShortcut>⌘S</Command.CommandShortcut>
|
||||
</Command.CommandItem>
|
||||
</Command.CommandGroup>
|
||||
</Command.CommandList>
|
||||
</Command.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,11 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Command } from '@cio/ui/base/command';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Command>)[] = [
|
||||
'value',
|
||||
'onValueChange',
|
||||
'label',
|
||||
'filter',
|
||||
'columns',
|
||||
'disablePointerSelection'
|
||||
];
|
||||
@@ -0,0 +1,82 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Dialog, Button, Input, Label } from '@cio/ui';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Dialog',
|
||||
component: Dialog.Root,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
argTypes: {
|
||||
open: {
|
||||
control: 'boolean',
|
||||
description: 'Whether the dialog is open',
|
||||
table: { defaultValue: { summary: 'false' } }
|
||||
},
|
||||
onOpenChange: {
|
||||
control: false,
|
||||
description: 'Callback function called when the open state changes',
|
||||
table: {
|
||||
type: { summary: '(open: boolean) => void' },
|
||||
defaultValue: { summary: 'undefined' }
|
||||
}
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template(args)}
|
||||
<Dialog.Root {...args}>
|
||||
<Dialog.DialogTrigger>
|
||||
<Button.Root>Open Dialog</Button.Root>
|
||||
</Dialog.DialogTrigger>
|
||||
<Dialog.DialogContent>
|
||||
<Dialog.DialogHeader>
|
||||
<Dialog.DialogTitle>Dialog Title</Dialog.DialogTitle>
|
||||
<Dialog.DialogDescription>This is a description of what the dialog is for.</Dialog.DialogDescription>
|
||||
</Dialog.DialogHeader>
|
||||
<div class="py-4">
|
||||
<p>Dialog content goes here.</p>
|
||||
</div>
|
||||
</Dialog.DialogContent>
|
||||
</Dialog.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Form">
|
||||
{#snippet template(args)}
|
||||
<Dialog.Root {...args}>
|
||||
<Dialog.DialogTrigger>
|
||||
<Button.Root>Edit Profile</Button.Root>
|
||||
</Dialog.DialogTrigger>
|
||||
<Dialog.DialogContent>
|
||||
<Dialog.DialogHeader>
|
||||
<Dialog.DialogTitle>Edit profile</Dialog.DialogTitle>
|
||||
<Dialog.DialogDescription
|
||||
>Make changes to your profile here. Click save when you're done.</Dialog.DialogDescription
|
||||
>
|
||||
</Dialog.DialogHeader>
|
||||
<div class="grid gap-4 py-4">
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label.Root for="name" class="text-right">Name</Label.Root>
|
||||
<Input.Root id="name" value="John Doe" class="col-span-3" />
|
||||
</div>
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label.Root for="username" class="text-right">Username</Label.Root>
|
||||
<Input.Root id="username" value="@johndoe" class="col-span-3" />
|
||||
</div>
|
||||
</div>
|
||||
<Dialog.DialogFooter>
|
||||
<Button.Root type="submit">Save changes</Button.Root>
|
||||
</Dialog.DialogFooter>
|
||||
</Dialog.DialogContent>
|
||||
</Dialog.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,4 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import * as Dialog from '@cio/ui/base/dialog';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Dialog.Root>)[] = ['open', 'onOpenChange'];
|
||||
@@ -1,6 +1,7 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { DropdownMenu, Button } from '@cio/ui';
|
||||
import { Button } from '@cio/ui';
|
||||
import * as DropdownMenu from '@cio/ui/base/dropdown-menu';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/DropdownMenu',
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Label } from '@cio/ui/base/label';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Label>)[] = ['children', 'child'];
|
||||
@@ -0,0 +1,45 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Label } from '@cio/ui/base/label';
|
||||
import { Input } from '@cio/ui/base/input';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Label',
|
||||
component: Label,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Label>Email</Label>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Input">
|
||||
{#snippet template()}
|
||||
<div class="grid w-full max-w-sm items-center gap-1.5">
|
||||
<Label for="email">Email</Label>
|
||||
<Input type="email" id="email" placeholder="Email" />
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Required">
|
||||
{#snippet template()}
|
||||
<div class="grid w-full max-w-sm items-center gap-1.5">
|
||||
<Label for="username">
|
||||
Username
|
||||
<span class="text-red-500">*</span>
|
||||
</Label>
|
||||
<Input id="username" placeholder="Username" required />
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,10 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Menubar } from '@cio/ui/base/menubar';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Menubar>)[] = [
|
||||
'onValueChange',
|
||||
'value',
|
||||
'dir',
|
||||
'onOpenChange',
|
||||
'disabled'
|
||||
];
|
||||
@@ -0,0 +1,90 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import * as Menubar from '@cio/ui/base/menubar';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Menubar',
|
||||
component: Menubar.Root,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
argTypes: {
|
||||
value: {
|
||||
control: 'text',
|
||||
description: 'The controlled value of the active menu'
|
||||
},
|
||||
onValueChange: {
|
||||
control: false,
|
||||
description: 'Callback function when the active menu changes'
|
||||
},
|
||||
dir: {
|
||||
control: 'select',
|
||||
options: ['ltr', 'rtl'],
|
||||
description: 'The reading direction of the menubar'
|
||||
},
|
||||
onOpenChange: {
|
||||
control: false,
|
||||
description: 'Callback function when the open state changes'
|
||||
},
|
||||
ref: {
|
||||
control: false,
|
||||
description: 'The underlying DOM element reference'
|
||||
},
|
||||
disabled: {
|
||||
control: 'boolean',
|
||||
description: 'Whether the menubar is disabled'
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Menubar.Root>
|
||||
<Menubar.Menu>
|
||||
<Menubar.Trigger>File</Menubar.Trigger>
|
||||
<Menubar.Content>
|
||||
<Menubar.Item>
|
||||
New Tab <span class="ml-auto text-xs">⌘T</span>
|
||||
</Menubar.Item>
|
||||
<Menubar.Item>
|
||||
New Window <span class="ml-auto text-xs">⌘N</span>
|
||||
</Menubar.Item>
|
||||
<Menubar.Separator />
|
||||
<Menubar.Item>Share</Menubar.Item>
|
||||
<Menubar.Separator />
|
||||
<Menubar.Item>Print</Menubar.Item>
|
||||
</Menubar.Content>
|
||||
</Menubar.Menu>
|
||||
<Menubar.Menu>
|
||||
<Menubar.Trigger>Edit</Menubar.Trigger>
|
||||
<Menubar.Content>
|
||||
<Menubar.Item>
|
||||
Undo <span class="ml-auto text-xs">⌘Z</span>
|
||||
</Menubar.Item>
|
||||
<Menubar.Item>
|
||||
Redo <span class="ml-auto text-xs">⇧⌘Z</span>
|
||||
</Menubar.Item>
|
||||
<Menubar.Separator />
|
||||
<Menubar.Item>Cut</Menubar.Item>
|
||||
<Menubar.Item>Copy</Menubar.Item>
|
||||
<Menubar.Item>Paste</Menubar.Item>
|
||||
</Menubar.Content>
|
||||
</Menubar.Menu>
|
||||
<Menubar.Menu>
|
||||
<Menubar.Trigger>View</Menubar.Trigger>
|
||||
<Menubar.Content>
|
||||
<Menubar.CheckboxItem checked={true}>Always Show Bookmarks Bar</Menubar.CheckboxItem>
|
||||
<Menubar.CheckboxItem>Always Show Full URLs</Menubar.CheckboxItem>
|
||||
<Menubar.Separator />
|
||||
<Menubar.Item>Reload <span class="ml-auto text-xs">⌘R</span></Menubar.Item>
|
||||
</Menubar.Content>
|
||||
</Menubar.Menu>
|
||||
</Menubar.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,22 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { ModeSwitcher } from '@cio/ui/base/dark-mode';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Mode Switcher',
|
||||
component: ModeSwitcher,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<div class="flex flex-col items-center gap-4">
|
||||
<p class="text-muted-foreground text-sm">Click to toggle dark/light mode</p>
|
||||
<ModeSwitcher />
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,10 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Pagination } from '@cio/ui/base/pagination';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Pagination>)[] = [
|
||||
'count',
|
||||
'page',
|
||||
'onPageChange',
|
||||
'perPage',
|
||||
'orientation'
|
||||
];
|
||||
@@ -0,0 +1,73 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import * as Pagination from '@cio/ui/base/pagination';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Pagination',
|
||||
component: Pagination.Root,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
let page = $state(1);
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Pagination.Root count={100} perPage={10} bind:page>
|
||||
<Pagination.Content>
|
||||
<Pagination.Item>
|
||||
<Pagination.PrevButton />
|
||||
</Pagination.Item>
|
||||
{#each Array.from({ length: 10 }, (_, i) => i + 1) as pageNum}
|
||||
<Pagination.Item>
|
||||
<Pagination.Link page={pageNum} isActive={pageNum === page}>
|
||||
{pageNum}
|
||||
</Pagination.Link>
|
||||
</Pagination.Item>
|
||||
{/each}
|
||||
<Pagination.Item>
|
||||
<Pagination.NextButton />
|
||||
</Pagination.Item>
|
||||
</Pagination.Content>
|
||||
</Pagination.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Ellipsis">
|
||||
{#snippet template()}
|
||||
<Pagination.Root count={500} perPage={10} bind:page>
|
||||
<Pagination.Content>
|
||||
<Pagination.Item>
|
||||
<Pagination.PrevButton />
|
||||
</Pagination.Item>
|
||||
<Pagination.Item>
|
||||
<Pagination.Link page={1} isActive={page === 1}>1</Pagination.Link>
|
||||
</Pagination.Item>
|
||||
<Pagination.Item>
|
||||
<Pagination.Ellipsis />
|
||||
</Pagination.Item>
|
||||
<Pagination.Item>
|
||||
<Pagination.Link {page} isActive={true}>{page}</Pagination.Link>
|
||||
</Pagination.Item>
|
||||
<Pagination.Item>
|
||||
<Pagination.Ellipsis />
|
||||
</Pagination.Item>
|
||||
<Pagination.Item>
|
||||
<Pagination.Link page={50}>50</Pagination.Link>
|
||||
</Pagination.Item>
|
||||
<Pagination.Item>
|
||||
<Pagination.NextButton />
|
||||
</Pagination.Item>
|
||||
</Pagination.Content>
|
||||
</Pagination.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,4 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Progress } from '@cio/ui/base/progress';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Progress>)[] = ['max', 'min', 'value'];
|
||||
@@ -0,0 +1,48 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Progress } from '@cio/ui/base/progress';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Progress',
|
||||
component: Progress,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<div class="w-[400px] space-y-4">
|
||||
<Progress value={33} />
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Different Values">
|
||||
{#snippet template()}
|
||||
<div class="w-[400px] space-y-6">
|
||||
<div class="space-y-2">
|
||||
<p class="text-sm font-medium">25% Complete</p>
|
||||
<Progress value={25} />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<p class="text-sm font-medium">50% Complete</p>
|
||||
<Progress value={50} />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<p class="text-sm font-medium">75% Complete</p>
|
||||
<Progress value={75} />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<p class="text-sm font-medium">100% Complete</p>
|
||||
<Progress value={100} />
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,12 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { RadioGroup } from '@cio/ui/base/radio-group';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof RadioGroup>)[] = [
|
||||
'value',
|
||||
'onValueChange',
|
||||
'disabled',
|
||||
'required',
|
||||
'name',
|
||||
'loop',
|
||||
'orientation'
|
||||
];
|
||||
@@ -0,0 +1,65 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import * as RadioGroup from '@cio/ui/base/radio-group';
|
||||
import { Label } from '@cio/ui/base/label';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/RadioGroup',
|
||||
component: RadioGroup.Root,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<RadioGroup.Root value="option-1">
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="option-1" id="option-1" />
|
||||
<Label for="option-1">Option 1</Label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="option-2" id="option-2" />
|
||||
<Label for="option-2">Option 2</Label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="option-3" id="option-3" />
|
||||
<Label for="option-3">Option 3</Label>
|
||||
</div>
|
||||
</RadioGroup.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Descriptions">
|
||||
{#snippet template()}
|
||||
<RadioGroup.Root value="comfortable" class="space-y-4">
|
||||
<div class="flex items-start space-x-2">
|
||||
<RadioGroup.Item value="default" id="r1" class="mt-1" />
|
||||
<div>
|
||||
<Label for="r1" class="font-medium">Default</Label>
|
||||
<p class="text-muted-foreground text-sm">The standard spacing for your app</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start space-x-2">
|
||||
<RadioGroup.Item value="comfortable" id="r2" class="mt-1" />
|
||||
<div>
|
||||
<Label for="r2" class="font-medium">Comfortable</Label>
|
||||
<p class="text-muted-foreground text-sm">More space for easier interaction</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start space-x-2">
|
||||
<RadioGroup.Item value="compact" id="r3" class="mt-1" />
|
||||
<div>
|
||||
<Label for="r3" class="font-medium">Compact</Label>
|
||||
<p class="text-muted-foreground text-sm">Less space, more content</p>
|
||||
</div>
|
||||
</div>
|
||||
</RadioGroup.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,14 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import * as Select from '@cio/ui/base/select';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Select.Root>)[] = [
|
||||
'value',
|
||||
'onValueChange',
|
||||
'disabled',
|
||||
'type',
|
||||
'open',
|
||||
'name',
|
||||
'required',
|
||||
'autocomplete',
|
||||
'allowDeselect'
|
||||
];
|
||||
@@ -0,0 +1,88 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import * as Select from '@cio/ui/base/select';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Select',
|
||||
component: Select.Root,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
argTypes: {
|
||||
value: {
|
||||
control: 'text',
|
||||
description: 'The controlled value of the select'
|
||||
},
|
||||
onValueChange: {
|
||||
control: false,
|
||||
description: 'Callback function when the value changes'
|
||||
},
|
||||
disabled: {
|
||||
control: 'boolean',
|
||||
description: 'Whether the select is disabled'
|
||||
},
|
||||
type: {
|
||||
control: 'select',
|
||||
options: ['single', 'multiple'],
|
||||
description: 'Whether the select allows single or multiple selection'
|
||||
},
|
||||
open: {
|
||||
control: 'boolean',
|
||||
description: 'The controlled open state of the select'
|
||||
},
|
||||
name: {
|
||||
control: 'text',
|
||||
description: 'The name attribute for the hidden input'
|
||||
},
|
||||
required: {
|
||||
control: 'boolean',
|
||||
description: 'Whether the select is required for form validation'
|
||||
},
|
||||
autocomplete: {
|
||||
control: 'text',
|
||||
description: 'The autocomplete attribute for the hidden input'
|
||||
},
|
||||
allowDeselect: {
|
||||
control: 'boolean',
|
||||
description: 'Whether to allow deselecting the selected value'
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
|
||||
const fruits = [
|
||||
{ value: 'apple', label: 'Apple' },
|
||||
{ value: 'banana', label: 'Banana' },
|
||||
{ value: 'blueberry', label: 'Blueberry' },
|
||||
{ value: 'grapes', label: 'Grapes' },
|
||||
{ value: 'pineapple', label: 'Pineapple' }
|
||||
];
|
||||
|
||||
let value = $state('');
|
||||
|
||||
const triggerContent = $derived(fruits.find((f) => f.value === value)?.label ?? 'Select a fruit');
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Select.Root type="single" name="favoriteFruit" bind:value>
|
||||
<Select.Trigger class="w-[180px]">
|
||||
{triggerContent}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Group>
|
||||
<Select.Label>Fruits</Select.Label>
|
||||
{#each fruits as fruit (fruit.value)}
|
||||
<Select.Item value={fruit.value} label={fruit.label} disabled={fruit.value === 'grapes'}>
|
||||
{fruit.label}
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Group>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,4 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Separator } from '@cio/ui/base/separator';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Separator>)[] = ['orientation', 'decorative'];
|
||||
@@ -0,0 +1,51 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Separator } from '@cio/ui/base/separator';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Separator',
|
||||
component: Separator,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Horizontal">
|
||||
{#snippet template()}
|
||||
<div class="w-96 space-y-4">
|
||||
<div>
|
||||
<h4 class="text-sm font-medium">Section 1</h4>
|
||||
<p class="text-muted-foreground text-sm">Content for the first section</p>
|
||||
</div>
|
||||
<Separator />
|
||||
<div>
|
||||
<h4 class="text-sm font-medium">Section 2</h4>
|
||||
<p class="text-muted-foreground text-sm">Content for the second section</p>
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Vertical">
|
||||
{#snippet template()}
|
||||
<div class="flex h-20 items-center space-x-4">
|
||||
<div class="space-y-1">
|
||||
<h4 class="text-sm font-medium">Item 1</h4>
|
||||
</div>
|
||||
<Separator orientation="vertical" />
|
||||
<div class="space-y-1">
|
||||
<h4 class="text-sm font-medium">Item 2</h4>
|
||||
</div>
|
||||
<Separator orientation="vertical" />
|
||||
<div class="space-y-1">
|
||||
<h4 class="text-sm font-medium">Item 3</h4>
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,4 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Sheet } from '@cio/ui/base/sheet';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Sheet>)[] = ['open', 'onOpenChange'];
|
||||
@@ -0,0 +1,108 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Sheet, Button, Input, Label } from '@cio/ui';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Sheet',
|
||||
component: Sheet.Root,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
argTypes: {
|
||||
open: {
|
||||
control: 'boolean',
|
||||
description: 'The controlled open state of the sheet'
|
||||
},
|
||||
onOpenChange: {
|
||||
control: false,
|
||||
description: 'Callback function when the open state changes'
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Right">
|
||||
{#snippet template()}
|
||||
<Sheet.Root>
|
||||
<Sheet.SheetTrigger>
|
||||
<Button.Root variant="outline">Open Sheet</Button.Root>
|
||||
</Sheet.SheetTrigger>
|
||||
<Sheet.SheetContent>
|
||||
<Sheet.SheetHeader>
|
||||
<Sheet.SheetTitle>Edit profile</Sheet.SheetTitle>
|
||||
<Sheet.SheetDescription
|
||||
>Make changes to your profile here. Click save when you're done.</Sheet.SheetDescription
|
||||
>
|
||||
</Sheet.SheetHeader>
|
||||
<div class="grid gap-4 py-4">
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label.Root for="name" class="text-right">Name</Label.Root>
|
||||
<Input.Root id="name" value="Pedro Duarte" class="col-span-3" />
|
||||
</div>
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label.Root for="username" class="text-right">Username</Label.Root>
|
||||
<Input.Root id="username" value="@peduarte" class="col-span-3" />
|
||||
</div>
|
||||
</div>
|
||||
<Sheet.SheetFooter>
|
||||
<Sheet.SheetClose>
|
||||
<Button.Root type="submit">Save changes</Button.Root>
|
||||
</Sheet.SheetClose>
|
||||
</Sheet.SheetFooter>
|
||||
</Sheet.SheetContent>
|
||||
</Sheet.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Left">
|
||||
{#snippet template()}
|
||||
<Sheet.Root>
|
||||
<Sheet.SheetTrigger>
|
||||
<Button.Root>Open Left Sheet</Button.Root>
|
||||
</Sheet.SheetTrigger>
|
||||
<Sheet.SheetContent side="left">
|
||||
<Sheet.SheetHeader>
|
||||
<Sheet.SheetTitle>Left Sheet</Sheet.SheetTitle>
|
||||
<Sheet.SheetDescription>This sheet opens from the left side.</Sheet.SheetDescription>
|
||||
</Sheet.SheetHeader>
|
||||
</Sheet.SheetContent>
|
||||
</Sheet.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Top">
|
||||
{#snippet template()}
|
||||
<Sheet.Root>
|
||||
<Sheet.SheetTrigger>
|
||||
<Button.Root>Open Top Sheet</Button.Root>
|
||||
</Sheet.SheetTrigger>
|
||||
<Sheet.SheetContent side="top">
|
||||
<Sheet.SheetHeader>
|
||||
<Sheet.SheetTitle>Top Sheet</Sheet.SheetTitle>
|
||||
<Sheet.SheetDescription>This sheet opens from the top.</Sheet.SheetDescription>
|
||||
</Sheet.SheetHeader>
|
||||
</Sheet.SheetContent>
|
||||
</Sheet.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Bottom">
|
||||
{#snippet template()}
|
||||
<Sheet.Root>
|
||||
<Sheet.SheetTrigger>
|
||||
<Button.Root>Open Bottom Sheet</Button.Root>
|
||||
</Sheet.SheetTrigger>
|
||||
<Sheet.SheetContent side="bottom">
|
||||
<Sheet.SheetHeader>
|
||||
<Sheet.SheetTitle>Bottom Sheet</Sheet.SheetTitle>
|
||||
<Sheet.SheetDescription>This sheet opens from the bottom.</Sheet.SheetDescription>
|
||||
</Sheet.SheetHeader>
|
||||
</Sheet.SheetContent>
|
||||
</Sheet.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,4 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Toaster as Sonner } from '@cio/ui/base/sonner';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Sonner>)[] = ['types', 'position', 'expand'];
|
||||
@@ -0,0 +1,67 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Toaster, toast } from '@cio/ui/base/sonner';
|
||||
import { Button } from '@cio/ui/base/button';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Sonner (Toast)',
|
||||
component: Toaster,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<div class="flex flex-col gap-4">
|
||||
<Toaster />
|
||||
<Button onclick={() => toast('This is a default toast message')}>Show Toast</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Success">
|
||||
{#snippet template()}
|
||||
<div class="flex flex-col gap-4">
|
||||
<Toaster />
|
||||
<Button variant="outline" onclick={() => toast.success('Course created successfully!')}>
|
||||
Show Success Toast
|
||||
</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Error">
|
||||
{#snippet template()}
|
||||
<div class="flex flex-col gap-4">
|
||||
<Toaster />
|
||||
<Button variant="destructive" onclick={() => toast.error('Failed to save changes. Please try again.')}>
|
||||
Show Error Toast
|
||||
</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Warning">
|
||||
{#snippet template()}
|
||||
<div class="flex flex-col gap-4">
|
||||
<Toaster />
|
||||
<Button variant="outline" onclick={() => toast.warning('You have unsaved changes!')}>Show Warning Toast</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Info">
|
||||
{#snippet template()}
|
||||
<div class="flex flex-col gap-4">
|
||||
<Toaster />
|
||||
<Button variant="secondary" onclick={() => toast.info('New updates are available')}>Show Info Toast</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,51 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Spinner } from '@cio/ui/base/spinner';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Spinner',
|
||||
component: Spinner,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Spinner />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Small">
|
||||
{#snippet template()}
|
||||
<Spinner class="h-4 w-4" />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Large">
|
||||
{#snippet template()}
|
||||
<Spinner class="h-12 w-12" />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Custom Color">
|
||||
{#snippet template()}
|
||||
<div class="flex gap-4">
|
||||
<Spinner class="text-blue-500" />
|
||||
<Spinner class="text-green-500" />
|
||||
<Spinner class="text-red-500" />
|
||||
<Spinner class="text-purple-500" />
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Text">
|
||||
{#snippet template()}
|
||||
<div class="flex items-center gap-2">
|
||||
<Spinner />
|
||||
<span>Loading...</span>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,11 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Switch } from '@cio/ui/base/switch';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Switch>)[] = [
|
||||
'checked',
|
||||
'onCheckedChange',
|
||||
'disabled',
|
||||
'name',
|
||||
'required',
|
||||
'value'
|
||||
];
|
||||
@@ -0,0 +1,29 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Switch } from '@cio/ui/base/switch';
|
||||
import { Label } from '@cio/ui/base/label';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Switch',
|
||||
component: Switch,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Switch id="airplane-mode" />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Label">
|
||||
{#snippet template()}
|
||||
<div class="flex items-center space-x-2">
|
||||
<Switch id="airplane-mode" />
|
||||
<Label for="airplane-mode">Airplane Mode</Label>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,92 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import * as Table from '@cio/ui/base/table';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Table',
|
||||
component: Table.Root,
|
||||
parameters: {
|
||||
layout: 'padded'
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Table.Root>
|
||||
<Table.Caption>A list of your recent invoices.</Table.Caption>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.Head class="w-[100px]">Invoice</Table.Head>
|
||||
<Table.Head>Status</Table.Head>
|
||||
<Table.Head>Method</Table.Head>
|
||||
<Table.Head class="text-right">Amount</Table.Head>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
<Table.Row>
|
||||
<Table.Cell class="font-medium">INV001</Table.Cell>
|
||||
<Table.Cell>Paid</Table.Cell>
|
||||
<Table.Cell>Credit Card</Table.Cell>
|
||||
<Table.Cell class="text-right">$250.00</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell class="font-medium">INV002</Table.Cell>
|
||||
<Table.Cell>Pending</Table.Cell>
|
||||
<Table.Cell>PayPal</Table.Cell>
|
||||
<Table.Cell class="text-right">$150.00</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell class="font-medium">INV003</Table.Cell>
|
||||
<Table.Cell>Unpaid</Table.Cell>
|
||||
<Table.Cell>Bank Transfer</Table.Cell>
|
||||
<Table.Cell class="text-right">$350.00</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell class="font-medium">INV004</Table.Cell>
|
||||
<Table.Cell>Paid</Table.Cell>
|
||||
<Table.Cell>Credit Card</Table.Cell>
|
||||
<Table.Cell class="text-right">$450.00</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Body>
|
||||
<Table.Footer>
|
||||
<Table.Row>
|
||||
<Table.Cell colspan={3}>Total</Table.Cell>
|
||||
<Table.Cell class="text-right">$1,200.00</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Footer>
|
||||
</Table.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Simple Table">
|
||||
{#snippet template()}
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.Head>Name</Table.Head>
|
||||
<Table.Head>Email</Table.Head>
|
||||
<Table.Head>Role</Table.Head>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
<Table.Row>
|
||||
<Table.Cell>John Doe</Table.Cell>
|
||||
<Table.Cell>john@example.com</Table.Cell>
|
||||
<Table.Cell>Admin</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>Jane Smith</Table.Cell>
|
||||
<Table.Cell>jane@example.com</Table.Cell>
|
||||
<Table.Cell>User</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>Bob Johnson</Table.Cell>
|
||||
<Table.Cell>bob@example.com</Table.Cell>
|
||||
<Table.Cell>Editor</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,10 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Tabs } from '@cio/ui/base/tabs';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Tabs>)[] = [
|
||||
'value',
|
||||
'onValueChange',
|
||||
'disabled',
|
||||
'activationMode',
|
||||
'orientation'
|
||||
];
|
||||
@@ -0,0 +1,44 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import * as Tabs from '@cio/ui/base/tabs';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Tabs',
|
||||
component: Tabs.Root,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Tabs.Root value="overview" class="w-[500px]">
|
||||
<Tabs.List class="grid w-full grid-cols-3">
|
||||
<Tabs.Trigger value="overview">Overview</Tabs.Trigger>
|
||||
<Tabs.Trigger value="analytics">Analytics</Tabs.Trigger>
|
||||
<Tabs.Trigger value="reports">Reports</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
<Tabs.Content value="overview">
|
||||
<div class="space-y-4 pt-4">
|
||||
<p class="text-muted-foreground text-sm">View your overview dashboard with key metrics and insights.</p>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="analytics">
|
||||
<div class="space-y-4 pt-4">
|
||||
<p class="text-muted-foreground text-sm">Deep dive into your analytics and user behavior patterns.</p>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="reports">
|
||||
<div class="space-y-4 pt-4">
|
||||
<p class="text-muted-foreground text-sm">Generate and download detailed reports for your records.</p>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
</Tabs.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,9 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Tooltip } from '@cio/ui/base/tooltip';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Tooltip>)[] = [
|
||||
'disableHoverableContent',
|
||||
'delayDuration',
|
||||
'ignoreNonKeyboardFocus',
|
||||
'disabled'
|
||||
];
|
||||
@@ -2,13 +2,34 @@
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Tooltip, Provider, Trigger, Content } from '@cio/ui/base/tooltip';
|
||||
import { Button } from '@cio/ui/base/button';
|
||||
// import { Arro}
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Tooltip',
|
||||
component: Provider,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
argTypes: {
|
||||
disableHoverableContent: {
|
||||
control: 'boolean',
|
||||
description: 'Prevents the content from being hoverable'
|
||||
},
|
||||
delayDuration: {
|
||||
control: 'number',
|
||||
description: 'The delay in milliseconds before the tooltip appears'
|
||||
},
|
||||
ignoreNonKeyboardFocus: {
|
||||
control: 'boolean',
|
||||
description: 'Whether to ignore non-keyboard focus events'
|
||||
},
|
||||
disabled: {
|
||||
control: 'boolean',
|
||||
description: 'Whether the tooltip is disabled'
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarFooter,
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarGroupLabel,
|
||||
SidebarHeader,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarProvider,
|
||||
SidebarTrigger
|
||||
} from '@cio/ui/base/sidebar';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Molecules/Sidebar',
|
||||
component: Sidebar,
|
||||
parameters: {
|
||||
layout: 'fullscreen'
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<SidebarProvider>
|
||||
<Sidebar>
|
||||
<SidebarHeader>
|
||||
<h2 class="px-4 text-lg font-semibold">My App</h2>
|
||||
</SidebarHeader>
|
||||
<SidebarContent>
|
||||
<SidebarGroup>
|
||||
<SidebarGroupLabel>Navigation</SidebarGroupLabel>
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<span>Dashboard</span>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<span>Projects</span>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<span>Settings</span>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
</SidebarContent>
|
||||
<SidebarFooter>
|
||||
<p class="text-muted-foreground px-4 text-sm">© 2024 My App</p>
|
||||
</SidebarFooter>
|
||||
</Sidebar>
|
||||
<main class="flex-1 p-4">
|
||||
<SidebarTrigger />
|
||||
<div class="mt-4">
|
||||
<h1 class="text-2xl font-bold">Main Content</h1>
|
||||
<p class="mt-2">This is the main content area.</p>
|
||||
</div>
|
||||
</main>
|
||||
</SidebarProvider>
|
||||
{/snippet}
|
||||
</Story>
|
||||
Reference in New Issue
Block a user