From 57e9bc2dc17313e8de8932d1de5f63f9dcc30fae Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Wed, 14 Jul 2021 23:09:42 +0100 Subject: [PATCH] Better show support --- public/index.html | 2 +- src/components/Card.css | 2 +- src/components/EpisodeSelector.css | 0 src/components/EpisodeSelector.js | 13 ++++ src/components/InputBox.css | 60 +++------------- src/components/InputBox.js | 34 ++------- src/components/MovieRow.css | 14 ++-- src/components/MovieRow.js | 1 - src/components/NumberSelector.css | 48 +++++++++++++ src/components/NumberSelector.js | 20 ++++++ src/components/Progress.css | 6 +- src/components/Title.css | 9 ++- src/components/TypeSelector.css | 59 ++++++++++++++++ src/components/TypeSelector.js | 24 +++++++ src/components/VideoElement.css | 2 +- src/components/VideoElement.js | 15 +++- src/hooks/useMovie.js | 2 +- src/index.css | 29 +++++++- src/lib/lookMovie.js | 39 +++++++++-- src/service-worker.js | 72 ------------------- src/views/Movie.css | 3 + src/views/Movie.js | 71 +++++++++++++++++-- src/views/Search.css | 2 +- src/views/Search.js | 64 ++++++++++++----- yarn.lock | 109 ++++++++++++++++++++++++++++- 25 files changed, 495 insertions(+), 205 deletions(-) create mode 100644 src/components/EpisodeSelector.css create mode 100644 src/components/EpisodeSelector.js create mode 100644 src/components/NumberSelector.css create mode 100644 src/components/NumberSelector.js create mode 100644 src/components/TypeSelector.css create mode 100644 src/components/TypeSelector.js delete mode 100644 src/service-worker.js diff --git a/public/index.html b/public/index.html index 4c313487..885b2d5b 100644 --- a/public/index.html +++ b/public/index.html @@ -20,7 +20,7 @@ movie-web - +
diff --git a/src/components/Card.css b/src/components/Card.css index 710f0e49..6dabda2b 100644 --- a/src/components/Card.css +++ b/src/components/Card.css @@ -1,5 +1,5 @@ .card { - background-color: #22232A; + background-color: var(--card); padding: 3rem 4rem; margin: 0 3rem; border-radius: 10px; diff --git a/src/components/EpisodeSelector.css b/src/components/EpisodeSelector.css new file mode 100644 index 00000000..e69de29b diff --git a/src/components/EpisodeSelector.js b/src/components/EpisodeSelector.js new file mode 100644 index 00000000..3881c64c --- /dev/null +++ b/src/components/EpisodeSelector.js @@ -0,0 +1,13 @@ +import React from 'react'; +import { TypeSelector } from './TypeSelector'; +import { NumberSelector } from './NumberSelector'; +import './EpisodeSelector.css' + +export function EpisodeSelector({ setSeason, setEpisode, seasons, episodes, currentSeason, currentEpisode }) { + return ( +
+ ({ value: v.toString(), label: `Season ${v}`}))} selected={currentSeason}/>

