diff --git a/components/core/Avatar/Avatar.module.css b/components/core/Avatar/Avatar.module.css deleted file mode 100644 index c3a2af639..000000000 --- a/components/core/Avatar/Avatar.module.css +++ /dev/null @@ -1,2 +0,0 @@ -.root { -} diff --git a/components/core/Avatar/Avatar.tsx b/components/core/Avatar/Avatar.tsx index bb76544e7..20ec7454c 100644 --- a/components/core/Avatar/Avatar.tsx +++ b/components/core/Avatar/Avatar.tsx @@ -1,21 +1,39 @@ import cn from 'classnames' import { FC } from 'react' -import s from './Avatar.module.css' - +import { random } from 'lodash' +import { useState } from 'react' interface Props { className?: string children?: any } -const Avatar: FC = ({ className }) => { - const rootClassName = cn(s.root, className) +function getRandomPairOfColors() { + const colors = ['#f33', '#7928ca', '#50e3c2', '#7928ca', '#7928CA'] + const getRandomIdx = () => random(0, colors.length - 1) + let idx = getRandomIdx() + let idx2 = getRandomIdx() + + // Has to be a different color + while (idx2 === idx) { + idx2 = getRandomIdx() + } + + // Returns a pair of colors + return [colors[idx], colors[idx2]] +} + +const Avatar: FC = ({}) => { + const [bg] = useState(getRandomPairOfColors) + return ( -
- +
+ {/* Add an image - We're generating a gradient as placeholder + */}
) } diff --git a/components/product/ProductSlider/ProductSlider.tsx b/components/product/ProductSlider/ProductSlider.tsx new file mode 100644 index 000000000..c255b5038 --- /dev/null +++ b/components/product/ProductSlider/ProductSlider.tsx @@ -0,0 +1,34 @@ +import { FC, useState } from 'react' +import React from 'react' +import SwipeableViews from 'react-swipeable-views' + +interface Props { + children?: any +} + +const ProductSlider: FC = ({ children }) => { + const [idx, setIdx] = useState(0) + const count = React.Children.count(children) + + const goBack = () => { + idx !== 0 ? setIdx(idx - 1) : setIdx(count - 1) + } + + const goNext = () => { + idx + 1 === count ? setIdx(0) : setIdx(idx + 1) + } + + return ( +
+
+
+
+
+ + {children} + +
+ ) +} + +export default ProductSlider diff --git a/components/product/ProductSlider/index.ts b/components/product/ProductSlider/index.ts new file mode 100644 index 000000000..504440410 --- /dev/null +++ b/components/product/ProductSlider/index.ts @@ -0,0 +1 @@ +export { default } from './ProductSlider' diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx index 50e1c7e81..2eb132355 100644 --- a/components/product/ProductView/ProductView.tsx +++ b/components/product/ProductView/ProductView.tsx @@ -1,13 +1,13 @@ import cn from 'classnames' +import { NextSeo } from 'next-seo' import { FC, useState } from 'react' import s from './ProductView.module.css' -import { Button, Container } from '@components/ui' -import { Swatch } from '@components/product' import { Colors } from '@components/ui/types' -import type { Product } from '@lib/bigcommerce/api/operations/get-product' -import useAddItem from '@lib/bigcommerce/cart/use-add-item' import { useUI } from '@components/ui/context' - +import { Button, Container } from '@components/ui' +import { Swatch, ProductSlider } from '@components/product' +import useAddItem from '@lib/bigcommerce/cart/use-add-item' +import type { Product } from '@lib/bigcommerce/api/operations/get-product' interface Props { className?: string children?: any @@ -44,7 +44,24 @@ const ProductView: FC = ({ product, className }) => { return ( -
+ +

{product.name} @@ -55,13 +72,18 @@ const ProductView: FC = ({ product, className }) => { {product.prices?.price.currencyCode}

-
+
- + + {product.images.edges?.map((image) => ( + + ))} +
+
+ +
+
diff --git a/components/product/index.ts b/components/product/index.ts index c9459e858..82ac6c548 100644 --- a/components/product/index.ts +++ b/components/product/index.ts @@ -1,3 +1,4 @@ export { default as Swatch } from './Swatch' export { default as ProductView } from './ProductView' export { default as ProductCard } from './ProductCard' +export { default as ProductSlider } from './ProductSlider' diff --git a/config.json b/config.json new file mode 100644 index 000000000..6c279ee04 --- /dev/null +++ b/config.json @@ -0,0 +1,18 @@ +{ + "seo": { + "title": "ACME Storefront | Powered by Next.js Commerce", + "titleTemplate": "%s - ACME Storefront", + "description": "Next.js Commerce -> https://www.nextjs.org/commerce", + "openGraph": { + "type": "website", + "locale": "en_IE", + "url": "https://nextjs.org/commerce", + "site_name": "Next.js Commerce" + }, + "twitter": { + "handle": "@nextjs", + "site": "@nextjs", + "cardType": "summary_large_image" + } + } +} diff --git a/package.json b/package.json index 1d6a81c37..c452c1dd6 100644 --- a/package.json +++ b/package.json @@ -21,18 +21,23 @@ "@headlessui/react": "^0.2.0", "@tailwindcss/ui": "^0.6.2", "@types/classnames": "^2.2.10", + "@types/react-swipeable-views": "^0.13.0", "classnames": "^2.2.6", "cookie": "^0.4.1", "js-cookie": "^2.2.1", "lodash.debounce": "^4.0.8", "next": "^9.5.4", + "next-seo": "^4.11.0", "next-themes": "^0.0.4", + "nextjs-progressbar": "^0.0.6", "postcss-nesting": "^7.0.1", "react": "^16.13.1", "react-aria": "^3.0.0", "react-dom": "^16.13.1", "react-icons": "^3.11.0", "react-merge-refs": "^1.1.0", + "react-swipeable-views": "^0.13.9", + "react-swipeable-views-utils": "^0.14.0-alpha.0", "react-ticker": "^1.2.2", "swr": "^0.3.3" }, diff --git a/pages/_app.tsx b/pages/_app.tsx index 2b362df40..51f376b77 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,10 +1,13 @@ import { FC } from 'react' +import { DefaultSeo } from 'next-seo' import type { AppProps } from 'next/app' -import { SSRProvider, OverlayProvider } from 'react-aria' import { ThemeProvider } from 'next-themes' +import { SSRProvider, OverlayProvider } from 'react-aria' import '@assets/global.css' import '@assets/tailwind.css' import '@assets/utils.css' +import config from '../config.json' +import Head from 'next/head' const Noop: FC = ({ children }) => <>{children} @@ -12,14 +15,21 @@ export default function MyApp({ Component, pageProps }: AppProps) { const Layout = (Component as any).Layout || Noop return ( - - - - - - - - - + <> + + + + + + + + + + + + + + + ) } diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 000000000..c4826c947 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/icon-144x144.png b/public/icon-144x144.png new file mode 100644 index 000000000..aeeaabd3f Binary files /dev/null and b/public/icon-144x144.png differ diff --git a/public/icon-192x192.png b/public/icon-192x192.png new file mode 100644 index 000000000..055ecf31e Binary files /dev/null and b/public/icon-192x192.png differ diff --git a/public/icon-512x512.png b/public/icon-512x512.png new file mode 100644 index 000000000..754628cb7 Binary files /dev/null and b/public/icon-512x512.png differ diff --git a/public/icon.png b/public/icon.png new file mode 100644 index 000000000..c4df8c7d1 Binary files /dev/null and b/public/icon.png differ diff --git a/public/site.webmanifest b/public/site.webmanifest new file mode 100644 index 000000000..bb792da42 --- /dev/null +++ b/public/site.webmanifest @@ -0,0 +1,22 @@ +{ + "name": "Next.js Commerce", + "short_name": "Next.js Commerce", + "description": "Next.js Commerce -> https://www.nextjs.org/commerce", + "display": "standalone", + "start_url": "/", + "theme_color": "#fff", + "background_color": "#000000", + "orientation": "portrait", + "icons": [ + { + "src": "/icon-192x192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "/icon-512x512.png", + "type": "image/png", + "sizes": "512x512" + } + ] +} \ No newline at end of file diff --git a/public/slider-arrows.png b/public/slider-arrows.png new file mode 100644 index 000000000..0740919c9 Binary files /dev/null and b/public/slider-arrows.png differ diff --git a/tailwind.config.js b/tailwind.config.js index 4f605d5fa..8cbc245b8 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -17,6 +17,7 @@ module.exports = { 'accent-1': '#FAFAFA', 'accent-2': '#F1F3F5', 'accent-4': '#888', + 'accent-6': '#E5E5E5', 'accent-8': '#111111', violet: '#7928CA', pink: '#FF0080', diff --git a/yarn.lock b/yarn.lock index c5ed20203..592959eb7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1009,7 +1009,14 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-typescript" "^7.10.4" -"@babel/runtime@7.11.2", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.6.2", "@babel/runtime@^7.8.4": +"@babel/runtime@7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0.tgz#adeb78fedfc855aa05bc041640f3f6f98e85424c" + integrity sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA== + dependencies: + regenerator-runtime "^0.12.0" + +"@babel/runtime@7.11.2", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.8.4": version "7.11.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== @@ -2175,6 +2182,21 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== +"@types/react-swipeable-views@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@types/react-swipeable-views/-/react-swipeable-views-0.13.0.tgz#9e5f2efa51380886f3f73014ac8b15546d337210" + integrity sha512-orrreCcXev6IUXDuHf07RDDCAoIZRMSr95eyWmYNRfjic7w/O+68iPu0NCysVls+UygRNvoqZMuXI72N/58E1w== + dependencies: + "@types/react" "*" + +"@types/react@*": + version "16.9.52" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.52.tgz#c46c72d1a1d8d9d666f4dd2066c0e22600ccfde1" + integrity sha512-EHRjmnxiNivwhGdMh9sz1Yw9AUxTSZFxKqdBWAAzyZx3sufWwx6ogqHYh/WB1m/I4ZpjkoZLExF5QTy2ekVi/Q== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + "@types/react@^16.9.49": version "16.9.50" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.50.tgz#cb5f2c22d42de33ca1f5efc6a0959feb784a3a2d" @@ -5176,6 +5198,11 @@ jws@^3.2.2: jwa "^1.4.1" safe-buffer "^5.0.1" +keycode@^2.1.7: + version "2.2.0" + resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.2.0.tgz#3d0af56dc7b8b8e5cba8d0a97f107204eec22b04" + integrity sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ= + keyv@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" @@ -5676,6 +5703,11 @@ neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== +next-seo@^4.11.0: + version "4.11.0" + resolved "https://registry.yarnpkg.com/next-seo/-/next-seo-4.11.0.tgz#b4f160414b49e6e3dc7791df25e29b50550ebb67" + integrity sha512-JrrGA+wD20ArI5jTqbLE2jipmA5VCCcjBlb1ZI2lKktd7lCXNs/IIvwkNfJPPK0vFp/ewwylA6kO5CyX2fflig== + next-themes@^0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.0.4.tgz#fb06a9d03887201dd8fdd75fc1c84f406988f61e" @@ -5751,6 +5783,13 @@ next@^9.5.4: webpack "4.44.1" webpack-sources "1.4.3" +nextjs-progressbar@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/nextjs-progressbar/-/nextjs-progressbar-0.0.6.tgz#d1841df42f2342807dc6f7ad1034ddb8ec8541d4" + integrity sha512-9sxNpUSHOnmRV8/3yEZ9NV5c/ip2CpQ7jim3EOOZp49qIHrgNxmy/kzoulNjt50AlA7pAu/8rwgC2WpzmSMrdg== + dependencies: + nprogress "^0.2.0" + no-case@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.3.tgz#c21b434c1ffe48b39087e86cfb4d2582e9df18f8" @@ -5838,6 +5877,11 @@ normalize.css@^8.0.1: resolved "https://registry.yarnpkg.com/normalize.css/-/normalize.css-8.0.1.tgz#9b98a208738b9cc2634caacbc42d131c97487bf3" integrity sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg== +nprogress@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1" + integrity sha1-y480xTIT2JVyP8urkH6UIq28r7E= + nullthrows@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" @@ -6591,7 +6635,7 @@ promise@^7.1.1: dependencies: asap "~2.0.3" -prop-types@15.7.2, prop-types@^15.6.2: +prop-types@15.7.2, prop-types@^15.5.4, prop-types@^15.6.0, prop-types@^15.6.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -6715,6 +6759,15 @@ react-dom@^16.13.1: prop-types "^15.6.2" scheduler "^0.19.1" +react-event-listener@^0.6.0: + version "0.6.6" + resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.6.6.tgz#758f7b991cad9086dd39fd29fad72127e1d8962a" + integrity sha512-+hCNqfy7o9wvO6UgjqFmBzARJS7qrNoda0VqzvOuioEpoEXKutiKuv92dSz6kP7rYLmyHPyYNLesi5t/aH1gfw== + dependencies: + "@babel/runtime" "^7.2.0" + prop-types "^15.6.0" + warning "^4.0.1" + react-icons@^3.11.0: version "3.11.0" resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-3.11.0.tgz#2ca2903dfab8268ca18ebd8cc2e879921ec3b254" @@ -6737,6 +6790,57 @@ react-refresh@0.8.3: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" integrity sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg== +react-swipeable-views-core@^0.13.7: + version "0.13.7" + resolved "https://registry.yarnpkg.com/react-swipeable-views-core/-/react-swipeable-views-core-0.13.7.tgz#c082b553f26e83fd20fc17f934200eb717023c8a" + integrity sha512-ekn9oDYfBt0oqJSGGwLEhKvn+QaqMGTy//9dURTLf+vp7W5j6GvmKryYdnwJCDITaPFI2hujXV4CH9krhvaE5w== + dependencies: + "@babel/runtime" "7.0.0" + warning "^4.0.1" + +react-swipeable-views-core@^0.14.0-alpha.0: + version "0.14.0-alpha.0" + resolved "https://registry.yarnpkg.com/react-swipeable-views-core/-/react-swipeable-views-core-0.14.0-alpha.0.tgz#1c40dd1c328c97048a8f2cb9de504ee611ae21dd" + integrity sha512-TQm58RJv01EseBfaeY0kZUIBmhs1NyKXwhJL52iN/UlzbQSiaIE2kk+mSGicUriBK0H7UlScgLeJR91AJ7SVcA== + dependencies: + "@babel/runtime" "7.0.0" + warning "^4.0.1" + +react-swipeable-views-utils@^0.13.9: + version "0.13.9" + resolved "https://registry.yarnpkg.com/react-swipeable-views-utils/-/react-swipeable-views-utils-0.13.9.tgz#a66e98f2f4502d8b00182901f80d13b2f903e10f" + integrity sha512-QLGxRKrbJCbWz94vkWLzb1Daaa2Y/TZKmsNKQ6WSNrS+chrlfZ3z9tqZ7YUJlW6pRWp3QZdLSY3UE3cN0TXXmw== + dependencies: + "@babel/runtime" "7.0.0" + keycode "^2.1.7" + prop-types "^15.6.0" + react-event-listener "^0.6.0" + react-swipeable-views-core "^0.13.7" + shallow-equal "^1.2.1" + +react-swipeable-views-utils@^0.14.0-alpha.0: + version "0.14.0-alpha.0" + resolved "https://registry.yarnpkg.com/react-swipeable-views-utils/-/react-swipeable-views-utils-0.14.0-alpha.0.tgz#1bc91cf89d13417a0ca8edc11b4a2c55c4a889b9" + integrity sha512-Ya9Xtr4uE1CYxyrPwtcImzcZFcOr3PP51kRgIOTx3Dx9SF31OtF0t2CgXuypTYTs7G4StRE3NzWlvSBiMZSVtQ== + dependencies: + "@babel/runtime" "7.0.0" + keycode "^2.1.7" + prop-types "^15.6.0" + react-event-listener "^0.6.0" + react-swipeable-views-core "^0.14.0-alpha.0" + shallow-equal "^1.2.1" + +react-swipeable-views@^0.13.9: + version "0.13.9" + resolved "https://registry.yarnpkg.com/react-swipeable-views/-/react-swipeable-views-0.13.9.tgz#d6a6c508bf5288ad55509f9c65916db5df0f2cec" + integrity sha512-WXC2FKYvZ9QdJ31v9LjEJEl1bA7E4AcaloTkbW0uU0dYf5uvv4aOpiyxubvOkVl1a5L2UAHmKSif4TmJ9usrSg== + dependencies: + "@babel/runtime" "7.0.0" + prop-types "^15.5.4" + react-swipeable-views-core "^0.13.7" + react-swipeable-views-utils "^0.13.9" + warning "^4.0.1" + react-ticker@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/react-ticker/-/react-ticker-1.2.2.tgz#12cda5ff8266c6fe90ffcd8c58e12ba1596ddf24" @@ -6809,6 +6913,11 @@ regenerate@^1.4.0: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f" integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A== +regenerator-runtime@^0.12.0: + version "0.12.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" + integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== + regenerator-runtime@^0.13.4: version "0.13.7" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" @@ -7194,6 +7303,11 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" +shallow-equal@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.2.1.tgz#4c16abfa56043aa20d050324efa68940b0da79da" + integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA== + shell-quote@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" @@ -7934,6 +8048,13 @@ vue-template-compiler@^2.6.12: de-indent "^1.0.2" he "^1.1.0" +warning@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" + integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== + dependencies: + loose-envify "^1.0.0" + watchpack@2.0.0-beta.13: version "2.0.0-beta.13" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.0.0-beta.13.tgz#9d9b0c094b8402139333e04eb6194643c8384f55"