feat: files page updated to latest design (#218)

* feat: altered the design of the tabs and redid the download tab

* feat: redesign the upload file

* fix: styles of tabs on hover

* fix: display troubleshoot component when the status of the node is not OK

* fix: when removing the file, remove the reference upload reference as well

* fix: on inputs the label should not be selectable

* feat: add placeholder to inputs and make the label non-selectable

* refactor: improved the readability of the upload file component

* chore: removed PeerDetail component

* fix: replaced "batch" with (postage) "stamp" for clarity

* refactor: address PR review comments

* feat: disable the download button if there is no value
This commit is contained in:
Vojtech Simetka
2021-10-08 13:34:55 +02:00
committed by GitHub
parent 03265687ad
commit 93af7f35a3
9 changed files with 237 additions and 224 deletions
+53 -11
View File
@@ -1,10 +1,11 @@
import { ReactElement, useState } from 'react' import { ReactElement, ChangeEvent, useState } from 'react'
import { makeStyles, Theme, createStyles } from '@material-ui/core/styles' import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
import Collapse from '@material-ui/core/Collapse' import Collapse from '@material-ui/core/Collapse'
import { ListItem, Typography, Grid, IconButton, InputBase, Button } from '@material-ui/core' import { ListItem, Typography, Grid, IconButton, InputBase, Button } from '@material-ui/core'
import { Edit, Minus, RotateCcw, Check } from 'react-feather' import { Edit, Minus, RotateCcw, Check } from 'react-feather'
import ExpandableListItemActions from './ExpandableListItemActions' import ExpandableListItemActions from './ExpandableListItemActions'
import ExpandableListItemNote from './ExpandableListItemNote'
const useStyles = makeStyles((theme: Theme) => const useStyles = makeStyles((theme: Theme) =>
createStyles({ createStyles({
@@ -33,30 +34,64 @@ const useStyles = makeStyles((theme: Theme) =>
keyMargin: { keyMargin: {
marginRight: theme.spacing(1), marginRight: theme.spacing(1),
}, },
unselectableLabel: {
cursor: 'default',
userSelect: 'none',
// Many browsers don't support yet the general user-select css property
WebkitUserSelect: 'none',
MozUserSelect: 'none',
msUserSelect: 'none',
},
}), }),
) )
interface Props { interface Props {
label: string label: string
value: string value?: string
placeholder?: string
helperText?: string
expandedOnly?: boolean
confirmLabel?: string
confirmLabelDisabled?: boolean
onChange?: (value: string) => void
onConfirm: (value: string) => void onConfirm: (value: string) => void
} }
export default function ExpandableListItemKey({ label, value, onConfirm }: Props): ReactElement | null { export default function ExpandableListItemKey({
label,
value,
onConfirm,
onChange,
confirmLabel,
confirmLabelDisabled,
expandedOnly,
helperText,
placeholder,
}: Props): ReactElement | null {
const classes = useStyles() const classes = useStyles()
const [open, setOpen] = useState(false) const [open, setOpen] = useState(Boolean(expandedOnly))
const [inputValue, setInputValue] = useState(value) const [inputValue, setInputValue] = useState<string>(value || '')
const toggleOpen = () => setOpen(!open) const toggleOpen = () => setOpen(!open)
const handleChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
setInputValue(e.target.value)
if (onChange) onChange(e.target.value)
}
return ( return (
<> <>
<ListItem className={`${classes.header} ${open ? classes.headerOpen : ''}`}> <ListItem className={`${classes.header} ${open ? classes.headerOpen : ''}`}>
<Grid container direction="column" justifyContent="space-between" alignItems="stretch"> <Grid container direction="column" justifyContent="space-between" alignItems="stretch">
<Grid container direction="row" justifyContent="space-between" alignItems="center"> <Grid container direction="row" justifyContent="space-between" alignItems="center">
{label && <Typography variant="body1">{label}</Typography>} {label && (
<Typography variant="body1" className={classes.unselectableLabel}>
{label}
</Typography>
)}
<Typography variant="body2"> <Typography variant="body2">
<div> <div>
{!open && value} {!open && value}
{!expandedOnly && (
<IconButton size="small" className={classes.copyValue}> <IconButton size="small" className={classes.copyValue}>
{open ? ( {open ? (
<Minus onClick={toggleOpen} strokeWidth={1} /> <Minus onClick={toggleOpen} strokeWidth={1} />
@@ -64,13 +99,15 @@ export default function ExpandableListItemKey({ label, value, onConfirm }: Props
<Edit onClick={toggleOpen} strokeWidth={1} /> <Edit onClick={toggleOpen} strokeWidth={1} />
)} )}
</IconButton> </IconButton>
)}
</div> </div>
</Typography> </Typography>
</Grid> </Grid>
<Collapse in={open} timeout="auto" unmountOnExit> <Collapse in={open} timeout="auto" unmountOnExit>
<InputBase <InputBase
value={inputValue} value={inputValue}
onChange={e => setInputValue(e.target.value)} placeholder={placeholder}
onChange={handleChange}
fullWidth fullWidth
className={classes.content} className={classes.content}
autoFocus autoFocus
@@ -79,20 +116,25 @@ export default function ExpandableListItemKey({ label, value, onConfirm }: Props
</Grid> </Grid>
</ListItem> </ListItem>
<Collapse in={open} timeout="auto" unmountOnExit> <Collapse in={open} timeout="auto" unmountOnExit>
{helperText && <ExpandableListItemNote>{helperText}</ExpandableListItemNote>}
<ExpandableListItemActions> <ExpandableListItemActions>
<Button <Button
variant="contained" variant="contained"
disabled={inputValue === value} disabled={
inputValue === value ||
Boolean(confirmLabelDisabled) || // Disable if external validation is provided
(inputValue === '' && value === undefined) // Disable if no initial value was not provided and the field is empty. The undefined check is improtant so that it is possible to submit with empty input in other cases
}
startIcon={<Check size="1rem" />} startIcon={<Check size="1rem" />}
onClick={() => onConfirm(inputValue)} onClick={() => onConfirm(inputValue)}
> >
Save {confirmLabel || 'Save'}
</Button> </Button>
<Button <Button
variant="contained" variant="contained"
disabled={inputValue === value} disabled={inputValue === value || inputValue === ''}
startIcon={<RotateCcw size="1rem" />} startIcon={<RotateCcw size="1rem" />}
onClick={() => setInputValue(value)} onClick={() => setInputValue(value || '')}
> >
Cancel Cancel
</Button> </Button>
-24
View File
@@ -1,24 +0,0 @@
import type { ReactElement } from 'react'
import { Typography } from '@material-ui/core'
function truncStringPortion(str: string, firstCharCount = 10, endCharCount = 10) {
return `${str.substring(0, firstCharCount)}...${str.substring(str.length - endCharCount, str.length)}`
}
interface Props {
peerId: string
characterLength?: number
}
export default function PeerDetail({ peerId, characterLength }: Props): ReactElement {
return (
<Typography
variant="button"
style={{
fontFamily: 'monospace, monospace',
}}
>
{truncStringPortion(peerId, characterLength, characterLength)}
</Typography>
)
}
+14 -14
View File
@@ -1,9 +1,6 @@
import React, { ReactElement, ReactNode } from 'react' import React, { ReactElement, ReactNode } from 'react'
import { makeStyles } from '@material-ui/core/styles' import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
import Tabs from '@material-ui/core/Tabs' import { Tab, Tabs } from '@material-ui/core'
import Tab from '@material-ui/core/Tab'
import Typography from '@material-ui/core/Typography'
import Box from '@material-ui/core/Box'
interface TabPanelProps { interface TabPanelProps {
children?: ReactNode children?: ReactNode
@@ -16,24 +13,25 @@ function TabPanel(props: TabPanelProps) {
return ( return (
<div role="tabpanel" hidden={value !== index} {...other}> <div role="tabpanel" hidden={value !== index} {...other}>
{value === index && ( {value === index && children}
<Box p={3}>
<Typography>{children}</Typography>
</Box>
)}
</div> </div>
) )
} }
const useStyles = makeStyles(() => ({ const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: { root: {
flexGrow: 1, flexGrow: 1,
}, },
})) content: {
marginTop: theme.spacing(2),
},
}),
)
interface TabsValues { interface TabsValues {
component: ReactNode component: ReactNode
label: string label: ReactNode
} }
interface Props { interface Props {
@@ -55,16 +53,18 @@ export default function SimpleTabs({ values, index, indexChanged }: Props): Reac
return ( return (
<div className={classes.root}> <div className={classes.root}>
<Tabs value={v} onChange={handleChange}> <Tabs value={v} onChange={handleChange} variant="fullWidth">
{values.map(({ label }, idx) => ( {values.map(({ label }, idx) => (
<Tab key={idx} label={label} /> <Tab key={idx} label={label} />
))} ))}
</Tabs> </Tabs>
<div className={classes.content}>
{values.map(({ component }, idx) => ( {values.map(({ component }, idx) => (
<TabPanel key={idx} value={v} index={idx}> <TabPanel key={idx} value={v} index={idx}>
{component} {component}
</TabPanel> </TabPanel>
))} ))}
</div> </div>
</div>
) )
} }
+14 -52
View File
@@ -1,66 +1,28 @@
import { ReactElement, useState, useContext } from 'react' import { ReactElement, useState, useContext } from 'react'
import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
import { Paper, InputBase, IconButton, FormHelperText } from '@material-ui/core'
import { Search } from '@material-ui/icons'
import { Context as SettingsContext } from '../../providers/Settings' import { Context as SettingsContext } from '../../providers/Settings'
import ExpandableListItemInput from '../../components/ExpandableListItemInput'
import { Utils } from '@ethersphere/bee-js' import { Utils } from '@ethersphere/bee-js'
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
padding: theme.spacing(0.25),
display: 'flex',
alignItems: 'center',
},
input: {
marginLeft: theme.spacing(1),
flex: 1,
},
iconButton: {
padding: 10,
},
divider: {
height: 28,
margin: 4,
},
}),
)
export default function Files(): ReactElement { export default function Files(): ReactElement {
const classes = useStyles()
const { apiUrl } = useContext(SettingsContext) const { apiUrl } = useContext(SettingsContext)
const [referenceInput, setReferenceInput] = useState('') const [referenceError, setReferenceError] = useState<string | undefined>(undefined)
const [referenceError, setReferenceError] = useState<Error | null>(null)
const handleReferenceChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => { const validateChange = (value: string) => {
setReferenceInput(e.target.value) if (Utils.isHexString(value, 64) || Utils.isHexString(value, 128)) setReferenceError(undefined)
else setReferenceError('Incorrect format of swarm hash. Expected 64 or 128 hexstring characters.')
if (Utils.isHexString(e.target.value, 64) || Utils.isHexString(e.target.value, 128)) setReferenceError(null)
else setReferenceError(new Error('Incorrect format of swarm hash'))
} }
return ( return (
<> <ExpandableListItemInput
<Paper className={classes.root}> label="Swarm Hash"
<InputBase onConfirm={value => window.open(`${apiUrl}/bzz/${value}`, '_blank')}
className={classes.input} onChange={validateChange}
placeholder="Enter swarm reference e.g. 0773a91efd6547c754fc1d95fb1c62c7d1b47f959c2caa685dfec8736da95c1c" helperText={referenceError}
inputProps={{ 'aria-label': 'retrieve file from swarm' }} confirmLabel={'Download'}
value={referenceInput} confirmLabelDisabled={Boolean(referenceError)}
onChange={handleReferenceChange} placeholder="e.g. 31fb0362b1a42536134c86bc58b97ac0244e5c6630beec3e27c2d1cecb38c605"
expandedOnly
/> />
<IconButton
href={`${apiUrl}/bzz/${referenceInput}`}
target="_blank"
disabled={referenceError !== null || !referenceInput}
className={classes.iconButton}
aria-label="download"
>
<Search />
</IconButton>
</Paper>
{referenceError && <FormHelperText error>{referenceError.message}</FormHelperText>}
</>
) )
} }
+4 -8
View File
@@ -1,9 +1,5 @@
import Button from '@material-ui/core/Button'
import ListItemIcon from '@material-ui/core/ListItemIcon'
import Menu from '@material-ui/core/Menu'
import MenuItem from '@material-ui/core/MenuItem'
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import PeerDetailDrawer from '../../components/PeerDetail' import { Button, ListItemIcon, Typography, Menu, MenuItem } from '@material-ui/core'
import { EnrichedPostageBatch } from '../../providers/Stamps' import { EnrichedPostageBatch } from '../../providers/Stamps'
interface Props { interface Props {
@@ -25,10 +21,10 @@ export default function SimpleMenu({ stamps, selectedStamp, setSelected }: Props
return ( return (
<div> <div>
<Button aria-controls="simple-menu" aria-haspopup="true" onClick={handleClick}> <Button variant="contained" aria-haspopup="true" onClick={handleClick}>
Change Change
</Button> </Button>
<Menu id="simple-menu" anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose}> <Menu anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose}>
{stamps.map(stamp => ( {stamps.map(stamp => (
<MenuItem <MenuItem
key={stamp.batchID} key={stamp.batchID}
@@ -39,7 +35,7 @@ export default function SimpleMenu({ stamps, selectedStamp, setSelected }: Props
selected={stamp.batchID === selectedStamp?.batchID} selected={stamp.batchID === selectedStamp?.batchID}
> >
<ListItemIcon>{stamp.usageText}</ListItemIcon> <ListItemIcon>{stamp.usageText}</ListItemIcon>
<PeerDetailDrawer peerId={stamp.batchID} /> <Typography variant="body2">{stamp.batchID.substr(0, 8)}[]</Typography>
</MenuItem> </MenuItem>
))} ))}
</Menu> </Menu>
+84 -35
View File
@@ -1,20 +1,31 @@
import { Button, CircularProgress, Container } from '@material-ui/core' import { Button, CircularProgress, Container, Avatar, Chip, Typography } from '@material-ui/core'
import Avatar from '@material-ui/core/Avatar' import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
import Chip from '@material-ui/core/Chip'
import { DropzoneArea } from 'material-ui-dropzone' import { DropzoneArea } from 'material-ui-dropzone'
import { useSnackbar } from 'notistack' import { useSnackbar } from 'notistack'
import { RotateCcw, Check } from 'react-feather'
import { ReactElement, useContext, useEffect, useState } from 'react' import { ReactElement, useContext, useEffect, useState } from 'react'
import UploadSizeAlert from '../../components/AlertUploadSize' import UploadSizeAlert from '../../components/AlertUploadSize'
import ClipboardCopy from '../../components/ClipboardCopy' import ClipboardCopy from '../../components/ClipboardCopy'
import PeerDetailDrawer from '../../components/PeerDetail'
import { Context, EnrichedPostageBatch } from '../../providers/Stamps' import { Context, EnrichedPostageBatch } from '../../providers/Stamps'
import { Context as SettingsContext } from '../../providers/Settings' import { Context as SettingsContext } from '../../providers/Settings'
import CreatePostageStamp from '../stamps/CreatePostageStampModal' import CreatePostageStamp from '../stamps/CreatePostageStampModal'
import SelectStamp from './SelectStamp' import SelectStamp from './SelectStamp'
import ExpandableListItem from '../../components/ExpandableListItem'
import ExpandableListItemKey from '../../components/ExpandableListItemKey'
import ExpandableListItemNote from '../../components/ExpandableListItemNote'
import ExpandableListItemActions from '../../components/ExpandableListItemActions'
const useStyles = makeStyles((theme: Theme) =>
createStyles({
content: { marginTop: theme.spacing(2) },
loadingProgress: { textAlign: 'center', padding: '50px' },
}),
)
const MAX_FILE_SIZE = 1_000_000_000 // 1 gigabyte const MAX_FILE_SIZE = 1_000_000_000 // 1 gigabyte
export default function Files(): ReactElement { export default function Files(): ReactElement {
const classes = useStyles()
const [dropzoneKey, setDropzoneKey] = useState(0) const [dropzoneKey, setDropzoneKey] = useState(0)
const [file, setFile] = useState<File | null>(null) const [file, setFile] = useState<File | null>(null)
const [uploadReference, setUploadReference] = useState('') const [uploadReference, setUploadReference] = useState('')
@@ -22,10 +33,14 @@ export default function Files(): ReactElement {
const [selectedStamp, setSelectedStamp] = useState<EnrichedPostageBatch | null>(null) const [selectedStamp, setSelectedStamp] = useState<EnrichedPostageBatch | null>(null)
const { isLoading, error, stamps } = useContext(Context) const { isLoading, error, stamps, refresh } = useContext(Context)
const { beeApi } = useContext(SettingsContext) const { beeApi } = useContext(SettingsContext)
const { enqueueSnackbar } = useSnackbar() const { enqueueSnackbar } = useSnackbar()
useEffect(() => {
refresh()
}, [])
// Choose a postage stamp that has the lowest usage // Choose a postage stamp that has the lowest usage
useEffect(() => { useEffect(() => {
if (!selectedStamp && stamps && stamps.length > 0) { if (!selectedStamp && stamps && stamps.length > 0) {
@@ -47,68 +62,102 @@ export default function Files(): ReactElement {
setIsUploadingFile(true) setIsUploadingFile(true)
beeApi beeApi
.uploadFile(selectedStamp.batchID, file) .uploadFile(selectedStamp.batchID, file)
.then(hash => { .then(hash => setUploadReference(hash.reference))
window.setTimeout(() => {
setFile(null)
setUploadReference(hash.reference)
setDropzoneKey(dropzoneKey + 1)
}, 0)
})
.catch(e => enqueueSnackbar(`Error uploading: ${e.message}`, { variant: 'error' })) .catch(e => enqueueSnackbar(`Error uploading: ${e.message}`, { variant: 'error' }))
.finally(() => { .finally(() => setIsUploadingFile(false))
setIsUploadingFile(false) }
})
const uploadNew = () => {
setTimeout(() => {
setFile(null)
setDropzoneKey(dropzoneKey + 1)
setUploadReference('')
}, 0)
} }
const handleChange = (files?: File[]) => { const handleChange = (files?: File[]) => {
setUploadReference('')
if (files) { if (files) {
setFile(files[0]) setFile(files[0])
} }
} }
return ( return (
<div> <>
<div>
<DropzoneArea <DropzoneArea
key={'dropzone-' + dropzoneKey} key={'dropzone-' + dropzoneKey}
onChange={handleChange} onChange={handleChange}
filesLimit={1} filesLimit={1}
maxFileSize={MAX_FILE_SIZE} maxFileSize={MAX_FILE_SIZE}
/> />
<div style={{ marginTop: '15px' }}> <div className={classes.content}>
{/* We have file and can upload display stamp selection */}
{file && !isUploadingFile && !uploadReference && (
<>
<ExpandableListItemNote>
To upload this file to your node, you need a postage stamp. You can buy a new one or you can use an
existing stamp (providing its sufficient for this file).
</ExpandableListItemNote>
{selectedStamp && ( {selectedStamp && (
<div style={{ display: 'flex' }}> <ExpandableListItem
<small> label={
with Postage Stamp{' '} <>
Upload with Postage Stamp{' '}
<Chip <Chip
avatar={<Avatar>{selectedStamp.usageText}</Avatar>} avatar={<Avatar>{selectedStamp.usageText}</Avatar>}
label={<PeerDetailDrawer peerId={selectedStamp.batchID} characterLength={6} />} label={<Typography variant="body2">{selectedStamp.batchID.substr(0, 8)}[]</Typography>}
deleteIcon={<ClipboardCopy value={selectedStamp.batchID} />} deleteIcon={<ClipboardCopy value={selectedStamp.batchID} />}
onDelete={() => {} /* eslint-disable-line*/} onDelete={() => {} /* eslint-disable-line*/}
variant="outlined" variant="outlined"
/> />
</small> </>
<SelectStamp stamps={stamps} selectedStamp={selectedStamp} setSelected={setSelectedStamp} /> }
</div> value={<SelectStamp stamps={stamps} selectedStamp={selectedStamp} setSelected={setSelectedStamp} />}
/>
)} )}
{!selectedStamp && <CreatePostageStamp />} {!selectedStamp && (
<Button disabled={!file && isUploadingFile && !selectedStamp} onClick={() => uploadFile()}> <ExpandableListItemActions>
<CreatePostageStamp />
</ExpandableListItemActions>
)}
</>
)}
{/* We have file and can upload display upload button */}
{file && !uploadReference && (
<>
<ExpandableListItemActions>
<Button
variant="contained"
disabled={!file && isUploadingFile && !selectedStamp}
onClick={() => uploadFile()}
startIcon={<Check size="1rem" />}
>
Upload Upload
</Button> </Button>
{file && <UploadSizeAlert file={file} />}
{isUploadingFile && ( {isUploadingFile && (
<Container style={{ textAlign: 'center', padding: '50px' }}> <Container className={classes.loadingProgress}>
<CircularProgress /> <CircularProgress />
</Container> </Container>
)} )}
</ExpandableListItemActions>
<UploadSizeAlert file={file} />
</>
)}
{/* File has already been uploaded */}
{uploadReference && ( {uploadReference && (
<div style={{ marginBottom: '15px', display: 'flex' }}> <>
<span>{uploadReference}</span> <ExpandableListItemKey label="Swarm Reference" value={uploadReference} />
<ClipboardCopy value={uploadReference} /> <ExpandableListItemActions>
</div> <Button variant="contained" onClick={uploadNew} startIcon={<RotateCcw size="1rem" />}>
Upload New File
</Button>
</ExpandableListItemActions>
</>
)} )}
</div> </div>
</div> </>
</div>
) )
} }
+3 -7
View File
@@ -1,20 +1,17 @@
import { ReactElement, useContext } from 'react' import { ReactElement, useContext } from 'react'
import { Container } from '@material-ui/core'
import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard'
import { Context } from '../../providers/Bee'
import Download from './Download' import Download from './Download'
import Upload from './Upload' import Upload from './Upload'
import TabsContainer from '../../components/TabsContainer' import TabsContainer from '../../components/TabsContainer'
import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard'
import { Context as BeeContext } from '../../providers/Bee'
export default function Files(): ReactElement { export default function Files(): ReactElement {
const { status } = useContext(Context) const { status } = useContext(BeeContext)
if (!status.all) return <TroubleshootConnectionCard /> if (!status.all) return <TroubleshootConnectionCard />
return ( return (
<Container maxWidth="sm">
<TabsContainer <TabsContainer
values={[ values={[
{ {
@@ -27,6 +24,5 @@ export default function Files(): ReactElement {
}, },
]} ]}
/> />
</Container>
) )
} }
+8 -2
View File
@@ -5,7 +5,9 @@ import { Container, CircularProgress } from '@material-ui/core'
import StampsTable from './StampsTable' import StampsTable from './StampsTable'
import CreatePostageStampModal from './CreatePostageStampModal' import CreatePostageStampModal from './CreatePostageStampModal'
import { Context } from '../../providers/Stamps' import { Context as StampsContext } from '../../providers/Stamps'
import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard'
import { Context as BeeContext } from '../../providers/Bee'
const useStyles = makeStyles(() => const useStyles = makeStyles(() =>
createStyles({ createStyles({
@@ -25,7 +27,11 @@ const useStyles = makeStyles(() =>
export default function Accounting(): ReactElement { export default function Accounting(): ReactElement {
const classes = useStyles() const classes = useStyles()
const { stamps, isLoading, error, start, stop } = useContext(Context) const { stamps, isLoading, error, start, stop } = useContext(StampsContext)
const { status } = useContext(BeeContext)
if (!status.all) return <TroubleshootConnectionCard />
useEffect(() => { useEffect(() => {
start() start()
+6 -20
View File
@@ -68,32 +68,18 @@ const componentsOverrides = (theme: Theme) => ({
}, },
MuiTab: { MuiTab: {
root: { root: {
backgroundColor: 'transparent', backgroundColor: theme.palette.background.paper,
fontWeight: theme.typography.fontWeightRegular,
marginRight: theme.spacing(4),
fontFamily: [
'-apple-system',
'BlinkMacSystemFont',
'"Segoe UI"',
'Roboto',
'"Helvetica Neue"',
'Arial',
'sans-serif',
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'"Segoe UI Symbol"',
].join(','),
'&:hover': { '&:hover': {
color: theme.palette.secondary, backgroundColor: '#fcf2e8',
color: theme.palette.primary.main,
opacity: 1, opacity: 1,
}, },
'&$selected': { '&$selected': {
color: theme.palette.secondary,
fontWeight: theme.typography.fontWeightMedium, fontWeight: theme.typography.fontWeightMedium,
}, },
'&:focus': {
color: theme.palette.secondary,
}, },
textColorInherit: {
opacity: 0.5,
}, },
}, },
MuiTabs: { MuiTabs: {
@@ -101,7 +87,7 @@ const componentsOverrides = (theme: Theme) => ({
borderBottom: 'none', borderBottom: 'none',
}, },
indicator: { indicator: {
backgroundColor: theme.palette.primary.main, backgroundColor: 'transparent',
}, },
}, },
}) })