mirror of
https://github.com/Ernous/TorrServerJellyfin.git
synced 2025-12-19 21:46:11 +05:00
added icons for noserver or no files
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|
||||||
|
<script src='https://cdn.lordicon.com/libs/frhvbuzj/lord-icon-2.0.2.js' />
|
||||||
<script src="https://www.gstatic.com/firebasejs/8.1.2/firebase-app.js"></script>
|
<script src="https://www.gstatic.com/firebasejs/8.1.2/firebase-app.js"></script>
|
||||||
<script src="https://www.gstatic.com/firebasejs/8.1.2/firebase-analytics.js"></script>
|
<script src="https://www.gstatic.com/firebasejs/8.1.2/firebase-analytics.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -44,10 +44,7 @@ export default function AddDialog({
|
|||||||
const [skipDebounce, setSkipDebounce] = useState(false)
|
const [skipDebounce, setSkipDebounce] = useState(false)
|
||||||
const [isCustomTitleEnabled, setIsCustomTitleEnabled] = useState(false)
|
const [isCustomTitleEnabled, setIsCustomTitleEnabled] = useState(false)
|
||||||
|
|
||||||
const { data: torrents } = useQuery('torrents', getTorrents, {
|
const { data: torrents } = useQuery('torrents', getTorrents, { retry: 1, refetchInterval: 1000 })
|
||||||
retry: 1,
|
|
||||||
refetchInterval: 1000,
|
|
||||||
})
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const allHashes = torrents.map(({ hash }) => hash)
|
const allHashes = torrents.map(({ hash }) => hash)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
|
|
||||||
import AddDialog from './AddDialog'
|
import AddDialog from './AddDialog'
|
||||||
|
|
||||||
export default function AddDialogButton() {
|
export default function AddDialogButton({ isOffline, isLoading }) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [isDialogOpen, setIsDialogOpen] = useState(false)
|
const [isDialogOpen, setIsDialogOpen] = useState(false)
|
||||||
const handleClickOpen = () => setIsDialogOpen(true)
|
const handleClickOpen = () => setIsDialogOpen(true)
|
||||||
@@ -15,7 +15,7 @@ export default function AddDialogButton() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ListItem button key='Add' onClick={handleClickOpen}>
|
<ListItem disabled={isOffline || isLoading} button key='Add' onClick={handleClickOpen}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<LibraryAddIcon />
|
<LibraryAddIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
|
|||||||
@@ -10,17 +10,19 @@ import SettingsDialog from 'components/Settings'
|
|||||||
import RemoveAll from 'components/RemoveAll'
|
import RemoveAll from 'components/RemoveAll'
|
||||||
import AboutDialog from 'components/About'
|
import AboutDialog from 'components/About'
|
||||||
import CloseServer from 'components/CloseServer'
|
import CloseServer from 'components/CloseServer'
|
||||||
|
import { memo } from 'react'
|
||||||
|
|
||||||
import { AppSidebarStyle } from './style'
|
import { AppSidebarStyle } from './style'
|
||||||
|
|
||||||
export default function Sidebar({ isDrawerOpen, setIsDonationDialogOpen }) {
|
const Sidebar = ({ isDrawerOpen, setIsDonationDialogOpen, isOffline, isLoading }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppSidebarStyle isDrawerOpen={isDrawerOpen}>
|
<AppSidebarStyle isDrawerOpen={isDrawerOpen}>
|
||||||
<List>
|
<List>
|
||||||
<AddDialogButton />
|
<AddDialogButton isOffline={isOffline} isLoading={isLoading} />
|
||||||
<RemoveAll />
|
|
||||||
|
<RemoveAll isOffline={isOffline} isLoading={isLoading} />
|
||||||
</List>
|
</List>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
@@ -28,7 +30,7 @@ export default function Sidebar({ isDrawerOpen, setIsDonationDialogOpen }) {
|
|||||||
<List>
|
<List>
|
||||||
<SettingsDialog />
|
<SettingsDialog />
|
||||||
|
|
||||||
<CloseServer />
|
<CloseServer isOffline={isOffline} isLoading={isLoading} />
|
||||||
</List>
|
</List>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
@@ -46,3 +48,5 @@ export default function Sidebar({ isDrawerOpen, setIsDonationDialogOpen }) {
|
|||||||
</AppSidebarStyle>
|
</AppSidebarStyle>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default memo(Sidebar)
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import TorrentList from 'components/TorrentList'
|
|||||||
import DonateSnackbar from 'components/Donate'
|
import DonateSnackbar from 'components/Donate'
|
||||||
import DonateDialog from 'components/Donate/DonateDialog'
|
import DonateDialog from 'components/Donate/DonateDialog'
|
||||||
import useChangeLanguage from 'utils/useChangeLanguage'
|
import useChangeLanguage from 'utils/useChangeLanguage'
|
||||||
|
import { useQuery } from 'react-query'
|
||||||
|
import { getTorrents } from 'utils/Utils'
|
||||||
|
|
||||||
import { AppWrapper, AppHeader, LanguageSwitch } from './style'
|
import { AppWrapper, AppHeader, LanguageSwitch } from './style'
|
||||||
import Sidebar from './Sidebar'
|
import Sidebar from './Sidebar'
|
||||||
@@ -25,6 +27,13 @@ export default function App() {
|
|||||||
const [isDonationDialogOpen, setIsDonationDialogOpen] = useState(false)
|
const [isDonationDialogOpen, setIsDonationDialogOpen] = useState(false)
|
||||||
const [torrServerVersion, setTorrServerVersion] = useState('')
|
const [torrServerVersion, setTorrServerVersion] = useState('')
|
||||||
const [currentLang, changeLang] = useChangeLanguage()
|
const [currentLang, changeLang] = useChangeLanguage()
|
||||||
|
const [isOffline, setIsOffline] = useState(false)
|
||||||
|
const { data: torrents, isLoading } = useQuery('torrents', getTorrents, {
|
||||||
|
retry: 1,
|
||||||
|
refetchInterval: 1000,
|
||||||
|
onError: () => setIsOffline(true),
|
||||||
|
onSuccess: () => setIsOffline(false),
|
||||||
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
axios.get(echoHost()).then(({ data }) => setTorrServerVersion(data))
|
axios.get(echoHost()).then(({ data }) => setTorrServerVersion(data))
|
||||||
@@ -58,9 +67,14 @@ export default function App() {
|
|||||||
</div>
|
</div>
|
||||||
</AppHeader>
|
</AppHeader>
|
||||||
|
|
||||||
<Sidebar isDrawerOpen={isDrawerOpen} setIsDonationDialogOpen={setIsDonationDialogOpen} />
|
<Sidebar
|
||||||
|
isOffline={isOffline}
|
||||||
|
isLoading={isLoading}
|
||||||
|
isDrawerOpen={isDrawerOpen}
|
||||||
|
setIsDonationDialogOpen={setIsDonationDialogOpen}
|
||||||
|
/>
|
||||||
|
|
||||||
<TorrentList />
|
<TorrentList isOffline={isOffline} torrents={torrents} isLoading={isLoading} />
|
||||||
|
|
||||||
{isDonationDialogOpen && <DonateDialog onClose={() => setIsDonationDialogOpen(false)} />}
|
{isDonationDialogOpen && <DonateDialog onClose={() => setIsDonationDialogOpen(false)} />}
|
||||||
{!JSON.parse(localStorage.getItem('snackbarIsClosed')) && <DonateSnackbar />}
|
{!JSON.parse(localStorage.getItem('snackbarIsClosed')) && <DonateSnackbar />}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { PowerSettingsNew as PowerSettingsNewIcon } from '@material-ui/icons'
|
|||||||
import { shutdownHost } from 'utils/Hosts'
|
import { shutdownHost } from 'utils/Hosts'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
export default function CloseServer() {
|
export default function CloseServer({ isOffline, isLoading }) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const closeDialog = () => setOpen(false)
|
const closeDialog = () => setOpen(false)
|
||||||
@@ -12,7 +12,7 @@ export default function CloseServer() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ListItem button key={t('CloseServer')} onClick={openDialog}>
|
<ListItem disabled={isOffline || isLoading} button key={t('CloseServer')} onClick={openDialog}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<PowerSettingsNewIcon />
|
<PowerSettingsNewIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
|
|||||||
@@ -31,14 +31,15 @@ const fnRemoveAll = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function RemoveAll() {
|
export default function RemoveAll({ isOffline, isLoading }) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const closeDialog = () => setOpen(false)
|
const closeDialog = () => setOpen(false)
|
||||||
const openDialog = () => setOpen(true)
|
const openDialog = () => setOpen(true)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ListItem button key={t('RemoveAll')} onClick={openDialog}>
|
<ListItem disabled={isOffline || isLoading} button key={t('RemoveAll')} onClick={openDialog}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<DeleteIcon />
|
<DeleteIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
import { useState } from 'react'
|
|
||||||
import { Typography } from '@material-ui/core'
|
|
||||||
import TorrentCard from 'components/TorrentCard'
|
|
||||||
import CircularProgress from '@material-ui/core/CircularProgress'
|
|
||||||
import { TorrentListWrapper, CenteredGrid } from 'components/App/style'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { useQuery } from 'react-query'
|
|
||||||
import { getTorrents } from 'utils/Utils'
|
|
||||||
|
|
||||||
export default function TorrentList() {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const [isOffline, setIsOffline] = useState(false)
|
|
||||||
const { data: torrents, isLoading } = useQuery('torrents', getTorrents, {
|
|
||||||
retry: 1,
|
|
||||||
refetchInterval: 1000,
|
|
||||||
onError: () => setIsOffline(true),
|
|
||||||
onSuccess: () => setIsOffline(false),
|
|
||||||
})
|
|
||||||
|
|
||||||
if (isLoading || isOffline || !torrents.length) {
|
|
||||||
return (
|
|
||||||
<CenteredGrid>
|
|
||||||
{isOffline ? (
|
|
||||||
<Typography>{t('Offline')}</Typography>
|
|
||||||
) : isLoading ? (
|
|
||||||
<CircularProgress />
|
|
||||||
) : (
|
|
||||||
!torrents.length && <Typography>{t('NoTorrentsAdded')}</Typography>
|
|
||||||
)}
|
|
||||||
</CenteredGrid>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TorrentListWrapper>
|
|
||||||
{torrents.map(torrent => (
|
|
||||||
<TorrentCard key={torrent.hash} torrent={torrent} />
|
|
||||||
))}
|
|
||||||
</TorrentListWrapper>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
29
web/src/components/TorrentList/AddFirstTorrent.jsx
Normal file
29
web/src/components/TorrentList/AddFirstTorrent.jsx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
import AddDialog from '../Add/AddDialog'
|
||||||
|
import IconWrapper from './style'
|
||||||
|
|
||||||
|
export default function AddFirstTorrent() {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const [isDialogOpen, setIsDialogOpen] = useState(false)
|
||||||
|
const handleClickOpen = () => setIsDialogOpen(true)
|
||||||
|
const handleClose = () => setIsDialogOpen(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<IconWrapper onClick={() => handleClickOpen(true)} isButton>
|
||||||
|
<lord-icon
|
||||||
|
src='https://cdn.lordicon.com/bbnkwdur.json'
|
||||||
|
trigger='loop'
|
||||||
|
colors='primary:#121331,secondary:#00A572'
|
||||||
|
stroke='26'
|
||||||
|
scale='60'
|
||||||
|
/>
|
||||||
|
<div className='icon-label'>{t('NoTorrentsAdded')}</div>
|
||||||
|
</IconWrapper>
|
||||||
|
|
||||||
|
{isDialogOpen && <AddDialog handleClose={handleClose} />}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
20
web/src/components/TorrentList/NoServerConnection.jsx
Normal file
20
web/src/components/TorrentList/NoServerConnection.jsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
import IconWrapper from './style'
|
||||||
|
|
||||||
|
export default function NoServerConnection() {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IconWrapper>
|
||||||
|
<lord-icon
|
||||||
|
src='https://cdn.lordicon.com/wrprwmwt.json'
|
||||||
|
trigger='loop'
|
||||||
|
colors='primary:#121331,secondary:#00A572'
|
||||||
|
stroke='26'
|
||||||
|
scale='60'
|
||||||
|
/>
|
||||||
|
<div className='icon-label'>{t('Offline')}</div>
|
||||||
|
</IconWrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
30
web/src/components/TorrentList/index.jsx
Normal file
30
web/src/components/TorrentList/index.jsx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import TorrentCard from 'components/TorrentCard'
|
||||||
|
import CircularProgress from '@material-ui/core/CircularProgress'
|
||||||
|
import { TorrentListWrapper, CenteredGrid } from 'components/App/style'
|
||||||
|
|
||||||
|
import NoServerConnection from './NoServerConnection'
|
||||||
|
import AddFirstTorrent from './AddFirstTorrent'
|
||||||
|
|
||||||
|
export default function TorrentList({ isOffline, isLoading, torrents }) {
|
||||||
|
if (isLoading || isOffline || !torrents.length) {
|
||||||
|
return (
|
||||||
|
<CenteredGrid>
|
||||||
|
{isOffline ? (
|
||||||
|
<NoServerConnection />
|
||||||
|
) : isLoading ? (
|
||||||
|
<CircularProgress />
|
||||||
|
) : (
|
||||||
|
!torrents.length && <AddFirstTorrent />
|
||||||
|
)}
|
||||||
|
</CenteredGrid>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TorrentListWrapper>
|
||||||
|
{torrents.map(torrent => (
|
||||||
|
<TorrentCard key={torrent.hash} torrent={torrent} />
|
||||||
|
))}
|
||||||
|
</TorrentListWrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
30
web/src/components/TorrentList/style.js
Normal file
30
web/src/components/TorrentList/style.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import styled, { css } from 'styled-components'
|
||||||
|
|
||||||
|
export default styled.div`
|
||||||
|
${({ isButton }) => css`
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
padding: 20px 40px;
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
${isButton &&
|
||||||
|
css`
|
||||||
|
background: #93d7b4;
|
||||||
|
transition: 0.2s;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
:hover {
|
||||||
|
background: #71cc9d;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
|
||||||
|
lord-icon {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-label {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
`
|
||||||
Reference in New Issue
Block a user