diff --git a/index.js b/index.js index f246e8a..48108b9 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,8 @@ import SeriesPage from './src/pages/SeriesPage' import { useEventApi, useEventCalendar } from './src/hooks/data' import { useTimeout } from './src/hooks/timerHooks' import LoaderLayout from './src/pages/LoaderLayout' +import FourOhFour from './src/pages/404' +import Series from './src/pages/Series' const App = () => { const { data: calData, calLoading } = useEventCalendar() @@ -26,10 +28,14 @@ const App = () => { + {seriesData.length ? seriesData.map(series => ( )) : null} + + + ) diff --git a/src/assets/styles/index.scss b/src/assets/styles/index.scss index 026cd08..d8c11d0 100644 --- a/src/assets/styles/index.scss +++ b/src/assets/styles/index.scss @@ -1,2 +1,22 @@ @import 'reset'; @import 'fontface'; + +body { + background-color: #112b39; + overflow-x: hidden; + + scrollbar-color: #feb9b3; + scrollbar-width: thin; + + &::-webkit-scrollbar { + width: 5px; + height: 5px; + } + &::-webkit-scrollbar-track { + background-color: #f6f4f5; + } + &::-webkit-scrollbar-thumb { + background-color: #feb9b3; + border-radius: 0px; + } +} diff --git a/src/assets/theme/index.js b/src/assets/theme/index.js index c0c66df..ef0287f 100644 --- a/src/assets/theme/index.js +++ b/src/assets/theme/index.js @@ -21,13 +21,13 @@ export const textSizes = { sm: 14, md: 16, lg: 21, - xl: 32, + xl: 28, xxl: 92, hg: 200, } export const defaultTheme = { - background: colours.rose, foreground: colours.midnight, highlight: colours.highlight + background: colours.midnightDarker, foreground: colours.rose, highlight: colours.highlight } export default { diff --git a/src/components/Flex/index.js b/src/components/Flex/index.js new file mode 100644 index 0000000..eadb460 --- /dev/null +++ b/src/components/Flex/index.js @@ -0,0 +1,15 @@ +import styled from 'styled-components' + +export const Row = styled.div` + display: flex; + flex-direction: ${props => (props.reverse ? 'row-reverse' : 'row')}; + justify-content: ${props => props.justify || 'flex-start'}; + align-items: ${props => props.align || 'flex-start'}; +` + +export const Column = styled.div` + display: flex; + flex-direction: ${props => (props.reverse ? 'column-reverse' : 'column')}; + justify-content: ${props => props.justify || 'flex-start'}; + align-items: ${props => props.align || 'flex-start'}; +` diff --git a/src/components/Header/index.js b/src/components/Header/index.js new file mode 100644 index 0000000..85b5ab1 --- /dev/null +++ b/src/components/Header/index.js @@ -0,0 +1,36 @@ +import { h } from 'preact' +import { Link as ReactLink } from 'react-router-dom' +import { RightBox, StyledRow as Row } from './styles' +import { ImageLogo } from '../Logo' +import Link from '../Link' + +import navigation from '../../data/navigation' +import { colours, textSizes } from '../../assets/theme' + +const Navigation = ({ theme = {}, lang = 'en' }) => ( + + {navigation[lang].map(navItem => {navItem.label})} + +) + + +const BigHeader = ({ theme = {}, lang = 'en', ...rest }) => ( + + + + + + +) + +const MiniHeader = ({ theme = {}, lang = 'en', ...rest }) => ( + + + +) + +const Header = ({ miniHeader, ...rest }) => miniHeader ? : + +export default Header diff --git a/src/components/Header/styles.js b/src/components/Header/styles.js new file mode 100644 index 0000000..dda927f --- /dev/null +++ b/src/components/Header/styles.js @@ -0,0 +1,30 @@ +import styled from 'styled-components' +import { Row } from '../Flex' + + +export const StyledRow = styled(Row)` + pointer-events: all; + height: 100px; + background-color: ${({ theme }) => theme.background}; + color: ${({ theme }) => theme.foreground}; + position: absolute; + left: ${({ miniHeader }) => miniHeader ? 'initial' : '0'}; + top: 0; + right: 0; + z-index: 1; + + img { + max-height: 80px; + mix-blend-mode: exclusion; + padding: 1em; + } + + a:hover { + opacity: 0.5; + } +` +export const RightBox = styled(Row)` + a { + margin-right: 4em; + } +` \ No newline at end of file diff --git a/src/components/Link/index.js b/src/components/Link/index.js index 3e85cf9..18de9f8 100644 --- a/src/components/Link/index.js +++ b/src/components/Link/index.js @@ -1,6 +1,23 @@ -import styled from 'styled-components' +import { h } from 'preact' -export const Link = styled.a` - text-decoration: none; -` -export default Link +import { useRouteMatch } from 'react-router-dom' + +import { A } from '../Text' +import { RRLink } from './styles' + +const Link = ({ children, to, activeOnlyWhenExact = true, href, textProps: { colour, size } = {}, navLink, ...rest }) => { + const match = useRouteMatch({ + path: to, + exact: activeOnlyWhenExact + }) + + console.log({ colour }) + + return href ? {children} : ( + + {children} + + ) +} + +export default Link \ No newline at end of file diff --git a/src/components/Link/styles.js b/src/components/Link/styles.js new file mode 100644 index 0000000..885c46b --- /dev/null +++ b/src/components/Link/styles.js @@ -0,0 +1,32 @@ +import styled from 'styled-components' +import { Link } from 'react-router-dom' +import { colours } from '../../assets/theme' + +export const RRLink = styled(Link)` + color: ${props => { console.log({ col: props.$colour }); return props.$colour || colours.highlight }}; + text-decoration: none; + ${props => props.$navLink ? ` + font-family: Lunchtype24; + ` : ''}; + position: relative; + + ${props => props.$selected ? ` + &::before, &::after { + color: ${colours.highlight}; + font-size: 21px; + position: absolute; + top: 50%; + font-family: 'Karla'; + transform: translateY(-50%); + } + + &::before { + content: '< '; + left: -1em; + } + &::after { + content: ' >'; + right: -1em; + } + ` : ''}; +` \ No newline at end of file diff --git a/src/components/Logo/index.js b/src/components/Logo/index.js index d7a25e6..dfaa337 100644 --- a/src/components/Logo/index.js +++ b/src/components/Logo/index.js @@ -3,6 +3,8 @@ import { bool, string } from 'prop-types' import styled from 'styled-components' import { colours } from '../../assets/theme' +import LogoBird from '../../../static/logo.png' + const Logo = ({ colour = colours.offwhite, ...rest }) => ( ( ) +const Img = styled.img` + mix-blend-mode: exclusion; +` + +export const ImageLogo = (props) => {props.alt} + export default Logo diff --git a/src/components/Markdown/index.js b/src/components/Markdown/index.js index 2d775e0..2ed227b 100644 --- a/src/components/Markdown/index.js +++ b/src/components/Markdown/index.js @@ -4,8 +4,8 @@ import MarkdownRenderer from 'markdown-to-jsx' import { MarkdownWrapper } from './styles' import { P, A, H1, H2, H3, Span } from '../Text' -const Markdown = ({ children, withLinebreaks, options, ...rest }) => ( - +const Markdown = ({ children, withLinebreaks, options, theme, ...rest }) => ( + theme && theme.highlight || colours.highlight}; } img { diff --git a/src/components/SeriesCard/index.js b/src/components/SeriesCard/index.js new file mode 100644 index 0000000..783a96e --- /dev/null +++ b/src/components/SeriesCard/index.js @@ -0,0 +1,40 @@ +import { formatDistanceToNow } from 'date-fns' +import { h } from 'preact' +import Link from '../Link' +import { H2, H3, Label } from '../Text' +import strings from '../../data/strings' +import { Img, LabelBlock, Wrapper } from './styles' +import { andList } from '../../helpers/string' +import { colours } from '../../assets/theme' + +const SeriesCard = ({ series: { image, episodes: allEpisodes, title, subtitle, hosts: hostsArray, slug, }, isPast, ...rest }) => { + const episodes = allEpisodes[isPast ? 'past' : 'future'] + const hosts = hostsArray.map(({ actor }) => actor.name) + + // return episodes.length ? ( + return ( + + + + + {episodes.length} {strings.en.episodes} + + + {isPast ? strings.en.lastStream : strings.en.nextStream} {episodes && episodes.length && formatDistanceToNow(new Date(episodes[0].endsOn), { addSuffix: true })} + + + +

{title}

+

{subtitle}

+ {hosts.length ? : null} +
+ + ) + // ) : null +} + +export default SeriesCard diff --git a/src/components/SeriesCard/styles.js b/src/components/SeriesCard/styles.js new file mode 100644 index 0000000..45de9b4 --- /dev/null +++ b/src/components/SeriesCard/styles.js @@ -0,0 +1,43 @@ +import styled from 'styled-components' +import { colours } from '../../assets/theme' +import { Label } from '../Text' + +export const Wrapper = styled.div` + display: flex; + flex-direction: column; + margin-right: 3em; + width: min-content; + + h2 { + margin-bottom: 0.1em; + } + h3 { + margin-bottom: 0.5em; + } + + &:hover div { + filter: invert() + } +` + +export const Img = styled.div` + background: url(${({ src }) => src}); + width: 380px; + height: 215px; + background-size: cover; + position: relative; + background-position: center; + margin: 0 0 1em 0; +` + +export const LabelBlock = styled(Label).attrs(props => ({ + colour: props.colour || colours.midnightDarker +}))` + position: absolute; + background-color: ${colours.white}; + right: 0; + ${({ $position }) => $position === 'top' ? + 'top: 0;' : 'bottom: 0;' + }; + padding: 4px +` \ No newline at end of file diff --git a/src/components/Text/index.js b/src/components/Text/index.js index fb1be7f..a4fa6e3 100644 --- a/src/components/Text/index.js +++ b/src/components/Text/index.js @@ -78,11 +78,24 @@ export const H1 = ({ children, size, ...rest }) => ( ) -export const H2 = ({ children, ...rest }) => ( +export const H2 = ({ children, size, ...rest }) => ( + {children} + +) + +export const H3 = ({ children, size, ...rest }) => ( + ( {children} ) -export const Span = ({ children, ...rest }) => ( - +export const Span = ({ children, colour, size, weight, ...rest }) => ( + {children} ) @@ -120,8 +133,8 @@ export const Label = ({ children, size, ...rest }) => ( {children} ) -export const A = ({ children, ...rest }) => ( - +export const A = ({ children, colour, fontFamily, ...rest }) => ( + {children} ) diff --git a/src/components/Text/styles.js b/src/components/Text/styles.js index d39503d..64143cb 100644 --- a/src/components/Text/styles.js +++ b/src/components/Text/styles.js @@ -3,18 +3,18 @@ import { colours } from '../../assets/theme' export const TextBase = styled.span` ${({ - $size, - $fontStyle, - weight, - colour, - align, - lineHeight, - opacity = 1, - $fontFamily: fontFamily, - selectable, - underline, - $sizeUnit, - }) => css` + $size, + $fontStyle, + weight, + colour, + align, + lineHeight, + opacity = 1, + $fontFamily: fontFamily, + selectable, + underline, + $sizeUnit, +}) => css` font-family: ${fontFamily}; font-weight: ${weight}; text-align: ${align}; diff --git a/src/data/credits.md b/src/data/credits.md deleted file mode 100644 index 5635ead..0000000 --- a/src/data/credits.md +++ /dev/null @@ -1,17 +0,0 @@ -## Credits - -A [NEW DESIGN CONGRESS](https://newdesigncongress.org) project - -Series operated by **[RECLAIMFUTURES](https://reclaimfutures.org)** - -Infrastructure by **[UNDERSCO.RE](https://undersco.re)** - -Stream Design by **[BENJAMIN JONES](mailto:benjamin@newdesigncongress.org)** - -Host & Research by **[CADE DIEHM](https://shiba.computer)** - -Stream Backgrounds by **[IGNATIUS GILFEDDER](https://ignatius.design)** - -Music \*\*\*\*by: [♥ GOJII ♥](https://gojii.bandcamp.com/), [ABELARD](https://abelard.bandcamp.com/), [Frog of Earth](https://frogoftheearth.bandcamp.com/) & [spatial manufacture ltd.](https://spatialmanufactureltd.bandcamp.com/)\*\* - -Simulcasted at [UNDERSCORE TV](https://stream.undersco.re) and [Twitch](https://twitch.tv/newdesigncongress) diff --git a/src/data/intro.md b/src/data/intro.md deleted file mode 100644 index bce3de5..0000000 --- a/src/data/intro.md +++ /dev/null @@ -1,3 +0,0 @@ -[NEW DESIGN CONGRESS](https://newdesigncongress.org) x [RECLAIMFUTURES](https://reclaimfutures.org) present _The Para-Real: Finding the Future in Unexpected Places,_ a livestream series about subcultures building livelihoods in spite of platform exploitation. Over 12 episodes streamed weekly, we meet filmmakers who have never met their actors, artists building their own networks of value, documentarians exploring digital identity, and members of resilient subcultures. All of these people share a commonality: they have an innate understanding of the _Para-Real,_ and have seized upon it to better their surroundings. - -Between the digital realm and our physical world, _The Para-Real_ is a third space, equally material but poorly understood. The _Para-Real_ is where class politics, economics and the outcomes of hardware and infrastructure design collide. It manifests as the desire for play that turns young Minecraft players into network administrators, the moments where digital security meets physical safety, the creation of mutually-supportive artist-driven marketplaces or the tension inherent in Virtual Reality’s land-grab against the living room. The _Para-Real_ is the embodiment of the observation, ‘_We shape our tools, and thereafter our tools shape us._’ _The future is not a Zoom call_. The digital systems we are confined to today merge protocol with platform to prey on isolation and extract value from labour. That we grapple with this incarnation of the digital realm indicates a dominant cartel in decline. In its place is a vacuum. We must resist the immature groupthink of the 90s’ vision of what the Internet can be. The _Para-Real_ is once again contested space. diff --git a/src/data/navigation.js b/src/data/navigation.js new file mode 100644 index 0000000..5b22474 --- /dev/null +++ b/src/data/navigation.js @@ -0,0 +1,16 @@ +export default { + en: [ + { + label: 'Program guide', + to: '/program' + }, + { + label: 'Series', + to: '/series' + }, + { + label: 'Archive', + href: 'https://tv.undersco.re/' + } + ] +} \ No newline at end of file diff --git a/src/data/strings.js b/src/data/strings.js index 6b401c8..a7a0fbf 100644 --- a/src/data/strings.js +++ b/src/data/strings.js @@ -1,6 +1,6 @@ export default { en: { - nextStream: 'Program', + program: 'Program', pastStream: 'Previous Episodes', nowPlaying: 'Now playing', noStreams: 'No upcoming streams, check back soon.', @@ -11,5 +11,14 @@ export default { watchEpisode: 'Watch Episode', watchTrailer: 'Watch the trailer', joinStream: 'Click to join stream', + fourohfour: '404', + pageNotFound: 'Page not found', + goHome: 'Return to Home', + series: 'Series', + currentSeries: 'Current Series', + pastSeries: 'Past Series', + lastStream: 'Last stream', + nextStream: 'Next stream', + episodes: 'episodes', }, } diff --git a/src/helpers/string.js b/src/helpers/string.js index c8daa5b..e41aa5a 100644 --- a/src/helpers/string.js +++ b/src/helpers/string.js @@ -27,4 +27,38 @@ export const camelise = str => { return index === 0 ? letter.toLowerCase() : letter.toUpperCase(); }) .replace(/\s+/g, ''); +}; + +/** + * + * Takes an array of strings and returns a string list separated by + * commas and an 'and' connector before the last item. + * @param {Array} list - List of strings || 2d array of strings. [0] = string to display, [1] = string to inject into before/after. + * @param {string} [connector] - Optional connector to join the last item, defaults to '&'. + * @param {Object} [wrapEachItem] - Optional object to wrap each item with a string. + * @param {string} [wrapEachItem.before] - Optional string to prefix each item. + * @param {string} [wrapEachItem.after] - Optional string to suffix each item. + * @param {string} [replace] - String to be replaced by second part of list item array if supplied. + * + */ +export const andList = (list, connector = '&', wrapEachItem, replace = '{#}') => { + if (!Array.isArray(list)) return list; + + const wrapItem = (item) => { + if (wrapEachItem) { + if (Array.isArray(item)) { + return `${wrapEachItem.before.replace(replace, item[1])}${item[0]}${wrapEachItem.after.replace(replace, item[1])}`; + } + return `${wrapEachItem.before}${item}${wrapEachItem.after}`; + } + return item; + }; + + return list.map((item, index) => { + if (index + 1 === list.length && index !== 0) { + return ` ${connector} ${wrapItem(item)}`; + } + + return list.length === 1 || index === list.length - 2 ? wrapItem(item) : `${wrapItem(item)}, `; + }).join(''); }; \ No newline at end of file diff --git a/src/helpers/utils.js b/src/helpers/utils.js new file mode 100644 index 0000000..d829a5e --- /dev/null +++ b/src/helpers/utils.js @@ -0,0 +1,5 @@ +export const splitArray = (arr, num = 2) => arr.reduce((result, value, index, array) => { + if (index % num === 0) + result.push(array.slice(index, index + num)) + return result +}, []) \ No newline at end of file diff --git a/src/hooks/data.js b/src/hooks/data.js index fce28b5..7ae13fa 100644 --- a/src/hooks/data.js +++ b/src/hooks/data.js @@ -3,6 +3,7 @@ import axios from 'axios' import ICAL from 'ical.js' import config from '../data/config' import { useSeriesStore } from '../store/index' +import 'regenerator-runtime/runtime' export const useEventCalendar = () => { const [data, setData] = useState([]) @@ -99,7 +100,7 @@ export const useEventCalendar = () => { export const useEventApi = () => { const [series, setSeries] = useSeriesStore(store => [store.series, store.setSeries]) - const [loading, setLoading] = useState(true) + const [loading, setLoading] = useState(!!series.length) async function fetchData() { diff --git a/src/layouts/InfoLayout/index.js b/src/layouts/InfoLayout/index.js index b58a556..4184505 100644 --- a/src/layouts/InfoLayout/index.js +++ b/src/layouts/InfoLayout/index.js @@ -1,53 +1,40 @@ import { h } from 'preact' import { bool } from 'prop-types' +import { Link } from 'react-router-dom' -import { H1, Label } from '../../components/Text' +import { H1 } from '../../components/Text' import { Wrapper, - TaglineContainer, Content, Hero, - FadeBottom, + FadeTop, + PositionedLink, } from './styles' -import { colours } from '../../assets/theme' -import { NdcLogo, RFLogo } from '../../components/Logo' +import Header from '../../components/Header' +import { ImageLogo } from '../../components/Logo' -const InfoLayout = ({ title, subtitle, image, children, theme }) => { - console.log({ theme }) - return ( - - - {children} - - -
-

{title}

-

( + + + + + + {children} + + +
+

{title}

+

- {subtitle} -

-

- - - - - - - - - - -
-
- ) -} - -InfoLayout.propTypes = { - loading: bool, -} + > + {subtitle} + + + + +) export default InfoLayout diff --git a/src/layouts/InfoLayout/styles.js b/src/layouts/InfoLayout/styles.js index 289cbe3..acccbed 100644 --- a/src/layouts/InfoLayout/styles.js +++ b/src/layouts/InfoLayout/styles.js @@ -1,7 +1,7 @@ +import { Link } from 'react-router-dom' import styled from 'styled-components' import { colours } from '../../assets/theme' - -import Logo from '../../components/Logo' +import { ImageLogo as Logo } from '../../components/Logo' const heroWidth = 'calc(100vw - 600px - 4em)' @@ -29,9 +29,9 @@ export const Wrapper = styled.div` h3 { color: ${props => props.theme.foreground}; } - a { + /* a { color: ${props => props.theme.highlight}; - } + } */ button { color: ${props => props.theme.foreground}; @@ -51,23 +51,8 @@ export const Top = styled.div` width: 50%; ` -const gradientColourLight = '#F8E5E2' -const gradientColourDark = colours.midnightDarker -const getGradient = (direction, lightDark) => - `linear-gradient(to ${direction}, ${lightDark === 'dark' ? gradientColourDark : gradientColourLight - }ee 0%,${lightDark === 'dark' ? gradientColourDark : gradientColourLight - }00 100%);` - -// prettier-ignore -export const Fade = styled.div` - width: 100%; - background-color: linear; - position: fixed; - padding: 2em 0 1em 2em; - top: 0; - left: 0; - background: ${getGradient('bottom')}; -` +const getGradient = (direction, colour) => + `linear-gradient(to ${direction}, ${colour}ee 0%,${colour}00 100%);` export const Hero = styled.div` width: ${heroWidth}; @@ -83,16 +68,17 @@ export const Hero = styled.div` box-sizing: border-box; display: flex; flex-direction: column; - justify-content: space-between; + justify-content: flex-end; pointer-events: none; h1, h2 { color: ${colours.offwhite}; } - h1:not(:last-of-type) { + h1{ + margin-bottom: 0.2em; + &:not(:last-of-type) { font-size: 12vw; - margin-bottom: 0.5em; @media screen and (max-height: 600px) { font-size: 20vh; @@ -100,7 +86,7 @@ export const Hero = styled.div` @media screen and (max-width: 1200px) { font-size: 20vh; } - } + }} @media screen and (max-width: 1000px) { display: none; @@ -118,27 +104,43 @@ export const LoaderWrapper = styled.div` ` export const Content = styled.div` - /* margin-bottom: 3em; */ + padding-top: 80px; + + img.img-logo { + max-height: 80px; + mix-blend-mode: exclusion; + /* padding: 1em; */ + } ` -export const PositionedLogo = styled(Logo)`` +export const PositionedLink = styled(Link)` + position: absolute; + z-index: 2; + top: 0; + left: 0; + background-color: ${({ theme }) => theme.background}; -export const FadeBottom = styled.div` - background: ${getGradient('top', 'dark')}; + &:hover img { + filter: invert(1); + mix-blend-mode: normal; + } + + img { + max-height: 80px; + mix-blend-mode: exclusion; + padding: 0.5em 2em 0; + } +` + +export const FadeTop = styled.div` + background: ${({ colour }) => colour ? getGradient('bottom', colour) : colours.rose}; width: ${heroWidth}; position: fixed; - bottom: 0em; + top: 0em; padding-bottom: 0.5em; right: 0; - /* left: 0; */ pointer-events: none; min-height: 75px; - - /* @media screen and (max-width: 800px) { - h1 { - font-size: 24px; - } - } */ ` export const TaglineContainer = styled.div` diff --git a/src/layouts/Page/index.js b/src/layouts/Page/index.js index 2a1fecc..ce3c19f 100644 --- a/src/layouts/Page/index.js +++ b/src/layouts/Page/index.js @@ -3,10 +3,12 @@ import PropTypes, { oneOfType, shape, string } from 'prop-types' import SEO from '../../components/Seo' -// import Header from '../../molecules/Header' +import Header from '../../components/Header' import { capitaliseFirstLetter } from '../../helpers/string' +import { defaultTheme } from '../../assets/theme' +import { ThemedBlock } from './styles' -const Page = ({ children, title = '', description, metaImg, backTo, noindex }) => ( +const Page = ({ children, title = '', description, metaImg, backTo, noindex, withHeader = true, theme = defaultTheme }) => ( - {/*
*/} - {children} + {withHeader ?
: null} + + {children} + ) diff --git a/src/layouts/Page/styles.js b/src/layouts/Page/styles.js new file mode 100644 index 0000000..3456bc9 --- /dev/null +++ b/src/layouts/Page/styles.js @@ -0,0 +1,12 @@ +import styled from 'styled-components' +// import { defaultTheme } from '../../assets/theme' + +export const ThemedBlock = styled.div` + color: ${({ theme }) => theme.foreground}; + background-color: ${({ theme }) => theme.background}; + padding-top: ${({ withHeader }) => withHeader ? '100px' : 0}; + min-height: 100vh; + height: 100%; + min-width: 100vw; + box-sizing: border-box; +` \ No newline at end of file diff --git a/src/pages/404/index.js b/src/pages/404/index.js new file mode 100644 index 0000000..e5c70d3 --- /dev/null +++ b/src/pages/404/index.js @@ -0,0 +1,23 @@ +import { h } from 'preact' + +import translations from '../../data/strings' +import { H2 } from '../../components/Text' +import { + Wrapper, + Title, + StyledLink as Link +} from './styles' +import { textSizes } from '../../assets/theme' +import Page from '../../layouts/Page' + +const FourOhFour = () => ( + + + {translations.en.fourohfour} +

