Files
housesof/src/routes/shop/index.svelte

203 lines
5.7 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang="ts">
import { browser } from '$app/env'
import { getContext, onMount } from 'svelte'
import anime from 'animejs'
import type { AnimeTimelineInstance } from 'animejs'
import { cartOpen } from '$utils/stores/shop'
// Components
import PageTransition from '$components/PageTransition.svelte'
import Metas from '$components/Metas.svelte'
import Image from '$components/atoms/Image.svelte'
import SiteTitle from '$components/atoms/SiteTitle.svelte'
import ButtonCart from '$components/atoms/ButtonCart.svelte'
import ShopLocationSwitcher from '$components/molecules/ShopLocationSwitcher.svelte'
import PostersGrid from '$components/organisms/PostersGrid.svelte'
import PosterLayout from '$components/layouts/PosterLayout.svelte'
export let product: any
export let shopProduct: any
const { shop, shopLocations, posters } = getContext('shop')
let introEl: HTMLElement
let navObserver: IntersectionObserver
let scrolledPastIntro = false
/**
* Transition: Anime timeline
*/
let timeline: AnimeTimelineInstance
if (browser) {
requestAnimationFrame(() => {
timeline = anime.timeline({
duration: 1600,
easing: 'easeOutQuart',
autoplay: false,
})
// Hero image
timeline.add({
targets: '.shop-page__background',
scale: [1.06, 1],
opacity: [0, 1],
duration: 2400,
}, 400)
// Intro top elements
timeline.add({
targets: '.shop-page__intro .top > *',
translateY: [-100, 0],
delay: anime.stagger(250),
}, 400)
// Intro navbar
timeline.add({
targets: '.shop-page__nav .container > *',
translateY: [100, 0],
delay: anime.stagger(250),
}, 700)
})
}
onMount(() => {
// 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)
// Transition in
requestAnimationFrame(() => {
timeline.play()
})
// Destroy
return () => {
navObserver && navObserver.unobserve(introEl)
}
})
</script>
<Metas
title="Shop Houses Of"
description=""
image=""
/>
<PageTransition name="shop-page">
<section class="shop-page__intro" bind:this={introEl}>
<div class="top container">
<a href="/" class="back" sveltekit:noscroll>
<svg width="5" height="8" viewBox="0 0 5 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 1 1 4l3 3" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span>Back to Houses Of</span>
</a>
<span class="shop-title">Shop</span>
</div>
<SiteTitle
variant="inline"
/>
<nav class="shop-page__nav">
<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}" sveltekit:prefetch sveltekit:noscroll>
{name}
</a>
</li>
{/each}
</ul>
</nav>
<ButtonCart />
</div>
</nav>
<Image
class="shop-page__background"
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 />
</nav>
<section class="shop-page__about grid">
<div class="description grid text-normal">
<div class="description__inner">
{@html shop.about}
</div>
</div>
</section>
<PosterLayout
product={product}
shopProduct={shopProduct}
/>
<PostersGrid {posters} />
</PageTransition>
<script context="module" lang="ts">
import { getRandomElement } from '$utils/functions'
/** @type {import('@sveltejs/kit').Load} */
export async function load ({ url, params, fetch, session, stuff }) {
let shopProduct: any
// Get a random product from the API
const productAPI = getRandomElement(stuff.posters)
// Fetch this product on Swell API
if (productAPI) {
const shopProductRes = await fetch('/api/swell', {
method: 'POST',
body: JSON.stringify({
action: 'getProduct',
productId: productAPI.product_id,
})
})
if (shopProductRes.ok) {
shopProduct = await shopProductRes.json()
}
}
return {
props: {
product: productAPI,
shopProduct,
}
}
}
</script>