ui(component): Adds flexible DataRow component (#4399)

This commit is contained in:
Dan Rukas 2024-10-08 12:25:44 -04:00 committed by GitHub
parent c8923c5499
commit 8f0035aeef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 1890 additions and 27 deletions

View File

@ -0,0 +1,171 @@
// src/_pages/patterns.tsx
import React, { useState } from 'react';
import { createRoot } from 'react-dom/client';
import '../tailwind.css';
import { Button } from '../components/Button';
import {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
} from '../components/Select';
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuLabel,
DropdownMenuSub,
DropdownMenuSubTrigger,
DropdownMenuSubContent,
DropdownMenuPortal,
} from '../components/DropdownMenu';
import { Icons } from '../components/Icons/Icons';
import DataRow from '../_prototypes/DataRow/DataRow';
import dataList from '../_prototypes/DataRow/dataList.json';
import actionOptionsMap from '../_prototypes/DataRow/actionOptionsMap';
import {
Accordion,
AccordionItem,
AccordionTrigger,
AccordionContent,
} from '../components/Accordion/Accordion';
import { Slider } from '../components/Slider';
import { Switch } from '../components/Switch';
import { Label } from '../components/Label';
import { Input } from '../components/Input';
import { Tabs, TabsList, TabsTrigger, TabsContent } from '../components/Tabs';
import { ChevronDownIcon } from '@radix-ui/react-icons';
interface DataItem {
id: number;
title: string;
description: string;
optionalField?: string;
colorHex?: string;
details?: string;
series?: string;
}
interface ListGroup {
type: string;
items: DataItem[];
}
function Patterns() {
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 py-6">
{/* Simulated Panel List for "Segmentation" */}
<div className="w-64 space-y-0">
<Accordion
type="multiple"
defaultValue={['measurements-list', 'measurements-additional']}
collapsible
>
{/* 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>
);
}
const container = document.getElementById('root');
const root = createRoot(container!);
root.render(<Patterns />);

View File

@ -0,0 +1,43 @@
// src/_pages/patterns.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import '../tailwind.css';
// component imports
import { Button } from '../components/Button';
import { Input } from '../components/Input';
import { Label } from '../components/Label';
import {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
} from '../components/Select';
import { Tabs, TabsList, TabsTrigger, TabsContent } from '../components/Tabs';
import Separator from '../components/Separator';
import { Switch } from '../components/Switch';
import { Checkbox } from '../components/Checkbox';
import { Toggle, toggleVariants } from '../components/Toggle';
import { Slider } from '../components/Slider';
import { ScrollArea, ScrollBar } from '../components/ScrollArea';
import { PanelSplit } from '../_prototypes/PanelSplit'; // Updated import path
function Patterns() {
return (
<div className="my-4 mx-auto max-w-6xl py-6">
<div className="text-3xl"> Patterns 1 </div>
<PanelSplit />;
</div>
);
}
const container = document.getElementById('root');
const root = createRoot(container);
root.render(React.createElement(Patterns));

View File

@ -0,0 +1,316 @@
import React, { useState } from 'react';
import { createRoot } from 'react-dom/client';
import '../tailwind.css';
import { Button } from '../components/Button';
import {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
} from '../components/Select';
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuLabel,
DropdownMenuSub,
DropdownMenuSubTrigger,
DropdownMenuSubContent,
DropdownMenuPortal,
} from '../components/DropdownMenu';
import { Icons } from '../components/Icons/Icons';
import DataRow from '../_prototypes/DataRow/DataRow';
import dataList from '../_prototypes/DataRow/dataList.json';
import actionOptionsMap from '../_prototypes/DataRow/actionOptionsMap';
import {
Accordion,
AccordionItem,
AccordionTrigger,
AccordionContent,
} from '../components/Accordion/Accordion';
import { Slider } from '../components/Slider';
import { Switch } from '../components/Switch';
import { Label } from '../components/Label';
import { Input } from '../components/Input';
import { Tabs, TabsList, TabsTrigger, TabsContent } from '../components/Tabs';
import { ChevronDownIcon } from '@radix-ui/react-icons';
interface DataItem {
id: number;
title: string;
description: string;
optionalField?: string;
colorHex?: string;
details?: string;
series?: string;
}
interface ListGroup {
type: string;
items: DataItem[];
}
function Patterns() {
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 max-w-6xl justify-end py-6">
<div className="w-64 space-y-0">
<Accordion
type="multiple"
defaultValue={['segmentation-tools', 'segmentation-list']}
collapsible
>
{/* 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">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="icon"
>
<Icons.More className="h-6 w-6" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
<DropdownMenuItem>
<Icons.Add className="text-foreground" />
<span className="pl-2">Create New Segmentation</span>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuLabel>Current Segmentation</DropdownMenuLabel>
<DropdownMenuItem>
<Icons.Rename className="text-foreground" />
<span className="pl-2">Rename</span>
</DropdownMenuItem>
<DropdownMenuItem>
<Icons.Delete className="text-foreground" />
<span className="pl-2">Delete</span>
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<Icons.Export className="text-foreground" />
<span className="pl-2">Export & Download</span>
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuItem>Export DICOM SEG</DropdownMenuItem>
<DropdownMenuItem>Download DICOM SEG</DropdownMenuItem>
<DropdownMenuItem>Download DICOM RTSTRUCT</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
</DropdownMenuContent>
</DropdownMenu>
<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`;
return (
<DataRow
key={`panel-${compositeId}`}
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>
);
}
const container = document.getElementById('root');
const root = createRoot(container!);
root.render(<Patterns />);

View File

@ -1,13 +1,8 @@
// src/_pages/patterns.tsx
import React from 'react';
import React, { useState } from 'react';
import { createRoot } from 'react-dom/client';
import '../tailwind.css';
// component imports
import { Button } from '../components/Button';
import { Input } from '../components/Input';
import { Label } from '../components/Label';
import {
Select,
SelectGroup,
@ -20,24 +15,302 @@ import {
SelectScrollUpButton,
SelectScrollDownButton,
} from '../components/Select';
import { Tabs, TabsList, TabsTrigger, TabsContent } from '../components/Tabs';
import Separator from '../components/Separator';
import { Switch } from '../components/Switch';
import { Checkbox } from '../components/Checkbox';
import { Toggle, toggleVariants } from '../components/Toggle';
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuLabel,
DropdownMenuSub,
DropdownMenuSubTrigger,
DropdownMenuSubContent,
DropdownMenuPortal,
} from '../components/DropdownMenu';
import { Icons } from '../components/Icons/Icons';
import DataRow from '../_prototypes/DataRow/DataRow';
import dataList from '../_prototypes/DataRow/dataList.json';
import actionOptionsMap from '../_prototypes/DataRow/actionOptionsMap';
import {
Accordion,
AccordionItem,
AccordionTrigger,
AccordionContent,
} from '../components/Accordion/Accordion';
import { Slider } from '../components/Slider';
import { ScrollArea, ScrollBar } from '../components/ScrollArea';
import { PanelSplit } from '../_prototypes/PanelSplit'; // Updated import path
import { Switch } from '../components/Switch';
import { Label } from '../components/Label';
import { Input } from '../components/Input';
import { Tabs, TabsList, TabsTrigger, TabsContent } from '../components/Tabs';
import { ChevronDownIcon } from '@radix-ui/react-icons';
interface DataItem {
id: number;
title: string;
description: string;
optionalField?: string;
colorHex?: string;
details?: string;
series?: string;
}
interface ListGroup {
type: string;
items: DataItem[];
}
function Patterns() {
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 mx-auto max-w-6xl py-6">
<div className="text-3xl"> Patterns 1 </div>
<PanelSplit />;
<div className="my-4 flex max-w-6xl justify-end py-6">
<div className="w-64 space-y-0">
<Accordion
type="multiple"
defaultValue={['segmentation-tools', 'segmentation-list']}
collapsible
>
{/* 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">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="icon"
>
<Icons.More className="h-6 w-6" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
<DropdownMenuItem>
<Icons.Add className="text-foreground" />
<span className="pl-2">Create New Segmentation</span>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuLabel>Current Segmentation</DropdownMenuLabel>
<DropdownMenuItem>
<Icons.Rename className="text-foreground" />
<span className="pl-2">Rename</span>
</DropdownMenuItem>
<DropdownMenuItem>
<Icons.Delete className="text-foreground" />
<span className="pl-2">Delete</span>
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<Icons.Export className="text-foreground" />
<span className="pl-2">Export & Download</span>
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuItem>Export DICOM SEG</DropdownMenuItem>
<DropdownMenuItem>Download DICOM SEG</DropdownMenuItem>
<DropdownMenuItem>Download DICOM RTSTRUCT</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
</DropdownMenuContent>
</DropdownMenu>
<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>
);
}
const container = document.getElementById('root');
const root = createRoot(container);
root.render(React.createElement(Patterns));
const root = createRoot(container!);
root.render(<Patterns />);

View File

@ -18,7 +18,7 @@ import {
SelectScrollDownButton,
} from '../components/Select';
import { Tabs, TabsList, TabsTrigger, TabsContent } from '../components/Tabs';
import Separator from '../components/Separator';
import { Separator } from '../components/Separator';
import { Switch } from '../components/Switch';
import { Checkbox } from '../components/Checkbox';
import { Toggle, toggleVariants } from '../components/Toggle';
@ -374,6 +374,20 @@ export default function Playground() {
</div>
</div>
<h2 className="section-header">Accordion</h2>
<div className="row">
<div className="example">
<div className="w-40 px-5">
<Slider
className="w-full"
defaultValue={[50]}
max={100}
step={1}
/>
</div>
</div>
</div>
<h2 className="section-header">Scroll Area</h2>
<div className="row">
<div className="example">

View File

@ -0,0 +1,196 @@
import React, { useState } from 'react';
import { Button } from '../../components/Button/Button';
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
} from '../../components/DropdownMenu';
import { Icons } from '../../components/Icons/Icons';
import {
Tooltip,
TooltipTrigger,
TooltipContent,
TooltipProvider,
} from '../../components/Tooltip/Tooltip';
interface DataRowProps {
number: number;
title: string;
description: string;
optionalField?: string;
colorHex?: string;
details?: string;
series?: string;
actionOptions: string[];
onAction: (action: string) => void;
isSelected?: boolean;
onSelect?: () => void;
}
const DataRow: React.FC<DataRowProps> = ({
number,
title,
description,
optionalField,
colorHex,
details,
series,
actionOptions,
onAction,
isSelected = false,
onSelect,
}) => {
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const [isVisible, setIsVisible] = useState<boolean>(true);
const isTitleLong = title.length > 25;
return (
<TooltipProvider>
{' '}
{/* Ensure TooltipProvider wraps the component */}
<div className="flex flex-col">
{/* Row 1 with 'group' class to enable group-hover */}
<div
className={`flex items-center ${
isSelected ? 'bg-popover' : 'bg-muted'
} group relative cursor-pointer ${isVisible ? '' : 'opacity-60'}`}
onClick={onSelect}
>
{/* Hover Overlay */}
<div className="bg-primary/20 pointer-events-none absolute inset-0 opacity-0 transition-opacity group-hover:opacity-100"></div>
{/* Number Box */}
<div
className={`flex h-7 max-h-7 w-7 flex-shrink-0 items-center justify-center rounded-l border-r border-black text-sm ${
isSelected ? 'bg-highlight text-black' : 'bg-muted text-muted-foreground'
} overflow-hidden`}
>
{number}
</div>
{/* Color Circle (Optional) */}
{colorHex && (
<div className="flex h-7 w-5 items-center justify-center">
<span
className="ml-2 h-2 w-2 rounded-full"
style={{ backgroundColor: colorHex }}
></span>
</div>
)}
{/* Label with Conditional Tooltip */}
<div className="ml-2 flex-1 overflow-hidden">
{isTitleLong ? (
<Tooltip>
<TooltipTrigger asChild>
<span
className={`cursor-default text-sm ${
isSelected ? 'text-highlight' : 'text-muted-foreground'
} [overflow:hidden] [display:-webkit-box] [-webkit-line-clamp:2] [-webkit-box-orient:vertical]`}
>
{title}
</span>
</TooltipTrigger>
<TooltipContent
side="top"
align="center"
>
{title}
</TooltipContent>
</Tooltip>
) : (
<span
className={`text-sm ${
isSelected ? 'text-highlight' : 'text-muted-foreground'
} [overflow:hidden] [display:-webkit-box] [-webkit-line-clamp:2] [-webkit-box-orient:vertical]`}
>
{title}
</span>
)}
</div>
{/* Actions and Visibility Toggle */}
<div className="relative ml-2 flex items-center space-x-1">
{/* Visibility Toggle Icon */}
{isVisible ? (
<Button
size="small"
variant="ghost"
className={`h-6 w-6 transition-opacity ${
isSelected ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
}`}
aria-label="Hide"
onClick={e => {
e.stopPropagation(); // Prevent row selection on button click
setIsVisible(false);
}}
>
<Icons.Hide className="h-6 w-6" />
</Button>
) : (
<Button
size="small"
variant="ghost"
className="h-6 w-6 opacity-100"
aria-label="Show"
onClick={e => {
e.stopPropagation(); // Prevent row selection on button click
setIsVisible(true);
}}
>
<Icons.Show className="h-6 w-6" />
</Button>
)}
{/* Actions Dropdown Menu */}
<DropdownMenu onOpenChange={open => setIsDropdownOpen(open)}>
<DropdownMenuTrigger asChild>
<Button
size="small"
variant="ghost"
className={`h-6 w-6 transition-opacity ${
isSelected || isDropdownOpen
? 'opacity-100'
: 'opacity-0 group-hover:opacity-100'
}`}
aria-label="Actions"
onClick={e => e.stopPropagation()} // Prevent row selection on button click
>
<Icons.More className="h-6 w-6" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem>
<Icons.Rename className="text-foreground" />
<span className="pl-2">Rename</span>
</DropdownMenuItem>
<DropdownMenuItem>
<Icons.Lock className="text-foreground" />
<span className="pl-2">Lock</span>
</DropdownMenuItem>
<DropdownMenuItem>
<Icons.Delete className="text-foreground" />
<span className="pl-2">Delete</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
{/* Row 2 (Details and Series) */}
{(details || series) && (
<div className="ml-7 bg-black px-2 py-1">
{/* Updated Flex Container: Changed 'items-center' to 'items-start' */}
<div className="text-secondary-foreground flex items-start justify-between whitespace-pre-line text-sm leading-normal">
<span>{details}</span>
{series && <span className="text-muted-foreground">{series}</span>}
</div>
</div>
)}
</div>
</TooltipProvider>
);
};
export default DataRow;

