feat: init card and nav

This commit is contained in:
2021-01-14 17:12:40 +00:00
parent c5e8c04ddc
commit e129093113
19 changed files with 417 additions and 112 deletions

View File

@@ -5,7 +5,42 @@ module.exports = {
title: `Abc Project Design`,
description: `Easy as ABC`,
keywords: `Foo bar baz`,
navData: [],
navData: [
{
title: "Home",
to: "/"
},
{
title: "Services",
to: "/services",
subNav: [
{
title: "Bathrooms",
to: "/services/bathrooms"
},
{
title: "Tiling",
to: "/services/tiling"
},
{
title: "Electrics",
to: "/services/electrics"
},
{
title: "Carpentry",
to: "/services/carpentry"
}
]
},
{
title: "About",
to: "/about"
},
{
title: "Contact",
to: "/contact"
}
],
reviews: [
{
name: "Rated People",

View File

@@ -1,11 +1,11 @@
import React from "react";
import { Link as GatsbyLink } from "gatsby";
import Img from "gatsby-image";
import styled from "styled-components";
const Container = styled.div`
display: flex;
align-items: center;
overflow: hidden;
margin: 0 calc(var(--spacing-x-xs) * -1) var(--spacing-y-sm);
@media (max-width: 30em) {
@@ -15,15 +15,34 @@ const Container = styled.div`
}
`;
const Media = styled.div`
const Media = styled.span`
padding: 0 var(--spacing-x-xs);
transition: transform 0.15s ease-in, filter 0.15s ease-in;
`;
const Content = styled.div`
const Content = styled.span`
padding: 0 var(--spacing-x-xs);
`;
export default function Card({ image, children }) {
return (
const Link = styled(GatsbyLink)`
outline: 0;
text-decoration: none;
color: var(--color-black);
&:hover ${Media} {
transform: scale(1.1);
filter: brightness(110%) contrast(110%);
}
@media (max-width: 30em) {
&:nth-child(even) ${Container} {
flex-direction: row-reverse;
}
}
`;
export default function Card({ image, children, to }) {
const render = () => (
<Container>
{image && (
<Media>
@@ -39,4 +58,5 @@ export default function Card({ image, children }) {
<Content>{children}</Content>
</Container>
);
return to ? <Link to={to}>{render()}</Link> : render();
}

View File

@@ -10,6 +10,7 @@ const Content = styled.div`
max-width: var(--theme-max-width);
margin: 0 auto;
padding: var(--spacing-y-lg) var(--spacing-x-sm);
font-size: var(--font-size-sm);
text-align: center;
`;

View File

@@ -79,7 +79,7 @@ const Slogan = styled.p`
export default function HeaderLogo({ transition }) {
const [visible, setVisible] = useState(!transition);
useEffect(() => transition && setVisible(true));
useEffect(() => transition && setVisible(true), [transition]);
return (
<Container>
<Top visible={visible}>

View File

@@ -9,6 +9,15 @@ const Container = styled.button`
background-color: transparent;
padding: 4px 8px;
border: 0;
cursor: pointer;
&:focus {
outline: 0;
}
@media (min-width: 30em) {
display: none;
}
`;
const Bar = styled.span`

View File

@@ -0,0 +1,47 @@
import React from "react";
import styled, { css } from "styled-components";
import NavLink from "./nav-link";
const SubList = styled.ul`
margin: 0 0 0 var(--spacing-x-md);
padding: 0;
list-style: none;
@media (min-width: 30em) {
display: none;
flex-direction: column;
position: absolute;
margin: 0;
padding: var(--spacing-y-xs) var(--spacing-x-xs);
background-color: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(2px);
}
`;
const ListItem = styled.li`
position: relative;
&:focus-within ${SubList}, &:hover ${SubList} {
@media (min-width: 30em) {
display: flex;
}
}
`;
export default function NavItem({ children, subNav, ...other }) {
const hasChildren = subNav && subNav.length > 0;
return (
<ListItem>
<NavLink {...other}>{children}</NavLink>
{hasChildren && (
<SubList>
{subNav.map((link, i) => (
<ListItem key={i}>
<NavLink to={link.to}>{link.title}</NavLink>
</ListItem>
))}
</SubList>
)}
</ListItem>
);
}

View File

@@ -1,56 +1,30 @@
import React from "react";
import styled, { css } from "styled-components";
import { Link as GatsbyLink } from "gatsby";
const SubList = styled.ul`
position: absolute;
display: none;
flex-direction: column;
min-width: 120px;
margin: 0;
padding: 0;
list-style: none;
`;
const ListItem = styled.li`
position: relative;
margin: 0 var(--spacing-y-xs);
&:hover ${SubList} {
@media (min-width: 40rem) {
display: flex;
}
}
`;
import styled from "styled-components";
const Link = styled(GatsbyLink)`
display: block;
color: white;
display: inline-block;
padding: 0;
margin-bottom: var(--spacing-y-sm);
color: var(--color-white);
font-size: var(--font-size-lg);
text-decoration: none;
padding: 5px;
margin-top: var(--spacing-y-xs);
border-bottom: 2px solid transparent;
cursor: pointer;
${props =>
props.active &&
css`
border-color: var(--color-white);
`}
&:focus {
outline: none;
}
@media (min-width: 30em) {
font-size: var(--font-size-sm);
margin: 0 var(--spacing-x-xs);
padding: 9px 0;
border-bottom: 2px solid
${props => (props.active ? `var(--color-white)` : `transparent`)};
}
`;
export default function NavLink({ children, subLinks, ...other }) {
return (
<ListItem>
<Link {...other}>{children}</Link>
{subLinks && subLinks.length > 0 && (
<SubList>
{subLinks.map((link, i) => (
<Link to={link.to} key={i}>
{link.title}
</Link>
))}
</SubList>
)}
</ListItem>
);
export default function NavLink({ location, children, to }) {
console.log(location);
return <Link to={to}>{children}</Link>;
}

View File

@@ -1,60 +1,86 @@
import React from "react";
import { Link } from "gatsby";
import styled from "styled-components";
import NavLink from "./nav-link";
import NavItem from "./nav-item";
import MenuButton from "./menu-button";
import LogoArrows from "../icons/logo-arrows.svg";
const Container = styled.div`
position: ${props => (props.open ? "fixed" : "absolute")};
position: fixed;
top: 0;
right: 0;
bottom: 0;
z-index: 6;
transform: ${props =>
props.open ? `translate3d(0, 0, 0)` : `translate3d(100%, 0, 0)`};
transition: transform 0.15s;
@media (min-width: 30em) {
bottom: auto;
left: 0;
display: flex;
background-color: rgba(0, 0, 0, 0.4);
flex-direction: column-reverse;
z-index: 6;
background-color: ${props =>
props.open ? `rgba(0, 0, 0, 0.8)` : `rgba(0, 0, 0, 0.4)`};
backdrop-filter: blur(2px);
transform: ${props =>
props.open
? `translate3d(0, 0, 0)`
: `translate3d(0, calc(-100% + 40px), 0)`};
transition: transform 0.3s ease-in-out, background-color 0.3s ease-in-out;
@media (min-width: 30em) {
position: absolute;
display: flex;
flex-direction: row;
bottom: auto;
background-color: rgba(0, 0, 0, 0.6);
transform: none;
transition: none;
}
`;
const Menu = styled.div`
position: absolute;
top: 0;
left: 0;
padding: var(--spacing-y-xs) var(--spacing-x-md) 0 0;
transform: translateX(-100%);
display: flex;
justify-content: space-between;
align-items: stretch;
color: white;
margin: var(--spacing-x-xs) var(--spacing-y-sm);
`;
@media (min-width: 30em) {
display: none;
const Heading = styled(Link)`
display: flex;
flex-direction: column;
justify-content: space-around;
opacity: ${props => (props.visible ? 1 : 0)};
transform: opacity 0.3s ease-in;
svg {
width: 24px;
height: 12px;
&:first-of-type {
path:first-child {
fill: var(--theme-color-primary);
}
path:last-child {
fill: var(--theme-color-secondary);
}
}
&:last-of-type {
transform: rotate(180deg);
path:first-child {
fill: var(--theme-color-dark);
}
path:last-child {
fill: var(--theme-color-secondary);
}
}
}
`;
const Content = styled.nav`
margin: 0 var(--spacing-x-sm);
flex-grow: 1;
margin: var(--spacing-y-lg) var(--spacing-x-md);
@media (max-width: 30em) {
background-color: rgba(0, 0, 0, 0.4);
}
`;
const Overlay = styled.div`
@media (max-width: 30em) {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 5;
display: ${props => (props.visible ? `block` : `none`)};
background-color: rgba(0, 0, 0, 0.75);
backdrop-filter: blur(2px);
@media (min-width: 30em) {
display: flex;
margin: 0;
}
`;
@@ -70,25 +96,25 @@ const List = styled.ul`
`;
export default function Nav({ data, open, setOpen }) {
const handleOverlayClick = () => setOpen(false);
const handleButtonClick = () => setOpen(!open);
return (
<>
<Container open={open}>
<Menu>
<Heading to="/" visible={!open}>
<LogoArrows />
<LogoArrows />
</Heading>
<MenuButton open={open} onClick={handleButtonClick} />
</Menu>
<Content>
<List>
{data.map((link, i) => (
<NavLink key={i} subNav={link.subNav} to={link.to}>
<NavItem key={i} subNav={link.subNav} to={link.to}>
{link.title}
</NavLink>
</NavItem>
))}
</List>
</Content>
</Container>
<Overlay visible={open} onClick={handleOverlayClick} />
</>
);
}

BIN
src/images/bathroom2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 MiB

View File

@@ -1,6 +1,7 @@
import React from "react";
import React, { useState } from "react";
import { useStaticQuery, graphql } from "gatsby";
import { Helmet } from "react-helmet";
import Nav from "./components/nav";
import Footer from "./components/footer";
import { createGlobalStyle } from "styled-components";
import "@fontsource/cooper-hewitt/400.css";
@@ -65,6 +66,7 @@ const GlobalStyle = createGlobalStyle`
box-sizing: border-box;
margin: 0;
font-family: 'Cooper Hewitt', sans-serif;
overflow-x: hidden;
overflow-y: ${props => (props.navOpen ? "hidden" : "auto")};
}
@@ -83,7 +85,8 @@ const GlobalStyle = createGlobalStyle`
}
`;
export default function Layout({ children }) {
export default function Layout({ location, children }) {
console.log(location);
const data = useStaticQuery(graphql`
query HeaderQuery {
site {
@@ -91,11 +94,20 @@ export default function Layout({ children }) {
title
description
keywords
navData {
title
to
subNav {
title
to
}
}
}
}
}
`);
const { title, description, keywords } = data.site.siteMetadata;
const { title, description, keywords, navData } = data.site.siteMetadata;
const [navOpen, setNavOpen] = useState();
return (
<>
<main>
@@ -106,10 +118,11 @@ export default function Layout({ children }) {
{ name: "keywords", content: keywords }
]}
/>
<GlobalStyle />
<GlobalStyle navOpen={navOpen} />
{children}
<Footer />
</main>
<Nav data={navData} open={navOpen} setOpen={setNavOpen} />
</>
);
}

View File

@@ -1,5 +1,5 @@
import React from "react";
import { graphql } from "gatsby";
import { Link, graphql } from "gatsby";
import Layout from "../layout";
import Header from "../components/header";
import HeaderLogo from "../components/header-logo";
@@ -9,10 +9,12 @@ export default function Index({ data }) {
return (
<Layout>
<Header image={data.headerImage.childImageSharp.fluid}>
<HeaderLogo visible={true} />
<h2>404</h2>
</Header>
<Section variant="primary">oops.</Section>
<Section>
<p>Page not found</p>
<Link to="/">Back Home</Link>
</Section>
</Layout>
);
}

70
src/pages/colours.js Normal file
View File

@@ -0,0 +1,70 @@
import React from "react";
import { graphql } from "gatsby";
import Layout from "../layout";
import Header from "../components/header";
import HeaderLogo from "../components/header-logo";
import Section from "../components/section";
import Text from "../components/text";
export default function Index({ data }) {
return (
<Layout>
<Header image={data.headerImage.childImageSharp.fluid}>
<HeaderLogo>
<h1>ABC Project Design</h1>
<p>Easy as ABC</p>
</HeaderLogo>
</Header>
<Section>
<Text
style={{
"background-color": "var(--theme-color-primary)"
}}
>
--theme-color-primary: #9c0905;
</Text>
<Text
style={{
"background-color": "var(--theme-color-secondary)"
}}
>
--theme-color-secondary: #9590a8;
</Text>
<Text
style={{
"background-color": "var(--theme-color-tertiary)"
}}
>
--theme-color-tertiary: #bbcbcb;
</Text>
<Text
style={{
"background-color": "var(--theme-color-light)"
}}
>
--theme-color-light: #e5ffde;
</Text>
<Text
style={{
"background-color": "var(--theme-color-dark)",
color: "white"
}}
>
--theme-color-dark: #000a61;
</Text>
</Section>
</Layout>
);
}
export const query = graphql`
query {
headerImage: file(relativePath: { eq: "bathroom.png" }) {
childImageSharp {
fluid(maxWidth: 1920, quality: 100) {
...GatsbyImageSharpFluid_withWebp
}
}
}
}
`;

View File

@@ -4,6 +4,7 @@ import Layout from "../layout";
import Header from "../components/header";
import HeaderLogo from "../components/header-logo";
import Section from "../components/section";
import Card from "../components/card";
import ReviewSummary from "../components/review-summary";
import CustomSlick from "../components/custom-slick";
import Text from "../components/text";
@@ -12,7 +13,7 @@ export default function Index({ data }) {
return (
<Layout>
<Header image={data.headerImage.childImageSharp.fluid}>
<HeaderLogo />
<HeaderLogo transition={true} />
</Header>
<Section>
<Text>
@@ -25,6 +26,32 @@ export default function Index({ data }) {
operate in Essex, Hertfordshire, Kent and London.
</Text>
</Section>
<Section grid={2}>
<Card
to="/services/bathrooms"
image={data.bathroomImage.childImageSharp.fixed}
>
Bathrooms
</Card>
<Card
to="/services/tiling"
image={data.tilingImage.childImageSharp.fixed}
>
Tiling
</Card>
<Card
to="/services/electrics"
image={data.electricsImage.childImageSharp.fixed}
>
Electrics
</Card>
<Card
to="/services/carpentry"
image={data.carpentryImage.childImageSharp.fixed}
>
Carpentry
</Card>
</Section>
<Section variant="primary">
<CustomSlick>
{data.site.siteMetadata.reviews.map((review, i) => (
@@ -45,6 +72,34 @@ export const query = graphql`
}
}
}
bathroomImage: file(relativePath: { eq: "service_bathroom.png" }) {
childImageSharp {
fixed(width: 96, height: 54, quality: 100) {
...GatsbyImageSharpFixed_withWebp
}
}
}
tilingImage: file(relativePath: { eq: "service_tiling.png" }) {
childImageSharp {
fixed(width: 96, height: 54, quality: 100) {
...GatsbyImageSharpFixed_withWebp
}
}
}
electricsImage: file(relativePath: { eq: "service_electrics.png" }) {
childImageSharp {
fixed(width: 96, height: 54, quality: 100) {
...GatsbyImageSharpFixed_withWebp
}
}
}
carpentryImage: file(relativePath: { eq: "service_carpentry.png" }) {
childImageSharp {
fixed(width: 96, height: 54, quality: 100) {
...GatsbyImageSharpFixed_withWebp
}
}
}
site {
siteMetadata {
reviews {

View File

@@ -0,0 +1,26 @@
import React from "react";
import { graphql } from "gatsby";
import Layout from "../../layout";
import Header from "../../components/header";
export default function Index({ data }) {
return (
<Layout>
<Header image={data.headerImage.childImageSharp.fluid}>
<h1>Bathrooms</h1>
</Header>
</Layout>
);
}
export const query = graphql`
query {
headerImage: file(relativePath: { eq: "bathroom2.png" }) {
childImageSharp {
fluid(maxWidth: 1920, quality: 100) {
...GatsbyImageSharpFluid_withWebp
}
}
}
}
`;

View File

@@ -0,0 +1,27 @@
import React from "react";
import { graphql } from "gatsby";
import Layout from "../../layout";
import Header from "../../components/header";
export default function Index({ location, data }) {
console.log(location);
return (
<Layout>
<Header image={data.headerImage.childImageSharp.fluid}>
<h1>Services</h1>
</Header>
</Layout>
);
}
export const query = graphql`
query {
headerImage: file(relativePath: { eq: "bathroom2.png" }) {
childImageSharp {
fluid(maxWidth: 1920, quality: 100) {
...GatsbyImageSharpFluid_withWebp
}
}
}
}
`;