header work WIP

This commit is contained in:
sunda 2021-10-20 16:32:27 +02:00
parent b2fad77434
commit 6d2090eea9
12 changed files with 165 additions and 82 deletions

View File

@ -26,6 +26,13 @@ export const textSizes = {
hg: 200, hg: 200,
} }
export const screenSizes = {
xs: 670,
sm: 800,
md: 1000,
lg: 1500,
}
export const defaultTheme = { export const defaultTheme = {
background: colours.midnightDarker, foreground: colours.rose, highlight: colours.highlight background: colours.midnightDarker, foreground: colours.rose, highlight: colours.highlight
} }

View File

@ -1,36 +1,66 @@
import { h } from 'preact' import { h } from 'preact'
import { Link as ReactLink } from 'react-router-dom' import { Link as ReactLink } from 'react-router-dom'
import { RightBox, StyledRow as Row } from './styles' import { RightBox, StyledRow as Row, Modal } from './styles'
import { ImageLogo } from '../Logo' import { ImageLogo } from '../Logo'
import { useWindowSize } from '../../hooks/dom'
import Link from '../Link' import Link from '../Link'
import { Span } from '../Text'
import CrossSvg from '../Svg/Cross'
import navigation from '../../data/navigation' import navigation from '../../data/navigation'
import { colours, textSizes } from '../../assets/theme' import { colours, screenSizes, textSizes } from '../../assets/theme'
import { useToggle } from '../../hooks/utility'
const Navigation = ({ theme = {}, lang = 'en' }) => ( const Navigation = ({ theme = {}, lang = 'en', headerTheme }) => navigation[lang].map(navItem => (
<RightBox as="nav"> <Link
{navigation[lang].map(navItem => <Link navLink to={navItem.to} href={navItem.href} textProps={{ navLink
size: textSizes.xl, colour: theme.foreground || colours.rose to={navItem.to}
}}>{navItem.label}</Link>)} href={navItem.href}
</RightBox> textProps={{
) size: textSizes.xl,
colour: headerTheme.foreground || theme.foreground || colours.rose
}}>
{navItem.label}
</Link>
))
const NavigationModal = ({ theme = {}, lang = 'en', headerTheme, toggleMenuOpen, ...rest }) => (
const BigHeader = ({ theme = {}, lang = 'en', ...rest }) => ( <Modal theme={theme} {...rest}>
<Row theme={theme} align="center" justify="space-between" {...rest}>
<ReactLink to="/"> <ReactLink to="/">
<ImageLogo /> <ImageLogo />
</ReactLink> </ReactLink>
<Navigation theme={theme} lang={lang} {...rest} /> <CrossSvg size={32} colour={theme.foreground} onClick={toggleMenuOpen} />
<div>
<Navigation theme={theme} lang={lang} headerTheme={theme} {...rest} />
</div>
</Modal>
)
const FullHeader = ({ theme = {}, headerTheme = {}, lang = 'en', miniHeader, isMobile, toggleMenuOpen, ...rest }) => (
<Row theme={headerTheme} align="center" justify="space-between" miniHeader={miniHeader} {...rest}>
{!miniHeader ? <ReactLink to="/">
<ImageLogo />
</ReactLink> : null}
{!isMobile ? (
<RightBox as="nav">
<Navigation theme={theme} lang={lang} headerTheme={headerTheme} {...rest} />
</RightBox>
) : <Span onClick={toggleMenuOpen} size={textSizes.xl} colour={headerTheme.foreground || theme.foreground || colours.rose} fontFamily="Lunchtype24"
>Menu</Span>}
</Row> </Row>
) )
const MiniHeader = ({ theme = {}, lang = 'en', ...rest }) => (
<Row theme={theme} align="center" justify="space-between" miniHeader {...rest}>
<Navigation theme={theme} lang={lang} {...rest} />
</Row>
)
const Header = ({ miniHeader, ...rest }) => miniHeader ? <MiniHeader {...rest} /> : <BigHeader {...rest} />
const Header = ({ miniHeader, theme, ...rest }) => {
const headerTheme = { foreground: theme.background, background: 'transparent', }
const { width: screenWidth } = useWindowSize()
const [menuOpen, toggleMenuOpen] = useToggle(false)
const isMobile = screenWidth < screenSizes.lg
if (menuOpen) return <NavigationModal toggleMenuOpen={toggleMenuOpen} theme={theme} headerTheme={headerTheme} {...rest} />
return <FullHeader toggleMenuOpen={toggleMenuOpen} menuOpen={menuOpen} miniHeader={miniHeader} isMobile={isMobile} theme={theme} headerTheme={headerTheme} {...rest} />
}
export default Header export default Header