View File

@ -0,0 +1,11 @@
// src/_prototypes/DataRow/actionOptionsMap.ts
const actionOptionsMap: { [key: string]: string[] } = {
Measurement: ['Rename', 'Lock', 'Delete'],
Segmentation: ['Rename', 'Lock', 'Export', 'Delete'],
'ROI Tools': ['Rename', 'Lock', 'Delete'],
'Organ Segmentation': ['Rename', 'Lock', 'Export', 'Delete'],
// Add more types and their corresponding actions as needed
};
export default actionOptionsMap;

View File

@ -0,0 +1,200 @@
[
{
"type": "Measurement",
"items": [
{
"id": 1,
"title": "Measurement Label",
"description": "Description for Measurement One.",
"optionalField": "Optional Info 1",
"details": "Data"
},
{
"id": 2,
"title": "Measurement Label",
"description": "Description for Measurement Two.",
"details": "Data"
}
]
},
{
"type": "Segmentation",
"items": [
{
"id": 3,
"title": "Segmentation One",
"colorHex": "#FF5733",
"description": "Description for Segmentation One."
},
{
"id": 4,
"title": "Segmentation Two",
"colorHex": "#FF5733",
"description": "Description for Segmentation Two."
},
{
"id": 5,
"title": "Segmentation Three",
"colorHex": "#FF5733",
"description": "Description for Segmentation Three."
}
]
},
{
"type": "ROI Tools",
"items": [
{
"id": 6,
"title": "Linear",
"description": "Description for Linear.",
"details": "49.2 mm",
"series": "S:2 I:1"
},
{
"id": 7,
"title": "Bidirectional",
"description": "Description for Bidirectional.",
"details": "L: 34.5 mm\nW: 23.0 mm",
"series": "S:2 I:2"
},
{
"id": 8,
"title": "Ellipse",
"description": "Description for Ellipse.",
"details": "2641 mm²\nMax: 1087 HU",
"series": "S:2 I:4"
},
{
"id": 9,
"title": "Rectangle",
"description": "Description for Rectangle.",
"details": "1426 mm²\nMax: 718 HU",
"series": "S:2 I:5"
},
{
"id": 10,
"title": "Circle",
"description": "Description for Circle.",
"details": "7339 mm²\nMax: 871 HU",
"series": "S:2 I:6"
},
{
"id": 11,
"title": "Freehand ROI",
"description": "Description for Freehand ROI.",
"details": "Mean: 215 HU\nMax: 947 HU\nArea: 839 mm²",
"series": "S:2 I:7"
},
{
"id": 12,
"title": "Spline Tool",
"description": "Description for Spline Tool.",
"details": "Area: 203 mm²",
"series": "S:2 I:8"
},
{
"id": 13,
"title": "Livewire Tool",
"description": "Description for Livewire Tool.",
"details": "",
"series": "S:2 I:3"
},
{
"id": 14,
"title": "Annotation Lorem ipsum dolor sit amet long measurement name continues here",
"description": "Description for Annotation.",
"details": "",
"series": "S:2 I:3"
}
]
},
{
"type": "Organ Segmentation",
"items": [
{
"id": 15,
"title": "Spleen",
"description": "Description for Spleen.",
"colorHex": "#6B8E23"
},
{
"id": 16,
"title": "Kidney",
"description": "Description for Kidney.",
"colorHex": "#4682B4"
},
{
"id": 17,
"title": "Kidney very long title name lorem ipsum dolor sit amet segmentation",
"description": "Description for Kidney.",
"colorHex": "#9ACD32"
},
{
"id": 18,
"title": "Gallbladder",
"description": "Description for Gallbladder.",
"colorHex": "#20B2AA"
},
{
"id": 19,
"title": "Esophagus",
"description": "Description for Esophagus.",
"colorHex": "#DAA520"
},
{
"id": 20,
"title": "Liver",
"description": "Description for Liver.",
"colorHex": "#CD5C5C"
},
{
"id": 21,
"title": "Stomach",
"description": "Description for Stomach.",
"colorHex": "#778899"
},
{
"id": 22,
"title": "Abdominal aorta",
"description": "Description for Abdominal Aorta.",
"colorHex": "#B8860B"
},
{
"id": 23,
"title": "Inferior vena cava",
"description": "Description for Inferior Vena Cava.",
"colorHex": "#556B2F"
},
{
"id": 24,
"title": "Portal vein",
"description": "Description for Portal Vein.",
"colorHex": "#8B4513"
},
{
"id": 25,
"title": "Pancreas",
"description": "Description for Pancreas.",
"colorHex": "#2F4F4F"
},
{
"id": 26,
"title": "Adrenal gland",
"description": "Description for Adrenal Gland.",
"colorHex": "#708090"
},
{
"id": 27,
"title": "Adrenal gland",
"description": "Description for Adrenal Gland.",
"colorHex": "#6A5ACD"
},
{
"id": 28,
"title": "New Seg Test New Seg Test New Seg Test New Seg Test New Seg Test New Seg Test ",
"description": "Description for New Seg Test.",
"colorHex": "#4682B4"
}
]
}
]

