Use layout groups
This commit is contained in:
43
src/routes/(shop)/shop/+error.svelte
Normal file
43
src/routes/(shop)/shop/+error.svelte
Normal file
@@ -0,0 +1,43 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import { page } from '$app/stores'
|
||||
// Components
|
||||
import Metas from '$components/Metas.svelte'
|
||||
import PageTransition from '$components/PageTransition.svelte'
|
||||
import ShopHeader from '$components/organisms/ShopBanner.svelte'
|
||||
import PostersGrid from '$components/organisms/PostersGrid.svelte'
|
||||
|
||||
const { posters }: any = getContext('shop')
|
||||
const errors = {
|
||||
404: {
|
||||
title: 'Product not found',
|
||||
message: 'The product you are looking for does not exist… yet!',
|
||||
},
|
||||
500: {
|
||||
title: 'Server error',
|
||||
message: "That is embarassing, the problem is on our side.",
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<Metas
|
||||
title="{errors[$page.status].title} – Houses Of"
|
||||
/>
|
||||
|
||||
|
||||
<PageTransition>
|
||||
<main class="shop-page">
|
||||
<ShopHeader />
|
||||
|
||||
<section class="shop-page__error">
|
||||
<div class="container grid">
|
||||
<div class="inner">
|
||||
<h2 class="title-big">Uh oh!</h2>
|
||||
<p class="text-medium">{errors[$page.status].message}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<PostersGrid {posters} />
|
||||
</main>
|
||||
</PageTransition>
|
||||
78
src/routes/(shop)/shop/+layout.server.ts
Normal file
78
src/routes/(shop)/shop/+layout.server.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { error } from '@sveltejs/kit'
|
||||
import type { LayoutServerLoad } from './$types'
|
||||
import { fetchAPI } from '$utils/api'
|
||||
import { fetchSwell } from '$utils/functions/shopServer'
|
||||
|
||||
export const load: LayoutServerLoad = async () => {
|
||||
try {
|
||||
// Get content from API
|
||||
const res = await fetchAPI(`query {
|
||||
shop {
|
||||
page_heroimage { id }
|
||||
}
|
||||
|
||||
location (
|
||||
filter: {
|
||||
has_poster: { _eq: true },
|
||||
status: { _eq: "published" },
|
||||
},
|
||||
sort: "name"
|
||||
) {
|
||||
name
|
||||
slug
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
settings {
|
||||
seo_image_shop { id }
|
||||
}
|
||||
}`)
|
||||
|
||||
const { data: { shop, location, posters, settings }} = res
|
||||
|
||||
|
||||
/**
|
||||
* Get products data from Swell
|
||||
*/
|
||||
const shopProducts: any = await fetchSwell('/products', {
|
||||
category: 'posters',
|
||||
})
|
||||
|
||||
if (shopProducts) {
|
||||
return {
|
||||
shop,
|
||||
locations: location,
|
||||
posters,
|
||||
shopProducts: shopProducts.results,
|
||||
settings,
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
throw error(500, err.message)
|
||||
}
|
||||
}
|
||||
50
src/routes/(shop)/shop/+layout.svelte
Normal file
50
src/routes/(shop)/shop/+layout.svelte
Normal file
@@ -0,0 +1,50 @@
|
||||
<style lang="scss">
|
||||
@import "../../../style/pages/shop";
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types'
|
||||
import { setContext } from 'svelte'
|
||||
import { cartNotifications } from '$utils/stores/shop'
|
||||
// Components
|
||||
import Cart from '$components/organisms/Cart.svelte'
|
||||
import NotificationCart from '$components/molecules/NotificationCart.svelte'
|
||||
|
||||
export let data: PageData
|
||||
|
||||
const { shop, locations, posters, shopProducts, settings } = data
|
||||
|
||||
let scrollY: number
|
||||
|
||||
// Locations with an existing poster product
|
||||
const shopLocations = locations.filter(({ slug }: any) => {
|
||||
if (posters.find((poster: any) => poster.location.slug === slug)) {
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
setContext('shop', {
|
||||
shop,
|
||||
posters,
|
||||
shopLocations,
|
||||
shopProducts,
|
||||
settings,
|
||||
})
|
||||
</script>
|
||||
|
||||
<svelte:window bind:scrollY />
|
||||
|
||||
|
||||
<Cart />
|
||||
|
||||
<div class="notifications" class:is-top={scrollY <= 100}>
|
||||
{#each $cartNotifications as { id, title, name, image } (id)}
|
||||
<NotificationCart
|
||||
title={title}
|
||||
name={name}
|
||||
image={image}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<slot />
|
||||
56
src/routes/(shop)/shop/+page.server.ts
Normal file
56
src/routes/(shop)/shop/+page.server.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { error } from '@sveltejs/kit'
|
||||
import type { PageServerLoad } from './$types'
|
||||
import { fetchAPI } from '$utils/api'
|
||||
import { getRandomItem } from '$utils/functions'
|
||||
import { fetchSwell } from '$utils/functions/shopServer'
|
||||
|
||||
export const load: PageServerLoad = async ({ setHeaders }) => {
|
||||
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: any = getRandomItem(data.data.posters)
|
||||
|
||||
// Fetch Swell API for product
|
||||
const shopProduct: any = await fetchSwell(`/products/${randomPoster.product_id}`)
|
||||
|
||||
if (shopProduct) {
|
||||
setHeaders({ 'Cache-Control': 'public, max-age=1, stale-while-revalidate=86399' })
|
||||
|
||||
return {
|
||||
product: randomPoster,
|
||||
shopProduct,
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
throw error(500, err.message)
|
||||
}
|
||||
}
|
||||
40
src/routes/(shop)/shop/+page.svelte
Normal file
40
src/routes/(shop)/shop/+page.svelte
Normal file
@@ -0,0 +1,40 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types'
|
||||
import { getContext } from 'svelte'
|
||||
import { getAssetUrlKey } from '$utils/api'
|
||||
import { shopCurrentProductSlug } from '$utils/stores/shop'
|
||||
// Components
|
||||
import PageTransition from '$components/PageTransition.svelte'
|
||||
import Metas from '$components/Metas.svelte'
|
||||
import PostersGrid from '$components/organisms/PostersGrid.svelte'
|
||||
import ShopHeader from '$components/organisms/ShopBanner.svelte'
|
||||
import PosterLayout from '$components/layouts/PosterLayout.svelte'
|
||||
|
||||
export let data: PageData
|
||||
|
||||
const { product, shopProduct }: { product: any, shopProduct: any } = data
|
||||
const { posters, settings }: any = getContext('shop')
|
||||
|
||||
// Update current random product slug
|
||||
$shopCurrentProductSlug = product.location.slug
|
||||
</script>
|
||||
|
||||
<Metas
|
||||
title="Shop – Houses Of"
|
||||
description="Welcome to the Houses Of Shop, discover our original series of graphic posters made for lovers of design, travel and photography"
|
||||
image={getAssetUrlKey(settings.seo_image_shop.id, 'share-image')}
|
||||
/>
|
||||
|
||||
|
||||
<PageTransition>
|
||||
<main class="shop-page">
|
||||
<ShopHeader {product} />
|
||||
|
||||
<PosterLayout
|
||||
product={product}
|
||||
shopProduct={shopProduct}
|
||||
/>
|
||||
|
||||
<PostersGrid {posters} />
|
||||
</main>
|
||||
</PageTransition>
|
||||
53
src/routes/(shop)/shop/[type]-[name]/+page.server.ts
Normal file
53
src/routes/(shop)/shop/[type]-[name]/+page.server.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { error } from '@sveltejs/kit'
|
||||
import type { PageServerLoad } from './$types'
|
||||
import { fetchAPI } from '$utils/api'
|
||||
import { fetchSwell } from '$utils/functions/shopServer'
|
||||
|
||||
export const load: PageServerLoad = async ({ params, setHeaders }) => {
|
||||
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: any = await fetchSwell(`/products/${poster.product_id}`)
|
||||
|
||||
if (shopProduct) {
|
||||
setHeaders({ 'Cache-Control': 'public, max-age=1, stale-while-revalidate=604799' })
|
||||
|
||||
return {
|
||||
product: poster,
|
||||
shopProduct,
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
throw error(404)
|
||||
}
|
||||
}
|
||||
39
src/routes/(shop)/shop/[type]-[name]/+page.svelte
Normal file
39
src/routes/(shop)/shop/[type]-[name]/+page.svelte
Normal file
@@ -0,0 +1,39 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types'
|
||||
import { getContext } from 'svelte'
|
||||
import { getAssetUrlKey } from '$utils/api'
|
||||
import { shopCurrentProductSlug } from '$utils/stores/shop'
|
||||
import { capitalizeFirstLetter } from '$utils/functions'
|
||||
// Components
|
||||
import PageTransition from '$components/PageTransition.svelte'
|
||||
import Metas from '$components/Metas.svelte'
|
||||
import ShopHeader from '$components/organisms/ShopBanner.svelte'
|
||||
import PostersGrid from '$components/organisms/PostersGrid.svelte'
|
||||
import PosterLayout from '$components/layouts/PosterLayout.svelte'
|
||||
|
||||
export let data: PageData
|
||||
|
||||
const { posters }: any = getContext('shop')
|
||||
|
||||
$shopCurrentProductSlug = data.product.location.slug
|
||||
</script>
|
||||
|
||||
<Metas
|
||||
title="{data.product.location.name} {capitalizeFirstLetter(data.product.type)} – Houses Of"
|
||||
description={data.product.description}
|
||||
image={getAssetUrlKey(data.product.photos_product[2].directus_files_id.id, 'share-image')}
|
||||
/>
|
||||
|
||||
|
||||
<PageTransition>
|
||||
<main class="shop-page">
|
||||
<ShopHeader product={data.product} />
|
||||
|
||||
<PosterLayout
|
||||
product={data.product}
|
||||
shopProduct={data.shopProduct}
|
||||
/>
|
||||
|
||||
<PostersGrid {posters} />
|
||||
</main>
|
||||
</PageTransition>
|
||||
Reference in New Issue
Block a user