bunch of styling
This commit is contained in:
		
							parent
							
								
									d4a07710ba
								
							
						
					
					
						commit
						aa7ffc900b
					
				
							
								
								
									
										88
									
								
								app.js
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								app.js
									
									
									
									
									
								
							| @ -1,26 +1,21 @@ | ||||
| import { h } from 'preact' | ||||
| import { useState, useEffect } from 'preact/hooks' | ||||
| import 'regenerator-runtime/runtime' | ||||
| import axios from 'axios' | ||||
| import { isWithinInterval, subHours } from 'date-fns' | ||||
| import { addHours } from 'date-fns/esm' | ||||
| 
 | ||||
| import Video from './src/components/Video' | ||||
| import config from './src/data/config' | ||||
| import Info from './src/components/Info' | ||||
| import { useCalendar } from './src/hooks/data' | ||||
| import { useEventStream } from './src/hooks/data' | ||||
| import { useTimeout } from './src/hooks/timerHooks' | ||||
| 
 | ||||
| // const appStates = [
 | ||||
| //  'noStream',
 | ||||
| //  'streamLive',
 | ||||
| //  'streamFinished'
 | ||||
| // ]
 | ||||
| 
 | ||||
| export default () => { | ||||
|   const [isPlaying, setIsPlaying] = useState(false) | ||||
|   const [videoUrl, setVideoUrl] = useState(null) | ||||
|   const [feedData, setFeedData] = useState([]) | ||||
|   const [currentVideo, setCurrentVideo] = useState(null) | ||||
|   const [streamIsLive, setStreamLive] = useState(false) | ||||
|   const [infoActive, setInfoActive] = useState(false) | ||||
|   const [minLoadTimePassed, setMinTimeUp] = useState(false) | ||||
|   const { data, loading } = useCalendar() | ||||
|   const { data, loading } = useEventStream() | ||||
| 
 | ||||
|   useTimeout(() => { | ||||
|     setMinTimeUp(true) | ||||
| @ -28,40 +23,26 @@ export default () => { | ||||
| 
 | ||||
|   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, | ||||
|       data.forEach((stream, index) => { | ||||
|         // if (stream.title === 'A Wider Screen') {
 | ||||
|         if (index === 0) { | ||||
|           setCurrentVideo(stream) | ||||
|         } | ||||
|           setFeedData(arr => [...arr, item]) | ||||
|         if ( | ||||
|           isWithinInterval(new Date(), { | ||||
|             start: subHours(stream.start, 1), | ||||
|             end: addHours(stream.end, 1), | ||||
|           }) | ||||
|         ) { | ||||
|           setCurrentVideo(stream) | ||||
|         } | ||||
|         if ( | ||||
|           isWithinInterval(new Date(), { | ||||
|             start: stream.start, | ||||
|             end: stream.end, | ||||
|           }) | ||||
|         ) { | ||||
|           setStreamLive(`${config.peertube_root}${stream.embedPath}`) | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
| @ -69,16 +50,23 @@ export default () => { | ||||
| 
 | ||||
|   return ( | ||||
|     <div> | ||||
|       {false ? ( | ||||
|       {currentVideo && !infoActive && minLoadTimePassed ? ( | ||||
|         <Video | ||||
|           playing={isPlaying} | ||||
|           setPlaying={setIsPlaying} | ||||
|           src={videoUrl} | ||||
|           title={config.next_stream.title} | ||||
|           org={config.next_stream.org} | ||||
|           src={`${config.peertube_root}${currentVideo.embedPath}`} | ||||
|           title={currentVideo.title} | ||||
|           org={currentVideo.channel.displayName} | ||||
|           setInfoActive={setInfoActive} | ||||
|         /> | ||||
|       ) : ( | ||||
|         <Info data={feedData} loading={loading || !minLoadTimePassed} /> | ||||
|         <Info | ||||
|           data={data} | ||||
|           loading={loading || !minLoadTimePassed} | ||||
|           infoActive={infoActive} | ||||
|           currentVideo={currentVideo} | ||||
|           setInfoActive={setInfoActive} | ||||
|         /> | ||||
|       )} | ||||
|     </div> | ||||
|   ) | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/IconSM.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/assets/img/IconSM.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 58 KiB | 
| @ -3,7 +3,7 @@ export const colours = { | ||||
|   midnightDarker: '#112B39', | ||||
|   offwhite: '#f6f4f5', | ||||
| 
 | ||||
|   white: '#fff', | ||||
|   white: '#ffffff', | ||||
|   highlight: '#03a59e', | ||||
|   roseDarker: '#FEB9B3', | ||||
|   rose: '#F1CFCD', | ||||
|  | ||||
| @ -1,19 +1,40 @@ | ||||
| import { h } from 'preact' | ||||
| import { useEffect, useRef, useState } from 'preact/hooks' | ||||
| import { useWindowDimensions } from '../../hooks/dom' | ||||
| import { useToggle } from '../../hooks/utility' | ||||
| 
 | ||||
| import { ChatWrapper } from './styles' | ||||
| import { Label } from '../Text' | ||||
| import { ChatFrame, ChatWrapper, ChatHeader, CloseBox } from './styles' | ||||
| import { colours } from '../../assets/theme' | ||||
| 
 | ||||
| const Chat = ({}) => { | ||||
|   return ( | ||||
|   const { width, height } = useWindowDimensions() | ||||
|   const [chatIsOpen, toggleChatOpen] = useToggle(true) | ||||
|   return chatIsOpen ? ( | ||||
|     <ChatWrapper> | ||||
|       <ChatFrame> | ||||
|         <ChatHeader chatIsOpen> | ||||
|           <Label weight="400" size={24}> | ||||
|             Chat | ||||
|           </Label> | ||||
|           <CloseBox colour={colours.white} size={18} onClick={toggleChatOpen} /> | ||||
|         </ChatHeader> | ||||
|         <iframe | ||||
|           src="https://titanembeds.com/embed/803918964082212905?css=215&defaultchannel=817134294199566356&lang=en_EN" | ||||
|         height="500" | ||||
|           height={(height / 4) * 3} | ||||
|           width="350" | ||||
|           frameBorder="0" | ||||
|           title="discord-chat" | ||||
|         class="titanembed" | ||||
|           className="titanembed" | ||||
|         /> | ||||
|       </ChatFrame> | ||||
|     </ChatWrapper> | ||||
|   ) : ( | ||||
|     <ChatHeader chatIsOpen={false} onClick={toggleChatOpen}> | ||||
|       <Label weight="400" size={24}> | ||||
|         Chat | ||||
|       </Label> | ||||
|     </ChatHeader> | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,10 +1,55 @@ | ||||
| import styled from 'styled-components' | ||||
| import { colours, ui } from '../../assets/theme' | ||||
| import CrossSvg from '../Svg/Cross' | ||||
| import { Label } from '../Text' | ||||
| 
 | ||||
| export const ChatFrame = styled.div` | ||||
|   /* border: 2px solid ${colours.white}; */ | ||||
|   /* padding: 20px; */ | ||||
| ` | ||||
| 
 | ||||
| export const ChatWrapper = styled.div` | ||||
|   position: fixed; | ||||
|   z-index: 10; | ||||
|   bottom: 0; | ||||
|   right: 32px; | ||||
|   bottom: -5px; | ||||
|   right: 0; | ||||
|   backdrop-filter: blur(20px); | ||||
|   background-color: ${colours.midnight}40; | ||||
|   /* padding: 20px; */ | ||||
|   border-radius: ${ui.borderRadius}px; | ||||
| ` | ||||
| 
 | ||||
| export const ChatHeader = styled.div` | ||||
|   position: absolute; | ||||
|   bottom: ${props => (props.chatIsOpen ? 'initial' : 0)}; | ||||
|   top: ${props => (props.chatIsOpen ? '4px' : 'initial')}; | ||||
|   /* cursor: ${props => (props.dragging ? 'grabbing' : 'grab')}; */ | ||||
|   border-radius: ${ui.borderRadius}px 0 0 0; | ||||
| 
 | ||||
| 
 | ||||
|   height: 32px; | ||||
|   box-sizing: border-box; | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   width: ${props => (props.chatIsOpen ? '100%' : 'fit-content')}; | ||||
| 
 | ||||
|   justify-content: space-between; | ||||
|   padding: 0px 0px 3px 0px; | ||||
|   right: 0; | ||||
|   box-sizing: content-box; | ||||
|   border: ${props => | ||||
|     props.chatIsOpen ? 'none' : `1px solid ${colours.white}`}; | ||||
|   border-bottom: ${props => | ||||
|     props.chatIsOpen ? `1px solid ${colours.white}75` : 'none'}; | ||||
|     border-right: none; | ||||
| 
 | ||||
|   label { | ||||
|     margin-left: 12px; | ||||
|     margin-right: ${props => (props.chatIsOpen ? '0' : '12px')} | ||||
|   } | ||||
| ` | ||||
| 
 | ||||
| export const CloseBox = styled(CrossSvg)` | ||||
|   padding: 12px; | ||||
|   cursor: pointer; | ||||
| ` | ||||
|  | ||||
| @ -1,39 +1,55 @@ | ||||
| /* eslint-disable react/prop-types */ | ||||
| import { h, Fragment } from 'preact' | ||||
| import { useEffect, useRef, useState } from 'preact/hooks' | ||||
| import { isBefore } from 'date-fns' | ||||
| import { isFuture, isPast } from 'date-fns' | ||||
| 
 | ||||
| import { P } from '../Text' | ||||
| import translations from '../../data/strings' | ||||
| import InfoLayout from '../InfoLayout' | ||||
| import { VideoCard, Title, InfoContent } from './styles' | ||||
| import { | ||||
|   VideoCard, | ||||
|   Title, | ||||
|   InfoContent, | ||||
|   PositionedCross as CrossSvg, | ||||
| } from './styles' | ||||
| 
 | ||||
| const Info = ({ data, loading }) => { | ||||
|   const now = new Date() | ||||
| const Info = ({ data, loading, infoActive, setInfoActive, currentVideo }) => { | ||||
|   const pastStreams = | ||||
|     data && data.length | ||||
|       ? data.filter(feeditem => isBefore(new Date(feeditem.end), now)) | ||||
|       ? data.filter(feeditem => isPast(new Date(feeditem.end))) | ||||
|       : [] | ||||
| 
 | ||||
|   const futureStreams = | ||||
|     data && data.length | ||||
|       ? data.filter(feeditem => isBefore(now, new Date(feeditem.start))) | ||||
|       ? data.filter( | ||||
|           feeditem => | ||||
|             feeditem.id !== (currentVideo && currentVideo.id) && | ||||
|             isFuture(new Date(feeditem.start)) | ||||
|         ) | ||||
|       : [] | ||||
| 
 | ||||
|   console.log({ currentVideo }) | ||||
| 
 | ||||
|   return ( | ||||
|     <InfoLayout | ||||
|       title={ | ||||
|         data && data.length | ||||
|           ? `${translations.en.nextStream}:` | ||||
|           : translations.en.noStreams | ||||
|       } | ||||
|       loading={loading} | ||||
|     > | ||||
|     <InfoLayout loading={loading}> | ||||
|       {infoActive && <CrossSvg onClick={() => setInfoActive(false)} />} | ||||
|       {!loading && ( | ||||
|         <InfoContent> | ||||
|           {currentVideo && ( | ||||
|             <Fragment> | ||||
|               <Title>{translations.en.nowPlaying}:</Title> | ||||
|               <VideoCard {...currentVideo} /> | ||||
|             </Fragment> | ||||
|           )} | ||||
| 
 | ||||
|           {futureStreams.length && ( | ||||
|             <Fragment> | ||||
|               <Title>{translations.en.nextStream}:</Title> | ||||
|               {futureStreams.map(feeditem => ( | ||||
|                 <VideoCard key={feeditem.start} {...feeditem} /> | ||||
|               ))} | ||||
|             </Fragment> | ||||
|           )} | ||||
| 
 | ||||
|           {pastStreams.length ? ( | ||||
|             <Fragment> | ||||
|               <Title>{translations.en.pastStream}:</Title> | ||||
|  | ||||
| @ -5,8 +5,11 @@ import { colours } from '../../assets/theme' | ||||
| import config from '../../data/config' | ||||
| import Logo from '../Logo' | ||||
| import translations from '../../data/strings' | ||||
| import CrossSvg from '../Svg/Cross' | ||||
| 
 | ||||
| import { P, H1, H2, Span, Label } from '../Text' | ||||
| import Link from '../Link' | ||||
| import { bool, instanceOf, string } from 'prop-types' | ||||
| 
 | ||||
| export const Wrapper = styled.div` | ||||
|   height: 100vh; | ||||
| @ -51,10 +54,24 @@ export const Title = styled(H1)` | ||||
|   margin: 0.3em 0; | ||||
| ` | ||||
| 
 | ||||
| export const PositionedCross = styled(CrossSvg)` | ||||
|   position: fixed; | ||||
|   right: 2.5em; | ||||
|   top: 2em; | ||||
|   width: 24px; | ||||
|   height: 24px; | ||||
|   cursor: pointer; | ||||
|   stroke: ${colours.midnightDarker}; | ||||
| 
 | ||||
|   &:hover { | ||||
|     opacity: 0.5; | ||||
|   } | ||||
| ` | ||||
| 
 | ||||
| const VCWrapper = styled.div` | ||||
|   max-width: 600px; | ||||
|   margin-bottom: 3em; | ||||
|   border-left: 7px solid ${colours.midnightDarker}; | ||||
|   margin: 0 0 6em 2px; | ||||
|   border-left: 5px solid ${colours.midnightDarker}; | ||||
|   padding-left: 1em; | ||||
| ` | ||||
| 
 | ||||
| @ -71,18 +88,32 @@ const DateLabel = styled(Label)` | ||||
|   display: block; | ||||
| ` | ||||
| 
 | ||||
| const LinkBlock = styled(Link)` | ||||
|   display: block; | ||||
|   width: 100%; | ||||
| ` | ||||
| 
 | ||||
| export const VideoCard = ({ | ||||
|   name, | ||||
|   title, | ||||
|   description, | ||||
|   start, | ||||
|   end, | ||||
|   previewPath, | ||||
|   hasPassed, | ||||
| }) => { | ||||
|   return ( | ||||
|   videoUrl, | ||||
| }) => ( | ||||
|   <VCWrapper> | ||||
|       <ItemTitle>{name}</ItemTitle> | ||||
|     {videoUrl && hasPassed ? ( | ||||
|       <LinkBlock href={videoUrl}> | ||||
|         <ItemTitle>{title}</ItemTitle> | ||||
|         <VCImg src={`${config.peertube_root}${previewPath}`} alt="" /> | ||||
|       </LinkBlock> | ||||
|     ) : ( | ||||
|       <Fragment> | ||||
|         <ItemTitle>{title}</ItemTitle> | ||||
|         <VCImg src={`${config.peertube_root}${previewPath}`} alt="" /> | ||||
|       </Fragment> | ||||
|     )} | ||||
|     <DateLabel colour={colours.midnight} size="18"> | ||||
|       {`${ | ||||
|         hasPassed | ||||
| @ -95,5 +126,14 @@ export const VideoCard = ({ | ||||
|     </DateLabel> | ||||
|     <P>{description}</P> | ||||
|   </VCWrapper> | ||||
|   ) | ||||
| ) | ||||
| 
 | ||||
| VideoCard.propTypes = { | ||||
|   title: string, | ||||
|   description: string, | ||||
|   start: instanceOf(Date), | ||||
|   end: instanceOf(Date), | ||||
|   previewPath: string, | ||||
|   hasPassed: bool, | ||||
|   videoUrl: string, | ||||
| } | ||||
|  | ||||
| @ -7,7 +7,7 @@ import { | ||||
|   Wrapper, | ||||
|   PositionedLogo as Logo, | ||||
|   TaglineContainer, | ||||
|   Title, | ||||
|   LoaderWrapper, | ||||
|   Content, | ||||
|   Fade, | ||||
| } from './styles' | ||||
| @ -16,7 +16,7 @@ import { colours } from '../../assets/theme' | ||||
| import Loader from '../Loader' | ||||
| import { useTimeout } from '../../hooks/timerHooks' | ||||
| 
 | ||||
| const InfoLayout = ({ title, children, loading }) => { | ||||
| const InfoLayout = ({ children, loading }) => { | ||||
|   return ( | ||||
|     <Wrapper> | ||||
|       <Fade> | ||||
| @ -24,13 +24,12 @@ const InfoLayout = ({ title, children, loading }) => { | ||||
|       </Fade> | ||||
|       <Content> | ||||
|         {loading ? ( | ||||
|           <div> | ||||
|           <LoaderWrapper> | ||||
|             <Loader /> | ||||
|           </div> | ||||
|           </LoaderWrapper> | ||||
|         ) : ( | ||||
|           <Title>{title}</Title> | ||||
|           children | ||||
|         )} | ||||
|         {children} | ||||
|       </Content> | ||||
| 
 | ||||
|       <TaglineContainer> | ||||
| @ -46,7 +45,6 @@ const InfoLayout = ({ title, children, loading }) => { | ||||
| } | ||||
| 
 | ||||
| InfoLayout.propTypes = { | ||||
|   title: string, | ||||
|   loading: bool, | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -59,8 +59,14 @@ export const Fade = styled.div` | ||||
|   left: 0; | ||||
|   background: ${getGradient('bottom')}; | ||||
| ` | ||||
| export const Title = styled(H1)` | ||||
|   margin: 0.5em 0; | ||||
| export const LoaderWrapper = styled.div` | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
|   height: 100vh; | ||||
|   position: fixed; | ||||
|   top: 0; | ||||
|   width: 50vw; | ||||
| ` | ||||
| 
 | ||||
| export const Content = styled.div` | ||||
|  | ||||
							
								
								
									
										6
									
								
								src/components/Link/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/components/Link/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| import styled from 'styled-components' | ||||
| 
 | ||||
| export const Link = styled.a` | ||||
|   text-decoration: none; | ||||
| ` | ||||
| export default Link | ||||
							
								
								
									
										16
									
								
								src/components/Svg/Cross.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/components/Svg/Cross.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| import { h } from 'preact' | ||||
| import { bool, string } from 'prop-types' | ||||
| 
 | ||||
| const Cross = ({ colour = 'inherit', size, ...rest }) => ( | ||||
|   <svg viewBox="0 0 100 100" height={size} {...rest}> | ||||
|     <path | ||||
|       stroke={colour} | ||||
|       strokeLinecap="none" | ||||
|       strokeLinejoin="none" | ||||
|       strokeWidth="18" | ||||
|       d="M11.354 11.757l77.637 77.636m-77.627 0L89 11.757" | ||||
|     /> | ||||
|   </svg> | ||||
| ) | ||||
| 
 | ||||
| export default Cross | ||||
| @ -4,16 +4,18 @@ 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 { H2 } from '../Text' | ||||
| import Overlay from '../VideoOverlay' | ||||
| import { useToggle } from '../../hooks/utility' | ||||
| import { VideoWrapper, Iframe } from './styles' | ||||
| 
 | ||||
| const Video = ({ playing, setPlaying, src, title, org }) => { | ||||
| const Video = ({ playing, setPlaying, src, title, org, setInfoActive }) => { | ||||
|   const videoiFrame = useRef(null) | ||||
|   const overlayTimeout = useRef(null) | ||||
|   const videoWrapperEl = useRef(null) | ||||
|   const [videoReady, setVideoReady] = useState(false) | ||||
|   // const [isFullscreen, toggleFullscreen] = useToggle(false)
 | ||||
|   // const [chatActive, setChatActive] = useState(false)
 | ||||
|   const [overlayActive, setOverlayActiveState] = useState(true) | ||||
|   const ptVideo = useRef(null) | ||||
| 
 | ||||
| @ -43,6 +45,37 @@ const Video = ({ playing, setPlaying, src, title, org }) => { | ||||
|     } | ||||
|   }, [playing]) | ||||
| 
 | ||||
|   const goFullscreen = () => { | ||||
|     // toggleFullscreen()
 | ||||
|   } | ||||
| 
 | ||||
|   const exitFullscreen = () => { | ||||
|     // toggleFullscreen()
 | ||||
|   } | ||||
| 
 | ||||
|   const handleKeyPress = keyCode => { | ||||
|     if (keyCode === 32) { | ||||
|       setPlaying(!playing) | ||||
|     } | ||||
|     // if (keyCode === 70 && !isFullscreen) {
 | ||||
|     // console.log('goFullscreen')
 | ||||
|     // goFullscreen()
 | ||||
|     // }
 | ||||
|     // if (keyCode === 70 && isFullscreen) {
 | ||||
|     // console.log('exitFullscreen')
 | ||||
|     // exitFullscreen()
 | ||||
|     // }
 | ||||
|   } | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     window.addEventListener('keydown', ({ keyCode }) => handleKeyPress(keyCode)) | ||||
| 
 | ||||
|     return () => | ||||
|       window.removeEventListener('keydown', ({ keyCode }) => | ||||
|         handleKeyPress(keyCode) | ||||
|       ) | ||||
|   }, []) | ||||
| 
 | ||||
|   const activateOverlay = () => { | ||||
|     clearTimeout(overlayTimeout.current) | ||||
|     setOverlayActiveState(true) | ||||
| @ -58,8 +91,14 @@ const Video = ({ playing, setPlaying, src, title, org }) => { | ||||
|       $active={overlayActive || !playing} | ||||
|       onClick={() => setPlaying(!playing)} | ||||
|       onMouseMove={activateOverlay} | ||||
|       // ref={videoWrapperEl}
 | ||||
|     > | ||||
|       <Overlay active={overlayActive || !playing} title={title} org={org} /> | ||||
|       <Overlay | ||||
|         active={overlayActive || !playing} | ||||
|         title={title} | ||||
|         org={org} | ||||
|         setInfoActive={setInfoActive} | ||||
|       /> | ||||
|       <Iframe | ||||
|         sandbox="allow-same-origin allow-scripts allow-popups" | ||||
|         src={`${src}?api=1&controls=false`} | ||||
|  | ||||
| @ -1,14 +1,14 @@ | ||||
| import { h } from 'preact' | ||||
| import { Fragment, h } from 'preact' | ||||
| import { bool, string } from 'prop-types' | ||||
| 
 | ||||
| import Logo from '../Logo' | ||||
| import { P } from '../Text' | ||||
| import { OverlayWrapper, TopLeft } from './styles' | ||||
| import { H2, P } from '../Text' | ||||
| import { InfoButton, OverlayWrapper, TopLeft } from './styles' | ||||
| 
 | ||||
| const VideoOverlay = ({ active, title, org }) => { | ||||
|   const displayTitle = `${title}${org ? ` — ${org}` : ''}` | ||||
| const VideoOverlay = ({ active, title, org, setInfoActive }) => ( | ||||
|   // const displayTitle = `${title}${org ? ` — ${org}` : ''}`
 | ||||
| 
 | ||||
|   return ( | ||||
|   <Fragment> | ||||
|     <OverlayWrapper> | ||||
|       <TopLeft $active={active}> | ||||
|         <Logo active={active} /> | ||||
| @ -18,12 +18,13 @@ const VideoOverlay = ({ active, title, org }) => { | ||||
|             margin-top: 16px; | ||||
|           `}
 | ||||
|         > | ||||
|           {displayTitle} | ||||
|           {title} | ||||
|         </P> | ||||
|       </TopLeft> | ||||
|     </OverlayWrapper> | ||||
|   ) | ||||
| } | ||||
|     <InfoButton $active={active} onClick={() => setInfoActive(true)} /> | ||||
|   </Fragment> | ||||
| ) | ||||
| 
 | ||||
| VideoOverlay.propTypes = { | ||||
|   active: bool, | ||||
|  | ||||
| @ -1,4 +1,6 @@ | ||||
| import styled, { css } from 'styled-components' | ||||
| import { colours } from '../../assets/theme' | ||||
| import burb from '../../assets/img/IconSM.png' | ||||
| 
 | ||||
| export const OverlayWrapper = styled.div` | ||||
|   z-index: 2; | ||||
| @ -18,4 +20,39 @@ export const TopLeft = styled.div` | ||||
|       transform: translateY(0%); | ||||
|       opacity: 1; | ||||
|     `};
 | ||||
| 
 | ||||
|   p, | ||||
|   svg { | ||||
|     backdrop-filter: blur(20px); | ||||
|     background-color: ${colours.midnight}40; | ||||
|     padding: 4px 8px; | ||||
|     display: inline-block; | ||||
|     margin-right: 45%; | ||||
|     border-radius: 5px; | ||||
|   } | ||||
| ` | ||||
| 
 | ||||
| export const InfoButton = styled.img.attrs(() => ({ | ||||
|   src: burb, | ||||
| }))` | ||||
|   opacity: 0.001; | ||||
|   transform: translateY(-20%); | ||||
|   transition: all 0.2s ease-in-out; | ||||
|   transition-delay: 0.2s; | ||||
|   position: fixed; | ||||
|   right: 2em; | ||||
|   top: 2em; | ||||
|   width: 45px; | ||||
|   height: 45px; | ||||
|   z-index: 100; | ||||
|   ${props => | ||||
|     props.$active && | ||||
|     css` | ||||
|       transform: translateY(0%); | ||||
|       opacity: 1; | ||||
|     `};
 | ||||
| 
 | ||||
|   &:hover { | ||||
|     filter: invert(1); | ||||
|   } | ||||
| ` | ||||
|  | ||||
| @ -2,6 +2,7 @@ export default { | ||||
|   en: { | ||||
|     nextStream: 'Next streams', | ||||
|     pastStream: 'Latest streams', | ||||
|     nowPlaying: 'Now playing', | ||||
|     noStreams: 'No upcoming streams, check back soon.', | ||||
|     underscoreTagline: ['LEAVE THE', 'SURVEILLANCE ECONOMY', '— TOGETHER.'], | ||||
|     streamDateFuture: 'Going live at: ', | ||||
|  | ||||
| @ -1,20 +1,63 @@ | ||||
| import { useEffect, useState } from 'preact/hooks' | ||||
| import { useEffect, useState, useRef } from 'preact/hooks' | ||||
| import axios from 'axios' | ||||
| import ical from 'ical' | ||||
| import config from '../data/config' | ||||
| 
 | ||||
| export const useCalendar = () => { | ||||
|   const [data, setData] = useState(null) | ||||
| export const useEventStream = () => { | ||||
|   const [data, setData] = useState([]) | ||||
|   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)) | ||||
|     const calItems = Object.values(ical.parseICS(responseData)) | ||||
|       .filter(feedItem => feedItem.type === 'VEVENT') | ||||
|       .sort((a, b) => new Date(a.start) - new Date(b.start)) | ||||
|     setData(streamsData) | ||||
| 
 | ||||
|     await Promise.all( | ||||
|       calItems.map(async calItem => { | ||||
|         if (calItem.url) { | ||||
|           const id = calItem.url.val.split('/').pop() | ||||
|           const { | ||||
|             data: { | ||||
|               account, | ||||
|               category, | ||||
|               channel, | ||||
|               embedPath, | ||||
|               language, | ||||
|               state, | ||||
|               previewPath, | ||||
|               views, | ||||
|               duration, | ||||
|             }, | ||||
|             data: nesd, | ||||
|           } = await axios.get(`https://tv.undersco.re/api/v1/videos/${id}`) | ||||
| 
 | ||||
|           console.log({ nesd }) | ||||
| 
 | ||||
|           const item = { | ||||
|             title: calItem.summary, | ||||
|             account, | ||||
|             category, | ||||
|             channel, | ||||
|             description: calItem.description, | ||||
|             embedPath, | ||||
|             language, | ||||
|             state, | ||||
|             previewPath, | ||||
|             views, | ||||
|             start: calItem.start, | ||||
|             end: calItem.end, | ||||
|             id, | ||||
|             duration, | ||||
|             videoUrl: calItem?.url?.val, | ||||
|           } | ||||
|           setData(arr => [...arr, item]) | ||||
|         } | ||||
|       }) | ||||
|     ) | ||||
| 
 | ||||
|     setLoading(false) | ||||
|   } | ||||
| 
 | ||||
| @ -24,73 +67,3 @@ export const useCalendar = () => { | ||||
| 
 | ||||
|   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])
 | ||||
|  | ||||
							
								
								
									
										37
									
								
								src/hooks/dom.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/hooks/dom.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| import { useState, useEffect } from 'preact/hooks' | ||||
| 
 | ||||
| const getWidth = () => | ||||
|   window.innerWidth || | ||||
|   document.documentElement.clientWidth || | ||||
|   document.body.clientWidth | ||||
| 
 | ||||
| const getHeight = () => | ||||
|   window.innerHeight || | ||||
|   document.documentElement.clientHeight || | ||||
|   document.body.clientHeight | ||||
| 
 | ||||
| // save current window width in the state object
 | ||||
| export const useWindowDimensions = () => { | ||||
|   const [width, setWidth] = useState(getWidth()) | ||||
|   const [height, setHeight] = useState(getHeight()) | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     let timeoutId = null | ||||
|     const resizeListener = () => { | ||||
|       clearTimeout(timeoutId) | ||||
|       timeoutId = setTimeout(() => { | ||||
|         setWidth(getWidth()) | ||||
|         setHeight(getHeight()) | ||||
|       }, 50) | ||||
|     } | ||||
|     window.addEventListener('resize', resizeListener) | ||||
| 
 | ||||
|     // clean up function
 | ||||
|     return () => { | ||||
|       // remove resize listener
 | ||||
|       window.removeEventListener('resize', resizeListener) | ||||
|     } | ||||
|   }, []) | ||||
| 
 | ||||
|   return { width, height } | ||||
| } | ||||
							
								
								
									
										9
									
								
								src/hooks/utility.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/hooks/utility.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| import { useCallback, useState } from 'preact/hooks' | ||||
| 
 | ||||
| export const useToggle = (initialValue = false) => { | ||||
|   const [value, setValue] = useState(initialValue) | ||||
|   const toggle = useCallback(() => { | ||||
|     setValue(v => !v) | ||||
|   }, []) | ||||
|   return [value, toggle] | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user