+ setEpisode({episode: e, season: currentSeason})} choices={episodes.map(v=>({ value: v.toString(), label: v}))} selected={currentEpisode.season === currentSeason?currentEpisode.episode:null}/> +
+ ) +} diff --git a/src/components/InputBox.css b/src/components/InputBox.css index f1480b9c..4339c9e7 100644 --- a/src/components/InputBox.css +++ b/src/components/InputBox.css @@ -19,8 +19,8 @@ .inputTextBox { border-width: 0; outline: none; - background-color: #36363e; - color: white; + background-color: var(--content); + color: var(--text); padding: .7rem 1.5rem; height: auto; flex: 1; @@ -28,52 +28,21 @@ } .inputSearchButton { - background-color: #A73B83; + background-color: var(--button); border-width: 0; - color: white; + color: var(--text); padding: .5rem 2.1rem; font-weight: bold; cursor: pointer; } -.inputDropdown { - border-width: 0; - outline: none; - background-color: #36363e; - color: white; - padding: .7rem 1rem; - height: auto; - width: 25%; - color: white; - font-weight: bold; - cursor: pointer; -} - -.inputOptionBox { - border-width: 0; - outline: none; - background-color: #36363e; - color: white; - height: auto; - width: 10%; - box-sizing: border-box; -} - -.inputDropdown:hover { - background-color: #3C3D44; -} - .inputSearchButton:hover { - background-color: #9C3179; + background-color: var(--button-hover); } .inputTextBox:hover { - background-color: #3C3D44; -} - -.inputOptionBox:hover { - background-color: #3C3D44; + background-color: var(--content-hover); } .inputSearchButton .text > .arrow { @@ -83,11 +52,13 @@ right: -0.8rem; bottom: -0.2rem; } + .inputSearchButton .text { display: flex; position: relative; transition: transform 0.2s ease-in-out; } + .inputSearchButton:hover .text > .arrow { transform: translateX(8px); opacity: 1; @@ -98,7 +69,7 @@ } .inputSearchButton:active { - background-color: #8b286a; + background-color: var(--button-active); } @media screen and (max-width: 700px) { @@ -121,17 +92,4 @@ margin-top: .5rem; width: 100%; } - - .inputDropdown { - width: 100%; - padding: .7rem 1.5rem; - } - - .inputOptionBox { - margin-top: .5rem; - width: 50%; - /* align-items:stretch; */ - align-self: center; - padding: .7rem 1.5rem; - } } diff --git a/src/components/InputBox.js b/src/components/InputBox.js index a42900b9..f1f5d2ea 100644 --- a/src/components/InputBox.js +++ b/src/components/InputBox.js @@ -5,22 +5,13 @@ import './InputBox.css' // props = { onSubmit: (str) => {}, placeholder: string} export function InputBox({ onSubmit, placeholder }) { const [searchTerm, setSearchTerm] = React.useState(""); - const [type, setType] = React.useState("movie"); - const [season, setSeason] = React.useState(""); - const [episode, setEpisode] = React.useState(""); - - const showContentType = type === "show" ? false : true; return (
{ e.preventDefault(); - onSubmit(searchTerm, type, season, episode) + onSubmit(searchTerm) return false; }}> - setSearchTerm(e.target.value)} required /> - setSeason(e.target.value)} - hidden={showContentType} - required={!showContentType} - /> - setEpisode(e.target.value)} - hidden={showContentType} - required={!showContentType} /> - +
) } diff --git a/src/components/MovieRow.css b/src/components/MovieRow.css index 45986130..99a6cad0 100644 --- a/src/components/MovieRow.css +++ b/src/components/MovieRow.css @@ -1,8 +1,8 @@ .movieRow { display: flex; border-radius: 5px; - background-color: #35363D; - color: white; + background-color: var(--content); + color: var(--text); padding: .8rem 1.5rem; margin-top: .5rem; cursor: pointer; @@ -23,11 +23,11 @@ } .movieRow .left .year { - color: #BCBECB; + color: var(--text-secondary); } .movieRow .watch { - color: #D678B7; + color: var(--theme-color-text); display: flex; align-items: center; } @@ -43,7 +43,7 @@ } .movieRow:hover { - background-color: #3A3B40; + background-color: var(--content-hover); } .movieRow:hover .watch .arrow { @@ -51,8 +51,8 @@ } .attribute { - color: white; - background-color: #D678B7; + color: var(--text); + background-color: var(--theme-color); font-size: .75rem; padding: .25rem; border-radius: 10px; diff --git a/src/components/MovieRow.js b/src/components/MovieRow.js index c304aa4d..a3ae80bd 100644 --- a/src/components/MovieRow.js +++ b/src/components/MovieRow.js @@ -12,7 +12,6 @@ export function MovieRow(props) { ({props.year})
-

Watch {props.type}

diff --git a/src/components/NumberSelector.css b/src/components/NumberSelector.css new file mode 100644 index 00000000..4f8e62f9 --- /dev/null +++ b/src/components/NumberSelector.css @@ -0,0 +1,48 @@ +.numberSelector { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(2.5rem, 1fr)); + gap: 5px; + position: relative; + margin-bottom: 1.5rem; +} + +.numberSelector .choiceWrapper { + position: relative; +} + +.numberSelector .choiceWrapper::before { + content: ''; + display: block; + width: 100%; + padding-bottom: 100%; +} + +.numberSelector .choice { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: var(--choice); + margin-right: 5px; + padding: .2rem; + display: flex; + justify-content: center; + align-items: center; + text-align: center; + color: var(--text); + font-weight: bold; + cursor: pointer; + user-select: none; + border-radius: 10%; + box-sizing: border-box; +} + +.numberSelector .choice:hover { + background-color: var(--choice-hover); +} + +.numberSelector .choice.selected { + color: var(--text); + background-color: var(--choice-hover); +} diff --git a/src/components/NumberSelector.js b/src/components/NumberSelector.js new file mode 100644 index 00000000..ecbf9658 --- /dev/null +++ b/src/components/NumberSelector.js @@ -0,0 +1,20 @@ +import React from 'react'; +// import { Arrow } from './Arrow'; +import './NumberSelector.css' + +// setType: (txt: string) => void +// choices: { label: string, value: string }[] +// selected: string +export function NumberSelector({ setType, choices, selected }) { + return ( +
+ {choices.map(v=>( +
+
setType(v.value)}> + {v.label} +
+
+ ))} +
+ ) +} diff --git a/src/components/Progress.css b/src/components/Progress.css index 9c0b84f4..a0116519 100644 --- a/src/components/Progress.css +++ b/src/components/Progress.css @@ -1,6 +1,6 @@ .progress { text-align: center; - color: #BCBECB; + color: var(--text-secondary); display: flex; align-items: center; justify-content: center; @@ -32,12 +32,12 @@ .progress .bar .bar-inner { transition: width 400ms ease-in-out, background-color 100ms ease-in-out; - background-color: #D463AE; + background-color: var(--theme-color); border-radius: 10px; height: 100%; width: 0%; } .progress.failed .bar .bar-inner { - background-color: #d85b66; + background-color: var(--failed); } diff --git a/src/components/Title.css b/src/components/Title.css index 6796dce9..c5691634 100644 --- a/src/components/Title.css +++ b/src/components/Title.css @@ -1,6 +1,6 @@ .title { font-size: 2rem; - color: white; + color: var(--text); /* max-width: 20rem; */ margin: 0; padding: 0; @@ -10,9 +10,13 @@ .title-size-medium { font-size: 1.5rem; } +.title-size-small { + font-size: 1.1rem; + color: #afb1b8; +} .title-accent { - color: #E880C5; + color: var(--theme-color); font-weight: 600; margin: 0; padding: 0; @@ -34,3 +38,4 @@ .title-accent.title-accent-link:hover .arrow { transform: translateY(.1rem) translateX(-.5rem); } + diff --git a/src/components/TypeSelector.css b/src/components/TypeSelector.css new file mode 100644 index 00000000..39273f17 --- /dev/null +++ b/src/components/TypeSelector.css @@ -0,0 +1,59 @@ + +/* TODO better responsiveness, use dropdown if more than 5 options */ +.typeSelector { + display: inline-flex; + position: relative; + margin-bottom: 1.5rem; + max-width: 100%; + flex-wrap: wrap; +} + +.typeSelector::before { + content: ""; + position: absolute; + width: 100%; + bottom: 0; + background-color: #3a3c46; + height: 4px; + border-radius: 2px; +} + +.typeSelector .choice { + width: 7rem; + height: 3rem; + padding: .3rem .2rem; + display: flex; + justify-content: center; + align-items: center; + text-align: center; + box-sizing: border-box; + color: #585A67; + font-weight: bold; + cursor: pointer; + user-select: none; +} + +.typeSelector .choice:hover { + color: #afb1b8; +} + +.typeSelector .choice.selected { + color: var(--text); +} + +.typeSelector .selectedBar { + position: absolute; + height: 4px; + width: 7rem; + background-color: var(--theme-color); + border-radius: 2px; + bottom: 0; + transition: transform 150ms ease-in-out; +} + +@media screen and (max-width: 700px) { + .typeSelector { + width: 80%; + display: block; + } +} diff --git a/src/components/TypeSelector.js b/src/components/TypeSelector.js new file mode 100644 index 00000000..ee96b275 --- /dev/null +++ b/src/components/TypeSelector.js @@ -0,0 +1,24 @@ +import React from 'react'; +// import { Arrow } from './Arrow'; +import './TypeSelector.css' + +// setType: (txt: string) => void +// choices: { label: string, value: string }[] +// selected: string +export function TypeSelector({ setType, choices, selected }) { + const selectedIndex = choices.findIndex(v=>v.value===selected); + const transformStyles = { + opacity: selectedIndex!==-1?1:0, + transform: `translateX(${selectedIndex!==-1?selectedIndex*7:0}rem)` + } + return ( +
+ {choices.map(v=>( +
setType(v.value)}> + {v.label} +
+ ))} +
+
+ ) +} diff --git a/src/components/VideoElement.css b/src/components/VideoElement.css index f3a684a6..bb829039 100644 --- a/src/components/VideoElement.css +++ b/src/components/VideoElement.css @@ -5,6 +5,6 @@ } .videoElementText { - color: white; + color: var(--text); margin: 0; } diff --git a/src/components/VideoElement.js b/src/components/VideoElement.js index 2bdba8da..c568302e 100644 --- a/src/components/VideoElement.js +++ b/src/components/VideoElement.js @@ -3,13 +3,14 @@ import Hls from 'hls.js' import './VideoElement.css' // streamUrl: string -export function VideoElement({ streamUrl }) { +// loading: boolean +export function VideoElement({ streamUrl, loading }) { const videoRef = React.useRef(null); const [error, setError] = React.useState(false); React.useEffect(() => { setError(false) - if (!videoRef || !videoRef.current) return; + if (!videoRef || !videoRef.current || !streamUrl || streamUrl.length === 0 || loading) return; const hls = new Hls(); @@ -23,11 +24,19 @@ export function VideoElement({ streamUrl }) { hls.attachMedia(videoRef.current); hls.loadSource(streamUrl); - }, [videoRef, streamUrl]) + }, [videoRef, streamUrl, loading]) + + // TODO make better loading/error/empty state if (error) return (

Your browser is not supported

) + if (loading) + return

Loading episode

+ + if (!streamUrl || streamUrl.length === 0) + return

No video selected

+ return (