{translations.en.pageNotFound}

+ {translations.en.goHome} +
+
+) + +export default FourOhFour diff --git a/src/pages/404/styles.js b/src/pages/404/styles.js new file mode 100644 index 0000000..83b219c --- /dev/null +++ b/src/pages/404/styles.js @@ -0,0 +1,33 @@ +import styled from 'styled-components' +import { colours } from '../../assets/theme' +import { H1 } from '../../components/Text' +import Link from '../../components/Link' + +export const Wrapper = styled.div` + height: calc(100vh - 100px); + width: 100vw; + padding: 2em; + display: flex; + justify-content: center; + flex-direction: column; + align-items: center; + background-color: ${colours.midnightDarker}; + box-sizing: border-box; + + + @media screen and (max-width: 1200px) { + padding: 1.5em; + } + @media screen and (max-width: 800px) { + padding: 1em; + } +` + +export const Title = styled(H1)` + margin-bottom: 0.2em +` + +export const StyledLink = styled(Link)` + margin-top: 1em; +` + diff --git a/src/pages/LoaderLayout/styles.js b/src/pages/LoaderLayout/styles.js index 44ac7a6..121e18e 100644 --- a/src/pages/LoaderLayout/styles.js +++ b/src/pages/LoaderLayout/styles.js @@ -4,14 +4,14 @@ import bg from '../../assets/img/hero/1lg.png' // import { H1 } from '../../components/Text' -import Logo from '../../components/Logo' +import { ImageLogo as Logo } from '../../components/Logo' -const heroWidth = '66vw' +const heroWidth = 'calc(100vw - 600px - 4em)' export const Wrapper = styled.div` height: 100vh; width: 100vw; - padding: 2em; + /* padding: 2em; */ display: flex; background-color: ${colours.midnightDarker}; box-sizing: border-box; @@ -25,10 +25,10 @@ export const Wrapper = styled.div` } @media screen and (max-width: 1200px) { - padding: 1.5em; + /* padding: 1.5em; */ } @media screen and (max-width: 800px) { - padding: 1em; + /* padding: 1em; */ } ` @@ -96,7 +96,7 @@ export const LoaderWrapper = styled.div` height: 100vh; position: fixed; top: 0; - width: 33vw; + width: calc(600px + 4em); @media screen and (max-width: 1000px) { width: 100vw; @@ -108,9 +108,10 @@ export const Content = styled.div` ` export const PositionedLogo = styled(Logo)` - position: fixed; - top: 2em; - left: 3em; + /* position: fixed; */ + max-height: 80px; + mix-blend-mode: exclusion; + padding: 1em; ` export const FadeBottom = styled.div` diff --git a/src/pages/Series/index.js b/src/pages/Series/index.js new file mode 100644 index 0000000..99c8315 --- /dev/null +++ b/src/pages/Series/index.js @@ -0,0 +1,53 @@ +/* eslint-disable react/prop-types */ +import { isWithinInterval } from 'date-fns' +import { h } from 'preact' +import { H1, H2 } from '../../components/Text' +import strings from '../../data/strings' +import { useEventApi } from '../../hooks/data' +import { Content, SeriesGrid, SeriesRow } from './styles' + +import Page from '../../layouts/Page' +import SeriesCard from '../../components/SeriesCard' +import { colours } from '../../assets/theme' + +const Series = () => { + const { data: seriesDataArray } = useEventApi() + const pastSeries = [] + + const currentSeries = seriesDataArray.filter(series => { + // const seriesInTheLastMonth = series.episodes.past.filter(episode => { + + // }) + if (series.episodes.future.length) { + return true + } + + pastSeries.push(series) + return false + + }) + + + return ( + + + +

