feat: Custom Menu Structure (#1605)

This commit is contained in:
Rodrigo Antinarelli 2020-04-03 20:08:34 -03:00 committed by James A. Petts
parent ba5e1497bf
commit f8bbee22b7
25 changed files with 202 additions and 75 deletions

View File

@ -1,4 +1,14 @@
export default { export default {
title: '@ohif/ui', title: '@ohif/ui',
menu: ['Getting Started', 'Readme', 'Components', 'Views'], menu: [
'Getting Started',
// COMPONENTS ARE DEFINED JUST TO CUSTOMIZE THEIR SORTING
'General',
'Form',
'Navigation',
// 'Feedback',
// 'Other',
'Data Display',
],
ignore: ['README.md'],
}; };

View File

@ -1,6 +1,6 @@
--- ---
name: Button name: Button
menu: Components menu: General
route: components/button route: components/button
--- ---
@ -180,20 +180,10 @@ import { Button } from '@ohif/ui';
</Button> </Button>
</div> </div>
<div className="mb-2"> <div className="mb-2">
<Button <Button variant="contained" rounded="none" color="white" className="m-1">
variant="contained"
rounded="none"
color="white"
className="m-1"
>
Non Rounded Non Rounded
</Button> </Button>
<Button <Button variant="contained" rounded="small" color="white" className="m-1">
variant="contained"
rounded="small"
color="white"
className="m-1"
>
Small Rounded Small Rounded
</Button> </Button>
<Button <Button
@ -204,20 +194,10 @@ import { Button } from '@ohif/ui';
> >
Medium Rounded Medium Rounded
</Button> </Button>
<Button <Button variant="contained" rounded="large" color="white" className="m-1">
variant="contained"
rounded="large"
color="white"
className="m-1"
>
Large Rounded Large Rounded
</Button> </Button>
<Button <Button variant="contained" rounded="full" color="white" className="m-1">
variant="contained"
rounded="full"
color="white"
className="m-1"
>
Full Rounded Full Rounded
</Button> </Button>
</div> </div>
@ -344,7 +324,7 @@ import { IconButton } from '@ohif/ui';
<IconButton className="m-2" variant="text"> <IconButton className="m-2" variant="text">
<Icon name="settings" /> <Icon name="settings" />
</IconButton> </IconButton>
<IconButton className="m-2" variant="outlined" > <IconButton className="m-2" variant="outlined">
<Icon name="settings" /> <Icon name="settings" />
</IconButton> </IconButton>
</div> </div>
@ -390,7 +370,7 @@ import { IconButton } from '@ohif/ui';
<IconButton className="m-2"> <IconButton className="m-2">
<Icon name="settings" /> <Icon name="settings" />
</IconButton> </IconButton>
<IconButton className="m-2" variant="outlined" > <IconButton className="m-2" variant="outlined">
<Icon name="settings" /> <Icon name="settings" />
</IconButton> </IconButton>
<IconButton className="m-2" variant="text"> <IconButton className="m-2" variant="text">
@ -433,7 +413,6 @@ import { IconButton } from '@ohif/ui';
</div> </div>
</Playground> </Playground>
## Properties ## Properties
<Props of={Button} /> <Props of={Button} />

View File

@ -1,6 +1,6 @@
--- ---
name: ButtonGroup name: ButtonGroup
menu: Components menu: General
route: components/buttonGroup route: components/buttonGroup
--- ---

View File

@ -1,6 +1,6 @@
--- ---
name: Date Range name: Date Range
menu: Components menu: Form
route: components/date-range route: components/date-range
--- ---

View File

@ -1,6 +1,6 @@
--- ---
name: Empty Studies name: Empty Studies
menu: Components menu: Data Display
route: components/empty-studies route: components/empty-studies
--- ---

View File

@ -1,6 +1,6 @@
--- ---
name: Icon name: Icon
menu: Components menu: General
route: components/icon route: components/icon
--- ---

View File

@ -1,6 +1,6 @@
--- ---
name: Input name: Input
menu: Components menu: Form
route: components/input route: components/input
--- ---

View File

@ -1,6 +1,6 @@
--- ---
name: InputDateRange name: InputDateRange
menu: Components menu: Form
route: components/InputDateRange route: components/InputDateRange
--- ---
@ -30,7 +30,7 @@ import { InputDateRange } from '@ohif/ui';
<InputDateRange <InputDateRange
label="Dates" label="Dates"
value={dates} value={dates}
onChange={dates => setDates(dates)} onChange={(dates) => setDates(dates)}
/> />
</div> </div>
</div> </div>

View File

@ -1,6 +1,6 @@
--- ---
name: InputGroup name: InputGroup
menu: Components menu: Form
route: components/InputGroup route: components/InputGroup
--- ---

View File

@ -1,6 +1,6 @@
--- ---
name: InputMultiSelect name: InputMultiSelect
menu: Components menu: Form
route: components/InputMultiSelect route: components/InputMultiSelect
--- ---
@ -33,7 +33,7 @@ import { InputMultiSelect } from '@ohif/ui';
{ value: 'SR', label: 'SR' }, { value: 'SR', label: 'SR' },
]} ]}
value={values} value={values}
onChange={values => { onChange={(values) => {
setValues(values); setValues(values);
}} }}
/> />

