UI for stream series pages

This commit is contained in:
Sunda 2021-10-11 19:15:09 +02:00
parent 3cab6fb683
commit a3bea12645
7 changed files with 57 additions and 73 deletions

2
app.js
View File

@ -10,7 +10,7 @@ import { useTimeout } from './src/hooks/timerHooks'
export default (props) => { export default (props) => {
console.log({ props }) // console.log({ props })
const [currentVideo, setCurrentVideo] = useState(null) const [currentVideo, setCurrentVideo] = useState(null)
const [streamIsLive, setStreamIsLive] = useState(false) const [streamIsLive, setStreamIsLive] = useState(false)
const [infoActive, setInfoActive] = useState(false) const [infoActive, setInfoActive] = useState(false)

View File

@ -4,7 +4,6 @@ import { BrowserRouter, Route, Switch } from 'react-router-dom'
import Main from './app' import Main from './app'
import SeriesPage from './src/pages/SeriesPage' import SeriesPage from './src/pages/SeriesPage'
import { slugify } from './src/helpers/string'
import { useEventApi, useEventCalendar } from './src/hooks/data' import { useEventApi, useEventCalendar } from './src/hooks/data'
import { useTimeout } from './src/hooks/timerHooks' import { useTimeout } from './src/hooks/timerHooks'
import LoaderLayout from './src/pages/LoaderLayout' import LoaderLayout from './src/pages/LoaderLayout'
@ -20,7 +19,6 @@ const App = () => {
const seriesData = Object.values(seriesDataArray) const seriesData = Object.values(seriesDataArray)
console.log(seriesData)
return calLoading || eventsLoading || !minLoadTimePassed ? ( return calLoading || eventsLoading || !minLoadTimePassed ? (
<LoaderLayout /> <LoaderLayout />
@ -29,7 +27,7 @@ const App = () => {
<Switch> <Switch>
<Route exact path="/" component={Main} /> <Route exact path="/" component={Main} />
{seriesData.length ? seriesData.map(series => ( {seriesData.length ? seriesData.map(series => (
<Route exact path={`/series/${slugify(series.name)}`}> <Route exact path={`/series/${series.slug}`}>
<SeriesPage data={series} /> <SeriesPage data={series} />
</Route>)) : null} </Route>)) : null}
</Switch> </Switch>

View File

@ -17,18 +17,12 @@ import Loader from '../Loader'
import { useTimeout } from '../../hooks/timerHooks' import { useTimeout } from '../../hooks/timerHooks'
import { NdcLogo, RFLogo } from '../Logo' import { NdcLogo, RFLogo } from '../Logo'
const InfoLayout = ({ title, subtitle, children, loading }) => ( const InfoLayout = ({ title, subtitle, image, children }) => (
<Wrapper> <Wrapper>
<Content> <Content>
{loading ? ( {children}
<LoaderWrapper>
<Loader />
</LoaderWrapper>
) : (
children
)}
</Content> </Content>
<Hero> <Hero image={image}>
<div> <div>
<H1>{title}</H1> <H1>{title}</H1>
<H1 <H1

View File

@ -1,8 +1,5 @@
import styled from 'styled-components' import styled from 'styled-components'
import { colours } from '../../assets/theme' import { colours } from '../../assets/theme'
import bg from '../../assets/img/hero/2md.png'
import { H1 } from '../Text'
import Logo from '../Logo' import Logo from '../Logo'
@ -13,7 +10,7 @@ export const Wrapper = styled.div`
width: 100vw; width: 100vw;
padding: 2em; padding: 2em;
display: flex; display: flex;
background-color: ${colours.roseLight}; background-color: ${colours.midnight};
box-sizing: border-box; box-sizing: border-box;
position: fixed; position: fixed;
overflow-y: scroll; overflow-y: scroll;
@ -21,7 +18,7 @@ export const Wrapper = styled.div`
p, p,
h1, h1,
h2 { h2 {
color: ${colours.midnightDarker}; color: ${colours.rose};
} }
@media screen and (max-width: 1200px) { @media screen and (max-width: 1200px) {
@ -57,7 +54,7 @@ export const Fade = styled.div`
export const Hero = styled.div` export const Hero = styled.div`
width: ${heroWidth}; width: ${heroWidth};
height: 100vh; height: 100vh;
background: url(${bg}); background: url(${(props) => props.image});
background-size: cover; background-size: cover;
background-position-x: right; background-position-x: right;
position: fixed; position: fixed;
@ -76,7 +73,8 @@ export const Hero = styled.div`
} }
h1:not(:last-of-type) { h1:not(:last-of-type) {
font-size: 15vw; font-size: 12vw;
margin-bottom: 0.5em;
@media screen and (max-height: 600px) { @media screen and (max-height: 600px) {
font-size: 20vh; font-size: 20vh;

View File

@ -2,7 +2,7 @@
import { h, Fragment } from 'preact' import { h, Fragment } from 'preact'
import MarkdownRenderer from 'markdown-to-jsx' import MarkdownRenderer from 'markdown-to-jsx'
import { MarkdownWrapper } from './styles' import { MarkdownWrapper } from './styles'
import { P, A, H1, H2, Span } from '../Text' import { P, A, H1, H2, H3, Span } from '../Text'
const Markdown = ({ children, withLinebreaks, options, ...rest }) => ( const Markdown = ({ children, withLinebreaks, options, ...rest }) => (
<MarkdownWrapper $withLinebreaks={withLinebreaks}> <MarkdownWrapper $withLinebreaks={withLinebreaks}>
@ -36,6 +36,9 @@ const Markdown = ({ children, withLinebreaks, options, ...rest }) => (
h2: { h2: {
component: H2, component: H2,
}, },
h3: {
component: H3,
},
}, },
...options, ...options,
}} }}

View File

@ -6,11 +6,11 @@ import striptags from 'striptags'
import { H1 } from '../../components/Text' import { H1 } from '../../components/Text'
import Markdown from '../../components/Markdown' import Markdown from '../../components/Markdown'
// import translations from '../../data/strings' import translations from '../../data/strings'
import InfoLayout from '../../components/InfoLayout' import InfoLayout from '../../components/InfoLayout'
import VideoEmbed from '../../components/VideoEmbed' import VideoEmbed from '../../components/VideoEmbed'
import { import {
VideoCard, EpisodeCard,
Title, Title,
InfoContent, InfoContent,
PositionedCross as CrossSvg, PositionedCross as CrossSvg,
@ -36,28 +36,12 @@ const SeriesPage = ({ data }) => {
setEmbedUrl('') setEmbedUrl('')
} }
console.log({ data }) console.log({ past: data.episodes.past, future: data.episodes.future })
// const pastStreams = const credits = `
// data && data.length ## Credits
// ? data.filter(feeditem => isPast(new Date(feeditem.end))) ${data.credits}
// : [] `
// const futureStreams =
// data && data.length
// ? data
// .filter(
// feeditem =>
// feeditem.id !== (currentVideo && currentVideo.id) &&
// isFuture(new Date(feeditem.start))
// )
// .sort(
// (a, b) =>
// // Turn your strings into dates, and then subtract them
// // to get a value that is either negative, positive, or zero.
// new Date(a.start) - new Date(b.start)
// )
// : []
const dateString = `${new Date()}` const dateString = `${new Date()}`
let tzShort = let tzShort =
@ -73,15 +57,15 @@ const SeriesPage = ({ data }) => {
} }
return ( return (
<InfoLayout title={data.name} subtitle={striptags(data.summary)}> <InfoLayout title={data.title} subtitle={striptags(data.subtitle)} image={data.image}>
{embedURL ? ( {embedURL ? (
<VideoEmbed onClose={deactivateEmbed} url={embedURL} /> <VideoEmbed onClose={deactivateEmbed} url={embedURL} />
) : null} ) : null}
<Fragment> <Fragment>
<InfoContent> <InfoContent>
<H1>{data.name}:</H1> <H1>{data.title}:</H1>
<H1>{data.summary}</H1> <H1>{data.subtitle}</H1>
<Markdown withLinebreaks>{intro}</Markdown> <Markdown withLinebreaks>{data.description}</Markdown>
<Trailer imgSrc={trailerThumb} onClick={onClickTrailerButton} /> <Trailer imgSrc={trailerThumb} onClick={onClickTrailerButton} />
@ -105,15 +89,16 @@ const SeriesPage = ({ data }) => {
{/* {currentVideo && ( {/* {currentVideo && (
<Fragment> <Fragment>
<Title>{translations.en.nowPlaying}:</Title> <Title>{translations.en.nowPlaying}:</Title>
<VideoCard {...currentVideo} /> <EpisodeCard {...currentVideo} />
</Fragment> </Fragment>
)} )}
{futureStreams.length ? ( */}
{data.episodes.future.length ? (
<Fragment> <Fragment>
<Title>{translations.en.nextStream}:</Title> <Title>{translations.en.nextStream}:</Title>
{futureStreams.map(feeditem => ( {data.episodes.future.map(feeditem => (
<VideoCard <EpisodeCard
key={feeditem.start} key={feeditem.start}
tzShort={tzShort} tzShort={tzShort}
{...feeditem} {...feeditem}
@ -121,13 +106,12 @@ const SeriesPage = ({ data }) => {
))} ))}
</Fragment> </Fragment>
) : null} ) : null}
{data.episodes.past.length ? (
{pastStreams.length ? (
<Fragment> <Fragment>
<Title>{translations.en.pastStream}:</Title> <Title>Past streams:</Title>
{pastStreams.map(feeditem => ( {data.episodes.past.map(feeditem => (
<VideoCard <EpisodeCard
key={feeditem.start} key={feeditem.beginsOn}
hasPassed hasPassed
onClickButton={() => onClickButton={() =>
setEmbedUrl(`${config.peertube_root}${feeditem.embedPath}`) setEmbedUrl(`${config.peertube_root}${feeditem.embedPath}`)
@ -136,10 +120,11 @@ const SeriesPage = ({ data }) => {
/> />
))} ))}
</Fragment> </Fragment>
) : null} */} ) : null}
{/* <InfoContent> <InfoContent>
<Title>Credits</Title>
<Markdown>{credits}</Markdown> <Markdown>{credits}</Markdown>
</InfoContent> */} </InfoContent>
</Fragment> </Fragment>
</InfoLayout> </InfoLayout>

View File

@ -1,9 +1,11 @@
import { h, Fragment } from 'preact' import { h, Fragment } from 'preact'
import { zonedTimeToUtc, utcToZonedTime, format } from 'date-fns-tz' import { zonedTimeToUtc, utcToZonedTime, format } from 'date-fns-tz'
import { bool, instanceOf, string } from 'prop-types' import { bool, func, instanceOf, string } from 'prop-types'
import styled from 'styled-components' import styled from 'styled-components'
import { colours, textSizes } from '../../assets/theme' import { colours, textSizes } from '../../assets/theme'
import config from '../../data/config' import config from '../../data/config'
import Markdown from '../../components/Markdown'
import Logo from '../../components/Logo' import Logo from '../../components/Logo'
import translations from '../../data/strings' import translations from '../../data/strings'
import CrossSvg from '../../components/Svg/Cross' import CrossSvg from '../../components/Svg/Cross'
@ -149,26 +151,27 @@ const LinkBlock = styled(Link)`
const renderTitles = titles => const renderTitles = titles =>
titles.split('\\n').map(title => <H2 key={title}>{title}</H2>) titles.split('\\n').map(title => <H2 key={title}>{title}</H2>)
export const VideoCard = ({ export const EpisodeCard = ({
title, title,
description, description,
start, beginsOn,
previewPath,
hasPassed, hasPassed,
videoUrl, videoUrl,
onClickButton, onClickButton,
tzShort, tzShort,
image
}) => { }) => {
const startDate = new Date(start) const startDate = new Date(beginsOn)
console.log({ startDate })
const utcDate = zonedTimeToUtc(startDate, 'Europe/Berlin') const utcDate = zonedTimeToUtc(startDate, 'Europe/Berlin')
const { timeZone } = Intl.DateTimeFormat().resolvedOptions() const { timeZone } = Intl.DateTimeFormat().resolvedOptions()
const zonedDate = utcToZonedTime(utcDate, timeZone) const zonedDate = utcToZonedTime(utcDate, timeZone)
return ( return (
<VCWrapper> <VCWrapper>
<DateLabel colour={colours.midnight} size={textSizes.lg}> <DateLabel size={textSizes.lg}>
{`${hasPassed ? translations.en.streamDatePast : ''}`} {`${hasPassed ? translations.en.streamDatePast : ''}`}
<Span bold colour={colours.midnight}> <Span bold colour={colours.rose}>
{hasPassed {hasPassed
? format(zonedDate, 'dd/MM/yy') ? format(zonedDate, 'dd/MM/yy')
: `${format(zonedDate, 'do LLLL y // HH:mm')} ${tzShort}`} : `${format(zonedDate, 'do LLLL y // HH:mm')} ${tzShort}`}
@ -177,15 +180,15 @@ export const VideoCard = ({
{videoUrl && hasPassed ? ( {videoUrl && hasPassed ? (
<LinkBlock href={videoUrl}> <LinkBlock href={videoUrl}>
<ItemTitleWrapper>{renderTitles(title)}</ItemTitleWrapper> <ItemTitleWrapper>{renderTitles(title)}</ItemTitleWrapper>
<VCImg src={`${config.peertube_root}${previewPath}`} alt="" /> <VCImg src={image} alt="" />
</LinkBlock> </LinkBlock>
) : ( ) : (
<Fragment> <Fragment>
<ItemTitleWrapper>{renderTitles(title)}</ItemTitleWrapper> <ItemTitleWrapper>{renderTitles(title)}</ItemTitleWrapper>
<VCImg src={`${config.peertube_root}${previewPath}`} alt="" /> <VCImg src={image} alt="" />
</Fragment> </Fragment>
)} )}
<P>{description}</P> <Markdown withLinebreaks>{description}</Markdown>
{hasPassed ? ( {hasPassed ? (
<Button onClick={onClickButton}>{translations.en.watchEpisode}</Button> <Button onClick={onClickButton}>{translations.en.watchEpisode}</Button>
) : ( ) : (
@ -203,10 +206,13 @@ export const VideoCard = ({
) )
} }
VideoCard.propTypes = { EpisodeCard.propTypes = {
title: string, title: string,
description: string, description: string,
start: instanceOf(Date), beginsOn: instanceOf(Date),
onClickButton: func,
tzShort: string,
image: string,
previewPath: string, previewPath: string,
hasPassed: bool, hasPassed: bool,
videoUrl: string, videoUrl: string,