View File

@ -1,5 +1,7 @@
import styled from 'styled-components' import styled from 'styled-components'
import { screenSizes } from '../../assets/theme'
import { Row } from '../Flex' import { Row } from '../Flex'
import CrossSvg from '../Svg/Cross'
export const StyledRow = styled(Row)` export const StyledRow = styled(Row)`
@ -19,12 +21,56 @@ export const StyledRow = styled(Row)`
padding: 1em; padding: 1em;
} }
a:hover {
opacity: 0.5; a, span {
margin-right: 2em;
cursor: pointer;
@media screen and (max-width: ${screenSizes.md}px) {
margin-right: 1em;
}
&:hover {
opacity: 0.5;
}
} }
` `
export const RightBox = styled(Row)` export const RightBox = styled(Row)`
a { `
margin-right: 4em;
export const Modal = styled.div`
z-index: 100;
background-color: ${({ theme }) => theme.background};
color: ${({ theme }) => theme.foreground};
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
pointer-events: all;
img {
max-height: 80px;
mix-blend-mode: exclusion;
padding: 1em;
}
div {
padding: 3em;
display: flex;
flex-direction: column;
}
div a {
margin-bottom: 1em;
font-size: 6vh;
display: inline-block;
line-height: 0.8;
} }
` `
export const PositionedCross = styled(CrossSvg)`
position: fixed;
right: 1em;
top: 1em;
`

View File

@ -11,8 +11,6 @@ const Link = ({ children, to, activeOnlyWhenExact = true, href, textProps: { col
exact: activeOnlyWhenExact exact: activeOnlyWhenExact
}) })
console.log({ colour })
return href ? <A href={href} colour={colour} size={size} fontFamily={navLink ? 'Lunchtype24' : null} {...rest}>{children}</A> : ( return href ? <A href={href} colour={colour} size={size} fontFamily={navLink ? 'Lunchtype24' : null} {...rest}>{children}</A> : (
<A as="span" colour={colour} size={size} {...rest}> <A as="span" colour={colour} size={size} {...rest}>
<RRLink to={to} $navLink={navLink} $colour={colour} $selected={match && navLink}>{children}</RRLink> <RRLink to={to} $navLink={navLink} $colour={colour} $selected={match && navLink}>{children}</RRLink>

View File

@ -1,5 +1,8 @@
export const slugify = (title) => { export const slugify = (title) => {
let str = title.replace(/^\s+|\s+$/g, '') // trim let str = title ? title.replace(/^\s+|\s+$/g, '') : null // trim
if (!str) return title;
str = str.toLowerCase() str = str.toLowerCase()
// remove accents, swap ñ for n, etc // remove accents, swap ñ for n, etc
@ -22,11 +25,11 @@ export const capitaliseFirstLetter = word =>
word ? `${word?.charAt(0).toUpperCase()}${word?.slice(1)}` : ''; word ? `${word?.charAt(0).toUpperCase()}${word?.slice(1)}` : '';
export const camelise = str => { export const camelise = str => {
return str return str ? str
.replace(/(?:^\w|[A-Z]|\b\w)/g, (letter, index) => { .replace(/(?:^\w|[A-Z]|\b\w)/g, (letter, index) => {
return index === 0 ? letter.toLowerCase() : letter.toUpperCase(); return index === 0 ? letter.toLowerCase() : letter.toUpperCase();
}) })
.replace(/\s+/g, ''); .replace(/\s+/g, '') : str
}; };
/** /**

View File

@ -35,3 +35,31 @@ export const useWindowDimensions = () => {
return { width, height } return { width, height }
} }
export const useWindowSize = () => {
// Initialize state with undefined width/height so server and client renders match
// Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/
const [windowSize, setWindowSize] = useState({
width: undefined,
height: undefined,
})
useEffect(() => {
// Handler to call on window resize
function handleResize() {
// Set window width/height to state
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
})
}
// Add event listener
window.addEventListener('resize', handleResize)
// Call handler right away so state gets updated with initial window size
handleResize()
// Remove event listener on cleanup
return () => window.removeEventListener('resize', handleResize)
}, []) // Empty array ensures that effect is only run on mount
return windowSize
}

View File

@ -23,7 +23,7 @@ const InfoLayout = ({ title, subtitle, image, children, theme }) => (
{children} {children}
</Content> </Content>
<Hero image={image}> <Hero image={image}>
<Header theme={{ foreground: theme.background, background: 'transparent', }} miniHeader /> <Header theme={theme} miniHeader />
<H1>{title}</H1> <H1>{title}</H1>
<H1 <H1
css={` css={`

View File

@ -1,6 +1,6 @@
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import styled from 'styled-components' import styled from 'styled-components'
import { colours } from '../../assets/theme' import { colours, screenSizes } from '../../assets/theme'
import { ImageLogo as Logo } from '../../components/Logo' import { ImageLogo as Logo } from '../../components/Logo'
const heroWidth = 'calc(100vw - 600px - 4em)' const heroWidth = 'calc(100vw - 600px - 4em)'
@ -15,10 +15,10 @@ export const Wrapper = styled.div`
overflow-y: scroll; overflow-y: scroll;
@media screen and (max-width: 1200px) { @media screen and (max-width: ${screenSizes.lg}px) {
padding: 1.5em; padding: 1.5em;
} }
@media screen and (max-width: 800px) { @media screen and (max-width: ${screenSizes.sm}px) {
padding: 1em; padding: 1em;
} }
@ -79,16 +79,9 @@ export const Hero = styled.div`
margin-bottom: 0.2em; margin-bottom: 0.2em;
&:not(:last-of-type) { &:not(:last-of-type) {
font-size: 12vw; font-size: 12vw;
@media screen and (max-height: 600px) {
font-size: 20vh;
}
@media screen and (max-width: 1200px) {
font-size: 20vh;
}
}} }}
@media screen and (max-width: 1000px) { @media screen and (max-width: ${screenSizes.md}px) {
display: none; display: none;
} }
` `

View File

@ -1,5 +1,5 @@
import styled from 'styled-components' import styled from 'styled-components'
import { colours } from '../../assets/theme' import { colours, screenSizes } from '../../assets/theme'
import { H1 } from '../../components/Text' import { H1 } from '../../components/Text'
import Link from '../../components/Link' import Link from '../../components/Link'
@ -15,10 +15,10 @@ export const Wrapper = styled.div`
box-sizing: border-box; box-sizing: border-box;
@media screen and (max-width: 1200px) { @media screen and (max-width: ${screenSizes.lg}px) {
padding: 1.5em; padding: 1.5em;
} }
@media screen and (max-width: 800px) { @media screen and (max-width: ${screenSizes.sm}px) {
padding: 1em; padding: 1em;
} }
` `

View File

@ -1,5 +1,5 @@
import styled from 'styled-components' import styled from 'styled-components'
import { colours } from '../../assets/theme' import { colours, screenSizes } from '../../assets/theme'
import bg from '../../assets/img/hero/1lg.png' import bg from '../../assets/img/hero/1lg.png'
// import { H1 } from '../../components/Text' // import { H1 } from '../../components/Text'
@ -23,13 +23,6 @@ export const Wrapper = styled.div`
h2 { h2 {
color: ${colours.midnightDarker}; color: ${colours.midnightDarker};
} }
@media screen and (max-width: 1200px) {
/* padding: 1.5em; */
}
@media screen and (max-width: 800px) {
/* padding: 1em; */
}
` `
export const Top = styled.div` export const Top = styled.div`
@ -72,19 +65,7 @@ export const Hero = styled.div`
justify-content: space-between; justify-content: space-between;
pointer-events: none; pointer-events: none;
/* @media screen and (max-width: ${screenSizes.md}px) {
h1:not(:last-of-type) {
font-size: 30vh;
@media screen and (max-height: 600px) {
font-size: 20vh;
}
@media screen and (max-width: 1200px) {
font-size: 20vh;
}
} */
@media screen and (max-width: 1000px) {
display: none; display: none;
} }
` `
@ -98,7 +79,7 @@ export const LoaderWrapper = styled.div`
top: 0; top: 0;
width: calc(600px + 4em); width: calc(600px + 4em);
@media screen and (max-width: 1000px) { @media screen and (max-width: ${screenSizes.md}px) {
width: 100vw; width: 100vw;
} }
` `
@ -143,7 +124,7 @@ export const TaglineContainer = styled.div`
margin-bottom: 0.2em; margin-bottom: 0.2em;
} }
@media screen and (max-width: 1000px) { @media screen and (max-width: ${screenSizes.md}px) {
h1 { h1 {
color: ${colours.rose}; color: ${colours.rose};
font-size: 24px; font-size: 24px;

View File

@ -1,6 +1,6 @@
/* eslint-disable react/prop-types */ /* eslint-disable react/prop-types */
import { isWithinInterval } from 'date-fns' import { isWithinInterval } from 'date-fns'
import { h } from 'preact' import { Fragment, h } from 'preact'
import { H1, H2 } from '../../components/Text' import { H1, H2 } from '../../components/Text'
import strings from '../../data/strings' import strings from '../../data/strings'
import { useEventApi } from '../../hooks/data' import { useEventApi } from '../../hooks/data'
@ -24,7 +24,6 @@ const Series = () => {
pastSeries.push(series) pastSeries.push(series)
return false return false
}) })
@ -32,12 +31,14 @@ const Series = () => {
<Page title={strings.en.series}> <Page title={strings.en.series}>
<Content> <Content>
<SeriesGrid> <SeriesGrid>
<H1 colour={colours.rose}>{strings.en.currentSeries}</H1> {currentSeries.map(series => (
<SeriesRow> <Fragment>
{currentSeries.map(series => ( <H1 colour={colours.rose}>{strings.en.currentSeries}</H1>
<SeriesCard series={series} /> <SeriesRow>
))} <SeriesCard series={series} />
</SeriesRow> </SeriesRow>
</Fragment>
))}
<H1 colour={colours.rose}>{strings.en.pastSeries}</H1> <H1 colour={colours.rose}>{strings.en.pastSeries}</H1>
<SeriesRow> <SeriesRow>
{pastSeries.map(series => ( {pastSeries.map(series => (

View File

@ -16,18 +16,14 @@ import {
TrailerContainer, TrailerContainer,
} from './styles' } from './styles'
import config from '../../data/config'
import Page from '../../layouts/Page' import Page from '../../layouts/Page'
import { splitArray } from '../../helpers/utils' import { splitArray } from '../../helpers/utils'
import Header from '../../components/Header'
import theme from '../../assets/theme'
const SeriesPage = ({ data }) => { const SeriesPage = ({ data }) => {
const credits = data.credits ? `
const credits = `
## Credits ## Credits
${data.credits} ${data.credits}
` ` : null
const dateString = `${new Date()}` const dateString = `${new Date()}`
let tzShort = let tzShort =
@ -52,7 +48,7 @@ const SeriesPage = ({ data }) => {
<InfoContent> <InfoContent>
<H1>{data.title}:</H1> <H1>{data.title}:</H1>
<H1>{data.subtitle}</H1> <H1>{data.subtitle}</H1>
<Markdown withLinebreaks theme={data.theme}>{data.description}</Markdown> {data.description ? <Markdown withLinebreaks theme={data.theme}>{data.description}</Markdown> : null}
{data.trailer ? ( {data.trailer ? (
<TrailerContainer> <TrailerContainer>
@ -101,7 +97,7 @@ const SeriesPage = ({ data }) => {
))} ))}
</Fragment> </Fragment>
) : null} ) : null}
{data.credits ? <InfoContent> {credits ? <InfoContent>
<Title>Credits</Title> <Title>Credits</Title>
<Markdown theme={data.theme}>{credits}</Markdown> <Markdown theme={data.theme}>{credits}</Markdown>
</InfoContent> : null} </InfoContent> : null}