mirror of
https://github.com/Ernous/TorrServerJellyfin.git
synced 2025-12-19 21:46:11 +05:00
torrent cards rewritten
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
"parse-torrent-title": "^1.3.0",
|
"parse-torrent-title": "^1.3.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-copy-to-clipboard": "^5.0.3",
|
"react-copy-to-clipboard": "^5.0.3",
|
||||||
|
"react-div-100vh": "^0.6.0",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-konva": "^17.0.2-4",
|
"react-konva": "^17.0.2-4",
|
||||||
"react-measure": "^2.5.2",
|
"react-measure": "^2.5.2",
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
import CssBaseline from '@material-ui/core/CssBaseline'
|
|
||||||
import { createMuiTheme, MuiThemeProvider } from '@material-ui/core'
|
|
||||||
|
|
||||||
import Appbar from './components/Appbar/index'
|
|
||||||
|
|
||||||
const baseTheme = createMuiTheme({
|
|
||||||
overrides: {
|
|
||||||
MuiCssBaseline: {
|
|
||||||
'@global': {
|
|
||||||
html: {
|
|
||||||
WebkitFontSmoothing: 'auto',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
palette: {
|
|
||||||
primary: {
|
|
||||||
main: '#3fb57a',
|
|
||||||
},
|
|
||||||
secondary: {
|
|
||||||
main: '#FFA724',
|
|
||||||
},
|
|
||||||
tonalOffset: 0.2,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
export default function App() {
|
|
||||||
return (
|
|
||||||
<MuiThemeProvider theme={baseTheme}>
|
|
||||||
<CssBaseline />
|
|
||||||
<Appbar />
|
|
||||||
</MuiThemeProvider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
60
web/src/App/Sidebar.jsx
Normal file
60
web/src/App/Sidebar.jsx
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { playlistAllHost, shutdownHost } from 'utils/Hosts'
|
||||||
|
import Divider from '@material-ui/core/Divider'
|
||||||
|
import ListItem from '@material-ui/core/ListItem'
|
||||||
|
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
||||||
|
import ListItemText from '@material-ui/core/ListItemText'
|
||||||
|
import AddDialogButton from 'components/Add'
|
||||||
|
import RemoveAll from 'components/RemoveAll'
|
||||||
|
import SettingsDialog from 'components/Settings'
|
||||||
|
import AboutDialog from 'components/About'
|
||||||
|
import UploadDialog from 'components/Upload'
|
||||||
|
import {
|
||||||
|
CreditCard as CreditCardIcon,
|
||||||
|
List as ListIcon,
|
||||||
|
PowerSettingsNew as PowerSettingsNewIcon,
|
||||||
|
} from '@material-ui/icons'
|
||||||
|
import List from '@material-ui/core/List'
|
||||||
|
|
||||||
|
import { AppSidebarStyle } from './style'
|
||||||
|
|
||||||
|
export default function Sidebar({ isDrawerOpen, setIsDonationDialogOpen }) {
|
||||||
|
return (
|
||||||
|
<AppSidebarStyle isDrawerOpen={isDrawerOpen}>
|
||||||
|
<List>
|
||||||
|
<AddDialogButton />
|
||||||
|
<UploadDialog />
|
||||||
|
<RemoveAll />
|
||||||
|
<ListItem button component='a' key='Playlist all torrents' target='_blank' href={playlistAllHost()}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<ListIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText primary='Playlist all torrents' />
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<List>
|
||||||
|
<SettingsDialog />
|
||||||
|
<AboutDialog />
|
||||||
|
<ListItem button key='Close server' onClick={() => fetch(shutdownHost())}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<PowerSettingsNewIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText primary='Close server' />
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<List>
|
||||||
|
<ListItem button key='Donation' onClick={() => setIsDonationDialogOpen(true)}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<CreditCardIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText primary='Donate' />
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
</AppSidebarStyle>
|
||||||
|
)
|
||||||
|
}
|
||||||
66
web/src/App/index.jsx
Normal file
66
web/src/App/index.jsx
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import CssBaseline from '@material-ui/core/CssBaseline'
|
||||||
|
import { createMuiTheme, MuiThemeProvider } from '@material-ui/core'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import Typography from '@material-ui/core/Typography'
|
||||||
|
import IconButton from '@material-ui/core/IconButton'
|
||||||
|
import { Menu as MenuIcon, Close as CloseIcon } from '@material-ui/icons'
|
||||||
|
import { getTorrServerHost } from 'utils/Hosts'
|
||||||
|
import TorrentList from 'components/TorrentList'
|
||||||
|
import DonateSnackbar from 'components/Donate'
|
||||||
|
import DonateDialog from 'components/Donate/DonateDialog'
|
||||||
|
import Div100vh from 'react-div-100vh'
|
||||||
|
|
||||||
|
import { AppWrapper, AppHeader } from './style'
|
||||||
|
import Sidebar from './Sidebar'
|
||||||
|
|
||||||
|
const baseTheme = createMuiTheme({
|
||||||
|
overrides: { MuiCssBaseline: { '@global': { html: { WebkitFontSmoothing: 'auto' } } } },
|
||||||
|
palette: { primary: { main: '#3fb57a' }, secondary: { main: '#FFA724' }, tonalOffset: 0.2 },
|
||||||
|
})
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
const [isDrawerOpen, setIsDrawerOpen] = useState(false)
|
||||||
|
const [isDonationDialogOpen, setIsDonationDialogOpen] = useState(false)
|
||||||
|
const [tsVersion, setTSVersion] = useState('')
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch(`${getTorrServerHost()}/echo`)
|
||||||
|
.then(resp => resp.text())
|
||||||
|
.then(txt => {
|
||||||
|
if (!txt.startsWith('<!DOCTYPE html>')) setTSVersion(txt)
|
||||||
|
})
|
||||||
|
}, [isDrawerOpen])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MuiThemeProvider theme={baseTheme}>
|
||||||
|
<CssBaseline />
|
||||||
|
|
||||||
|
{/* Div100vh - iOS WebKit fix */}
|
||||||
|
<Div100vh>
|
||||||
|
<AppWrapper>
|
||||||
|
<AppHeader>
|
||||||
|
<IconButton
|
||||||
|
style={{ marginRight: '20px' }}
|
||||||
|
color='inherit'
|
||||||
|
onClick={() => setIsDrawerOpen(!isDrawerOpen)}
|
||||||
|
edge='start'
|
||||||
|
>
|
||||||
|
{isDrawerOpen ? <CloseIcon /> : <MenuIcon />}
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
<Typography variant='h6' noWrap>
|
||||||
|
TorrServer {tsVersion}
|
||||||
|
</Typography>
|
||||||
|
</AppHeader>
|
||||||
|
|
||||||
|
<Sidebar isDrawerOpen={isDrawerOpen} setIsDonationDialogOpen={setIsDonationDialogOpen} />
|
||||||
|
|
||||||
|
<TorrentList />
|
||||||
|
|
||||||
|
{isDonationDialogOpen && <DonateDialog onClose={() => setIsDonationDialogOpen(false)} />}
|
||||||
|
{!JSON.parse(localStorage.getItem('snackbarIsClosed')) && <DonateSnackbar />}
|
||||||
|
</AppWrapper>
|
||||||
|
</Div100vh>
|
||||||
|
</MuiThemeProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
57
web/src/App/style.js
Normal file
57
web/src/App/style.js
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import styled, { css } from 'styled-components'
|
||||||
|
|
||||||
|
export const AppWrapper = styled.div`
|
||||||
|
height: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 60px 1fr;
|
||||||
|
grid-template-rows: 60px 1fr;
|
||||||
|
grid-template-areas:
|
||||||
|
'head head'
|
||||||
|
'side content';
|
||||||
|
`
|
||||||
|
export const AppHeader = styled.div`
|
||||||
|
background: #3fb57a;
|
||||||
|
color: rgba(0, 0, 0, 0.87);
|
||||||
|
grid-area: head;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
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: 0 24px;
|
||||||
|
z-index: 3;
|
||||||
|
`
|
||||||
|
export const AppSidebarStyle = styled.div`
|
||||||
|
${({ isDrawerOpen }) => css`
|
||||||
|
grid-area: side;
|
||||||
|
width: ${isDrawerOpen ? '400%' : '100%'};
|
||||||
|
z-index: 2;
|
||||||
|
overflow-x: hidden;
|
||||||
|
transition: width 195ms cubic-bezier(0.4, 0, 0.6, 1) 0ms;
|
||||||
|
border-right: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
background: #fff;
|
||||||
|
white-space: nowrap;
|
||||||
|
`}
|
||||||
|
`
|
||||||
|
export const TorrentListWrapper = styled.div`
|
||||||
|
grid-area: content;
|
||||||
|
padding: 20px;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
place-content: start;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(max-content, 570px));
|
||||||
|
gap: 20px;
|
||||||
|
|
||||||
|
@media (max-width: 1260px), (max-height: 500px) {
|
||||||
|
padding: 10px;
|
||||||
|
gap: 15px;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1100px) {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 700px) {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
`
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
import { useEffect, useState } from 'react'
|
|
||||||
import clsx from 'clsx'
|
|
||||||
import { useTheme } from '@material-ui/core/styles'
|
|
||||||
import Drawer from '@material-ui/core/Drawer'
|
|
||||||
import AppBar from '@material-ui/core/AppBar'
|
|
||||||
import Toolbar from '@material-ui/core/Toolbar'
|
|
||||||
import List from '@material-ui/core/List'
|
|
||||||
import Typography from '@material-ui/core/Typography'
|
|
||||||
import Divider from '@material-ui/core/Divider'
|
|
||||||
import IconButton from '@material-ui/core/IconButton'
|
|
||||||
import MenuIcon from '@material-ui/icons/Menu'
|
|
||||||
import ChevronLeftIcon from '@material-ui/icons/ChevronLeft'
|
|
||||||
import ChevronRightIcon from '@material-ui/icons/ChevronRight'
|
|
||||||
import ListItem from '@material-ui/core/ListItem'
|
|
||||||
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
|
||||||
import ListItemText from '@material-ui/core/ListItemText'
|
|
||||||
import CreditCardIcon from '@material-ui/icons/CreditCard'
|
|
||||||
import ListIcon from '@material-ui/icons/List'
|
|
||||||
import PowerSettingsNewIcon from '@material-ui/icons/PowerSettingsNew'
|
|
||||||
import { playlistAllHost, shutdownHost, getTorrServerHost } from 'utils/Hosts'
|
|
||||||
import TorrentList from 'components/TorrentList'
|
|
||||||
import AddDialogButton from 'components/Add'
|
|
||||||
import RemoveAll from 'components/RemoveAll'
|
|
||||||
import SettingsDialog from 'components/Settings'
|
|
||||||
import AboutDialog from 'components/About'
|
|
||||||
import DonateSnackbar from 'components/Donate'
|
|
||||||
import DonateDialog from 'components/Donate/DonateDialog'
|
|
||||||
import UploadDialog from 'components/Upload'
|
|
||||||
|
|
||||||
import useStyles from './useStyles'
|
|
||||||
|
|
||||||
export default function MiniDrawer() {
|
|
||||||
const classes = useStyles()
|
|
||||||
const theme = useTheme()
|
|
||||||
const [isDrawerOpen, setIsDrawerOpen] = useState(false)
|
|
||||||
const [isDonationDialogOpen, setIsDonationDialogOpen] = useState(false)
|
|
||||||
const [tsVersion, setTSVersion] = useState('')
|
|
||||||
|
|
||||||
const handleDrawerOpen = () => setIsDrawerOpen(true)
|
|
||||||
const handleDrawerClose = () => setIsDrawerOpen(false)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetch(`${getTorrServerHost()}/echo`)
|
|
||||||
.then(resp => resp.text())
|
|
||||||
.then(txt => {
|
|
||||||
if (!txt.startsWith('<!DOCTYPE html>')) setTSVersion(txt)
|
|
||||||
})
|
|
||||||
}, [isDrawerOpen])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.root}>
|
|
||||||
<AppBar
|
|
||||||
position='fixed'
|
|
||||||
className={clsx(classes.appBar, {
|
|
||||||
[classes.appBarShift]: isDrawerOpen,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<Toolbar>
|
|
||||||
<IconButton
|
|
||||||
color='inherit'
|
|
||||||
aria-label='open drawer'
|
|
||||||
onClick={handleDrawerOpen}
|
|
||||||
edge='start'
|
|
||||||
className={clsx(classes.menuButton, {
|
|
||||||
[classes.hide]: isDrawerOpen,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<MenuIcon />
|
|
||||||
</IconButton>
|
|
||||||
<Typography variant='h6' noWrap>
|
|
||||||
TorrServer {tsVersion}
|
|
||||||
</Typography>
|
|
||||||
</Toolbar>
|
|
||||||
</AppBar>
|
|
||||||
|
|
||||||
<Drawer
|
|
||||||
variant='permanent'
|
|
||||||
className={clsx(classes.drawer, {
|
|
||||||
[classes.drawerOpen]: isDrawerOpen,
|
|
||||||
[classes.drawerClose]: !isDrawerOpen,
|
|
||||||
})}
|
|
||||||
classes={{
|
|
||||||
paper: clsx({
|
|
||||||
[classes.drawerOpen]: isDrawerOpen,
|
|
||||||
[classes.drawerClose]: !isDrawerOpen,
|
|
||||||
}),
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className={classes.toolbar}>
|
|
||||||
<IconButton onClick={handleDrawerClose}>
|
|
||||||
{theme.direction === 'rtl' ? <ChevronRightIcon /> : <ChevronLeftIcon />}
|
|
||||||
</IconButton>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
<List>
|
|
||||||
<AddDialogButton />
|
|
||||||
<UploadDialog />
|
|
||||||
<RemoveAll />
|
|
||||||
<ListItem button component='a' key='Playlist all torrents' target='_blank' href={playlistAllHost()}>
|
|
||||||
<ListItemIcon>
|
|
||||||
<ListIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary='Playlist all torrents' />
|
|
||||||
</ListItem>
|
|
||||||
</List>
|
|
||||||
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
<List>
|
|
||||||
<SettingsDialog />
|
|
||||||
<AboutDialog />
|
|
||||||
<ListItem button key='Close server' onClick={() => fetch(shutdownHost())}>
|
|
||||||
<ListItemIcon>
|
|
||||||
<PowerSettingsNewIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary='Close server' />
|
|
||||||
</ListItem>
|
|
||||||
</List>
|
|
||||||
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
<List>
|
|
||||||
<ListItem button key='Donation' onClick={() => setIsDonationDialogOpen(true)}>
|
|
||||||
<ListItemIcon>
|
|
||||||
<CreditCardIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary='Donate' />
|
|
||||||
</ListItem>
|
|
||||||
</List>
|
|
||||||
</Drawer>
|
|
||||||
|
|
||||||
<main className={classes.content}>
|
|
||||||
<div className={classes.toolbar} />
|
|
||||||
|
|
||||||
<TorrentList />
|
|
||||||
</main>
|
|
||||||
|
|
||||||
{isDonationDialogOpen && <DonateDialog onClose={() => setIsDonationDialogOpen(false)} />}
|
|
||||||
{!JSON.parse(localStorage.getItem('snackbarIsClosed')) && <DonateSnackbar />}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
import { makeStyles } from '@material-ui/core/styles'
|
|
||||||
|
|
||||||
const drawerWidth = 240
|
|
||||||
|
|
||||||
export default makeStyles(theme => ({
|
|
||||||
root: {
|
|
||||||
display: 'flex',
|
|
||||||
},
|
|
||||||
appBar: {
|
|
||||||
zIndex: theme.zIndex.drawer + 1,
|
|
||||||
transition: theme.transitions.create(['width', 'margin'], {
|
|
||||||
easing: theme.transitions.easing.sharp,
|
|
||||||
duration: theme.transitions.duration.leavingScreen,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
appBarShift: {
|
|
||||||
marginLeft: drawerWidth,
|
|
||||||
width: `calc(100% - ${drawerWidth}px)`,
|
|
||||||
transition: theme.transitions.create(['width', 'margin'], {
|
|
||||||
easing: theme.transitions.easing.sharp,
|
|
||||||
duration: theme.transitions.duration.enteringScreen,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
menuButton: {
|
|
||||||
marginRight: 36,
|
|
||||||
},
|
|
||||||
hide: {
|
|
||||||
display: 'none',
|
|
||||||
},
|
|
||||||
drawer: {
|
|
||||||
width: drawerWidth,
|
|
||||||
flexShrink: 1,
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
},
|
|
||||||
drawerOpen: {
|
|
||||||
width: drawerWidth,
|
|
||||||
transition: theme.transitions.create('width', {
|
|
||||||
easing: theme.transitions.easing.sharp,
|
|
||||||
duration: theme.transitions.duration.enteringScreen,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
drawerClose: {
|
|
||||||
transition: theme.transitions.create('width', {
|
|
||||||
easing: theme.transitions.easing.sharp,
|
|
||||||
duration: theme.transitions.duration.leavingScreen,
|
|
||||||
}),
|
|
||||||
overflowX: 'hidden',
|
|
||||||
width: theme.spacing(7) + 1,
|
|
||||||
[theme.breakpoints.up('sm')]: {
|
|
||||||
width: theme.spacing(9) + 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
toolbar: {
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'flex-end',
|
|
||||||
padding: theme.spacing(0, 1),
|
|
||||||
// necessary for content to be below app bar
|
|
||||||
...theme.mixins.toolbar,
|
|
||||||
},
|
|
||||||
content: {
|
|
||||||
flexGrow: 1,
|
|
||||||
padding: theme.spacing(3),
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { NoImageIcon } from 'icons'
|
import { NoImageIcon } from 'icons'
|
||||||
import { humanizeSize } from 'utils/Utils'
|
import { humanizeSize, shortenText } from 'utils/Utils'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { Button, ButtonGroup } from '@material-ui/core'
|
import { Button, ButtonGroup } from '@material-ui/core'
|
||||||
import ptt from 'parse-torrent-title'
|
import ptt from 'parse-torrent-title'
|
||||||
@@ -30,8 +30,6 @@ import { DownlodSpeedWidget, UploadSpeedWidget, PeersWidget, SizeWidget } from '
|
|||||||
import TorrentFunctions from './TorrentFunctions'
|
import TorrentFunctions from './TorrentFunctions'
|
||||||
import { isFilePlayable } from './helpers'
|
import { isFilePlayable } from './helpers'
|
||||||
|
|
||||||
const shortenText = (text, count) => text.slice(0, count) + (text.length > count ? '...' : '')
|
|
||||||
|
|
||||||
const Loader = () => (
|
const Loader = () => (
|
||||||
<div style={{ minHeight: '80vh', display: 'grid', placeItems: 'center' }}>
|
<div style={{ minHeight: '80vh', display: 'grid', placeItems: 'center' }}>
|
||||||
<CircularProgress />
|
<CircularProgress />
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import 'fontsource-roboto'
|
import 'fontsource-roboto'
|
||||||
import { forwardRef, useState } from 'react'
|
import { forwardRef, useState } from 'react'
|
||||||
import HeightIcon from '@material-ui/icons/Height'
|
import { UnfoldMore as UnfoldMoreIcon, Close as CloseIcon, Delete as DeleteIcon } from '@material-ui/icons'
|
||||||
import CloseIcon from '@material-ui/icons/Close'
|
import { getPeerString, humanizeSize, shortenText } from 'utils/Utils'
|
||||||
import DeleteIcon from '@material-ui/icons/Delete'
|
|
||||||
import { getPeerString, humanizeSize } from 'utils/Utils'
|
|
||||||
import { torrentsHost } from 'utils/Hosts'
|
import { torrentsHost } from 'utils/Hosts'
|
||||||
import { NoImageIcon } from 'icons'
|
import { NoImageIcon } from 'icons'
|
||||||
import DialogTorrentDetailsContent from 'components/DialogTorrentDetailsContent'
|
import DialogTorrentDetailsContent from 'components/DialogTorrentDetailsContent'
|
||||||
@@ -12,16 +10,7 @@ import Slide from '@material-ui/core/Slide'
|
|||||||
import { Button, DialogActions, DialogTitle, useMediaQuery, useTheme } from '@material-ui/core'
|
import { Button, DialogActions, DialogTitle, useMediaQuery, useTheme } from '@material-ui/core'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
import {
|
import { StyledButton, TorrentCard, TorrentCardButtons, TorrentCardDescription, TorrentCardPoster } from './style'
|
||||||
StyledButton,
|
|
||||||
TorrentCard,
|
|
||||||
TorrentCardButtons,
|
|
||||||
TorrentCardDescription,
|
|
||||||
TorrentCardDescriptionContent,
|
|
||||||
TorrentCardDescriptionLabel,
|
|
||||||
TorrentCardPoster,
|
|
||||||
TorrentCardDetails,
|
|
||||||
} from './style'
|
|
||||||
|
|
||||||
const Transition = forwardRef((props, ref) => <Slide direction='up' ref={ref} {...props} />)
|
const Transition = forwardRef((props, ref) => <Slide direction='up' ref={ref} {...props} />)
|
||||||
|
|
||||||
@@ -51,7 +40,7 @@ export default function Torrent({ torrent }) {
|
|||||||
|
|
||||||
<TorrentCardButtons>
|
<TorrentCardButtons>
|
||||||
<StyledButton onClick={openDetailedInfo}>
|
<StyledButton onClick={openDetailedInfo}>
|
||||||
<HeightIcon />
|
<UnfoldMoreIcon />
|
||||||
<span>Details</span>
|
<span>Details</span>
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
|
|
||||||
@@ -67,31 +56,29 @@ export default function Torrent({ torrent }) {
|
|||||||
</TorrentCardButtons>
|
</TorrentCardButtons>
|
||||||
|
|
||||||
<TorrentCardDescription>
|
<TorrentCardDescription>
|
||||||
<span>
|
<div className='description-title-wrapper'>
|
||||||
<TorrentCardDescriptionLabel>Name</TorrentCardDescriptionLabel>
|
<div className='description-section-name'>Name</div>
|
||||||
<TorrentCardDescriptionContent isTitle>{title || name}</TorrentCardDescriptionContent>
|
<div className='description-torrent-title'>{shortenText(title || name, 100)}</div>
|
||||||
</span>
|
</div>
|
||||||
|
|
||||||
<TorrentCardDetails>
|
<div className='description-statistics-wrapper'>
|
||||||
<span>
|
<div className='description-statistics-element-wrapper'>
|
||||||
<TorrentCardDescriptionLabel>Size</TorrentCardDescriptionLabel>
|
<div className='description-section-name'>Size</div>
|
||||||
<TorrentCardDescriptionContent>
|
<div className='description-statistics-element-value'>{torrentSize > 0 && humanizeSize(torrentSize)}</div>
|
||||||
{torrentSize > 0 && humanizeSize(torrentSize)}
|
</div>
|
||||||
</TorrentCardDescriptionContent>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span>
|
<div className='description-statistics-element-wrapper'>
|
||||||
<TorrentCardDescriptionLabel>Speed</TorrentCardDescriptionLabel>
|
<div className='description-section-name'>Speed</div>
|
||||||
<TorrentCardDescriptionContent>
|
<div className='description-statistics-element-value'>
|
||||||
{downloadSpeed > 0 ? humanizeSize(downloadSpeed) : '---'}
|
{downloadSpeed > 0 ? humanizeSize(downloadSpeed) : '---'}
|
||||||
</TorrentCardDescriptionContent>
|
</div>
|
||||||
</span>
|
</div>
|
||||||
|
|
||||||
<span>
|
<div className='description-statistics-element-wrapper'>
|
||||||
<TorrentCardDescriptionLabel>Peers</TorrentCardDescriptionLabel>
|
<div className='description-section-name'>Peers</div>
|
||||||
<TorrentCardDescriptionContent>{getPeerString(torrent) || '---'}</TorrentCardDescriptionContent>
|
<div className='description-statistics-element-value'>{getPeerString(torrent) || '---'}</div>
|
||||||
</span>
|
</div>
|
||||||
</TorrentCardDetails>
|
</div>
|
||||||
</TorrentCardDescription>
|
</TorrentCardDescription>
|
||||||
</TorrentCard>
|
</TorrentCard>
|
||||||
|
|
||||||
|
|||||||
@@ -4,22 +4,26 @@ export const TorrentCard = styled.div`
|
|||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: 120px 260px 1fr;
|
||||||
grid-template-rows: 175px minmax(min-content, 1fr);
|
grid-template-rows: 180px;
|
||||||
grid-template-areas:
|
grid-template-areas: 'poster description buttons';
|
||||||
'poster buttons'
|
|
||||||
'description description';
|
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
background: #3fb57a;
|
background: #3fb57a;
|
||||||
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%);
|
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%);
|
||||||
|
|
||||||
@media (max-width: 600px), (max-height: 500px) {
|
@media (max-width: 1260px), (max-height: 500px) {
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
'poster description'
|
'poster description'
|
||||||
'buttons buttons';
|
'buttons buttons';
|
||||||
grid-template-columns: 25% 1fr;
|
|
||||||
grid-template-rows: 100px min-content;
|
grid-template-columns: 70px 1fr;
|
||||||
|
grid-template-rows: 110px max-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 770px) {
|
||||||
|
grid-template-columns: 60px 1fr;
|
||||||
|
grid-template-rows: 90px max-content;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
@@ -33,7 +37,9 @@ export const TorrentCardPoster = styled.div`
|
|||||||
isPoster
|
isPoster
|
||||||
? css`
|
? css`
|
||||||
img {
|
img {
|
||||||
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
@@ -41,26 +47,27 @@ export const TorrentCardPoster = styled.div`
|
|||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
background: #74c39c;
|
background: #74c39c;
|
||||||
border: 1px solid;
|
border: 1px solid #337a57;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
transform: translateY(-3px);
|
transform: translateY(-3px);
|
||||||
}
|
}
|
||||||
`};
|
`};
|
||||||
|
|
||||||
@media (max-width: 600px), (max-height: 500px) {
|
@media (max-width: 1260px), (max-height: 500px) {
|
||||||
svg {
|
svg {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export const TorrentCardButtons = styled.div`
|
export const TorrentCardButtons = styled.div`
|
||||||
grid-area: buttons;
|
grid-area: buttons;
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
|
|
||||||
@media (max-width: 600px), (max-height: 500px) {
|
@media (max-width: 1260px), (max-height: 500px) {
|
||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(3, 1fr);
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
export const TorrentCardDescription = styled.div`
|
export const TorrentCardDescription = styled.div`
|
||||||
@@ -68,44 +75,102 @@ export const TorrentCardDescription = styled.div`
|
|||||||
background: #74c39c;
|
background: #74c39c;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
word-break: break-word;
|
display: grid;
|
||||||
|
grid-template-rows: 55% 1fr;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
@media (max-width: 600px), (max-height: 500px) {
|
@media (max-width: 770px) {
|
||||||
|
grid-template-rows: 60% 1fr;
|
||||||
|
gap: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 770px) {
|
||||||
|
grid-template-rows: 56% 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description-title-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
|
||||||
}
|
}
|
||||||
`
|
|
||||||
|
|
||||||
export const TorrentCardDescriptionLabel = styled.div`
|
.description-section-name {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
letter-spacing: 0.4px;
|
letter-spacing: 0.4px;
|
||||||
color: #216e47;
|
color: #216e47;
|
||||||
`
|
|
||||||
|
|
||||||
export const TorrentCardDescriptionContent = styled.div`
|
@media (max-width: 770px) {
|
||||||
margin-left: 5px;
|
font-size: 0.4rem;
|
||||||
margin-bottom: 10px;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.description-torrent-title {
|
||||||
|
overflow: auto;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
|
|
||||||
|
@media (max-width: 770px) {
|
||||||
|
font-size: 0.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 600px), (max-height: 500px) {
|
@media (max-width: 600px), (max-height: 500px) {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
|
|
||||||
${({ isTitle }) =>
|
|
||||||
isTitle &&
|
|
||||||
css`
|
|
||||||
overflow: auto;
|
|
||||||
height: 45px;
|
|
||||||
`}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 410px) {
|
@media (max-width: 410px) {
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.description-statistics-wrapper {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 80px 80px 1fr;
|
||||||
|
align-self: end;
|
||||||
|
|
||||||
|
@media (max-width: 1260px), (max-height: 500px) {
|
||||||
|
grid-template-columns: 70px 70px 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 770px) {
|
||||||
|
grid-template-columns: 65px 65px 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px), (max-height: 500px) {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.description-statistics-element-wrapper {
|
||||||
|
}
|
||||||
|
|
||||||
|
.description-statistics-element-value {
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
word-break: break-all;
|
||||||
|
|
||||||
|
@media (max-width: 1260px), (max-height: 500px) {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 770px) {
|
||||||
|
font-size: 0.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px), (max-height: 500px) {
|
||||||
|
font-size: 11px;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 410px) {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export const StyledButton = styled.button`
|
export const StyledButton = styled.button`
|
||||||
@@ -121,41 +186,39 @@ export const StyledButton = styled.button`
|
|||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif;
|
font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif;
|
||||||
letter-spacing: 0.009em;
|
letter-spacing: 0.009em;
|
||||||
|
padding: 10px 20px;
|
||||||
|
|
||||||
|
:hover {
|
||||||
|
background: #2a7e54;
|
||||||
|
}
|
||||||
|
|
||||||
> :first-child {
|
> :first-child {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 600px), (max-height: 500px) {
|
@media (max-width: 1260px), (max-height: 500px) {
|
||||||
padding: 5px 0;
|
padding: 5px 10px;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
span {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> :first-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
@media (max-width: 500px) {
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 15px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:hover {
|
@media (max-width: 420px) {
|
||||||
background: #2a7e54;
|
padding: 7px 10px;
|
||||||
}
|
justify-content: center;
|
||||||
`
|
|
||||||
|
|
||||||
export const TorrentCardDetails = styled.div`
|
svg {
|
||||||
@media (max-width: 600px), (max-height: 500px) {
|
display: none;
|
||||||
display: grid;
|
}
|
||||||
grid-template-columns: repeat(3, 1fr);
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|||||||
@@ -5,24 +5,10 @@ import { torrentsHost } from 'utils/Hosts'
|
|||||||
import TorrentCard from 'components/TorrentCard'
|
import TorrentCard from 'components/TorrentCard'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import CircularProgress from '@material-ui/core/CircularProgress'
|
import CircularProgress from '@material-ui/core/CircularProgress'
|
||||||
|
import { TorrentListWrapper } from 'App/style'
|
||||||
const TorrentListWrapper = styled.div`
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, 350px);
|
|
||||||
gap: 30px;
|
|
||||||
|
|
||||||
@media (max-width: 600px), (max-height: 500px) {
|
|
||||||
gap: 10px;
|
|
||||||
grid-template-columns: repeat(auto-fit, 310px);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 410px) {
|
|
||||||
grid-template-columns: minmax(min-content, 290px);
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const CenteredGrid = styled.div`
|
const CenteredGrid = styled.div`
|
||||||
height: 75vh;
|
height: 100%;
|
||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
`
|
`
|
||||||
@@ -63,7 +49,9 @@ export default function TorrentList() {
|
|||||||
<Typography>Offline</Typography>
|
<Typography>Offline</Typography>
|
||||||
</CenteredGrid>
|
</CenteredGrid>
|
||||||
) : !torrents.length ? (
|
) : !torrents.length ? (
|
||||||
|
<CenteredGrid>
|
||||||
<Typography>No torrents added</Typography>
|
<Typography>No torrents added</Typography>
|
||||||
|
</CenteredGrid>
|
||||||
) : (
|
) : (
|
||||||
<TorrentListWrapper>
|
<TorrentListWrapper>
|
||||||
{torrents.map(torrent => (
|
{torrents.map(torrent => (
|
||||||
|
|||||||
@@ -8,3 +8,6 @@ export function getPeerString(torrent) {
|
|||||||
if (!torrent || !torrent.connected_seeders) return ''
|
if (!torrent || !torrent.connected_seeders) return ''
|
||||||
return `[${torrent.connected_seeders}] ${torrent.active_peers} / ${torrent.total_peers}`
|
return `[${torrent.connected_seeders}] ${torrent.active_peers} / ${torrent.total_peers}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const shortenText = (text, sympolAmount) =>
|
||||||
|
text.slice(0, sympolAmount) + (text.length > sympolAmount ? '...' : '')
|
||||||
|
|||||||
@@ -10282,6 +10282,11 @@ react-dev-utils@^11.0.3:
|
|||||||
strip-ansi "6.0.0"
|
strip-ansi "6.0.0"
|
||||||
text-table "0.2.0"
|
text-table "0.2.0"
|
||||||
|
|
||||||
|
react-div-100vh@^0.6.0:
|
||||||
|
version "0.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-div-100vh/-/react-div-100vh-0.6.0.tgz#577972d8ac17693edcd44061c1a4b5a7578e49ec"
|
||||||
|
integrity sha512-ErV0VTNXUd8jZqofC0ExZr5u+XDD2kN2te4SbwtqsyTm0UOjVYu53kP+FalGQrTe+DoMG8VYR2dITcAFu7c/5w==
|
||||||
|
|
||||||
react-dom@^17.0.2:
|
react-dom@^17.0.2:
|
||||||
version "17.0.2"
|
version "17.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
|
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
|
||||||
|
|||||||
Reference in New Issue
Block a user