Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Landing Page Design Updates #91

Merged
merged 7 commits into from
Sep 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/nextjs/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ function ButtonComponent(
"py-4",
"px-8",
"text-body-reg",
"font-bold",
{
"bg-blue text-white hover:text-sky": variant === "primary",
"bg-white text-blue hover:bg-blue hover:text-sky border border-blue": variant === "secondary",
"bg-[transparent] text-blue hover:bg-blue hover:text-sky border border-blue": variant === "secondary",
"bg-white text-yellow hover:bg-yellow hover:text-blue": variant === "tertiary",
"bg-thunder-cloud text-dark-thunder-cloud hover:text-dark-thunder-cloud": disabled,
"cursor-pointer": as === "a",
},
className
);
Expand Down
24 changes: 18 additions & 6 deletions packages/nextjs/components/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,34 @@ import Link from "next/link";

import { Image } from "./Image";

interface Props {
children: React.ReactNode;
export interface CardProps {
title: string;
price?: string | number;
subTitle?: string;
to: string;
className?: string;
imageProps: {
src: SanityImageSource;
alt: string;
width?: number;
height?: number;
};
}

export const Card: React.FC<Props> = ({ to, children, imageProps, className = "" }) => {
export const Card: React.FC<CardProps> = ({ to, subTitle, title, price, imageProps, className = "" }) => {
return (
<Link href={to}>
<a className={`hover:shadow-lg border flex flex-col items-center justify-center ${className}`}>
<Image width={400} height={400} src={imageProps.src} alt={imageProps.alt} />
<h2 className="text-xl font-bold my-2">{children}</h2>
<a className={`flex flex-col justify-center text-blue ${className}`}>
<Image
className="rounded-2xl"
width={imageProps.width ?? 400}
height={imageProps.height ?? 400}
src={imageProps.src}
alt={imageProps.alt}
/>
<h2 className="text-h6 mt-4 mb-1">{title}</h2>
{price && <span className="text-eyebrow font-bold">${price}</span>}
{subTitle && <span className="text-eyebrow">{subTitle}</span>}
</a>
</Link>
);
Expand Down
6 changes: 3 additions & 3 deletions packages/nextjs/components/CategoryList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ export const CategoryList = ({ items }: CategoryListProps) => {
src: category.images?.[0]?.images ?? "",
alt: category.images?.[0]?.name ?? "",
}}
>
{category.name}
</Card>
title={category.name ?? ""}
subTitle={category.description ?? ""}
/>
</li>
))}
</ul>
Expand Down
57 changes: 57 additions & 0 deletions packages/nextjs/components/FeaturedList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import classNames from "classnames";
import { Card, CardProps } from "components/Card";
import { GetProductsAndCategoriesQuery } from "utils/generated/graphql";

type Props = {
items?: GetProductsAndCategoriesQuery["allProduct"] | GetProductsAndCategoriesQuery["allCategory"];
};

export const FeaturedList = ({ items }: Props) => {
if (!items) return null;

return (
<ul
className={classNames("grid", "m-9", "grid-cols-1", "gap-4", "sm:gap-0", {
"sm:grid-cols-3": items.length >= 3,
"sm:grid-cols-2": items.length === 2,
})}
>
{items.map((item) => {
let props: CardProps;

if (item.__typename === "Product") {
props = {
to: `/products/${item.slug?.current}`,
title: item.name ?? "",
price: item.variants?.[0]?.price ?? "",
imageProps: {
src: item.variants?.[0]?.images?.[0]?.images ?? "",
alt: item.variants?.[0]?.images?.[0]?.name ?? "",
},
};
} else if (item.__typename === "Category") {
props = {
to: `/categories/${item.slug?.current}`,
title: item.name ?? "",
subTitle: item.description ?? "",
imageProps: {
src: item.images?.[0]?.images ?? "",
alt: item.images?.[0]?.name ?? "",
width: 600,
height: 600,
},
};
} else {
// Unexpected type
return null;
}

return (
<li key={item._id} className="sm:border-r-2 border-r-blue last:border-r-0 flex justify-center">
<Card {...props} />
</li>
);
})}
</ul>
);
};
7 changes: 7 additions & 0 deletions packages/nextjs/components/FeaturedQuote.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const FeaturedQuote = () => {
return (
<div className="border-t-2 border-t-blue flex justify-center text-center w-full py-16">
<h3 className="text-h3 text-blue">&quot;Game-changing bread service.&quot;</h3>
</div>
);
};
6 changes: 5 additions & 1 deletion packages/nextjs/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
export const Footer = () => {
return <div className="h-10 border-t flex items-center justify-start px-6">© MMXXII Formidable Labs, LLC.</div>;
return (
<div className="h-20 border-t-2 border-t-blue text-blue flex items-center justify-start px-6">
© MMXXII Formidable Labs, LLC.
</div>
);
};
96 changes: 72 additions & 24 deletions packages/nextjs/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import classNames from "classnames";
import Link from "next/link";
import React from "react";
import { MdShoppingCart } from "react-icons/md";
import React, { useState } from "react";
import { FiMenu, FiShoppingCart } from "react-icons/fi";
import { MdClose } from "react-icons/md";

import { useCart } from "./CartContext";
import { Search } from "./Search";
Expand All @@ -17,32 +19,78 @@ const NAV_ITEMS = [
];

