UI for stream series pages
This commit is contained in:
parent
3cab6fb683
commit
a3bea12645
2
app.js
2
app.js
@ -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)
|
||||||
|
4
index.js
4
index.js
@ -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>
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
}}
|
}}
|
||||||
|
@ -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>
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user