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

@@ -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>
);
}