✨ Rework Shop pages and switch to page endpoints
- Create ShopHeader component to reuse on pages - Use page endpoints to query data from API and Swell - Remove use of `stuff`
This commit is contained in:
133
src/components/organisms/ShopHeader.svelte
Normal file
133
src/components/organisms/ShopHeader.svelte
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { getContext, onMount } from 'svelte'
|
||||||
|
import anime from 'animejs'
|
||||||
|
import type { AnimeTimelineInstance } from 'animejs'
|
||||||
|
import { cartOpen } from '$utils/stores/shop'
|
||||||
|
// Components
|
||||||
|
import Image from '$components/atoms/Image.svelte'
|
||||||
|
import ButtonCart from '$components/atoms/ButtonCart.svelte'
|
||||||
|
import ShopLocationSwitcher from '$components/molecules/ShopLocationSwitcher.svelte'
|
||||||
|
|
||||||
|
export let product: any = undefined
|
||||||
|
|
||||||
|
const { shop, shopLocations } = getContext('shop')
|
||||||
|
|
||||||
|
let navObserver: IntersectionObserver
|
||||||
|
let introEl: HTMLElement
|
||||||
|
let scrolledPastIntro = false
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animations
|
||||||
|
*/
|
||||||
|
// Setup animations
|
||||||
|
const timeline: AnimeTimelineInstance = 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)
|
||||||
|
|
||||||
|
// Hero title
|
||||||
|
timeline.add({
|
||||||
|
targets: '.shop-page__intro h1',
|
||||||
|
translateY: [32, 0],
|
||||||
|
opacity: [0, 1],
|
||||||
|
}, 500)
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
// Transition in
|
||||||
|
requestAnimationFrame(timeline.play)
|
||||||
|
|
||||||
|
|
||||||
|
// Destroy
|
||||||
|
return () => {
|
||||||
|
navObserver && navObserver.unobserve(introEl)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1>Shop</h1>
|
||||||
|
|
||||||
|
<nav class="shop-page__nav">
|
||||||
|
<div class="container">
|
||||||
|
<p class="text-label">Choose a city</p>
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
{#each shopLocations as { name, slug }}
|
||||||
|
<li class:is-active={product && 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>
|
||||||
@@ -1,148 +1,28 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getContext, onMount } from 'svelte'
|
import { getContext } from 'svelte'
|
||||||
import anime from 'animejs'
|
|
||||||
import type { AnimeTimelineInstance } from 'animejs'
|
|
||||||
import { cartOpen } from '$utils/stores/shop'
|
|
||||||
import { capitalizeFirstLetter } from '$utils/functions'
|
import { capitalizeFirstLetter } from '$utils/functions'
|
||||||
// Components
|
// Components
|
||||||
import PageTransition from '$components/PageTransition.svelte'
|
import PageTransition from '$components/PageTransition.svelte'
|
||||||
import Metas from '$components/Metas.svelte'
|
import Metas from '$components/Metas.svelte'
|
||||||
import Image from '$components/atoms/Image.svelte'
|
import ShopHeader from '$components/organisms/ShopHeader.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 PostersGrid from '$components/organisms/PostersGrid.svelte'
|
||||||
import PosterLayout from '$components/layouts/PosterLayout.svelte'
|
import PosterLayout from '$components/layouts/PosterLayout.svelte'
|
||||||
|
|
||||||
export let product: any
|
export let product: any
|
||||||
export let shopProduct: any
|
export let shopProduct: any
|
||||||
|
|
||||||
const { shop, shopLocations, posters } = getContext('shop')
|
const { posters } = getContext('shop')
|
||||||
|
|
||||||
let introEl: HTMLElement
|
|
||||||
let navObserver: IntersectionObserver
|
|
||||||
let scrolledPastIntro = false
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Animations
|
|
||||||
*/
|
|
||||||
// Setup animations
|
|
||||||
const timeline: AnimeTimelineInstance = 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)
|
|
||||||
|
|
||||||
// Transition in
|
|
||||||
requestAnimationFrame(timeline.play)
|
|
||||||
|
|
||||||
|
|
||||||
// Destroy
|
|
||||||
return () => {
|
|
||||||
navObserver && navObserver.unobserve(introEl)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Metas
|
<Metas
|
||||||
title="{product.location.name} {capitalizeFirstLetter(product.type)} – Houses Of Shop"
|
title="{product.location.name} {capitalizeFirstLetter(product.type)} – Houses Of"
|
||||||
description=""
|
description=""
|
||||||
image=""
|
image=""
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
<PageTransition name="shop-page">
|
<PageTransition name="shop-page">
|
||||||
<section class="shop-page__intro" bind:this={introEl}>
|
<ShopHeader {product} />
|
||||||
<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">Choose a 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>
|
|
||||||
|
|
||||||
<PosterLayout
|
<PosterLayout
|
||||||
product={product}
|
product={product}
|
||||||
@@ -151,36 +31,3 @@
|
|||||||
|
|
||||||
<PostersGrid {posters} />
|
<PostersGrid {posters} />
|
||||||
</PageTransition>
|
</PageTransition>
|
||||||
|
|
||||||
|
|
||||||
<script context="module" lang="ts">
|
|
||||||
/** @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 = stuff.posters.find(poster => poster.location.slug === params.name)
|
|
||||||
|
|
||||||
// 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>
|
|
||||||
57
src/routes/shop/[type]-[name].ts
Normal file
57
src/routes/shop/[type]-[name].ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import type { RequestEvent, RequestHandlerOutput } from '@sveltejs/kit'
|
||||||
|
import { fetchAPI } from '$utils/api'
|
||||||
|
import { getProduct } from '$utils/functions/swell'
|
||||||
|
|
||||||
|
export async function get({ params }: RequestEvent): Promise<RequestHandlerOutput> {
|
||||||
|
try {
|
||||||
|
// Get content from API
|
||||||
|
const data = await fetchAPI(`
|
||||||
|
query {
|
||||||
|
poster: product (search: "${params.name}") {
|
||||||
|
name
|
||||||
|
type
|
||||||
|
description
|
||||||
|
details
|
||||||
|
location {
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
product_id
|
||||||
|
photos_product {
|
||||||
|
directus_files_id {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
photos_preview {
|
||||||
|
directus_files_id {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
const poster = data.data.poster[0]
|
||||||
|
|
||||||
|
// Fetch Swell API for product
|
||||||
|
const shopProduct = await getProduct(poster.product_id)
|
||||||
|
|
||||||
|
if (shopProduct) {
|
||||||
|
return {
|
||||||
|
body: {
|
||||||
|
product: poster,
|
||||||
|
shopProduct,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
status: 404,
|
||||||
|
body: error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,10 +41,10 @@
|
|||||||
|
|
||||||
|
|
||||||
<script context="module" lang="ts">
|
<script context="module" lang="ts">
|
||||||
|
import type { LoadEvent, LoadOutput } from '@sveltejs/kit'
|
||||||
import { fetchAPI } from '$utils/api'
|
import { fetchAPI } from '$utils/api'
|
||||||
|
|
||||||
/** @type {import('@sveltejs/kit').Load} */
|
export async function load ({ fetch }: LoadEvent): Promise<LoadOutput> {
|
||||||
export async function load ({ url, params, fetch, session, stuff }) {
|
|
||||||
// Get content from API
|
// Get content from API
|
||||||
const res = await fetchAPI(`
|
const res = await fetchAPI(`
|
||||||
query {
|
query {
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
|
|
||||||
const { data: { shop, location, posters } } = res
|
const { data: { shop, location, posters }} = res
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,11 +123,6 @@
|
|||||||
posters,
|
posters,
|
||||||
shopProducts,
|
shopProducts,
|
||||||
},
|
},
|
||||||
stuff: {
|
|
||||||
shop,
|
|
||||||
posters,
|
|
||||||
shopProducts,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -1,81 +1,16 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getContext, onMount } from 'svelte'
|
import { getContext } from 'svelte'
|
||||||
import anime from 'animejs'
|
|
||||||
import type { AnimeTimelineInstance } from 'animejs'
|
|
||||||
import { cartOpen } from '$utils/stores/shop'
|
|
||||||
// Components
|
// Components
|
||||||
import PageTransition from '$components/PageTransition.svelte'
|
import PageTransition from '$components/PageTransition.svelte'
|
||||||
import Metas from '$components/Metas.svelte'
|
import Metas from '$components/Metas.svelte'
|
||||||
import Image from '$components/atoms/Image.svelte'
|
|
||||||
import ButtonCart from '$components/atoms/ButtonCart.svelte'
|
|
||||||
import ShopLocationSwitcher from '$components/molecules/ShopLocationSwitcher.svelte'
|
|
||||||
import PostersGrid from '$components/organisms/PostersGrid.svelte'
|
import PostersGrid from '$components/organisms/PostersGrid.svelte'
|
||||||
|
import ShopHeader from '$components/organisms/ShopHeader.svelte'
|
||||||
import PosterLayout from '$components/layouts/PosterLayout.svelte'
|
import PosterLayout from '$components/layouts/PosterLayout.svelte'
|
||||||
|
|
||||||
export let product: any
|
export let product: any
|
||||||
export let shopProduct: any
|
export let shopProduct: any
|
||||||
|
|
||||||
const { shop, shopLocations, posters } = getContext('shop')
|
const { posters } = getContext('shop')
|
||||||
|
|
||||||
let introEl: HTMLElement
|
|
||||||
var navObserver: IntersectionObserver
|
|
||||||
var scrolledPastIntro = false
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Animations
|
|
||||||
*/
|
|
||||||
// Setup animations
|
|
||||||
const timeline: AnimeTimelineInstance = 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)
|
|
||||||
|
|
||||||
// Transition in
|
|
||||||
requestAnimationFrame(timeline.play)
|
|
||||||
|
|
||||||
|
|
||||||
// Destroy
|
|
||||||
return () => {
|
|
||||||
navObserver && navObserver.unobserve(introEl)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Metas
|
<Metas
|
||||||
@@ -86,57 +21,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<PageTransition name="shop-page">
|
<PageTransition name="shop-page">
|
||||||
<section class="shop-page__intro" bind:this={introEl}>
|
<ShopHeader {product} />
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1>Shop</h1>
|
|
||||||
|
|
||||||
<nav class="shop-page__nav">
|
|
||||||
<div class="container">
|
|
||||||
<p class="text-label">Choose a 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>
|
|
||||||
|
|
||||||
<PosterLayout
|
<PosterLayout
|
||||||
product={product}
|
product={product}
|
||||||
@@ -145,38 +30,3 @@
|
|||||||
|
|
||||||
<PostersGrid {posters} />
|
<PostersGrid {posters} />
|
||||||
</PageTransition>
|
</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>
|
|
||||||
60
src/routes/shop/index.ts
Normal file
60
src/routes/shop/index.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import type { RequestEvent, RequestHandlerOutput } from '@sveltejs/kit'
|
||||||
|
import { fetchAPI } from '$utils/api'
|
||||||
|
import { getRandomElement } from '$utils/functions'
|
||||||
|
import { getProduct } from '$utils/functions/swell'
|
||||||
|
|
||||||
|
export async function get({}: RequestEvent): Promise<RequestHandlerOutput> {
|
||||||
|
try {
|
||||||
|
// Get content from API
|
||||||
|
const data = await fetchAPI(`
|
||||||
|
query {
|
||||||
|
posters: product (
|
||||||
|
filter: { status: { _eq: "published" }}
|
||||||
|
) {
|
||||||
|
name
|
||||||
|
type
|
||||||
|
description
|
||||||
|
details
|
||||||
|
location {
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
product_id
|
||||||
|
photos_product {
|
||||||
|
directus_files_id {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
photos_preview {
|
||||||
|
directus_files_id {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
const randomPoster = getRandomElement(data.data.posters)
|
||||||
|
|
||||||
|
// Fetch Swell API for product
|
||||||
|
const shopProduct = await getProduct(randomPoster.product_id)
|
||||||
|
|
||||||
|
if (shopProduct) {
|
||||||
|
return {
|
||||||
|
body: {
|
||||||
|
product: randomPoster,
|
||||||
|
shopProduct,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
status: 404,
|
||||||
|
body: error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user