{strings.en.currentSeries}

+ + {currentSeries.map(series => ( + + ))} + +

{strings.en.pastSeries}

+ + {pastSeries.map(series => ( + + ))} + +
+
+
+ ) +} + +export default Series diff --git a/src/pages/Series/styles.js b/src/pages/Series/styles.js new file mode 100644 index 0000000..80ff761 --- /dev/null +++ b/src/pages/Series/styles.js @@ -0,0 +1,14 @@ +import styled from 'styled-components' +import { Row } from '../../components/Flex' + +export const Content = styled.div` + padding-top: 64px; +` + +export const SeriesGrid = styled.div` + margin-left: 32px; +` + +export const SeriesRow = styled(Row)` + margin: 3em 0 6em 0; +` \ No newline at end of file diff --git a/src/pages/SeriesPage/index.js b/src/pages/SeriesPage/index.js index 6639b1f..c3ade91 100644 --- a/src/pages/SeriesPage/index.js +++ b/src/pages/SeriesPage/index.js @@ -18,6 +18,9 @@ import { import config from '../../data/config' import Page from '../../layouts/Page' +import { splitArray } from '../../helpers/utils' +import Header from '../../components/Header' +import theme from '../../assets/theme' const SeriesPage = ({ data }) => { @@ -39,14 +42,17 @@ const SeriesPage = ({ data }) => { tzShort = tzShort[1].match(/[A-Z]/g).join('') } + const links = data.links.length ? splitArray(data.links, 2) : null + + return ( - +

{data.title}:

{data.subtitle}

- {data.description} + {data.description} {data.trailer ? ( @@ -54,9 +60,9 @@ const SeriesPage = ({ data }) => { ) : null} - {data.links.length ? - - {data.links.map(link => ( + {links ? + links.map(linkRow => + {linkRow.map(link => ( { ))} - : null + ) : null }
{data.episodes.future.length ? ( - {translations.en.nextStream}: + {translations.en.program}: {data.episodes.future.map(feeditem => ( { theme={data.theme} key={feeditem.beginsOn} hasPassed - onClickButton={() => - setEmbedUrl(`${config.peertube_root}${feeditem.embedPath}`) - } + onClickButton={() => null} // todo: fix this {...feeditem} /> ))} ) : null} - + {data.credits ? Credits - {credits} - + {credits} + : null}
diff --git a/src/pages/SeriesPage/styles.js b/src/pages/SeriesPage/styles.js index 280b93a..33820a3 100644 --- a/src/pages/SeriesPage/styles.js +++ b/src/pages/SeriesPage/styles.js @@ -9,10 +9,9 @@ import Markdown from '../../components/Markdown' import Logo from '../../components/Logo' import translations from '../../data/strings' import CrossSvg from '../../components/Svg/Cross' -import PlaySvg from '../../components/Svg/Play' -import { P, H1, H2, Span, Label } from '../../components/Text' -import { Link } from '../../components/Link' +import { H1, H2, Span, Label } from '../../components/Text' +import Link from '../../components/Link' import Button from '../../components/Button' export const TrailerContainer = styled.div` @@ -104,7 +103,8 @@ export const PositionedCross = styled(CrossSvg)` export const VCWrapper = styled.div` max-width: 600px; - margin: 0 0 6em 2px; + margin: 0 0 0 2px; + padding-bottom: 3em; button { margin-top: 16px; @@ -139,13 +139,15 @@ const renderTitles = titles => export const EpisodeCard = ({ title, + image, + + description, beginsOn, hasPassed, videoUrl, onClickButton, tzShort, - image, theme, }) => { const startDate = new Date(beginsOn) @@ -174,7 +176,7 @@ export const EpisodeCard = ({ )} - {description} + {description} {hasPassed ? ( ) : ( @@ -193,13 +195,10 @@ export const EpisodeCard = ({ } EpisodeCard.propTypes = { - title: string, description: string, beginsOn: instanceOf(Date), onClickButton: func, tzShort: string, - image: string, - previewPath: string, hasPassed: bool, videoUrl: string, } diff --git a/src/store/helpers.js b/src/store/helpers.js index 4a0e4b8..7e4215a 100644 --- a/src/store/helpers.js +++ b/src/store/helpers.js @@ -1,10 +1,10 @@ -export const getMetadataByKey = (episode, key) => { +export const getMetadataByKey = (episode, key, firstItem = true) => { const filteredItems = episode.metadata.length ? episode.metadata.filter( - meta => meta.key === key + meta => meta.key.includes(key) ) : null if (filteredItems) { - return filteredItems[0].value + return firstItem ? filteredItems[0].value : filteredItems } return null @@ -16,11 +16,20 @@ export const getPostByKey = (posts, key) => { } export const getResourcesByKey = (resources, key, lookup = 'title') => { - const filteredResources = resources.elements.length ? resources.elements.filter(resource => resource[lookup] === key) : [] + const filteredResources = resources.elements.length ? resources.elements.filter(resource => resource[lookup].includes(key)) : [] if (!filteredResources.length) return null return filteredResources } -export const getPeertubeIDfromUrl = (string) => string && string.includes('https://tv.undersco.re') ? string.split('/').pop() : string \ No newline at end of file +export const getPeertubeIDfromUrl = (string) => string && string.includes('https://tv.undersco.re') ? string.split('/').pop() : string + +export const getEpisodeCode = (episode) => { + const metaItems = getMetadataByKey(episode, 'mz:plain:', false) + if (metaItems && metaItems.length) { + // TODO + } + + return 'TODO' +} \ No newline at end of file diff --git a/src/store/index.js b/src/store/index.js index 3f86ef1..72ab87a 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2,14 +2,15 @@ import create from 'zustand' import striptags from 'striptags' import { isFuture, isPast } from 'date-fns' import { slugify } from '../helpers/string' -import { getMetadataByKey, getPostByKey, getResourcesByKey, getPeertubeIDfromUrl } from './helpers' +import { getMetadataByKey, getPostByKey, getResourcesByKey, getPeertubeIDfromUrl, getEpisodeCode } from './helpers' import { colours, defaultTheme } from '../assets/theme' export const [useSeriesStore] = create(set => ({ series: [], setSeries: seriesArray => { - const allSeries = seriesArray.map(({ name, organizedEvents, posts, resources, banner, summary }) => { + const allSeries = seriesArray.map(({ name, organizedEvents, posts, resources, banner, summary, members }) => { + const allEpisodes = organizedEvents.elements.length ? organizedEvents.elements.map(ep => ({ title: ep.title, @@ -18,11 +19,15 @@ export const [useSeriesStore] = create(set => ({ description: ep.description, media: ep.media, image: ep.picture ? ep.picture.url : null, - peertubeId: getPeertubeIDfromUrl(getMetadataByKey(ep, 'mz:live:peertube:url')), + peertubeId: getPeertubeIDfromUrl(getMetadataByKey(ep, 'peertube:url')), + code: getEpisodeCode(ep) })) : [] const trailer = getResourcesByKey(resources, 'SERIES_TRAILER')?.[0]?.resourceUrl ?? null const theme = striptags(getPostByKey(posts, 'THEME')) + const orgLinks = getResourcesByKey(resources, 'ORG_LINK:')?.map(link => link.title) + + console.log({ orgLinks }) const series = { @@ -39,8 +44,9 @@ export const [useSeriesStore] = create(set => ({ slug: slugify(name), credits: getPostByKey(posts, 'SERIES_CREDITS'), trailer, - links: getResourcesByKey(resources, 'LINK') || [], - theme: theme ? JSON.parse(theme) : defaultTheme + links: getResourcesByKey(resources, 'SERIES_LINK') || [], + theme: theme ? JSON.parse(theme) : defaultTheme, + hosts: members.elements.filter(({ actor }) => actor.name !== 'streamappbot') } return series }) diff --git a/static/logo.png b/static/logo.png new file mode 100644 index 0000000..f3ba84b Binary files /dev/null and b/static/logo.png differ