UNPKG

vitessce

Version:

Vitessce app and React component library

160 lines (151 loc) 4.19 kB
import React, { useState } from 'react'; import { makeStyles } from '@material-ui/core/styles'; import CloudDownloadIcon from '@material-ui/icons/CloudDownload'; import MenuItem from '@material-ui/core/MenuItem'; import IconButton from '@material-ui/core/IconButton'; import Link from '@material-ui/core/Link'; import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown'; import ArrowDropUpIcon from '@material-ui/icons/ArrowDropUp'; import SettingsIcon from '@material-ui/icons/Settings'; import CloseIcon from '@material-ui/icons/Close'; import { SCROLL_CARD, BLACK_CARD, SECONDARY_CARD } from './classNames'; import LoadingIndicator from './LoadingIndicator'; import { PopperMenu } from './shared-mui/components'; const useStyles = makeStyles(theme => ({ iconButton: { border: 'none', marginLeft: 0, background: 'none', color: theme.palette.primaryForeground, paddingLeft: '0.25em', paddingRight: '0.25em', borderRadius: '2px', '&:hover': { backgroundColor: theme.palette.primaryBackgroundLight, }, '&:first-child': { marginLeft: '0.25em', }, '&:last-child': { marginRight: '0.25em', }, '& svg': { width: '0.7em', height: '0.7em', verticalAlign: 'middle', overflow: 'visible', }, }, downloadLink: { color: theme.palette.primaryForeground, }, })); function SettingsIconWithArrow({ open }) { return ( <> <SettingsIcon /> {open ? <ArrowDropUpIcon /> : <ArrowDropDownIcon />} </> ); } function PlotOptions(props) { const { options } = props; const [open, setOpen] = useState(false); const classes = useStyles(); return ( <PopperMenu open={open} setOpen={setOpen} buttonIcon={<SettingsIconWithArrow open={open} />} buttonClassName={classes.iconButton} placement="bottom-end" > {options} </PopperMenu> ); } function CloudDownloadIconWithArrow({ open }) { return ( <> <CloudDownloadIcon /> {open ? <ArrowDropUpIcon /> : <ArrowDropDownIcon />} </> ); } function DownloadOptions(props) { const { urls } = props; const [open, setOpen] = useState(false); const classes = useStyles(); return ( <PopperMenu open={open} setOpen={setOpen} buttonIcon={<CloudDownloadIconWithArrow open={open} />} buttonClassName={classes.iconButton} placement="bottom-end" > {urls.map(({ url, name }) => ( <MenuItem dense key={url}> <Link underline="none" href={url} target="_blank" rel="noopener" className={classes.downloadLink}> Download {name} </Link> </MenuItem> ))} </PopperMenu> ); } function ClosePaneButton(props) { const { removeGridComponent } = props; const classes = useStyles(); return ( <IconButton onClick={removeGridComponent} size="small" className={classes.iconButton} title="close" > <CloseIcon /> </IconButton> ); } export default function TitleInfo(props) { const { title, info, children, isScroll, isSpatial, removeGridComponent, urls, isReady, options, } = props; // eslint-disable-next-line no-nested-ternary const childClassName = isScroll ? SCROLL_CARD : (isSpatial ? BLACK_CARD : SECONDARY_CARD); return ( // d-flex without wrapping div is not always full height; I don't understand the root cause. <> <div className="title"> <div className="title-left"> {title} </div> <div className="title-info" title={info}> {info} </div> <div className="title-buttons"> { options && ( <PlotOptions options={options} /> ) } {urls && urls.length > 0 && ( <DownloadOptions urls={urls} /> )} <ClosePaneButton removeGridComponent={removeGridComponent} /> </div> </div> <div className={childClassName}> { !isReady && <LoadingIndicator /> } {children} </div> </> // "pl-2" only matters when the window is very narrow. ); }