More work on logic flow + info page
This commit is contained in:
parent
4973f351aa
commit
0ba8deacd0
65
app.js
65
app.js
@ -1,14 +1,13 @@
|
|||||||
import { h } from 'preact'
|
import { h } from 'preact'
|
||||||
import axios from 'axios'
|
import { useState, useEffect } from 'preact/hooks'
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
||||||
import 'regenerator-runtime/runtime'
|
import 'regenerator-runtime/runtime'
|
||||||
import { useEffect, useState } from 'preact/hooks'
|
import axios from 'axios'
|
||||||
|
|
||||||
import Video from './src/components/Video'
|
import Video from './src/components/Video'
|
||||||
import config from './src/data/config'
|
import config from './src/data/config'
|
||||||
import Info from './src/components/Info'
|
import Info from './src/components/Info'
|
||||||
import { useFetch } from './src/assets/hooks/calendar'
|
import { useCalendar } from './src/hooks/data'
|
||||||
import { P } from './src/components/Text'
|
import { useTimeout } from './src/hooks/timerHooks'
|
||||||
|
|
||||||
// const appStates = [
|
// const appStates = [
|
||||||
// 'noStream',
|
// 'noStream',
|
||||||
@ -19,13 +18,58 @@ import { P } from './src/components/Text'
|
|||||||
export default () => {
|
export default () => {
|
||||||
const [isPlaying, setIsPlaying] = useState(false)
|
const [isPlaying, setIsPlaying] = useState(false)
|
||||||
const [videoUrl, setVideoUrl] = useState(null)
|
const [videoUrl, setVideoUrl] = useState(null)
|
||||||
// const [feedData, setFeedData] = useState([])
|
const [feedData, setFeedData] = useState([])
|
||||||
|
const [minLoadTimePassed, setMinTimeUp] = useState(false)
|
||||||
|
const { data, loading } = useCalendar()
|
||||||
|
|
||||||
const { data: feedData, loading } = useFetch(`${config.calendar}`)
|
useTimeout(() => {
|
||||||
|
setMinTimeUp(true)
|
||||||
|
}, 1500)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data && data.length) {
|
||||||
|
data.forEach(async (calItem, index) => {
|
||||||
|
if (calItem.url) {
|
||||||
|
const id = calItem.url.val.split('/').pop()
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: {
|
||||||
|
account,
|
||||||
|
category,
|
||||||
|
channel,
|
||||||
|
embedPath,
|
||||||
|
language,
|
||||||
|
name,
|
||||||
|
state,
|
||||||
|
previewPath,
|
||||||
|
views,
|
||||||
|
},
|
||||||
|
} = await axios.get(`https://tv.undersco.re/api/v1/videos/${id}`)
|
||||||
|
|
||||||
|
const item = {
|
||||||
|
name,
|
||||||
|
account,
|
||||||
|
category,
|
||||||
|
channel,
|
||||||
|
description: calItem.description,
|
||||||
|
embedPath,
|
||||||
|
language,
|
||||||
|
state,
|
||||||
|
previewPath,
|
||||||
|
views,
|
||||||
|
start: calItem.start,
|
||||||
|
end: calItem.end,
|
||||||
|
id,
|
||||||
|
}
|
||||||
|
setFeedData(arr => [...arr, item])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [data])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{/* {false ? (
|
{false ? (
|
||||||
<Video
|
<Video
|
||||||
playing={isPlaying}
|
playing={isPlaying}
|
||||||
setPlaying={setIsPlaying}
|
setPlaying={setIsPlaying}
|
||||||
@ -33,8 +77,9 @@ export default () => {
|
|||||||
title={config.next_stream.title}
|
title={config.next_stream.title}
|
||||||
org={config.next_stream.org}
|
org={config.next_stream.org}
|
||||||
/>
|
/>
|
||||||
) : ( */}
|
) : (
|
||||||
{loading ? <P>LOADING :)</P> : <Info data={feedData} />}
|
<Info data={feedData} loading={loading || !minLoadTimePassed} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@peertube/embed-api": "^0.0.4",
|
"@peertube/embed-api": "^0.0.4",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
|
"date-fns": "^2.19.0",
|
||||||
|
"ical": "^0.8.0",
|
||||||
"preact": "^10.5.12",
|
"preact": "^10.5.12",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"styled-components": "^5.2.1"
|
"styled-components": "^5.2.1"
|
||||||
|
BIN
src/assets/fonts/Karla/Karla-Regular.ttf
Normal file
BIN
src/assets/fonts/Karla/Karla-Regular.ttf
Normal file
Binary file not shown.
@ -1,23 +0,0 @@
|
|||||||
import { useEffect, useState } from 'preact/hooks'
|
|
||||||
import axios from 'axios'
|
|
||||||
|
|
||||||
export const useFetch = url => {
|
|
||||||
const [data, setData] = useState(null)
|
|
||||||
const [loading, setLoading] = useState(true)
|
|
||||||
|
|
||||||
async function fetchData() {
|
|
||||||
setLoading(true)
|
|
||||||
|
|
||||||
const { data: responseData } = await axios.get(url)
|
|
||||||
console.log('url', url)
|
|
||||||
console.log('responseData', responseData)
|
|
||||||
setData(responseData)
|
|
||||||
setLoading(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchData()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return { loading, data }
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
import { PeerTubePlayer } from '@peertube/embed-api';
|
|
||||||
import 'regenerator-runtime/runtime';
|
|
||||||
import { toggleVideoPlaying } from './video-controls';
|
|
||||||
import { getVideoData } from './scheduling';
|
|
||||||
|
|
||||||
const streamData = getVideoData();
|
|
||||||
|
|
||||||
const videoWrapper = document.getElementById('video-wrapper');
|
|
||||||
const overlay = document.getElementById('overlay');
|
|
||||||
const videoiFrame = document.querySelector('iframe.video-player');
|
|
||||||
|
|
||||||
const video = {
|
|
||||||
isPlaying: false,
|
|
||||||
overlayVisible: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const setUpPlayer = async () => {
|
|
||||||
const player = new PeerTubePlayer(videoiFrame);
|
|
||||||
|
|
||||||
await player.ready;
|
|
||||||
|
|
||||||
onPlayerReady(player);
|
|
||||||
app();
|
|
||||||
};
|
|
||||||
|
|
||||||
const app = () => {
|
|
||||||
if (streamData && streamData) {
|
|
||||||
console.log({ streamData });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onPlayerReady = (player) => {
|
|
||||||
videoWrapper.addEventListener('mousemove', showOverlay);
|
|
||||||
|
|
||||||
videoWrapper.addEventListener('click', () => {
|
|
||||||
toggleVideoPlaying({
|
|
||||||
player,
|
|
||||||
video,
|
|
||||||
onPlay: () => {
|
|
||||||
hideOverlay();
|
|
||||||
},
|
|
||||||
onPause: () => {
|
|
||||||
showOverlay();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
video.isPlaying = !video.isPlaying;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const showOverlay = () => {
|
|
||||||
if (!video.overlayVisible) {
|
|
||||||
videoWrapper.classList.add('active');
|
|
||||||
overlay.classList.add('active');
|
|
||||||
|
|
||||||
setTimeout(hideOverlay, 2000);
|
|
||||||
}
|
|
||||||
video.overlayVisible = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const hideOverlay = () => {
|
|
||||||
if (video.isPlaying) {
|
|
||||||
video.overlayVisible = false;
|
|
||||||
videoWrapper.classList.remove('active');
|
|
||||||
overlay.classList.remove('active');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
setUpPlayer();
|
|
@ -1,12 +0,0 @@
|
|||||||
import axios from 'axios';
|
|
||||||
import 'regenerator-runtime/runtime';
|
|
||||||
import config from '../../data/conf.json';
|
|
||||||
|
|
||||||
export const getVideoData = async () => {
|
|
||||||
console.log({ config });
|
|
||||||
const { data } = await axios.get(`https://tv.undersco.re/api/v1/videos/${config.next_stream.peertube_id}`);
|
|
||||||
|
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
};
|
|
@ -1,15 +0,0 @@
|
|||||||
export const toggleVideoPlaying = ({ player, video, onPlay, onPause }) => {
|
|
||||||
console.log('video', video);
|
|
||||||
|
|
||||||
if (video.isPlaying) {
|
|
||||||
player.pause();
|
|
||||||
if (typeof onPause === 'function') {
|
|
||||||
onPause();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
player.play();
|
|
||||||
if (typeof onPlay === 'function') {
|
|
||||||
onPlay();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,3 +1,11 @@
|
|||||||
|
/* Karla Regular */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Karla';
|
||||||
|
src: url('../fonts/Karla/Karla-Regular.ttf') format('truetype');
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
/* Karla Medium */
|
/* Karla Medium */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Karla';
|
font-family: 'Karla';
|
||||||
|
4
src/components/Info/helpers.js
Normal file
4
src/components/Info/helpers.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export const sortData = data =>
|
||||||
|
Object.values(data)
|
||||||
|
.filter(feedItem => feedItem.type === 'VEVENT')
|
||||||
|
.sort((a, b) => new Date(a.start) - new Date(b.start))
|
@ -1,42 +1,51 @@
|
|||||||
import { h } from 'preact'
|
/* eslint-disable react/prop-types */
|
||||||
|
import { h, Fragment } from 'preact'
|
||||||
import { useEffect, useRef, useState } from 'preact/hooks'
|
import { useEffect, useRef, useState } from 'preact/hooks'
|
||||||
|
import { isBefore } from 'date-fns'
|
||||||
|
|
||||||
import { H1, H2, P } from '../Text'
|
import { P } from '../Text'
|
||||||
import {
|
|
||||||
Wrapper,
|
|
||||||
PositionedLogo as Logo,
|
|
||||||
TaglineContainer,
|
|
||||||
Top,
|
|
||||||
} from './styles'
|
|
||||||
import translations from '../../data/strings'
|
import translations from '../../data/strings'
|
||||||
import InfoLayout from '../InfoLayout'
|
import InfoLayout from '../InfoLayout'
|
||||||
|
import { VideoCard, Title, InfoContent } from './styles'
|
||||||
|
|
||||||
const allowedChannels = [7, 4] // ReclaimFutures, NDC
|
const Info = ({ data, loading }) => {
|
||||||
|
const now = new Date()
|
||||||
|
const pastStreams =
|
||||||
|
data && data.length
|
||||||
|
? data.filter(feeditem => isBefore(new Date(feeditem.end), now))
|
||||||
|
: []
|
||||||
|
|
||||||
const Info = ({ data }) => {
|
const futureStreams =
|
||||||
// const [feed, setFeed] = useState([])
|
data && data.length
|
||||||
|
? data.filter(feeditem => isBefore(now, new Date(feeditem.start)))
|
||||||
// useEffect(() => {
|
: []
|
||||||
// setFeed(sortData(data))
|
|
||||||
// }, [data])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log({ data })
|
|
||||||
}, [data])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InfoLayout title={translations.en.noStreams}>
|
<InfoLayout
|
||||||
<P>ding dong</P>
|
title={
|
||||||
|
data && data.length
|
||||||
|
? `${translations.en.nextStream}:`
|
||||||
|
: translations.en.noStreams
|
||||||
|
}
|
||||||
|
loading={loading}
|
||||||
|
>
|
||||||
|
{!loading && (
|
||||||
|
<InfoContent>
|
||||||
|
{futureStreams.map(feeditem => (
|
||||||
|
<VideoCard key={feeditem.start} {...feeditem} />
|
||||||
|
))}
|
||||||
|
{pastStreams.length ? (
|
||||||
|
<Fragment>
|
||||||
|
<Title>{translations.en.pastStream}:</Title>
|
||||||
|
{pastStreams.map(feeditem => (
|
||||||
|
<VideoCard key={feeditem.start} hasPassed {...feeditem} />
|
||||||
|
))}
|
||||||
|
</Fragment>
|
||||||
|
) : null}
|
||||||
|
</InfoContent>
|
||||||
|
)}
|
||||||
</InfoLayout>
|
</InfoLayout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortData = data => {
|
|
||||||
// if (!data || data?.length === 0) return
|
|
||||||
// console.log('data', data)
|
|
||||||
// return data.filter(feedItem => {
|
|
||||||
// return allowedChannels.includes(feedItem.channel.id) && feedItem.isLive
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Info
|
export default Info
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
|
import { format } from 'date-fns'
|
||||||
|
import { h, Fragment } from 'preact'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { colours } from '../../assets/theme'
|
import { colours } from '../../assets/theme'
|
||||||
|
import config from '../../data/config'
|
||||||
import Logo from '../Logo'
|
import Logo from '../Logo'
|
||||||
|
import translations from '../../data/strings'
|
||||||
|
|
||||||
|
import { P, H1, H2, Span, Label } from '../Text'
|
||||||
|
|
||||||
export const Wrapper = styled.div`
|
export const Wrapper = styled.div`
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
@ -27,6 +33,10 @@ export const Wrapper = styled.div`
|
|||||||
|
|
||||||
export const Top = styled.div``
|
export const Top = styled.div``
|
||||||
|
|
||||||
|
export const InfoContent = styled.div`
|
||||||
|
padding-bottom: 1em;
|
||||||
|
`
|
||||||
|
|
||||||
export const PositionedLogo = styled(Logo)`
|
export const PositionedLogo = styled(Logo)`
|
||||||
margin-bottom: 64px;
|
margin-bottom: 64px;
|
||||||
`
|
`
|
||||||
@ -36,3 +46,54 @@ export const TaglineContainer = styled.div`
|
|||||||
margin-top: 32px;
|
margin-top: 32px;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const Title = styled(H1)`
|
||||||
|
margin: 0.3em 0;
|
||||||
|
`
|
||||||
|
|
||||||
|
const VCWrapper = styled.div`
|
||||||
|
max-width: 600px;
|
||||||
|
margin-bottom: 3em;
|
||||||
|
border-left: 7px solid ${colours.midnightDarker};
|
||||||
|
padding-left: 1em;
|
||||||
|
`
|
||||||
|
|
||||||
|
const VCImg = styled.img`
|
||||||
|
width: 100%;
|
||||||
|
`
|
||||||
|
|
||||||
|
const ItemTitle = styled(H2)`
|
||||||
|
margin-bottom: 0.3em;
|
||||||
|
`
|
||||||
|
|
||||||
|
const DateLabel = styled(Label)`
|
||||||
|
margin: 1em 0;
|
||||||
|
display: block;
|
||||||
|
`
|
||||||
|
|
||||||
|
export const VideoCard = ({
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
previewPath,
|
||||||
|
hasPassed,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<VCWrapper>
|
||||||
|
<ItemTitle>{name}</ItemTitle>
|
||||||
|
<VCImg src={`${config.peertube_root}${previewPath}`} alt="" />
|
||||||
|
<DateLabel colour={colours.midnight} size="18">
|
||||||
|
{`${
|
||||||
|
hasPassed
|
||||||
|
? translations.en.streamDatePast
|
||||||
|
: translations.en.streamDateFuture
|
||||||
|
}`}
|
||||||
|
<Span bold colour={colours.midnight}>
|
||||||
|
{format(new Date(start), 'hh:mm dd/MM/yy')}
|
||||||
|
</Span>
|
||||||
|
</DateLabel>
|
||||||
|
<P>{description}</P>
|
||||||
|
</VCWrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -1,34 +1,53 @@
|
|||||||
import { h } from 'preact'
|
import { h } from 'preact'
|
||||||
import { useEffect, useRef, useState } from 'preact/hooks'
|
import { useEffect, useRef, useState } from 'preact/hooks'
|
||||||
|
import { bool, string } from 'prop-types'
|
||||||
|
|
||||||
import { H1, H2, P } from '../Text'
|
import { H1, H2 } from '../Text'
|
||||||
import {
|
import {
|
||||||
Wrapper,
|
Wrapper,
|
||||||
PositionedLogo as Logo,
|
PositionedLogo as Logo,
|
||||||
TaglineContainer,
|
TaglineContainer,
|
||||||
Top,
|
Title,
|
||||||
Content,
|
Content,
|
||||||
|
Fade,
|
||||||
} from './styles'
|
} from './styles'
|
||||||
import translations from '../../data/strings'
|
import translations from '../../data/strings'
|
||||||
import { colours } from '../../assets/theme'
|
import { colours } from '../../assets/theme'
|
||||||
|
import Loader from '../Loader'
|
||||||
|
import { useTimeout } from '../../hooks/timerHooks'
|
||||||
|
|
||||||
const InfoLayout = ({ title, children }) => {
|
const InfoLayout = ({ title, children, loading }) => {
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<Logo active colour={colours.midnightDarker} />
|
<Fade>
|
||||||
|
<Logo active colour={colours.midnightDarker} />
|
||||||
|
</Fade>
|
||||||
<Content>
|
<Content>
|
||||||
<H2>{title}</H2>
|
{loading ? (
|
||||||
|
<div>
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Title>{title}</Title>
|
||||||
|
)}
|
||||||
{children}
|
{children}
|
||||||
</Content>
|
</Content>
|
||||||
|
|
||||||
<TaglineContainer>
|
<TaglineContainer>
|
||||||
{translations &&
|
{translations &&
|
||||||
translations.en.underscoreTagline.map(line => (
|
translations.en.underscoreTagline.map(line => (
|
||||||
<H1 key={line}>{line}</H1>
|
<H1 align="right" key={line}>
|
||||||
|
{line}
|
||||||
|
</H1>
|
||||||
))}
|
))}
|
||||||
</TaglineContainer>
|
</TaglineContainer>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InfoLayout.propTypes = {
|
||||||
|
title: string,
|
||||||
|
loading: bool,
|
||||||
|
}
|
||||||
|
|
||||||
export default InfoLayout
|
export default InfoLayout
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { colours } from '../../assets/theme'
|
import { colours } from '../../assets/theme'
|
||||||
|
|
||||||
|
import { H1 } from '../Text'
|
||||||
|
|
||||||
import Logo from '../Logo'
|
import Logo from '../Logo'
|
||||||
|
|
||||||
export const Wrapper = styled.div`
|
export const Wrapper = styled.div`
|
||||||
@ -41,14 +44,52 @@ export const Wrapper = styled.div`
|
|||||||
export const Top = styled.div`
|
export const Top = styled.div`
|
||||||
width: 50%;
|
width: 50%;
|
||||||
`
|
`
|
||||||
export const Content = styled.div``
|
|
||||||
|
|
||||||
export const PositionedLogo = styled(Logo)`
|
const gradientColour = '#F8E5E2'
|
||||||
|
const getGradient = direction =>
|
||||||
|
`linear-gradient(to ${direction}, ${gradientColour}ee 0%,${gradientColour}00 100%);`
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
export const Fade = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
background-color: linear;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 2em;
|
padding: 2em 0 1em 2em;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background: ${getGradient('bottom')};
|
||||||
`
|
`
|
||||||
|
export const Title = styled(H1)`
|
||||||
|
margin: 0.5em 0;
|
||||||
|
`
|
||||||
|
|
||||||
|
export const Content = styled.div`
|
||||||
|
/* margin-bottom: 3em; */
|
||||||
|
`
|
||||||
|
|
||||||
|
export const PositionedLogo = styled(Logo)``
|
||||||
|
|
||||||
export const TaglineContainer = styled.div`
|
export const TaglineContainer = styled.div`
|
||||||
|
background: ${getGradient('top')};
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 2em;
|
bottom: 0em;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
right: 1em;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
@media screen and (max-width: 1200px) {
|
||||||
|
width: 100vw;
|
||||||
|
right: auto;
|
||||||
|
left: 1.5em;
|
||||||
|
h1 {
|
||||||
|
font-size: 32px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 800px) {
|
||||||
|
h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
38
src/components/Loader/index.js
Normal file
38
src/components/Loader/index.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { h } from 'preact'
|
||||||
|
import { useRef, useState } from 'preact/hooks'
|
||||||
|
import { useInterval, useTimeout } from '../../hooks/timerHooks'
|
||||||
|
import { colours } from '../../assets/theme'
|
||||||
|
import { H1 } from '../Text'
|
||||||
|
|
||||||
|
// const symbols = ['⌏', '⌎', '⌌', '⌍']
|
||||||
|
|
||||||
|
const Loader = ({
|
||||||
|
active = true,
|
||||||
|
offset = 0,
|
||||||
|
animation = [':..', '.:.', '..:', '...'],
|
||||||
|
}) => {
|
||||||
|
const [text, setText] = useState('.')
|
||||||
|
const arrayPosition = useRef(offset)
|
||||||
|
const rate = 350
|
||||||
|
|
||||||
|
useInterval(
|
||||||
|
() => {
|
||||||
|
setText(animation[arrayPosition.current])
|
||||||
|
|
||||||
|
if (arrayPosition.current === animation.length - 1) {
|
||||||
|
arrayPosition.current = 0
|
||||||
|
} else {
|
||||||
|
arrayPosition.current += 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
active ? rate : null
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<H1 as="span" colour={colours.midnightDarker}>
|
||||||
|
{text}
|
||||||
|
</H1>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Loader
|
@ -25,7 +25,7 @@ const Text = ({
|
|||||||
weight={weight}
|
weight={weight}
|
||||||
lineHeight={lineHeight}
|
lineHeight={lineHeight}
|
||||||
$fontFamily={fontFamily}
|
$fontFamily={fontFamily}
|
||||||
size={size}
|
$size={size}
|
||||||
selectable={selectable}
|
selectable={selectable}
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
@ -66,7 +66,7 @@ export const H1 = ({ children, ...rest }) => {
|
|||||||
<Text
|
<Text
|
||||||
tag="h1"
|
tag="h1"
|
||||||
weight="700"
|
weight="700"
|
||||||
size="48"
|
$size="48"
|
||||||
lineHeight="0.8"
|
lineHeight="0.8"
|
||||||
fontFamily="Lunchtype24"
|
fontFamily="Lunchtype24"
|
||||||
{...rest}
|
{...rest}
|
||||||
@ -80,7 +80,7 @@ export const H2 = ({ children, ...rest }) => (
|
|||||||
<Text
|
<Text
|
||||||
tag="h2"
|
tag="h2"
|
||||||
weight="700"
|
weight="700"
|
||||||
size="25"
|
$size="25"
|
||||||
lineHeight="1"
|
lineHeight="1"
|
||||||
fontFamily="Lunchtype24"
|
fontFamily="Lunchtype24"
|
||||||
{...rest}
|
{...rest}
|
||||||
@ -92,9 +92,9 @@ export const H2 = ({ children, ...rest }) => (
|
|||||||
export const P = ({ children, ...rest }) => (
|
export const P = ({ children, ...rest }) => (
|
||||||
<Text
|
<Text
|
||||||
tag="p"
|
tag="p"
|
||||||
weight="500"
|
weight="400"
|
||||||
size="13"
|
$size="15"
|
||||||
lineHeight="16px"
|
lineHeight="21px"
|
||||||
fontFamily="Karla"
|
fontFamily="Karla"
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
@ -102,15 +102,15 @@ export const P = ({ children, ...rest }) => (
|
|||||||
</Text>
|
</Text>
|
||||||
)
|
)
|
||||||
export const Span = ({ children, ...rest }) => (
|
export const Span = ({ children, ...rest }) => (
|
||||||
<Text tag="span" size="inherit" weight="inherit" {...rest}>
|
<Text tag="span" $size="inherit" weight="inherit" {...rest}>
|
||||||
{children}
|
{children}
|
||||||
</Text>
|
</Text>
|
||||||
)
|
)
|
||||||
export const Label = ({ children, ...rest }) => (
|
export const Label = ({ children, size, ...rest }) => (
|
||||||
<Text
|
<Text
|
||||||
tag="label"
|
tag="label"
|
||||||
weight="500"
|
weight="500"
|
||||||
size="13"
|
$size={size || '15'}
|
||||||
lineHeight="13px"
|
lineHeight="13px"
|
||||||
fontFamily="Karla"
|
fontFamily="Karla"
|
||||||
{...rest}
|
{...rest}
|
||||||
|
@ -3,7 +3,7 @@ import { colours } from '../../assets/theme'
|
|||||||
|
|
||||||
export const TextBase = styled.span`
|
export const TextBase = styled.span`
|
||||||
${({
|
${({
|
||||||
size,
|
$size,
|
||||||
weight,
|
weight,
|
||||||
colour,
|
colour,
|
||||||
align,
|
align,
|
||||||
@ -21,7 +21,7 @@ export const TextBase = styled.span`
|
|||||||
opacity: ${opacity};
|
opacity: ${opacity};
|
||||||
user-select: ${selectable ? 'inherit' : 'none'};
|
user-select: ${selectable ? 'inherit' : 'none'};
|
||||||
text-decoration: ${underline ? 'underline' : 'none'};
|
text-decoration: ${underline ? 'underline' : 'none'};
|
||||||
font-size: ${size}px;
|
font-size: ${$size}px;
|
||||||
|
|
||||||
::selection {
|
::selection {
|
||||||
background-color: ${colours.midnightDarker};
|
background-color: ${colours.midnightDarker};
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
export default {
|
export default {
|
||||||
en: {
|
en: {
|
||||||
nextStream: 'Next stream',
|
nextStream: 'Next streams',
|
||||||
|
pastStream: 'Latest streams',
|
||||||
noStreams: 'No upcoming streams, check back soon.',
|
noStreams: 'No upcoming streams, check back soon.',
|
||||||
underscoreTagline: ['LEAVE THE', 'SURVEILLANCE ECONOMY', '— TOGETHER.'],
|
underscoreTagline: ['LEAVE THE', 'SURVEILLANCE ECONOMY', '— TOGETHER.'],
|
||||||
|
streamDateFuture: 'Going live at: ',
|
||||||
|
streamDatePast: 'First broadcast: ',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
96
src/hooks/data.js
Normal file
96
src/hooks/data.js
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import { useEffect, useState } from 'preact/hooks'
|
||||||
|
import axios from 'axios'
|
||||||
|
import ical from 'ical'
|
||||||
|
import config from '../data/config'
|
||||||
|
|
||||||
|
export const useCalendar = () => {
|
||||||
|
const [data, setData] = useState(null)
|
||||||
|
const [loading, setLoading] = useState(true)
|
||||||
|
|
||||||
|
async function fetchData() {
|
||||||
|
setLoading(true)
|
||||||
|
|
||||||
|
const { data: responseData } = await axios.get(`${config.calendar}`)
|
||||||
|
const streamsData = Object.values(ical.parseICS(responseData))
|
||||||
|
.filter(feedItem => feedItem.type === 'VEVENT')
|
||||||
|
.sort((a, b) => new Date(a.start) - new Date(b.start))
|
||||||
|
setData(streamsData)
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchData()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return { loading, data }
|
||||||
|
}
|
||||||
|
|
||||||
|
// export const useCalendar = () => {
|
||||||
|
// const [data, setData] = useState(null)
|
||||||
|
// const [loading, setLoading] = useState(true)
|
||||||
|
|
||||||
|
// async function fetchData() {
|
||||||
|
// setLoading(true)
|
||||||
|
|
||||||
|
// const { data: responseData } = await axios.get(`${config.calendar}`)
|
||||||
|
// const streamsData = Object.values(ical.parseICS(responseData))
|
||||||
|
// .filter(feedItem => feedItem.type === 'VEVENT')
|
||||||
|
// .sort((a, b) => new Date(a.start) - new Date(b.start))
|
||||||
|
// setData(streamsData)
|
||||||
|
// setLoading(false)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// fetchData()
|
||||||
|
// }, [])
|
||||||
|
|
||||||
|
// return { loading, data }
|
||||||
|
// }
|
||||||
|
// useEffect(() => {
|
||||||
|
// const feedPromise =
|
||||||
|
// data &&
|
||||||
|
// data.map(async feedItem => {
|
||||||
|
// if (feedItem.url) {
|
||||||
|
// const id = feedItem.url.val.split('/').pop()
|
||||||
|
|
||||||
|
// const {
|
||||||
|
// data: {
|
||||||
|
// account,
|
||||||
|
// category,
|
||||||
|
// channel,
|
||||||
|
// description,
|
||||||
|
// embedPath,
|
||||||
|
// language,
|
||||||
|
// name,
|
||||||
|
// state,
|
||||||
|
// previewPath,
|
||||||
|
// views,
|
||||||
|
// },
|
||||||
|
// } = await axios.get(`https://tv.undersco.re/api/v1/videos/${id}`)
|
||||||
|
|
||||||
|
// const item = {
|
||||||
|
// name,
|
||||||
|
// account,
|
||||||
|
// category,
|
||||||
|
// channel,
|
||||||
|
// description,
|
||||||
|
// embedPath,
|
||||||
|
// language,
|
||||||
|
// state,
|
||||||
|
// previewPath,
|
||||||
|
// views,
|
||||||
|
// start: feedItem.start,
|
||||||
|
// end: feedItem.end,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// console.log(item)
|
||||||
|
|
||||||
|
// return item
|
||||||
|
// }
|
||||||
|
// return null
|
||||||
|
// })
|
||||||
|
|
||||||
|
// feedPromise.then(result => {
|
||||||
|
// console.log(result)
|
||||||
|
// })
|
||||||
|
// }, [data])
|
38
src/hooks/timerHooks.js
Normal file
38
src/hooks/timerHooks.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/* eslint-disable consistent-return */
|
||||||
|
import { useEffect, useRef } from 'preact/hooks'
|
||||||
|
|
||||||
|
export const useInterval = (callback, interval) => {
|
||||||
|
const savedCallback = useRef()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
savedCallback.current = callback
|
||||||
|
}, [callback])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function tick() {
|
||||||
|
savedCallback.current()
|
||||||
|
}
|
||||||
|
if (interval !== null) {
|
||||||
|
const id = setInterval(tick, interval)
|
||||||
|
return () => clearInterval(id)
|
||||||
|
}
|
||||||
|
}, [interval])
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useTimeout = (callback, timeout) => {
|
||||||
|
const savedCallback = useRef()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
savedCallback.current = callback
|
||||||
|
}, [callback])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function tick() {
|
||||||
|
savedCallback.current()
|
||||||
|
}
|
||||||
|
if (timeout !== null) {
|
||||||
|
const id = setTimeout(tick, timeout)
|
||||||
|
return () => clearTimeout(id)
|
||||||
|
}
|
||||||
|
}, [timeout])
|
||||||
|
}
|
24
yarn.lock
24
yarn.lock
@ -2483,6 +2483,11 @@ data-urls@^1.1.0:
|
|||||||
whatwg-mimetype "^2.2.0"
|
whatwg-mimetype "^2.2.0"
|
||||||
whatwg-url "^7.0.0"
|
whatwg-url "^7.0.0"
|
||||||
|
|
||||||
|
date-fns@^2.19.0:
|
||||||
|
version "2.19.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.19.0.tgz#65193348635a28d5d916c43ec7ce6fbd145059e1"
|
||||||
|
integrity sha512-X3bf2iTPgCAQp9wvjOQytnf5vO5rESYRXlPIVcgSbtT5OTScPcsf9eZU+B/YIkKAtYr5WeCii58BgATrNitlWg==
|
||||||
|
|
||||||
deasync@^0.1.14:
|
deasync@^0.1.14:
|
||||||
version "0.1.21"
|
version "0.1.21"
|
||||||
resolved "https://registry.yarnpkg.com/deasync/-/deasync-0.1.21.tgz#bb11eabd4466c0d8776f0d82deb8a6126460d30f"
|
resolved "https://registry.yarnpkg.com/deasync/-/deasync-0.1.21.tgz#bb11eabd4466c0d8776f0d82deb8a6126460d30f"
|
||||||
@ -3612,6 +3617,13 @@ https-browserify@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
||||||
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
|
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
|
||||||
|
|
||||||
|
ical@^0.8.0:
|
||||||
|
version "0.8.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ical/-/ical-0.8.0.tgz#aa93f021dfead58e54aaa22076a11ca07d65886b"
|
||||||
|
integrity sha512-/viUSb/RGLLnlgm0lWRlPBtVeQguQRErSPYl3ugnUaKUnzQswKqOG3M8/P1v1AB5NJwlHTuvTq1cs4mpeG2rCg==
|
||||||
|
dependencies:
|
||||||
|
rrule "2.4.1"
|
||||||
|
|
||||||
iconv-lite@0.4.24, iconv-lite@^0.4.17:
|
iconv-lite@0.4.24, iconv-lite@^0.4.17:
|
||||||
version "0.4.24"
|
version "0.4.24"
|
||||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||||
@ -4263,6 +4275,11 @@ lru-cache@^4.0.1, lru-cache@^4.1.5:
|
|||||||
pseudomap "^1.0.2"
|
pseudomap "^1.0.2"
|
||||||
yallist "^2.1.2"
|
yallist "^2.1.2"
|
||||||
|
|
||||||
|
luxon@^1.3.3:
|
||||||
|
version "1.26.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.26.0.tgz#d3692361fda51473948252061d0f8561df02b578"
|
||||||
|
integrity sha512-+V5QIQ5f6CDXQpWNICELwjwuHdqeJM1UenlZWx5ujcRMc9venvluCjFb4t5NYLhb6IhkbMVOxzVuOqkgMxee2A==
|
||||||
|
|
||||||
magic-string@^0.22.4:
|
magic-string@^0.22.4:
|
||||||
version "0.22.5"
|
version "0.22.5"
|
||||||
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.5.tgz#8e9cf5afddf44385c1da5bc2a6a0dbd10b03657e"
|
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.5.tgz#8e9cf5afddf44385c1da5bc2a6a0dbd10b03657e"
|
||||||
@ -5792,6 +5809,13 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
|
|||||||
hash-base "^3.0.0"
|
hash-base "^3.0.0"
|
||||||
inherits "^2.0.1"
|
inherits "^2.0.1"
|
||||||
|
|
||||||
|
rrule@2.4.1:
|
||||||
|
version "2.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/rrule/-/rrule-2.4.1.tgz#1d0db4e45f2b0e92e2cca62d2f7093729ac7ec94"
|
||||||
|
integrity sha512-+NcvhETefswZq13T8nkuEnnQ6YgUeZaqMqVbp+ZiFDPCbp3AVgQIwUvNVDdMNrP05bKZG9ddDULFp0qZZYDrxg==
|
||||||
|
optionalDependencies:
|
||||||
|
luxon "^1.3.3"
|
||||||
|
|
||||||
run-async@^2.2.0:
|
run-async@^2.2.0:
|
||||||
version "2.4.1"
|
version "2.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
|
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
|
||||||
|
Loading…
Reference in New Issue
Block a user