Files
housesof/apps/website/src/routes/+layout.svelte

143 lines
3.9 KiB
Svelte

<style lang="scss">
// Toast
:global(.toast--global) {
position: fixed;
z-index: 20;
max-width: 420px;
bottom: var(--offset-sides);
right: var(--offset-sides);
left: calc(var(--offset-sides) + 44px + 24px);
@include bp (mob-lg) {
left: auto;
}
}
</style>
<script lang="ts">
import 'sanitize.css'
import '../style/global.scss'
import { PUBLIC_ANALYTICS_DOMAIN } from '$env/static/public'
import { browser } from '$app/environment'
import { page } from '$app/stores'
import { beforeNavigate, afterNavigate } from '$app/navigation'
import { setContext } from 'svelte'
import { fade } from 'svelte/transition'
import { DELAY, DURATION } from '$utils/constants'
import { pageLoading, previousPage } from '$utils/stores'
import { scrollToTop } from 'utils/scroll'
import '$utils/polyfills'
// Components
import SVGSprite from '$components/SVGSprite.svelte'
import SmoothScroll from '$components/SmoothScroll.svelte'
import Analytics from '$components/Analytics.svelte'
import Switcher from '$components/molecules/Switcher/Switcher.svelte'
import Toast from '$components/molecules/Toast/Toast.svelte'
import Footer from '$components/organisms/Footer/Footer.svelte'
let { data, children } = $props()
let innerHeight = $state<number>()
// Fonts to preload
const fonts = [
'G-Light',
'G-Regular',
'G-Medium',
'G-Semibold',
'J-Extralight',
'J-Light',
]
// Set global data
setContext('global', data)
/**
* On page change
*/
beforeNavigate(({ from, to }) => {
// Store previous page (for photo Viewer close button)
$previousPage = from.url.pathname
// Enable page loading state if URL changed
if (from?.route.id !== to?.route.id) {
$pageLoading = true
}
})
afterNavigate(({ from }) => {
// Remove page loading state
setTimeout(() => $pageLoading = false, DELAY.PAGE_LOADING)
// Scroll back to top when new page is ready (excepted certain pages)
if (from?.url?.pathname && (!$page.url.searchParams.get('country') && !$page.url.pathname.includes('/shop/'))) {
setTimeout(scrollToTop, DELAY.PAGE_IN)
}
})
$effect(() => {
// Set viewport height
innerHeight && document.body.style.setProperty('--vh', `${innerHeight}px`)
// Avoid FOUC
document.body.style.opacity = '1'
// Define page loading
document.body.classList.toggle('is-loading', $pageLoading)
// Block scroll on certain conditions
// document.body.classList.toggle('block-scroll', condition)
})
</script>
<svelte:window bind:innerHeight />
<svelte:head>
<link rel="canonical" href={$page.url.href.split('#')[0]} />
{#each fonts as font}
<link rel="preload" href="/fonts/{font}.woff2" as="font" type="font/woff2" crossorigin="anonymous">
{/each}
</svelte:head>
<Switcher />
{#key data.currentPath}
<div
in:fade={{ duration: DURATION.PAGE_IN, delay: DELAY.PAGE_LOADING }}
out:fade={{ duration: DURATION.PAGE_OUT }}
>
{@render children()}
{#if !$page.params.photo}
<Footer />
{/if}
</div>
{/key}
{#if !['/[photo]'].some(sub => $page.route.id.includes(sub))}
<Toast
type="global"
id="posters-promo"
text="Upgrade your walls! Our graphic posters are <strong>10% off</strong> in cart with free shipping."
cta={{
label: 'View posters',
url: '/shop',
color: 'pink',
}}
images={data.shop.module_images.map(({ directus_files_id: { id, title } }) => ({ id, title }))}
class="toast-home"
/>
{/if}
<SVGSprite />
<SmoothScroll />
{#if browser}
<Analytics domain={PUBLIC_ANALYTICS_DOMAIN} />
{/if}