//Look at https://github.com/mui-org/material-ui/blob/master/docs/src/pages/components/material-icons/SearchIcons.js import React from 'react'; import { makeStyles } from '@material-ui/core/styles'; import Paper from '@material-ui/core/Paper'; import clsx from 'clsx'; import PropTypes from 'prop-types'; import Grid from '@material-ui/core/Grid'; import Dialog from '@material-ui/core/Dialog'; import DialogActions from '@material-ui/core/DialogActions'; import DialogContent from '@material-ui/core/DialogContent'; import DialogTitle from '@material-ui/core/DialogTitle'; import Tooltip from '@material-ui/core/Tooltip'; import Button from '@material-ui/core/Button'; import * as icons from '@material-ui/icons'; import { Box, Typography } from '@material-ui/core'; import { PageTitle } from 'components'; function selectNode(node) { // Clear any current selection const selection = window.getSelection(); selection.removeAllRanges(); // Select code const range = document.createRange(); range.selectNodeContents(node); selection.addRange(range); } let Icons = props => { const { icons, classes, handleClickOpen } = props; const handleClick = event => { selectNode(event.currentTarget); }; return ( <div> {icons.map(icon => { return ( <span key={icon.key} className={clsx('markdown-body', classes.icon)}> <icon.Icon tabIndex={-1} onClick={handleClickOpen} title={icon.key} className={classes.iconSvg} /> <p onClick={handleClick}>{icon.key}</p> </span> ); })} </div> ); }; Icons.propTypes = { classes: PropTypes.object.isRequired, handleClickOpen: PropTypes.func.isRequired, icons: PropTypes.array.isRequired }; Icons = React.memo(Icons); const useDialogStyles = makeStyles(theme => ({ markdown: { background: 'rgb(39, 44, 52)', color: '#fff', padding: theme.spacing(3) }, import: { textAlign: 'right', padding: theme.spacing(0.5, 1) }, container: { marginBottom: theme.spacing(5) }, canvas: { fontSize: 210, marginTop: theme.spacing(2), color: theme.palette.primary.dark, backgroundSize: '30px 30px', backgroundColor: '#fff', backgroundPosition: '0 0, 0 15px, 15px -15px, -15px 0px', backgroundImage: 'linear-gradient(45deg, #f4f4f4 25%, transparent 25%), linear-gradient(-45deg, #f4f4f4 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #f4f4f4 75%), linear-gradient(-45deg, transparent 75%, #f4f4f4 75%)' }, fontSize: { margin: theme.spacing(2) }, context: { margin: theme.spacing(0.5), padding: theme.spacing(1, 2), borderRadius: theme.shape.borderRadius, boxSizing: 'content-box' }, contextPrimary: { color: theme.palette.primary.main }, contextPrimaryInverse: { color: theme.palette.primary.contrastText, backgroundColor: theme.palette.primary.main }, contextTextPrimary: { color: theme.palette.text.primary }, contextTextPrimaryInverse: { color: theme.palette.background.paper, backgroundColor: theme.palette.text.primary }, contextTextSecondary: { color: theme.palette.text.secondary }, contextTextSecondaryInverse: { color: theme.palette.background.paper, backgroundColor: theme.palette.text.secondary } })); let DialogDetails = props => { const classes = useDialogStyles(); const { open, selectedIcon, handleClose } = props; const handleClick = event => { selectNode(event.currentTarget); }; return ( <Dialog fullWidth maxWidth="sm" open={open} onClose={handleClose} aria-labelledby="icon-dialog-title" > {selectedIcon ? ( <React.Fragment> <DialogTitle id="icon-dialog-title" onClick={handleClick}> {selectedIcon.key} </DialogTitle> <Box className={classes.markdown} onClick={handleClick}> <Typography color="inherit" variant="subtitle2"> {`import ${selectedIcon.key}Icon from '@material-ui/icons/${selectedIcon.key};`} </Typography> </Box> <DialogContent> <Grid container className={classes.container}> <Grid item xs={12} sm="auto"> <Grid container justify="center"> <selectedIcon.Icon className={classes.canvas} /> </Grid> </Grid> <Grid item xs> <Grid container alignItems="flex-end" justify="center"> <Grid item> <Tooltip title="fontSize small"> <selectedIcon.Icon className={classes.fontSize} fontSize="small" /> </Tooltip> </Grid> <Grid item> <Tooltip title="fontSize medium"> <selectedIcon.Icon className={classes.fontSize} /> </Tooltip> </Grid> <Grid item> <Tooltip title="fontSize large"> <selectedIcon.Icon className={classes.fontSize} fontSize="large" /> </Tooltip> </Grid> </Grid> <Grid container justify="center"> <selectedIcon.Icon className={clsx(classes.context, classes.contextPrimary)} /> <selectedIcon.Icon className={clsx(classes.context, classes.contextPrimaryInverse)} /> </Grid> <Grid container justify="center"> <selectedIcon.Icon className={clsx(classes.context, classes.contextTextPrimary)} /> <selectedIcon.Icon className={clsx(classes.context, classes.contextTextPrimaryInverse)} /> </Grid> <Grid container justify="center"> <selectedIcon.Icon className={clsx(classes.context, classes.contextTextSecondary)} /> <selectedIcon.Icon className={clsx(classes.context, classes.contextTextSecondaryInverse)} /> </Grid> </Grid> </Grid> </DialogContent> <DialogActions> <Button onClick={handleClose} color="primary"> Close </Button> </DialogActions> </React.Fragment> ) : ( <div /> )} </Dialog> ); }; DialogDetails.propTypes = { handleClose: PropTypes.func.isRequired, open: PropTypes.bool.isRequired, selectedIcon: PropTypes.object }; DialogDetails = React.memo(DialogDetails); const useStyles = makeStyles(theme => ({ root: { padding: theme.spacing(4) }, form: { margin: theme.spacing(2, 0) }, paper: { padding: theme.spacing(2, 4), margin: theme.spacing(4, 0) }, input: { marginLeft: 8, flex: 1 }, iconButton: { padding: 10 }, icon: { display: 'inline-block', width: 86, overflow: 'hidden', textOverflow: 'ellipsis', textAlign: 'center', color: theme.palette.text.secondary, margin: '0 4px', fontSize: 12, '& p': { margin: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, iconSvg: { boxSizing: 'content-box', cursor: 'pointer', color: theme.palette.text.primary, borderRadius: theme.shape.borderRadius, transition: theme.transitions.create(['background-color', 'box-shadow'], { duration: theme.transitions.duration.shortest }), fontSize: 40, padding: theme.spacing(2), margin: theme.spacing(0.5, 0), '&:hover': { backgroundColor: theme.palette.background.paper, boxShadow: theme.shadows[1] } }, results: { marginBottom: theme.spacing(1) }, showAll: { marginTop: theme.spacing(5) } })); const allIconsMap = {}; const allIcons = Object.keys(icons) .sort() .map(key => { const icon = { key, Icon: icons[key] }; allIconsMap[key] = icon; return icon; }); export default function SearchIcons() { const classes = useStyles(); const [open, setOpen] = React.useState(false); const [selectedIcon, setSelectedIcon] = React.useState(null); const [showMore, setShowMore] = React.useState(false); const handleClickOpen = React.useCallback(event => { setSelectedIcon(allIconsMap[event.currentTarget.getAttribute('title')]); setOpen(true); }, []); const handleClose = React.useCallback(() => { setOpen(false); }, []); const isMounted = React.useRef(false); React.useEffect(() => { isMounted.current = true; return () => { isMounted.current = false; }; }, []); const onShowMore = () => setShowMore(true); const filteredIcons = !showMore ? allIcons.slice(0, 100) : allIcons; return ( <div className={classes.root}> <PageTitle title="Icons" /> <Paper className={classes.paper} elevation={0}> <Icons icons={filteredIcons} classes={classes} handleClickOpen={handleClickOpen} /> {!showMore && ( <Box width={1} textAlign="center"> <Button className={classes.showAll} onClick={onShowMore} color="primary"> Show All Icons </Button> </Box> )} </Paper> <DialogDetails open={open} selectedIcon={selectedIcon} handleClose={handleClose} /> </div> ); }