View File

@ -0,0 +1,15 @@
// src/_prototypes/DataRow/types.ts
export interface DataItem {
id: number;
title: string;
description: string;
optionalField?: string;
colorHex?: string;
details?: string;
}
export interface ListGroup {
type: string;
items: DataItem[];
}

View File

@ -36,7 +36,7 @@ const AccordionTrigger = React.forwardRef<
{...props}
>
{children}
<ChevronDownIcon className="text-muted-foreground h-4 w-4 shrink-0 transition-transform duration-200" />
<ChevronDownIcon className="text-primary h-4 w-4 shrink-0 transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
));

View File

@ -142,7 +142,7 @@ const DropdownMenuLabel = React.forwardRef<
>(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Label
ref={ref}
className={cn('px-2 py-1 text-sm font-semibold', inset && 'pl-8', className)}
className={cn('text-muted-foreground px-2 py-1 text-xs', inset && 'pl-8', className)}
{...props}
/>
));
@ -154,7 +154,7 @@ const DropdownMenuSeparator = React.forwardRef<
>(({ className, ...props }, ref) => (
<DropdownMenuPrimitive.Separator
ref={ref}
className={cn('bg-muted -mx-1 my-1 h-px', className)}
className={cn('bg-muted my-1 mx-2 h-px', className)}
{...props}
/>
));