export const Header = () => {
const [navOpen, setNavOpen] = useState(false);
const { cartTotal } = useCart();

const onMobileNavClick = () => setNavOpen((prev) => !prev);

const onMobileNavClose = () => setNavOpen(false);

return (
<div className="h-20 flex items-center justify-between bg-white px-6 border-b shadow">
<div className="flex items-center">
<h2 className="text-2xl font-bold">
<>
<nav className="h-16 sm:h-28 flex items-center justify-between px-6 border-b-2 border-b-blue shadow transition-all">
<div className="flex items-center">
<Link href="/">
<a>NextJs Ecom</a>
<a onClick={onMobileNavClose}>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src="/Logo.svg" alt="Formidable Boulangerie" className="h-10" />
</a>
</Link>
</h2>
<nav className="ml-8">
{NAV_ITEMS.map(({ href, label }) => (
<Link href={href} key={label}>
<a className="text-gray-600 text-xl hover:text-gray-900 mr-2">{label}</a>
</Link>
))}
</nav>
</div>
<div className="flex items-center">
<Search />
<Link href="/cart">
<a className="flex items-center">
<MdShoppingCart size={30} /> <span className="text-gray-600 text-xl">{cartTotal}</span>
</a>
</Link>
</div>
</div>
<ul className="ml-8 hidden sm:flex">
{/* Desktop Nav */}
{NAV_ITEMS.map(({ href, label }) => (
<li key={label} className="text-blue text-body-reg mr-4 last:mr-0">
<Link href={href}>
<a>{label}</a>
</Link>
</li>
))}
</ul>
</div>
<div className="flex items-center">
<Search />
<Link href="/cart">
<a className="flex items-center text-blue text-body-reg" onClick={onMobileNavClose}>
<span className="hidden sm:block">Cart</span>
<FiShoppingCart size={24} className="mx-2" />
<span>{cartTotal}</span>
</a>
</Link>

{/* Mobile Nav */}
<div className="sm:hidden">
<button
type="button"
className="flex ml-4 text-blue"
aria-controls="mobile-menu"
aria-expanded="false"
onClick={onMobileNavClick}
>
<span className="sr-only">Open Main Menu</span>
{navOpen ? <MdClose size={24} /> : <FiMenu size={24} />}
</button>
</div>
</div>
</nav>
<ul
className={classNames("flex", "flex-col", "sm:hidden", "bg-yellow", "text-blue", "transition-all", {
"h-full": navOpen === true,
"max-h-0": navOpen === false,
})}
>
{navOpen &&
NAV_ITEMS?.map(({ label, href }) => {
return (
<li key={href} className={`border-b border-b-blue text-h4 py-4 px-3`}>
<Link href={href}>
<a className="text-xl" onClick={onMobileNavClose}>
{label}
</a>
</Link>
</li>
);
})}
</ul>
</>
);
};
17 changes: 11 additions & 6 deletions packages/nextjs/components/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import classNames from "classnames";
import { InputHTMLAttributes, useId } from "react";
import { ForwardedRef, forwardRef, InputHTMLAttributes, useId } from "react";

interface Props extends InputHTMLAttributes<HTMLInputElement> {
label: string;
label?: string;
placeholder: string;
disabled?: boolean;
}

export const Input: React.FC<Props> = ({ label, disabled, ...props }) => {
const InputComponent = ({ label, disabled, ...props }: Props, ref: ForwardedRef<HTMLInputElement>) => {
const id = useId();

return (
<div className="flex flex-col w-72">
<label htmlFor={id} className="text-body-reg mb-2 text-blue">
{label}
</label>
{label && (
<label htmlFor={id} className="text-body-reg mb-2 text-blue">
{label}
</label>
)}
<input
ref={ref}
id={id}
disabled={disabled}
className={classNames(
Expand All @@ -36,3 +39,5 @@ export const Input: React.FC<Props> = ({ label, disabled, ...props }) => {
</div>
);
};

export const Input = forwardRef(InputComponent);
16 changes: 11 additions & 5 deletions packages/nextjs/components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Head from "next/head";
import React from "react";
import { Footer } from "./Footer";
import { Header } from "./Header";
Expand All @@ -8,10 +9,15 @@ interface Props {

export const Layout: React.FC<Props> = ({ children }) => {
return (
<div className="h-screen flex flex-col">
<Header />
<main className="flex-1 overflow-auto px-4 w-full">{children}</main>
<Footer />
</div>
<>
<Head>
<title>Formidable Boulangerie</title>
</Head>
<div className="h-screen flex flex-col">
<Header />
<main className="flex-1 overflow-auto w-full">{children}</main>
<Footer />
</div>
</>
);
};
28 changes: 0 additions & 28 deletions packages/nextjs/components/ProductList.tsx

This file was deleted.

8 changes: 4 additions & 4 deletions packages/nextjs/components/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import debounce from "lodash.debounce";
import { ProductSearch } from "utils/groqTypes/ProductSearch";
import Link from "next/link";
import { Image } from "./Image";
import { Input } from "./Input";

const SEARCH_QUERY = groq`*[_type == 'product']
| score(
Expand Down Expand Up @@ -74,10 +75,9 @@ export const Search: React.FC = () => {
}, [closeMenu]);

return (
<div className="mr-5">
<div className="mr-4 hidden sm:block">
<div {...getComboboxProps()}>
<input
className="border rounded p-2 w-72"
<Input
{...getInputProps({
type: "search",
id: "search",
Expand All @@ -90,7 +90,7 @@ export const Search: React.FC = () => {
{...getMenuProps({
"aria-labelledby": "search-label",
})}
className={`absolute bg-white w-72 mt-2 border rounded z-10 p-5 ${!isOpen ? "hidden" : ""}`}
className={`absolute w-72 bg-yellow mt-2 border rounded z-10 p-5 ${!isOpen ? "hidden" : ""}`}
>
{isOpen && products.length ? (
products.map((product) => (
Expand Down
Loading