added more detailed info page + styles. Commit rest before refactor
This commit is contained in:
parent
8f68c37588
commit
4973f351aa
40
app.js
40
app.js
@ -5,34 +5,36 @@ import 'regenerator-runtime/runtime'
|
||||
import { useEffect, useState } from 'preact/hooks'
|
||||
|
||||
import Video from './src/components/Video'
|
||||
import config from './src/data/conf.json'
|
||||
import config from './src/data/config'
|
||||
import Info from './src/components/Info'
|
||||
import { useFetch } from './src/assets/hooks/calendar'
|
||||
import { P } from './src/components/Text'
|
||||
|
||||
// const appStates = [
|
||||
// 'noStream',
|
||||
// 'streamLive',
|
||||
// 'streamFinished'
|
||||
// ]
|
||||
|
||||
export default () => {
|
||||
const [isPlaying, setIsPlaying] = useState(false)
|
||||
const [videoUrl, setVideoUrl] = useState(null)
|
||||
// const [feedData, setFeedData] = useState([])
|
||||
|
||||
useEffect(() => {
|
||||
const getData = async () => {
|
||||
const { data } = await axios.get(
|
||||
`${config.peertube_root}/api/v1/videos/${config.next_stream.peertube_id}`
|
||||
)
|
||||
console.log(data)
|
||||
const src = `${config.peertube_root}${data.embedPath}`
|
||||
console.log('src', src)
|
||||
setVideoUrl(src)
|
||||
}
|
||||
|
||||
getData()
|
||||
}, [])
|
||||
const { data: feedData, loading } = useFetch(`${config.calendar}`)
|
||||
|
||||
return (
|
||||
<div>
|
||||
{videoUrl ? (
|
||||
<Video playing={isPlaying} setPlaying={setIsPlaying} src={videoUrl} />
|
||||
) : (
|
||||
<Info />
|
||||
)}
|
||||
{/* {false ? (
|
||||
<Video
|
||||
playing={isPlaying}
|
||||
setPlaying={setIsPlaying}
|
||||
src={videoUrl}
|
||||
title={config.next_stream.title}
|
||||
org={config.next_stream.org}
|
||||
/>
|
||||
) : ( */}
|
||||
{loading ? <P>LOADING :)</P> : <Info data={feedData} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
4
index.js
4
index.js
@ -1,6 +1,6 @@
|
||||
import { h, render } from 'preact'
|
||||
import App from './app'
|
||||
|
||||
const AppEl = document.getElementById('app')
|
||||
const appEl = document.getElementById('app')
|
||||
|
||||
render(<App />, AppEl)
|
||||
render(<App />, appEl)
|
||||
|
@ -21,6 +21,7 @@
|
||||
"styled-components": "^5.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.13.10",
|
||||
"babel": "^6.23.0",
|
||||
"babel-plugin-transform-react-jsx": "^6.24.1",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
|
23
src/assets/hooks/calendar.js
Normal file
23
src/assets/hooks/calendar.js
Normal file
@ -0,0 +1,23 @@
|
||||
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,14 +1,20 @@
|
||||
export const colours = {
|
||||
midnight: '#233b4a',
|
||||
midnightDarker: '#112B39',
|
||||
offwhite: '#f6f4f5',
|
||||
|
||||
white: '#fff',
|
||||
highlight: '#03a59e',
|
||||
rose: '#FEB9B3',
|
||||
roseDarker: '#FEB9B3',
|
||||
rose: '#F1CFCD',
|
||||
}
|
||||
|
||||
colours.text = colours.offwhite
|
||||
|
||||
export const ui = {
|
||||
borderRadius: 4,
|
||||
}
|
||||
|
||||
export const textSizes = {
|
||||
xs: 11,
|
||||
sm: 14,
|
||||
@ -22,4 +28,5 @@ export const textSizes = {
|
||||
export default {
|
||||
colours,
|
||||
textSizes,
|
||||
ui,
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
import styled from 'styled-components'
|
||||
import { colours } from '../../assets/theme'
|
||||
import { colours, ui } from '../../assets/theme'
|
||||
|
||||
export const ChatWrapper = styled.div`
|
||||
position: fixed;
|
||||
z-index: 10;
|
||||
bottom: 0;
|
||||
right: 32px;
|
||||
border-radius: ${ui.borderRadius}px;
|
||||
`
|
||||
|
@ -1,18 +1,42 @@
|
||||
import { h } from 'preact'
|
||||
import { useEffect, useRef, useState } from 'preact/hooks'
|
||||
|
||||
import Logo from '../Logo'
|
||||
import { H1, P } from '../Text'
|
||||
import { Wrapper } from './styles'
|
||||
import { H1, H2, P } from '../Text'
|
||||
import {
|
||||
Wrapper,
|
||||
PositionedLogo as Logo,
|
||||
TaglineContainer,
|
||||
Top,
|
||||
} from './styles'
|
||||
import translations from '../../data/strings'
|
||||
import InfoLayout from '../InfoLayout'
|
||||
|
||||
const allowedChannels = [7, 4] // ReclaimFutures, NDC
|
||||
|
||||
const Info = ({ data }) => {
|
||||
// const [feed, setFeed] = useState([])
|
||||
|
||||
// useEffect(() => {
|
||||
// setFeed(sortData(data))
|
||||
// }, [data])
|
||||
|
||||
useEffect(() => {
|
||||
console.log({ data })
|
||||
}, [data])
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<Logo active />
|
||||
<H1>Next Stream</H1>
|
||||
<P>dsdas</P>
|
||||
</Wrapper>
|
||||
<InfoLayout title={translations.en.noStreams}>
|
||||
<P>ding dong</P>
|
||||
</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
|
||||
|
@ -1,9 +1,38 @@
|
||||
import styled from 'styled-components'
|
||||
import { colours } from '../../assets/theme'
|
||||
import Logo from '../Logo'
|
||||
|
||||
export const Wrapper = styled.div`
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
padding: 2em;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: column;
|
||||
|
||||
background-color: ${colours.rose};
|
||||
background: url(https://images.unsplash.com/photo-1579762715118-a6f1d4b934f1?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=3031&q=80)
|
||||
${colours.rose};
|
||||
box-sizing: border-box;
|
||||
background-size: cover;
|
||||
background-position-y: 50%;
|
||||
background-position-x: 20vw;
|
||||
background-blend-mode: soft-light;
|
||||
|
||||
p,
|
||||
h1,
|
||||
h2 {
|
||||
color: ${colours.midnightDarker};
|
||||
}
|
||||
`
|
||||
|
||||
export const Top = styled.div``
|
||||
|
||||
export const PositionedLogo = styled(Logo)`
|
||||
margin-bottom: 64px;
|
||||
`
|
||||
|
||||
export const TaglineContainer = styled.div`
|
||||
h1 {
|
||||
margin-top: 32px;
|
||||
}
|
||||
`
|
||||
|
34
src/components/InfoLayout/index.js
Normal file
34
src/components/InfoLayout/index.js
Normal file
@ -0,0 +1,34 @@
|
||||
import { h } from 'preact'
|
||||
import { useEffect, useRef, useState } from 'preact/hooks'
|
||||
|
||||
import { H1, H2, P } from '../Text'
|
||||
import {
|
||||
Wrapper,
|
||||
PositionedLogo as Logo,
|
||||
TaglineContainer,
|
||||
Top,
|
||||
Content,
|
||||
} from './styles'
|
||||
import translations from '../../data/strings'
|
||||
import { colours } from '../../assets/theme'
|
||||
|
||||
const InfoLayout = ({ title, children }) => {
|
||||
return (
|
||||
<Wrapper>
|
||||
<Logo active colour={colours.midnightDarker} />
|
||||
<Content>
|
||||
<H2>{title}</H2>
|
||||
{children}
|
||||
</Content>
|
||||
|
||||
<TaglineContainer>
|
||||
{translations &&
|
||||
translations.en.underscoreTagline.map(line => (
|
||||
<H1 key={line}>{line}</H1>
|
||||
))}
|
||||
</TaglineContainer>
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
|
||||
export default InfoLayout
|
54
src/components/InfoLayout/styles.js
Normal file
54
src/components/InfoLayout/styles.js
Normal file
@ -0,0 +1,54 @@
|
||||
import styled from 'styled-components'
|
||||
import { colours } from '../../assets/theme'
|
||||
import Logo from '../Logo'
|
||||
|
||||
export const Wrapper = styled.div`
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
padding: 6em 2em 2em 2em;
|
||||
display: flex;
|
||||
/* justify-content: space-between; */
|
||||
/* flex-direction: column; */
|
||||
|
||||
background: url(https://images.unsplash.com/photo-1579762715118-a6f1d4b934f1?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=3031&q=80)
|
||||
${colours.rose};
|
||||
box-sizing: border-box;
|
||||
background-size: cover;
|
||||
background-position-y: 50%;
|
||||
background-position-x: 23vw;
|
||||
background-blend-mode: soft-light;
|
||||
position: fixed;
|
||||
overflow-y: scroll;
|
||||
|
||||
p,
|
||||
h1,
|
||||
h2 {
|
||||
color: ${colours.midnightDarker};
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
padding: 6em 1.5em 1.5em 1.5em;
|
||||
background-size: 150%;
|
||||
background-position-x: 0vw;
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
padding: 6em 1em 1em 1em;
|
||||
background-size: 250%;
|
||||
background-position-x: -50vw;
|
||||
}
|
||||
`
|
||||
|
||||
export const Top = styled.div`
|
||||
width: 50%;
|
||||
`
|
||||
export const Content = styled.div``
|
||||
|
||||
export const PositionedLogo = styled(Logo)`
|
||||
position: fixed;
|
||||
top: 2em;
|
||||
`
|
||||
|
||||
export const TaglineContainer = styled.div`
|
||||
position: fixed;
|
||||
bottom: 2em;
|
||||
`
|
@ -1,14 +1,15 @@
|
||||
import { h } from 'preact'
|
||||
import { bool, string } from 'prop-types'
|
||||
import styled, { css } from 'styled-components'
|
||||
import styled from 'styled-components'
|
||||
import { colours } from '../../assets/theme'
|
||||
|
||||
const Logo = ({ colour = colours.offwhite, active }) => (
|
||||
const Logo = ({ colour = colours.offwhite, active, ...rest }) => (
|
||||
<LogoSvg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 865 140"
|
||||
$active={active}
|
||||
{...rest}
|
||||
>
|
||||
<path
|
||||
fill={colour}
|
||||
@ -19,18 +20,6 @@ const Logo = ({ colour = colours.offwhite, active }) => (
|
||||
|
||||
const LogoSvg = styled.svg`
|
||||
width: 200px;
|
||||
padding: 1em;
|
||||
transform: translateY(-20%);
|
||||
transition: all 0.2s ease-in-out;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
|
||||
${props =>
|
||||
props.$active &&
|
||||
css`
|
||||
transform: translateY(0%);
|
||||
opacity: 1;
|
||||
`}
|
||||
`
|
||||
|
||||
Logo.propTypes = {
|
||||
|
@ -62,16 +62,29 @@ Text.propTypes = {
|
||||
}
|
||||
|
||||
export const H1 = ({ children, ...rest }) => {
|
||||
console.log({ children })
|
||||
return (
|
||||
<Text tag="h1" weight="700" size="48" fontFamily="Lunchtype24" {...rest}>
|
||||
<Text
|
||||
tag="h1"
|
||||
weight="700"
|
||||
size="48"
|
||||
lineHeight="0.8"
|
||||
fontFamily="Lunchtype24"
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
export const H2 = ({ children, ...rest }) => (
|
||||
<Text tag="h2" weight="700" size="25" fontFamily="Lunchtype24" {...rest}>
|
||||
<Text
|
||||
tag="h2"
|
||||
weight="700"
|
||||
size="25"
|
||||
lineHeight="1"
|
||||
fontFamily="Lunchtype24"
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
)
|
||||
|
@ -1,4 +1,5 @@
|
||||
import styled, { css } from 'styled-components'
|
||||
import { colours } from '../../assets/theme'
|
||||
|
||||
export const TextBase = styled.span`
|
||||
${({
|
||||
@ -21,5 +22,10 @@ export const TextBase = styled.span`
|
||||
user-select: ${selectable ? 'inherit' : 'none'};
|
||||
text-decoration: ${underline ? 'underline' : 'none'};
|
||||
font-size: ${size}px;
|
||||
|
||||
::selection {
|
||||
background-color: ${colours.midnightDarker};
|
||||
color: ${colours.offwhite};
|
||||
}
|
||||
`}
|
||||
`
|
||||
|
@ -1,13 +1,16 @@
|
||||
import { h } from 'preact'
|
||||
import { useEffect, useRef, useState } from 'preact/hooks'
|
||||
import { bool, func, string } from 'prop-types'
|
||||
import 'regenerator-runtime/runtime'
|
||||
import { PeerTubePlayer } from '@peertube/embed-api'
|
||||
|
||||
import Logo from '../Logo'
|
||||
import Chat from '../Chat'
|
||||
import { VideoWrapper, Iframe, Overlay } from './styles'
|
||||
import { H2 } from '../Text'
|
||||
import Overlay from '../VideoOverlay'
|
||||
import { VideoWrapper, Iframe } from './styles'
|
||||
|
||||
const Video = ({ playing, setPlaying, src }) => {
|
||||
const Video = ({ playing, setPlaying, src, title, org }) => {
|
||||
const videoiFrame = useRef(null)
|
||||
const overlayTimeout = useRef(null)
|
||||
const [videoReady, setVideoReady] = useState(false)
|
||||
@ -56,9 +59,7 @@ const Video = ({ playing, setPlaying, src }) => {
|
||||
onClick={() => setPlaying(!playing)}
|
||||
onMouseMove={activateOverlay}
|
||||
>
|
||||
<Overlay>
|
||||
<Logo active={overlayActive || !playing}></Logo>
|
||||
</Overlay>
|
||||
<Overlay active={overlayActive || !playing} title={title} org={org} />
|
||||
<Iframe
|
||||
sandbox="allow-same-origin allow-scripts allow-popups"
|
||||
src={`${src}?api=1&controls=false`}
|
||||
@ -66,9 +67,17 @@ const Video = ({ playing, setPlaying, src }) => {
|
||||
allowfullscreen
|
||||
ref={videoiFrame}
|
||||
/>
|
||||
<Chat></Chat>
|
||||
<Chat />
|
||||
</VideoWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
Video.propTypes = {
|
||||
playing: bool,
|
||||
setPlaying: func.isRequired,
|
||||
src: string.isRequired,
|
||||
title: string.isRequired,
|
||||
org: string,
|
||||
}
|
||||
|
||||
export default Video
|
||||
|
34
src/components/VideoOverlay/index.js
Normal file
34
src/components/VideoOverlay/index.js
Normal file
@ -0,0 +1,34 @@
|
||||
import { h } from 'preact'
|
||||
import { bool, string } from 'prop-types'
|
||||
|
||||
import Logo from '../Logo'
|
||||
import { P } from '../Text'
|
||||
import { OverlayWrapper, TopLeft } from './styles'
|
||||
|
||||
const VideoOverlay = ({ active, title, org }) => {
|
||||
const displayTitle = `${title}${org ? ` — ${org}` : ''}`
|
||||
|
||||
return (
|
||||
<OverlayWrapper>
|
||||
<TopLeft $active={active}>
|
||||
<Logo active={active} />
|
||||
<P
|
||||
size={18}
|
||||
css={`
|
||||
margin-top: 16px;
|
||||
`}
|
||||
>
|
||||
{displayTitle}
|
||||
</P>
|
||||
</TopLeft>
|
||||
</OverlayWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
VideoOverlay.propTypes = {
|
||||
active: bool,
|
||||
title: string.isRequired,
|
||||
org: string,
|
||||
}
|
||||
|
||||
export default VideoOverlay
|
21
src/components/VideoOverlay/styles.js
Normal file
21
src/components/VideoOverlay/styles.js
Normal file
@ -0,0 +1,21 @@
|
||||
import styled, { css } from 'styled-components'
|
||||
|
||||
export const OverlayWrapper = styled.div`
|
||||
z-index: 2;
|
||||
position: fixed;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
pointer-events: none;
|
||||
`
|
||||
export const TopLeft = styled.div`
|
||||
opacity: 0;
|
||||
transform: translateY(-20%);
|
||||
transition: all 0.2s ease-in-out;
|
||||
padding: 2em;
|
||||
${props =>
|
||||
props.$active &&
|
||||
css`
|
||||
transform: translateY(0%);
|
||||
opacity: 1;
|
||||
`};
|
||||
`
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"peertube_root": "https://tv.undersco.re",
|
||||
"next_stream": {
|
||||
"title": "Femboy Photoshoot",
|
||||
"peertube_id": "5c457282-e8d0-4464-9c07-cb6bb71d7153",
|
||||
"startDate": "Fri Mar 05 2021 21:00:00 GMT+0100 (Central European Standard Time",
|
||||
"endDate": "Fri Mar 05 2021 21:00:00 GMT+0100 (Central European Standard Time"
|
||||
}
|
||||
}
|
14
src/data/config.js
Normal file
14
src/data/config.js
Normal file
@ -0,0 +1,14 @@
|
||||
export default {
|
||||
peertube_root: 'https://tv.undersco.re',
|
||||
calendar:
|
||||
'https://cloud.undersco.re/remote.php/dav/public-calendars/9FzomgAfidHWCQcx?export',
|
||||
next_stream: {
|
||||
title: 'Femboy Photoshoot',
|
||||
peertube_id: 'cafce2b3-550b-4656-bae0-c167d3994a0d',
|
||||
org: 'New Design Congress',
|
||||
startDate:
|
||||
'Fri Mar 05 2021 21:00:00 GMT+0100 (Central European Standard Time',
|
||||
endDate:
|
||||
'Fri Mar 05 2021 21:00:00 GMT+0100 (Central European Standard Time',
|
||||
},
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
export default {
|
||||
en: {
|
||||
nextStream: 'Next stream:',
|
||||
nextStream: 'Next stream',
|
||||
noStreams: 'No upcoming streams, check back soon.',
|
||||
underscoreTagline: ['LEAVE THE', 'SURVEILLANCE ECONOMY', '— TOGETHER.'],
|
||||
},
|
||||
}
|
||||
|
19
yarn.lock
19
yarn.lock
@ -41,6 +41,15 @@
|
||||
semver "^5.4.1"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/eslint-parser@^7.13.10":
|
||||
version "7.13.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.13.10.tgz#e272979914f36bb6cea144c14c32bb51632696dd"
|
||||
integrity sha512-/I1HQ3jGPhIpeBFeI3wO9WwWOnBYpuR0pX0KlkdGcRQAVX9prB/FCS2HBpL7BiFbzhny1YCiBH8MTZD2jJa7Hg==
|
||||
dependencies:
|
||||
eslint-scope "5.1.0"
|
||||
eslint-visitor-keys "^1.3.0"
|
||||
semver "^6.3.0"
|
||||
|
||||
"@babel/generator@^7.0.0 <7.4.0":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.4.tgz#9aa48c1989257877a9d971296e5b73bfe72e446e"
|
||||
@ -2940,6 +2949,14 @@ eslint-restricted-globals@^0.1.1:
|
||||
resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7"
|
||||
integrity sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=
|
||||
|
||||
eslint-scope@5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5"
|
||||
integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==
|
||||
dependencies:
|
||||
esrecurse "^4.1.0"
|
||||
estraverse "^4.1.1"
|
||||
|
||||
eslint-scope@^3.7.1:
|
||||
version "3.7.3"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535"
|
||||
@ -2948,7 +2965,7 @@ eslint-scope@^3.7.1:
|
||||
esrecurse "^4.1.0"
|
||||
estraverse "^4.1.1"
|
||||
|
||||
eslint-visitor-keys@^1.0.0:
|
||||
eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
|
||||
integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
|
||||
|
Loading…
Reference in New Issue
Block a user