View File

@ -5,6 +5,52 @@ type IconProps = React.HTMLAttributes<SVGElement>;
export const Icons = {
// Usage example: <Icons.ArrowLeft />
Add: (props: IconProps) => (
<svg
width="24px"
height="24px"
viewBox="0 0 24 24"
{...props}
>
<g
id="Add"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
>
<rect
id="Rectangle"
x="0"
y="0"
width="24"
height="24"
></rect>
<g
id="Group"
transform="translate(6, 6)"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
>
<line
x1="6"
y1="0"
x2="6"
y2="12"
id="Path"
></line>
<line
x1="12"
y1="6"
x2="0"
y2="6"
id="Path"
></line>
</g>
</g>
</svg>
),
ChevronClosed: (props: IconProps) => (
<svg
width="24px"
@ -75,6 +121,153 @@ export const Icons = {
</g>
</svg>
),
Controls: (props: IconProps) => (
<svg
width="18px"
height="18px"
viewBox="0 0 18 18"
{...props}
>
<g
id="Controls"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
strokeLinecap="round"
strokeLinejoin="round"
>
<circle
id="Oval"
stroke="currentColor"
cx="9"
cy="3.34782609"
r="1.73913043"
></circle>
<line
x1="10.7373913"
y1="3.34782609"
x2="16.4095652"
y2="3.34782609"
id="Path"
stroke="currentColor"
></line>
<line
x1="1.62695652"
y1="3.34782609"
x2="7.2573913"
y2="3.34782609"
id="Path"
stroke="currentColor"
></line>
<g
id="Group-26"
transform="translate(9.0183, 9) scale(-1, 1) translate(-9.0183, -9)translate(1.627, 7.2609)"
stroke="currentColor"
>
<circle
id="Oval"
transform="translate(3.8948, 1.7391) scale(-1, 1) translate(-3.8948, -1.7391)"
cx="3.89478261"
cy="1.73913043"
r="1.73913043"
></circle>
<line
x1="5.63043478"
y1="1.73913043"
x2="14.7826087"
y2="1.73913043"
id="Path"
transform="translate(10.2065, 1.7391) scale(-1, 1) translate(-10.2065, -1.7391)"
></line>
<line
x1="0"
y1="1.73913043"
x2="2.15217391"
y2="1.73913043"
id="Path"
transform="translate(1.0761, 1.7391) scale(-1, 1) translate(-1.0761, -1.7391)"
></line>
</g>
<circle
id="Oval"
stroke="currentColor"
cx="7.26086957"
cy="14.6521739"
r="1.73913043"
></circle>
<line
x1="8.99652174"
y1="14.6521739"
x2="16.4095652"
y2="14.6521739"
id="Path"
stroke="currentColor"
></line>
<line
x1="1.62695652"
y1="14.6521739"
x2="5.52173913"
y2="14.6521739"
id="Path"
stroke="currentColor"
></line>
</g>
</svg>
),
Delete: (props: IconProps) => (
<svg
width="24px"
height="24px"
viewBox="0 0 24 24"
{...props}
>
<g
id="Delete"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
>
<rect
id="Rectangle"
x="0"
y="0"
width="24"
height="24"
></rect>
<circle
id="Oval"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
cx="12"
cy="12"
r="7"
></circle>
<line
x1="8.95652174"
y1="8.95652174"
x2="15.0434783"
y2="15.0434783"
id="Path"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
></line>
<line
x1="15.0434783"
y1="8.95652174"
x2="8.95652174"
y2="15.0434783"
id="Path"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
></line>
</g>
</svg>
),
Download: (props: IconProps) => (
<svg
width="24px"
@ -146,6 +339,174 @@ export const Icons = {
</g>
</svg>
),
Export: (props: IconProps) => (
<svg
width="24px"
height="24px"
viewBox="0 0 24 24"
{...props}
>
<g
id="Export"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
>
<rect
id="Rectangle"
x="0"
y="0"
width="24"
height="24"
></rect>
<line
x1="12"
y1="13.125"
x2="12"
y2="5"
id="Path"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
></line>
<polyline
id="Path"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
points="9.1875 7.8125 12 5 14.8125 7.8125"
></polyline>
<path
d="M13.875,10.000625 L16.375,10.000625 C16.720178,10.000625 17,10.280447 17,10.625625 L17,18.750625 C17,19.095803 16.720178,19.375625 16.375,19.375625 L7.625,19.375625 C7.27982203,19.375625 7,19.095803 7,18.750625 L7,10.625625 C7,10.280447 7.27982203,10.000625 7.625,10.000625 L10.125,10.000625"
id="Path"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
></path>
</g>
</svg>
),
Hide: (props: IconProps) => (
<svg
width="24px"
height="24px"
viewBox="0 0 24 24"
{...props}
>
<g
id="hide"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
>
<rect
id="Rectangle"
x="0"
y="0"
width="24"
height="24"
></rect>
<circle
id="Oval"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
cx="12.4986195"
cy="11.8041442"
r="2.58684689"
></circle>
<path
d="M20.906611,11.5617197 C20.0470387,10.5861089 16.6094888,7 12.4986195,7 C8.38775024,7 4.95020027,10.5861089 4.090628,11.5617197 C3.96979067,11.7007491 3.96979067,11.9075393 4.090628,12.0465687 C4.95020027,13.0221796 8.38775024,16.6082885 12.4986195,16.6082885 C16.6094888,16.6082885 20.0470387,13.0221796 20.906611,12.0465687 C21.0274483,11.9075393 21.0274483,11.7007491 20.906611,11.5617197 Z"
id="Path"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
></path>
</g>
</svg>
),
Info: (props: IconProps) => (
<svg
width="24px"
height="24px"
viewBox="0 0 24 24"
{...props}
>
<g
id="icon-download"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
>
<rect
id="Rectangle"
x="0"
y="0"
width="24"
height="24"
rx="4"
></rect>
<circle
id="Oval"
fillRule="nonzero"
cx="12.192"
cy="12.192"
r="8.192"
></circle>
<path
d="M12.192,4.00160754 C7.66678807,4.00160754 4,7.6683956 4,12.1928038 C4,16.7172119 7.66759184,20.3848038 12.192,20.3848038 C16.7172119,20.3848038 20.384,16.7172119 20.384,12.1928038 C20.384,7.6683956 16.7172119,4.00080377 12.192,4.00080377 L12.192,4.00160754 Z M12.192,4.8053752 C16.2727284,4.8053752 19.5802323,8.11287912 19.5802323,12.1936075 C19.5802323,16.2735322 16.2727284,19.5818399 12.192,19.5818399 C8.11127159,19.5818399 4.80376766,16.2735322 4.80376766,12.1936075 C4.80376766,8.11287912 8.11127159,4.80457143 12.192,4.80457143 L12.192,4.8053752 Z"
id="Shape"
fill="currentColor"
fillRule="nonzero"
></path>
<path
d="M11.5425557,10.4920314 C12.0867064,10.4920314 12.534405,10.905168 12.5882575,11.4356546 L12.5938838,11.5425557 L12.5938838,16.0870581 C12.5938838,16.308898 12.4138399,16.4889419 12.192,16.4889419 C11.9950769,16.4889419 11.8303046,16.346675 11.7965463,16.1593972 L11.7901162,16.0870581 L11.7901162,11.5425557 C11.7901162,11.4260094 11.7089356,11.3279498 11.5996232,11.3014254 L11.5433595,11.2957991 L10.2436672,11.2957991 C10.0218273,11.2957991 9.84178336,11.1157551 9.84178336,10.8939152 C9.84178336,10.6961884 9.98405024,10.5322198 10.1713281,10.4984615 L10.2436672,10.4920314 L11.541752,10.4920314 L11.5425557,10.4920314 Z M11.2178336,7.24561381 L11.3094631,7.25124019 C11.6679435,7.29625118 11.9444396,7.60168289 11.9444396,7.97221978 C11.9444396,8.37410361 11.6197174,8.69882575 11.2178336,8.69882575 C10.8167535,8.69882575 10.4920314,8.37329984 10.4920314,7.97221978 C10.4920314,7.60248666 10.7685275,7.29625118 11.1270078,7.25124019 L11.2178336,7.24561381 Z"
id="Shape"
fill="currentColor"
fillRule="nonzero"
></path>
<path
d="M14.139529,15.6867818 C14.3613689,15.6867818 14.5414129,15.8668257 14.5414129,16.0886656 C14.5414129,16.2855887 14.399146,16.4503611 14.2118681,16.4841193 L14.139529,16.4905495 L10.244471,16.4905495 C10.0226311,16.4905495 9.84258713,16.3105055 9.84258713,16.0886656 C9.84258713,15.8909388 9.984854,15.7269702 10.1721319,15.6932119 L10.244471,15.6867818 L14.139529,15.6867818 L14.139529,15.6867818 Z"
id="Path"
fill="currentColor"
fillRule="nonzero"
></path>
</g>
</svg>
),
Lock: (props: IconProps) => (
<svg
width="24px"
height="24px"
viewBox="0 0 24 24"
{...props}
>
<g
id="Lock"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
>
<rect
id="Rectangle"
x="0"
y="0"
width="24"
height="24"
></rect>
<path
d="M16,10.6666667 L16,8 C16,5.79133333 14.2086667,4 12,4 C9.79133333,4 8,5.79133333 8,8 L8,10.6666667 L7.5,10.6666667 C6.67157288,10.6666667 6,11.3382395 6,12.1666667 L6,18.5 C6,19.3284271 6.67157288,20 7.5,20 L16.5,20 C17.3284271,20 18,19.3284271 18,18.5 L18,12.1666667 C18,11.3382395 17.3284271,10.6666667 16.5,10.6666667 L16,10.6666667 L16,10.6666667 Z M9.33333333,10.6666667 L9.33333333,8 C9.33333333,6.52933333 10.5293333,5.33333333 12,5.33333333 C13.4706667,5.33333333 14.6666667,6.52933333 14.6666667,8 L14.6666667,10.6666667 L9.33333333,10.6666667 Z"
id="Shape"
fill="currentColor"
fillRule="nonzero"
></path>
</g>
</svg>
),
ListView: (props: IconProps) => (
<svg
width="24px"
@ -270,6 +631,162 @@ export const Icons = {
</g>
</svg>
),
DisplayFillAndOutline: (props: IconProps) => (
<svg
width="18px"
height="18px"
viewBox="0 0 18 18"
{...props}
>
<g
id="view-outline-fill"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
>
<g id="Group-13">
<rect
id="Rectangle"
x="0"
y="0"
width="18"
height="18"
></rect>
<rect
id="Rectangle"
stroke="currentColor"
x="1.5"
y="1.5"
width="15"
height="15"
rx="1"
></rect>
<rect
id="Rectangle"
fill="currentColor"
x="3.5"
y="3.5"
width="11"
height="11"
rx="1"
></rect>
</g>
</g>
</svg>
),
DisplayOutlineOnly: (props: IconProps) => (
<svg
width="18px"
height="18px"
viewBox="0 0 18 18"
{...props}
>
<g
id="view-outline"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
>
<g id="Group-13">
<rect
id="Rectangle"
x="0"
y="0"
width="18"
height="18"
></rect>
<rect
id="Rectangle"
stroke="currentColor"
x="1.5"
y="1.5"
width="15"
height="15"
rx="1"
></rect>
</g>
</g>
</svg>
),
DisplayFillOnly: (props: IconProps) => (
<svg
width="18px"
height="18px"
viewBox="0 0 18 18"
{...props}
>
<g
id="view-fill"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
>
<g id="Group-13">
<rect
id="Rectangle"
x="0"
y="0"
width="18"
height="18"
></rect>
<rect
id="Rectangle"
fill="currentColor"
x="2"
y="2"
width="14"
height="14"
rx="1"
></rect>
</g>
</g>
</svg>
),
Actions: (props: IconProps) => (
<svg
width="24px"
height="24px"
viewBox="0 0 24 24"
{...props}
>
<g
id="more-dropdown"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
>
<rect
id="Rectangle"
x="0"
y="0"
width="24"
height="24"
></rect>
<g
id="Group-2"
transform="translate(5, 4)"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
>
<circle
id="Oval"
cx="6.74621802"
cy="7.5938001"
r="1.68710308"
></circle>
<path
d="M8.17972732,1.06493425 L8.67634848,2.69920529 C8.84616867,3.26259112 9.42371506,3.59782471 9.99714943,3.46585687 L11.6537273,3.08194406 C12.2982043,2.9366791 12.9621245,3.22831522 13.2911435,3.80120174 C13.6201625,4.37408825 13.5374848,5.09450899 13.0872366,5.57796434 L11.9284539,6.82714853 C11.528377,7.25995707 11.528377,7.92764314 11.9284539,8.36045168 L13.0872366,9.60963586 C13.5374848,10.0930912 13.6201625,10.813512 13.2911435,11.3863985 C12.9621245,11.959285 12.2982043,12.2509211 11.6537273,12.1056561 L9.99714943,11.7217433 C9.42371506,11.5897755 8.84616867,11.9250091 8.67634848,12.4883949 L8.17972732,14.122666 C7.98874475,14.7549849 7.40616232,15.1876002 6.745631,15.1876002 C6.08509968,15.1876002 5.50251725,14.7549849 5.31153468,14.122666 L4.81491352,12.4883949 C4.64509333,11.9250091 4.06754694,11.5897755 3.49411257,11.7217433 L1.83753467,12.1056561 C1.19305769,12.2509211 0.529137506,11.959285 0.200118485,11.3863985 C-0.128900535,10.813512 -0.0462227777,10.0930912 0.404025372,9.60963586 L1.56280807,8.36045168 C1.96288499,7.92764314 1.96288499,7.25995707 1.56280807,6.82714853 L0.404025372,5.57796434 C-0.0462227777,5.09450899 -0.128900535,4.37408825 0.200118485,3.80120174 C0.529137506,3.22831522 1.19305769,2.9366791 1.83753467,3.08194406 L3.49411257,3.46585687 C4.06754694,3.59782471 4.64509333,3.26259112 4.81491352,2.69920529 L5.31153468,1.06493425 C5.50251725,0.43261528 6.08509968,0 6.745631,0 C7.40616232,0 7.98874475,0.43261528 8.17972732,1.06493425 Z"
id="Path"
></path>
</g>
</g>
</svg>
),
PinFill: (props: IconProps) => (
<svg
width="24px"
@ -361,6 +878,51 @@ export const Icons = {
</g>
</svg>
),
Rename: (props: IconProps) => (
<svg
width="24px"
height="24px"
viewBox="0 0 24 24"
{...props}
>
<g
id="Rename"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
>
<rect
id="Rectangle"
x="0"
y="0"
width="24"
height="24"
></rect>
<g
id="rename"
transform="translate(4.5, 5)"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
>
<polygon
id="Rectangle"
transform="translate(7.6682, 7.2953) rotate(45) translate(-7.6682, -7.2953)"
points="5.71337096 0.360798742 9.62306412 0.360798742 9.62306412 14.2297836 5.71337096 14.2297836"
></polygon>
<polygon
id="Path"
points="1.38207653 10.8162548 0 14.963136 4.14688121 13.5810595"
></polygon>
<path
d="M13.9536949,3.77359418 L11.1895418,1.00944111 L11.650234,0.548748934 C12.4172745,-0.192083594 13.6365239,-0.181488647 14.3905743,0.57256175 C15.1446246,1.32661215 15.1552196,2.54586147 14.4143871,3.312902 L13.9536949,3.77359418 Z"
id="Path"
></path>
</g>
</g>
</svg>
),
ThumbnailView: (props: IconProps) => (
<svg
width="24px"
@ -718,7 +1280,7 @@ export const Icons = {
{...props}
>
<g
fill="#348CFD"
fill="currentColor"
fillRule="evenodd"
>
<path d="M7 .102A6.899 6.899 0 1 0 7 13.9 6.899 6.899 0 0 0 7 .102zm0 .875a6.024 6.024 0 1 1 0 12.048A6.024 6.024 0 0 1 7 .977z" />
@ -736,7 +1298,7 @@ export const Icons = {
{...props}
>
<g
stroke="#348CFD"
stroke="currentColor"
strokeWidth="1.5"
fill="none"
fillRule="evenodd"
@ -770,7 +1332,7 @@ export const Icons = {
<g
id="Segmentation---assets"
transform="translate(-42.127, -62.1087)"
stroke="#348CFD"
stroke="currentColor"
>
<g
id="icon-display-settings"
@ -849,6 +1411,68 @@ export const Icons = {
</g>
</svg>
),
Show: (props: IconProps) => (
<svg
width="24px"
height="24px"
viewBox="0 0 24 24"
{...props}
>
<g
id="show"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
>
<rect
id="Rectangle"
x="0"
y="0"
width="24"
height="24"
></rect>
<path
d="M18.0567826,8.96286957 C19.1471229,9.75269568 20.1356859,10.674229 21,11.7065217 C21,11.7065217 17.1949565,16.5108696 12.5,16.5108696 C11.7479876,16.5066962 11.0007435,16.3911225 10.2826087,16.167913"
id="Path"
stroke="#348CFD"
strokeLinecap="round"
strokeLinejoin="round"
></path>
<path
d="M6.93286957,14.4413043 C5.84666081,13.6535964 4.86162018,12.7350857 4,11.7065217 C4,11.7065217 7.80504348,6.90217391 12.5,6.90217391 C13.1235541,6.90480509 13.7443251,6.98550531 14.3478261,7.1423913"
id="Path"
stroke="#348CFD"
strokeLinecap="round"
strokeLinejoin="round"
></path>
<path
d="M9.54347826,11.7065217 C9.54347826,10.0736799 10.8671581,8.75 12.5,8.75"
id="Path"
stroke="#348CFD"
strokeLinecap="round"
strokeLinejoin="round"
></path>
<path
d="M15.4565217,11.7065217 C15.4565217,13.3393636 14.1328419,14.6630435 12.5,14.6630435"
id="Path"
stroke="#348CFD"
strokeLinecap="round"
strokeLinejoin="round"
></path>
<line
x1="19.7065217"
y1="4.5"
x2="5.29347826"
y2="18.9130435"
id="Path"
stroke="#348CFD"
strokeLinecap="round"
strokeLinejoin="round"
></line>
</g>
</svg>
),
SidePanelCloseLeft: (props: IconProps) => (
<svg
width="20px"

View File

@ -17,7 +17,7 @@ const TooltipContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
'bg-primary-dark border-secondary-light text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 overflow-hidden rounded-md border px-3 py-1.5 text-xs',
'bg-primary-dark border-secondary-light text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 overflow-hidden rounded border px-3 py-1.5 text-xs',
className
)}
{...props}

View File

@ -18,7 +18,7 @@
--primary: 214 98% 60%;
--primary-foreground: 0 0% 98%;
--secondary: 214 66% 48%;
--secondary-foreground: 0 0% 98%;
--secondary-foreground: 200 50% 84%;
--muted: 234 64% 10%;
--muted-foreground: 200 46% 65%;
--accent: 217 79% 24%;