diff --git a/common/constants.js b/common/constants.js new file mode 100644 index 0000000..32928d7 --- /dev/null +++ b/common/constants.js @@ -0,0 +1,5 @@ +export const BREAKPOINTS = { + SM: 460, + MD: 700, + LG: 920, +} diff --git a/components/header/Header.jsx b/components/header/Header.jsx index 37b3fbe..f09941e 100644 --- a/components/header/Header.jsx +++ b/components/header/Header.jsx @@ -1,38 +1,67 @@ +import { useMemo } from 'react' import Link from 'next/link' import { getRelativeURL } from '../../common/routes' import { getLiteral } from '../../common/i18n' +import useWindowSize from '../../hooks/useWindowSize' import GitHubLogo from '../../public/icons/github-logo' +import IconCalendar from '../../public/icons/calendar' +import IconBooks from '../../public/icons/books' +import { BREAKPOINTS } from '../../common/constants' const Header = () => { + const { width } = useWindowSize() + + const isMobile = useMemo(() => { + return width < BREAKPOINTS.MD + }, [width]) + return (
-
- - - - {getLiteral('page:title')} - - +
+
+ + + + {getLiteral(isMobile ? 'page:title-mobile' : 'page:title')} + + -

{getLiteral('page:date')}

+

{getLiteral('page:date')}

+
+ +
- -
) } diff --git a/components/header/header.scss b/components/header/header.scss index d58717a..8ba6e94 100644 --- a/components/header/header.scss +++ b/components/header/header.scss @@ -1,23 +1,41 @@ .header { - @extend %grid; - align-items: center; + position: sticky; + top: 0; - padding: spacing(3) 0; - border-bottom: 1px solid $white; + padding: 0 spacing(2); + + backdrop-filter: blur(60px); + + @media (min-width: $lg) { + padding: 0 spacing(4); + } + + &__content { + display: flex; + justify-content: space-between; + + padding: spacing(2) 0; + + border-bottom: 1px solid $white; + + @media (min-width: $lg) { + padding: spacing(2) 0; + } + } &__logo { - grid-column: 1 / 4; - display: flex; align-items: center; column-gap: spacing(2); } - &__link { + &__home-link { display: flex; align-items: center; column-gap: spacing(2); + @extend %header-3; + .github-logo { height: spacing(4); width: spacing(4); @@ -30,20 +48,77 @@ &__chip { padding: spacing(1) spacing(1.5); + margin-right: spacing(2); border: 1px solid $white; box-sizing: border-box; border-radius: 27px; + @extend %subtitle-1; + cursor: default; } &__navigation { - grid-column: 11 / 13; + display: flex; + align-items: center; } &__list { display: flex; - column-gap: spacing(5); + column-gap: spacing(2); + + @media (min-width: $lg) { + column-gap: spacing(4); + } + } + + &__link { + display: flex; + align-items: center; + justify-content: center; + column-gap: spacing(1); + + height: spacing(5); + width: spacing(5); + + @media (min-width: $md) { + height: spacing(6); + width: spacing(6); + } + + @media (min-width: $lg) { + width: auto; + height: auto; + } + } + + .icon-calendar, + .icon-books { + height: spacing(3); + width: spacing(3); + + rect, + line { + stroke: $white; + } + + @media (min-width: $md) { + height: spacing(4); + width: spacing(4); + } + + @media (min-width: $lg) { + height: spacing(3); + width: spacing(3); + } + } + + &__link-text { + display: none; + + @media (min-width: $lg) { + display: initial; + } } } diff --git a/components/home/hero/Hero.jsx b/components/home/hero/Hero.jsx index cc37d2f..c9981ec 100644 --- a/components/home/hero/Hero.jsx +++ b/components/home/hero/Hero.jsx @@ -5,10 +5,12 @@ import { getRelativeURL } from '../../../common/routes' const Hero = ({ date, title, buttonText }) => { return (
-

{date}

-

{title}

+
+

{date}

+

{title}

- {buttonText} + {buttonText} +
) } diff --git a/components/home/hero/hero.scss b/components/home/hero/hero.scss index 42b61d4..6c3540d 100644 --- a/components/home/hero/hero.scss +++ b/components/home/hero/hero.scss @@ -1,2 +1,27 @@ .hero { + min-height: 100vh; + + @extend %grid; + + &__content { + grid-column: 3 / 9; + + display: flex; + flex-direction: column; + justify-content: center; + align-items: flex-start; + } + + &__chip { + @extend %header-2; + padding: spacing(2) spacing(4); + margin-bottom: spacing(4); + + border: 1px solid $white; + border-radius: 83px; + } + + &__title { + @extend %header-1; + } } diff --git a/content/commons.json b/content/commons.json index 3b4068d..3285902 100644 --- a/content/commons.json +++ b/content/commons.json @@ -17,6 +17,7 @@ "navigation:resources": "Resources", "page:title": "Maintainer Month", + "page:title-mobile": "MM", "page:date": "June 2022", "resources:title": "Resources", diff --git a/hooks/useWindowSize.js b/hooks/useWindowSize.js new file mode 100644 index 0000000..afc532c --- /dev/null +++ b/hooks/useWindowSize.js @@ -0,0 +1,29 @@ +import { useState, useEffect } from 'react' + +function 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 +} + +export default useWindowSize diff --git a/public/icons/books.js b/public/icons/books.js new file mode 100644 index 0000000..44a9613 --- /dev/null +++ b/public/icons/books.js @@ -0,0 +1,95 @@ +const IconBooks = () => { + return ( + + + + + + + + + + ) +} + +export default IconBooks diff --git a/public/icons/calendar.js b/public/icons/calendar.js new file mode 100644 index 0000000..8690a9e --- /dev/null +++ b/public/icons/calendar.js @@ -0,0 +1,58 @@ +const IconCalendar = () => { + return ( + + + + + + + ) +} + +export default IconCalendar diff --git a/styles/base.scss b/styles/base.scss index 88b7f36..175981b 100644 --- a/styles/base.scss +++ b/styles/base.scss @@ -1,18 +1,20 @@ html { - font-family: 'Inter', sans-serif; font-size: $font-base; - color: $white; } body { min-height: 100vh; overflow-x: hidden; + font-family: $inter; + @extend %body-1; + color: $white; + background: linear-gradient( 116.27deg, - #0366d6 -13.85%, - #59359a 31.49%, - #d73a49 107.36% + $blue -13.85%, + $purple 31.49%, + $red 107.36% ); } diff --git a/styles/helpers.scss b/styles/helpers.scss index b2632d4..874c4e4 100644 --- a/styles/helpers.scss +++ b/styles/helpers.scss @@ -4,8 +4,18 @@ %grid { display: grid; - grid-template-columns: repeat(12, 1fr); - grid-gap: spacing(3); - max-width: 1400px; + grid-template-columns: repeat(4, 1fr); + grid-gap: spacing(1); + max-width: 1000px; margin: 0 auto; + padding: 0 spacing(2); + + @media (min-width: $md) { + grid-template-columns: repeat(8, 1fr); + } + + @media (min-width: $lg) { + grid-template-columns: repeat(12, 1fr); + padding: 0 spacing(4); + } } diff --git a/styles/styles.scss b/styles/styles.scss index 310f10a..dc885a2 100644 --- a/styles/styles.scss +++ b/styles/styles.scss @@ -1,7 +1,7 @@ // Global @import './reset'; @import './tokens'; -@import './typography'; +@import './fonts'; @import './helpers'; @import './base'; diff --git a/styles/tokens.scss b/styles/tokens.scss index 15ffed5..edb6bab 100644 --- a/styles/tokens.scss +++ b/styles/tokens.scss @@ -2,13 +2,15 @@ $spacer: 8px; // Breakpoints -$xs: 375px; -$sm: 667px; -$md: 768px; -$lg: 1024px; +$sm: 460px; +$md: 700px; +$lg: 920px; // Colors $white: #fff; +$blue: #0a03d6; +$purple: #6b00cf; +$red: #e32e40; // Indexes diff --git a/styles/typography.scss b/styles/typography.scss deleted file mode 100644 index 089ceb1..0000000 --- a/styles/typography.scss +++ /dev/null @@ -1,12 +0,0 @@ -@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400&display=swap'); - -// Base -$font-base: 16; - -// Weights -$light: 300; -$regular: 400; -$medium: 500; -$semibold: 600; -$bold: 700; -$heavy: 900;