mirror of
https://github.com/Ernous/TorrServerJellyfin.git
synced 2025-12-19 13:36:09 +05:00
added new design to settings dialog
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
"react-measure": "^2.5.2",
|
||||
"react-query": "^3.17.0",
|
||||
"react-scripts": "4.0.3",
|
||||
"react-swipeable-views": "^0.14.0",
|
||||
"styled-components": "^5.3.0",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
|
||||
@@ -12,9 +12,10 @@ import usePreviousState from 'utils/usePreviousState'
|
||||
import { useQuery } from 'react-query'
|
||||
import { getTorrents } from 'utils/Utils'
|
||||
import parseTorrent from 'parse-torrent'
|
||||
import { ButtonWrapper, Header } from 'style/DialogStyles'
|
||||
|
||||
import { checkImageURL, getMoviePosters, chechTorrentSource, parseTorrentTitle } from './helpers'
|
||||
import { ButtonWrapper, Content, Header } from './style'
|
||||
import { Content } from './style'
|
||||
import RightSideComponent from './RightSideComponent'
|
||||
import LeftSideComponent from './LeftSideComponent'
|
||||
|
||||
@@ -219,14 +220,7 @@ export default function AddDialog({
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open
|
||||
onClose={handleClose}
|
||||
aria-labelledby='form-dialog-title'
|
||||
fullScreen={fullScreen}
|
||||
fullWidth
|
||||
maxWidth='md'
|
||||
>
|
||||
<Dialog open onClose={handleClose} fullScreen={fullScreen} fullWidth maxWidth='md'>
|
||||
<Header>{t(isEditMode ? 'EditTorrent' : 'AddNewTorrent')}</Header>
|
||||
|
||||
<Content isEditMode={isEditMode}>
|
||||
|
||||
@@ -1,19 +1,6 @@
|
||||
import { Button } from '@material-ui/core'
|
||||
import styled, { css } from 'styled-components'
|
||||
|
||||
export const Header = styled.div`
|
||||
${({ theme: { primary } }) => css`
|
||||
background: ${primary};
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
box-shadow: 0px 2px 4px -1px rgb(0 0 0 / 20%), 0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%);
|
||||
padding: 15px 24px;
|
||||
position: relative;
|
||||
`}
|
||||
`
|
||||
|
||||
export const Content = styled.div`
|
||||
${({
|
||||
isEditMode,
|
||||
@@ -349,13 +336,3 @@ export const PosterLanguageSwitch = styled.div`
|
||||
}
|
||||
`}
|
||||
`
|
||||
|
||||
export const ButtonWrapper = styled.div`
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
> :not(:last-child) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
`
|
||||
|
||||
@@ -5,14 +5,200 @@ import DialogContent from '@material-ui/core/DialogContent'
|
||||
import TextField from '@material-ui/core/TextField'
|
||||
import DialogActions from '@material-ui/core/DialogActions'
|
||||
import Button from '@material-ui/core/Button'
|
||||
import { FormControlLabel, InputLabel, Select, Switch } from '@material-ui/core'
|
||||
import Checkbox from '@material-ui/core/Checkbox'
|
||||
import {
|
||||
ButtonGroup,
|
||||
FormControlLabel,
|
||||
Grid,
|
||||
Input,
|
||||
InputLabel,
|
||||
Select,
|
||||
Slider,
|
||||
Switch,
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
} from '@material-ui/core'
|
||||
import { settingsHost, setTorrServerHost, getTorrServerHost } from 'utils/Hosts'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Header } from 'style/DialogStyles'
|
||||
import AppBar from '@material-ui/core/AppBar'
|
||||
import Tabs from '@material-ui/core/Tabs'
|
||||
import Tab from '@material-ui/core/Tab'
|
||||
import SwipeableViews from 'react-swipeable-views'
|
||||
import styled, { css } from 'styled-components'
|
||||
import { USBIcon, RAMIcon } from 'icons'
|
||||
|
||||
const FooterSection = styled.div`
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #e8e5eb;
|
||||
|
||||
> :last-child > :not(:last-child) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
`
|
||||
const Divider = styled.div`
|
||||
height: 1px;
|
||||
background-color: rgba(0, 0, 0, 0.12);
|
||||
margin: 30px 0;
|
||||
`
|
||||
|
||||
const PreloadCachePercentage = styled.div.attrs(
|
||||
({
|
||||
value,
|
||||
// theme: {
|
||||
// dialogTorrentDetailsContent: { gradientEndColor },
|
||||
// },
|
||||
}) => {
|
||||
const gradientStartColor = 'lightblue'
|
||||
const gradientEndColor = 'orangered'
|
||||
|
||||
return {
|
||||
// this block is here according to styled-components recomendation about fast changable components
|
||||
style: {
|
||||
background: `linear-gradient(to right, ${gradientEndColor} 0%, ${gradientEndColor} ${value}%, ${gradientStartColor} ${value}%, ${gradientStartColor} 100%)`,
|
||||
},
|
||||
}
|
||||
},
|
||||
)`
|
||||
${({ label, isPreloadEnabled }) => css`
|
||||
border: 1px solid;
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
color: #000;
|
||||
margin-bottom: 10px;
|
||||
position: relative;
|
||||
|
||||
:before {
|
||||
content: '${label}';
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
${isPreloadEnabled &&
|
||||
css`
|
||||
:after {
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
background: green;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
`}
|
||||
`}
|
||||
`
|
||||
|
||||
const PreloadCacheValue = styled.div`
|
||||
${({ color }) => css`
|
||||
display: grid;
|
||||
grid-template-columns: max-content 100px 1fr;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
|
||||
:not(:last-child) {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
:before {
|
||||
content: '';
|
||||
background: ${color};
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
`}
|
||||
`
|
||||
|
||||
const a11yProps = index => ({
|
||||
id: `full-width-tab-${index}`,
|
||||
'aria-controls': `full-width-tabpanel-${index}`,
|
||||
})
|
||||
|
||||
const TabPanel = ({ children, value, index, ...other }) => (
|
||||
<div role='tabpanel' hidden={value !== index} id={`full-width-tabpanel-${index}`} {...other}>
|
||||
{value === index && <>{children}</>}
|
||||
</div>
|
||||
)
|
||||
|
||||
const MainSettingsContent = styled.div`
|
||||
min-height: 500px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 40px;
|
||||
padding: 20px;
|
||||
|
||||
@media (max-width: 930px) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
`
|
||||
const SecondarySettingsContent = styled.div`
|
||||
min-height: 500px;
|
||||
padding: 20px;
|
||||
`
|
||||
|
||||
const StorageButton = styled.div`
|
||||
display: grid;
|
||||
place-items: center;
|
||||
gap: 10px;
|
||||
`
|
||||
|
||||
const StorageIconWrapper = styled.div`
|
||||
${({ selected }) => css`
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
border-radius: 50%;
|
||||
background: ${selected ? 'blue' : 'lightgray'};
|
||||
transition: 0.2s;
|
||||
|
||||
${!selected &&
|
||||
css`
|
||||
cursor: pointer;
|
||||
|
||||
:hover {
|
||||
background: orangered;
|
||||
}
|
||||
`}
|
||||
|
||||
svg {
|
||||
transform: rotate(-45deg) scale(0.75);
|
||||
}
|
||||
`}
|
||||
`
|
||||
|
||||
const CacheSizeSettings = styled.div``
|
||||
const CacheStorageSelector = styled.div`
|
||||
display: grid;
|
||||
grid-template-rows: max-content 1fr;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-areas: 'label label';
|
||||
place-items: center;
|
||||
|
||||
@media (max-width: 930px) {
|
||||
grid-template-columns: repeat(2, max-content);
|
||||
column-gap: 30px;
|
||||
}
|
||||
`
|
||||
|
||||
const CacheStorageSettings = styled.div``
|
||||
|
||||
const SettingSection = styled.section``
|
||||
const SettingLabel = styled.div``
|
||||
const SettingSectionLabel = styled.div`
|
||||
font-size: 25px;
|
||||
padding-bottom: 20px;
|
||||
`
|
||||
|
||||
export default function SettingsDialog({ handleClose }) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const fullScreen = useMediaQuery('@media (max-width:930px)')
|
||||
|
||||
const [settings, setSets] = useState({})
|
||||
const [show, setShow] = useState(false)
|
||||
const [tsHost, setTSHost] = useState(getTorrServerHost())
|
||||
@@ -83,9 +269,337 @@ export default function SettingsDialog({ handleClose }) {
|
||||
RemoveCacheOnDrop,
|
||||
} = settings
|
||||
|
||||
const { direction } = useTheme()
|
||||
const [selectedTab, setSelectedTab] = useState(0)
|
||||
|
||||
const handleChange = (_, newValue) => setSelectedTab(newValue)
|
||||
|
||||
const handleChangeIndex = index => setSelectedTab(index)
|
||||
|
||||
const [cacheSize, setCacheSize] = useState(96)
|
||||
const [cachePercentage, setCachePercentage] = useState(95)
|
||||
const [isProMode, setIsProMode] = useState(JSON.parse(localStorage.getItem('isProMode')) || false)
|
||||
const [isRamSelected, setIsRamSelected] = useState(true)
|
||||
|
||||
const handleSliderChange = (_, newValue) => {
|
||||
setCacheSize(newValue)
|
||||
}
|
||||
|
||||
const handleBlur = ({ target: { value } }) => {
|
||||
if (value < 32) return setCacheSize(32)
|
||||
if (value > 20000) return setCacheSize(20000)
|
||||
|
||||
setCacheSize(Math.round(value / 8) * 8)
|
||||
}
|
||||
|
||||
const handleInputChange = ({ target: { value } }) => {
|
||||
setCacheSize(value === '' ? '' : Number(value))
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open onClose={handleClose} aria-labelledby='form-dialog-title' fullWidth>
|
||||
<DialogTitle id='form-dialog-title'>{t('Settings')}</DialogTitle>
|
||||
<Dialog open onClose={handleClose} fullScreen={fullScreen} fullWidth maxWidth='md'>
|
||||
<Header>{t('Settings')}</Header>
|
||||
|
||||
<>
|
||||
<AppBar position='static' color='default'>
|
||||
<Tabs
|
||||
value={selectedTab}
|
||||
onChange={handleChange}
|
||||
indicatorColor='primary'
|
||||
textColor='primary'
|
||||
variant='fullWidth'
|
||||
>
|
||||
<Tab label='Основные' {...a11yProps(0)} />
|
||||
|
||||
<Tab
|
||||
disabled={!isProMode}
|
||||
label={isProMode ? 'Дополнительные' : 'Дополнительные (включите pro mode)'}
|
||||
{...a11yProps(1)}
|
||||
/>
|
||||
</Tabs>
|
||||
</AppBar>
|
||||
|
||||
<SwipeableViews
|
||||
axis={direction === 'rtl' ? 'x-reverse' : 'x'}
|
||||
index={selectedTab}
|
||||
onChangeIndex={handleChangeIndex}
|
||||
>
|
||||
<TabPanel value={selectedTab} index={0} dir={direction}>
|
||||
<MainSettingsContent>
|
||||
<CacheSizeSettings>
|
||||
<SettingSectionLabel>Настройки кеша</SettingSectionLabel>
|
||||
|
||||
<PreloadCachePercentage
|
||||
value={100 - cachePercentage}
|
||||
label={`Кеш ${cacheSize} МБ`}
|
||||
isPreloadEnabled={PreloadBuffer}
|
||||
/>
|
||||
|
||||
<PreloadCacheValue color='orangered'>
|
||||
<div>
|
||||
{100 - cachePercentage}% ({Math.round((cacheSize / 100) * (100 - cachePercentage))} МБ)
|
||||
</div>
|
||||
<div>От кеша будет оставаться позади воспроизводимого блока</div>
|
||||
</PreloadCacheValue>
|
||||
|
||||
<PreloadCacheValue color='lightblue'>
|
||||
<div>
|
||||
{cachePercentage}% ({Math.round((cacheSize / 100) * cachePercentage)} МБ)
|
||||
</div>
|
||||
<div>От кеша будет спереди от воспроизводимого блока</div>
|
||||
</PreloadCacheValue>
|
||||
|
||||
<Divider />
|
||||
|
||||
<SettingSection>
|
||||
<SettingLabel>Размер кеша</SettingLabel>
|
||||
|
||||
<Grid container spacing={2} alignItems='center'>
|
||||
<Grid item xs>
|
||||
<Slider min={32} max={1024} value={cacheSize} onChange={handleSliderChange} step={8} />
|
||||
</Grid>
|
||||
|
||||
{isProMode && (
|
||||
<Grid item>
|
||||
<Input
|
||||
value={cacheSize}
|
||||
margin='dense'
|
||||
onChange={handleInputChange}
|
||||
onBlur={handleBlur}
|
||||
style={{ width: '65px' }}
|
||||
inputProps={{
|
||||
step: 8,
|
||||
min: 32,
|
||||
max: 20000,
|
||||
type: 'number',
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</SettingSection>
|
||||
|
||||
<SettingSection>
|
||||
<SettingLabel>Кеш предзагрузки</SettingLabel>
|
||||
|
||||
<Grid container spacing={2} alignItems='center'>
|
||||
<Grid item xs>
|
||||
<Slider
|
||||
min={40}
|
||||
max={95}
|
||||
value={cachePercentage}
|
||||
onChange={(_, newValue) => setCachePercentage(newValue)}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{isProMode && (
|
||||
<Grid item>
|
||||
<Input
|
||||
value={cachePercentage}
|
||||
margin='dense'
|
||||
onChange={({ target: { value } }) => setCachePercentage(value === '' ? '' : Number(value))}
|
||||
onBlur={({ target: { value } }) => {
|
||||
if (value < 0) return setCachePercentage(0)
|
||||
if (value > 100) return setCachePercentage(100)
|
||||
}}
|
||||
style={{ width: '65px' }}
|
||||
inputProps={{
|
||||
min: 0,
|
||||
max: 100,
|
||||
type: 'number',
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</SettingSection>
|
||||
|
||||
<SettingSection>
|
||||
<FormControlLabel
|
||||
control={<Switch checked={PreloadBuffer} onChange={inputForm} id='PreloadBuffer' color='primary' />}
|
||||
label={t('PreloadBuffer')}
|
||||
/>
|
||||
</SettingSection>
|
||||
</CacheSizeSettings>
|
||||
|
||||
{isRamSelected ? (
|
||||
<CacheStorageSelector>
|
||||
<SettingSectionLabel style={{ placeSelf: 'start', gridArea: 'label' }}>
|
||||
Место хранения кеша
|
||||
</SettingSectionLabel>
|
||||
|
||||
<StorageButton>
|
||||
<StorageIconWrapper selected>
|
||||
<RAMIcon />
|
||||
</StorageIconWrapper>
|
||||
<div>Оперативная память</div>
|
||||
</StorageButton>
|
||||
|
||||
<StorageButton>
|
||||
<StorageIconWrapper onClick={() => setIsRamSelected(false)}>
|
||||
<USBIcon />
|
||||
</StorageIconWrapper>
|
||||
<div>Диск</div>
|
||||
</StorageButton>
|
||||
</CacheStorageSelector>
|
||||
) : (
|
||||
<CacheStorageSettings>
|
||||
<SettingSectionLabel>Место хранения кеша</SettingSectionLabel>
|
||||
|
||||
<ButtonGroup fullWidth color='primary'>
|
||||
<Button onClick={() => setIsRamSelected(true)}>
|
||||
<div>
|
||||
<RAMIcon width='50px' />
|
||||
<div>Оперативная память</div>
|
||||
</div>
|
||||
</Button>
|
||||
|
||||
<Button variant='contained'>
|
||||
<div>
|
||||
<USBIcon width='50px' color='white' />
|
||||
<div>Диск</div>
|
||||
</div>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch checked={RemoveCacheOnDrop} onChange={inputForm} id='RemoveCacheOnDrop' color='primary' />
|
||||
}
|
||||
label={t('RemoveCacheOnDrop')}
|
||||
/>
|
||||
<small>{t('RemoveCacheOnDropDesc')}</small>
|
||||
<TextField
|
||||
onChange={inputForm}
|
||||
margin='dense'
|
||||
id='TorrentsSavePath'
|
||||
label={t('TorrentsSavePath')}
|
||||
value={TorrentsSavePath}
|
||||
type='url'
|
||||
fullWidth
|
||||
/>
|
||||
</CacheStorageSettings>
|
||||
)}
|
||||
</MainSettingsContent>
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel value={selectedTab} index={1} dir={direction}>
|
||||
<SecondarySettingsContent>
|
||||
<SettingSectionLabel>Дополнительные настройки</SettingSectionLabel>
|
||||
|
||||
<FormControlLabel
|
||||
control={<Switch checked={EnableIPv6} onChange={inputForm} id='EnableIPv6' color='primary' />}
|
||||
label={t('EnableIPv6')}
|
||||
/>
|
||||
<br />
|
||||
<FormControlLabel
|
||||
control={<Switch checked={!DisableTCP} onChange={inputForm} id='DisableTCP' color='primary' />}
|
||||
label={t('TCP')}
|
||||
/>
|
||||
<br />
|
||||
<FormControlLabel
|
||||
control={<Switch checked={!DisableUTP} onChange={inputForm} id='DisableUTP' color='primary' />}
|
||||
label={t('UTP')}
|
||||
/>
|
||||
<br />
|
||||
<FormControlLabel
|
||||
control={<Switch checked={!DisablePEX} onChange={inputForm} id='DisablePEX' color='primary' />}
|
||||
label={t('PEX')}
|
||||
/>
|
||||
<br />
|
||||
<FormControlLabel
|
||||
control={<Switch checked={ForceEncrypt} onChange={inputForm} id='ForceEncrypt' color='primary' />}
|
||||
label={t('ForceEncrypt')}
|
||||
/>
|
||||
<br />
|
||||
<TextField
|
||||
onChange={inputForm}
|
||||
margin='dense'
|
||||
id='TorrentDisconnectTimeout'
|
||||
label={t('TorrentDisconnectTimeout')}
|
||||
value={TorrentDisconnectTimeout}
|
||||
type='number'
|
||||
fullWidth
|
||||
/>
|
||||
<br />
|
||||
<TextField
|
||||
onChange={inputForm}
|
||||
margin='dense'
|
||||
id='ConnectionsLimit'
|
||||
label={t('ConnectionsLimit')}
|
||||
value={ConnectionsLimit}
|
||||
type='number'
|
||||
fullWidth
|
||||
/>
|
||||
<br />
|
||||
<FormControlLabel
|
||||
control={<Switch checked={!DisableDHT} onChange={inputForm} id='DisableDHT' color='primary' />}
|
||||
label={t('DHT')}
|
||||
/>
|
||||
<br />
|
||||
<TextField
|
||||
onChange={inputForm}
|
||||
margin='dense'
|
||||
id='DhtConnectionLimit'
|
||||
label={t('DhtConnectionLimit')}
|
||||
value={DhtConnectionLimit}
|
||||
type='number'
|
||||
fullWidth
|
||||
/>
|
||||
<br />
|
||||
<TextField
|
||||
onChange={inputForm}
|
||||
margin='dense'
|
||||
id='DownloadRateLimit'
|
||||
label={t('DownloadRateLimit')}
|
||||
value={DownloadRateLimit}
|
||||
type='number'
|
||||
fullWidth
|
||||
/>
|
||||
<br />
|
||||
<FormControlLabel
|
||||
control={<Switch checked={!DisableUpload} onChange={inputForm} id='DisableUpload' color='primary' />}
|
||||
label={t('Upload')}
|
||||
/>
|
||||
<br />
|
||||
<TextField
|
||||
onChange={inputForm}
|
||||
margin='dense'
|
||||
id='UploadRateLimit'
|
||||
label={t('UploadRateLimit')}
|
||||
value={UploadRateLimit}
|
||||
type='number'
|
||||
fullWidth
|
||||
/>
|
||||
<br />
|
||||
<TextField
|
||||
onChange={inputForm}
|
||||
margin='dense'
|
||||
id='PeersListenPort'
|
||||
label={t('PeersListenPort')}
|
||||
value={PeersListenPort}
|
||||
type='number'
|
||||
fullWidth
|
||||
/>
|
||||
<br />
|
||||
<FormControlLabel
|
||||
control={<Switch checked={!DisableUPNP} onChange={inputForm} id='DisableUPNP' color='primary' />}
|
||||
label={t('UPNP')}
|
||||
/>
|
||||
<br />
|
||||
<InputLabel htmlFor='RetrackersMode'>{t('RetrackersMode')}</InputLabel>
|
||||
<Select onChange={inputForm} type='number' native id='RetrackersMode' value={RetrackersMode}>
|
||||
<option value={0}>{t('DontAddRetrackers')}</option>
|
||||
<option value={1}>{t('AddRetrackers')}</option>
|
||||
<option value={2}>{t('RemoveRetrackers')}</option>
|
||||
<option value={3}>{t('ReplaceRetrackers')}</option>
|
||||
</Select>
|
||||
<br />
|
||||
</SecondarySettingsContent>
|
||||
</TabPanel>
|
||||
</SwipeableViews>
|
||||
</>
|
||||
{/* <DialogTitle id='form-dialog-title'>{t('Settings')}</DialogTitle>
|
||||
<DialogContent>
|
||||
<TextField
|
||||
onChange={onInputHost}
|
||||
@@ -269,7 +783,33 @@ export default function SettingsDialog({ handleClose }) {
|
||||
<Button onClick={handleSave} color='primary' variant='outlined'>
|
||||
{t('Save')}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</DialogActions> */}
|
||||
<FooterSection>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={isProMode}
|
||||
onChange={({ target: { checked } }) => {
|
||||
setIsProMode(checked)
|
||||
localStorage.setItem('isProMode', checked)
|
||||
if (!checked) setSelectedTab(0)
|
||||
}}
|
||||
color='primary'
|
||||
/>
|
||||
}
|
||||
label='Pro mode'
|
||||
/>
|
||||
|
||||
<div>
|
||||
<Button onClick={handleClose} color='secondary' variant='outlined'>
|
||||
{t('Cancel')}
|
||||
</Button>
|
||||
|
||||
<Button variant='contained' onClick={handleSave} color='primary'>
|
||||
{t('Save')}
|
||||
</Button>
|
||||
</div>
|
||||
</FooterSection>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
24
web/src/style/DialogStyles.js
Normal file
24
web/src/style/DialogStyles.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import styled, { css } from 'styled-components'
|
||||
|
||||
export const Header = styled.div`
|
||||
${({ theme: { primary } }) => css`
|
||||
background: ${primary};
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
box-shadow: 0px 2px 4px -1px rgb(0 0 0 / 20%), 0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%);
|
||||
padding: 15px 24px;
|
||||
position: relative;
|
||||
`}
|
||||
`
|
||||
|
||||
export const ButtonWrapper = styled.div`
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
> :not(:last-child) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
`
|
||||
@@ -1167,6 +1167,13 @@
|
||||
core-js-pure "^3.0.0"
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0.tgz#adeb78fedfc855aa05bc041640f3f6f98e85424c"
|
||||
integrity sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.12.0"
|
||||
|
||||
"@babel/runtime@7.12.1":
|
||||
version "7.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740"
|
||||
@@ -7894,6 +7901,11 @@ just-debounce@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.1.0.tgz#2f81a3ad4121a76bc7cb45dbf704c0d76a8e5ddf"
|
||||
integrity sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==
|
||||
|
||||
keycode@^2.1.7:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.2.0.tgz#3d0af56dc7b8b8e5cba8d0a97f107204eec22b04"
|
||||
integrity sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ=
|
||||
|
||||
killable@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
|
||||
@@ -8158,7 +8170,7 @@ loglevel@^1.6.8:
|
||||
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197"
|
||||
integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==
|
||||
|
||||
loose-envify@^1.1.0, loose-envify@^1.4.0:
|
||||
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||
@@ -10207,7 +10219,7 @@ prompts@^2.0.1:
|
||||
kleur "^3.0.3"
|
||||
sisteransi "^1.0.5"
|
||||
|
||||
prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
version "15.7.2"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||
@@ -10451,6 +10463,15 @@ react-error-overlay@^6.0.9:
|
||||
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
|
||||
integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
|
||||
|
||||
react-event-listener@^0.6.0:
|
||||
version "0.6.6"
|
||||
resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.6.6.tgz#758f7b991cad9086dd39fd29fad72127e1d8962a"
|
||||
integrity sha512-+hCNqfy7o9wvO6UgjqFmBzARJS7qrNoda0VqzvOuioEpoEXKutiKuv92dSz6kP7rYLmyHPyYNLesi5t/aH1gfw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.2.0"
|
||||
prop-types "^15.6.0"
|
||||
warning "^4.0.1"
|
||||
|
||||
react-i18next@^11.10.0:
|
||||
version "11.10.0"
|
||||
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.10.0.tgz#f34257447e18e710e36d8fd3f721dd7d37c7004f"
|
||||
@@ -10559,6 +10580,37 @@ react-scripts@4.0.3:
|
||||
optionalDependencies:
|
||||
fsevents "^2.1.3"
|
||||
|
||||
react-swipeable-views-core@^0.14.0:
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/react-swipeable-views-core/-/react-swipeable-views-core-0.14.0.tgz#6ac443a7cc7bc5ea022fbd549292bb5fff361cce"
|
||||
integrity sha512-0W/e9uPweNEOSPjmYtuKSC/SvKKg1sfo+WtPdnxeLF3t2L82h7jjszuOHz9C23fzkvLfdgkaOmcbAxE9w2GEjA==
|
||||
dependencies:
|
||||
"@babel/runtime" "7.0.0"
|
||||
warning "^4.0.1"
|
||||
|
||||
react-swipeable-views-utils@^0.14.0:
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/react-swipeable-views-utils/-/react-swipeable-views-utils-0.14.0.tgz#6b76e251906747482730c22002fe47ab1014ba32"
|
||||
integrity sha512-W+fXBOsDqgFK1/g7MzRMVcDurp3LqO3ksC8UgInh2P/tKgb5DusuuB1geKHFc6o1wKl+4oyER4Zh3Lxmr8xbXA==
|
||||
dependencies:
|
||||
"@babel/runtime" "7.0.0"
|
||||
keycode "^2.1.7"
|
||||
prop-types "^15.6.0"
|
||||
react-event-listener "^0.6.0"
|
||||
react-swipeable-views-core "^0.14.0"
|
||||
shallow-equal "^1.2.1"
|
||||
|
||||
react-swipeable-views@^0.14.0:
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/react-swipeable-views/-/react-swipeable-views-0.14.0.tgz#149c0df3d92220cc89e3f6d5c04a78dfe46f9b54"
|
||||
integrity sha512-wrTT6bi2nC3JbmyNAsPXffUXLn0DVT9SbbcFr36gKpbaCgEp7rX/OFxsu5hPc/NBsUhHyoSRGvwqJNNrWTwCww==
|
||||
dependencies:
|
||||
"@babel/runtime" "7.0.0"
|
||||
prop-types "^15.5.4"
|
||||
react-swipeable-views-core "^0.14.0"
|
||||
react-swipeable-views-utils "^0.14.0"
|
||||
warning "^4.0.1"
|
||||
|
||||
react-transition-group@^4.4.0:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9"
|
||||
@@ -10699,6 +10751,11 @@ regenerator-runtime@^0.11.0:
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
|
||||
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
|
||||
|
||||
regenerator-runtime@^0.12.0:
|
||||
version "0.12.1"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
|
||||
integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==
|
||||
|
||||
regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7:
|
||||
version "0.13.7"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
|
||||
@@ -11315,6 +11372,11 @@ sha.js@^2.4.0, sha.js@^2.4.8:
|
||||
inherits "^2.0.1"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
shallow-equal@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.2.1.tgz#4c16abfa56043aa20d050324efa68940b0da79da"
|
||||
integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==
|
||||
|
||||
shallowequal@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
|
||||
@@ -12751,6 +12813,13 @@ walker@^1.0.7, walker@~1.0.5:
|
||||
dependencies:
|
||||
makeerror "1.0.x"
|
||||
|
||||
warning@^4.0.1:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
|
||||
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
|
||||
dependencies:
|
||||
loose-envify "^1.0.0"
|
||||
|
||||
watchpack-chokidar2@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957"
|
||||
|
||||
Reference in New Issue
Block a user