Using two switchers (one in the shop nav and the other in the cart) makes possible to have the switcher over the Cart overlay (over intro)
240 lines
6.7 KiB
Svelte
240 lines
6.7 KiB
Svelte
<script lang="ts">
|
||
import { onMount } from 'svelte'
|
||
import { shopLocations, cartOpen, cartNotifications } from '$utils/stores/shop'
|
||
// Components
|
||
import Metas from '$components/Metas.svelte'
|
||
import PosterLayout from '$components/layouts/PosterLayout.svelte'
|
||
import SiteTitle from '$components/atoms/SiteTitle.svelte'
|
||
import Image from '$components/atoms/Image.svelte'
|
||
import ButtonCart from '$components/atoms/ButtonCart.svelte'
|
||
import Poster from '$components/molecules/Poster.svelte'
|
||
import NotificationCart from '$components/molecules/NotificationCart.svelte'
|
||
import EmailForm from '$components/molecules/EmailForm.svelte'
|
||
import ShopLocationSwitcher from '$components/molecules/ShopLocationSwitcher.svelte';
|
||
import Cart from '$components/organisms/Cart.svelte'
|
||
|
||
export let shop: any
|
||
export let locations: any
|
||
export let posters: any
|
||
export let product: any
|
||
export let productShop: any
|
||
|
||
let introEl: HTMLElement
|
||
let navObserver: IntersectionObserver
|
||
let scrolledPastIntro = false
|
||
|
||
// Locations with an existing poster product
|
||
$shopLocations = locations.filter(({ slug }: any) => {
|
||
if (posters.find((poster: any) => poster.location.slug === slug)) {
|
||
return true
|
||
}
|
||
})
|
||
|
||
|
||
onMount(async () => {
|
||
// Reveal the nav past the Intro
|
||
navObserver = new IntersectionObserver(entries => {
|
||
entries.forEach(entry => {
|
||
scrolledPastIntro = !entry.isIntersecting
|
||
})
|
||
}, {
|
||
threshold: 0,
|
||
rootMargin: '0px 0px 0px'
|
||
})
|
||
navObserver.observe(introEl)
|
||
|
||
|
||
// Destroy
|
||
return () => {
|
||
navObserver && navObserver.unobserve(introEl)
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<Metas
|
||
title="Shop – Houses Of"
|
||
description=""
|
||
image=""
|
||
/>
|
||
|
||
{#key product}
|
||
<main class="shop-page">
|
||
<Cart />
|
||
|
||
<section class="shop-page__intro" bind:this={introEl}>
|
||
<a href="/" class="back">
|
||
Back to Houses Of
|
||
</a>
|
||
<span class="shop-title">Shop</span>
|
||
|
||
<SiteTitle
|
||
variant="inline"
|
||
/>
|
||
|
||
<header class="shop-page__header">
|
||
<div class="container">
|
||
<p class="text-label">Shop your city</p>
|
||
<nav>
|
||
<ul>
|
||
{#each $shopLocations as { name, slug }}
|
||
<li class:is-active={slug === product.location.slug}>
|
||
<a href="/shop/poster-{slug}">{name}</a>
|
||
</li>
|
||
{/each}
|
||
</ul>
|
||
</nav>
|
||
|
||
<ButtonCart />
|
||
</div>
|
||
</header>
|
||
|
||
<Image
|
||
id={shop.page_heroimage.id}
|
||
alt="photo"
|
||
sizeKey="hero"
|
||
sizes={{
|
||
large: { width: 1800, height: 1200 },
|
||
medium: { width: 1200, height: 800 },
|
||
small: { width: 700, height: 700 },
|
||
}}
|
||
/>
|
||
</section>
|
||
|
||
<nav class="shop-location"
|
||
class:is-visible={scrolledPastIntro}
|
||
class:is-overlaid={$cartOpen}
|
||
>
|
||
<ShopLocationSwitcher />
|
||
<ButtonCart />
|
||
|
||
<div class="shop-location__notifications">
|
||
{#each $cartNotifications as { id, title, name, image } (id)}
|
||
<NotificationCart
|
||
title={title}
|
||
name={name}
|
||
image={image}
|
||
/>
|
||
{/each}
|
||
</div>
|
||
</nav>
|
||
|
||
<section class="shop-page__about grid">
|
||
<p class="description text-normal">{shop.about}</p>
|
||
</section>
|
||
|
||
<PosterLayout
|
||
product={product}
|
||
productShop={productShop}
|
||
/>
|
||
|
||
<section class="shop-page__posters grid">
|
||
<h3>View all of our available posters</h3>
|
||
<div class="set">
|
||
{#each posters as { location, photos_product }}
|
||
<Poster
|
||
location={location}
|
||
image={photos_product.length && photos_product[1].directus_files_id}
|
||
/>
|
||
{/each}
|
||
</div>
|
||
<div class="subscribe">
|
||
<p>Subscribe to be notified when new posters become available</p>
|
||
<EmailForm />
|
||
</div>
|
||
</section>
|
||
</main>
|
||
{/key}
|
||
|
||
<slot />
|
||
|
||
|
||
<script context="module" lang="ts">
|
||
import { fetchAPI } from '$utils/api'
|
||
import { getRandomElement } from '$utils/functions'
|
||
|
||
export async function load ({ page, fetch, session, stuff }) {
|
||
// Init Swell
|
||
// swell.init(import.meta.env.VITE_SWELL_STORE_ID, import.meta.env.VITE_SWELL_API_TOKEN)
|
||
|
||
// Get content from API
|
||
const res = await fetchAPI(`
|
||
query {
|
||
shop {
|
||
about
|
||
page_heroimage { id }
|
||
}
|
||
|
||
location (
|
||
filter: { has_poster: { _eq: true }},
|
||
sort: "name"
|
||
) {
|
||
name
|
||
slug
|
||
}
|
||
|
||
posters: product {
|
||
name
|
||
type
|
||
description
|
||
details
|
||
location {
|
||
name
|
||
slug
|
||
}
|
||
product_id
|
||
photos_product {
|
||
directus_files_id {
|
||
id
|
||
title
|
||
}
|
||
}
|
||
photos_preview {
|
||
directus_files_id {
|
||
id
|
||
title
|
||
}
|
||
}
|
||
}
|
||
}
|
||
`)
|
||
|
||
const { data } = res
|
||
|
||
/**
|
||
* Define product
|
||
*/
|
||
const productAPI = (!page.params.type && !page.params.name)
|
||
// Get a random product
|
||
? data.posters[getRandomElement(data.posters)]
|
||
// Get the current product from slug
|
||
: data.posters.find(({ location }: any) => location.slug === page.params.name)
|
||
|
||
/**
|
||
* Get product data from Swell
|
||
*/
|
||
let productShopRes: any
|
||
|
||
const productShop = await fetch('/api/swell', {
|
||
method: 'POST',
|
||
body: JSON.stringify({
|
||
action: 'getProduct',
|
||
productId: productAPI.product_id,
|
||
})
|
||
})
|
||
if (productShop) {
|
||
productShopRes = await productShop.json()
|
||
}
|
||
|
||
|
||
return {
|
||
props: {
|
||
shop: data.shop,
|
||
locations: data.location,
|
||
posters: data.posters,
|
||
product: productAPI,
|
||
productShop: productShopRes,
|
||
}
|
||
}
|
||
}
|
||
</script>
|