diff --git a/web/src/components/Add/AddDialog.jsx b/web/src/components/Add/AddDialog.jsx
index 7766ed5..a4c1aa1 100644
--- a/web/src/components/Add/AddDialog.jsx
+++ b/web/src/components/Add/AddDialog.jsx
@@ -5,7 +5,6 @@ import Dialog from '@material-ui/core/Dialog'
import { torrentsHost, torrentUploadHost } from 'utils/Hosts'
import axios from 'axios'
import { useTranslation } from 'react-i18next'
-import styled, { css } from 'styled-components'
import { NoImageIcon, AddItemIcon, TorrentIcon } from 'icons'
import debounce from 'lodash/debounce'
import { v4 as uuidv4 } from 'uuid'
@@ -14,260 +13,25 @@ import { Cancel as CancelIcon } from '@material-ui/icons'
import { useDropzone } from 'react-dropzone'
import { useMediaQuery } from '@material-ui/core'
-const Header = styled.div`
- background: #00a572;
- color: rgba(0, 0, 0, 0.87);
- font-size: 20px;
- color: #fff;
- font-weight: 500;
- 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;
-`
-
-const Content = styled.div`
- background: linear-gradient(145deg, #e4f6ed, #b5dec9);
- flex: 1;
- display: grid;
- grid-template-columns: repeat(2, 1fr);
- border-bottom: 1px solid rgba(0, 0, 0, 0.12);
- overflow: auto;
-
- @media (max-width: 930px) {
- grid-template-columns: 1fr;
- }
-`
-
-const LeftSide = styled.div`
- padding: 0 20px 20px 20px;
- border-right: 1px solid rgba(0, 0, 0, 0.12);
-`
-const RightSide = styled.div`
- display: flex;
- flex-direction: column;
-`
-
-const RightSideBottomSectionBasicStyles = css`
- transition: transform 0.3s;
- padding: 20px;
- height: 100%;
- display: grid;
-`
-
-const RightSideBottomSectionNoFile = styled.div`
- ${RightSideBottomSectionBasicStyles}
- border: 4px dashed transparent;
-
- ${({ isDragActive }) => isDragActive && `border: 4px dashed green`};
-
- justify-items: center;
- grid-template-rows: 100px 1fr;
- cursor: pointer;
-
- :hover {
- background-color: rgba(0, 0, 0, 0.04);
- svg {
- transform: translateY(-4%);
- }
- }
-
- @media (max-width: 930px) {
- height: 400px;
- place-items: center;
- grid-template-rows: 40% 1fr;
- }
-`
-
-const RightSideBottomSectionFileSelected = styled.div`
- ${RightSideBottomSectionBasicStyles}
- place-items: center;
-
- @media (max-width: 930px) {
- height: 400px;
- }
-`
-
-const TorrentIconWrapper = styled.div`
- position: relative;
-`
-
-const CancelIconWrapper = styled.div`
- position: absolute;
- top: -9px;
- left: 10px;
- cursor: pointer;
-
- > svg {
- transition: all 0.3s;
- fill: rgba(0, 0, 0, 0.7);
-
- :hover {
- fill: rgba(0, 0, 0, 0.6);
- }
- }
-`
-
-const IconWrapper = styled.div`
- display: grid;
- justify-items: center;
- align-content: start;
- gap: 10px;
- align-self: start;
-
- svg {
- transition: all 0.3s;
- }
-`
-
-const RightSideTopSection = styled.div`
- background: #e3f2eb;
- padding: 0 20px 20px 20px;
- transition: all 0.3s;
-
- ${({ active }) => active && 'box-shadow: 0 8px 10px -9px rgba(0, 0, 0, 0.5)'};
-`
-
-const PosterWrapper = styled.div`
- margin-top: 20px;
- display: grid;
- grid-template-columns: max-content 1fr;
- grid-template-rows: 300px max-content;
- column-gap: 5px;
- position: relative;
- margin-bottom: 20px;
-
- grid-template-areas:
- 'poster suggestions'
- 'clear empty';
-
- @media (max-width: 540px) {
- grid-template-columns: 1fr;
- gap: 5px 0;
- justify-items: center;
- grid-template-areas:
- 'poster'
- 'clear'
- 'suggestions';
- }
-`
-const PosterSuggestions = styled.div`
- display: grid;
- grid-area: suggestions;
- grid-template-columns: repeat(3, max-content);
- grid-template-rows: repeat(4, max-content);
- gap: 5px;
-
- @media (max-width: 540px) {
- grid-template-columns: repeat(5, max-content);
- }
- @media (max-width: 375px) {
- grid-template-columns: repeat(4, max-content);
- }
-`
-const PosterSuggestionsItem = styled.div`
- cursor: pointer;
- width: 71px;
- height: 71px;
-
- @media (max-width: 430px) {
- width: 60px;
- height: 60px;
- }
-
- @media (max-width: 375px) {
- width: 71px;
- height: 71px;
- }
-
- @media (max-width: 355px) {
- width: 60px;
- height: 60px;
- }
-
- img {
- transition: all 0.3s;
- border-radius: 5px;
- width: 100%;
- height: 100%;
- object-fit: cover;
-
- :hover {
- filter: brightness(130%);
- }
- }
-`
-
-export const Poster = styled.div`
- ${({ poster }) => css`
- border-radius: 5px;
- overflow: hidden;
- width: 200px;
- grid-area: poster;
-
- ${poster
- ? css`
- img {
- width: 200px;
- object-fit: cover;
- border-radius: 5px;
- height: 100%;
- }
- `
- : css`
- display: grid;
- place-items: center;
- background: #74c39c;
-
- svg {
- transform: scale(1.5) translateY(-3px);
- }
- `}
- `}
-`
-
-const ClearPosterButton = styled(Button)`
- grid-area: clear;
- justify-self: center;
- transform: translateY(-50%);
- position: absolute;
- ${({ showbutton }) => !showbutton && 'display: none'};
-
- @media (max-width: 540px) {
- transform: translateY(-140%);
- }
-`
-
-const ButtonWrapper = styled.div`
- padding: 20px;
- display: flex;
- justify-content: flex-end;
-
- > :not(:last-child) {
- margin-right: 10px;
- }
-`
-
-const getMoviePosters = (movieName, language = 'en') => {
- const request = `${`http://api.themoviedb.org/3/search/multi?api_key=${process.env.REACT_APP_TMDB_API_KEY}`}&language=${language}&include_image_language=${language},null&query=${movieName}`
-
- return axios
- .get(request)
- .then(({ data: { results } }) =>
- results.filter(el => el.poster_path).map(el => `https://image.tmdb.org/t/p/w300${el.poster_path}`),
- )
- .catch(() => null)
-}
-
-const checkImageURL = async url => {
- if (!url || !url.match(/.(jpg|jpeg|png|gif)$/i)) return false
-
- try {
- await fetch(url)
- return true
- } catch (e) {
- return false
- }
-}
+import {
+ ButtonWrapper,
+ CancelIconWrapper,
+ ClearPosterButton,
+ Content,
+ Header,
+ IconWrapper,
+ LeftSide,
+ Poster,
+ PosterSuggestions,
+ PosterSuggestionsItem,
+ PosterWrapper,
+ RightSide,
+ RightSideBottomSectionFileSelected,
+ RightSideBottomSectionNoFile,
+ RightSideTopSection,
+ TorrentIconWrapper,
+} from './style'
+import { checkImageURL, getMoviePosters } from './helpers'
export default function AddDialog({ handleClose }) {
const { t } = useTranslation()
@@ -338,16 +102,18 @@ export default function AddDialog({ handleClose }) {
const handleSave = () => {
if (selectedFile) {
+ // file save
const data = new FormData()
data.append('save', 'true')
data.append('file', selectedFile)
title && data.append('title', title)
posterUrl && data.append('poster', posterUrl)
- axios.post(torrentUploadHost(), data).finally(() => handleClose())
+ axios.post(torrentUploadHost(), data).finally(handleClose)
} else {
+ // link save
axios
.post(torrentsHost(), { action: 'add', link: torrentSource, title, poster: posterUrl, save_to_db: true })
- .finally(() => handleClose())
+ .finally(handleClose)
}
}
@@ -396,6 +162,7 @@ export default function AddDialog({ handleClose }) {
{isPosterUrlCorrect ?
: }
+
{posterList
?.filter(url => url !== posterUrl)
diff --git a/web/src/components/Add/helpers.js b/web/src/components/Add/helpers.js
new file mode 100644
index 0000000..215d2f8
--- /dev/null
+++ b/web/src/components/Add/helpers.js
@@ -0,0 +1,23 @@
+import axios from 'axios'
+
+export const getMoviePosters = (movieName, language = 'en') => {
+ const request = `${`http://api.themoviedb.org/3/search/multi?api_key=${process.env.REACT_APP_TMDB_API_KEY}`}&language=${language}&include_image_language=${language},null&query=${movieName}`
+
+ return axios
+ .get(request)
+ .then(({ data: { results } }) =>
+ results.filter(el => el.poster_path).map(el => `https://image.tmdb.org/t/p/w300${el.poster_path}`),
+ )
+ .catch(() => null)
+}
+
+export const checkImageURL = async url => {
+ if (!url || !url.match(/.(jpg|jpeg|png|gif)$/i)) return false
+
+ try {
+ await fetch(url)
+ return true
+ } catch (e) {
+ return false
+ }
+}
diff --git a/web/src/components/Add/style.js b/web/src/components/Add/style.js
new file mode 100644
index 0000000..bb475f4
--- /dev/null
+++ b/web/src/components/Add/style.js
@@ -0,0 +1,236 @@
+import { Button } from '@material-ui/core'
+import styled, { css } from 'styled-components'
+
+export const Header = styled.div`
+ background: #00a572;
+ color: rgba(0, 0, 0, 0.87);
+ font-size: 20px;
+ color: #fff;
+ font-weight: 500;
+ 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`
+ background: linear-gradient(145deg, #e4f6ed, #b5dec9);
+ flex: 1;
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ border-bottom: 1px solid rgba(0, 0, 0, 0.12);
+ overflow: auto;
+
+ @media (max-width: 930px) {
+ grid-template-columns: 1fr;
+ }
+`
+
+export const LeftSide = styled.div`
+ padding: 0 20px 20px 20px;
+ border-right: 1px solid rgba(0, 0, 0, 0.12);
+`
+export const RightSide = styled.div`
+ display: flex;
+ flex-direction: column;
+`
+
+export const RightSideBottomSectionBasicStyles = css`
+ transition: transform 0.3s;
+ padding: 20px;
+ height: 100%;
+ display: grid;
+`
+
+export const RightSideBottomSectionNoFile = styled.div`
+ ${RightSideBottomSectionBasicStyles}
+ border: 4px dashed transparent;
+ text-align: center;
+
+ ${({ isDragActive }) => isDragActive && `border: 4px dashed green`};
+
+ justify-items: center;
+ grid-template-rows: 100px 1fr;
+ cursor: pointer;
+
+ :hover {
+ background-color: rgba(0, 0, 0, 0.04);
+ svg {
+ transform: translateY(-4%);
+ }
+ }
+
+ @media (max-width: 930px) {
+ height: 400px;
+ place-items: center;
+ grid-template-rows: 40% 1fr;
+ }
+`
+
+export const RightSideBottomSectionFileSelected = styled.div`
+ ${RightSideBottomSectionBasicStyles}
+ place-items: center;
+
+ @media (max-width: 930px) {
+ height: 400px;
+ }
+`
+
+export const TorrentIconWrapper = styled.div`
+ position: relative;
+`
+
+export const CancelIconWrapper = styled.div`
+ position: absolute;
+ top: -9px;
+ left: 10px;
+ cursor: pointer;
+
+ > svg {
+ transition: all 0.3s;
+ fill: rgba(0, 0, 0, 0.7);
+
+ :hover {
+ fill: rgba(0, 0, 0, 0.6);
+ }
+ }
+`
+
+export const IconWrapper = styled.div`
+ display: grid;
+ justify-items: center;
+ align-content: start;
+ gap: 10px;
+ align-self: start;
+
+ svg {
+ transition: all 0.3s;
+ }
+`
+
+export const RightSideTopSection = styled.div`
+ background: #e3f2eb;
+ padding: 0 20px 20px 20px;
+ transition: all 0.3s;
+
+ ${({ active }) => active && 'box-shadow: 0 8px 10px -9px rgba(0, 0, 0, 0.5)'};
+`
+
+export const PosterWrapper = styled.div`
+ margin-top: 20px;
+ display: grid;
+ grid-template-columns: max-content 1fr;
+ grid-template-rows: 300px max-content;
+ column-gap: 5px;
+ position: relative;
+ margin-bottom: 20px;
+
+ grid-template-areas:
+ 'poster suggestions'
+ 'clear empty';
+
+ @media (max-width: 540px) {
+ grid-template-columns: 1fr;
+ gap: 5px 0;
+ justify-items: center;
+ grid-template-areas:
+ 'poster'
+ 'clear'
+ 'suggestions';
+ }
+`
+export const PosterSuggestions = styled.div`
+ display: grid;
+ grid-area: suggestions;
+ grid-template-columns: repeat(3, max-content);
+ grid-template-rows: repeat(4, max-content);
+ gap: 5px;
+
+ @media (max-width: 540px) {
+ grid-template-columns: repeat(5, max-content);
+ }
+ @media (max-width: 375px) {
+ grid-template-columns: repeat(4, max-content);
+ }
+`
+export const PosterSuggestionsItem = styled.div`
+ cursor: pointer;
+ width: 71px;
+ height: 71px;
+
+ @media (max-width: 430px) {
+ width: 60px;
+ height: 60px;
+ }
+
+ @media (max-width: 375px) {
+ width: 71px;
+ height: 71px;
+ }
+
+ @media (max-width: 355px) {
+ width: 60px;
+ height: 60px;
+ }
+
+ img {
+ transition: all 0.3s;
+ border-radius: 5px;
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+
+ :hover {
+ filter: brightness(130%);
+ }
+ }
+`
+
+export const Poster = styled.div`
+ ${({ poster }) => css`
+ border-radius: 5px;
+ overflow: hidden;
+ width: 200px;
+ grid-area: poster;
+
+ ${poster
+ ? css`
+ img {
+ width: 200px;
+ object-fit: cover;
+ border-radius: 5px;
+ height: 100%;
+ }
+ `
+ : css`
+ display: grid;
+ place-items: center;
+ background: #74c39c;
+
+ svg {
+ transform: scale(1.5) translateY(-3px);
+ }
+ `}
+ `}
+`
+
+export const ClearPosterButton = styled(Button)`
+ grid-area: clear;
+ justify-self: center;
+ transform: translateY(-50%);
+ position: absolute;
+ ${({ showbutton }) => !showbutton && 'display: none'};
+
+ @media (max-width: 540px) {
+ transform: translateY(-140%);
+ }
+`
+
+export const ButtonWrapper = styled.div`
+ padding: 20px;
+ display: flex;
+ justify-content: flex-end;
+
+ > :not(:last-child) {
+ margin-right: 10px;
+ }
+`
diff --git a/web/src/components/DialogTorrentDetailsContent/DetailedView/index.jsx b/web/src/components/DialogTorrentDetailsContent/DetailedView/index.jsx
index a65a7e5..aa037ed 100644
--- a/web/src/components/DialogTorrentDetailsContent/DetailedView/index.jsx
+++ b/web/src/components/DialogTorrentDetailsContent/DetailedView/index.jsx
@@ -11,14 +11,14 @@ import {
DownlodSpeedWidget,
} from '../widgets'
-export default function Test({
+export default function DetailedView({
downloadSpeed,
uploadSpeed,
torrent,
torrentSize,
PiecesCount,
PiecesLength,
- statString,
+ stat,
cache,
}) {
return (
@@ -32,7 +32,7 @@ export default function Test({
-
+
diff --git a/web/src/components/DialogTorrentDetailsContent/index.jsx b/web/src/components/DialogTorrentDetailsContent/index.jsx
index e1cdd42..f4ee8b7 100644
--- a/web/src/components/DialogTorrentDetailsContent/index.jsx
+++ b/web/src/components/DialogTorrentDetailsContent/index.jsx
@@ -54,7 +54,6 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) {
stat,
download_speed: downloadSpeed,
upload_speed: uploadSpeed,
- stat_string: statString,
torrent_size: torrentSize,
file_stats: torrentFileList,
} = torrent
@@ -133,7 +132,7 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) {
torrentSize={torrentSize}
PiecesCount={PiecesCount}
PiecesLength={PiecesLength}
- statString={statString}
+ stat={stat}
cache={cache}
/>
) : (
@@ -156,7 +155,7 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) {
-
+
diff --git a/web/src/components/DialogTorrentDetailsContent/widgets.jsx b/web/src/components/DialogTorrentDetailsContent/widgets.jsx
index a8d5f69..a4a1437 100644
--- a/web/src/components/DialogTorrentDetailsContent/widgets.jsx
+++ b/web/src/components/DialogTorrentDetailsContent/widgets.jsx
@@ -9,6 +9,7 @@ import {
} from '@material-ui/icons'
import { getPeerString, humanizeSize } from 'utils/Utils'
import { useTranslation } from 'react-i18next'
+import { GETTING_INFO, IN_DB, CLOSED, PRELOAD, WORKING } from 'torrentStates'
import StatisticsField from './StatisticsField'
@@ -69,17 +70,25 @@ export const PiecesLengthWidget = ({ data }) => {
)
}
-export const StatusWidget = ({ data }) => {
+export const StatusWidget = ({ stat }) => {
const { t } = useTranslation()
- let i18nd = data
- if (data.toLowerCase() === 'torrent added') i18nd = t('TorrentAdded')
- else if (data.toLowerCase() === 'torrent getting info') i18nd = t('TorrentGettingInfo')
- else if (data.toLowerCase() === 'torrent preload') i18nd = t('TorrentPreload')
- else if (data.toLowerCase() === 'torrent working') i18nd = t('TorrentWorking')
- else if (data.toLowerCase() === 'torrent closed') i18nd = t('TorrentClosed')
- else if (data.toLowerCase() === 'torrent in db') i18nd = t('TorrentInDb')
+
+ const values = {
+ [GETTING_INFO]: t('TorrentGettingInfo'),
+ [PRELOAD]: t('TorrentPreload'),
+ [WORKING]: t('TorrentWorking'),
+ [CLOSED]: t('TorrentClosed'),
+ [IN_DB]: t('TorrentInDb'),
+ }
+
return (
-
+
)
}