docs(ui): add base for ui component showcase in docs (#4414)

This commit is contained in:
Alireza authored and GitHub committed 2024-10-15 09:53:26 -04:00
1 parent 9125cec333
commit 465df5c573
48 files changed
+5160 -4740

No files matched your search

+238 -2
View File
@@ -1,3 +1,241 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap');
@tailwind base;
@tailwind components;
@tailwind utilities;
/* OHIF Theme */
@layer base {
:root {
--highlight: 191 74% 63%;
--background: 236 62% 5%;
--foreground: 0 0% 98%;
--card: 236 62% 5%;
--card-foreground: 0 0% 98%;
--popover: 219 90% 15%;
--popover-foreground: 0 0% 98%;
--primary: 214 98% 60%;
--primary-foreground: 0 0% 98%;
--secondary: 214 66% 48%;
--secondary-foreground: 200 50% 84%;
--muted: 234 64% 10%;
--muted-foreground: 200 46% 65%;
--accent: 217 79% 24%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 14.9%;
--input: 236 45% 21%;
--ring: 214 98% 60%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
--radius: 0.5rem;
}
.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--card: 0 0% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 0 0% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 214 98% 60%;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 14.9%;
--secondary-foreground: 0 0% 98%;
--muted: 0 0% 14.9%;
--muted-foreground: 0 0% 63.9%;
--accent: 0 0% 14.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 14.9%;
--input: 236 45% 21%;
--ring: 214 98% 60%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
}
/* ORIGINAL THEME for comparison and testing
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 72.22% 50.59%;
--destructive-foreground: 0 0% 98%;
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--ring: 240 5% 64.9%;
--radius: 0.5rem;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
}
.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 85.7% 97.3%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
}
*/
/* Theme Copy Example
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
--card: 0 0% 100%;
--card-foreground: 224 71.4% 4.1%;
--popover: 0 0% 100%;
--popover-foreground: 224 71.4% 4.1%;
--primary: 262.1 83.3% 57.8%;
--primary-foreground: 210 20% 98%;
--secondary: 220 14.3% 95.9%;
--secondary-foreground: 220.9 39.3% 11%;
--muted: 220 14.3% 95.9%;
--muted-foreground: 220 8.9% 46.1%;
--accent: 220 14.3% 95.9%;
--accent-foreground: 220.9 39.3% 11%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 20% 98%;
--border: 220 13% 91%;
--input: 220 13% 91%;
--ring: 262.1 83.3% 57.8%;
--radius: 0.5rem;
--chart-1: ;
--chart-2: ;
--chart-3: ;
--chart-4: ;
--chart-5: ;
}
.dark {
--background: 224 71.4% 4.1%;
--foreground: 210 20% 98%;
--card: 224 71.4% 4.1%;
--card-foreground: 210 20% 98%;
--popover: 224 71.4% 4.1%;
--popover-foreground: 210 20% 98%;
--primary: 263.4 70% 50.4%;
--primary-foreground: 210 20% 98%;
--secondary: 215 27.9% 16.9%;
--secondary-foreground: 210 20% 98%;
--muted: 215 27.9% 16.9%;
--muted-foreground: 217.9 10.6% 64.9%;
--accent: 215 27.9% 16.9%;
--accent-foreground: 210 20% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 20% 98%;
--border: 215 27.9% 16.9%;
--input: 215 27.9% 16.9%;
--ring: 263.4 70% 50.4%;
--chart-1: ;
--chart-2: ;
--chart-3: ;
--chart-4: ;
--chart-5: ;
}
}
*/
h2.section-header {
@apply py-4 text-2xl font-normal text-white;
}
h3.section-header {
@apply py-3 text-xl text-white;
}
.playground-row {
@apply bg-card mb-6 flex flex-row flex-wrap rounded-md border py-10;
}
.example {
@apply flex-initial px-6;
}
.example2 {
@apply flex-initial px-4;
}
/* Additional CSS edits to components */
/* Tooltip */
.TooltipContent[data-side='bottom'] {
animation-name: slideDown;
}
/* Custom CSS to hide default number input arrows */
input[type='number']::-webkit-inner-spin-button,
input[type='number']::-webkit-outer-spin-button {
@apply appearance-none;
}
input[type='number'] {
-moz-appearance: textfield; /* For Firefox */
}
.navbar__item {
display: flex;
align-items: center;
}
.navbar__item svg {
margin-left: 5px;
}
/* stylelint-disable docusaurus/copyright-header */
/**
* Any CSS included here will be global. The classic template
@@ -98,8 +336,6 @@ html[data-theme='dark'] {
/* Typography updates */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
html {
font-size: 1em;
}
@@ -0,0 +1,25 @@
import React from 'react';
import Layout from '@theme/Layout';
import { useHistory } from '@docusaurus/router';
export default function Patterns() {
const history = useHistory();
return (
<Layout>
<h1>Patterns</h1>
<button
className="bg-slate-400"
onClick={() => history.push('/patterns/segmentation-panel')}
>
{'Segmentation Panel'}
</button>
<button
className="bg-slate-400"
onClick={() => history.push('/patterns/measurement-panel')}
>
{'Measurements Panel'}
</button>
</Layout>
);
}
@@ -0,0 +1,130 @@
import React, { useState } from 'react';
import { Button } from '../../../../ui-next/src/components/Button';
import { Icons } from '../../../../ui-next/src/components/Icons';
import {
Accordion,
AccordionItem,
AccordionTrigger,
AccordionContent,
} from '../../../../ui-next/src/components/Accordion';
import { DataRow } from '../../../../ui-next/src/components/DataRow';
import { actionOptionsMap, dataList } from '../../../../ui-next/assets/data';
interface DataItem {
id: number;
title: string;
description: string;
optionalField?: string;
colorHex?: string;
details?: string;
series?: string;
}
interface ListGroup {
type: string;
items: DataItem[];
}
export default function Measurements() {
const [selectedRowId, setSelectedRowId] = 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));
};
const organSegmentationGroup = dataList.find(
(listGroup: ListGroup) => listGroup.type === 'Organ Segmentation'
);
const roiToolsGroup = dataList.find((listGroup: ListGroup) => listGroup.type === 'ROI Tools');
if (!organSegmentationGroup) {
return <div className="text-red-500">Organ Segmentation data not found.</div>;
}
if (!roiToolsGroup) {
return <div className="text-red-500">ROI Tools data not found.</div>;
}
return (
<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>
</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>
</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>
{/* 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>
</div>
);
}
@@ -0,0 +1,250 @@
import React, { useState } from 'react';
import { DataRow } from '../../../../ui-next/src/components/DataRow';
import { Button } from '../../../../ui-next/src/components/Button';
import {
Select,
SelectValue,
SelectTrigger,
SelectContent,
SelectItem,
} from '../../../../ui-next/src/components/Select';
import { Icons } from '../../../../ui-next/src/components/Icons';
import {
Accordion,
AccordionItem,
AccordionTrigger,
AccordionContent,
} from '../../../../ui-next/src/components/Accordion';
import { Slider } from '../../../../ui-next/src/components/Slider';
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 { actionOptionsMap, dataList } from '../../../../ui-next/assets/data';
interface DataItem {
id: number;
title: string;
description: string;
optionalField?: string;
colorHex?: string;
details?: string;
series?: string;
}
interface ListGroup {
type: string;
items: DataItem[];
}
export default function SegmentationPanel() {
const [selectedRowId, setSelectedRowId] = useState<string | null>(null);
const [selectedTab, setSelectedTab] = useState<string>('Fill & Outline');
const handleAction = (id: string, action: string) => {
console.log(`Action "${action}" triggered for item with id: ${id}`);
// Implement actual action logic here
};
// Handle row selection
const handleRowSelect = (id: string) => {
setSelectedRowId(prevSelectedId => (prevSelectedId === id ? null : id));
};
const organSegmentationGroup = dataList.find(
(listGroup: ListGroup) => listGroup.type === 'Organ Segmentation'
);
if (!organSegmentationGroup) {
return <div className="text-red-500">Organ Segmentation data not found.</div>;
}
return (
<div className="my-4 flex h-full w-full max-w-6xl justify-end bg-black py-6">
<div className="w-64 space-y-0">
<Accordion
type="multiple"
defaultValue={['segmentation-tools', 'segmentation-list']}
>
{/* Segmentation Tools */}
<AccordionItem value="segmentation-tools">
<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>Segmentation Tools</span>
</AccordionTrigger>
<AccordionContent>
<div className="bg-muted mb-0.5 h-32 rounded-b pb-3"></div>
</AccordionContent>
</AccordionItem>
{/* Segmentation List */}
<AccordionItem value="segmentation-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>Segmentation List</span>
</AccordionTrigger>
<AccordionContent>
<div className="mb-0">
{/* Header Controls */}
<div className="bg-muted flex h-10 w-full items-center space-x-1 rounded-t px-1.5">
<Select>
<SelectTrigger className="w-full overflow-hidden">
<SelectValue placeholder="Segmentation 1" />
</SelectTrigger>
<SelectContent>
<SelectItem value="seg1">Segmentation 1</SelectItem>
<SelectItem value="seg2">Segmentation 2</SelectItem>
<SelectItem value="seg3">Segmentation Long Name 123</SelectItem>
</SelectContent>
</Select>
<Button
variant="ghost"
size="icon"
>
<Icons.Info className="h-6 w-6" />
</Button>
</div>
{/* Appearance Settings */}
<AccordionItem value="segmentation-display">
<AccordionTrigger className="bg-muted hover:bg-accent mt-0.5 flex h-7 w-full items-center justify-between rounded-b pr-1 pl-2 font-normal text-white">
<div className="flex space-x-2">
<Icons.Controls className="text-primary" />
<span className="text-primary pr-1">Appearance Settings</span>
</div>
</AccordionTrigger>
<AccordionContent>
<div className="bg-muted mb-0.5 space-y-2 rounded-b px-1.5 pt-0.5 pb-3">
<div className="mx-1 mb-2.5 mt-1 flex items-center justify-between space-x-4">
{/* Display Label with Selected Tab */}
<div className="text-muted-foreground text-xs">Show: {selectedTab}</div>
{/* Tabs Controls */}
<Tabs
value={selectedTab}
onValueChange={setSelectedTab}
>
<TabsList>
<TabsTrigger value="Fill & Outline">
<Icons.DisplayFillAndOutline className="text-primary" />
</TabsTrigger>
<TabsTrigger value="Outline Only">
<Icons.DisplayOutlineOnly className="text-primary" />
</TabsTrigger>
<TabsTrigger value="Fill Only">
<Icons.DisplayFillOnly className="text-primary" />
</TabsTrigger>
</TabsList>
</Tabs>
</div>
{/* Opacity Slider */}
<div className="my-2 flex items-center">
<Label className="text-muted-foreground mx-1 w-14 flex-none whitespace-nowrap text-xs">
Opacity
</Label>
<Slider
className="mx-1 flex-1"
defaultValue={[85]}
max={100}
step={1}
/>
<Input
className="mx-1 w-10 flex-none"
placeholder="85"
/>
</div>
{/* Border Slider */}
<div className="my-2 flex items-center">
<Label className="text-muted-foreground mx-1 w-14 flex-none whitespace-nowrap text-xs">
Border
</Label>
<Slider
className="mx-1 flex-1"
defaultValue={[10]}
max={100}
step={1}
/>
<Input
className="mx-1 w-10 flex-none"
placeholder="2"
/>
</div>
{/* Sync Changes Switch */}
<div className="my-2 flex items-center pl-1 pb-1">
<Switch defaultChecked />
<Label className="text-muted-foreground mx-2 w-14 flex-none whitespace-nowrap text-xs">
Sync changes in all viewports
</Label>
</div>
<div className="border-input w-full border"></div>
{/* Display Inactive Segmentations Switch */}
<div className="my-2 flex items-center pl-1">
<Switch defaultChecked />
<Label className="text-muted-foreground mx-2 w-14 flex-none whitespace-nowrap text-xs">
Display inactive segmentations
</Label>
</div>
{/* Additional Opacity Slider */}
<div className="my-2 flex items-center">
<Label className="text-muted-foreground mx-1 w-14 flex-none whitespace-nowrap text-xs">
Opacity
</Label>
<Slider
className="mx-1 flex-1"
defaultValue={[65]}
max={100}
step={1}
/>
<Input
className="mx-1 w-10 flex-none"
placeholder="65"
/>
</div>
</div>
</AccordionContent>
</AccordionItem>
{/* Action Buttons */}
<div className="my-px flex h-9 w-full items-center justify-between rounded pl-0.5 pr-7">
<Button
size="sm"
variant="ghost"
className="pr pl-0.5"
>
<Icons.Add />
Add Segment
</Button>
<Button
size="icon"
variant="ghost"
>
<Icons.Hide className="h-6 w-6" />
</Button>
</div>
</div>
{/* Data Rows */}
<div className="space-y-px">
{organSegmentationGroup.items.map((item, index) => {
const compositeId = `${organSegmentationGroup.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}
actionOptions={actionOptionsMap[organSegmentationGroup.type] || ['Action']}
onAction={(action: string) => handleAction(compositeId, action)}
isSelected={selectedRowId === compositeId}
onSelect={() => handleRowSelect(compositeId)}
/>
);
})}
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
</div>
</div>
);
}
+27
View File
@@ -0,0 +1,27 @@
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>
);
}
+522
View File
@@ -0,0 +1,522 @@
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';
interface ShowcaseRowProps {
title: string;
description?: string;
children: React.ReactNode;
code: string;
}
export default function ComponentShowcase() {
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>
</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>
);
}