torrent cards rewritten

This commit is contained in:
Daniel Shleifman
2021-06-02 19:19:41 +03:00
parent 8696f6cd0b
commit f0a2ba8390
13 changed files with 346 additions and 361 deletions

View File

@@ -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",

View File

@@ -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
View 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
View 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
View 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;
}
`

View File

@@ -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>
)
}

View File

@@ -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),
},
}))

View File

@@ -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 />

View File

@@ -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>

View File

@@ -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);
} }
` `

View File

@@ -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 => (

View File

@@ -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 ? '...' : '')

View File

@@ -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"