feat: OHIF-v3 UI Component Library (#2653)
* wip on storybook as a replacement for using UI components in docusaurus, since it causes too many problems * fix: storybook webpack config * feat: add more stories * feat: add more stories * feat: add more stories * feat: fix logo and babel runtime error * feat: move to mdx docs for ui * feat: enhanced mdx for header and styles * feat: Add button usecases * feat: Add buttonGroup docs * feat: Add docs and use case to cine and contex menu * feat: fix decorators * feat: add header and dropdown docs * feat: add Icon and input docs * feat: add more docs * feat: add more stories * fix: feedback section * feat: Add doc page * feat: Add typography and color stories * yarn lock * add analytics to v3-ui * new banner image * new viewport component * update review comments
@ -44,7 +44,7 @@
|
||||
"react-resize-detector": "^3.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.7.6",
|
||||
"@babel/runtime": "7.16.3",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"lodash.debounce": "4.0.8",
|
||||
"react-cornerstone-viewport": "4.1.2"
|
||||
|
||||
@ -41,6 +41,6 @@
|
||||
"webpack-merge": "^5.7.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.7.6"
|
||||
"@babel/runtime": "7.16.3"
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
"react-cornerstone-viewport": "4.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.7.6",
|
||||
"@babel/runtime": "7.16.3",
|
||||
"classnames": "^2.2.6"
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
"webpack-merge": "^5.7.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.7.6",
|
||||
"@babel/runtime": "7.16.3",
|
||||
"@ohif/ui": "^1.8.2",
|
||||
"@xstate/react": "^0.8.1",
|
||||
"xstate": "^4.10.0"
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
"@ohif/core": "^2.12.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.7.6"
|
||||
"@babel/runtime": "7.16.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"webpack": "^5.50.0",
|
||||
|
||||
@ -52,8 +52,8 @@
|
||||
"link-list": "npm ls --depth=0 --link=true"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.7.6",
|
||||
"config-point": "^0.3.4",
|
||||
"@babel/runtime": "7.16.3",
|
||||
"core-js": "^3.2.1",
|
||||
"cornerstone-core": "2.6.0",
|
||||
"wslink": "^0.1.8"
|
||||
@ -134,6 +134,6 @@
|
||||
]
|
||||
},
|
||||
"resolutions": {
|
||||
"**/@babel/runtime": "7.7.6"
|
||||
"**/@babel/runtime": "7.16.3"
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
"@ohif/ui": "^1.8.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.7.6",
|
||||
"@babel/runtime": "7.16.3",
|
||||
"dcmjs": "0.16.1",
|
||||
"dicomweb-client": "^0.6.0",
|
||||
"isomorphic-base64": "^1.0.2",
|
||||
|
||||
@ -80,7 +80,7 @@ the extension. The following lines of code should be added to the OHIF:
|
||||
/* ... */
|
||||
"dependencies": {
|
||||
/* ... */
|
||||
"@babel/runtime": "7.7.6",
|
||||
"@babel/runtime": "7.16.3",
|
||||
"@ohif/core": "^2.5.1",
|
||||
"@ohif/extension-cornerstone": "^2.4.0",
|
||||
"@ohif/extension-measurement-tracking": "^0.0.1",
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"react-i18next": "^10.11.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.7.6",
|
||||
"@babel/runtime": "7.16.3",
|
||||
"i18next-locize-backend": "^2.0.0",
|
||||
"locize-editor": "^2.0.0",
|
||||
"locize-lastused": "^1.1.0"
|
||||
|
||||
8
platform/ui/.storybook/OHIFTheme.js
Normal file
@ -0,0 +1,8 @@
|
||||
import { create } from '@storybook/theming';
|
||||
|
||||
export default create({
|
||||
base: 'light',
|
||||
brandTitle: 'OHIF',
|
||||
brandUrl: 'https://ohif.org',
|
||||
brandImage: 'ohif-logo-light.svg',
|
||||
});
|
||||
3
platform/ui/.storybook/custom.css
Normal file
@ -0,0 +1,3 @@
|
||||
#storybook-explorer-menu svg {
|
||||
color: #5034ff;
|
||||
}
|
||||
62
platform/ui/.storybook/main.js
Normal file
@ -0,0 +1,62 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
stories: ['../src/**/*.stories.@(mdx)'],
|
||||
addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-google-analytics'],
|
||||
core: {
|
||||
builder: 'webpack5',
|
||||
},
|
||||
staticDirs: ['../static'],
|
||||
webpackFinal: async (config, { configType }) => {
|
||||
// `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
|
||||
// You can change the configuration based on that.
|
||||
// 'PRODUCTION' is used when building the static version of storybook.
|
||||
// config.module.rules[0].use[0].options.plugins[1] = [
|
||||
// '@babel/plugin-proposal-class-properties',
|
||||
// { loose: true },
|
||||
// ];
|
||||
|
||||
// Make whatever fine-grained changes you need
|
||||
config.module.rules.push({
|
||||
test: /\.m?js/,
|
||||
resolve: {
|
||||
fullySpecified: false,
|
||||
},
|
||||
});
|
||||
|
||||
// Default rule for images /\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/
|
||||
const fileLoaderRule = config.module.rules.find(
|
||||
rule => rule.test && rule.test.test('.svg')
|
||||
);
|
||||
fileLoaderRule.exclude = /\.svg$/;
|
||||
|
||||
// console.log(JSON.stringify(config.module.rules, null, 2));
|
||||
|
||||
config.module.rules.push({
|
||||
test: /\.svg$/,
|
||||
use: [
|
||||
{ loader: require.resolve('babel-loader') },
|
||||
// { loader: 'svg-inline-loader' },
|
||||
],
|
||||
});
|
||||
|
||||
config.module.rules.push({
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
// HERE: OPTIONS
|
||||
postcssOptions: {
|
||||
plugins: [require('tailwindcss'), require('autoprefixer')],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
include: path.resolve(__dirname, '../'),
|
||||
});
|
||||
|
||||
// Return the altered config
|
||||
return config;
|
||||
},
|
||||
};
|
||||
28
platform/ui/.storybook/manager-head.html
Normal file
@ -0,0 +1,28 @@
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Lato:100,300,400,500,700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<title>OHIF UI Component</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: #f0f3ff !important;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#storybook-explorer-menu svg {
|
||||
color: #2b5282;
|
||||
}
|
||||
</style>
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script
|
||||
async
|
||||
src="https://www.googletagmanager.com/gtag/js?id=G-3S63CTHNP6"
|
||||
></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-3S63CTHNP6');
|
||||
</script>
|
||||
17
platform/ui/.storybook/manager.js
Normal file
@ -0,0 +1,17 @@
|
||||
// .storybook/manager.js
|
||||
|
||||
import { addons } from '@storybook/addons';
|
||||
import ohifTheme from './OHIFTheme';
|
||||
import favicon from '/static/favicon.png';
|
||||
|
||||
const link = document.createElement('link');
|
||||
link.setAttribute('rel', 'shortcut icon');
|
||||
link.setAttribute('href', favicon);
|
||||
document.head.appendChild(link);
|
||||
|
||||
addons.setConfig({
|
||||
theme: ohifTheme,
|
||||
});
|
||||
|
||||
window.STORYBOOK_GA_ID = "G-3S63CTHNP6"
|
||||
window.STORYBOOK_REACT_GA_OPTIONS = {}
|
||||
84
platform/ui/.storybook/preview.js
Normal file
@ -0,0 +1,84 @@
|
||||
import { parameters } from '@storybook/addon-docs/dist/esm/frameworks/react/config';
|
||||
import { addParameters } from '@storybook/react';
|
||||
import { DocsPage, DocsContainer } from '@storybook/addon-docs/blocks';
|
||||
import {
|
||||
Heading,
|
||||
SectionName,
|
||||
Footer,
|
||||
AnchorListItem,
|
||||
LinkComponent,
|
||||
} from '../src/storybook/components';
|
||||
|
||||
import '../src/tailwind.css';
|
||||
import './custom.css';
|
||||
|
||||
// https://github.com/mondaycom/monday-ui-react-core/tree/master/.storybook
|
||||
addParameters({
|
||||
docs: {
|
||||
...parameters.docs,
|
||||
inlineStories: true,
|
||||
container: ({ children, context }) => (
|
||||
<DocsContainer context={context}>{children}</DocsContainer>
|
||||
),
|
||||
page: DocsPage,
|
||||
components: {
|
||||
Heading,
|
||||
Footer,
|
||||
h2: SectionName,
|
||||
h3: ({ children }) => (
|
||||
<h3 className="my-2 text-xl to-blue-900">{children}</h3>
|
||||
),
|
||||
li: AnchorListItem,
|
||||
a: LinkComponent,
|
||||
p: ({ children }) => (
|
||||
<p className="my-2 text-gray-800 font-inter">{children}</p>
|
||||
),
|
||||
// todo: add pre and code
|
||||
},
|
||||
},
|
||||
viewMode: 'docs',
|
||||
previewTabs: {
|
||||
'storybook/docs/panel': {
|
||||
index: -1,
|
||||
},
|
||||
canvas: { title: 'Sandbox' },
|
||||
},
|
||||
actions: { argTypesRegex: '^on[A-Z].*' },
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/,
|
||||
},
|
||||
},
|
||||
viewport: {
|
||||
disable: true,
|
||||
},
|
||||
backgrounds: {
|
||||
default: 'OHIF-v3',
|
||||
values: [
|
||||
{
|
||||
name: 'White',
|
||||
value: '#FFFFFF',
|
||||
},
|
||||
{
|
||||
name: 'OHIF-v3',
|
||||
value: '#090C29',
|
||||
},
|
||||
{
|
||||
name: 'Light',
|
||||
value: '#F8F8F8',
|
||||
},
|
||||
{
|
||||
name: 'Dark',
|
||||
value: '#333333',
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
storySort: {
|
||||
order: ['Welcome', 'Contribute', 'Foundations', 'Modals', '*'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const decorators = [];
|
||||
@ -1 +1,14 @@
|
||||
# @ohif/ui
|
||||
|
||||
## For Running Storybook
|
||||
|
||||
```
|
||||
cd platform/ui
|
||||
|
||||
yarn install
|
||||
|
||||
yarn storybook
|
||||
|
||||
```
|
||||
|
||||
Stories are available default at `http://localhost:6006/`
|
||||
|
||||
1
platform/ui/babel.config.js
Normal file
@ -0,0 +1 @@
|
||||
module.exports = require('../../babel.config.js');
|
||||
@ -21,7 +21,9 @@
|
||||
"scripts": {
|
||||
"start": "yarn run build --watch",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
"build:package": "yarn run build"
|
||||
"build:package": "yarn run build",
|
||||
"storybook": "start-storybook -p 6006",
|
||||
"build-storybook": "build-storybook"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "17.0.2",
|
||||
@ -44,7 +46,19 @@
|
||||
"react-with-direction": "^1.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.14.8",
|
||||
"@storybook/addon-actions": "^6.4.9",
|
||||
"@storybook/addon-docs": "^6.4.9",
|
||||
"@storybook/addon-essentials": "^6.4.9",
|
||||
"@storybook/addon-google-analytics": "^6.2.9",
|
||||
"@storybook/addon-links": "^6.4.9",
|
||||
"@storybook/builder-webpack5": "^6.4.9",
|
||||
"@storybook/manager-webpack5": "^6.4.9",
|
||||
"@storybook/react": "^6.4.9",
|
||||
"@storybook/source-loader": "^6.4.9",
|
||||
"autoprefixer": "9.7.4",
|
||||
"babel-loader": "^8.2.2",
|
||||
"dotenv-webpack": "6.0.4",
|
||||
"postcss": "^8.3.5",
|
||||
"postcss-loader": "^6.1.1",
|
||||
"prop-types": "15.7.2",
|
||||
|
||||
@ -13,7 +13,7 @@ const Link = ({ href, children, showIcon = false }) => {
|
||||
>
|
||||
{children}
|
||||
{!!showIcon && (
|
||||
<Icon name="external-link" className="w-5 text-white ml-2" />
|
||||
<Icon name="external-link" className="w-5 ml-2 text-white" />
|
||||
)}
|
||||
</Typography>
|
||||
</a>
|
||||
@ -23,31 +23,31 @@ const Link = ({ href, children, showIcon = false }) => {
|
||||
const Row = ({ title, value, link }) => {
|
||||
return (
|
||||
<div className="flex mb-4">
|
||||
<Typography variant="subtitle" component="p" className="text-white w-48">
|
||||
<Typography variant="subtitle" component="p" className="w-48 text-white">
|
||||
{title}
|
||||
</Typography>
|
||||
|
||||
{link ? (
|
||||
<Link href={link}>{value}</Link>
|
||||
) : (
|
||||
<Typography
|
||||
variant="subtitle"
|
||||
component="p"
|
||||
className="text-white w-48"
|
||||
>
|
||||
{value}
|
||||
</Typography>
|
||||
)}
|
||||
<Typography
|
||||
variant="subtitle"
|
||||
component="p"
|
||||
className="w-48 text-white"
|
||||
>
|
||||
{value}
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const AboutModal = ({buildNumber, versionNumber}) => {
|
||||
const AboutModal = ({ buildNumber, versionNumber }) => {
|
||||
const { os, version, name } = detect();
|
||||
const browser = `${name[0].toUpperCase()}${name.substr(1)} ${version}`;
|
||||
|
||||
const renderRowTitle = title => (
|
||||
<div className="border-b-2 border-black pb-3 mb-3">
|
||||
<div className="pb-3 mb-3 border-b-2 border-black">
|
||||
<Typography variant="h6" className="text-primary-light">
|
||||
{title}
|
||||
</Typography>
|
||||
@ -57,10 +57,7 @@ const AboutModal = ({buildNumber, versionNumber}) => {
|
||||
<div>
|
||||
{renderRowTitle('Important Links')}
|
||||
<div className="flex mb-8">
|
||||
<Link
|
||||
href="https://community.ohif.org/"
|
||||
showIcon={true}
|
||||
>
|
||||
<Link href="https://community.ohif.org/" showIcon={true}>
|
||||
Visit the forum
|
||||
</Link>
|
||||
<span className="ml-4">
|
||||
@ -102,6 +99,6 @@ const AboutModal = ({buildNumber, versionNumber}) => {
|
||||
AboutModal.propTypes = {
|
||||
buildNumber: PropTypes.string,
|
||||
versionNumber: PropTypes.string,
|
||||
}
|
||||
};
|
||||
|
||||
export default AboutModal;
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
import AboutModal from '../AboutModal';
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import {
|
||||
createComponentTemplate,
|
||||
createStoryMetaSettings,
|
||||
} from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: AboutModal,
|
||||
title: 'Modals/About',
|
||||
};
|
||||
|
||||
<Meta title="Modals/About" component={AboutModal} />
|
||||
|
||||
export const aboutTemplate = args => (
|
||||
<div className="bg-primary-dark">
|
||||
<AboutModal {...args} />
|
||||
</div>
|
||||
);
|
||||
|
||||
<Heading
|
||||
title="About Modal"
|
||||
componentRelativePath="AboutModal/AboutModal.jsx"
|
||||
/>
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Usage](#usage)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
OHIF about modal component provides information about the application version
|
||||
and build number
|
||||
|
||||
<Canvas>
|
||||
<Story name="Overview">{aboutTemplate.bind({})}</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={AboutModal} />
|
||||
|
||||
## Usage
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="AboutModal/__stories__/aboutModal.stories.mdx" />
|
||||
@ -23,7 +23,6 @@ const roundedClasses = {
|
||||
full: 'rounded-full',
|
||||
};
|
||||
|
||||
|
||||
const variantClasses = {
|
||||
text: {
|
||||
default:
|
||||
@ -64,16 +63,11 @@ const variantClasses = {
|
||||
'border bg-primary-light border-primary-light text-black hover:opacity-80 active:opacity-100 focus:opacity-80',
|
||||
},
|
||||
disabled: {
|
||||
default:
|
||||
'cursor-not-allowed opacity-50 bg-primary-light text-black',
|
||||
primary:
|
||||
'cursor-not-allowed opacity-50 bg-primary-main text-white',
|
||||
secondary:
|
||||
'cursor-not-allowed opacity-50 bg-secondary-light text-white',
|
||||
white:
|
||||
'cursor-not-allowed opacity-50 bg-white text-black',
|
||||
black:
|
||||
'cursor-not-allowed opacity-50 bg-black text-white',
|
||||
default: 'cursor-not-allowed opacity-50 bg-primary-light text-black',
|
||||
primary: 'cursor-not-allowed opacity-50 bg-primary-main text-white',
|
||||
secondary: 'cursor-not-allowed opacity-50 bg-secondary-light text-white',
|
||||
white: 'cursor-not-allowed opacity-50 bg-white text-black',
|
||||
black: 'cursor-not-allowed opacity-50 bg-black text-white',
|
||||
light:
|
||||
'cursor-not-allowed opacity-50 border bg-primary-light border-primary-light text-black',
|
||||
},
|
||||
@ -140,7 +134,7 @@ const Button = ({
|
||||
variantClasses[variant][color],
|
||||
roundedClasses[rounded],
|
||||
sizeClasses[size],
|
||||
fullWidthClasses[fullWidth],
|
||||
fullWidthClasses[fullWidth]
|
||||
)}
|
||||
disabled={disabled}
|
||||
ref={buttonElement}
|
||||
@ -156,11 +150,25 @@ const Button = ({
|
||||
);
|
||||
};
|
||||
|
||||
Button.defaultProps = {
|
||||
color: defaults.color,
|
||||
disabled: false,
|
||||
children: '',
|
||||
onClick: () => {},
|
||||
};
|
||||
|
||||
Button.propTypes = {
|
||||
/** What is inside the button, can be text or react component */
|
||||
children: PropTypes.node,
|
||||
/** Callback to be called when the button is clicked */
|
||||
onClick: PropTypes.func.isRequired,
|
||||
/** Button size */
|
||||
size: PropTypes.oneOf(['small', 'medium', 'large', 'initial', 'inherit']),
|
||||
/** Button corner roundness */
|
||||
rounded: PropTypes.oneOf(['none', 'small', 'medium', 'large', 'full']),
|
||||
/** Button variants */
|
||||
variant: PropTypes.oneOf(['text', 'outlined', 'contained']),
|
||||
/** Button color */
|
||||
color: PropTypes.oneOf([
|
||||
'default',
|
||||
'primary',
|
||||
@ -168,16 +176,21 @@ Button.propTypes = {
|
||||
'white',
|
||||
'black',
|
||||
'inherit',
|
||||
'light'
|
||||
'light',
|
||||
]),
|
||||
/** Whether the button should have full width */
|
||||
fullWidth: PropTypes.bool,
|
||||
/** Whether the button should be disabled */
|
||||
disabled: PropTypes.bool,
|
||||
/** Button type */
|
||||
type: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
/** Button start icon name - if any icon is specified */
|
||||
startIcon: PropTypes.node,
|
||||
/** Button end icon name - if any icon is specified */
|
||||
endIcon: PropTypes.node,
|
||||
/** Additional TailwindCSS classnames */
|
||||
className: PropTypes.string,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default Button;
|
||||
|
||||
170
platform/ui/src/components/Button/__stories__/button.stories.mdx
Normal file
@ -0,0 +1,170 @@
|
||||
import Button from '../Button';
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import {
|
||||
createComponentTemplate,
|
||||
createStoryMetaSettings,
|
||||
} from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: Button,
|
||||
title: 'Components/Button',
|
||||
};
|
||||
|
||||
<Meta title="Components/Button" component={Button} />
|
||||
|
||||
export const buttonTemplate = createComponentTemplate(Button);
|
||||
|
||||
<Heading title="Button" componentRelativePath="Button/Button.jsx"/>
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Usage](#usage)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
|
||||
## Overview
|
||||
|
||||
You can use the button component to create a button. It can be used in different ways, the default
|
||||
button is a simple button with a text.
|
||||
|
||||
<Canvas>
|
||||
<Story name="Overview"
|
||||
args={{children: "Button", color:"default"}}>
|
||||
{buttonTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={Button} />
|
||||
|
||||
## Usage
|
||||
### Variants
|
||||
There can be different variants of buttons: `text`, `outlined`,
|
||||
`contained`, and `disabled`.
|
||||
|
||||
|
||||
<Canvas>
|
||||
<Story name="Variants" >
|
||||
<div className="flex space-x-2">
|
||||
<Button variant="text">Text Button</Button>
|
||||
<Button variant="outlined">Outlined Button</Button>
|
||||
<Button variant="contained">Contained Button</Button>
|
||||
<Button variant="disabled">Disabled Button</Button>
|
||||
</div>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
|
||||
### Colors
|
||||
There are different colors for the button: `default`, `primary`, `secondary`, `white`, `black`, `inherit`, `light`.
|
||||
|
||||
|
||||
<Canvas>
|
||||
<Story name="Colors" >
|
||||
<div className="flex space-x-2">
|
||||
<Button color="default">Default Button</Button>
|
||||
<Button color="primary">Primary Button</Button>
|
||||
<Button color="secondary">Secondary Button</Button>
|
||||
<Button color="white">White Button</Button>
|
||||
<Button color="black">Black Button</Button>
|
||||
<Button color="inherit">Inherit Button</Button>
|
||||
<Button color="light">Light Button</Button>
|
||||
</div>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
### Mixing props
|
||||
You can mix different props together to create a button.
|
||||
|
||||
<Canvas>
|
||||
<Story name="Custom" >
|
||||
<Button color="secondary" variant="outlined">Custom Button</Button>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
### Disabled
|
||||
You can disable the button by setting the variant to `disabled`.
|
||||
|
||||
<Canvas>
|
||||
<Story name="Disabled" >
|
||||
<Button variant="disabled">Disabled Button</Button>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
|
||||
### Start/End Icons
|
||||
You can add an icon to the start of the button. It accepts an icon component.
|
||||
|
||||
|
||||
<Canvas>
|
||||
<Story name="Start Icon" >
|
||||
{() => {
|
||||
// svg icon for github
|
||||
const Github = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="feather feather-github"
|
||||
>
|
||||
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
return <Button startIcon={<Github />}>Start Icon Button</Button>;
|
||||
}}
|
||||
}}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
End Icon is the same as start icon, but for the end of the button.
|
||||
|
||||
|
||||
<Canvas>
|
||||
<Story name="End Icon" >
|
||||
{() => {
|
||||
// svg icon for github
|
||||
const Github = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="feather feather-github"
|
||||
>
|
||||
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
return <Button startIcon={<Github />} endIcon={<Github />}>Start and End Icon Button</Button>;
|
||||
}}
|
||||
}}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
|
||||
### Full width
|
||||
You can make the button full width by setting the `fullWidth` prop to `true`.
|
||||
|
||||
<Canvas>
|
||||
<Story name="Full Width" >
|
||||
<Button fullWidth color="secondary">Full Width Button</Button>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Contribute
|
||||
<Footer componentRelativePath="Button/__stories__/button.stories.mdx"/>
|
||||
@ -0,0 +1,101 @@
|
||||
import ButtonGroup from '../ButtonGroup';
|
||||
import Button from '../../Button';
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import {
|
||||
createComponentTemplate,
|
||||
createStoryMetaSettings,
|
||||
} from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: ButtonGroup,
|
||||
title: 'Components/ButtonGroup',
|
||||
};
|
||||
|
||||
<Meta title="Components/ButtonGroup" component={ButtonGroup} />
|
||||
|
||||
export const buttonGroupTemplate = args => (
|
||||
<ButtonGroup {...args}>
|
||||
<Button>One</Button>
|
||||
<Button>Two</Button>
|
||||
<Button>Three</Button>
|
||||
</ButtonGroup>
|
||||
);
|
||||
|
||||
<Heading
|
||||
title="ButtonGroup"
|
||||
componentRelativePath="ButtonGroup/ButtonGroup.jsx"
|
||||
/>
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Usage](#usage)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
ButtonGroup is a container for a group of buttons.
|
||||
|
||||
<Canvas>
|
||||
<Story name="Overview">{buttonGroupTemplate.bind({})}</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={ButtonGroup} />
|
||||
|
||||
## Usage
|
||||
|
||||
### Variants
|
||||
|
||||
There are three different variants of ButtonGroup:
|
||||
|
||||
<Canvas>
|
||||
<Story name="Variants">
|
||||
<div className="flex flex-col space-y-2">
|
||||
<ButtonGroup variant="text">
|
||||
<Button>Text</Button>
|
||||
<Button>Text</Button>
|
||||
<Button>Text</Button>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup variant="outlined">
|
||||
<Button>Outlined</Button>
|
||||
<Button>Outlined</Button>
|
||||
<Button>Outlined</Button>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup variant="contained">
|
||||
<Button>Contained</Button>
|
||||
<Button>Contained</Button>
|
||||
<Button>Contained</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
### Orientation
|
||||
|
||||
You can change the orientation of the buttons in the group by setting the
|
||||
`orientation` prop.
|
||||
|
||||
<Canvas>
|
||||
<Story name="Orientation Horizontal">
|
||||
<ButtonGroup orientation="horizontal">
|
||||
<Button>Horizontal-1</Button>
|
||||
<Button>Horizontal-2</Button>
|
||||
</ButtonGroup>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
Or vertical
|
||||
|
||||
<Canvas>
|
||||
<Story name="Orientation Vertical">
|
||||
<ButtonGroup orientation="vertical">
|
||||
<Button>Vertical-1</Button>
|
||||
<Button>Vertical-2</Button>
|
||||
</ButtonGroup>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="ButtonGroup/__stories__/buttonGroup.stories.mdx" />
|
||||
@ -0,0 +1,32 @@
|
||||
import CinePlayer from '../CinePlayer';
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: CinePlayer,
|
||||
title: 'Components/CinePlayer',
|
||||
};
|
||||
|
||||
<Meta title="Components/CinePlayer" component={CinePlayer} />
|
||||
|
||||
export const cineTemplate = createComponentTemplate(CinePlayer);
|
||||
|
||||
<Heading title="CinePlayer" componentRelativePath="CinePlayer/CinePlayer.jsx" />
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
<Canvas>
|
||||
<Story name="Overview">{cineTemplate.bind({})}</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={CinePlayer} />
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="CinePlayer/__stories__/cinePlayer.stories.mdx" />
|
||||
@ -0,0 +1,63 @@
|
||||
import ContextMenu from '../ContextMenu';
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: ContextMenu,
|
||||
title: 'Modals/ContextMenu',
|
||||
};
|
||||
|
||||
<Meta title="Modals/ContextMenu" component={ContextMenu} />
|
||||
|
||||
export const contextMenueTemplate = createComponentTemplate(ContextMenu);
|
||||
|
||||
<Heading
|
||||
title="ContextMenu"
|
||||
componentRelativePath="ContextMenu/ContextMenu.jsx"
|
||||
/>
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
Context Menu is a component that is used to display a list of options to the
|
||||
user. This component can be used for use cases such as opening a list of options
|
||||
on user right click.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
items: [
|
||||
{
|
||||
label: 'Delete measurement',
|
||||
actionType: 'Delete',
|
||||
action: (item) => {
|
||||
window.alert(`${item.label} clicked`);
|
||||
},
|
||||
value: {},
|
||||
},
|
||||
{
|
||||
label: 'Add Label',
|
||||
actionType: 'setLabel',
|
||||
action: (item) => {
|
||||
window.alert(`${item.label} clicked`);
|
||||
},
|
||||
value: {},
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
{contextMenueTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={ContextMenu} />
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="ContextMenu/__stories__/contextMenu.stories.mdx" />
|
||||
@ -0,0 +1,46 @@
|
||||
import DateRange from '../DateRange';
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
|
||||
export const argTypes = {
|
||||
component: DateRange,
|
||||
title: 'Components/DateRange',
|
||||
};
|
||||
|
||||
<Meta title="Components/DateRange" component={DateRange} />
|
||||
|
||||
export const DateRangeTemplate = (args) => (
|
||||
<div className="h-96">
|
||||
<DateRange {...args} />
|
||||
</div>
|
||||
);
|
||||
|
||||
<Heading title="DateRange" componentRelativePath="DateRange/DateRange.jsx" />
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
DateRange is a component that allows you to select a range of dates.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
id: 'date-range-1',
|
||||
startDate: '1990-05-01',
|
||||
endDate: '2022-01-01',
|
||||
}}
|
||||
>
|
||||
{DateRangeTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={DateRange} />
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="DateRange/__stories__/dateRange.stories.mdx" />
|
||||
@ -0,0 +1,67 @@
|
||||
import Dialog from '../Dialog';
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: Dialog,
|
||||
title: 'Modals/Dialog',
|
||||
};
|
||||
|
||||
<Meta title="Modals/Dialog" component={Dialog} />
|
||||
|
||||
export const DialogTemplate = createComponentTemplate(Dialog);
|
||||
|
||||
<Heading title="Dialog" componentRelativePath="Dialog/Dialog.jsx" />
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Usage](#usage)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
Dialog is a modal dialog component which enabled to show a modal dialog.
|
||||
|
||||
<Canvas>
|
||||
<Story name="Overview">{DialogTemplate.bind({})}</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={Dialog} />
|
||||
|
||||
## Usage
|
||||
|
||||
It can be used to show a modal dialog to submit a form or show a message.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Submit"
|
||||
args={{
|
||||
title: 'Dialog Title',
|
||||
text: 'Dialog Text',
|
||||
onClose: () => {
|
||||
window.alert('Dialog closed');
|
||||
},
|
||||
noCloseButton: false,
|
||||
actions: [
|
||||
{
|
||||
id: 'cancel',
|
||||
text: 'Cancel',
|
||||
type: 'cancel',
|
||||
},
|
||||
{
|
||||
id: 'submit',
|
||||
text: 'Submit',
|
||||
type: 'primary',
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
{DialogTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="Dialog/__stories__/dialog.stories.mdx" />
|
||||
@ -21,7 +21,7 @@ const Dropdown = ({ id, children, showDropdownIcon, list }) => {
|
||||
}}
|
||||
data-cy={id}
|
||||
>
|
||||
{!!icon && <Icon name={icon} className="text-white w-4 mr-2" />}
|
||||
{!!icon && <Icon name={icon} className="w-4 mr-2 text-white" />}
|
||||
<Typography>{title}</Typography>
|
||||
</div>
|
||||
);
|
||||
@ -40,11 +40,9 @@ const Dropdown = ({ id, children, showDropdownIcon, list }) => {
|
||||
|
||||
const renderTitleElement = () => {
|
||||
return (
|
||||
<div className="flex text-white items-center">
|
||||
<div className="flex items-center">
|
||||
{children}
|
||||
{showDropdownIcon && (
|
||||
<Icon name="chevron-down" className="text-white ml-1" />
|
||||
)}
|
||||
{showDropdownIcon && <Icon name="chevron-down" className="ml-1" />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -94,7 +92,7 @@ const Dropdown = ({ id, children, showDropdownIcon, list }) => {
|
||||
|
||||
return (
|
||||
<div data-cy="dropdown" ref={element} className="relative">
|
||||
<div className="cursor-pointer flex items-center" onClick={toggleList}>
|
||||
<div className="flex items-center cursor-pointer" onClick={toggleList}>
|
||||
{renderTitleElement()}
|
||||
</div>
|
||||
|
||||
|
||||
@ -0,0 +1,75 @@
|
||||
import Dropdown from '../Dropdown';
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: Dropdown,
|
||||
title: 'Components/Dropdown',
|
||||
};
|
||||
|
||||
<Meta title="Components/Dropdown" component={Dropdown} />
|
||||
|
||||
export const DropdownTemplate = (args) => (
|
||||
// Todo: this should not set a background
|
||||
<div className="flex h-32">
|
||||
<Dropdown {...args} />
|
||||
</div>
|
||||
);
|
||||
|
||||
<Heading title="Dropdown" componentRelativePath="Dropdown/Dropdown.jsx" />
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Usage](#usage)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
Dropdown is a modal Dropdown component which enabled to show a modal Dropdown.
|
||||
|
||||
<Canvas>
|
||||
<Story name="Overview" args={{ id: 'dropdown-d', list: [] }}>
|
||||
{DropdownTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={Dropdown} />
|
||||
|
||||
## Usage
|
||||
|
||||
You can list the items in the dropdown.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="List"
|
||||
args={{
|
||||
id: 'dropdown-1',
|
||||
children: <div className="text-black">Drop Down</div>,
|
||||
showDropdownIcon: true,
|
||||
list: [
|
||||
{
|
||||
title: 'Item 1',
|
||||
icon: 'clipboard',
|
||||
onClick: () => {
|
||||
alert('Item 1 clicked');
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Item 2',
|
||||
icon: 'tracked',
|
||||
onClick: () => {
|
||||
alert('Item 2 clicked');
|
||||
},
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
{DropdownTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="Dropdown/__stories__/dropdown.stories.mdx" />
|
||||
@ -14,7 +14,7 @@ const ExpandableToolbarButton = ({
|
||||
icon,
|
||||
className,
|
||||
content: Content,
|
||||
contentProps
|
||||
contentProps,
|
||||
}) => {
|
||||
const classes = {
|
||||
type: {
|
||||
@ -54,7 +54,12 @@ const ExpandableToolbarButton = ({
|
||||
<Icon name={icon} />
|
||||
</IconButton>
|
||||
<div className="absolute z-10 pt-4">
|
||||
<div className={classnames("ExpandableToolbarButton__content w-48", className)}>
|
||||
<div
|
||||
className={classnames(
|
||||
'ExpandableToolbarButton__content w-48',
|
||||
className
|
||||
)}
|
||||
>
|
||||
<Content {...contentProps} onClick={onChildClickHandler} />
|
||||
</div>
|
||||
</div>
|
||||
@ -62,9 +67,11 @@ const ExpandableToolbarButton = ({
|
||||
);
|
||||
};
|
||||
|
||||
const noop = () => { };
|
||||
const noop = () => {};
|
||||
|
||||
ExpandableToolbarButton.defaultProps = {
|
||||
id: '',
|
||||
icon: 'clipboard',
|
||||
isActive: false,
|
||||
type: 'primary',
|
||||
content: null,
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
import Header from '../Header';
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: Header,
|
||||
title: 'Components/Header',
|
||||
};
|
||||
|
||||
<Meta title="Components/Header" component={Header} />
|
||||
|
||||
export const HeaderTemplate = createComponentTemplate(Header);
|
||||
|
||||
<Heading title="Header" componentRelativePath="Header/Header.jsx" />
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Usage](#usage)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
Header is a component that renders the header of the application.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
menuOptions: [
|
||||
{
|
||||
title: 'About',
|
||||
icon: 'info',
|
||||
onClick: () => window.alert('About clicked'),
|
||||
},
|
||||
],
|
||||
isReturnEnabled: true,
|
||||
isSticky: false,
|
||||
onClickReturnButton: () => window.alert('Return clicked'),
|
||||
}}
|
||||
>
|
||||
{HeaderTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={Header} />
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="Header/__stories__/header.stories.mdx" />
|
||||
@ -4,12 +4,17 @@ import classNames from 'classnames';
|
||||
import { HotkeyField, Typography } from '../';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
|
||||
/* TODO: Move these configs and utils to core? */
|
||||
import { MODIFIER_KEYS } from './hotkeysConfig';
|
||||
import { validate, splitHotkeyDefinitionsAndCreateTuples } from './utils';
|
||||
|
||||
const HotkeysPreferences = ({ disabled, hotkeyDefinitions, errors: controlledErrors, onChange, hotkeysModule }) => {
|
||||
const HotkeysPreferences = ({
|
||||
disabled,
|
||||
hotkeyDefinitions,
|
||||
errors: controlledErrors,
|
||||
onChange,
|
||||
hotkeysModule,
|
||||
}) => {
|
||||
const { t } = useTranslation('UserPreferencesModal');
|
||||
|
||||
const visibleHotkeys = Object.keys(hotkeyDefinitions)
|
||||
@ -42,51 +47,74 @@ const HotkeysPreferences = ({ disabled, hotkeyDefinitions, errors: controlledErr
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='flex flex-row justify-center'>
|
||||
<div className='flex flex-row justify-evenly w-full'>
|
||||
<div className="flex flex-row justify-center">
|
||||
<div className="flex flex-row w-full justify-evenly">
|
||||
{splitedHotkeys.map((hotkeys, index) => {
|
||||
return (
|
||||
<div key={`HotkeyGroup@${index}`} className='flex flex-row'>
|
||||
<div className='p-2 text-right flex flex-col'>
|
||||
<div key={`HotkeyGroup@${index}`} className="flex flex-row">
|
||||
<div className="flex flex-col p-2 text-right">
|
||||
{hotkeys.map((hotkey, hotkeyIndex) => {
|
||||
const [id, definition] = hotkey;
|
||||
const isFirst = hotkeyIndex === 0;
|
||||
const error = errors[id];
|
||||
|
||||
const onChangeHandler = keys => onHotkeyChangeHandler(id, { ...definition, keys });
|
||||
const onChangeHandler = keys =>
|
||||
onHotkeyChangeHandler(id, { ...definition, keys });
|
||||
|
||||
return (
|
||||
<div key={`HotkeyItem@${hotkeyIndex}`} className='flex flex-row justify-end mb-2'>
|
||||
<div className='flex flex-col items-center'>
|
||||
<div
|
||||
key={`HotkeyItem@${hotkeyIndex}`}
|
||||
className="flex flex-row justify-end mb-2"
|
||||
>
|
||||
<div className="flex flex-col items-center">
|
||||
<Typography
|
||||
variant='subtitle'
|
||||
className={classNames('pr-6 w-full text-right text-primary-light', !isFirst && 'hidden')}
|
||||
variant="subtitle"
|
||||
className={classNames(
|
||||
'pr-6 w-full text-right text-primary-light',
|
||||
!isFirst && 'hidden'
|
||||
)}
|
||||
>
|
||||
{t('Function')}
|
||||
</Typography>
|
||||
</Typography>
|
||||
<Typography
|
||||
variant='subtitle'
|
||||
className={classNames('pr-6 h-full flex flex-row items-center whitespace-nowrap', isFirst && 'mt-5')}>
|
||||
variant="subtitle"
|
||||
className={classNames(
|
||||
'pr-6 h-full flex flex-row items-center whitespace-nowrap',
|
||||
isFirst && 'mt-5'
|
||||
)}
|
||||
>
|
||||
{definition.label}
|
||||
</Typography>
|
||||
</div>
|
||||
<div className='flex flex-col'>
|
||||
<div className="flex flex-col">
|
||||
<Typography
|
||||
variant='subtitle'
|
||||
className={classNames('pr-6 pl-0 text-left text-primary-light', !isFirst && 'hidden')}
|
||||
variant="subtitle"
|
||||
className={classNames(
|
||||
'pr-6 pl-0 text-left text-primary-light',
|
||||
!isFirst && 'hidden'
|
||||
)}
|
||||
>
|
||||
{t('Shortcut')}
|
||||
</Typography>
|
||||
<div className={classNames('flex flex-col w-32', isFirst && 'mt-5')}>
|
||||
</Typography>
|
||||
<div
|
||||
className={classNames(
|
||||
'flex flex-col w-32',
|
||||
isFirst && 'mt-5'
|
||||
)}
|
||||
>
|
||||
<HotkeyField
|
||||
disabled={disabled}
|
||||
keys={definition.keys}
|
||||
modifierKeys={MODIFIER_KEYS}
|
||||
onChange={onChangeHandler}
|
||||
hotkeys={hotkeysModule}
|
||||
className='text-lg h-8'
|
||||
className="h-8 text-lg"
|
||||
/>
|
||||
{error && <span className='p-2 text-left text-red-600 text-sm'>{error}</span>}
|
||||
{error && (
|
||||
<span className="p-2 text-sm text-left text-red-600">
|
||||
{error}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -101,7 +129,7 @@ const HotkeysPreferences = ({ disabled, hotkeyDefinitions, errors: controlledErr
|
||||
);
|
||||
};
|
||||
|
||||
const noop = () => { };
|
||||
const noop = () => {};
|
||||
|
||||
HotkeysPreferences.propTypes = {
|
||||
onChange: PropTypes.func,
|
||||
@ -113,12 +141,12 @@ HotkeysPreferences.propTypes = {
|
||||
unpause: PropTypes.func.isRequired,
|
||||
startRecording: PropTypes.func.isRequired,
|
||||
record: PropTypes.func.isRequired,
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
HotkeysPreferences.defaultProps = {
|
||||
onChange: noop,
|
||||
disabled: false
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
export default HotkeysPreferences;
|
||||
|
||||
@ -2,12 +2,21 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import getIcon from './getIcon';
|
||||
|
||||
const Icon = ({ name, ...otherProps }) => {
|
||||
const Icon = ({ name, className, ...otherProps }) => {
|
||||
if (className) {
|
||||
return (
|
||||
<div className={className}>
|
||||
{getIcon(name, className, { ...otherProps })}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <React.Fragment>{getIcon(name, { ...otherProps })}</React.Fragment>;
|
||||
};
|
||||
|
||||
Icon.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
export default Icon;
|
||||
|
||||
92
platform/ui/src/components/Icon/__stories__/icon.stories.mdx
Normal file
@ -0,0 +1,92 @@
|
||||
import Icon from '../Icon';
|
||||
import { ICONS } from '../getIcon';
|
||||
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: Icon,
|
||||
title: 'Components/Icon',
|
||||
};
|
||||
|
||||
<Meta title="Components/Icon" component={Icon} />
|
||||
|
||||
export const IconTemplate = (args) => (
|
||||
// Todo: Icon colors
|
||||
<div className="w-8 h-8">
|
||||
<Icon {...args} />
|
||||
</div>
|
||||
);
|
||||
|
||||
<Heading title="Icon" componentRelativePath="Icon/Icon.jsx" />
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Usage](#usage)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
Icon is a component that renders the Icons.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
name: 'clipboard',
|
||||
}}
|
||||
>
|
||||
{IconTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={Icon} />
|
||||
|
||||
## Usage
|
||||
|
||||
You can choose the icon from the list of icons. Here we have render all the
|
||||
icons.
|
||||
|
||||
<Canvas>
|
||||
<Story name="All Icons">
|
||||
{() => {
|
||||
const icons = Object.keys(ICONS);
|
||||
return (
|
||||
<div className="flex flex-wrap">
|
||||
{icons
|
||||
.filter((ic) => ic !== 'magnifier')
|
||||
.map((icon) => (
|
||||
<div className="m-4 flex flex-col justify-center items-center">
|
||||
<div class="w-8 h-8">
|
||||
<Icon name={icon} />
|
||||
</div>
|
||||
<div className="text-gray-600">{icon}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Color
|
||||
|
||||
Icon colors can be changed by wrapping the icon in a div with the class name
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Colors"
|
||||
args={{
|
||||
name: 'clipboard',
|
||||
className: 'text-red-700',
|
||||
}}
|
||||
>
|
||||
{IconTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="Icon/__stories__/icon.stories.mdx" />
|
||||
26
platform/ui/src/components/IconButton/IconButton.stories.jsx
Normal file
@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import IconButton from './IconButton';
|
||||
import Icon from '../Icon/Icon';
|
||||
import { ICONS } from '../Icon/getIcon';
|
||||
|
||||
export default {
|
||||
component: IconButton,
|
||||
title: 'Icons/IconButton',
|
||||
argTypes: {
|
||||
iconName: {
|
||||
control: { type: 'select', options: Object.keys(ICONS) },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const Template = ({ iconName, ...args }) => (
|
||||
<IconButton {...args}>
|
||||
<Icon name={iconName} />
|
||||
</IconButton>
|
||||
);
|
||||
|
||||
export const Default = Template.bind({});
|
||||
|
||||
Default.args = {
|
||||
iconName: 'clipboard',
|
||||
};
|
||||
@ -0,0 +1,75 @@
|
||||
import Input from '../Input';
|
||||
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: Input,
|
||||
title: 'Components/Input',
|
||||
};
|
||||
|
||||
<Meta title="Components/Input" component={Input} />
|
||||
|
||||
export const InputTemplate = createComponentTemplate(Input);
|
||||
|
||||
<Heading title="Input" componentRelativePath="Input/Input.jsx" />
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Usage](#usage)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
Input is a component that renders the Inputs.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
label: 'Input',
|
||||
}}
|
||||
>
|
||||
{InputTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={Input} />
|
||||
|
||||
## Usage
|
||||
|
||||
### Transparent
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Transparent"
|
||||
args={{
|
||||
transparent: true,
|
||||
}}
|
||||
>
|
||||
{InputTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
### Classnames
|
||||
|
||||
You can change the appearance of the container and label.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="ClassNames"
|
||||
args={{
|
||||
label: 'Input',
|
||||
containerClassName: 'bg-gray-500',
|
||||
labelClassName: 'text-yellow-500',
|
||||
}}
|
||||
>
|
||||
{InputTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="Input/__stories__/input.stories.mdx" />
|
||||
@ -0,0 +1,38 @@
|
||||
import LayoutSelector from '../LayoutSelector';
|
||||
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: LayoutSelector,
|
||||
title: 'Components/LayoutSelector',
|
||||
};
|
||||
|
||||
<Meta title="Components/LayoutSelector" component={LayoutSelector} />
|
||||
|
||||
export const LayoutSelectorTemplate = createComponentTemplate(LayoutSelector);
|
||||
|
||||
<Heading
|
||||
title="LayoutSelector"
|
||||
componentRelativePath="LayoutSelector/LayoutSelector.jsx"
|
||||
/>
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
LayoutSelector is a component that renders the LayoutSelectors.
|
||||
|
||||
<Canvas>
|
||||
<Story name="Overview">{LayoutSelectorTemplate.bind({})}</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={LayoutSelector} />
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="LayoutSelector/__stories__/layoutSelector.stories.mdx" />
|
||||
@ -0,0 +1,73 @@
|
||||
import MeasurementTable from '../MeasurementTable';
|
||||
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: MeasurementTable,
|
||||
title: 'Components/MeasurementTable',
|
||||
};
|
||||
|
||||
<Meta title="Components/MeasurementTable" component={MeasurementTable} />
|
||||
|
||||
export const MeasurementTableTemplate = (args) => (
|
||||
<div className="w-64 h-64 bg-primary-dark">
|
||||
<MeasurementTable {...args} />
|
||||
</div>
|
||||
);
|
||||
|
||||
<Heading
|
||||
title="MeasurementTable"
|
||||
componentRelativePath="MeasurementTable/MeasurementTable.jsx"
|
||||
/>
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
MeasurementTable is a component that renders the MeasurementTables.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
title: 'Measurements',
|
||||
}}
|
||||
>
|
||||
{MeasurementTableTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={MeasurementTable} />
|
||||
|
||||
## Usage
|
||||
|
||||
With data
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="With Data"
|
||||
args={{
|
||||
title: 'Measurements',
|
||||
amount: 1,
|
||||
data: [
|
||||
{
|
||||
id: 1,
|
||||
label: '(empty)',
|
||||
displayText: ['193.1 mm (S:6, I:5)'],
|
||||
isActive: false,
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
{MeasurementTableTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="MeasurementTable/__stories__/measurementTable.stories.mdx" />
|
||||
@ -3,7 +3,14 @@ import classnames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, Icon } from '../';
|
||||
|
||||
const Notification = ({ id, type, message, actions, onSubmit, onOutsideClick }) => {
|
||||
const Notification = ({
|
||||
id,
|
||||
type,
|
||||
message,
|
||||
actions,
|
||||
onSubmit,
|
||||
onOutsideClick,
|
||||
}) => {
|
||||
const notificationRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
@ -93,7 +100,7 @@ Notification.defaultProps = {
|
||||
};
|
||||
|
||||
Notification.propTypes = {
|
||||
type: PropTypes.string,
|
||||
type: PropTypes.oneOf(['error', 'warning', 'info', 'success']),
|
||||
message: PropTypes.string.isRequired,
|
||||
actions: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
|
||||
@ -0,0 +1,63 @@
|
||||
import Notification from '../Notification';
|
||||
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: Notification,
|
||||
title: 'Components/Notification',
|
||||
};
|
||||
|
||||
<Meta title="Components/Notification" component={Notification} />
|
||||
|
||||
export const NotificationTemplate = createComponentTemplate(Notification);
|
||||
|
||||
<Heading
|
||||
title="Notification"
|
||||
componentRelativePath="Notification/Notification.jsx"
|
||||
/>
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
Notification is a component that renders the Notifications.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
message: 'Track all measurement for this series?',
|
||||
type: 'info',
|
||||
actions: [
|
||||
{
|
||||
type: 'cancel',
|
||||
text: 'No',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
type: 'secondary',
|
||||
text: 'No, do not ask again',
|
||||
value: -1,
|
||||
},
|
||||
{
|
||||
type: 'primary',
|
||||
text: 'Yes',
|
||||
value: 1,
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
{NotificationTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={Notification} />
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="Notification/__stories__/notification.stories.mdx" />
|
||||
@ -0,0 +1,71 @@
|
||||
import SegmentationTable from '../SegmentationTable';
|
||||
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: SegmentationTable,
|
||||
title: 'Components/SegmentationTable',
|
||||
};
|
||||
|
||||
<Meta title="Components/SegmentationTable" component={SegmentationTable} />
|
||||
|
||||
export const SegmentationTableTemplate = (args) => (
|
||||
<div className="w-64 h-96 bg-primary-dark">
|
||||
<SegmentationTable {...args} />
|
||||
</div>
|
||||
);
|
||||
|
||||
<Heading
|
||||
title="SegmentationTable"
|
||||
componentRelativePath="SegmentationTable/SegmentationTable.jsx"
|
||||
/>
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
SegmentationTable is a component that renders the SegmentationTables.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
title: 'Segmentations',
|
||||
}}
|
||||
>
|
||||
{SegmentationTableTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={SegmentationTable} />
|
||||
|
||||
## Usage
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="With Data"
|
||||
args={{
|
||||
title: 'Segmentations',
|
||||
amount: 1,
|
||||
activeSegmentationId: 'ptScene-labelmap-0',
|
||||
segmentations: [
|
||||
{
|
||||
id: 'ptScene-labelmap-0',
|
||||
label: 'ptScene-labelmap-0',
|
||||
displayText: ['SUV Peak: 25.58'],
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
{SegmentationTableTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="SegmentationTable/__stories__/segmentationTable.stories.mdx" />
|
||||
@ -0,0 +1,58 @@
|
||||
import SidePanel from '../SidePanel';
|
||||
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: SidePanel,
|
||||
title: 'Components/SidePanel',
|
||||
};
|
||||
|
||||
<Meta title="Components/SidePanel" component={SidePanel} />
|
||||
|
||||
export const SidePanelTemplate = (args) => (
|
||||
<div className="w-96">
|
||||
<SidePanel {...args} />
|
||||
</div>
|
||||
);
|
||||
|
||||
<Heading title="SidePanel" componentRelativePath="SidePanel/SidePanel.jsx" />
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
SidePanel is a component that renders the SidePanels.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
side: 'left',
|
||||
defaultComponentOpen: 'Example',
|
||||
childComponents: [
|
||||
{
|
||||
iconName: 'home',
|
||||
iconLabel: 'launch-info',
|
||||
name: 'Example',
|
||||
label: 'home',
|
||||
content: () => <div>Hello</div>,
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
{SidePanelTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={SidePanel} />
|
||||
|
||||
## Usage
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="SidePanel/__stories__/sidePanel.stories.mdx" />
|
||||
@ -0,0 +1,75 @@
|
||||
import SplitButton from '../SplitButton';
|
||||
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: SplitButton,
|
||||
title: 'Components/SplitButton',
|
||||
};
|
||||
|
||||
<Meta title="Components/SplitButton" component={SplitButton} />
|
||||
|
||||
export const SplitButtonTemplate = (args) => (
|
||||
<div className="h-32 bg-primary-dark">
|
||||
<SplitButton {...args} />
|
||||
</div>
|
||||
);
|
||||
|
||||
<Heading
|
||||
title="SplitButton"
|
||||
componentRelativePath="SplitButton/SplitButton.jsx"
|
||||
/>
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
SplitButton is a component that renders the SplitButtons.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
primary: {
|
||||
id: 'Length',
|
||||
icon: 'tool-length',
|
||||
label: 'Length',
|
||||
type: 'tool',
|
||||
commandName: undefined,
|
||||
commandOptions: { toolName: 'Length' },
|
||||
tooltip: 'Length',
|
||||
},
|
||||
bState: {},
|
||||
secondary: {
|
||||
icon: 'chevron-down',
|
||||
label: '',
|
||||
isActive: true,
|
||||
tooltip: 'More Measure Tools',
|
||||
},
|
||||
items: [
|
||||
{
|
||||
id: 'Bidirectional',
|
||||
icon: 'tool-bidirectional',
|
||||
label: 'Bidirectional',
|
||||
type: 'tool',
|
||||
commandName: undefined,
|
||||
commandOptions: { toolName: 'Bidirectional' },
|
||||
tooltip: 'Bidirectional',
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
{SplitButtonTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={SplitButton} />
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="SplitButton/__stories__/splitButton.stories.mdx" />
|
||||
@ -0,0 +1,129 @@
|
||||
import StudyBrowser from '../StudyBrowser';
|
||||
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: StudyBrowser,
|
||||
title: 'Components/StudyBrowser',
|
||||
};
|
||||
|
||||
<Meta title="Components/StudyBrowser" component={StudyBrowser} />
|
||||
|
||||
export const StudyBrowserTemplate = (args) => (
|
||||
<div className="w-96">
|
||||
<StudyBrowser {...args} />
|
||||
</div>
|
||||
);
|
||||
|
||||
<Heading
|
||||
title="StudyBrowser"
|
||||
componentRelativePath="StudyBrowser/StudyBrowser.jsx"
|
||||
/>
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
StudyBrowser is a component that renders the StudyBrowsers.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
tabs: [
|
||||
{
|
||||
name: 'primary',
|
||||
label: 'Primary',
|
||||
studies: [],
|
||||
},
|
||||
{
|
||||
name: 'recent',
|
||||
label: 'Recent',
|
||||
studies: [],
|
||||
},
|
||||
{
|
||||
name: 'all',
|
||||
label: 'All',
|
||||
studies: [],
|
||||
},
|
||||
],
|
||||
expandedStudyInstanceUIDs: ['1.3.6.1.4'],
|
||||
activeTabName: 'primary',
|
||||
}}
|
||||
>
|
||||
{StudyBrowserTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={StudyBrowser} />
|
||||
|
||||
## Usage
|
||||
|
||||
With Studies
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="With Studies"
|
||||
args={{
|
||||
tabs: [
|
||||
{
|
||||
name: 'primary',
|
||||
label: 'Primary',
|
||||
studies: [
|
||||
{
|
||||
studyInstanceUid:
|
||||
'1.3.6.1.4.1.25403.345050719074.3824.20170126085406.1',
|
||||
date: '26-Oct-2015',
|
||||
description: 'CT CHEST W CONTRAST',
|
||||
modalities: 'CT',
|
||||
numInstances: 1,
|
||||
displaySets: [
|
||||
{
|
||||
displaySetInstanceUID: '0b66675a-a4e3-a718-21f4-035d2d178d62',
|
||||
description: 'Topogram 0.6',
|
||||
seriesNumber: '1',
|
||||
modality: 'CT',
|
||||
seriesDate: '26-Oct-2015',
|
||||
numInstances: 1,
|
||||
StudyInstanceUID:
|
||||
'1.3.6.1.4.1.25403.345050719074.3824.20170126085406.1',
|
||||
componentType: 'thumbnailTracked',
|
||||
dragData: {
|
||||
type: 'displayset',
|
||||
displaySetInstanceUID:
|
||||
'0b66675a-a4e3-a718-21f4-035d2d178d62',
|
||||
},
|
||||
isTracked: false,
|
||||
viewportIdentificator: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'recent',
|
||||
label: 'Recent',
|
||||
studies: [],
|
||||
},
|
||||
{
|
||||
name: 'all',
|
||||
label: 'All',
|
||||
studies: [],
|
||||
},
|
||||
],
|
||||
expandedStudyInstanceUIDs: ['1.3.6.1.4'],
|
||||
activeTabName: 'primary',
|
||||
}}
|
||||
>
|
||||
{StudyBrowserTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="StudyBrowser/__stories__/studyBrowser.stories.mdx" />
|
||||
@ -0,0 +1,52 @@
|
||||
import StudyItem from '../StudyItem';
|
||||
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: StudyItem,
|
||||
title: 'Components/StudyItem',
|
||||
};
|
||||
|
||||
<Meta title="Components/StudyItem" component={StudyItem} />
|
||||
|
||||
export const StudyItemTemplate = (args) => (
|
||||
<div className="w-96">
|
||||
<StudyItem {...args} />
|
||||
</div>
|
||||
);
|
||||
|
||||
<Heading title="StudyItem" componentRelativePath="StudyItem/StudyItem.jsx" />
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
StudyItem is a component that renders the StudyItems.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
date: '16-Jan-1960',
|
||||
description: 'WB PET/CT',
|
||||
numInstances: 934,
|
||||
modalities: 'CTPT',
|
||||
isActive: false,
|
||||
}}
|
||||
>
|
||||
{StudyItemTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={StudyItem} />
|
||||
|
||||
## Usage
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="StudyItem/__stories__/studyItem.stories.mdx" />
|
||||
@ -0,0 +1,57 @@
|
||||
import StudyListExpandedRow from '../StudyListExpandedRow';
|
||||
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: StudyListExpandedRow,
|
||||
title: 'Components/StudyListExpandedRow',
|
||||
};
|
||||
|
||||
<Meta
|
||||
title="Components/StudyListExpandedRow"
|
||||
component={StudyListExpandedRow}
|
||||
/>
|
||||
|
||||
export const StudyListExpandedRowTemplate =
|
||||
createComponentTemplate(StudyListExpandedRow);
|
||||
|
||||
<Heading
|
||||
title="StudyListExpandedRow"
|
||||
componentRelativePath="StudyListExpandedRow/StudyListExpandedRow.js"
|
||||
/>
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
StudyListExpandedRow is a component that renders the StudyListExpandedRows.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
seriesTableColumns: {
|
||||
description: 'Description',
|
||||
seriesNumber: 'Series',
|
||||
modality: 'Modality',
|
||||
instances: 'Instances',
|
||||
},
|
||||
seriesTableDataSource: [],
|
||||
}}
|
||||
>
|
||||
{StudyListExpandedRowTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={StudyListExpandedRow} />
|
||||
|
||||
## Usage
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="StudyListExpandedRow/__stories__/studyListExpandedRow.stories.mdx" />
|
||||
@ -0,0 +1,66 @@
|
||||
import ToolbarButton from '../ToolbarButton';
|
||||
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: ToolbarButton,
|
||||
title: 'Components/ToolbarButton',
|
||||
};
|
||||
|
||||
<Meta title="Components/ToolbarButton" component={ToolbarButton} />
|
||||
|
||||
export const ToolbarButtonTemplate = (args) => (
|
||||
<div className="bg-primary-dark h-16">
|
||||
<div class="w-8">
|
||||
<ToolbarButton {...args} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
<Heading
|
||||
title="ToolbarButton"
|
||||
componentRelativePath="ToolbarButton/ToolbarButton.js"
|
||||
/>
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
ToolbarButton is a component that renders the ToolbarButtons.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
type: 'tool',
|
||||
id: 'Zoom',
|
||||
icon: 'tool-zoom',
|
||||
label: 'Zoom',
|
||||
commandOptions: {
|
||||
toolName: 'Zoom',
|
||||
},
|
||||
dropdownContent: null,
|
||||
isActive: false,
|
||||
bState: {
|
||||
primaryToolId: 'Wwwc',
|
||||
toggles: {},
|
||||
groups: {
|
||||
primary: 'Wwwc',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{ToolbarButtonTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={ToolbarButton} />
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="ToolbarButton/__stories__/toolbarButton.stories.mdx" />
|
||||
@ -0,0 +1,79 @@
|
||||
import Tooltip from '../Tooltip';
|
||||
import Icon from '../../Icon';
|
||||
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: Tooltip,
|
||||
title: 'Components/Tooltip',
|
||||
};
|
||||
|
||||
<Meta title="Components/Tooltip" component={Tooltip} />
|
||||
|
||||
export const TooltipTemplate = (args) => (
|
||||
<div className="h-16 w-full">
|
||||
<div class="w-8 h-8 mx-auto">
|
||||
<Tooltip {...args}>
|
||||
<Icon name="clipboard" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
<Heading title="Tooltip" componentRelativePath="Tooltip/Tooltip.js" />
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Usage](#usage)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
Tooltip is a component that renders the Tooltips.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
content: 'Tooltip',
|
||||
}}
|
||||
>
|
||||
{TooltipTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={Tooltip} />
|
||||
|
||||
## Usage
|
||||
|
||||
### Position
|
||||
|
||||
You can set the position of the tooltip by using the `position` prop.
|
||||
|
||||
<Canvas>
|
||||
<Story name="Position">
|
||||
<div className="h-16 w-full m-8">
|
||||
<div class="w-8 h-8 mx-auto">
|
||||
<Tooltip position="right" content="right">
|
||||
<Icon name="clipboard" />
|
||||
<span>Right</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-16 w-full m-8">
|
||||
<div class="w-8 h-8 mx-auto">
|
||||
<Tooltip position="left" content="left">
|
||||
<Icon name="clipboard" />
|
||||
<span>Left</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="Tooltip/__stories__/tooltip.stories.mdx" />
|
||||
@ -0,0 +1,152 @@
|
||||
import Typography from '../Typography';
|
||||
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
import { createComponentTemplate } from '../../../storybook/functions/create-component-story';
|
||||
|
||||
export const argTypes = {
|
||||
component: Typography,
|
||||
title: 'Foundations/Typography',
|
||||
};
|
||||
|
||||
<Meta title="Foundations/Typography" component={Typography} />
|
||||
|
||||
<Heading title="Typography" componentRelativePath="Typography/Typography.js" />
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Usage](#usage)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
Typography is a component that renders the Typographys.
|
||||
|
||||
<Canvas>
|
||||
<Story name="Overview">
|
||||
<Typography variant="h1" className="text-blue-800">
|
||||
Heading 1
|
||||
</Typography>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
### Usage
|
||||
|
||||
#### Variants
|
||||
|
||||
There are several variants of the Typography component.
|
||||
|
||||
<Canvas>
|
||||
<Story name="Variants">
|
||||
<Typography variant="h1" className="text-blue-800">
|
||||
Heading 1
|
||||
</Typography>
|
||||
<Typography variant="h2" className="text-blue-800">
|
||||
Heading 2
|
||||
</Typography>
|
||||
<Typography variant="h3" className="text-blue-800">
|
||||
Heading 3
|
||||
</Typography>
|
||||
<Typography variant="h4" className="text-blue-800">
|
||||
Heading 4
|
||||
</Typography>
|
||||
<Typography variant="h5" className="text-blue-800">
|
||||
Heading 5
|
||||
</Typography>
|
||||
<Typography variant="h6" className="text-blue-800">
|
||||
Heading 6
|
||||
</Typography>
|
||||
<Typography variant="p" className="text-blue-800">
|
||||
Paragraph
|
||||
</Typography>
|
||||
<Typography variant="subtitle" className="text-blue-800">
|
||||
Subtitle
|
||||
</Typography>
|
||||
<Typography variant="caption" className="text-blue-800">
|
||||
Caption
|
||||
</Typography>
|
||||
<Typography variant="body" className="text-blue-800">
|
||||
Body
|
||||
</Typography>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
#### Text Color
|
||||
|
||||
You can use the `color` prop to change the color of the text.
|
||||
|
||||
<Canvas>
|
||||
<Story name="Text Color">
|
||||
<Typography variant="h5" color="primary">
|
||||
Primary Color
|
||||
</Typography>
|
||||
<Typography variant="h5" color="secondary">
|
||||
Secondary Color
|
||||
</Typography>
|
||||
<Typography variant="h5" color="error">
|
||||
Error Color
|
||||
</Typography>
|
||||
<Typography variant="h5" color="inherit">
|
||||
Inherit Color
|
||||
</Typography>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
#### Custom className
|
||||
|
||||
You can use the `className` prop to add a custom className to the Typography.
|
||||
|
||||
<Canvas>
|
||||
<Story name="Custom Class">
|
||||
<Typography variant="h5" className="text-red-400">
|
||||
Custom Red Color
|
||||
</Typography>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
#### Align
|
||||
|
||||
<Canvas>
|
||||
<Story name="Align">
|
||||
<Typography variant="body" align="left" color="primary">
|
||||
Align Left: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
|
||||
tincidunt tempus ante, non blandit sem vehicula ac. Vestibulum in dolor
|
||||
commodo, elementum massa scelerisque, molestie nulla. Aenean sed odio
|
||||
interdum, rutrum ex at, volutpat diam. Donec vel tristique sem, eget
|
||||
iaculis velit. Aenean placerat justo
|
||||
</Typography>
|
||||
<br />
|
||||
<Typography variant="body" align="center" color="primary">
|
||||
Align Center: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
|
||||
tincidunt tempus ante, non blandit sem vehicula ac. Vestibulum in dolor
|
||||
commodo, elementum massa scelerisque, molestie nulla. Aenean sed odio
|
||||
interdum, rutrum ex at, volutpat diam. Donec vel tristique sem, eget
|
||||
iaculis velit. Aenean placerat justo
|
||||
</Typography>
|
||||
<br />
|
||||
<Typography variant="body" align="right" color="primary">
|
||||
Align Right: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
|
||||
tincidunt tempus ante, non blandit sem vehicula ac. Vestibulum in dolor
|
||||
commodo, elementum massa scelerisque, molestie nulla. Aenean sed odio
|
||||
interdum, rutrum ex at, volutpat diam. Donec vel tristique sem, eget
|
||||
iaculis velit. Aenean placerat justo
|
||||
</Typography>
|
||||
<br />
|
||||
<Typography variant="body" align="justify" color="primary">
|
||||
Align Justify: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Sed tincidunt tempus ante, non blandit sem vehicula ac. Vestibulum in
|
||||
dolor commodo, elementum massa scelerisque, molestie nulla. Aenean sed
|
||||
odio interdum, rutrum ex at, volutpat diam. Donec vel tristique sem, eget
|
||||
iaculis velit. Aenean placerat justo
|
||||
</Typography>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={Typography} />
|
||||
|
||||
## Usage
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="Typography/__stories__/typography.stories.mdx" />
|
||||
@ -0,0 +1,67 @@
|
||||
import Viewport from "../Viewport";
|
||||
|
||||
import { ArgsTable, Story, Canvas, Meta } from "@storybook/addon-docs";
|
||||
import { createComponentTemplate } from "../../../storybook/functions/create-component-story";
|
||||
|
||||
export const argTypes = {
|
||||
component: Viewport,
|
||||
title: "Components/Viewport",
|
||||
};
|
||||
|
||||
<Meta title="Components/Viewport" component={Viewport} />
|
||||
|
||||
export const ViewportTemplate = (args) => (
|
||||
<div className="h-40 bg-primary-dark">
|
||||
<Viewport {...args} />
|
||||
</div>
|
||||
);
|
||||
|
||||
<Heading title="Viewport" componentRelativePath="Viewport/Viewport.jsx" />
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
Viewport is a component that renders the Viewport action bar.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
viewportIndex: 0,
|
||||
onSeriesChange: (direction) => alert(`Annotation ${direction}`),
|
||||
studyData: {
|
||||
label: "A",
|
||||
isTracked: true,
|
||||
isLocked: false,
|
||||
isRehydratable: false,
|
||||
studyDate: "07-Sep-2011",
|
||||
currentSeries: 1,
|
||||
seriesDescription:
|
||||
"Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit ",
|
||||
modality: "CT",
|
||||
patientInformation: {
|
||||
patientName: "Smith, Jane",
|
||||
patientSex: "F",
|
||||
patientAge: "59",
|
||||
MRN: "10000001",
|
||||
thickness: "5.0mm",
|
||||
spacing: "1.25mm",
|
||||
scanner: "Aquilion",
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{ViewportTemplate.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={Viewport} />
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="Viewport/__stories__/Viewport.stories.mdx" />
|
||||
@ -239,11 +239,11 @@ const ViewportActionBar = ({
|
||||
};
|
||||
|
||||
const borderColor = useAltStyling ? '#365A6A' : '#1D205A';
|
||||
const backgroundColor = useAltStyling
|
||||
? '#031923'
|
||||
: isTracked
|
||||
? '#020424'
|
||||
: null;
|
||||
|
||||
let backgroundColor = '#020424';
|
||||
if (useAltStyling || isTracked) {
|
||||
backgroundColor = '#031923'
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
import React from 'react'
|
||||
import ViewportActionBar from './ViewportActionBar'
|
||||
|
||||
export default {
|
||||
component: ViewportActionBar,
|
||||
title: 'Components/ViewportActionBar',
|
||||
}
|
||||
|
||||
export const Default = () => (
|
||||
<div className="w-1/2 p-4 h-64">
|
||||
<ViewportActionBar
|
||||
onSeriesChange={direction => alert(`Series ${direction}`)}
|
||||
studyData={{
|
||||
label: 'A',
|
||||
isTracked: false,
|
||||
isLocked: false,
|
||||
isRehydratable: true,
|
||||
studyDate: '07-Sep-2010',
|
||||
currentSeries: 1,
|
||||
seriesDescription:
|
||||
'Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit Series description lorem ipsum dolor sit ',
|
||||
modality: 'CT',
|
||||
patientInformation: {
|
||||
patientName: 'Smith, Jane',
|
||||
patientSex: 'F',
|
||||
patientAge: '59',
|
||||
MRN: '10000001',
|
||||
thickness: '2.0mm',
|
||||
spacing: '1.25mm',
|
||||
scanner: 'Aquilion',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
BIN
platform/ui/src/storybook/assets/button.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
platform/ui/src/storybook/assets/code.png
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
platform/ui/src/storybook/assets/codeblock-error.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
platform/ui/src/storybook/assets/component-tree.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
platform/ui/src/storybook/assets/header.png
Normal file
|
After Width: | Height: | Size: 184 KiB |
BIN
platform/ui/src/storybook/assets/sandbox.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
platform/ui/src/storybook/assets/storybook.png
Normal file
|
After Width: | Height: | Size: 179 KiB |
6
platform/ui/src/storybook/color/color.jsx
Normal file
@ -0,0 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
// Create a square box with a given color
|
||||
export const Color = ({ color }) => {
|
||||
return <div className="w-8 h-8" style={{ backgroundColor: color }} />;
|
||||
};
|
||||
117
platform/ui/src/storybook/colors.stories.mdx
Normal file
@ -0,0 +1,117 @@
|
||||
import { Meta } from '@storybook/addon-docs';
|
||||
import { Color } from './color/color';
|
||||
|
||||
<Meta title="Foundations/Color" />
|
||||
|
||||
## Overview
|
||||
|
||||
Below you can see the color palette of the application and the className to use
|
||||
for each color.
|
||||
|
||||
<br />
|
||||
|
||||
### Primary Colors
|
||||
|
||||
<div className="grid grid-cols-4 gap-4 h-auto w-full bg-gray-200 p-8">
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="bg-primary-dark w-16 h-16" />
|
||||
<span>primary-dark</span>
|
||||
</div>
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="bg-primary-light w-16 h-16" />
|
||||
<span>primary-light</span>
|
||||
</div>
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="bg-primary-main w-16 h-16" />
|
||||
<span>primary-main</span>
|
||||
</div>
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="bg-primary-active w-16 h-16" />
|
||||
<span>primary-active</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
#### Usage
|
||||
|
||||
Therefore you can use the className to style the color of a component (using
|
||||
`bg-${color-class}`) or text (using `text-${color-class}`).
|
||||
|
||||
```jsx
|
||||
<div className="bg-primary-main text-primary-light">OHIF UI Components</div>
|
||||
```
|
||||
|
||||
to render
|
||||
|
||||
<div className="bg-primary-main text-primary-light">OHIF UI Components</div>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
### Secondary Colors
|
||||
|
||||
<div className="grid grid-cols-4 gap-4 h-auto w-full bg-gray-200 p-8">
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="bg-secondary-dark w-16 h-16" />
|
||||
<span>secondary-dark</span>
|
||||
</div>
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="bg-secondary-light w-16 h-16" />
|
||||
<span>secondary-light</span>
|
||||
</div>
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="bg-secondary-main w-16 h-16" />
|
||||
<span>secondary-main</span>
|
||||
</div>
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="bg-secondary-active w-16 h-16" />
|
||||
<span>secondary-active</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
### Common Colors
|
||||
|
||||
<div className="grid grid-cols-4 gap-4 h-auto w-full bg-gray-200 p-8">
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="bg-common-bright w-16 h-16" />
|
||||
<span>common-bright</span>
|
||||
</div>
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="bg-common-light w-16 h-16" />
|
||||
<span>common-light</span>
|
||||
</div>
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="bg-common-main w-16 h-16" />
|
||||
<span>common-main</span>
|
||||
</div>
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="bg-common-dark w-16 h-16" />
|
||||
<span>common-dark</span>
|
||||
</div>
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="bg-common-active w-16 h-16" />
|
||||
<span>common-active</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
### Custom Colors
|
||||
|
||||
<div className="grid grid-cols-4 gap-4 h-auto w-full bg-gray-200 p-8">
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="bg-customgreen-100 w-16 h-16" />
|
||||
<span>customgreen-100</span>
|
||||
</div>
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="bg-customblue-100 w-16 h-16" />
|
||||
<span>customblue-100</span>
|
||||
</div>
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="bg-customblue-200 w-16 h-16" />
|
||||
<span>customblue-200</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,3 @@
|
||||
export const AnchorListItem = ({ children }) => {
|
||||
return <li className="text-gray-800">{children}</li>;
|
||||
};
|
||||
19
platform/ui/src/storybook/components/footer/footer.jsx
Normal file
@ -0,0 +1,19 @@
|
||||
import React from 'react';
|
||||
|
||||
export const Footer = ({ componentRelativePath }) => {
|
||||
return (
|
||||
<div>
|
||||
<p className="my-2 text-gray-800 font-inter">
|
||||
We always welcome feedback and suggestions. If you are interested to add
|
||||
additional usecases, please send us a pull request. Edit this page on{' '}
|
||||
<a
|
||||
className="text-blue-400"
|
||||
href={`https://github.com/OHIF/Viewers/edit/v3-stable/platform/ui/src/components/${componentRelativePath}`}
|
||||
>
|
||||
Github
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
46
platform/ui/src/storybook/components/heading/heading.jsx
Normal file
@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
|
||||
function GitHubLogo() {
|
||||
return (
|
||||
<svg
|
||||
className="inline"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 1024 1024"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z"
|
||||
transform="scale(64)"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export const Heading = ({ title, componentRelativePath }) => {
|
||||
return (
|
||||
<div className="flex items-center w-full">
|
||||
<div>
|
||||
<h1 className="text-4xl font-normal text-blue-600 font-inter">
|
||||
{title}
|
||||
</h1>
|
||||
</div>
|
||||
{componentRelativePath && (
|
||||
<div className="ml-4">
|
||||
<a
|
||||
href={`https://github.com/OHIF/Viewers/blob/v3-stable/platform/ui/src/components/${componentRelativePath}`}
|
||||
className="text-sm font-normal text-blue-600"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<GitHubLogo />
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
17
platform/ui/src/storybook/components/image/image.jsx
Normal file
@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
|
||||
// centers the image in the container in the page
|
||||
export const WithImage = ({ children, image, alt, className }) => (
|
||||
<div className={className}>
|
||||
<img
|
||||
src={image}
|
||||
alt={alt}
|
||||
style={{
|
||||
display: 'block',
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
}}
|
||||
/>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
17
platform/ui/src/storybook/components/index.jsx
Normal file
@ -0,0 +1,17 @@
|
||||
// https://github.com/mondaycom/monday-ui-react-core/tree/master/src/storybook
|
||||
//
|
||||
import { Heading } from './heading/heading';
|
||||
import { AnchorListItem } from './anchor-list-item/anchor-list-item';
|
||||
import { LinkComponent } from './link-component/link-component';
|
||||
import { SectionName } from './section-name/section-name';
|
||||
import { Footer } from './footer/footer';
|
||||
import { WithImage } from './image/image';
|
||||
|
||||
export {
|
||||
Heading,
|
||||
AnchorListItem,
|
||||
LinkComponent,
|
||||
SectionName,
|
||||
Footer,
|
||||
WithImage,
|
||||
};
|
||||
@ -0,0 +1,32 @@
|
||||
import React from 'react';
|
||||
|
||||
export const LinkComponent = ({
|
||||
children,
|
||||
href,
|
||||
target: originalTarget,
|
||||
rel,
|
||||
}) => {
|
||||
const onClick = (event) => {
|
||||
if (originalTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
const target = document.querySelector(href);
|
||||
if (target) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
target.scrollIntoView();
|
||||
}
|
||||
};
|
||||
return (
|
||||
<a
|
||||
className="text-blue-600"
|
||||
onClick={onClick}
|
||||
target={originalTarget}
|
||||
rel={rel}
|
||||
href={href}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,23 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const SectionName = ({ className, children, ...props }) => {
|
||||
const id = useMemo(
|
||||
() =>
|
||||
children
|
||||
.toLowerCase()
|
||||
.split(' ')
|
||||
.join('-'),
|
||||
[children]
|
||||
);
|
||||
// eslint-disable-next-line jsx-a11y/heading-has-content
|
||||
return (
|
||||
<h2 id={id} {...props} className="mt-4 text-3xl text-blue-600">
|
||||
{children}
|
||||
</h2>
|
||||
);
|
||||
};
|
||||
|
||||
SectionName.propTypes = {
|
||||
children: PropTypes.string.isRequired,
|
||||
};
|
||||
110
platform/ui/src/storybook/contribute.stories.mdx
Normal file
@ -0,0 +1,110 @@
|
||||
import { Meta } from '@storybook/addon-docs';
|
||||
import { WithImage } from './components';
|
||||
import { WelcomeHeader } from './header/header';
|
||||
|
||||
import StoryBook from './assets/storybook.png';
|
||||
import CodeBlock from './assets/codeblock-error.png';
|
||||
|
||||
<Meta title="Contribute" />
|
||||
|
||||
## How to Contribute to the Docs
|
||||
|
||||
We are always looking for new contributors. If you are interested in
|
||||
contributing to the docs, please follow below instructions to run the storyBook
|
||||
locally and submit your new stories.
|
||||
|
||||
<br />
|
||||
|
||||
### Install OHIF Packages
|
||||
|
||||
Install OHIF Packages using `yarn install` command.
|
||||
|
||||
<br />
|
||||
|
||||
### Change Directory to OHIF UI
|
||||
|
||||
Change directory to OHIF UI using `cd platform/ui` command.
|
||||
|
||||
<br />
|
||||
|
||||
### Run Storybook
|
||||
|
||||
You can now run the storybook using `yarn storybook` command. This will open the
|
||||
storybook in your browser. You should be able to interact with Storybook and the
|
||||
already existing stories.
|
||||
|
||||
<WithImage image={StoryBook} alt={'storybook'} />
|
||||
|
||||
<br />
|
||||
|
||||
### Writing a Story
|
||||
|
||||
Stories for each UI component are stored in the `__stories__` folder. Stories
|
||||
are written in the `mdx` file format. You can read more about `mdx` file format
|
||||
[here](https://storybook.js.org/docs/react/api/mdx). In summary, the `mdx` file
|
||||
format is a way to write stories in a plain text format, but with the ability to
|
||||
use React components.
|
||||
|
||||
For Components that don't have a `mdx` file, you need to create a `mdx` file,
|
||||
Storybook automatically fetch the `mdx` file and render the story. You can use
|
||||
one of the already existing `mdx` files for the component (e.g.
|
||||
`button.stories.mdx`). If there is already a `mdx` file for the component, you
|
||||
can add you usage in the `usage` section of the `mdx` file. (again you can see
|
||||
`button.stories.mdx` for an example).
|
||||
|
||||
## Potential Issues
|
||||
|
||||
There are some potential issues that you might encounter when writing a story
|
||||
for a component. Please read the following sections carefully.
|
||||
|
||||
### Wrong Code Block Formatting
|
||||
|
||||
`mdx` is sensitive to whitespaces, so if you have a code block that has spaces
|
||||
in between the code block, it will not render correctly, and you will get an
|
||||
error. Always check the code block when you get an error.
|
||||
|
||||
For instance the following code block will generate the error (notice the extra
|
||||
vertical space in the code block):
|
||||
|
||||
```jsx
|
||||
export const TooltipTemplate = (args) => (
|
||||
<div className="h-16 w-full">
|
||||
<div class="w-8 h-8 mx-auto">
|
||||
<Tooltip {...args}>
|
||||
<Icon name="clipboard" />
|
||||
</Tooltip>
|
||||
// Imagine a whitespace here, we cannot show the extra vertical space, since
|
||||
mdx will generate error
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
```
|
||||
|
||||
<WithImage image={CodeBlock} alt={'codeblock'} />
|
||||
|
||||
<br />
|
||||
|
||||
### Stories with the same name
|
||||
|
||||
You should not have multiple stories with the same name. If you have multiple
|
||||
stories with the same name, it will cause an error.
|
||||
|
||||
The following code block will generate an error:
|
||||
|
||||
```jsx
|
||||
<Canvas>
|
||||
<Story name="Variants">
|
||||
<Typography variant="h1" color="initial">
|
||||
Heading 1
|
||||
</Typography>
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
<Canvas>
|
||||
<Story name="Variants">
|
||||
<Typography variant="h4" color="initial">
|
||||
Heading 4
|
||||
</Typography>
|
||||
</Story>
|
||||
</Canvas>
|
||||
```
|
||||
@ -0,0 +1,49 @@
|
||||
import React from 'react';
|
||||
|
||||
export function createComponentTemplate(ComponentClass) {
|
||||
return args => <ComponentClass {...args} />;
|
||||
}
|
||||
|
||||
// const allowedIcons = iconsMetaData.reduce(
|
||||
// (acc, icon) => {
|
||||
// const Component = AllIcons[icon.file.split(".")[0]];
|
||||
// acc.options.push(icon.name);
|
||||
// acc.mapping[icon.name] = Component;
|
||||
|
||||
// return acc;
|
||||
// },
|
||||
// { options: [], mapping: {} }
|
||||
// );
|
||||
|
||||
export function createStoryMetaSettings({
|
||||
component,
|
||||
enumPropNamesArray,
|
||||
iconPropNamesArray,
|
||||
}) {
|
||||
const argTypes = {};
|
||||
|
||||
// set enum allowed values inside argsTypes object
|
||||
enumPropNamesArray?.forEach(propName => {
|
||||
const enums = component[`${propName}s`];
|
||||
if (enums && enums instanceof Object) {
|
||||
argTypes[propName] = {
|
||||
options: Object.values(enums),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
if (component === Avatar) console.log(argTypes);
|
||||
|
||||
// set icon allowed values inside argsTypes object
|
||||
iconPropNamesArray?.forEach(propName => {
|
||||
argTypes[propName] = {
|
||||
options: allowedIcons.options,
|
||||
mapping: allowedIcons.mapping,
|
||||
control: {
|
||||
type: 'select',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return argTypes;
|
||||
}
|
||||
8
platform/ui/src/storybook/header/header.jsx
Normal file
@ -0,0 +1,8 @@
|
||||
import React from 'react';
|
||||
import Header from '../assets/header.png';
|
||||
|
||||
export const WelcomeHeader = () => (
|
||||
<div className="mb-8">
|
||||
<img src={Header} alt="OHIF-v3 User Interface Library" />
|
||||
</div>
|
||||
);
|
||||
62
platform/ui/src/storybook/welcome.stories.mdx
Normal file
@ -0,0 +1,62 @@
|
||||
import { Meta } from '@storybook/addon-docs';
|
||||
import { WithImage } from './components';
|
||||
import { WelcomeHeader } from './header/header';
|
||||
|
||||
import ComponentTree from './assets/component-tree.png';
|
||||
import Button from './assets/button.png';
|
||||
import Sandbox from './assets/sandbox.png';
|
||||
import Code from './assets/code.png';
|
||||
|
||||
<Meta title="Welcome" />
|
||||
|
||||
<WelcomeHeader />
|
||||
|
||||
## Introduction
|
||||
|
||||
OHIF-v3 UI component library is a collection of components and utilities that
|
||||
power OHIF's zero-footprint DICOM viewer ([demo](https://v3-demo.ohif.org/)). We maintain them as a separate
|
||||
component library to:
|
||||
|
||||
- Decouple presentation from business logic
|
||||
- Test and develop components isolation
|
||||
- Provide well documented, reusable components
|
||||
- Aid rapid application development for context specific viewers
|
||||
|
||||
<br />
|
||||
|
||||
## Storybook Introduction
|
||||
|
||||
We use [Storybook](https://storybook.js.org/) to document and showcase our
|
||||
components. On the left side of the screen, you'll see the component tree
|
||||
categorized into different sections.
|
||||
|
||||
<WithImage image={ComponentTree} alt="Component tree" className="my-8" />
|
||||
|
||||
### Getting Started
|
||||
|
||||
Each component folder contains examples of the component variants, its state and
|
||||
a playground to test it. Note: we are actively working on the component variants
|
||||
and their state and we are adding more examples as we go. Feel free to open a
|
||||
pull request to add more examples.
|
||||
|
||||
<WithImage
|
||||
image={Button}
|
||||
alt="Button Component"
|
||||
className="my-8 w-40 block mx-auto"
|
||||
/>
|
||||
|
||||
### Sandbox
|
||||
|
||||
The Sandbox (Playground) section of each story is a live preview of the
|
||||
component. You can test it by clicking on the component name in the component
|
||||
tree. This section allows you to interact with the component and change its
|
||||
properties.
|
||||
|
||||
<WithImage image={Sandbox} alt="Sandbox" className="my-8" />
|
||||
|
||||
### Code
|
||||
|
||||
Finally we have the code section. This section contains the source code of the
|
||||
illustrated component. You can copy and paste the code to your own project.
|
||||
|
||||
<WithImage image={Code} alt="Code" className="my-8" />
|
||||
@ -5,6 +5,8 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
|
||||
|
||||
/* Truncate 2 lines utility */
|
||||
.truncate-2-lines {
|
||||
overflow: hidden;
|
||||
@ -14,3 +16,4 @@
|
||||
line-height: 1.3;
|
||||
height: 2.1rem;
|
||||
}
|
||||
|
||||
|
||||
BIN
platform/ui/static/favicon.png
Normal file
|
After Width: | Height: | Size: 443 B |
15
platform/ui/static/ohif-logo-light.svg
Normal file
|
After Width: | Height: | Size: 16 KiB |
15
platform/ui/static/ohif-logo.svg
Normal file
|
After Width: | Height: | Size: 16 KiB |
@ -3,7 +3,7 @@ module.exports = {
|
||||
important: false,
|
||||
separator: ':',
|
||||
purge: {
|
||||
content: ['./src/**/*.{jsx,js,css}'],
|
||||
content: ['./src/**/*.{jsx,js,ts,tsx,css,mdx}'],
|
||||
safelist: [],
|
||||
},
|
||||
theme: {
|
||||
@ -13,6 +13,9 @@ module.exports = {
|
||||
lg: '1024px',
|
||||
xl: '1280px',
|
||||
},
|
||||
fontFamily: {
|
||||
inter: ['Inter', 'sans-serif'],
|
||||
},
|
||||
colors: {
|
||||
overlay: 'rgba(0, 0, 0, 0.8)',
|
||||
transparent: 'transparent',
|
||||
|
||||
@ -48,7 +48,7 @@
|
||||
"cornerstone-core": "^2.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.7.6",
|
||||
"@babel/runtime": "7.16.3",
|
||||
"@ohif/core": "^2.5.1",
|
||||
"@ohif/extension-cornerstone": "^2.4.0",
|
||||
"@ohif/extension-measurement-tracking": "^0.0.1",
|
||||
|
||||