feat: migrate dashboard to svelte 5 (#577)
* chore: migration to SvelteKit 2 * stage 1: migrate to svelte 5 and fix rerendering issues * stage 2: fix more $: reactivity across dashboard * fix merge conflicts * chore: migrate code in main to svelte 5 * chore: update preventDefault * chore: simplify tsconfig and remove unused mobileMenuRef in MobileMenu.svelte * chore: enforce .ts across dashboard * rename from classroomio-com to website * stage-3: Replace carbon icon svelte with lucide icon * update lock file * chore: finish icon replacement * fix: settings and setup page multiple rerender * stage 3: More icon and rerendering fixes * feat: checkpoint * feat: update editor * [not working] connect everything with ui build * storybook + ui + dashboard all working independently * add bg-black to +page.svelte * feat: add editor to storybook * chore: animate lucid icons (#590) * v1 animations * feat: change some course navigation icons & animate org navigation icons * chore: change settings icon * chore: use css instead of js for hover * rename animations --------- Co-authored-by: tunny17 <tvnji01@gmail.com> * chore: update path to node_modules types in api tsconfig * fix: update import path for DropdownMenu component * fix: add rollupOptions to build configuration in vite.config.ts * fix: remove rollupOptions from build configuration and add @floating-ui/dom dependency * install --------- Co-authored-by: tunny17 <tvnji01@gmail.com>
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
import type { StorybookConfig } from '@storybook/sveltekit';
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories: ['../src/**/*.stories.@(js|ts|svelte)'],
|
||||
addons: [
|
||||
'@storybook/addon-links',
|
||||
'@storybook/addon-essentials',
|
||||
'@storybook/addon-interactions',
|
||||
'@storybook/addon-svelte-csf'
|
||||
],
|
||||
framework: {
|
||||
name: '@storybook/sveltekit',
|
||||
options: {}
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1,16 @@
|
||||
import type { Preview } from '@storybook/svelte';
|
||||
|
||||
import '../src/index.css';
|
||||
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default preview;
|
||||
@@ -0,0 +1,19 @@
|
||||
# @cio/storybook
|
||||
|
||||
Storybook for ClassroomIO UI components.
|
||||
|
||||
## Development
|
||||
|
||||
To start the Storybook development server:
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
To build the Storybook:
|
||||
|
||||
```bash
|
||||
pnpm build
|
||||
```
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "@cio/storybook",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "storybook dev -p 6006",
|
||||
"build": "storybook build",
|
||||
"preview": "storybook preview",
|
||||
"build-storybook": "storybook build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cio/ui": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@storybook/addon-essentials": "^8.4.2",
|
||||
"@storybook/addon-interactions": "^8.4.2",
|
||||
"@storybook/addon-links": "^8.4.2",
|
||||
"@storybook/addon-svelte-csf": "^5.0.6",
|
||||
"@storybook/blocks": "^8.4.2",
|
||||
"@storybook/svelte": "^8.4.2",
|
||||
"@storybook/svelte-vite": "^10.0.2",
|
||||
"@storybook/sveltekit": "^8.4.2",
|
||||
"@storybook/test": "^8.4.2",
|
||||
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
||||
"@tailwindcss/vite": "^4.1.16",
|
||||
"storybook": "^8.4.2",
|
||||
"svelte": "^5.39.11",
|
||||
"tailwindcss": "^4.1.14",
|
||||
"@cio/tsconfig": "workspace:*",
|
||||
"typescript-svelte-plugin": "^0.3.50",
|
||||
"vite": "^7.1.4"
|
||||
}
|
||||
}
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
@@ -0,0 +1,100 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Button } from '@cio/ui/base/button';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Button',
|
||||
component: Button,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Button>Default Button</Button>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Secondary">
|
||||
{#snippet template(args)}
|
||||
<Button {...args} variant="secondary">Secondary Button</Button>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Destructive">
|
||||
{#snippet template(args)}
|
||||
<Button {...args} variant="destructive">Destructive Button</Button>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Outline">
|
||||
{#snippet template(args)}
|
||||
<Button {...args} variant="outline">Outline Button</Button>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Ghost">
|
||||
{#snippet template(args)}
|
||||
<Button {...args} variant="ghost">Ghost Button</Button>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Link">
|
||||
{#snippet template(args)}
|
||||
<Button {...args} variant="link">Link Button</Button>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Small">
|
||||
{#snippet template(args)}
|
||||
<Button {...args} size="sm">Small Button</Button>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Large">
|
||||
{#snippet template(args)}
|
||||
<Button {...args} size="lg">Large Button</Button>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Disabled">
|
||||
{#snippet template(args)}
|
||||
<Button {...args} disabled>Disabled Button</Button>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="As Link">
|
||||
{#snippet template(args)}
|
||||
<Button {...args} href="#">Link Button</Button>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="All Variants">
|
||||
{#snippet template()}
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<Button>Default</Button>
|
||||
<Button variant="secondary">Secondary</Button>
|
||||
<Button variant="destructive">Destructive</Button>
|
||||
<Button variant="outline">Outline</Button>
|
||||
<Button variant="ghost">Ghost</Button>
|
||||
<Button variant="link">Link</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="All Sizes">
|
||||
{#snippet template()}
|
||||
<div class="flex items-center gap-4">
|
||||
<Button size="sm">Small</Button>
|
||||
<Button>Default</Button>
|
||||
<Button size="lg">Large</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,4 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Button } from '@cio/ui/base/button';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Button>)[] = ['variant', 'size', 'disabled', 'class', 'type', 'href'];
|
||||
@@ -0,0 +1,117 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { DropdownMenu, Button } from '@cio/ui';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/DropdownMenu',
|
||||
component: DropdownMenu.Root,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
<Button.Root variant="outline">Open</Button.Root>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content>
|
||||
<DropdownMenu.Group>
|
||||
<DropdownMenu.Label>My Account</DropdownMenu.Label>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item>Profile</DropdownMenu.Item>
|
||||
<DropdownMenu.Item>Billing</DropdownMenu.Item>
|
||||
<DropdownMenu.Item>Settings</DropdownMenu.Item>
|
||||
<DropdownMenu.Item>Keyboard shortcuts</DropdownMenu.Item>
|
||||
</DropdownMenu.Group>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Group>
|
||||
<DropdownMenu.Item>Team</DropdownMenu.Item>
|
||||
<DropdownMenu.Sub>
|
||||
<DropdownMenu.SubTrigger>Invite users</DropdownMenu.SubTrigger>
|
||||
<DropdownMenu.SubContent>
|
||||
<DropdownMenu.Item>Email</DropdownMenu.Item>
|
||||
<DropdownMenu.Item>Message</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item>More...</DropdownMenu.Item>
|
||||
</DropdownMenu.SubContent>
|
||||
</DropdownMenu.Sub>
|
||||
<DropdownMenu.Item>New Team</DropdownMenu.Item>
|
||||
</DropdownMenu.Group>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item>GitHub</DropdownMenu.Item>
|
||||
<DropdownMenu.Item>Support</DropdownMenu.Item>
|
||||
<DropdownMenu.Item disabled>API</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item>Log out</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Icons">
|
||||
{#snippet template()}
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
<Button.Root variant="outline">Open</Button.Root>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content>
|
||||
<DropdownMenu.Item>
|
||||
<span>👤 Profile</span>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item>
|
||||
<span>💳 Billing</span>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item>
|
||||
<span>⚙️ Settings</span>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item>
|
||||
<span>🚪 Logout</span>
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Simple Menu">
|
||||
{#snippet template()}
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
<Button.Root variant="outline">Open</Button.Root>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content>
|
||||
<DropdownMenu.Item>Edit</DropdownMenu.Item>
|
||||
<DropdownMenu.Item>Duplicate</DropdownMenu.Item>
|
||||
<DropdownMenu.Item>Archive</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item class="text-red-600">Delete</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Checkboxes">
|
||||
{#snippet template()}
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
<Button.Root variant="outline">Open</Button.Root>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content>
|
||||
<DropdownMenu.Label>View Options</DropdownMenu.Label>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.CheckboxItem checked>Status Bar</DropdownMenu.CheckboxItem>
|
||||
<DropdownMenu.CheckboxItem>Activity Bar</DropdownMenu.CheckboxItem>
|
||||
<DropdownMenu.CheckboxItem checked>Panel</DropdownMenu.CheckboxItem>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.RadioGroup value="single">
|
||||
<DropdownMenu.RadioItem value="single">Single</DropdownMenu.RadioItem>
|
||||
<DropdownMenu.RadioItem value="group">Group</DropdownMenu.RadioItem>
|
||||
</DropdownMenu.RadioGroup>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,14 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Input } from '@cio/ui/base/input';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Input>)[] = [
|
||||
'value',
|
||||
'type',
|
||||
'placeholder',
|
||||
'disabled',
|
||||
'class',
|
||||
'id',
|
||||
'name',
|
||||
'required',
|
||||
'readonly'
|
||||
];
|
||||
@@ -0,0 +1,66 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Input } from '@cio/ui/base/input';
|
||||
import { Label } from '@cio/ui/base/label';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Input',
|
||||
component: Input,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default" args={{ placeholder: 'Enter text...' }} />
|
||||
|
||||
<Story name="With Label">
|
||||
{#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="Password">
|
||||
{#snippet template()}
|
||||
<Input type="password" placeholder="Password" />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Disabled">
|
||||
{#snippet template()}
|
||||
<Input disabled placeholder="Disabled input" />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Error">
|
||||
{#snippet template()}
|
||||
<div class="grid w-full max-w-sm items-center gap-1.5">
|
||||
<Label for="email-error">Email</Label>
|
||||
<Input type="email" id="email-error" placeholder="Email" class="border-red-500" />
|
||||
<p class="text-sm text-red-500">This field is required</p>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="File Input">
|
||||
{#snippet template()}
|
||||
<div class="grid w-full max-w-sm items-center gap-1.5">
|
||||
<Label for="picture">Picture</Label>
|
||||
<Input id="picture" type="file" />
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Search">
|
||||
{#snippet template()}
|
||||
<Input type="search" placeholder="Search..." />
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,109 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Popover, Button, Input, Label } from '@cio/ui';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Popover',
|
||||
component: Popover.Root,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Popover.Root>
|
||||
<Popover.Trigger>
|
||||
<Button.Root variant="outline">Open popover</Button.Root>
|
||||
</Popover.Trigger>
|
||||
<Popover.Content class="w-80">
|
||||
<div class="grid gap-4">
|
||||
<div class="space-y-2">
|
||||
<h4 class="font-medium leading-none">Dimensions</h4>
|
||||
<p class="text-muted-foreground text-sm">Set the dimensions for the layer.</p>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<div class="grid grid-cols-3 items-center gap-4">
|
||||
<Label.Root for="width">Width</Label.Root>
|
||||
<Input.Root id="width" value="100%" class="col-span-2 h-8" />
|
||||
</div>
|
||||
<div class="grid grid-cols-3 items-center gap-4">
|
||||
<Label.Root for="maxWidth">Max. width</Label.Root>
|
||||
<Input.Root id="maxWidth" value="300px" class="col-span-2 h-8" />
|
||||
</div>
|
||||
<div class="grid grid-cols-3 items-center gap-4">
|
||||
<Label.Root for="height">Height</Label.Root>
|
||||
<Input.Root id="height" value="25px" class="col-span-2 h-8" />
|
||||
</div>
|
||||
<div class="grid grid-cols-3 items-center gap-4">
|
||||
<Label.Root for="maxHeight">Max. height</Label.Root>
|
||||
<Input.Root id="maxHeight" value="none" class="col-span-2 h-8" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Popover.Content>
|
||||
</Popover.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Simple">
|
||||
{#snippet template()}
|
||||
<Popover.Root>
|
||||
<Popover.Trigger>
|
||||
<Button.Root>Click me</Button.Root>
|
||||
</Popover.Trigger>
|
||||
<Popover.Content>
|
||||
<p class="text-sm">This is a simple popover with some text content.</p>
|
||||
</Popover.Content>
|
||||
</Popover.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Form">
|
||||
{#snippet template()}
|
||||
<Popover.Root>
|
||||
<Popover.Trigger>
|
||||
<Button.Root variant="outline">Settings</Button.Root>
|
||||
</Popover.Trigger>
|
||||
<Popover.Content class="w-80">
|
||||
<div class="grid gap-4">
|
||||
<div class="space-y-2">
|
||||
<h4 class="font-medium leading-none">Settings</h4>
|
||||
<p class="text-muted-foreground text-sm">Manage your account settings.</p>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<div class="grid gap-1">
|
||||
<Label.Root for="name">Display name</Label.Root>
|
||||
<Input.Root id="name" value="Pedro Duarte" />
|
||||
</div>
|
||||
<div class="grid gap-1">
|
||||
<Label.Root for="username">Username</Label.Root>
|
||||
<Input.Root id="username" value="@peduarte" />
|
||||
</div>
|
||||
</div>
|
||||
<Button.Root size="sm" class="w-full">Save changes</Button.Root>
|
||||
</div>
|
||||
</Popover.Content>
|
||||
</Popover.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Information">
|
||||
{#snippet template()}
|
||||
<Popover.Root>
|
||||
<Popover.Trigger>
|
||||
<Button.Root variant="ghost" size="sm">ℹ️ Info</Button.Root>
|
||||
</Popover.Trigger>
|
||||
<Popover.Content class="w-56">
|
||||
<div class="space-y-2">
|
||||
<h4 class="font-medium">About this feature</h4>
|
||||
<p class="text-muted-foreground text-sm">
|
||||
This feature allows you to quickly access important information without leaving the current page.
|
||||
</p>
|
||||
</div>
|
||||
</Popover.Content>
|
||||
</Popover.Root>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,4 @@
|
||||
import { type ComponentProps } from 'svelte';
|
||||
import { Skeleton } from '@cio/ui/base/skeleton';
|
||||
|
||||
export const FIELDS: (keyof ComponentProps<typeof Skeleton>)[] = ['class'];
|
||||
@@ -0,0 +1,77 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Skeleton } from '@cio/ui/base/skeleton';
|
||||
import { FIELDS } from './fields';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Skeleton',
|
||||
component: Skeleton,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template(args)}
|
||||
<Skeleton {...args} class="h-4 w-[250px]" />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Circle">
|
||||
{#snippet template(args)}
|
||||
<Skeleton {...args} class="h-12 w-12 rounded-full" />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Card">
|
||||
{#snippet template()}
|
||||
<div class="flex items-center space-x-4">
|
||||
<Skeleton class="h-12 w-12 rounded-full" />
|
||||
<div class="space-y-2">
|
||||
<Skeleton class="h-4 w-[250px]" />
|
||||
<Skeleton class="h-4 w-[200px]" />
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Multiple Lines">
|
||||
{#snippet template()}
|
||||
<div class="space-y-2">
|
||||
<Skeleton class="h-4 w-[350px]" />
|
||||
<Skeleton class="h-4 w-[300px]" />
|
||||
<Skeleton class="h-4 w-[250px]" />
|
||||
<Skeleton class="h-4 w-[200px]" />
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Button">
|
||||
{#snippet template(args)}
|
||||
<Skeleton {...args} class="h-10 w-20" />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Loading State">
|
||||
{#snippet template()}
|
||||
<div class="space-y-4 rounded-lg border p-4">
|
||||
<div class="flex items-center space-x-4">
|
||||
<Skeleton class="h-12 w-12 rounded-full" />
|
||||
<div class="space-y-2">
|
||||
<Skeleton class="h-4 w-[200px]" />
|
||||
<Skeleton class="h-4 w-40" />
|
||||
</div>
|
||||
</div>
|
||||
<Skeleton class="h-[200px] w-full" />
|
||||
<div class="flex space-x-2">
|
||||
<Skeleton class="h-8 w-16" />
|
||||
<Skeleton class="h-8 w-16" />
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,14 @@
|
||||
<script>
|
||||
import { Tooltip, Button } from '@cio/ui';
|
||||
</script>
|
||||
|
||||
<Tooltip.Provider>
|
||||
<Tooltip.Root>
|
||||
<Tooltip.Trigger>
|
||||
<Button.Root variant="outline">Hover me</Button.Root>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Content>
|
||||
<p>Add to library</p>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Root>
|
||||
</Tooltip.Provider>
|
||||
@@ -0,0 +1,130 @@
|
||||
<script module>
|
||||
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}
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Atom/Tooltip',
|
||||
component: Provider,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Provider>
|
||||
<Tooltip>
|
||||
<Trigger>
|
||||
<Button variant="outline">Hover me</Button>
|
||||
</Trigger>
|
||||
<Content>
|
||||
<p>Add to library</p>
|
||||
</Content>
|
||||
</Tooltip>
|
||||
</Provider>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Arrow">
|
||||
{#snippet template()}
|
||||
<Provider>
|
||||
<Tooltip>
|
||||
<Trigger>
|
||||
<Button>Hover for tooltip</Button>
|
||||
</Trigger>
|
||||
<Content>
|
||||
<p>This tooltip has an arrow pointing to the trigger</p>
|
||||
<!-- <Arrow /> -->
|
||||
=>
|
||||
</Content>
|
||||
</Tooltip>
|
||||
</Provider>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Simple Text">
|
||||
{#snippet template()}
|
||||
<Provider>
|
||||
<Tooltip>
|
||||
<Trigger>
|
||||
<Button variant="ghost" size="sm">❓</Button>
|
||||
</Trigger>
|
||||
<Content>
|
||||
<p>Help information</p>
|
||||
</Content>
|
||||
</Tooltip>
|
||||
</Provider>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Multiple Tooltips">
|
||||
{#snippet template()}
|
||||
<Provider>
|
||||
<div class="flex gap-4">
|
||||
<Tooltip>
|
||||
<Trigger>
|
||||
<Button variant="outline">Save</Button>
|
||||
</Trigger>
|
||||
<Content>
|
||||
<p>Save your work (Ctrl+S)</p>
|
||||
</Content>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<Trigger>
|
||||
<Button variant="outline">Edit</Button>
|
||||
</Trigger>
|
||||
<Content>
|
||||
<p>Edit this item</p>
|
||||
</Content>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<Trigger>
|
||||
<Button variant="destructive">Delete</Button>
|
||||
</Trigger>
|
||||
<Content>
|
||||
<p>Permanently delete this item</p>
|
||||
</Content>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Provider>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Icon Button">
|
||||
{#snippet template()}
|
||||
<Provider>
|
||||
<Tooltip>
|
||||
<Trigger>
|
||||
<Button variant="ghost" size="sm">🔧</Button>
|
||||
</Trigger>
|
||||
<Content>
|
||||
<p>Settings</p>
|
||||
</Content>
|
||||
</Tooltip>
|
||||
</Provider>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Long Content">
|
||||
{#snippet template()}
|
||||
<Provider>
|
||||
<Tooltip>
|
||||
<Trigger>
|
||||
<Button variant="outline">Info</Button>
|
||||
</Trigger>
|
||||
<Content class="max-w-xs">
|
||||
<p>
|
||||
This is a longer tooltip with more detailed information that might span multiple lines to provide
|
||||
comprehensive context about the feature or action.
|
||||
</p>
|
||||
</Content>
|
||||
</Tooltip>
|
||||
</Provider>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,3 @@
|
||||
@import 'tailwindcss';
|
||||
|
||||
@import '@cio/ui/output.css';
|
||||
@@ -0,0 +1,62 @@
|
||||
import type { EditorProps } from '@cio/ui/custom/editor/types';
|
||||
|
||||
export const FIELDS: (keyof EditorProps)[] = [
|
||||
'showToolBar',
|
||||
'editable',
|
||||
'enablePersistence',
|
||||
'contentStorageKey',
|
||||
'editableStorageKey',
|
||||
'class',
|
||||
'editorClass'
|
||||
];
|
||||
|
||||
export const DEFAULT_CONTENT = {
|
||||
type: 'doc',
|
||||
content: [
|
||||
{
|
||||
type: 'heading',
|
||||
attrs: { level: 1 },
|
||||
content: [{ type: 'text', text: 'Welcome to the Editor' }]
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
content: [
|
||||
{ type: 'text', text: 'This is a ' },
|
||||
{ type: 'text', marks: [{ type: 'bold' }], text: 'rich text editor' },
|
||||
{ type: 'text', text: ' with support for various formatting options.' }
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'bulletList',
|
||||
content: [
|
||||
{
|
||||
type: 'listItem',
|
||||
content: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
content: [{ type: 'text', text: 'Support for lists' }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'listItem',
|
||||
content: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
content: [{ type: 'text', text: 'Rich text formatting' }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'listItem',
|
||||
content: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
content: [{ type: 'text', text: 'And much more!' }]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,82 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import { Editor } from '@cio/ui/custom/editor';
|
||||
import { FIELDS, DEFAULT_CONTENT } from './constants';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Molecules/Editor',
|
||||
component: Editor,
|
||||
parameters: {
|
||||
layout: 'padded',
|
||||
controls: {
|
||||
include: FIELDS
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template()}
|
||||
<Editor />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Sample Content">
|
||||
{#snippet template()}
|
||||
<Editor content={DEFAULT_CONTENT} />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Read Only">
|
||||
{#snippet template()}
|
||||
<Editor content={DEFAULT_CONTENT} editable={false} />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Without Toolbar">
|
||||
{#snippet template()}
|
||||
<Editor content={DEFAULT_CONTENT} showToolBar={false} />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Persistence">
|
||||
{#snippet template()}
|
||||
<Editor content={DEFAULT_CONTENT} enablePersistence={true} contentStorageKey="storybook-editor-content" />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Custom Styling">
|
||||
{#snippet template()}
|
||||
<Editor
|
||||
content={DEFAULT_CONTENT}
|
||||
class="mx-auto max-w-4xl rounded-lg border-2 border-blue-300"
|
||||
editorClass="h-64 p-4 bg-gray-50"
|
||||
/>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Callbacks">
|
||||
{#snippet template()}
|
||||
<Editor
|
||||
content={DEFAULT_CONTENT}
|
||||
onContentChange={(content) => console.log('Content changed:', content)}
|
||||
onEditorReady={(editor) => console.log('Editor ready:', editor)}
|
||||
/>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Multiple Editors">
|
||||
{#snippet template()}
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div>
|
||||
<h3 class="mb-2 text-lg font-semibold">Article</h3>
|
||||
<Editor content={DEFAULT_CONTENT} contentStorageKey="article-content" enablePersistence={true} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="mb-2 text-lg font-semibold">Notes</h3>
|
||||
<Editor showToolBar={false} editorClass="h-48" contentStorageKey="notes-content" enablePersistence={true} />
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
@@ -0,0 +1,16 @@
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
||||
// for more information about preprocessors
|
||||
preprocess: vitePreprocess(),
|
||||
|
||||
kit: {
|
||||
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
||||
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
|
||||
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"extends": "@cio/tsconfig/base.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"target": "ES2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"noImplicitAny": false,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"paths": {
|
||||
"@cio/ui": ["../ui/src"],
|
||||
"@cio/ui/*": ["../ui/src/*"],
|
||||
"$src/*": ["../ui/*"]
|
||||
},
|
||||
"typeRoots": ["../../node_modules/@types", "./node_modules/@types"],
|
||||
"types": ["node"],
|
||||
"jsx": "preserve",
|
||||
"lib": ["ES2020", "DOM"],
|
||||
"plugins": [
|
||||
{
|
||||
"name": "typescript-svelte-plugin",
|
||||
"enabled": true,
|
||||
"assumeIsSvelteProject": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": ["src/**/*", ".storybook/**/*", "vite.config.ts"]
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
||||
import * as path from 'path';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [tailwindcss(), svelte()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@cio/ui': path.resolve(__dirname, '../ui/src'),
|
||||
$src: path.resolve(__dirname, '../ui/src')
|
||||
},
|
||||
conditions: ['svelte', 'browser', 'import']
|
||||
},
|
||||
optimizeDeps: {
|
||||
include: ['svelte-tiptap'],
|
||||
exclude: ['@tiptap/core', '@tiptap/pm']
|
||||
},
|
||||
ssr: {
|
||||
noExternal: ['svelte-tiptap']
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user