diff --git a/platform/app/tailwind.config.js b/platform/app/tailwind.config.js
index 8837fff20..1ba323991 100644
--- a/platform/app/tailwind.config.js
+++ b/platform/app/tailwind.config.js
@@ -39,16 +39,18 @@ module.exports = {
mono: ['Menlo', 'Monaco', 'Consolas', '"Liberation Mono"', '"Courier New"', 'monospace'],
},
fontSize: {
- xxs: '0.6875rem', // 11px
- xs: '0.75rem', // 12px
- sm: '0.8125rem', // 13px
- base: '0.875rem', // 14px
- lg: '1rem', // 16px
- xl: '1.125rem', // 18px
- '2xl': '1.25rem', // 20px
- '3xl': '1.375rem', // 22px
- '4xl': '1.5rem', // 24px
- '5xl': '1.875rem', // 30px
+ xxs: '0.625rem', // 10px
+ xs: '0.6875rem', // 11px
+ sm: '0.75rem', // 12px
+ base: '0.8125rem', // 13px
+ lg: '0.875rem', // 14px
+ xl: '1rem', // 16px
+ // 2xl and above will be updated in an upcoming version
+ '2xl': '1.5rem',
+ '3xl': '1.875rem',
+ '4xl': '2.25rem',
+ '5xl': '3rem',
+ '6xl': '4rem',
},
},
};
diff --git a/platform/docs/docusaurus.config.js b/platform/docs/docusaurus.config.js
index 092b18377..e52508796 100644
--- a/platform/docs/docusaurus.config.js
+++ b/platform/docs/docusaurus.config.js
@@ -157,12 +157,6 @@ module.exports = {
srcDark: 'img/ohif-logo.svg',
},
items: [
- {
- href: 'https://ohif.org/showcase',
- label: 'Showcase',
- target: '_blank',
- position: 'left',
- },
{
position: 'left',
to: '/',
@@ -170,25 +164,28 @@ module.exports = {
docId: 'Introduction',
label: 'Docs',
},
+ {
+ to: '/components',
+ label: 'Components',
+ position: 'left',
+ },
+ {
+ href: 'https://ohif.org/showcase',
+ label: 'Showcase',
+ target: '_blank',
+ position: 'left',
+ },
{
href: 'https://ohif.org/collaborate',
label: 'Collaborate',
target: '_blank',
position: 'left',
},
- /*
- {
- to: '/playground',
- label: 'UI Playground',
- position: 'left',
- className: 'new-badge',
- },
- */
{
to: '/help',
//activeBaseRegex: '(^/help$)|(/help)',
label: 'Help',
- position: 'right',
+ position: 'left',
},
{
type: 'docsVersionDropdown',
diff --git a/platform/docs/src/css/custom.css b/platform/docs/src/css/custom.css
index 5d7b1b8eb..75b488090 100644
--- a/platform/docs/src/css/custom.css
+++ b/platform/docs/src/css/custom.css
@@ -233,7 +233,9 @@ input[type='number'] {
}
.navbar__item svg {
- margin-left: 5px;
+ margin-right: 5px;
+ display: inline-block;
+ vertical-align: middle;
}
/* stylelint-disable docusaurus/copyright-header */
diff --git a/platform/docs/src/pages/colors-and-type.tsx b/platform/docs/src/pages/colors-and-type.tsx
new file mode 100644
index 000000000..8aad79e03
--- /dev/null
+++ b/platform/docs/src/pages/colors-and-type.tsx
@@ -0,0 +1,418 @@
+import React, { useState } from 'react';
+import '../css/custom.css';
+
+import Layout from '@theme/Layout';
+import { Label } from '../../../ui-next/src/components/Label';
+import { Input } from '../../../ui-next/src/components/Input';
+import { Separator } from '../../../ui-next/src/components/Separator';
+import { Tabs, TabsList, TabsTrigger } from '../../../ui-next/src/components/Tabs';
+import {
+ Select,
+ SelectTrigger,
+ SelectContent,
+ SelectItem,
+ SelectValue,
+} from '../../../ui-next/src/components/Select';
+import { Button } from '../../../ui-next/src/components/Button';
+import { Switch } from '../../../ui-next/src/components/Switch';
+import { Checkbox } from '../../../ui-next/src/components/Checkbox';
+import { Toggle } from '../../../ui-next/src/components/Toggle';
+import { Slider } from '../../../ui-next/src/components/Slider';
+import { ScrollArea } from '../../../ui-next/src/components/ScrollArea';
+import {
+ DropdownMenu,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuItem,
+} from '../../../ui-next/src/components/DropdownMenu';
+import { Icons } from '../../../ui-next/src/components/Icons';
+import { Toaster, toast } from '../../../ui-next/src/components/Sonner';
+import {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardDescription,
+ CardContent,
+} from '../../../ui-next/src/components/Card';
+
+interface ShowcaseRowProps {
+ title: string;
+ description?: string;
+ children: React.ReactNode;
+ code: string;
+}
+
+export default function ComponentShowcase() {
+ // Handlers to trigger different types of toasts
+ const triggerSuccess = () => {
+ toast.success('This is a success toast!');
+ };
+
+ const triggerError = () => {
+ toast.error('This is an error toast!');
+ };
+
+ const triggerInfo = () => {
+ toast.info('This is an info toast!');
+ };
+
+ const triggerWarning = () => {
+ toast.warning('This is a warning toast!');
+ };
+
+ // Handler to trigger a toast.promise example
+ const triggerPromiseToast = () => {
+ const promise = () =>
+ new Promise<{ name: string }>(resolve =>
+ setTimeout(() => resolve({ name: 'Segmentation 1' }), 3000)
+ );
+
+ toast.promise(promise(), {
+ loading: 'Loading Segmentation...',
+ success: data => `${data.name} has been added`,
+ error: 'Error',
+ });
+ };
+
+ // Handler to trigger a toast with description
+ const triggerDescriptionToast = () => {
+ toast.success('Success heading', {
+ description: 'This is a detailed description of the success message.',
+ });
+ };
+
+ // Handler to trigger a toast with an action button
+ const triggerActionButtonToast = () => {
+ toast.info('No active segmentation detected', {
+ description: 'Create a segmentation before using the Brush',
+ });
+ };
+
+ // Handler to trigger a toast with a cancel button
+ const triggerCancelButtonToast = () => {
+ toast.error('No active segmentation detected', {
+ description: 'Create a segmentation before using the Brush',
+ });
+ };
+
+ // Handler to trigger a toast with both action and cancel buttons
+ const triggerCombinedToast = () => {
+ toast.warning('Warning!', {
+ description: 'This is a warning with both action and cancel buttons.',
+ action: (
+ alert('Retry action clicked')}
+ >
+ Retry
+
+ ),
+ cancel: (
+ toast.dismiss()}
+ >
+ Cancel
+
+ ),
+ });
+ };
+
+ // Handler to trigger a loading toast using Toaster's default loading icon
+ const showLoadingToast = () => {
+ toast.loading('Loading your data...');
+ };
+
+ return (
+
+
+
+
+
+
Colors & Typography
+
+
+
+
+
+ Used for active or selected elements in the Viewer.
+
+
+
+
+
+
+ Used for Actions. Icons use 'primary' at 100% opacity while various components will
+ use a reduced opacity. Hover and other states increase the opacity.
+
+
+
+
+
+
+ These three colors are used as background colors. For the lowest level above black
+ use 'background'. For normal panel backgrounds and other interactive components, use
+ 'muted'. For elements such as menus and popovers, use 'popover'.
+
+
+
+
+
+
+ For primary and important text, use 'foreground'. When secondary text is available,
+ use 'muted-foreground' to create separation and readability.
+
+
+
+
+
+
+
+
+ text-base
+ 13px
+
+
+
+
+ text-base is used as the base font size of the Viewer interface. Use when putting
+ text in panels or other interface elements next to medical images.
+
+
+
+
+
+
+ text-lg can be used for dialog text or important messaging text within the Viewer.
+ Use this font size for easier reading on other standard text pages.
+
+
+
+
+
+
+ text-xl can be used as headings within dialogs or messaging.
+
+
+
+
+
+
+ text-2xl
+ 18px
+
+
+
+
+ text-2xl can be used for page headers in the Viewer application or as dialog titles.
+
+
+
+
+
+
+ text-3xl
+ 20px
+
+
+
+
+ text-3xl can be used for extra large text size in the application.
+
+
+
+
+
+
+ text-sm can be used for details that do not need to be standard sizes in the Viewer.
+
+
+
+
+
+
+ );
+}
+
+function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
+ const [showCode, setShowCode] = useState(false);
+
+ return (
+
+
+
+
{title}
+
+
setShowCode(!showCode)}
+ >
+ {showCode ? 'Hide Code' : 'Show Code'}
+
+
+
+
+ {description &&
{description}
}
+
+
+
+ {showCode && (
+
+ {code}
+
+ )}
+
+ );
+}
+
+// function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
+// const [showCode, setShowCode] = useState(false);
+
+// return (
+//
+//
+//
+//
{title}
+// {description &&
{description}
}
+//
+//
setShowCode(!showCode)}
+// >
+// {showCode ? 'Hide Code' : 'Show Code'}
+//
+//
+//
{children}
+// {showCode && (
+//
+// {code}
+//
+// )}
+//
+// );
+// }
diff --git a/platform/docs/src/pages/components-list.tsx b/platform/docs/src/pages/components-list.tsx
new file mode 100644
index 000000000..3888fc0b9
--- /dev/null
+++ b/platform/docs/src/pages/components-list.tsx
@@ -0,0 +1,651 @@
+import React, { useState } from 'react';
+import '../css/custom.css';
+
+import Layout from '@theme/Layout';
+import { Label } from '../../../ui-next/src/components/Label';
+import { Input } from '../../../ui-next/src/components/Input';
+import { Separator } from '../../../ui-next/src/components/Separator';
+import { Tabs, TabsList, TabsTrigger } from '../../../ui-next/src/components/Tabs';
+import {
+ Select,
+ SelectTrigger,
+ SelectContent,
+ SelectItem,
+ SelectValue,
+} from '../../../ui-next/src/components/Select';
+import { Button } from '../../../ui-next/src/components/Button';
+import { Switch } from '../../../ui-next/src/components/Switch';
+import { Checkbox } from '../../../ui-next/src/components/Checkbox';
+import { Toggle } from '../../../ui-next/src/components/Toggle';
+import { Slider } from '../../../ui-next/src/components/Slider';
+import { ScrollArea } from '../../../ui-next/src/components/ScrollArea';
+import {
+ DropdownMenu,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuItem,
+} from '../../../ui-next/src/components/DropdownMenu';
+import { Icons } from '../../../ui-next/src/components/Icons';
+import { Toaster, toast } from '../../../ui-next/src/components/Sonner';
+import { DataRow } from '../../../ui-next/src/components/DataRow';
+import DataRowExample from './patterns/DataRowExample';
+import {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardDescription,
+ CardContent,
+} from '../../../ui-next/src/components/Card';
+
+interface ShowcaseRowProps {
+ title: string;
+ description?: string;
+ children: React.ReactNode;
+ code: string;
+}
+
+export default function ComponentShowcase() {
+ // Handlers to trigger different types of toasts
+ const triggerSuccess = () => {
+ toast.success('This is a success toast!');
+ };
+
+ const triggerError = () => {
+ toast.error('This is an error toast!');
+ };
+
+ const triggerInfo = () => {
+ toast.info('This is an info toast!');
+ };
+
+ const triggerWarning = () => {
+ toast.warning('This is a warning toast!');
+ };
+
+ // Handler to trigger a toast.promise example
+ const triggerPromiseToast = () => {
+ const promise = () =>
+ new Promise<{ name: string }>(resolve =>
+ setTimeout(() => resolve({ name: 'Segmentation 1' }), 3000)
+ );
+
+ toast.promise(promise(), {
+ loading: 'Loading Segmentation...',
+ success: data => `${data.name} has been added`,
+ error: 'Error',
+ });
+ };
+
+ // Handler to trigger a toast with description
+ const triggerDescriptionToast = () => {
+ toast.success('Completed', {
+ description: 'This is a detailed description of the success message.',
+ });
+ };
+
+ // Handler to trigger a toast with an action button
+ const triggerActionButtonToast = () => {
+ toast.info('No active segmentation detected', {
+ description: 'Create a segmentation before using the Brush',
+ });
+ };
+
+ // Handler to trigger a toast with a cancel button
+ const triggerCancelButtonToast = () => {
+ toast.error('No active segmentation detected', {
+ description: 'Create a segmentation before using the Brush',
+ });
+ };
+
+ // Handler to trigger a toast with both action and cancel buttons
+ const triggerCombinedToast = () => {
+ toast.warning('Warning!', {
+ description: 'This is a warning with both action and cancel buttons.',
+ action: (
+ alert('Retry action clicked')}
+ >
+ Retry
+
+ ),
+ cancel: (
+ toast.dismiss()}
+ >
+ Cancel
+
+ ),
+ });
+ };
+
+ // Handler to trigger a loading toast using Toaster's default loading icon
+ const showLoadingToast = () => {
+ toast.loading('Loading your data...');
+ };
+
+ return (
+
+
+
+
+
+
+
Components
+
+
+ {/* Alphabetically Sorted ShowcaseRows */}
+
Primary Button
+
+Secondary Button
+
+Ghost Button
+
+?
+
+Link
+ `}
+ >
+
+ Primary Button
+ Secondary Button
+ Ghost Button
+
+ ?
+
+ Link
+
+
+
+ Large Button
+
+
+ Small Button
+
+
+
+
+
+
+
+ Display inactive segmentations
+
+
+ `}
+ >
+
+
+
+ Display inactive segmentations
+
+
+
+
+
+ {/* Render the DataRowExample component */}
+
+
+
+
+
+ Open Basic
+
+
+ Item 1
+ Item 2
+ Long name Item 3
+
+
+
+
+
+ Open Align Start
+
+
+ Item 1
+ Item 2
+ Long name Item 3
+
+
+
+
+
+ Open Align End
+
+
+ Item 1
+ Item 2
+ Long name Item 3
+
+
+
+
+
+ Open Align Top
+
+
+ console.debug('Item 1')}>Item 1
+ console.debug('Item 2')}>Item 2
+ console.debug('Item 3')}>Long name Item 3
+
+
+ `}
+ >
+
+
+
+ Open Basic
+
+
+ Item 1
+ Item 2
+ Long name Item 3
+
+
+
+
+ Open Align Start
+
+
+ Item 1
+ Item 2
+ Long name Item 3
+
+
+
+
+ Open Align End
+
+
+ Item 1
+ Item 2
+ Long name Item 3
+
+
+
+
+ Open Align Top
+
+
+ console.debug('Item 1')}>
+ Item 1
+
+ console.debug('Item 2')}>
+ Item 2
+
+ console.debug('Item 3')}>
+ Long name Item 3
+
+
+
+
+
+
+
+
+ Patient Weight
+
+
+
+
+
+ `}
+ >
+
+
+ Patient Weight
+
+
+
+
+
+
+
+
+ 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.
+
+ `}
+ >
+
+ 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.
+
+
+
+
+
+
+
+
+ Light
+ Dark
+ System
+
+
+ `}
+ >
+
+
+
+
+
+ Light
+ Dark
+ System
+
+
+
+
+
+
+
+ `}
+ >
+
+
+
+
+
+
+ `}
+ >
+
+
+ Sync changes in all viewports
+
+
+
+
+
+ Circle
+
+ Sphere
+
+ Square
+
+
+ `}
+ >
+
+
+ Circle
+
+ Sphere
+
+ Square
+
+
+
+
+
+ {/* Toast Examples Section */}
+ Simple message:
+
+
+ Loading & Success Toast
+
+
+ Success Toast
+
+
+ Error Toast
+
+
+ Info Toast
+
+
+ Warning Toast
+
+
+ Message with details:
+
+
+ Success Toast
+
+
+ Info Toast
+
+
+ Error Toast
+
+
+ Toast with Buttons
+
+
+ {/* Render the Toaster component */}
+
+
+
+
+
+ );
+}
+
+function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
+ const [showCode, setShowCode] = useState(false);
+
+ return (
+
+
+
+
{title}
+
+
setShowCode(!showCode)}
+ >
+ {showCode ? 'Hide Code' : 'Show Code'}
+
+
+
+
+ {description &&
{description}
}
+
+
+
+ {showCode && (
+
+ {code}
+
+ )}
+
+ );
+}
+
+// function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
+// const [showCode, setShowCode] = useState(false);
+
+// return (
+//
+//
+//
+//
{title}
+// {description &&
{description}
}
+//
+//
setShowCode(!showCode)}
+// >
+// {showCode ? 'Hide Code' : 'Show Code'}
+//
+//
+//
{children}
+// {showCode && (
+//
+// {code}
+//
+// )}
+//
+// );
+// }
diff --git a/platform/docs/src/pages/components.tsx b/platform/docs/src/pages/components.tsx
new file mode 100644
index 000000000..ae2267035
--- /dev/null
+++ b/platform/docs/src/pages/components.tsx
@@ -0,0 +1,265 @@
+import React, { useState } from 'react';
+import '../css/custom.css';
+
+import Layout from '@theme/Layout';
+import { Label } from '../../../ui-next/src/components/Label';
+import { Input } from '../../../ui-next/src/components/Input';
+import { Separator } from '../../../ui-next/src/components/Separator';
+import { Tabs, TabsList, TabsTrigger } from '../../../ui-next/src/components/Tabs';
+import {
+ Select,
+ SelectTrigger,
+ SelectContent,
+ SelectItem,
+ SelectValue,
+} from '../../../ui-next/src/components/Select';
+import { Button } from '../../../ui-next/src/components/Button';
+import { Switch } from '../../../ui-next/src/components/Switch';
+import { Checkbox } from '../../../ui-next/src/components/Checkbox';
+import { Toggle } from '../../../ui-next/src/components/Toggle';
+import { Slider } from '../../../ui-next/src/components/Slider';
+import { ScrollArea } from '../../../ui-next/src/components/ScrollArea';
+import {
+ DropdownMenu,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuItem,
+} from '../../../ui-next/src/components/DropdownMenu';
+import { Icons } from '../../../ui-next/src/components/Icons';
+import { Toaster, toast } from '../../../ui-next/src/components/Sonner';
+import {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardDescription,
+ CardContent,
+} from '../../../ui-next/src/components/Card';
+
+interface ShowcaseRowProps {
+ title: string;
+ description?: string;
+ children: React.ReactNode;
+ code: string;
+}
+
+export default function ComponentShowcase() {
+ // Handlers to trigger different types of toasts
+ const triggerSuccess = () => {
+ toast.success('This is a success toast!');
+ };
+
+ const triggerError = () => {
+ toast.error('This is an error toast!');
+ };
+
+ const triggerInfo = () => {
+ toast.info('This is an info toast!');
+ };
+
+ const triggerWarning = () => {
+ toast.warning('This is a warning toast!');
+ };
+
+ // Handler to trigger a toast.promise example
+ const triggerPromiseToast = () => {
+ const promise = () =>
+ new Promise<{ name: string }>(resolve =>
+ setTimeout(() => resolve({ name: 'Segmentation 1' }), 3000)
+ );
+
+ toast.promise(promise(), {
+ loading: 'Loading Segmentation...',
+ success: data => `${data.name} has been added`,
+ error: 'Error',
+ });
+ };
+
+ // Handler to trigger a toast with description
+ const triggerDescriptionToast = () => {
+ toast.success('Success heading', {
+ description: 'This is a detailed description of the success message.',
+ });
+ };
+
+ // Handler to trigger a toast with an action button
+ const triggerActionButtonToast = () => {
+ toast.info('No active segmentation detected', {
+ description: 'Create a segmentation before using the Brush',
+ });
+ };
+
+ // Handler to trigger a toast with a cancel button
+ const triggerCancelButtonToast = () => {
+ toast.error('No active segmentation detected', {
+ description: 'Create a segmentation before using the Brush',
+ });
+ };
+
+ // Handler to trigger a toast with both action and cancel buttons
+ const triggerCombinedToast = () => {
+ toast.warning('Warning!', {
+ description: 'This is a warning with both action and cancel buttons.',
+ action: (
+ alert('Retry action clicked')}
+ >
+ Retry
+
+ ),
+ cancel: (
+ toast.dismiss()}
+ >
+ Cancel
+
+ ),
+ });
+ };
+
+ // Handler to trigger a loading toast using Toaster's default loading icon
+ const showLoadingToast = () => {
+ toast.loading('Loading your data...');
+ };
+
+ return (
+
+
+
+ );
+}
+
+function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
+ const [showCode, setShowCode] = useState(false);
+
+ return (
+
+ {/* Header Section */}
+
+
+
{title}
+
+
setShowCode(!showCode)}
+ >
+ {showCode ? 'Hide Code' : 'Show Code'}
+
+
+
+ {/* Content Section: 1/3 Left, 2/3 Right */}
+
+ {/* Left Side: Title and Description */}
+
+ {description &&
{description}
}
+
+
+ {/* Right Side: Example */}
+
+
+
+ {/* Code Section */}
+ {showCode && (
+
+ {code}
+
+ )}
+
+ );
+}
+
+// function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
+// const [showCode, setShowCode] = useState(false);
+
+// return (
+//
+//
+//
+//
{title}
+// {description &&
{description}
}
+//
+//
setShowCode(!showCode)}
+// >
+// {showCode ? 'Hide Code' : 'Show Code'}
+//
+//
+//
{children}
+// {showCode && (
+//
+// {code}
+//
+// )}
+//
+// );
+// }
diff --git a/platform/docs/src/pages/patterns.tsx b/platform/docs/src/pages/patterns.tsx
new file mode 100644
index 000000000..31958ba8b
--- /dev/null
+++ b/platform/docs/src/pages/patterns.tsx
@@ -0,0 +1,321 @@
+import React, { useState } from 'react';
+import '../css/custom.css';
+
+import Layout from '@theme/Layout';
+import { Label } from '../../../ui-next/src/components/Label';
+import { Input } from '../../../ui-next/src/components/Input';
+import { Separator } from '../../../ui-next/src/components/Separator';
+import { Tabs, TabsList, TabsTrigger } from '../../../ui-next/src/components/Tabs';
+import {
+ Select,
+ SelectTrigger,
+ SelectContent,
+ SelectItem,
+ SelectValue,
+} from '../../../ui-next/src/components/Select';
+import { Button } from '../../../ui-next/src/components/Button';
+import { Switch } from '../../../ui-next/src/components/Switch';
+import { Checkbox } from '../../../ui-next/src/components/Checkbox';
+import { Toggle } from '../../../ui-next/src/components/Toggle';
+import { Slider } from '../../../ui-next/src/components/Slider';
+import { ScrollArea } from '../../../ui-next/src/components/ScrollArea';
+import {
+ DropdownMenu,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuItem,
+} from '../../../ui-next/src/components/DropdownMenu';
+import { Icons } from '../../../ui-next/src/components/Icons';
+import { Toaster, toast } from '../../../ui-next/src/components/Sonner';
+import {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardDescription,
+ CardContent,
+} from '../../../ui-next/src/components/Card';
+
+interface ShowcaseRowProps {
+ title: string;
+ description?: string;
+ children: React.ReactNode;
+ code: string;
+}
+
+export default function ComponentShowcase() {
+ // Function to open links in a new window
+ const openLinkInNewWindow = url => {
+ window.open(url, '_blank', 'noopener,noreferrer');
+ };
+
+ // Handlers to trigger different types of toasts
+ const triggerSuccess = () => {
+ toast.success('This is a success toast!');
+ };
+
+ const triggerError = () => {
+ toast.error('This is an error toast!');
+ };
+
+ const triggerInfo = () => {
+ toast.info('This is an info toast!');
+ };
+
+ const triggerWarning = () => {
+ toast.warning('This is a warning toast!');
+ };
+
+ // Handler to trigger a toast.promise example
+ const triggerPromiseToast = () => {
+ const promise = () =>
+ new Promise<{ name: string }>(resolve =>
+ setTimeout(() => resolve({ name: 'Segmentation 1' }), 3000)
+ );
+
+ toast.promise(promise(), {
+ loading: 'Loading Segmentation...',
+ success: data => `${data.name} has been added`,
+ error: 'Error',
+ });
+ };
+
+ // Handler to trigger a toast with description
+ const triggerDescriptionToast = () => {
+ toast.success('Success heading', {
+ description: 'This is a detailed description of the success message.',
+ });
+ };
+
+ // Handler to trigger a toast with an action button
+ const triggerActionButtonToast = () => {
+ toast.info('No active segmentation detected', {
+ description: 'Create a segmentation before using the Brush',
+ });
+ };
+
+ // Handler to trigger a toast with a cancel button
+ const triggerCancelButtonToast = () => {
+ toast.error('No active segmentation detected', {
+ description: 'Create a segmentation before using the Brush',
+ });
+ };
+
+ // Handler to trigger a toast with both action and cancel buttons
+ const triggerCombinedToast = () => {
+ toast.warning('Warning!', {
+ description: 'This is a warning with both action and cancel buttons.',
+ action: (
+ alert('Retry action clicked')}
+ >
+ Retry
+
+ ),
+ cancel: (
+ toast.dismiss()}
+ >
+ Cancel
+
+ ),
+ });
+ };
+
+ // Handler to trigger a loading toast using Toaster's default loading icon
+ const showLoadingToast = () => {
+ toast.loading('Loading your data...');
+ };
+
+ return (
+
+
+
+
+
+
Patterns
+
+
+
+ Uses the Data Row component to displays a list of segments. The current
+ "Segmentation" is chosen with a Select above the current list.
+
+ openLinkInNewWindow('./patterns/patterns-segmentation')}
+ >
+ Launch Segmentation Example
+
+
+ }
+ code={`
+aaa
+ `}
+ >
+
+
+
+
+
+
+
+
+ Uses the Data Row component to displays a list of measurements. A custom "Label"
+ starts each row with measurement data appearing on the secondary row
+
+ openLinkInNewWindow('./patterns/patterns-measurements')}
+ >
+ Launch Measurements Example
+
+
+ }
+ code={`
+aaa
+ `}
+ >
+
+
+
+
+
+
+
+
+ );
+}
+
+function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
+ const [showCode, setShowCode] = useState(false);
+
+ return (
+
+
+
+
{title}
+
+
setShowCode(!showCode)}
+ >
+
+
+
+ {description &&
{description}
}
+
+
+
+ {showCode && (
+
+ {code}
+
+ )}
+
+ );
+}
+
+// function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
+// const [showCode, setShowCode] = useState(false);
+
+// return (
+//
+//
+//
+//
{title}
+// {description &&
{description}
}
+//
+//
setShowCode(!showCode)}
+// >
+// {showCode ? 'Hide Code' : 'Show Code'}
+//
+//
+//
{children}
+// {showCode && (
+//
+// {code}
+//
+// )}
+//
+// );
+// }
diff --git a/platform/docs/src/pages/patterns/DataRowExample.tsx b/platform/docs/src/pages/patterns/DataRowExample.tsx
new file mode 100644
index 000000000..16127bf35
--- /dev/null
+++ b/platform/docs/src/pages/patterns/DataRowExample.tsx
@@ -0,0 +1,91 @@
+import React from 'react';
+import { DataRow } from '../../../../ui-next/src/components/DataRow';
+import { Button } from '../../../../ui-next/src/components/Button';
+import { Icons } from '../../../../ui-next/src/components/Icons';
+
+// Mock data to demonstrate DataRow usage
+const mockData = [
+ {
+ id: 1,
+ title: 'Segment 1',
+ description: 'Description for Segment 1',
+ optionalField: 'Optional Info 1',
+ colorHex: '#FF5733',
+ details: 'Secondary details or text',
+ },
+ {
+ id: 2,
+ title: 'Segment 2',
+ description: 'Description for Segment 2',
+ optionalField: 'Optional Info 2',
+ colorHex: '#33C1FF',
+ details: 'Secondary details or text',
+ },
+ {
+ id: 3,
+ title: 'Segment 3',
+ description: 'Description for Segment 3',
+ optionalField: 'Optional Info 3',
+ colorHex: '#5533FF',
+ details: 'Secondary details or text',
+ },
+];
+
+// Mock action options map
+const actionOptionsMap = {
+ 'ROI Tools': ['Edit', 'Delete', 'View'],
+};
+
+interface DataItem {
+ id: number;
+ title: string;
+ description: string;
+ optionalField?: string;
+ colorHex?: string;
+ details?: string;
+ series?: string;
+}
+
+interface ListGroup {
+ type: string;
+ items: DataItem[];
+}
+
+const DataRowExample: React.FC = () => {
+ const [selectedRowId, setSelectedRowId] = React.useState(null);
+
+ const handleAction = (id: string, action: string) => {
+ console.log(`Action "${action}" triggered for item with id: ${id}`);
+ // Implement actual action logic here
+ };
+
+ const handleRowSelect = (id: string) => {
+ setSelectedRowId(prevSelectedId => (prevSelectedId === id ? null : id));
+ };
+
+ return (
+
+ {mockData.map((item, index) => {
+ const compositeId = `ROI Tools-${item.id}-panel`; // Ensure unique composite ID
+ return (
+ handleAction(compositeId, action)}
+ isSelected={selectedRowId === compositeId}
+ onSelect={() => handleRowSelect(compositeId)}
+ />
+ );
+ })}
+
+ );
+};
+
+export default DataRowExample;
diff --git a/platform/docs/src/pages/patterns/patterns-measurements.tsx b/platform/docs/src/pages/patterns/patterns-measurements.tsx
index 343bd908d..1daf39a6b 100644
--- a/platform/docs/src/pages/patterns/patterns-measurements.tsx
+++ b/platform/docs/src/pages/patterns/patterns-measurements.tsx
@@ -10,6 +10,7 @@ import {
import { DataRow } from '../../../../ui-next/src/components/DataRow';
import { actionOptionsMap, dataList } from '../../../../ui-next/assets/data';
import BrowserOnly from '@docusaurus/BrowserOnly';
+import { TooltipProvider } from '../../../../ui-next/src/components/Tooltip';
interface DataItem {
id: number;
@@ -48,82 +49,84 @@ export default function Measurements() {
return (
{() => (
-
- {/* Simulated Panel List for "Segmentation" */}
-
-
- {/* Segmentation Tools */}
-
-
- Measurements
-
-
-
-
2024-Jan-01
-
- Study title lorem ipsum
+
+
+ {/* Simulated Panel List for "Segmentation" */}
+
+
+ {/* Segmentation Tools */}
+
+
+ Measurements
+
+
+
+
2024-Jan-01
+
+ Study title lorem ipsum
+
-
-
-
-
-
- CSV
-
-
-
- Create DICOM SR
-
+
+
+
+
+ CSV
+
+
+
+ Create DICOM SR
+
+
-
-
- {roiToolsGroup.items.map((item, index) => {
- const compositeId = `${roiToolsGroup.type}-${item.id}-panel`; // Ensure unique composite ID
- return (
- handleAction(compositeId, action)}
- isSelected={selectedRowId === compositeId}
- onSelect={() => handleRowSelect(compositeId)}
- />
- );
- })}
-
-
-
+
+ {roiToolsGroup.items.map((item, index) => {
+ const compositeId = `${roiToolsGroup.type}-${item.id}-panel`; // Ensure unique composite ID
+ return (
+ handleAction(compositeId, action)}
+ isSelected={selectedRowId === compositeId}
+ onSelect={() => handleRowSelect(compositeId)}
+ />
+ );
+ })}
+
+
+
- {/* Additional Findings */}
-
-
- Additional Findings
-
-
-
-
-
-
-
+ {/* Additional Findings */}
+
+
+ Additional Findings
+
+
+
+
+
+
+
+
)}
diff --git a/platform/docs/src/pages/patterns/patterns-segmentation.tsx b/platform/docs/src/pages/patterns/patterns-segmentation.tsx
index 04d0088f7..c78b6c226 100644
--- a/platform/docs/src/pages/patterns/patterns-segmentation.tsx
+++ b/platform/docs/src/pages/patterns/patterns-segmentation.tsx
@@ -75,7 +75,7 @@ export default function SegmentationPanel() {
}
return (
-
+
{() => (
-
+
- history.push('/ui-playground')}
- >
- ui-playground
-
- history.push('/patterns')}
- >
- patterns
-
-
- );
-}
diff --git a/platform/docs/src/pages/ui-playground.tsx b/platform/docs/src/pages/ui-playground.tsx
deleted file mode 100644
index c6161a6a4..000000000
--- a/platform/docs/src/pages/ui-playground.tsx
+++ /dev/null
@@ -1,699 +0,0 @@
-import React, { useState } from 'react';
-import '../css/custom.css';
-
-import { Label } from '../../../ui-next/src/components/Label';
-import { Input } from '../../../ui-next/src/components/Input';
-import { Separator } from '../../../ui-next/src/components/Separator';
-import { Tabs, TabsList, TabsTrigger } from '../../../ui-next/src/components/Tabs';
-import {
- Select,
- SelectTrigger,
- SelectContent,
- SelectItem,
- SelectValue,
-} from '../../../ui-next/src/components/Select';
-import { Button } from '../../../ui-next/src/components/Button';
-import { Switch } from '../../../ui-next/src/components/Switch';
-import { Checkbox } from '../../../ui-next/src/components/Checkbox';
-import { Toggle } from '../../../ui-next/src/components/Toggle';
-import { Slider } from '../../../ui-next/src/components/Slider';
-import { ScrollArea } from '../../../ui-next/src/components/ScrollArea';
-import {
- DropdownMenu,
- DropdownMenuTrigger,
- DropdownMenuContent,
- DropdownMenuItem,
-} from '../../../ui-next/src/components/DropdownMenu';
-import { Icons } from '../../../ui-next/src/components/Icons';
-import { Toaster, toast } from '../../../ui-next/src/components/Sonner';
-
-interface ShowcaseRowProps {
- title: string;
- description?: string;
- children: React.ReactNode;
- code: string;
-}
-
-export default function ComponentShowcase() {
- // Handlers to trigger different types of toasts
- const triggerSuccess = () => {
- toast.success('This is a success toast!');
- };
-
- const triggerError = () => {
- toast.error('This is an error toast!');
- };
-
- const triggerInfo = () => {
- toast.info('This is an info toast!');
- };
-
- const triggerWarning = () => {
- toast.warning('This is a warning toast!');
- };
-
- // Handler to trigger a toast.promise example
- const triggerPromiseToast = () => {
- const promise = () =>
- new Promise<{ name: string }>(resolve =>
- setTimeout(() => resolve({ name: 'Segmentation 1' }), 3000)
- );
-
- toast.promise(promise(), {
- loading: 'Loading Segmentation...',
- success: data => `${data.name} has been added`,
- error: 'Error',
- });
- };
-
- // Handler to trigger a toast with description
- const triggerDescriptionToast = () => {
- toast.success('Success heading', {
- description: 'This is a detailed description of the success message.',
- });
- };
-
- // Handler to trigger a toast with an action button
- const triggerActionButtonToast = () => {
- toast.info('Info heading', {
- description: 'This is an info message with an action button.',
- action: (
- alert('Action button clicked')}
- >
- Undo
-
- ),
- });
- };
-
- // Handler to trigger a toast with a cancel button
- const triggerCancelButtonToast = () => {
- toast.error('Error!', {
- description: 'This is an error message with a cancel button.',
- cancel: (
- toast.dismiss()}
- >
- Dismiss
-
- ),
- });
- };
-
- // Handler to trigger a toast with both action and cancel buttons
- const triggerCombinedToast = () => {
- toast.warning('Warning!', {
- description: 'This is a warning with both action and cancel buttons.',
- action: (
- alert('Retry action clicked')}
- >
- Retry
-
- ),
- cancel: (
- toast.dismiss()}
- >
- Cancel
-
- ),
- });
- };
-
- // Handler to trigger a loading toast using Toaster's default loading icon
- const showLoadingToast = () => {
- toast.loading('Loading your data...');
- };
-
- return (
-
-
-
Primary Button
-
-Secondary Button
-
-Ghost Button
-
-?
-
-Link
- `}
- >
-
- Primary Button
- Secondary Button
- Ghost Button
-
- ?
-
- Link
-
-
-
-
Primary Button
-Secondary Button
-Ghost Button
-?
-Link
- `}
- >
-
-
- Primary Button
-
-
- Secondary Button
-
-
- Ghost Button
-
-
- ?
-
-
- Link
-
-
-
-
-
Primary Button
-Secondary Button
-Ghost Button
-?
-Link
- `}
- >
-
-
- Primary Button
-
-
- Secondary Button
-
-
- Ghost Button
-
-
- ?
-
-
- Link
-
-
-
-
-
-
- Patient Weight
-
-
-
-
-
- `}
- >
-
-
- Patient Weight
-
-
-
-
-
-
-
-
-
-
-
-
-
- `}
- >
-
-
-
-
- `}
- >
-
-
-
-
-
- Standard text size (text-base) 14px
-
Small text size (text-sm) 13px
-
Extra small text size (text-xs) 12px
- `}
- >
-
-
Standard text size (text-base) 14px
-
Small text size (text-sm) 13px
-
Extra small text size (text-xs) 12px
-
-
-
-
Large text size (text-lg) 16px
-
Extra large text size (text-xl) 18px
-
Double extra large text size (text-2xl) 20px
- `}
- >
-
-
Large text size (text-lg) 16px
-
Extra large text size (text-xl) 18px
-
Double extra large text size (text-2xl) 20px
-
-
-
-
-
- Circle
-
- Sphere
-
- Square
-
-
- `}
- >
-
-
- Circle
-
- Sphere
-
- Square
-
-
-
-
-
-
-
-
-
- Light
- Dark
- System
-
-
- `}
- >
-
-
-
-
-
- Light
- Dark
- System
-
-
-
-
-
-
- Open Basic
-
-
- Item 1
- Item 2
- Long name Item 3
-
-
-
-
-
- Open Align Start
-
-
- Item 1
- Item 2
- Long name Item 3
-
-
-
-
-
- Open Align End
-
-
- Item 1
- Item 2
- Long name Item 3
-
-
-
-
-
- Open Align Top
-
-
- console.debug('Item 1')}>Item 1
- console.debug('Item 2')}>Item 2
- console.debug('Item 3')}>Long name Item 3
-
-
- `}
- >
-
-
-
- Open Basic
-
-
- Item 1
- Item 2
- Long name Item 3
-
-
-
-
- Open Align Start
-
-
- Item 1
- Item 2
- Long name Item 3
-
-
-
-
- Open Align End
-
-
- Item 1
- Item 2
- Long name Item 3
-
-
-
-
- Open Align Top
-
-
- console.debug('Item 1')}>Item 1
- console.debug('Item 2')}>Item 2
- console.debug('Item 3')}>
- Long name Item 3
-
-
-
-
-
-
-
- `}
- >
-
-
-
-
-
-
- Display inactive segmentations
-
-
- `}
- >
-
-
-
- Display inactive segmentations
-
-
-
-
- Hello
- `}
- >
- Hello
-
-
-
-
-
- `}
- >
-
-
-
-
-
-
- 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.
-
- `}
- >
-
- 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.
-
-
-
- {/* Toast Examples Section */}
-
-
- Show Success Toast
-
-
- Show Error Toast
-
-
- Show Info Toast
-
-
- Show Warning Toast
-
-
- Loading & Success Toast
-
-
-
-
-
-
- Show Toast with Description
-
-
-
- Show Toast with Action Button
-
-
-
- Show Toast with Cancel Button
-
-
-
- Show Toast with Action & Cancel Buttons
-
-
- {/* Render the Toaster component */}
-
-
-
-
- );
-}
-
-function ShowcaseRow({ title, description, children, code }: ShowcaseRowProps) {
- const [showCode, setShowCode] = useState(false);
-
- return (
-
-
-
-
{title}
- {description &&
{description}
}
-
-
setShowCode(!showCode)}
- >
- {showCode ? 'Hide Code' : 'Show Code'}
-
-
-
{children}
- {showCode && (
-
- {code}
-
- )}
-
- );
-}
diff --git a/platform/docs/static/img/patterns-measurements.png b/platform/docs/static/img/patterns-measurements.png
new file mode 100644
index 000000000..5c1870ec9
Binary files /dev/null and b/platform/docs/static/img/patterns-measurements.png differ
diff --git a/platform/docs/static/img/patterns-segmentation.png b/platform/docs/static/img/patterns-segmentation.png
new file mode 100644
index 000000000..8eec0d4a0
Binary files /dev/null and b/platform/docs/static/img/patterns-segmentation.png differ
diff --git a/platform/docs/tailwind.config.js b/platform/docs/tailwind.config.js
index f36b44a65..7e858df22 100644
--- a/platform/docs/tailwind.config.js
+++ b/platform/docs/tailwind.config.js
@@ -16,16 +16,18 @@ module.exports = {
inter: ['Inter', 'sans-serif'],
},
fontSize: {
- xxs: '0.6875rem', // 11px
- xs: '0.75rem', // 12px
- sm: '0.8125rem', // 13px
- base: '0.875rem', // 14px
- lg: '1rem', // 16px
- xl: '1.125rem', // 18px
- '2xl': '1.25rem', // 20px
- '3xl': '1.375rem', // 22px
- '4xl': '1.5rem', // 24px
- '5xl': '1.875rem', // 30px
+ xxs: '0.625rem', // 10px
+ xs: '0.6875rem', // 11px
+ sm: '0.75rem', // 12px
+ base: '0.8125rem', // 13px
+ lg: '0.875rem', // 14px
+ xl: '1rem', // 16px
+ // 2xl and above will be updated in an upcoming version
+ '2xl': '1.5rem',
+ '3xl': '1.875rem',
+ '4xl': '2.25rem',
+ '5xl': '3rem',
+ '6xl': '4rem',
},
fontWeight: {
hairline: '100',
diff --git a/platform/ui-next/src/components/Accordion/Accordion.tsx b/platform/ui-next/src/components/Accordion/Accordion.tsx
index bc9d7c2dc..e7e2dc306 100644
--- a/platform/ui-next/src/components/Accordion/Accordion.tsx
+++ b/platform/ui-next/src/components/Accordion/Accordion.tsx
@@ -28,7 +28,7 @@ const AccordionTrigger = React.forwardRef<
svg]:rotate-270',
'[&[data-state=closed]>svg]:rotate-90'
@@ -48,7 +48,7 @@ const AccordionContent = React.forwardRef<
>(({ className, children, ...props }, ref) => (
{children}
diff --git a/platform/ui-next/src/components/Button/Button.tsx b/platform/ui-next/src/components/Button/Button.tsx
index e7668874a..48dbcc11f 100644
--- a/platform/ui-next/src/components/Button/Button.tsx
+++ b/platform/ui-next/src/components/Button/Button.tsx
@@ -5,14 +5,14 @@ import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '../../lib/utils';
const buttonVariants = cva(
- 'inline-flex items-center justify-center whitespace-nowrap rounded text-sm font-normal leading-tight transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
+ 'inline-flex items-center justify-center whitespace-nowrap rounded text-base font-normal leading-tight transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
{
variants: {
variant: {
default: 'bg-primary/60 text-primary-foreground hover:bg-primary/100',
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
outline:
- 'border border-input bg-background hover:bg-primary/25 hover:text-accent-foreground',
+ 'border border-primary/25 bg-background hover:bg-primary/25 text-primary hover:text-primary',
secondary: 'bg-primary/40 text-secondary-foreground hover:bg-primary/60',
ghost: 'font-normal text-primary hover:bg-primary/25',
link: 'font-normal text-primary underline-offset-4 hover:underline',
diff --git a/platform/ui-next/src/components/Calendar/Calendar.tsx b/platform/ui-next/src/components/Calendar/Calendar.tsx
index 72ce7501a..8dfbc99f4 100644
--- a/platform/ui-next/src/components/Calendar/Calendar.tsx
+++ b/platform/ui-next/src/components/Calendar/Calendar.tsx
@@ -32,7 +32,7 @@ function Calendar({ className, classNames, showOutsideDays = true, ...props }: C
head_row: 'flex',
head_cell: 'text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]',
row: 'flex w-full mt-2',
- cell: 'h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20',
+ cell: 'h-9 w-9 text-center text-base p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20',
day: cn(
buttonVariants({ variant: 'ghost' }),
'h-9 w-9 p-0 font-normal aria-selected:opacity-100'
diff --git a/platform/ui-next/src/components/Card/Card.tsx b/platform/ui-next/src/components/Card/Card.tsx
new file mode 100644
index 000000000..162bbcb77
--- /dev/null
+++ b/platform/ui-next/src/components/Card/Card.tsx
@@ -0,0 +1,75 @@
+import * as React from 'react';
+
+import { cn } from '../../lib/utils';
+
+const Card = React.forwardRef>(
+ ({ className, ...props }, ref) => (
+
+ )
+);
+Card.displayName = 'Card';
+
+const CardHeader = React.forwardRef>(
+ ({ className, ...props }, ref) => (
+
+ )
+);
+CardHeader.displayName = 'CardHeader';
+
+const CardTitle = React.forwardRef>(
+ ({ className, ...props }, ref) => (
+
+ )
+);
+CardTitle.displayName = 'CardTitle';
+
+const CardDescription = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+CardDescription.displayName = 'CardDescription';
+
+const CardContent = React.forwardRef>(
+ ({ className, ...props }, ref) => (
+
+ )
+);
+CardContent.displayName = 'CardContent';
+
+const CardFooter = React.forwardRef>(
+ ({ className, ...props }, ref) => (
+
+ )
+);
+CardFooter.displayName = 'CardFooter';
+
+export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
diff --git a/platform/ui-next/src/components/Card/index.ts b/platform/ui-next/src/components/Card/index.ts
new file mode 100644
index 000000000..7c9b951ca
--- /dev/null
+++ b/platform/ui-next/src/components/Card/index.ts
@@ -0,0 +1,2 @@
+import { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } from './Card';
+export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
diff --git a/platform/ui-next/src/components/Command/Command.tsx b/platform/ui-next/src/components/Command/Command.tsx
index 5e4a14caf..1a672a348 100644
--- a/platform/ui-next/src/components/Command/Command.tsx
+++ b/platform/ui-next/src/components/Command/Command.tsx
@@ -47,7 +47,7 @@ const CommandInput = React.forwardRef<
((props, ref) => (
));
@@ -90,7 +90,7 @@ const CommandGroup = React.forwardRef<
) => {
return (
);
diff --git a/platform/ui-next/src/components/DataRow/DataRow.tsx b/platform/ui-next/src/components/DataRow/DataRow.tsx
index 1c83b2f57..781855fb3 100644
--- a/platform/ui-next/src/components/DataRow/DataRow.tsx
+++ b/platform/ui-next/src/components/DataRow/DataRow.tsx
@@ -199,14 +199,14 @@ const DataRow: React.FC = ({
{/* Hover Overlay */}
- {/* Number Box */}
-
- {number}
-
+ {/* Number Box */}
+
+ {number}
+
{/* Color Circle (Optional) */}
{colorHex && (
@@ -224,7 +224,7 @@ const DataRow: React.FC = ({
@@ -240,7 +240,7 @@ const DataRow: React.FC = ({
) : (
@@ -315,7 +315,7 @@ const DataRow: React.FC = ({
{details && details.primary?.length > 0 && (
-
+
{renderDetails(details.primary)}
diff --git a/platform/ui-next/src/components/DateRange/DateRange.tsx b/platform/ui-next/src/components/DateRange/DateRange.tsx
index 9e2e39810..eebc7b916 100644
--- a/platform/ui-next/src/components/DateRange/DateRange.tsx
+++ b/platform/ui-next/src/components/DateRange/DateRange.tsx
@@ -90,7 +90,7 @@ export function DatePickerWithRange({
value={start}
onChange={e => handleInputChange(e, 'start')}
className={cn(
- 'border-inputfield-main focus:border-inputfield-focus h-[32px] w-full justify-start rounded border bg-black py-[6.5px] pl-[6.5px] pr-[6.5px] text-left text-sm font-normal hover:bg-black hover:text-white',
+ 'border-inputfield-main focus:border-inputfield-focus h-[32px] w-full justify-start rounded border bg-black py-[6.5px] pl-[6.5px] pr-[6.5px] text-left text-base font-normal hover:bg-black hover:text-white',
!start && 'text-muted-foreground'
)}
data-cy="input-date-range-start"
@@ -127,7 +127,7 @@ export function DatePickerWithRange({
value={end}
onChange={e => handleInputChange(e, 'end')}
className={cn(
- 'border-inputfield-main focus:border-inputfield-focus h-full w-full justify-start rounded border bg-black py-[6.5px] pl-[6.5px] pr-[6.5px] text-left text-sm font-normal hover:bg-black hover:text-white',
+ 'border-inputfield-main focus:border-inputfield-focus h-full w-full justify-start rounded border bg-black py-[6.5px] pl-[6.5px] pr-[6.5px] text-left text-base font-normal hover:bg-black hover:text-white',
!end && 'text-muted-foreground'
)}
data-cy="input-date-range-end"
diff --git a/platform/ui-next/src/components/Dialog/Dialog.tsx b/platform/ui-next/src/components/Dialog/Dialog.tsx
index 0b67911aa..8e69250f6 100644
--- a/platform/ui-next/src/components/Dialog/Dialog.tsx
+++ b/platform/ui-next/src/components/Dialog/Dialog.tsx
@@ -19,7 +19,7 @@ const DialogOverlay = React.forwardRef<
(({ className, ...props }, ref) => (
));
@@ -85,7 +85,7 @@ const DialogDescription = React.forwardRef<
>(({ className, ...props }, ref) => (
));
diff --git a/platform/ui-next/src/components/DisplaySetMessageListTooltip/DisplaySetMessageListTooltip.tsx b/platform/ui-next/src/components/DisplaySetMessageListTooltip/DisplaySetMessageListTooltip.tsx
index 48ec78c38..31f1d0118 100644
--- a/platform/ui-next/src/components/DisplaySetMessageListTooltip/DisplaySetMessageListTooltip.tsx
+++ b/platform/ui-next/src/components/DisplaySetMessageListTooltip/DisplaySetMessageListTooltip.tsx
@@ -23,9 +23,9 @@ const DisplaySetMessageListTooltip = ({ messages, id }): React.ReactNode => {
/>
-
+
(({ className, inset, ...props }, ref) => (
));
@@ -165,7 +165,7 @@ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes) => {
return (
);
diff --git a/platform/ui-next/src/components/Input/Input.tsx b/platform/ui-next/src/components/Input/Input.tsx
index e33596c54..9b4da766f 100644
--- a/platform/ui-next/src/components/Input/Input.tsx
+++ b/platform/ui-next/src/components/Input/Input.tsx
@@ -10,7 +10,7 @@ const Input = React.forwardRef(
{
const currentStep = Shepherd.activeTour?.getCurrentStep();
if (currentStep) {
const progress = document.createElement('span');
- progress.className = 'shepherd-progress text-base text-muted-foreground';
+ progress.className = 'shepherd-progress text-lg text-muted-foreground';
progress.innerText = `${Shepherd.activeTour?.steps.indexOf(currentStep) + 1}/${Shepherd.activeTour?.steps.length}`;
progress.style.position = 'absolute';
progress.style.left = '13px';
diff --git a/platform/ui-next/src/components/Select/Select.tsx b/platform/ui-next/src/components/Select/Select.tsx
index f0178f3fa..f3f0639b1 100644
--- a/platform/ui-next/src/components/Select/Select.tsx
+++ b/platform/ui-next/src/components/Select/Select.tsx
@@ -17,7 +17,7 @@ const SelectTrigger = React.forwardRef<
span]:line-clamp-1 hover:bg-primary/10 flex h-7 w-full items-center justify-between whitespace-nowrap rounded border bg-transparent px-2 py-2 text-sm shadow-sm focus:outline-none focus:ring-1 disabled:cursor-not-allowed disabled:opacity-50',
+ 'border-input text-foreground ring-offset-background placeholder:text-muted-foreground focus:ring-ring [&>span]:line-clamp-1 hover:bg-primary/10 flex h-7 w-full items-center justify-between whitespace-nowrap rounded border bg-transparent px-2 py-2 text-base shadow-sm focus:outline-none focus:ring-1 disabled:cursor-not-allowed disabled:opacity-50',
className
)}
{...props}
@@ -96,7 +96,7 @@ const SelectLabel = React.forwardRef<
>(({ className, ...props }, ref) => (
));
@@ -109,7 +109,7 @@ const SelectItem = React.forwardRef<
-
+
{selectedSort.label}
diff --git a/platform/ui-next/src/components/StudyBrowserViewOptions/StudyBrowserViewOptions.tsx b/platform/ui-next/src/components/StudyBrowserViewOptions/StudyBrowserViewOptions.tsx
index b926f7bbd..3e7a622ff 100644
--- a/platform/ui-next/src/components/StudyBrowserViewOptions/StudyBrowserViewOptions.tsx
+++ b/platform/ui-next/src/components/StudyBrowserViewOptions/StudyBrowserViewOptions.tsx
@@ -15,7 +15,7 @@ export function StudyBrowserViewOptions({ tabs, onSelectTab, activeTabName }: wi
return (
-
+
{activeTab?.label}
diff --git a/platform/ui-next/src/components/Tabs/Tabs.tsx b/platform/ui-next/src/components/Tabs/Tabs.tsx
index f054032bb..47b55e59f 100644
--- a/platform/ui-next/src/components/Tabs/Tabs.tsx
+++ b/platform/ui-next/src/components/Tabs/Tabs.tsx
@@ -27,7 +27,7 @@ const TabsTrigger = React.forwardRef<
)}
-
- {`${t('Number of studies')}: `}
-
+
{numOfStudies > 100 ? '>100' : numOfStudies}
+
+ {`${t('Studies')} `}
+
@@ -99,7 +100,9 @@ const StudyListFilter = ({
{numOfStudies > 100 && (
-
{t('Filter list to 100 studies or less to enable sorting')}
+
+ {t('Filter list to 100 studies or less to enable sorting')}
+
)}
diff --git a/platform/ui/src/components/Typography/Typography.tsx b/platform/ui/src/components/Typography/Typography.tsx
index 3f278831d..ed62f4926 100644
--- a/platform/ui/src/components/Typography/Typography.tsx
+++ b/platform/ui/src/components/Typography/Typography.tsx
@@ -32,7 +32,8 @@ const classes = {
h3: 'text-4xl',
h4: 'text-3xl',
h5: 'text-2xl',
- h6: 'text-xl',
+ // Using px value temporarily until larger fontsize variables are finalized
+ h6: 'text-[20px]',
subtitle: 'text-lg',
body: 'text-base',
caption: 'text-xs',