Skip to content
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
2 changes: 1 addition & 1 deletion templates/demo-store-neue/hydrogen.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default defineConfig({
shopify: {
storeDomain: 'hydrogen-preview.myshopify.com',
storefrontToken: '3b580e70970c4528da70c98e097c2fa0',
storefrontApiVersion: '2022-07',
storefrontApiVersion: 'unstable',
},
session: CookieSessionStorage('__session', {
path: '/',
Expand Down
1 change: 1 addition & 0 deletions templates/demo-store-neue/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"clsx": "^1.1.1",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-use": "^17.4.0",
"title": "^3.4.4",
"typographic-base": "^1.0.4"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {useState, Suspense} from 'react';
import {useCallback, useState, Suspense} from 'react';
import {useCountry, fetchSync} from '@shopify/hydrogen';
import {Listbox} from '@headlessui/react';
import Icon from '~/components/elements/Icon';
Expand All @@ -8,12 +8,20 @@ import Icon from '~/components/elements/Icon';
*/
export default function CountrySelector() {
const [listboxOpen, setListboxOpen] = useState(false);
const [selectedCountry] = useCountry();

const [selectedCountry, setSelectedCountry] = useCountry();
const setCountry = useCallback(({isoCode, name}) => {
fetch(`/api/countries`, {
body: JSON.stringify({isoCode, name}),
method: 'POST',
}).then(() => {
window.location.reload();
});
}, []);

return (
<div className="relative">
<Listbox onChange={setSelectedCountry}>
<Listbox onChange={setCountry}>
{({open}) => {
setTimeout(() => setListboxOpen(open));
return (
Expand All @@ -28,8 +36,8 @@ export default function CountrySelector() {
/>
</Listbox.Button>

<Listbox.Options className="">
<div className="">
<Listbox.Options className="absolute z-10 mt-2">
<div className="h-64 p-4 overflow-y-auto rounded-lg drop-shadow-2xl">
<Listbox.Option disabled className="">
Country
</Listbox.Option>
Expand All @@ -39,8 +47,8 @@ export default function CountrySelector() {
selectedCountry={selectedCountry}
getClassName={(active) => {
return (
`w-36 py-2 px-3 flex justify-between items-center text-left cursor-pointer` +
`rounded ${active ? 'bg-gray-200' : null}`
`w-full cursor-pointer py-2 px-3 flex justify-between items-center text-left cursor-pointer` +
`rounded ${active ? '' : null}`
);
}}
/>
Expand Down
77 changes: 43 additions & 34 deletions templates/demo-store-neue/src/components/blocks/ProductCard.jsx
Original file line number Diff line number Diff line change
@@ -1,67 +1,76 @@
import {Image, Link} from '@shopify/hydrogen';
import {Image, Link, Money, useMoney} from '@shopify/hydrogen';
import clsx from 'clsx';
import {Text} from '../elements';

export default function ProductCard({product, className}) {
const {compareAtPrice, price, handle, label, createdAt, image, title} =
product;
import {Text} from '~/components/elements';
import {isDiscounted, isNewArrival} from '~/lib/utils';
import {product as mockProduct} from '~/lib/placeholders';

export default function ProductCard({product = mockProduct, label, className}) {
let cardLabel;
var today = new Date();
var newArrivalDate = new Date(new Date().setDate(today.getDate() - 30));

const {
image,
priceV2: price,
compareAtPriceV2: compareAtPrice,
} = product.variants.nodes[0];

if (label) {
cardLabel = label;
} else if (compareAtPrice.amount > price.amount) {
} else if (price.amount > compareAtPrice?.amount) {
cardLabel = 'Sale';
} else if (createdAt > newArrivalDate) {
} else if (isNewArrival(product.publishedAt)) {
cardLabel = 'New';
}

const styles = clsx('grid gap-6', className);

return (
<Link to={`/products/${handle}`}>
<Link to={`/products/${product.handle}`}>
<div className={styles}>
<div className="relative rounded overflow-clip image-border">
<Text
as="label"
className="absolute top-0 right-0 m-4 leading-none text-right text-notice"
size="fine"
className="absolute top-0 right-0 m-4 text-right text-notice"
>
{cardLabel}
</Text>
<Image
width={336}
height={424}
className="aspect-[4/5] "
src={image}
alt="Alt Tag"
/>
<Image className="aspect-[4/5]" data={image} alt="Alt Tag" />
</div>
<div className="grid gap-2">
<div className="grid gap-1">
<Text
className="w-full overflow-hidden leading-none whitespace-nowrap text-ellipsis "
className="w-full overflow-hidden whitespace-nowrap text-ellipsis "
as="h3"
>
{title}
{product.title}
</Text>
<div className="flex gap-4">
<div className="flex gap-4">
<Text>
{price.symbol}
{price.amount}
</Text>
{compareAtPrice.amount > price.amount && (
<Text className="opacity-50 strike">
{compareAtPrice.symbol}
{compareAtPrice.amount}
</Text>
<Text className="flex gap-4">
<Money withoutTrailingZeros data={price} />
{isDiscounted(price, compareAtPrice) && (
<CompareAtPrice
className={'opacity-50'}
data={compareAtPrice}
/>
)}
</div>
<Text className="opacity-50">11 Colors Available</Text>
</Text>
</div>
</div>
</div>
</Link>
);
}

// <Money className="opacity-50 strike" data={compareAtPrice} />
function CompareAtPrice({data, className}) {
const {currencyNarrowSymbol, withoutTrailingZerosAndCurrency} =
useMoney(data);

const styles = clsx('strike', className);

return (
<span className={styles}>
{currencyNarrowSymbol}
{withoutTrailingZerosAndCurrency}
</span>
);
}
34 changes: 34 additions & 0 deletions templates/demo-store-neue/src/components/elements/Grid.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import clsx from 'clsx';
import {missingClass} from '~/lib/utils';

export default function Grid({
as = 'div',
gap = 'default',
layout = 'default',
items = 4,
flow = 'row',
children,
className,
}) {
const Component = as;

const layouts = {
default: `grid-cols-2 ${items >= 3 && 'md:grid-cols-3'} ${
items >= 4 && 'lg:grid-cols-4'
}`,
auto: 'auto-cols-auto',
};

const gaps = {
default: 'grid gap-2 md:gap-4 lg:gap-6',
};

const flows = {
row: 'grid-flow-row',
col: 'grid-flow-col',
};

const styles = clsx(flow[flow], gaps[gap], layouts[layout], className);

return <Component className={styles}>{children}</Component>;
}
12 changes: 11 additions & 1 deletion templates/demo-store-neue/src/components/elements/Heading.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,23 @@ import {missingClass, formatText} from '~/lib/utils';

export default function Heading({
as = 'h2',
level,
size = 'heading',
width = 'default',
format = true,
className = '',
children,
}) {
const Component = as;
const levels = {
1: 'h1',
2: 'h2',
3: 'h3',
4: 'h4',
5: 'h5',
6: 'h6',
};

const Component = level ? levels[level] : as;

const sizes = {
display: 'font-bold text-display',
Expand Down
11 changes: 10 additions & 1 deletion templates/demo-store-neue/src/components/elements/Text.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,24 @@ export default function Text({
as = 'span',
size = 'copy',
width = 'default',
color = 'default',
className,
format,
children,
}) {
const Component = as;

const colors = {
default: 'inherit',
primary: 'text-primary/90',
notice: 'text-notice',
contrast: 'text-contrast/90',
};

const sizes = {
lead: 'text-lead font-medium',
copy: 'text-copy',
fine: 'text-fine',
fine: 'text-fine subpixel-antialiased',
};

const widths = {
Expand All @@ -26,6 +34,7 @@ export default function Text({
const styles = clsx(
missingClass(className, 'max-w-') && widths[width],
missingClass(className, 'whitespace-') && 'whitespace-pre-wrap',
missingClass(className, 'text-') && colors[color],
sizes[size],
className,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export {default as Skeleton} from './Skeleton';
export {default as Button} from './Button';
export {default as Text} from './Text';
export {default as Heading} from './Heading';
export {default as Grid} from './Grid';
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import {
} from '~/components/sections';
import {Text, Button} from '~/components/elements';

export default function NotFound() {
export default function NotFound({type = 'page'}) {
const heading = `We’ve lost this ${type}`;
const description = `We couldn’t find the ${type} you’re looking for. Try checking the URL or heading back to the home page.`;

return (
<Layout>
<PageHeader heading="We’ve lost this page">
<PageHeader heading={heading}>
<Text format width="narrow" as="p">
We couldn’t find the page you’re looking for. Try checking the URL or
heading back to the home page.
{description}
</Text>
<Button width="auto" variant="secondary" to={'/'}>
Take me to the home page
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import Section from './Section';
import {Link, Image} from '@shopify/hydrogen';
import {Heading} from '../elements';
import PageSection from './PageSection';
import {Heading, Grid} from '~/components/elements';

const dummyCollections = [
const mockCollections = [
{
id: '1',
url: '/',
url: '/collections/freestyle-collection',
image: 'https://picsum.photos/seed/3/912',
title: 'Bath',
},
{
id: '2',
url: '/',
url: '/collections/freestyle-collection',
image: 'https://picsum.photos/seed/4/912',
title: 'Swim',
},
{
id: '3',
url: '/',
url: '/collections/freestyle-collection',
image: 'https://picsum.photos/seed/5/912',
title: 'Gifts',
},
Expand All @@ -27,30 +27,26 @@ const dummyCollections = [

export default function FeaturedCollections({
title = 'Collections',
collections = dummyCollections,
collections = mockCollections,
}) {
return (
<PageSection heading={title}>
<ul className="grid md:grid-cols-3 gap-m">
<Section heading={title}>
<Grid items={collections.length}>
{collections.map((collection) => (
<li key={collection.id}>
<Link to={collection.url}>
<div className="grid gap-m">
<div className="">
<Image
className="rounded shadow-border overflow-clip inline-block aspect-square md:aspect-[4/3] object-cover"
width={'100%'}
height={336}
alt={`Image of ${collection.title}`}
src={collection.image}
/>
</div>
<Heading size="copy">{collection.title}</Heading>
</div>
</Link>
</li>
<Link key={collection.id} to={collection.url}>
<div className="grid gap-m">
<Image
className="rounded shadow-border overflow-clip inline-block aspect-square md:aspect-[4/3] object-cover"
width={'100%'}
height={336}
alt={`Image of ${collection.title}`}
src={collection.image}
/>
<Heading size="copy">{collection.title}</Heading>
</div>
</Link>
))}
</ul>
</PageSection>
</Grid>
</Section>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const menusPlaceholder = [
links: [
{
id: 1,
title: 'Content &amp; Metafields',
title: 'Content & Metafields',
url: '/',
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function Header({title}) {
</Link>
<nav className="flex gap-l">
{/* TODO: Replace with Navigation API */}
<Link className={styles.text} to="/">
<Link className={styles.text} to="/collections/freestyle-collection">
Shop
</Link>
<Link className={styles.text} to="/">
Expand Down
Loading