View File

@ -1,6 +1,6 @@
--- ---
name: InputText name: InputText
menu: Components menu: Form
route: components/InputText route: components/InputText
--- ---

View File

@ -1,6 +1,6 @@
--- ---
name: Label name: Label
menu: Components menu: Form
route: components/label route: components/label
--- ---

View File

@ -1,6 +1,6 @@
--- ---
name: NavBar name: NavBar
menu: Components menu: Navigation
route: components/navBar route: components/navBar
--- ---

View File

@ -1,6 +1,6 @@
--- ---
name: Select name: Select
menu: Components menu: Form
route: components/select route: components/select
--- ---

View File

@ -1,6 +1,6 @@
--- ---
name: Study List Pagination name: Study List Pagination
menu: Components menu: Navigation
route: components/studyListPagination route: components/studyListPagination
--- ---

View File

@ -1,6 +1,6 @@
--- ---
name: Study List Table name: Study List Table
menu: Components menu: Data Display
route: components/studyListTable route: components/studyListTable
--- ---

View File

@ -1,6 +1,6 @@
--- ---
name: Table name: Table
menu: Components menu: Data Display
route: components/table route: components/table
--- ---
@ -36,7 +36,7 @@ import { Table, TableBody, TableCell, TableHead, TableRow } from '@ohif/ui';
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{new Array(25).fill('').map(row => ( {new Array(25).fill('').map((row) => (
<TableRow> <TableRow>
<TableCell>Content 01</TableCell> <TableCell>Content 01</TableCell>
<TableCell>Content 02</TableCell> <TableCell>Content 02</TableCell>

View File

@ -1,6 +1,6 @@
--- ---
name: Typography name: Typography
menu: Components menu: General
route: components/typography route: components/typography
--- ---

View File

@ -15,12 +15,13 @@ export const Layout = ({ children }) => {
const nav = useRef(); const nav = useRef();
const handleSidebarToggle = () => { const handleSidebarToggle = () => {
setSidebarOpen(s => !s); setSidebarOpen((s) => !s);
}; };
return ( return (
<BaseLayout sx={{ '& > div': { flex: '1 1 auto' } }} data-testid="layout"> <BaseLayout sx={{ '& > div': { flex: '1 1 auto' } }} data-testid="layout">
<Main <Main
id="main-layout"
sx={styles.main} sx={styles.main}
className={classnames({ className={classnames({
'overflow-hidden h-screen lg:overflow-auto': sidebarOpen, 'overflow-hidden h-screen lg:overflow-auto': sidebarOpen,

View File

@ -0,0 +1,51 @@
/** @jsx jsx */
import { jsx } from 'theme-ui';
import React from 'react';
import { useCurrentDoc } from 'docz';
import * as styles from 'gatsby-theme-docz/src/components/NavGroup/styles';
import { NavLink } from 'gatsby-theme-docz/src/components/NavLink';
import { NavGroup as DoczNavGroup } from 'gatsby-theme-docz/src/components/NavGroup';
import { ChevronDown } from 'gatsby-theme-docz/src/components/Icons';
export const NavGroup = ({ item, sidebarRef }) => {
const currentDoc = useCurrentDoc();
const currentDocRef = React.useRef();
const { name, menu } = item;
const [subheadingsVisible, setShowsubheadings] = React.useState(
currentDoc.menu === name
);
const toggleSubheadings = () => setShowsubheadings(!subheadingsVisible);
React.useEffect(() => {
if (sidebarRef.current && currentDocRef.current) {
sidebarRef.current.scrollTo(0, currentDocRef.current.offsetTop);
}
}, [sidebarRef]);
return (
<div sx={styles.wrapper} data-testid="nav-group">
<div sx={styles.title} onClick={toggleSubheadings}>
{item.name}
<ChevronDown sx={styles.chevron({ active: subheadingsVisible })} />
</div>
<div sx={styles.sublinkWrapper} data-testid="nav-group-links">
{menu &&
subheadingsVisible &&
menu.map((menu) => {
if (currentDoc.route === menu.route) {
return (
<NavLink key={menu.id} item={menu} ref={currentDocRef}>
{menu.name}
</NavLink>
);
}
return (
<NavLink key={menu.id} item={menu}>
{menu.name}
</NavLink>
);
})}
</div>
</div>
);
};

View File

@ -15,7 +15,7 @@ export const Sidebar = React.forwardRef((props, ref) => {
const menus = useMenus({ query }); const menus = useMenus({ query });
const currentDoc = useCurrentDoc(); const currentDoc = useCurrentDoc();
const currentDocRef = useRef(); const currentDocRef = useRef();
const handleChange = ev => { const handleChange = (ev) => {
setQuery(ev.target.value); setQuery(ev.target.value);
}; };
useEffect(() => { useEffect(() => {
@ -24,6 +24,47 @@ export const Sidebar = React.forwardRef((props, ref) => {
} }
}, [ref]); }, [ref]);
const customMenus = {
Components: [],
System: [],
Examples: [],
};
const MENU_CATEGORIES = {
Components: [
'General',
'Form',
'Navigation',
'Feedback',
'Data Display',
'Other',
],
Examples: ['Views'],
System: ['Colors'],
};
const renderMenuCategories = () => {
return Object.keys(customMenus).map((menuName) => {
return (
<div key={menuName}>
<h2 className="pl-2 border-l-8 -ml-4 border-secondary-active">
{menuName}
</h2>
{customMenus[menuName].map((item) => item)}
</div>
);
});
};
const getMenuCategory = (menuName) => {
return Object.keys(MENU_CATEGORIES).find((category) => {
if (MENU_CATEGORIES[category].includes(menuName)) {
return category;
}
return null;
});
};
return ( return (
<> <>
{props.sidebarOpen && ( {props.sidebarOpen && (
@ -56,11 +97,26 @@ export const Sidebar = React.forwardRef((props, ref) => {
onChange={handleChange} onChange={handleChange}
/> />
{menus && {menus &&
menus.map(menu => { menus.map((menu) => {
if (!menu.route) const isGroup = !!menu.menu;
const Component = isGroup ? NavGroup : NavLink;
const menuCategory = getMenuCategory(menu.name) || null;
if (menuCategory) {
customMenus[menuCategory].push(
<Component key={menu.id} item={menu} sidebarRef={ref}>
{!isGroup && menu.name}
</Component>
);
return null;
}
if (!menu.route) {
return ( return (
<NavGroup key={menu.id} item={menu} sidebarRef={ref} /> <NavGroup key={menu.id} item={menu} sidebarRef={ref} />
); );
}
if (menu.route === currentDoc.route) { if (menu.route === currentDoc.route) {
return ( return (
<NavLink key={menu.id} item={menu} ref={currentDocRef}> <NavLink key={menu.id} item={menu} ref={currentDocRef}>
@ -74,6 +130,7 @@ export const Sidebar = React.forwardRef((props, ref) => {
</NavLink> </NavLink>
); );
})} })}
{renderMenuCategories()}
</div> </div>
</> </>
)} )}

View File

@ -4,6 +4,9 @@
[data-testid='live-preview'] { [data-testid='live-preview'] {
background: #000; background: #000;
}
#main-layout {
@apply font-sans; @apply font-sans;
} }

View File

@ -1,20 +0,0 @@
---
name: Getting Started
route: /
---
# Getting Started
Design systems enable teams to build better products faster by making design reusable—reusability makes scale possible. This is the heart and primary value of design systems. A design system is a collection of reusable components, guided by clear standards, that can be assembled together to build any number of applications.
Regardless of the technologies and tools behind them, a successful design system follows these guiding principles:
- **Its consistent**. The way components are built and managed follows a predictable pattern.
- **Its self-contained**. Your design system is treated as a standalone dependency.
- **Its reusable**. Youve built components so they can be reused in many contexts.
- **Its accessible**. Applications built with your design system are usable by as many people as possible, no matter how they access the web.
- **Its robust**. No matter the product or platform to which your design system is applied, it should perform with grace and minimal bugs.
## Consistency
Your first, most important task when starting out is to define the rules of your system, document them, and ensure that everyone follows them. When you have clearly documented code standards and best practices in place, designers and developers from across your organization can easily use and, more importantly, contribute to your design system.

View File

@ -0,0 +1,47 @@
---
name: Getting Started
route: /
---
import { Playground } from 'docz';
import { Button } from '@ohif/ui';
# Getting Started
`@ohif/ui` is a collection of components and utilities that power OHIF's
zero-footprint DICOM viewer.
It's maintained in a monorepo, in the
[OHIF's repository](https://github.com/OHIF/Viewers/).
## Installation
Install `@ohif/ui` from your terminal:
```bash
// with npm
npm i @ohif/ui --save-exact
// with yarn
yarn add @ohif/ui --exact
```
## Usage
```javascript
// Import and use components
import { Button } from '@ohif/ui';
```
<Playground className="p-8" style={{ padding: 8 }}>
<div className="p-8">
<Button onClick={() => alert('Hello!')}>Click here!</Button>
</div>
</Playground>
## Examples
In the **Examples** section you can check many examples on how to build your
application using `@ohif/ui` components.
...

View File

@ -1,6 +1,5 @@
--- ---
name: Colors name: Colors
menu: System
route: system/colors route: system/colors
--- ---
@ -9,9 +8,9 @@ import BackgroundColor from './BackgroundColor';
# Color System # Color System
**@ohif/ui** offers a color system with a handful of color utility classes. `@ohif/ui` offers a color system with a handful of color utility classes.
As **@ohif/ui** uses Tailwind as a base styling library, you will be able to use As `@ohif/ui` uses Tailwind as a base styling library, you will be able to use
all the default colors from Tailwind, besides our custom colors too. all the default colors from Tailwind, besides our custom colors too.
# How to use # How to use