ui(components): updated component font sizes and design component docs (#4486)
This commit is contained in:
1 parent
23a2582231
commit
1801a217e3
42 files changed
+2034
-903
No files matched your search
@@ -157,12 +157,6 @@ module.exports = {
|
||||
srcDark: 'img/ohif-logo.svg',
|
||||
},
|
||||
items: [
|
||||
{
|
||||
href: 'https://ohif.org/showcase',
|
||||
label: 'Showcase',
|
||||
target: '_blank',
|
||||
position: 'left',
|
||||
},
|
||||
{
|
||||
position: 'left',
|
||||
to: '/',
|
||||
@@ -170,25 +164,28 @@ module.exports = {
|
||||
docId: 'Introduction',
|
||||
label: 'Docs',
|
||||
},
|
||||
{
|
||||
to: '/components',
|
||||
label: 'Components',
|
||||
position: 'left',
|
||||
},
|
||||
{
|
||||
href: 'https://ohif.org/showcase',
|
||||
label: 'Showcase',
|
||||
target: '_blank',
|
||||
position: 'left',
|
||||
},
|
||||
{
|
||||
href: 'https://ohif.org/collaborate',
|
||||
label: 'Collaborate',
|
||||
target: '_blank',
|
||||
position: 'left',
|
||||
},
|
||||
/*
|
||||
{
|
||||
to: '/playground',
|
||||
label: 'UI Playground',
|
||||
position: 'left',
|
||||
className: 'new-badge',
|
||||
},
|
||||
*/
|
||||
{
|
||||
to: '/help',
|
||||
//activeBaseRegex: '(^/help$)|(/help)',
|
||||
label: 'Help',
|
||||
position: 'right',
|
||||
position: 'left',
|
||||
},
|
||||
{
|
||||
type: 'docsVersionDropdown',
|
||||
|
||||
@@ -233,7 +233,9 @@ input[type='number'] {
|
||||
}
|
||||
|
||||
.navbar__item svg {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* stylelint-disable docusaurus/copyright-header */
|
||||
|
||||
@@ -0,0 +1,418 @@
|
||||
import React, { useState } from 'react';
|
||||
import '../css/custom.css';
|
||||
|
||||
import Layout from '@theme/Layout';
|
||||
import { Label } from '../../../ui-next/src/components/Label';
|
||||
import { Input } from '../../../ui-next/src/components/Input';
|
||||
import { Separator } from '../../../ui-next/src/components/Separator';
|
||||
import { Tabs, TabsList, TabsTrigger } from '../../../ui-next/src/components/Tabs';
|
||||
import {
|
||||
Select,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectValue,
|
||||
} from '../../../ui-next/src/components/Select';
|
||||
import { Button } from '../../../ui-next/src/components/Button';
|
||||
import { Switch } from '../../../ui-next/src/components/Switch';
|
||||
import { Checkbox } from '../../../ui-next/src/components/Checkbox';
|
||||
import { Toggle } from '../../../ui-next/src/components/Toggle';
|
||||
import { Slider } from '../../../ui-next/src/components/Slider';
|
||||
import { ScrollArea } from '../../../ui-next/src/components/ScrollArea';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
} from '../../../ui-next/src/components/DropdownMenu';
|
||||
import { Icons } from '../../../ui-next/src/components/Icons';
|
||||
import { Toaster, toast } from '../../../ui-next/src/components/Sonner';
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardFooter,
|
||||
CardTitle,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
} from '../../../ui-next/src/components/Card';
|
||||
|
||||
interface ShowcaseRowProps {
|
||||
title: string;
|
||||
description?: string;
|
||||
children: React.ReactNode;
|
||||
code: string;
|
||||
}
|
||||
|
||||
export default function ComponentShowcase() {
|
||||
// Handlers to trigger different types of toasts
|
||||
const triggerSuccess = () => {
|
||||
toast.success('This is a success toast!');
|
||||
};
|
||||
|
||||
const triggerError = () => {
|
||||
toast.error('This is an error toast!');
|
||||
};
|
||||
|
||||
const triggerInfo = () => {
|
||||
toast.info('This is an info toast!');
|
||||
};
|
||||
|
||||
const triggerWarning = () => {
|
||||
toast.warning('This is a warning toast!');
|
||||
};
|
||||
|
||||
// Handler to trigger a toast.promise example
|
||||
const triggerPromiseToast = () => {
|
||||
const promise = () =>
|
||||
new Promise<{ name: string }>(resolve =>
|
||||
setTimeout(() => resolve({ name: 'Segmentation 1' }), 3000)
|
||||
);
|
||||
|
||||
toast.promise(promise(), {
|
||||
loading: 'Loading Segmentation...',
|
||||
success: data => `${data.name} has been added`,
|
||||
error: 'Error',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with description
|
||||
const triggerDescriptionToast = () => {
|
||||
toast.success('Success heading', {
|
||||
description: 'This is a detailed description of the success message.',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with an action button
|
||||
const triggerActionButtonToast = () => {
|
||||
toast.info('No active segmentation detected', {
|
||||
description: 'Create a segmentation before using the Brush',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with a cancel button
|
||||
const triggerCancelButtonToast = () => {
|
||||
toast.error('No active segmentation detected', {
|
||||
description: 'Create a segmentation before using the Brush',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with both action and cancel buttons
|
||||
const triggerCombinedToast = () => {
|
||||
toast.warning('Warning!', {
|
||||
description: 'This is a warning with both action and cancel buttons.',
|
||||
action: (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => alert('Retry action clicked')}
|
||||
>
|
||||
Retry
|
||||
</Button>
|
||||
),
|
||||
cancel: (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => toast.dismiss()}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a loading toast using Toaster's default loading icon
|
||||
const showLoadingToast = () => {
|
||||
toast.loading('Loading your data...');
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout
|
||||
title="Colors and Typography"
|
||||
description="Colors and Typography"
|
||||
>
|
||||
<div className="text-foreground min-h-screen bg-black">
|
||||
<div className="mx-auto my-4 max-w-5xl pt-6 pb-3">
|
||||
<div className="grid grid-cols-1 gap-5 md:grid-cols-3">
|
||||
<a
|
||||
href="/colors-and-type"
|
||||
className="focus:ring-primary block rounded-lg text-inherit no-underline hover:no-underline focus:outline-none focus:ring-2"
|
||||
>
|
||||
<Card className="hover:bg-primary/30 w-full transition-colors">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-foreground text-xl">
|
||||
<Icons.ColorChange className="h-12 w-12" />
|
||||
Colors & Typography
|
||||
</CardTitle>
|
||||
<CardDescription className="text-lg">
|
||||
Color Palette and Typography Guidelines
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
</a>
|
||||
<a
|
||||
href="/components-list"
|
||||
className="focus:ring-primary block rounded-lg text-inherit no-underline hover:no-underline focus:outline-none focus:ring-2"
|
||||
>
|
||||
<Card className="hover:bg-primary/30 w-full transition-colors">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-foreground text-xl">
|
||||
<Icons.ColorChange className="h-12 w-12" />
|
||||
Components
|
||||
</CardTitle>
|
||||
<CardDescription className="text-lg">
|
||||
Essential UI Components with Variants
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
</a>
|
||||
<a
|
||||
href="/patterns"
|
||||
className="focus:ring-primary block rounded-lg text-inherit no-underline hover:no-underline focus:outline-none focus:ring-2"
|
||||
>
|
||||
<Card className="hover:bg-primary/30 w-full transition-colors">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-foreground text-xl">
|
||||
<Icons.ColorChange className="h-12 w-12" />
|
||||
Patterns
|
||||
</CardTitle>
|
||||
<CardDescription className="text-lg">
|
||||
Component-Based Layout Examples
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx-auto my-4 max-w-5xl pt-4 pb-6">
|
||||
<h1 className="text-foreground ml-6 mb-6 text-5xl">Colors & Typography</h1>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Colors"
|
||||
description="Updated color variables for new components."
|
||||
code={`Code Example Coming Soon`}
|
||||
>
|
||||
<div className="mb-6 grid grid-cols-[28%,1fr] items-start gap-x-8">
|
||||
<div className="space-y-2.5">
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="bg-highlight h-[30px] w-[30px] rounded"></div>
|
||||
<span className="text-foreground text-lg">highlight</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-3"></div>
|
||||
</div>
|
||||
<div className="text-secondary-foreground flex items-center pt-1.5 text-lg">
|
||||
Used for active or selected elements in the Viewer.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-6 grid grid-cols-[28%,1fr] items-start gap-x-8">
|
||||
<div className="space-y-2.5">
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="bg-primary h-[30px] w-[30px] rounded"></div>
|
||||
<span className="text-foreground text-lg">primary</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-3"></div>
|
||||
</div>
|
||||
<div className="text-secondary-foreground flex items-center pt-1.5 text-lg">
|
||||
Used for Actions. Icons use 'primary' at 100% opacity while various components will
|
||||
use a reduced opacity. Hover and other states increase the opacity.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-8 grid grid-cols-[28%,1fr] items-start gap-x-8">
|
||||
<div className="space-y-2.5">
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="bg-popover h-[30px] w-[30px] rounded"></div>
|
||||
<span className="text-foreground text-lg">popover</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="bg-muted h-[30px] w-[30px] rounded"></div>
|
||||
<span className="text-foreground text-lg">muted</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="bg-background border-input h-[30px] w-[30px] rounded border"></div>
|
||||
<span className="text-foreground text-lg">background</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-secondary-foreground flex items-center pt-1.5 text-lg">
|
||||
These three colors are used as background colors. For the lowest level above black
|
||||
use 'background'. For normal panel backgrounds and other interactive components, use
|
||||
'muted'. For elements such as menus and popovers, use 'popover'.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-8 grid grid-cols-[28%,1fr] items-start gap-x-8">
|
||||
<div className="space-y-2.5">
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="bg-foreground h-[30px] w-[30px] rounded"></div>
|
||||
<span className="text-foreground text-lg">foreground</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="bg-muted-foreground border-input h-[30px] w-[30px] rounded border"></div>
|
||||
<span className="text-foreground text-lg">muted-foreground</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-secondary-foreground flex items-center pt-1.5 text-lg">
|
||||
For primary and important text, use 'foreground'. When secondary text is available,
|
||||
use 'muted-foreground' to create separation and readability.
|
||||
</div>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Typography"
|
||||
description="Type variables and guidelines"
|
||||
code={`
|
||||
Code example coming soon
|
||||
`}
|
||||
>
|
||||
<div className="mb-6 grid grid-cols-[28%,1fr] items-start gap-x-8">
|
||||
<div className="space-y-2.5">
|
||||
<div className="flex items-center space-x-3 text-base">
|
||||
<span className="text-foreground">text-base</span>
|
||||
<span className="text-muted-foreground">13px</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-3"></div>
|
||||
</div>
|
||||
<div className="text-secondary-foreground flex items-center pt-0 text-lg">
|
||||
text-base is used as the base font size of the Viewer interface. Use when putting
|
||||
text in panels or other interface elements next to medical images.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-6 grid grid-cols-[28%,1fr] items-start gap-x-8">
|
||||
<div className="space-y-2.5">
|
||||
<div className="flex items-center space-x-3 text-lg">
|
||||
<span className="text-foreground">text-lg</span>
|
||||
<span className="text-muted-foreground">14px</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-3"></div>
|
||||
</div>
|
||||
<div className="text-secondary-foreground flex items-center pt-0 text-lg">
|
||||
text-lg can be used for dialog text or important messaging text within the Viewer.
|
||||
Use this font size for easier reading on other standard text pages.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-6 grid grid-cols-[28%,1fr] items-start gap-x-8">
|
||||
<div className="space-y-2.5">
|
||||
<div className="flex items-center space-x-3 text-xl">
|
||||
<span className="text-foreground">text-xl</span>
|
||||
<span className="text-muted-foreground">16px</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-3"></div>
|
||||
</div>
|
||||
<div className="text-secondary-foreground flex items-center pt-0 text-lg">
|
||||
text-xl can be used as headings within dialogs or messaging.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-6 grid grid-cols-[28%,1fr] items-start gap-x-8">
|
||||
<div className="space-y-2.5">
|
||||
<div className="flex items-center space-x-3 text-2xl">
|
||||
<span className="text-foreground">text-2xl</span>
|
||||
<span className="text-muted-foreground">18px</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-3"></div>
|
||||
</div>
|
||||
<div className="text-secondary-foreground flex items-center pt-0 text-lg">
|
||||
text-2xl can be used for page headers in the Viewer application or as dialog titles.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-6 grid grid-cols-[28%,1fr] items-start gap-x-8">
|
||||
<div className="space-y-2.5">
|
||||
<div className="flex items-center space-x-3 text-3xl">
|
||||
<span className="text-foreground">text-3xl</span>
|
||||
<span className="text-muted-foreground">20px</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-3"></div>
|
||||
</div>
|
||||
<div className="text-secondary-foreground flex items-center pt-0 text-lg">
|
||||
text-3xl can be used for extra large text size in the application.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-6 grid grid-cols-[28%,1fr] items-start gap-x-8">
|
||||
<div className="space-y-2.5">
|
||||
<div className="flex items-center space-x-3 text-sm">
|
||||
<span className="text-foreground">text-sm</span>
|
||||
<span className="text-muted-foreground">12px</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-3"></div>
|
||||
</div>
|
||||
<div className="text-secondary-foreground flex items-center pt-0 text-lg">
|
||||
text-sm can be used for details that do not need to be standard sizes in the Viewer.
|
||||
</div>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
|
||||
const [showCode, setShowCode] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="bg-background mb-8 rounded-lg p-6">
|
||||
<div className="mb-4 flex items-start justify-between">
|
||||
<div>
|
||||
<h2 className="text-highlight text-2xl">{title}</h2>
|
||||
</div>
|
||||
<Button
|
||||
className="text-primary"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setShowCode(!showCode)}
|
||||
>
|
||||
{showCode ? 'Hide Code' : 'Show Code'} <Icons.Code className="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-9 md:grid-cols-3">
|
||||
<div className="text-lg md:col-span-1">
|
||||
{description && <p className="text-secondary-foreground mt-2">{description}</p>}
|
||||
</div>
|
||||
<div className="flex min-h-[120px] items-center md:col-span-2">
|
||||
<div className="showcase-content">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
{showCode && (
|
||||
<pre className="border-input mt-4 overflow-x-auto rounded-md border bg-black p-4 text-sm">
|
||||
<code>{code}</code>
|
||||
</pre>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
|
||||
// const [showCode, setShowCode] = useState(false);
|
||||
|
||||
// return (
|
||||
// <div className="bg-background mb-8 rounded-lg p-6">
|
||||
// <div className="mb-4 flex items-start justify-between">
|
||||
// <div>
|
||||
// <h2 className="text-2xl font-bold">{title}</h2>
|
||||
// {description && <p className="text-secondary-foreground mt-1">{description}</p>}
|
||||
// </div>
|
||||
// <Button
|
||||
// className="text-primary"
|
||||
// variant="outline"
|
||||
// size="sm"
|
||||
// onClick={() => setShowCode(!showCode)}
|
||||
// >
|
||||
// {showCode ? 'Hide Code' : 'Show Code'} <Icons.Code className="ml-2 h-4 w-4" />
|
||||
// </Button>
|
||||
// </div>
|
||||
// <div className="showcase-content mb-4">{children}</div>
|
||||
// {showCode && (
|
||||
// <pre className="mt-4 overflow-x-auto rounded-md bg-black p-4 text-sm">
|
||||
// <code>{code}</code>
|
||||
// </pre>
|
||||
// )}
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
@@ -0,0 +1,651 @@
|
||||
import React, { useState } from 'react';
|
||||
import '../css/custom.css';
|
||||
|
||||
import Layout from '@theme/Layout';
|
||||
import { Label } from '../../../ui-next/src/components/Label';
|
||||
import { Input } from '../../../ui-next/src/components/Input';
|
||||
import { Separator } from '../../../ui-next/src/components/Separator';
|
||||
import { Tabs, TabsList, TabsTrigger } from '../../../ui-next/src/components/Tabs';
|
||||
import {
|
||||
Select,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectValue,
|
||||
} from '../../../ui-next/src/components/Select';
|
||||
import { Button } from '../../../ui-next/src/components/Button';
|
||||
import { Switch } from '../../../ui-next/src/components/Switch';
|
||||
import { Checkbox } from '../../../ui-next/src/components/Checkbox';
|
||||
import { Toggle } from '../../../ui-next/src/components/Toggle';
|
||||
import { Slider } from '../../../ui-next/src/components/Slider';
|
||||
import { ScrollArea } from '../../../ui-next/src/components/ScrollArea';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
} from '../../../ui-next/src/components/DropdownMenu';
|
||||
import { Icons } from '../../../ui-next/src/components/Icons';
|
||||
import { Toaster, toast } from '../../../ui-next/src/components/Sonner';
|
||||
import { DataRow } from '../../../ui-next/src/components/DataRow';
|
||||
import DataRowExample from './patterns/DataRowExample';
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardFooter,
|
||||
CardTitle,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
} from '../../../ui-next/src/components/Card';
|
||||
|
||||
interface ShowcaseRowProps {
|
||||
title: string;
|
||||
description?: string;
|
||||
children: React.ReactNode;
|
||||
code: string;
|
||||
}
|
||||
|
||||
export default function ComponentShowcase() {
|
||||
// Handlers to trigger different types of toasts
|
||||
const triggerSuccess = () => {
|
||||
toast.success('This is a success toast!');
|
||||
};
|
||||
|
||||
const triggerError = () => {
|
||||
toast.error('This is an error toast!');
|
||||
};
|
||||
|
||||
const triggerInfo = () => {
|
||||
toast.info('This is an info toast!');
|
||||
};
|
||||
|
||||
const triggerWarning = () => {
|
||||
toast.warning('This is a warning toast!');
|
||||
};
|
||||
|
||||
// Handler to trigger a toast.promise example
|
||||
const triggerPromiseToast = () => {
|
||||
const promise = () =>
|
||||
new Promise<{ name: string }>(resolve =>
|
||||
setTimeout(() => resolve({ name: 'Segmentation 1' }), 3000)
|
||||
);
|
||||
|
||||
toast.promise(promise(), {
|
||||
loading: 'Loading Segmentation...',
|
||||
success: data => `${data.name} has been added`,
|
||||
error: 'Error',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with description
|
||||
const triggerDescriptionToast = () => {
|
||||
toast.success('Completed', {
|
||||
description: 'This is a detailed description of the success message.',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with an action button
|
||||
const triggerActionButtonToast = () => {
|
||||
toast.info('No active segmentation detected', {
|
||||
description: 'Create a segmentation before using the Brush',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with a cancel button
|
||||
const triggerCancelButtonToast = () => {
|
||||
toast.error('No active segmentation detected', {
|
||||
description: 'Create a segmentation before using the Brush',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with both action and cancel buttons
|
||||
const triggerCombinedToast = () => {
|
||||
toast.warning('Warning!', {
|
||||
description: 'This is a warning with both action and cancel buttons.',
|
||||
action: (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => alert('Retry action clicked')}
|
||||
>
|
||||
Retry
|
||||
</Button>
|
||||
),
|
||||
cancel: (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => toast.dismiss()}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a loading toast using Toaster's default loading icon
|
||||
const showLoadingToast = () => {
|
||||
toast.loading('Loading your data...');
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout
|
||||
title="Components"
|
||||
description="OHIF Viewer Components"
|
||||
>
|
||||
<div className="text-foreground min-h-screen bg-black">
|
||||
<div className="mx-auto my-4 max-w-5xl pt-6 pb-3">
|
||||
<div className="grid grid-cols-1 gap-5 md:grid-cols-3">
|
||||
<a
|
||||
href="/colors-and-type"
|
||||
className="focus:ring-primary block rounded-lg text-inherit no-underline hover:no-underline focus:outline-none focus:ring-2"
|
||||
>
|
||||
<Card className="hover:bg-primary/30 w-full transition-colors">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-foreground text-xl">
|
||||
<Icons.ColorChange className="h-12 w-12" />
|
||||
Colors & Typography
|
||||
</CardTitle>
|
||||
<CardDescription className="text-base">
|
||||
Color Palette and Typography Guidelines
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
</a>
|
||||
<a
|
||||
href="/components-list"
|
||||
className="focus:ring-primary block rounded-lg text-inherit no-underline hover:no-underline focus:outline-none focus:ring-2"
|
||||
>
|
||||
<Card className="hover:bg-primary/30 w-full transition-colors">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-foreground text-xl">
|
||||
<Icons.ColorChange className="h-12 w-12" />
|
||||
Components
|
||||
</CardTitle>
|
||||
<CardDescription className="text-base">
|
||||
Essential UI Components with Variants
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
</a>
|
||||
<a
|
||||
href="/patterns"
|
||||
className="focus:ring-primary block rounded-lg text-inherit no-underline hover:no-underline focus:outline-none focus:ring-2"
|
||||
>
|
||||
<Card className="hover:bg-primary/30 w-full transition-colors">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-foreground text-xl">
|
||||
<Icons.ColorChange className="h-12 w-12" />
|
||||
Patterns
|
||||
</CardTitle>
|
||||
<CardDescription className="text-base">
|
||||
Component-Based Layout Examples
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx-auto my-4 max-w-5xl pt-4 pb-6">
|
||||
<div className="ml-6 mb-6 text-base">
|
||||
<h1 className="text-foreground mb-3 text-5xl">Components</h1>
|
||||
</div>
|
||||
|
||||
{/* Alphabetically Sorted ShowcaseRows */}
|
||||
<ShowcaseRow
|
||||
title="Buttons"
|
||||
description="Button components and size variants. Use the primary and secondary buttons in dialogs or screens where one action is required. In the Viewer application, use ghost button in panels where many different actions are available."
|
||||
code={`
|
||||
<Button variant="default">Primary Button</Button>
|
||||
|
||||
<Button variant="secondary">Secondary Button</Button>
|
||||
|
||||
<Button variant="ghost">Ghost Button</Button>
|
||||
|
||||
<Button variant="ghost" size="icon">?</Button>
|
||||
|
||||
<Button variant="link">Link</Button>
|
||||
`}
|
||||
>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
<Button variant="default">Primary Button</Button>
|
||||
<Button variant="secondary">Secondary Button</Button>
|
||||
<Button variant="ghost">Ghost Button</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
>
|
||||
?
|
||||
</Button>
|
||||
<Button variant="link">Link</Button>
|
||||
</div>
|
||||
<div className="mt-6 flex flex-wrap gap-4">
|
||||
<Button
|
||||
variant="default"
|
||||
size="lg"
|
||||
className="w-[107px]"
|
||||
>
|
||||
Large Button
|
||||
</Button>
|
||||
<Button
|
||||
variant="default"
|
||||
size="sm"
|
||||
>
|
||||
Small Button
|
||||
</Button>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Checkbox"
|
||||
description="When possible use Switch in place of checkbox. If necessary, Checkbox provides a smaller component to change between two states or options."
|
||||
code={`
|
||||
<div className="items-top flex space-x-2">
|
||||
<Checkbox id="terms1" />
|
||||
<div className="grid gap-1.5 pt-0.5 leading-none">
|
||||
<Label>Display inactive segmentations</Label>
|
||||
</div>
|
||||
</div>
|
||||
`}
|
||||
>
|
||||
<div className="items-top flex space-x-2">
|
||||
<Checkbox id="terms1" />
|
||||
<div className="grid gap-1.5 pt-0.5 leading-none">
|
||||
<Label>Display inactive segmentations</Label>
|
||||
</div>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Data Row"
|
||||
description="A selectable row with action menu options and visibility toggle. Color, Secondary details, and Image Series are optional to display."
|
||||
code={`
|
||||
Example code coming soon.
|
||||
`}
|
||||
>
|
||||
{/* Render the DataRowExample component */}
|
||||
<DataRowExample />
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Dropdown Menu"
|
||||
description="Dropdown menu provides a flexible list of options that can open from buttons or other elements"
|
||||
code={`
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
<Button>Open Basic</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem>Item 1</DropdownMenuItem>
|
||||
<DropdownMenuItem>Item 2</DropdownMenuItem>
|
||||
<DropdownMenuItem>Long name Item 3</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button>Open Align Start</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuItem>Item 1</DropdownMenuItem>
|
||||
<DropdownMenuItem>Item 2</DropdownMenuItem>
|
||||
<DropdownMenuItem>Long name Item 3</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button>Open Align End</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem>Item 1</DropdownMenuItem>
|
||||
<DropdownMenuItem>Item 2</DropdownMenuItem>
|
||||
<DropdownMenuItem>Long name Item 3</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button>Open Align Top</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent side="top" align="start">
|
||||
<DropdownMenuItem onSelect={() => console.debug('Item 1')}>Item 1</DropdownMenuItem>
|
||||
<DropdownMenuItem onSelect={() => console.debug('Item 2')}>Item 2</DropdownMenuItem>
|
||||
<DropdownMenuItem onSelect={() => console.debug('Item 3')}>Long name Item 3</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
`}
|
||||
>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
<Button>Open Basic</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem>Item 1</DropdownMenuItem>
|
||||
<DropdownMenuItem>Item 2</DropdownMenuItem>
|
||||
<DropdownMenuItem>Long name Item 3</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button>Open Align Start</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuItem>Item 1</DropdownMenuItem>
|
||||
<DropdownMenuItem>Item 2</DropdownMenuItem>
|
||||
<DropdownMenuItem>Long name Item 3</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button>Open Align End</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem>Item 1</DropdownMenuItem>
|
||||
<DropdownMenuItem>Item 2</DropdownMenuItem>
|
||||
<DropdownMenuItem>Long name Item 3</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button>Open Align Top</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
side="top"
|
||||
align="start"
|
||||
>
|
||||
<DropdownMenuItem onSelect={() => console.debug('Item 1')}>
|
||||
Item 1
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onSelect={() => console.debug('Item 2')}>
|
||||
Item 2
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onSelect={() => console.debug('Item 3')}>
|
||||
Long name Item 3
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Input"
|
||||
description="Input fields can be used with or without example text"
|
||||
code={`
|
||||
<div className="inline-block">
|
||||
<div className="mr-4 inline-block">
|
||||
<Label>Patient Weight</Label>
|
||||
</div>
|
||||
<div className="inline-block">
|
||||
<Input placeholder="(kg)" />
|
||||
</div>
|
||||
</div>
|
||||
`}
|
||||
>
|
||||
<div className="inline-block">
|
||||
<div className="mr-4 inline-block">
|
||||
<Label>Patient Weight</Label>
|
||||
</div>
|
||||
<div className="inline-block">
|
||||
<Input placeholder="(kg)" />
|
||||
</div>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Scroll Area"
|
||||
description="Displays a scroll indicator when hovering within an element."
|
||||
code={`
|
||||
<ScrollArea className="border-input bg-background h-[150px] w-[350px] rounded-md border p-2 text-sm text-white">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
|
||||
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
|
||||
non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
|
||||
magna aliqua.
|
||||
</ScrollArea>
|
||||
`}
|
||||
>
|
||||
<ScrollArea className="border-input bg-background h-[150px] w-[350px] rounded-md border p-2 text-sm text-white">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
|
||||
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
|
||||
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
|
||||
dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
|
||||
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt
|
||||
mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit,
|
||||
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
</ScrollArea>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Select"
|
||||
description="Switch between a list of options"
|
||||
code={`
|
||||
<Select>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Theme" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="light">Light</SelectItem>
|
||||
<SelectItem value="dark">Dark</SelectItem>
|
||||
<SelectItem value="system">System</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
`}
|
||||
>
|
||||
<Select>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Theme" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="light">Light</SelectItem>
|
||||
<SelectItem value="dark">Dark</SelectItem>
|
||||
<SelectItem value="system">System</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Slider"
|
||||
description="Used to select a value in a predefined range."
|
||||
code={`
|
||||
<div className="w-40 px-5">
|
||||
<Slider
|
||||
className="w-full"
|
||||
defaultValue={[50]}
|
||||
max={100}
|
||||
step={1}
|
||||
/>
|
||||
</div>
|
||||
`}
|
||||
>
|
||||
<div className="w-40 px-5">
|
||||
<Slider
|
||||
className="w-full"
|
||||
defaultValue={[50]}
|
||||
max={100}
|
||||
step={1}
|
||||
/>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Switch"
|
||||
description="A toggle Switch is used to change between two different states. Use descriptive labels next to Switches that are understandable before interacting."
|
||||
code={`
|
||||
<Switch />
|
||||
`}
|
||||
>
|
||||
<Switch defaultChecked />
|
||||
<Label className="text-foreground mx-2 w-14 flex-none whitespace-nowrap text-sm">
|
||||
Sync changes in all viewports
|
||||
</Label>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Tabs"
|
||||
description="Tabs (or segmented controls) can be used to provide navigation options or allow users to switch between multiple options (e.g., tool settings) "
|
||||
code={`
|
||||
<Tabs className="w-[400px]">
|
||||
<TabsList>
|
||||
<TabsTrigger value="circle">Circle</TabsTrigger>
|
||||
<Separator orientation="vertical" />
|
||||
<TabsTrigger value="sphere">Sphere</TabsTrigger>
|
||||
<Separator orientation="vertical" />
|
||||
<TabsTrigger value="square">Square</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
`}
|
||||
>
|
||||
<Tabs className="w-[400px]">
|
||||
<TabsList>
|
||||
<TabsTrigger value="circle">Circle</TabsTrigger>
|
||||
<Separator orientation="vertical" />
|
||||
<TabsTrigger value="sphere">Sphere</TabsTrigger>
|
||||
<Separator orientation="vertical" />
|
||||
<TabsTrigger value="square">Square</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Toast"
|
||||
description="A toast notification displays temporary feedback messages to users above the current UI. Notifications stack into one unit after multiple cascading notifications."
|
||||
code={`
|
||||
Example code coming soon.
|
||||
|
||||
`}
|
||||
>
|
||||
{/* Toast Examples Section */}
|
||||
Simple message:
|
||||
<div className="mt-2 mb-7 space-x-2">
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerPromiseToast}
|
||||
>
|
||||
Loading & Success Toast
|
||||
</Button>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerSuccess}
|
||||
>
|
||||
Success Toast
|
||||
</Button>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerError}
|
||||
>
|
||||
Error Toast
|
||||
</Button>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerInfo}
|
||||
>
|
||||
Info Toast
|
||||
</Button>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerWarning}
|
||||
>
|
||||
Warning Toast
|
||||
</Button>
|
||||
</div>
|
||||
Message with details:
|
||||
<div className="mt-2 space-x-2">
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerDescriptionToast}
|
||||
>
|
||||
Success Toast
|
||||
</Button>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerActionButtonToast}
|
||||
>
|
||||
Info Toast
|
||||
</Button>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerCancelButtonToast}
|
||||
>
|
||||
Error Toast
|
||||
</Button>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerCombinedToast}
|
||||
>
|
||||
Toast with Buttons
|
||||
</Button>
|
||||
</div>
|
||||
{/* Render the Toaster component */}
|
||||
<Toaster />
|
||||
</ShowcaseRow>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
|
||||
const [showCode, setShowCode] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="bg-background mb-8 rounded-lg p-6">
|
||||
<div className="mb-4 flex items-start justify-between">
|
||||
<div>
|
||||
<h2 className="text-highlight text-2xl">{title}</h2>
|
||||
</div>
|
||||
<Button
|
||||
className="text-primary"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setShowCode(!showCode)}
|
||||
>
|
||||
{showCode ? 'Hide Code' : 'Show Code'} <Icons.Code className="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-9 md:grid-cols-3">
|
||||
<div className="text-base md:col-span-1">
|
||||
{description && <p className="text-secondary-foreground mt-2">{description}</p>}
|
||||
</div>
|
||||
<div className="flex min-h-[120px] items-center md:col-span-2">
|
||||
<div className="showcase-content">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
{showCode && (
|
||||
<pre className="border-input mt-4 overflow-x-auto rounded-md border bg-black p-4 text-sm">
|
||||
<code>{code}</code>
|
||||
</pre>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
|
||||
// const [showCode, setShowCode] = useState(false);
|
||||
|
||||
// return (
|
||||
// <div className="bg-background mb-8 rounded-lg p-6">
|
||||
// <div className="mb-4 flex items-start justify-between">
|
||||
// <div>
|
||||
// <h2 className="text-2xl font-bold">{title}</h2>
|
||||
// {description && <p className="text-muted-foreground mt-1">{description}</p>}
|
||||
// </div>
|
||||
// <Button
|
||||
// className="text-primary"
|
||||
// variant="outline"
|
||||
// size="sm"
|
||||
// onClick={() => setShowCode(!showCode)}
|
||||
// >
|
||||
// {showCode ? 'Hide Code' : 'Show Code'} <Icons.Code className="ml-2 h-4 w-4" />
|
||||
// </Button>
|
||||
// </div>
|
||||
// <div className="showcase-content mb-4">{children}</div>
|
||||
// {showCode && (
|
||||
// <pre className="mt-4 overflow-x-auto rounded-md bg-black p-4 text-sm">
|
||||
// <code>{code}</code>
|
||||
// </pre>
|
||||
// )}
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
@@ -0,0 +1,265 @@
|
||||
import React, { useState } from 'react';
|
||||
import '../css/custom.css';
|
||||
|
||||
import Layout from '@theme/Layout';
|
||||
import { Label } from '../../../ui-next/src/components/Label';
|
||||
import { Input } from '../../../ui-next/src/components/Input';
|
||||
import { Separator } from '../../../ui-next/src/components/Separator';
|
||||
import { Tabs, TabsList, TabsTrigger } from '../../../ui-next/src/components/Tabs';
|
||||
import {
|
||||
Select,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectValue,
|
||||
} from '../../../ui-next/src/components/Select';
|
||||
import { Button } from '../../../ui-next/src/components/Button';
|
||||
import { Switch } from '../../../ui-next/src/components/Switch';
|
||||
import { Checkbox } from '../../../ui-next/src/components/Checkbox';
|
||||
import { Toggle } from '../../../ui-next/src/components/Toggle';
|
||||
import { Slider } from '../../../ui-next/src/components/Slider';
|
||||
import { ScrollArea } from '../../../ui-next/src/components/ScrollArea';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
} from '../../../ui-next/src/components/DropdownMenu';
|
||||
import { Icons } from '../../../ui-next/src/components/Icons';
|
||||
import { Toaster, toast } from '../../../ui-next/src/components/Sonner';
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardFooter,
|
||||
CardTitle,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
} from '../../../ui-next/src/components/Card';
|
||||
|
||||
interface ShowcaseRowProps {
|
||||
title: string;
|
||||
description?: string;
|
||||
children: React.ReactNode;
|
||||
code: string;
|
||||
}
|
||||
|
||||
export default function ComponentShowcase() {
|
||||
// Handlers to trigger different types of toasts
|
||||
const triggerSuccess = () => {
|
||||
toast.success('This is a success toast!');
|
||||
};
|
||||
|
||||
const triggerError = () => {
|
||||
toast.error('This is an error toast!');
|
||||
};
|
||||
|
||||
const triggerInfo = () => {
|
||||
toast.info('This is an info toast!');
|
||||
};
|
||||
|
||||
const triggerWarning = () => {
|
||||
toast.warning('This is a warning toast!');
|
||||
};
|
||||
|
||||
// Handler to trigger a toast.promise example
|
||||
const triggerPromiseToast = () => {
|
||||
const promise = () =>
|
||||
new Promise<{ name: string }>(resolve =>
|
||||
setTimeout(() => resolve({ name: 'Segmentation 1' }), 3000)
|
||||
);
|
||||
|
||||
toast.promise(promise(), {
|
||||
loading: 'Loading Segmentation...',
|
||||
success: data => `${data.name} has been added`,
|
||||
error: 'Error',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with description
|
||||
const triggerDescriptionToast = () => {
|
||||
toast.success('Success heading', {
|
||||
description: 'This is a detailed description of the success message.',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with an action button
|
||||
const triggerActionButtonToast = () => {
|
||||
toast.info('No active segmentation detected', {
|
||||
description: 'Create a segmentation before using the Brush',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with a cancel button
|
||||
const triggerCancelButtonToast = () => {
|
||||
toast.error('No active segmentation detected', {
|
||||
description: 'Create a segmentation before using the Brush',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with both action and cancel buttons
|
||||
const triggerCombinedToast = () => {
|
||||
toast.warning('Warning!', {
|
||||
description: 'This is a warning with both action and cancel buttons.',
|
||||
action: (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => alert('Retry action clicked')}
|
||||
>
|
||||
Retry
|
||||
</Button>
|
||||
),
|
||||
cancel: (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => toast.dismiss()}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a loading toast using Toaster's default loading icon
|
||||
const showLoadingToast = () => {
|
||||
toast.loading('Loading your data...');
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout
|
||||
title="OHIF Viewer Design System"
|
||||
description="OHIF Viewer Design System"
|
||||
>
|
||||
<div className="text-foreground min-h-screen bg-black">
|
||||
<div className="mx-auto my-4 max-w-5xl pt-6 pb-3">
|
||||
<div className="grid grid-cols-1 gap-5 md:grid-cols-3">
|
||||
<a
|
||||
href="/colors-and-type"
|
||||
className="focus:ring-primary block rounded-lg text-inherit no-underline hover:no-underline focus:outline-none focus:ring-2"
|
||||
>
|
||||
<Card className="hover:bg-primary/30 w-full transition-colors">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-foreground text-xl">
|
||||
<Icons.ColorChange className="h-12 w-12" />
|
||||
Colors & Typography
|
||||
</CardTitle>
|
||||
<CardDescription className="text-lg">
|
||||
Color Palette and Typography Guidelines
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
</a>
|
||||
<a
|
||||
href="/components-list"
|
||||
className="focus:ring-primary block rounded-lg text-inherit no-underline hover:no-underline focus:outline-none focus:ring-2"
|
||||
>
|
||||
<Card className="hover:bg-primary/30 w-full transition-colors">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-foreground text-xl">
|
||||
<Icons.ColorChange className="h-12 w-12" />
|
||||
Components
|
||||
</CardTitle>
|
||||
<CardDescription className="text-lg">
|
||||
Essential UI Components with Variants
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
</a>
|
||||
<a
|
||||
href="/patterns"
|
||||
className="focus:ring-primary block rounded-lg text-inherit no-underline hover:no-underline focus:outline-none focus:ring-2"
|
||||
>
|
||||
<Card className="hover:bg-primary/30 w-full transition-colors">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-foreground text-xl">
|
||||
<Icons.ColorChange className="h-12 w-12" />
|
||||
Patterns
|
||||
</CardTitle>
|
||||
<CardDescription className="text-lg">
|
||||
Component-Based Layout Examples
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
</a>
|
||||
</div>
|
||||
<div className="mt-12">
|
||||
<div className="text-md mx-auto max-w-2xl"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
|
||||
const [showCode, setShowCode] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="bg-background mb-8 rounded-lg p-6">
|
||||
{/* Header Section */}
|
||||
<div className="mb-4 flex items-start justify-between">
|
||||
<div>
|
||||
<h2 className="text-foreground text-2xl">{title}</h2>
|
||||
</div>
|
||||
<Button
|
||||
className="text-primary"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setShowCode(!showCode)}
|
||||
>
|
||||
{showCode ? 'Hide Code' : 'Show Code'} <Icons.Code className="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Content Section: 1/3 Left, 2/3 Right */}
|
||||
<div className="grid grid-cols-1 gap-9 md:grid-cols-3">
|
||||
{/* Left Side: Title and Description */}
|
||||
<div className="text-lg md:col-span-1">
|
||||
{description && <p className="text-muted-foreground mt-2">{description}</p>}
|
||||
</div>
|
||||
|
||||
{/* Right Side: Example */}
|
||||
<div className="flex min-h-[120px] items-center md:col-span-2">
|
||||
<div className="showcase-content">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Code Section */}
|
||||
{showCode && (
|
||||
<pre className="mt-4 overflow-x-auto rounded-md bg-black p-4 text-sm">
|
||||
<code>{code}</code>
|
||||
</pre>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
|
||||
// const [showCode, setShowCode] = useState(false);
|
||||
|
||||
// return (
|
||||
// <div className="bg-background mb-8 rounded-lg p-6">
|
||||
// <div className="mb-4 flex items-start justify-between">
|
||||
// <div>
|
||||
// <h2 className="text-2xl font-bold">{title}</h2>
|
||||
// {description && <p className="text-muted-foreground mt-1">{description}</p>}
|
||||
// </div>
|
||||
// <Button
|
||||
// className="text-primary"
|
||||
// variant="outline"
|
||||
// size="sm"
|
||||
// onClick={() => setShowCode(!showCode)}
|
||||
// >
|
||||
// {showCode ? 'Hide Code' : 'Show Code'} <Icons.Code className="ml-2 h-4 w-4" />
|
||||
// </Button>
|
||||
// </div>
|
||||
// <div className="showcase-content mb-4">{children}</div>
|
||||
// {showCode && (
|
||||
// <pre className="mt-4 overflow-x-auto rounded-md bg-black p-4 text-sm">
|
||||
// <code>{code}</code>
|
||||
// </pre>
|
||||
// )}
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
@@ -0,0 +1,321 @@
|
||||
import React, { useState } from 'react';
|
||||
import '../css/custom.css';
|
||||
|
||||
import Layout from '@theme/Layout';
|
||||
import { Label } from '../../../ui-next/src/components/Label';
|
||||
import { Input } from '../../../ui-next/src/components/Input';
|
||||
import { Separator } from '../../../ui-next/src/components/Separator';
|
||||
import { Tabs, TabsList, TabsTrigger } from '../../../ui-next/src/components/Tabs';
|
||||
import {
|
||||
Select,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectValue,
|
||||
} from '../../../ui-next/src/components/Select';
|
||||
import { Button } from '../../../ui-next/src/components/Button';
|
||||
import { Switch } from '../../../ui-next/src/components/Switch';
|
||||
import { Checkbox } from '../../../ui-next/src/components/Checkbox';
|
||||
import { Toggle } from '../../../ui-next/src/components/Toggle';
|
||||
import { Slider } from '../../../ui-next/src/components/Slider';
|
||||
import { ScrollArea } from '../../../ui-next/src/components/ScrollArea';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
} from '../../../ui-next/src/components/DropdownMenu';
|
||||
import { Icons } from '../../../ui-next/src/components/Icons';
|
||||
import { Toaster, toast } from '../../../ui-next/src/components/Sonner';
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardFooter,
|
||||
CardTitle,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
} from '../../../ui-next/src/components/Card';
|
||||
|
||||
interface ShowcaseRowProps {
|
||||
title: string;
|
||||
description?: string;
|
||||
children: React.ReactNode;
|
||||
code: string;
|
||||
}
|
||||
|
||||
export default function ComponentShowcase() {
|
||||
// Function to open links in a new window
|
||||
const openLinkInNewWindow = url => {
|
||||
window.open(url, '_blank', 'noopener,noreferrer');
|
||||
};
|
||||
|
||||
// Handlers to trigger different types of toasts
|
||||
const triggerSuccess = () => {
|
||||
toast.success('This is a success toast!');
|
||||
};
|
||||
|
||||
const triggerError = () => {
|
||||
toast.error('This is an error toast!');
|
||||
};
|
||||
|
||||
const triggerInfo = () => {
|
||||
toast.info('This is an info toast!');
|
||||
};
|
||||
|
||||
const triggerWarning = () => {
|
||||
toast.warning('This is a warning toast!');
|
||||
};
|
||||
|
||||
// Handler to trigger a toast.promise example
|
||||
const triggerPromiseToast = () => {
|
||||
const promise = () =>
|
||||
new Promise<{ name: string }>(resolve =>
|
||||
setTimeout(() => resolve({ name: 'Segmentation 1' }), 3000)
|
||||
);
|
||||
|
||||
toast.promise(promise(), {
|
||||
loading: 'Loading Segmentation...',
|
||||
success: data => `${data.name} has been added`,
|
||||
error: 'Error',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with description
|
||||
const triggerDescriptionToast = () => {
|
||||
toast.success('Success heading', {
|
||||
description: 'This is a detailed description of the success message.',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with an action button
|
||||
const triggerActionButtonToast = () => {
|
||||
toast.info('No active segmentation detected', {
|
||||
description: 'Create a segmentation before using the Brush',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with a cancel button
|
||||
const triggerCancelButtonToast = () => {
|
||||
toast.error('No active segmentation detected', {
|
||||
description: 'Create a segmentation before using the Brush',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with both action and cancel buttons
|
||||
const triggerCombinedToast = () => {
|
||||
toast.warning('Warning!', {
|
||||
description: 'This is a warning with both action and cancel buttons.',
|
||||
action: (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => alert('Retry action clicked')}
|
||||
>
|
||||
Retry
|
||||
</Button>
|
||||
),
|
||||
cancel: (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => toast.dismiss()}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a loading toast using Toaster's default loading icon
|
||||
const showLoadingToast = () => {
|
||||
toast.loading('Loading your data...');
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout
|
||||
title="Patterns"
|
||||
description="Patterns and example layouts"
|
||||
>
|
||||
<div className="text-foreground min-h-screen bg-black">
|
||||
<div className="mx-auto my-4 max-w-5xl pt-6 pb-3">
|
||||
<div className="grid grid-cols-1 gap-5 md:grid-cols-3">
|
||||
<a
|
||||
href="/colors-and-type"
|
||||
className="focus:ring-primary block rounded-lg text-inherit no-underline hover:no-underline focus:outline-none focus:ring-2"
|
||||
>
|
||||
<Card className="hover:bg-primary/30 w-full transition-colors">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-foreground text-xl">
|
||||
<Icons.ColorChange className="h-12 w-12" />
|
||||
Colors & Typography
|
||||
</CardTitle>
|
||||
<CardDescription className="text-lg">
|
||||
Color Palette and Typography Guidelines
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
</a>
|
||||
<a
|
||||
href="/components-list"
|
||||
className="focus:ring-primary block rounded-lg text-inherit no-underline hover:no-underline focus:outline-none focus:ring-2"
|
||||
>
|
||||
<Card className="hover:bg-primary/30 w-full transition-colors">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-foreground text-xl">
|
||||
<Icons.ColorChange className="h-12 w-12" />
|
||||
Components
|
||||
</CardTitle>
|
||||
<CardDescription className="text-lg">
|
||||
Essential UI Components with Variants
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
</a>
|
||||
<a
|
||||
href="/patterns"
|
||||
className="focus:ring-primary block rounded-lg text-inherit no-underline hover:no-underline focus:outline-none focus:ring-2"
|
||||
>
|
||||
<Card className="hover:bg-primary/30 w-full transition-colors">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-foreground text-xl">
|
||||
<Icons.ColorChange className="h-12 w-12" />
|
||||
Patterns
|
||||
</CardTitle>
|
||||
<CardDescription className="text-lg">
|
||||
Component-Based Layout Examples
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx-auto my-4 max-w-5xl pt-4 pb-6">
|
||||
<h1 className="text-foreground ml-6 mb-6 text-5xl">Patterns</h1>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Segmentation List"
|
||||
description={
|
||||
<div className="space-y-4">
|
||||
<div className="block">
|
||||
Uses the Data Row component to displays a list of segments. The current
|
||||
"Segmentation" is chosen with a Select above the current list.
|
||||
</div>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={() => openLinkInNewWindow('./patterns/patterns-segmentation')}
|
||||
>
|
||||
Launch Segmentation Example
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
code={`
|
||||
aaa
|
||||
`}
|
||||
>
|
||||
<div className="flex flex-wrap gap-4"></div>
|
||||
<div className="mt-6 mb-5 flex flex-wrap gap-4">
|
||||
<img
|
||||
src="/img/patterns-segmentation.png"
|
||||
alt="Segmentation Panel"
|
||||
width={274}
|
||||
></img>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Measurement List"
|
||||
description={
|
||||
<div className="space-y-4">
|
||||
<div className="block">
|
||||
Uses the Data Row component to displays a list of measurements. A custom "Label"
|
||||
starts each row with measurement data appearing on the secondary row
|
||||
</div>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={() => openLinkInNewWindow('./patterns/patterns-measurements')}
|
||||
>
|
||||
Launch Measurements Example
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
code={`
|
||||
aaa
|
||||
`}
|
||||
>
|
||||
<div className="flex flex-wrap gap-4"></div>
|
||||
<div className="mt-6 flex flex-wrap gap-4">
|
||||
<img
|
||||
src="/img/patterns-measurements.png"
|
||||
alt="Measurements Panel"
|
||||
width={274}
|
||||
></img>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
|
||||
const [showCode, setShowCode] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="bg-background mb-8 rounded-lg p-6">
|
||||
<div className="mb-4 flex items-start justify-between">
|
||||
<div>
|
||||
<h2 className="text-highlight text-2xl">{title}</h2>
|
||||
</div>
|
||||
<Button
|
||||
className="text-primary"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setShowCode(!showCode)}
|
||||
></Button>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-9 md:grid-cols-3">
|
||||
<div className="text-lg md:col-span-1">
|
||||
{description && <p className="text-secondary-foreground mt-2">{description}</p>}
|
||||
</div>
|
||||
<div className="flex min-h-[120px] items-center md:col-span-2">
|
||||
<div className="showcase-content">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
{showCode && (
|
||||
<pre className="border-input mt-4 overflow-x-auto rounded-md border bg-black p-4 text-sm">
|
||||
<code>{code}</code>
|
||||
</pre>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
|
||||
// const [showCode, setShowCode] = useState(false);
|
||||
|
||||
// return (
|
||||
// <div className="bg-background mb-8 rounded-lg p-6">
|
||||
// <div className="mb-4 flex items-start justify-between">
|
||||
// <div>
|
||||
// <h2 className="text-2xl font-bold">{title}</h2>
|
||||
// {description && <p className="text-muted-foreground mt-1">{description}</p>}
|
||||
// </div>
|
||||
// <Button
|
||||
// className="text-primary"
|
||||
// variant="outline"
|
||||
// size="sm"
|
||||
// onClick={() => setShowCode(!showCode)}
|
||||
// >
|
||||
// {showCode ? 'Hide Code' : 'Show Code'} <Icons.Code className="ml-2 h-4 w-4" />
|
||||
// </Button>
|
||||
// </div>
|
||||
// <div className="showcase-content mb-4">{children}</div>
|
||||
// {showCode && (
|
||||
// <pre className="mt-4 overflow-x-auto rounded-md bg-black p-4 text-sm">
|
||||
// <code>{code}</code>
|
||||
// </pre>
|
||||
// )}
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
@@ -0,0 +1,91 @@
|
||||
import React from 'react';
|
||||
import { DataRow } from '../../../../ui-next/src/components/DataRow';
|
||||
import { Button } from '../../../../ui-next/src/components/Button';
|
||||
import { Icons } from '../../../../ui-next/src/components/Icons';
|
||||
|
||||
// Mock data to demonstrate DataRow usage
|
||||
const mockData = [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Segment 1',
|
||||
description: 'Description for Segment 1',
|
||||
optionalField: 'Optional Info 1',
|
||||
colorHex: '#FF5733',
|
||||
details: 'Secondary details or text',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'Segment 2',
|
||||
description: 'Description for Segment 2',
|
||||
optionalField: 'Optional Info 2',
|
||||
colorHex: '#33C1FF',
|
||||
details: 'Secondary details or text',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'Segment 3',
|
||||
description: 'Description for Segment 3',
|
||||
optionalField: 'Optional Info 3',
|
||||
colorHex: '#5533FF',
|
||||
details: 'Secondary details or text',
|
||||
},
|
||||
];
|
||||
|
||||
// Mock action options map
|
||||
const actionOptionsMap = {
|
||||
'ROI Tools': ['Edit', 'Delete', 'View'],
|
||||
};
|
||||
|
||||
interface DataItem {
|
||||
id: number;
|
||||
title: string;
|
||||
description: string;
|
||||
optionalField?: string;
|
||||
colorHex?: string;
|
||||
details?: string;
|
||||
series?: string;
|
||||
}
|
||||
|
||||
interface ListGroup {
|
||||
type: string;
|
||||
items: DataItem[];
|
||||
}
|
||||
|
||||
const DataRowExample: React.FC = () => {
|
||||
const [selectedRowId, setSelectedRowId] = React.useState<string | null>(null);
|
||||
|
||||
const handleAction = (id: string, action: string) => {
|
||||
console.log(`Action "${action}" triggered for item with id: ${id}`);
|
||||
// Implement actual action logic here
|
||||
};
|
||||
|
||||
const handleRowSelect = (id: string) => {
|
||||
setSelectedRowId(prevSelectedId => (prevSelectedId === id ? null : id));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-[280px] space-y-px">
|
||||
{mockData.map((item, index) => {
|
||||
const compositeId = `ROI Tools-${item.id}-panel`; // Ensure unique composite ID
|
||||
return (
|
||||
<DataRow
|
||||
key={`panel-${compositeId}`} // Prefix to ensure uniqueness
|
||||
number={index + 1}
|
||||
title={item.title}
|
||||
description={item.description}
|
||||
optionalField={item.optionalField}
|
||||
colorHex={item.colorHex}
|
||||
details={item.details}
|
||||
series={item.series}
|
||||
actionOptions={actionOptionsMap['ROI Tools'] || ['Action']}
|
||||
onAction={(action: string) => handleAction(compositeId, action)}
|
||||
isSelected={selectedRowId === compositeId}
|
||||
onSelect={() => handleRowSelect(compositeId)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DataRowExample;
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
import { DataRow } from '../../../../ui-next/src/components/DataRow';
|
||||
import { actionOptionsMap, dataList } from '../../../../ui-next/assets/data';
|
||||
import BrowserOnly from '@docusaurus/BrowserOnly';
|
||||
import { TooltipProvider } from '../../../../ui-next/src/components/Tooltip';
|
||||
|
||||
interface DataItem {
|
||||
id: number;
|
||||
@@ -48,82 +49,84 @@ export default function Measurements() {
|
||||
return (
|
||||
<BrowserOnly>
|
||||
{() => (
|
||||
<div className="my-4 flex max-w-6xl justify-end bg-black py-6">
|
||||
{/* Simulated Panel List for "Segmentation" */}
|
||||
<div className="w-64 space-y-0">
|
||||
<Accordion
|
||||
type="multiple"
|
||||
defaultValue={['measurements-list', 'measurements-additional']}
|
||||
tabIndex={0}
|
||||
>
|
||||
{/* Segmentation Tools */}
|
||||
<AccordionItem value="measurements-list">
|
||||
<AccordionTrigger className="bg-popover hover:bg-accent text-muted-foreground my-0.5 flex h-7 w-full items-center justify-between rounded py-2 pr-1 pl-2 font-normal">
|
||||
<span>Measurements</span>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<div className="mx-2 my-0">
|
||||
<div className="text-foreground text-sm">2024-Jan-01</div>
|
||||
<div className="text-muted-foreground border-input border-b-2 pb-1 text-sm">
|
||||
Study title lorem ipsum
|
||||
<div className="px-auto my-4 flex min-h-screen w-full justify-center bg-black py-12">
|
||||
<TooltipProvider>
|
||||
{/* Simulated Panel List for "Segmentation" */}
|
||||
<div className="w-64 space-y-0">
|
||||
<Accordion
|
||||
type="multiple"
|
||||
defaultValue={['measurements-list', 'measurements-additional']}
|
||||
tabIndex={0}
|
||||
>
|
||||
{/* Segmentation Tools */}
|
||||
<AccordionItem value="measurements-list">
|
||||
<AccordionTrigger className="bg-popover hover:bg-accent text-muted-foreground my-0.5 flex h-7 w-full items-center justify-between rounded py-2 pr-1 pl-2 font-normal">
|
||||
<span>Measurements</span>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<div className="mx-2 my-0">
|
||||
<div className="text-foreground text-sm">2024-Jan-01</div>
|
||||
<div className="text-muted-foreground border-input border-b-2 pb-1 text-sm">
|
||||
Study title lorem ipsum
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex h-9 w-full items-center rounded pr-0.5">
|
||||
<div className="flex space-x-1">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="pl-1.5"
|
||||
>
|
||||
<Icons.Download />
|
||||
<span className="pl-1">CSV</span>
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="pl-0.5"
|
||||
>
|
||||
<Icons.Add />
|
||||
Create DICOM SR
|
||||
</Button>
|
||||
<div className="flex h-9 w-full items-center rounded pr-0.5">
|
||||
<div className="flex space-x-1">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="pl-1.5"
|
||||
>
|
||||
<Icons.Download />
|
||||
<span className="pl-1">CSV</span>
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="pl-0.5"
|
||||
>
|
||||
<Icons.Add />
|
||||
Create DICOM SR
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-px">
|
||||
{roiToolsGroup.items.map((item, index) => {
|
||||
const compositeId = `${roiToolsGroup.type}-${item.id}-panel`; // Ensure unique composite ID
|
||||
return (
|
||||
<DataRow
|
||||
key={`panel-${compositeId}`} // Prefix to ensure uniqueness
|
||||
number={index + 1}
|
||||
title={item.title}
|
||||
description={item.description}
|
||||
optionalField={item.optionalField}
|
||||
colorHex={item.colorHex}
|
||||
details={item.details}
|
||||
series={item.series} // Pass the new series field
|
||||
actionOptions={actionOptionsMap[roiToolsGroup.type] || ['Action']}
|
||||
onAction={(action: string) => handleAction(compositeId, action)}
|
||||
isSelected={selectedRowId === compositeId}
|
||||
onSelect={() => handleRowSelect(compositeId)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
<div className="space-y-px">
|
||||
{roiToolsGroup.items.map((item, index) => {
|
||||
const compositeId = `${roiToolsGroup.type}-${item.id}-panel`; // Ensure unique composite ID
|
||||
return (
|
||||
<DataRow
|
||||
key={`panel-${compositeId}`} // Prefix to ensure uniqueness
|
||||
number={index + 1}
|
||||
title={item.title}
|
||||
description={item.description}
|
||||
optionalField={item.optionalField}
|
||||
colorHex={item.colorHex}
|
||||
details={item.details}
|
||||
series={item.series} // Pass the new series field
|
||||
actionOptions={actionOptionsMap[roiToolsGroup.type] || ['Action']}
|
||||
onAction={(action: string) => handleAction(compositeId, action)}
|
||||
isSelected={selectedRowId === compositeId}
|
||||
onSelect={() => handleRowSelect(compositeId)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
|
||||
{/* Additional Findings */}
|
||||
<AccordionItem value="measurements-additional">
|
||||
<AccordionTrigger className="bg-popover hover:bg-accent text-muted-foreground my-0.5 flex h-7 w-full items-center justify-between rounded py-2 pr-1 pl-2 font-normal">
|
||||
<span>Additional Findings</span>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<div className="bg-muted mb-0.5 h-12 rounded-b pb-3"></div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</div>
|
||||
{/* Additional Findings */}
|
||||
<AccordionItem value="measurements-additional">
|
||||
<AccordionTrigger className="bg-popover hover:bg-accent text-muted-foreground my-0.5 flex h-7 w-full items-center justify-between rounded py-2 pr-1 pl-2 font-normal">
|
||||
<span>Additional Findings</span>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<div className="bg-muted mb-0.5 h-12 rounded-b pb-3"></div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</div>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
)}
|
||||
</BrowserOnly>
|
||||
|
||||
@@ -75,7 +75,7 @@ export default function SegmentationPanel() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="my-4 flex h-full w-full max-w-6xl justify-end bg-black py-6">
|
||||
<div className="px-auto flex min-h-screen w-full justify-center bg-black py-12">
|
||||
<div className="w-64 space-y-0">
|
||||
<TooltipProvider>
|
||||
<Accordion
|
||||
|
||||
@@ -27,7 +27,6 @@ import { Switch } from '../../../../ui-next/src/components/Switch';
|
||||
import { Label } from '../../../../ui-next/src/components/Label';
|
||||
import { Input } from '../../../../ui-next/src/components/Input';
|
||||
import { Tabs, TabsList, TabsTrigger } from '../../../../ui-next/src/components/Tabs';
|
||||
import { TooltipProvider } from '../../../../ui-next/src';
|
||||
import BrowserOnly from '@docusaurus/BrowserOnly';
|
||||
|
||||
interface DataItem {
|
||||
@@ -77,7 +76,7 @@ export default function TMTVPatterns() {
|
||||
return (
|
||||
<BrowserOnly>
|
||||
{() => (
|
||||
<div className="px-auto my-4 flex h-full w-full justify-center bg-black py-6">
|
||||
<div className="px-auto my-4 flex min-h-screen w-full justify-center bg-black py-12">
|
||||
<div className="w-64 space-y-0">
|
||||
<Accordion
|
||||
type="multiple"
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import React from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
import { useHistory } from '@docusaurus/router';
|
||||
|
||||
export default function Hello() {
|
||||
const history = useHistory();
|
||||
|
||||
return (
|
||||
<Layout
|
||||
title="Hello"
|
||||
description="Hello React Page"
|
||||
>
|
||||
<button
|
||||
className="bg-slate-400"
|
||||
onClick={() => history.push('/ui-playground')}
|
||||
>
|
||||
ui-playground
|
||||
</button>
|
||||
<button
|
||||
className="bg-slate-400"
|
||||
onClick={() => history.push('/patterns')}
|
||||
>
|
||||
patterns
|
||||
</button>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
@@ -1,699 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import '../css/custom.css';
|
||||
|
||||
import { Label } from '../../../ui-next/src/components/Label';
|
||||
import { Input } from '../../../ui-next/src/components/Input';
|
||||
import { Separator } from '../../../ui-next/src/components/Separator';
|
||||
import { Tabs, TabsList, TabsTrigger } from '../../../ui-next/src/components/Tabs';
|
||||
import {
|
||||
Select,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectValue,
|
||||
} from '../../../ui-next/src/components/Select';
|
||||
import { Button } from '../../../ui-next/src/components/Button';
|
||||
import { Switch } from '../../../ui-next/src/components/Switch';
|
||||
import { Checkbox } from '../../../ui-next/src/components/Checkbox';
|
||||
import { Toggle } from '../../../ui-next/src/components/Toggle';
|
||||
import { Slider } from '../../../ui-next/src/components/Slider';
|
||||
import { ScrollArea } from '../../../ui-next/src/components/ScrollArea';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
} from '../../../ui-next/src/components/DropdownMenu';
|
||||
import { Icons } from '../../../ui-next/src/components/Icons';
|
||||
import { Toaster, toast } from '../../../ui-next/src/components/Sonner';
|
||||
|
||||
interface ShowcaseRowProps {
|
||||
title: string;
|
||||
description?: string;
|
||||
children: React.ReactNode;
|
||||
code: string;
|
||||
}
|
||||
|
||||
export default function ComponentShowcase() {
|
||||
// Handlers to trigger different types of toasts
|
||||
const triggerSuccess = () => {
|
||||
toast.success('This is a success toast!');
|
||||
};
|
||||
|
||||
const triggerError = () => {
|
||||
toast.error('This is an error toast!');
|
||||
};
|
||||
|
||||
const triggerInfo = () => {
|
||||
toast.info('This is an info toast!');
|
||||
};
|
||||
|
||||
const triggerWarning = () => {
|
||||
toast.warning('This is a warning toast!');
|
||||
};
|
||||
|
||||
// Handler to trigger a toast.promise example
|
||||
const triggerPromiseToast = () => {
|
||||
const promise = () =>
|
||||
new Promise<{ name: string }>(resolve =>
|
||||
setTimeout(() => resolve({ name: 'Segmentation 1' }), 3000)
|
||||
);
|
||||
|
||||
toast.promise(promise(), {
|
||||
loading: 'Loading Segmentation...',
|
||||
success: data => `${data.name} has been added`,
|
||||
error: 'Error',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with description
|
||||
const triggerDescriptionToast = () => {
|
||||
toast.success('Success heading', {
|
||||
description: 'This is a detailed description of the success message.',
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with an action button
|
||||
const triggerActionButtonToast = () => {
|
||||
toast.info('Info heading', {
|
||||
description: 'This is an info message with an action button.',
|
||||
action: (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => alert('Action button clicked')}
|
||||
>
|
||||
Undo
|
||||
</Button>
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with a cancel button
|
||||
const triggerCancelButtonToast = () => {
|
||||
toast.error('Error!', {
|
||||
description: 'This is an error message with a cancel button.',
|
||||
cancel: (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => toast.dismiss()}
|
||||
>
|
||||
Dismiss
|
||||
</Button>
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a toast with both action and cancel buttons
|
||||
const triggerCombinedToast = () => {
|
||||
toast.warning('Warning!', {
|
||||
description: 'This is a warning with both action and cancel buttons.',
|
||||
action: (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => alert('Retry action clicked')}
|
||||
>
|
||||
Retry
|
||||
</Button>
|
||||
),
|
||||
cancel: (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => toast.dismiss()}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
// Handler to trigger a loading toast using Toaster's default loading icon
|
||||
const showLoadingToast = () => {
|
||||
toast.loading('Loading your data...');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-background text-foreground h-full">
|
||||
<div className="mx-auto my-4 max-w-6xl py-6">
|
||||
<ShowcaseRow
|
||||
title="Buttons"
|
||||
description="Various button styles and sizes"
|
||||
code={`
|
||||
<Button variant="default">Primary Button</Button>
|
||||
|
||||
<Button variant="secondary">Secondary Button</Button>
|
||||
|
||||
<Button variant="ghost">Ghost Button</Button>
|
||||
|
||||
<Button variant="ghost" size="icon">?</Button>
|
||||
|
||||
<Button variant="link">Link</Button>
|
||||
`}
|
||||
>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
<Button variant="default">Primary Button</Button>
|
||||
<Button variant="secondary">Secondary Button</Button>
|
||||
<Button variant="ghost">Ghost Button</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
>
|
||||
?
|
||||
</Button>
|
||||
<Button variant="link">Link</Button>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Small Buttons"
|
||||
description="Various small button styles"
|
||||
code={`
|
||||
<Button variant="default" size="sm">Primary Button</Button>
|
||||
<Button variant="secondary" size="sm">Secondary Button</Button>
|
||||
<Button variant="ghost" size="sm">Ghost Button</Button>
|
||||
<Button variant="ghost" size="icon">?</Button>
|
||||
<Button variant="link" size="sm">Link</Button>
|
||||
`}
|
||||
>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
<Button
|
||||
variant="default"
|
||||
size="sm"
|
||||
>
|
||||
Primary Button
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
>
|
||||
Secondary Button
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
>
|
||||
Ghost Button
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
>
|
||||
?
|
||||
</Button>
|
||||
<Button
|
||||
variant="link"
|
||||
size="sm"
|
||||
>
|
||||
Link
|
||||
</Button>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Button large"
|
||||
description="Various large button styles"
|
||||
code={`
|
||||
<Button variant="default" size="lg">Primary Button</Button>
|
||||
<Button variant="secondary" size="lg">Secondary Button</Button>
|
||||
<Button variant="ghost" size="lg">Ghost Button</Button>
|
||||
<Button variant="ghost" size="icon">?</Button>
|
||||
<Button variant="link" size="lg">Link</Button>
|
||||
`}
|
||||
>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
<Button
|
||||
variant="default"
|
||||
size="lg"
|
||||
>
|
||||
Primary Button
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="lg"
|
||||
>
|
||||
Secondary Button
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="lg"
|
||||
>
|
||||
Ghost Button
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
>
|
||||
?
|
||||
</Button>
|
||||
<Button
|
||||
variant="link"
|
||||
size="lg"
|
||||
>
|
||||
Link
|
||||
</Button>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Input"
|
||||
description="Input field with label"
|
||||
code={`
|
||||
<div className="inline-block">
|
||||
<div className="mr-4 inline-block">
|
||||
<Label>Patient Weight</Label>
|
||||
</div>
|
||||
<div className="inline-block">
|
||||
<Input placeholder="(kg)" />
|
||||
</div>
|
||||
</div>
|
||||
`}
|
||||
>
|
||||
<div className="inline-block">
|
||||
<div className="mr-4 inline-block">
|
||||
<Label>Patient Weight</Label>
|
||||
</div>
|
||||
<div className="inline-block">
|
||||
<Input placeholder="(kg)" />
|
||||
</div>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Color swatches"
|
||||
description="Various color swatches"
|
||||
code={`
|
||||
<div className="bg-actions h-16 w-16 rounded"></div>
|
||||
<div className="bg-infosecondary h-16 w-16 rounded"></div>
|
||||
<div className="bg-highlight h-16 w-16 rounded"></div>
|
||||
<div className="h-16 w-16 rounded bg-white"></div>
|
||||
<div className="h-16 w-16 rounded bg-white"></div>
|
||||
<div className="h-16 w-16 rounded bg-white"></div>
|
||||
`}
|
||||
>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
<div className="bg-actions h-16 w-16 rounded"></div>
|
||||
<div className="bg-infosecondary h-16 w-16 rounded"></div>
|
||||
<div className="bg-highlight h-16 w-16 rounded"></div>
|
||||
<div className="h-16 w-16 rounded bg-white"></div>
|
||||
<div className="h-16 w-16 rounded bg-white"></div>
|
||||
<div className="h-16 w-16 rounded bg-white"></div>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Slider"
|
||||
description="Adjustable slider component"
|
||||
code={`
|
||||
<Slider defaultValue={[50]} max={100} step={1} />
|
||||
`}
|
||||
>
|
||||
<div className="w-full max-w-sm">
|
||||
<Slider
|
||||
defaultValue={[50]}
|
||||
max={100}
|
||||
step={1}
|
||||
/>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Typography"
|
||||
description="Various text sizes"
|
||||
code={`
|
||||
<div className="text-base text-white">Standard text size (text-base) 14px</div>
|
||||
<div className="text-sm text-white">Small text size (text-sm) 13px</div>
|
||||
<div className="text-xs text-white">Extra small text size (text-xs) 12px</div>
|
||||
`}
|
||||
>
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="text-base text-white">Standard text size (text-base) 14px</div>
|
||||
<div className="text-sm text-white">Small text size (text-sm) 13px</div>
|
||||
<div className="text-xs text-white">Extra small text size (text-xs) 12px</div>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Typography large"
|
||||
description="Various large text sizes"
|
||||
code={`
|
||||
<div className="text-lg text-white">Large text size (text-lg) 16px</div>
|
||||
<div className="text-xl text-white">Extra large text size (text-xl) 18px</div>
|
||||
<div className="text-2xl text-white">Double extra large text size (text-2xl) 20px</div>
|
||||
`}
|
||||
>
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="text-lg text-white">Large text size (text-lg) 16px</div>
|
||||
<div className="text-xl text-white">Extra large text size (text-xl) 18px</div>
|
||||
<div className="text-2xl text-white">Double extra large text size (text-2xl) 20px</div>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Tabs"
|
||||
description="Tabs component"
|
||||
code={`
|
||||
<Tabs className="w-[400px]">
|
||||
<TabsList>
|
||||
<TabsTrigger value="circle">Circle</TabsTrigger>
|
||||
<Separator orientation="vertical" />
|
||||
<TabsTrigger value="sphere">Sphere</TabsTrigger>
|
||||
<Separator orientation="vertical" />
|
||||
<TabsTrigger value="square">Square</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
`}
|
||||
>
|
||||
<Tabs className="w-[400px]">
|
||||
<TabsList>
|
||||
<TabsTrigger value="circle">Circle</TabsTrigger>
|
||||
<Separator orientation="vertical" />
|
||||
<TabsTrigger value="sphere">Sphere</TabsTrigger>
|
||||
<Separator orientation="vertical" />
|
||||
<TabsTrigger value="square">Square</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Select"
|
||||
description="Select component"
|
||||
code={`
|
||||
<Select>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Theme" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="light">Light</SelectItem>
|
||||
<SelectItem value="dark">Dark</SelectItem>
|
||||
<SelectItem value="system">System</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
`}
|
||||
>
|
||||
<Select>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Theme" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="light">Light</SelectItem>
|
||||
<SelectItem value="dark">Dark</SelectItem>
|
||||
<SelectItem value="system">System</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Dropdown Menu"
|
||||
description="Various dropdown menu examples"
|
||||
code={`
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
<Button>Open Basic</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem>Item 1</DropdownMenuItem>
|
||||
<DropdownMenuItem>Item 2</DropdownMenuItem>
|
||||
<DropdownMenuItem>Long name Item 3</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button>Open Align Start</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuItem>Item 1</DropdownMenuItem>
|
||||
<DropdownMenuItem>Item 2</DropdownMenuItem>
|
||||
<DropdownMenuItem>Long name Item 3</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button>Open Align End</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem>Item 1</DropdownMenuItem>
|
||||
<DropdownMenuItem>Item 2</DropdownMenuItem>
|
||||
<DropdownMenuItem>Long name Item 3</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button>Open Align Top</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent side="top" align="start">
|
||||
<DropdownMenuItem onSelect={() => console.debug('Item 1')}>Item 1</DropdownMenuItem>
|
||||
<DropdownMenuItem onSelect={() => console.debug('Item 2')}>Item 2</DropdownMenuItem>
|
||||
<DropdownMenuItem onSelect={() => console.debug('Item 3')}>Long name Item 3</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
`}
|
||||
>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
<Button>Open Basic</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem>Item 1</DropdownMenuItem>
|
||||
<DropdownMenuItem>Item 2</DropdownMenuItem>
|
||||
<DropdownMenuItem>Long name Item 3</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button>Open Align Start</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuItem>Item 1</DropdownMenuItem>
|
||||
<DropdownMenuItem>Item 2</DropdownMenuItem>
|
||||
<DropdownMenuItem>Long name Item 3</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button>Open Align End</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem>Item 1</DropdownMenuItem>
|
||||
<DropdownMenuItem>Item 2</DropdownMenuItem>
|
||||
<DropdownMenuItem>Long name Item 3</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button>Open Align Top</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
side="top"
|
||||
align="start"
|
||||
>
|
||||
<DropdownMenuItem onSelect={() => console.debug('Item 1')}>Item 1</DropdownMenuItem>
|
||||
<DropdownMenuItem onSelect={() => console.debug('Item 2')}>Item 2</DropdownMenuItem>
|
||||
<DropdownMenuItem onSelect={() => console.debug('Item 3')}>
|
||||
Long name Item 3
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Switch"
|
||||
description="Switch component"
|
||||
code={`
|
||||
<Switch />
|
||||
`}
|
||||
>
|
||||
<Switch />
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Checkbox"
|
||||
description="Checkbox with label"
|
||||
code={`
|
||||
<div className="items-top flex space-x-2">
|
||||
<Checkbox id="terms1" />
|
||||
<div className="grid gap-1.5 pt-0.5 leading-none">
|
||||
<Label>Display inactive segmentations</Label>
|
||||
</div>
|
||||
</div>
|
||||
`}
|
||||
>
|
||||
<div className="items-top flex space-x-2">
|
||||
<Checkbox id="terms1" />
|
||||
<div className="grid gap-1.5 pt-0.5 leading-none">
|
||||
<Label>Display inactive segmentations</Label>
|
||||
</div>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Toggle"
|
||||
description="Toggle component"
|
||||
code={`
|
||||
<Toggle>Hello</Toggle>
|
||||
`}
|
||||
>
|
||||
<Toggle>Hello</Toggle>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Slider"
|
||||
description="Slider component"
|
||||
code={`
|
||||
<div className="w-40 px-5">
|
||||
<Slider
|
||||
className="w-full"
|
||||
defaultValue={[50]}
|
||||
max={100}
|
||||
step={1}
|
||||
/>
|
||||
</div>
|
||||
`}
|
||||
>
|
||||
<div className="w-40 px-5">
|
||||
<Slider
|
||||
className="w-full"
|
||||
defaultValue={[50]}
|
||||
max={100}
|
||||
step={1}
|
||||
/>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="Scroll Area"
|
||||
description="Scroll Area component"
|
||||
code={`
|
||||
<ScrollArea className="border-input bg-background h-[150px] w-[350px] rounded-md border p-2 text-sm text-white">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
|
||||
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
|
||||
non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
|
||||
magna aliqua.
|
||||
</ScrollArea>
|
||||
`}
|
||||
>
|
||||
<ScrollArea className="border-input bg-background h-[150px] w-[350px] rounded-md border p-2 text-sm text-white">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
|
||||
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
|
||||
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
|
||||
dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
|
||||
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt
|
||||
mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
|
||||
do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
</ScrollArea>
|
||||
</ShowcaseRow>
|
||||
<ShowcaseRow
|
||||
title="sonner 1"
|
||||
description="sonner1"
|
||||
code={`sdf`}
|
||||
>
|
||||
{/* Toast Examples Section */}
|
||||
<div className="space-x-2">
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerSuccess}
|
||||
>
|
||||
Show Success Toast
|
||||
</Button>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerError}
|
||||
>
|
||||
Show Error Toast
|
||||
</Button>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerInfo}
|
||||
>
|
||||
Show Info Toast
|
||||
</Button>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerWarning}
|
||||
>
|
||||
Show Warning Toast
|
||||
</Button>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerPromiseToast}
|
||||
>
|
||||
Loading & Success Toast
|
||||
</Button>
|
||||
</div>
|
||||
</ShowcaseRow>
|
||||
|
||||
<ShowcaseRow
|
||||
title="sonner 2"
|
||||
description="sonner2"
|
||||
code={`sdf`}
|
||||
>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerDescriptionToast}
|
||||
>
|
||||
Show Toast with Description
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerActionButtonToast}
|
||||
>
|
||||
Show Toast with Action Button
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerCancelButtonToast}
|
||||
>
|
||||
Show Toast with Cancel Button
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={triggerCombinedToast}
|
||||
>
|
||||
Show Toast with Action & Cancel Buttons
|
||||
</Button>
|
||||
|
||||
{/* Render the Toaster component */}
|
||||
<Toaster />
|
||||
</ShowcaseRow>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
|
||||
const [showCode, setShowCode] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="bg-secondary/10 mb-8 rounded-lg p-6">
|
||||
<div className="mb-4 flex items-start justify-between">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold">{title}</h2>
|
||||
{description && <p className="text-muted-foreground mt-1">{description}</p>}
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setShowCode(!showCode)}
|
||||
>
|
||||
{showCode ? 'Hide Code' : 'Show Code'} <Icons.Code className="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="showcase-content mb-4">{children}</div>
|
||||
{showCode && (
|
||||
<pre className="mt-4 overflow-x-auto rounded-md bg-black p-4 text-sm">
|
||||
<code>{code}</code>
|
||||
</pre>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 101 KiB |
@@ -16,16 +16,18 @@ module.exports = {
|
||||
inter: ['Inter', 'sans-serif'],
|
||||
},
|
||||
fontSize: {
|
||||
xxs: '0.6875rem', // 11px
|
||||
xs: '0.75rem', // 12px
|
||||
sm: '0.8125rem', // 13px
|
||||
base: '0.875rem', // 14px
|
||||
lg: '1rem', // 16px
|
||||
xl: '1.125rem', // 18px
|
||||
'2xl': '1.25rem', // 20px
|
||||
'3xl': '1.375rem', // 22px
|
||||
'4xl': '1.5rem', // 24px
|
||||
'5xl': '1.875rem', // 30px
|
||||
xxs: '0.625rem', // 10px
|
||||
xs: '0.6875rem', // 11px
|
||||
sm: '0.75rem', // 12px
|
||||
base: '0.8125rem', // 13px
|
||||
lg: '0.875rem', // 14px
|
||||
xl: '1rem', // 16px
|
||||
// 2xl and above will be updated in an upcoming version
|
||||
'2xl': '1.5rem',
|
||||
'3xl': '1.875rem',
|
||||
'4xl': '2.25rem',
|
||||
'5xl': '3rem',
|
||||
'6xl': '4rem',
|
||||
},
|
||||
fontWeight: {
|
||||
hairline: '100',
|
||||
|
||||
Reference in new issue
Block a user