refactor: migrate to Svelte 5
use runes ($props, $state, $derived, $effect, etc)
This commit is contained in:
@@ -9,11 +9,14 @@
|
||||
import Cart from '$components/organisms/Cart/Cart.svelte'
|
||||
import NotificationCart from '$components/molecules/NotificationCart/NotificationCart.svelte'
|
||||
|
||||
export let data
|
||||
let {
|
||||
data,
|
||||
children,
|
||||
} = $props()
|
||||
|
||||
const { shop, locations, posters, shopProducts, settings } = data
|
||||
|
||||
let scrollY: number
|
||||
let scrollY = $state<number>()
|
||||
|
||||
// Locations with an existing poster product
|
||||
const shopLocations = locations.filter(({ slug }: any) => {
|
||||
@@ -38,12 +41,8 @@
|
||||
|
||||
<div class="notifications" class:is-top={scrollY <= 100}>
|
||||
{#each $cartNotifications as { id, title, name, image } (id)}
|
||||
<NotificationCart
|
||||
title={title}
|
||||
name={name}
|
||||
image={image}
|
||||
/>
|
||||
<NotificationCart {title} {name} {image} />
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<slot />
|
||||
{@render children()}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import ShopHeader from '$components/organisms/ShopBanner/ShopBanner.svelte'
|
||||
import PosterLayout from '$components/layouts/PosterLayout/PosterLayout.svelte'
|
||||
|
||||
export let data
|
||||
let { data } = $props()
|
||||
|
||||
const { product, shopProduct }: { product: any, shopProduct: any } = data
|
||||
const { posters, settings }: any = getContext('shop')
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import PostersGrid from '$components/organisms/PostersGrid/PostersGrid.svelte'
|
||||
import PosterLayout from '$components/layouts/PosterLayout/PosterLayout.svelte'
|
||||
|
||||
export let data
|
||||
let { data } = $props()
|
||||
|
||||
const { posters }: any = getContext('shop')
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { page, navigating } from '$app/stores'
|
||||
import { onMount } from 'svelte'
|
||||
import { stagger, timeline } from 'motion'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
@@ -24,34 +23,33 @@
|
||||
import NewsletterModule from '$components/organisms/NewsletterModule/NewsletterModule.svelte'
|
||||
import ShopModule from '$components/organisms/ShopModule/ShopModule.svelte'
|
||||
|
||||
export let data
|
||||
let { data } = $props()
|
||||
|
||||
let photos = $state<any[]>(data.photos)
|
||||
let totalPhotos = $state(data.totalPhotos)
|
||||
|
||||
let { photos, totalPhotos }: { photos: any[], totalPhotos: number } = data
|
||||
$: ({ photos, totalPhotos } = data)
|
||||
const { location, product = undefined }: { location: any, totalPhotos: number, product: any } = data
|
||||
const { params } = $page
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
let introEl: HTMLElement
|
||||
let photosListEl: HTMLElement
|
||||
let scrollY: number
|
||||
let introEl = $state<HTMLElement>()
|
||||
let photosListEl = $state<HTMLElement>()
|
||||
let scrollY = $state<number>()
|
||||
let observerPhotos: IntersectionObserver
|
||||
let mutationPhotos: MutationObserver
|
||||
let currentPage = 1
|
||||
let ended: boolean
|
||||
let currentPhotosAmount: number
|
||||
let heroOffsetY = 0
|
||||
let currentPage = $state(1)
|
||||
let currentPhotosAmount = $derived(photos.length)
|
||||
let heroOffsetY = $state(0)
|
||||
|
||||
$: latestPhoto = photos[0]
|
||||
$: currentPhotosAmount = photos.length
|
||||
$: ended = currentPhotosAmount === totalPhotos
|
||||
const ended = $derived(currentPhotosAmount === totalPhotos)
|
||||
const latestPhoto = $derived(photos[0])
|
||||
|
||||
|
||||
/**
|
||||
* Load photos
|
||||
*/
|
||||
// Load more photos from CTA
|
||||
/** Load more photos from CTA */
|
||||
const loadMorePhotos = async () => {
|
||||
// Append more photos from API
|
||||
const newPhotos: any = await loadPhotos(currentPage + 1)
|
||||
@@ -64,9 +62,6 @@
|
||||
// Increment the current page
|
||||
currentPage++
|
||||
}
|
||||
|
||||
// Increment the currently visible amount of photos
|
||||
currentPhotosAmount += newPhotos.length
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,12 +97,14 @@
|
||||
/**
|
||||
* Add parallax on illustration when scrolling
|
||||
*/
|
||||
$: if (scrollY && scrollY < introEl.offsetHeight) {
|
||||
heroOffsetY = scrollY * 0.1
|
||||
}
|
||||
$effect(() => {
|
||||
if (scrollY && scrollY < introEl.offsetHeight) {
|
||||
heroOffsetY = scrollY * 0.1
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
onMount(() => {
|
||||
$effect(() => {
|
||||
// Define location's last seen state
|
||||
$seenLocations = JSON.stringify({
|
||||
// Add existing values
|
||||
@@ -264,9 +261,7 @@
|
||||
</Button>
|
||||
|
||||
{#if location.has_poster}
|
||||
<Button size="medium" url="/shop/poster-{location.slug}" text="Buy the poster" color="pinklight" class="shadow-small">
|
||||
<!-- <IconEarth /> -->
|
||||
</Button>
|
||||
<Button size="medium" url="/shop/poster-{location.slug}" text="Buy the poster" color="pinklight" class="shadow-small" />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@@ -309,7 +304,7 @@
|
||||
ended={ended}
|
||||
current={currentPhotosAmount}
|
||||
total={totalPhotos}
|
||||
on:click={() => !ended && loadMorePhotos()}
|
||||
onclick={() => !ended && loadMorePhotos()}
|
||||
>
|
||||
{#if !ended}
|
||||
<p class="more">See more photos</p>
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { browser } from '$app/environment'
|
||||
import { page, navigating } from '$app/stores'
|
||||
import { goto } from '$app/navigation'
|
||||
import { onMount, tick } from 'svelte'
|
||||
import { goto, replaceState } from '$app/navigation'
|
||||
import { tick } from 'svelte'
|
||||
import { fade, scale } from 'svelte/transition'
|
||||
import { quartOut } from 'svelte/easing'
|
||||
import dayjs from 'dayjs'
|
||||
@@ -24,70 +23,74 @@
|
||||
import IconArrow from '$components/atoms/IconArrow.svelte'
|
||||
import ButtonCircle from '$components/atoms/ButtonCircle/ButtonCircle.svelte'
|
||||
|
||||
export let data
|
||||
|
||||
let { photos, currentIndex }: { photos: any[], currentIndex: number } = data
|
||||
let { data } = $props()
|
||||
const { location, countPhotos, limit, offset }: { location: any, countPhotos: number, limit: number, offset: number } = data
|
||||
|
||||
enum directions { PREV, NEXT }
|
||||
|
||||
let innerWidth: number
|
||||
let fullscreenEl: HTMLElement
|
||||
let globalOffset = offset
|
||||
let isLoading = false
|
||||
let isFullscreen = false
|
||||
let hasNext = offset + limit < countPhotos
|
||||
let hasPrev = offset > 0
|
||||
let innerWidth = $state<number>()
|
||||
let fullscreenEl = $state<HTMLElement>()
|
||||
let photos = $state<any[]>(data.photos)
|
||||
let currentIndex = $state(data.currentIndex)
|
||||
let globalOffset = $state(offset)
|
||||
let isLoading = $state(false)
|
||||
let isFullscreen = $state(false)
|
||||
let hasNext = $state(offset + limit < countPhotos)
|
||||
let hasPrev = $state(offset > 0)
|
||||
|
||||
// Define if we can navigate depending on loading state, existing photos and index being first or last
|
||||
$: canGoPrev = !isLoading && (hasNext || currentIndex !== photos.length - 1)
|
||||
$: canGoNext = !isLoading && (hasPrev || currentIndex !== 0)
|
||||
const canGoPrev = $derived(!isLoading && (hasNext || currentIndex !== photos.length - 1))
|
||||
const canGoNext = $derived(!isLoading && (hasPrev || currentIndex !== 0))
|
||||
|
||||
// Define current photo
|
||||
$: currentPhoto = photos[currentIndex]
|
||||
$: currentPhotoIndex = globalOffset + currentIndex + 1
|
||||
const currentPhoto = $derived(photos[currentIndex])
|
||||
const currentPhotoIndex = $derived(globalOffset + currentIndex + 1)
|
||||
|
||||
// Take 7 photos in the global photos array (5 for current, 1 before first and 1 after last)
|
||||
// Start one index before the current image since the first one will be invisible
|
||||
$: sliceStart = Math.max(currentIndex - 1, 0)
|
||||
$: visiblePhotos = photos.slice(sliceStart, sliceStart + 7)
|
||||
const sliceStart = $derived(Math.max(currentIndex - 1, 0))
|
||||
const visiblePhotos = $derived(photos.slice(sliceStart, sliceStart + 7))
|
||||
|
||||
// Load previous photos
|
||||
$: if (browser && currentIndex === 0 && hasPrev) {
|
||||
loadPhotos(photos[0].id)
|
||||
}
|
||||
// Load next photos
|
||||
$: if (browser && currentIndex === photos.length - 5 && hasNext) {
|
||||
loadPhotos(photos[photos.length - 1].id, directions.NEXT)
|
||||
}
|
||||
$effect(() => {
|
||||
// Load previous photos
|
||||
if (currentIndex === 0 && hasPrev) {
|
||||
loadPhotos(photos[0].id)
|
||||
}
|
||||
|
||||
// Change URL to current photo slug
|
||||
$: if (browser && currentPhoto) {
|
||||
window.history.replaceState(null, '', $page.url.pathname.replace($page.params.photo, currentPhoto.slug))
|
||||
}
|
||||
// Load next photos
|
||||
if (currentIndex === photos.length - 5 && hasNext) {
|
||||
loadPhotos(photos[photos.length - 1].id, directions.NEXT)
|
||||
}
|
||||
|
||||
// Change URL to current photo slug
|
||||
if (currentPhoto) {
|
||||
replaceState('', $page.url.pathname.replace($page.params.photo, currentPhoto.slug))
|
||||
}
|
||||
})
|
||||
|
||||
// Define previous URL
|
||||
$: previousUrl = $previousPage ? $previousPage : `/${location.country.slug}/${location.slug}`
|
||||
const previousUrl = $derived($previousPage ? $previousPage : `/${location.country.slug}/${location.slug}`)
|
||||
|
||||
|
||||
/**
|
||||
* Photo navigation
|
||||
*/
|
||||
// Go to next photo
|
||||
/** Go to next photo */
|
||||
const goToNext = throttle(() => {
|
||||
canGoPrev && currentIndex++
|
||||
}, 200)
|
||||
|
||||
// Go to previous photo
|
||||
/** Go to previous photo */
|
||||
const goToPrevious = throttle(() => {
|
||||
canGoNext && (currentIndex = Math.max(currentIndex - 1, 0))
|
||||
}, 200)
|
||||
|
||||
// Close viewer and go to previous page
|
||||
/** Close viewer and go to previous page */
|
||||
const closeViewer = () => {
|
||||
goto(previousUrl, { replaceState: false, noScroll: true, keepFocus: true })
|
||||
}
|
||||
|
||||
// Enable navigation with keyboard
|
||||
/** Enable navigation with keyboard */
|
||||
const handleKeydown = ({ key, defaultPrevented }: KeyboardEvent) => {
|
||||
if (defaultPrevented) return
|
||||
switch (key) {
|
||||
@@ -98,7 +101,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Enable swipe gestures
|
||||
/** Enable swipe gestures */
|
||||
const handleSwipe = ({ detail }: CustomEvent<string>) => {
|
||||
// Swipe up and down on mobile/small screens
|
||||
if (innerWidth < 992) {
|
||||
@@ -214,7 +217,7 @@
|
||||
}
|
||||
|
||||
|
||||
onMount(() => {
|
||||
$effect(() => {
|
||||
/**
|
||||
* Animations
|
||||
*/
|
||||
@@ -289,14 +292,14 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<svelte:window bind:innerWidth on:keydown={handleKeydown} />
|
||||
<svelte:window bind:innerWidth onkeydown={handleKeydown} />
|
||||
|
||||
{#if currentPhoto}
|
||||
<Metas
|
||||
title="{currentPhoto.title} - Houses Of {location.name}"
|
||||
description="Photo of a beautiful home from {location.name}, {location.country.name}"
|
||||
image={getAssetUrlKey(currentPhoto.image.id, 'share')}
|
||||
/>
|
||||
<Metas
|
||||
title="{currentPhoto.title} - Houses Of {location.name}"
|
||||
description="Photo of a beautiful home from {location.name}, {location.country.name}"
|
||||
image={getAssetUrlKey(currentPhoto.image.id, 'share')}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
|
||||
@@ -317,10 +320,11 @@
|
||||
</ButtonCircle>
|
||||
|
||||
<div class="photo-page__carousel">
|
||||
<div class="photo-page__images"
|
||||
<div
|
||||
use:swipe
|
||||
on:swipe={handleSwipe}
|
||||
on:tap={toggleFullscreen}
|
||||
class="photo-page__images"
|
||||
onswipe={handleSwipe}
|
||||
ontap={toggleFullscreen}
|
||||
>
|
||||
{#each visiblePhotos as { id, image, title }, index (id)}
|
||||
<div class="photo-page__picture is-{currentIndex === 0 ? index + 1 : index}">
|
||||
@@ -340,10 +344,10 @@
|
||||
{/each}
|
||||
|
||||
<div class="photo-page__controls">
|
||||
<ButtonCircle class="prev shadow-box-dark" label="Previous" disabled={!canGoNext} clone={true} on:click={goToPrevious}>
|
||||
<ButtonCircle class="prev shadow-box-dark" label="Previous" disabled={!canGoNext} clone={true} onclick={goToPrevious}>
|
||||
<IconArrow color="pink" flip={true} />
|
||||
</ButtonCircle>
|
||||
<ButtonCircle class="next shadow-box-dark" label="Next" disabled={!canGoPrev} clone={true} on:click={goToNext}>
|
||||
<ButtonCircle class="next shadow-box-dark" label="Next" disabled={!canGoPrev} clone={true} onclick={goToNext}>
|
||||
<IconArrow color="pink" />
|
||||
</ButtonCircle>
|
||||
</div>
|
||||
@@ -378,10 +382,13 @@
|
||||
</div>
|
||||
|
||||
{#if isFullscreen}
|
||||
<div class="photo-page__fullscreen" bind:this={fullscreenEl}
|
||||
on:click={toggleFullscreen} on:keydown
|
||||
<div
|
||||
bind:this={fullscreenEl}
|
||||
class="photo-page__fullscreen"
|
||||
onclick={toggleFullscreen}
|
||||
in:fade={{ easing: quartOut, duration: 1000 }}
|
||||
out:fade={{ easing: quartOut, duration: 1000, delay: 300 }}
|
||||
role="presentation"
|
||||
>
|
||||
<div class="inner" transition:scale={{ easing: quartOut, start: 1.1, duration: 1000 }}>
|
||||
<Image
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { navigating } from '$app/stores'
|
||||
import { onMount, afterUpdate } from 'svelte'
|
||||
import { quartOut as quartOutSvelte } from 'svelte/easing'
|
||||
import { fade, fly } from 'svelte/transition'
|
||||
import { animate, inView, stagger, timeline } from 'motion'
|
||||
@@ -22,23 +21,30 @@
|
||||
import ProcessStep from '$components/molecules/ProcessStep/ProcessStep.svelte'
|
||||
import Banner from '$components/organisms/Banner/Banner.svelte'
|
||||
|
||||
export let data
|
||||
const { about, photos } = data
|
||||
let { data } = $props()
|
||||
|
||||
let scrollY: number, innerWidth: number, innerHeight: number
|
||||
let photosGridEl: HTMLElement
|
||||
let photosGridOffset: number = photosGridEl && photosGridEl.offsetTop
|
||||
let currentStep = 0
|
||||
let emailCopied: string = null
|
||||
let scrollY = $state<number>()
|
||||
let innerWidth = $state<number>()
|
||||
let innerHeight = $state<number>()
|
||||
let photosGridEl = $state<HTMLElement>()
|
||||
let photosGridOffset = $state<number>()
|
||||
let currentStep = $state(0)
|
||||
let emailCopied = $state<string>()
|
||||
let emailCopiedTimeout: ReturnType<typeof setTimeout> | number
|
||||
|
||||
$: parallaxPhotos = photosGridEl && map(scrollY, photosGridOffset - innerHeight, photosGridOffset + innerHeight / 1.5, 0, innerHeight * 0.15, true)
|
||||
$: fadedPhotosIndexes = innerWidth > 768
|
||||
? [0, 2, 5, 7, 9, 12, 17, 20, 22, 26, 30, 32, 34]
|
||||
: [1, 4, 5, 7, 11, 14, 17, 20, 24, 27, 30, 33, 34, 36, 40, 43]
|
||||
const parallaxPhotos = $derived(photosGridEl && map(scrollY, photosGridOffset - innerHeight, photosGridOffset + innerHeight / 1.5, 0, innerHeight * 0.15, true))
|
||||
const fadedPhotosIndexes = $derived(
|
||||
innerWidth > 768
|
||||
? [0, 2, 5, 7, 9, 12, 17, 20, 22, 26, 30, 32, 34]
|
||||
: [1, 4, 5, 7, 11, 14, 17, 20, 24, 27, 30, 33, 34, 36, 40, 43]
|
||||
)
|
||||
|
||||
|
||||
$effect(() => {
|
||||
// Update photos grid top offset
|
||||
photosGridOffset = photosGridEl.offsetTop
|
||||
|
||||
|
||||
onMount(() => {
|
||||
/**
|
||||
* Animations
|
||||
*/
|
||||
@@ -163,20 +169,14 @@
|
||||
// Run animation
|
||||
requestAnimationFrame(animation.play)
|
||||
})
|
||||
|
||||
|
||||
afterUpdate(() => {
|
||||
// Update photos grid top offset
|
||||
photosGridOffset = photosGridEl.offsetTop
|
||||
})
|
||||
</script>
|
||||
|
||||
<svelte:window bind:scrollY bind:innerWidth bind:innerHeight />
|
||||
|
||||
<Metas
|
||||
title={about.seo_title}
|
||||
description={about.seo_description}
|
||||
image={about.seo_image ? getAssetUrlKey(about.seo_image.id, 'share-image') : null}
|
||||
title={data.data.about.seo_title}
|
||||
description={data.about.seo_description}
|
||||
image={data.about.seo_image ? getAssetUrlKey(data.about.seo_image.id, 'share-image') : null}
|
||||
/>
|
||||
|
||||
|
||||
@@ -191,13 +191,13 @@
|
||||
|
||||
<section class="about__introduction">
|
||||
<div class="container grid">
|
||||
<h2 class="title-small">{about.intro_title}</h2>
|
||||
<h2 class="title-small">{data.about.intro_title}</h2>
|
||||
<div class="heading text-big">
|
||||
{@html about.intro_heading}
|
||||
{@html data.about.intro_heading}
|
||||
</div>
|
||||
|
||||
<div class="text text-small">
|
||||
{@html about.intro_text}
|
||||
{@html data.about.intro_text}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -207,8 +207,8 @@
|
||||
<figure class="first-photo">
|
||||
<Image
|
||||
class="picture shadow-box-dark"
|
||||
id={about.intro_firstphoto.id}
|
||||
alt={about.intro_firstphoto.title}
|
||||
id={data.about.intro_firstphoto.id}
|
||||
alt={data.about.intro_firstphoto.title}
|
||||
sizeKey="photo-list"
|
||||
sizes={{
|
||||
small: { width: 400 },
|
||||
@@ -218,29 +218,29 @@
|
||||
ratio={1.5}
|
||||
/>
|
||||
<figcaption class="text-info">
|
||||
{about.intro_firstphoto_caption}<br>
|
||||
{data.about.intro_firstphoto_caption}<br>
|
||||
in
|
||||
<a href="/{about.intro_firstlocation.country.slug}/{about.intro_firstlocation.slug}" data-sveltekit-noscroll>
|
||||
<img src={getAssetUrlKey(about.intro_firstlocation.country.flag.id, 'square-small')} width="32" height="32" alt={about.intro_firstlocation.country.flag.title}>
|
||||
<a href="/{data.about.intro_firstlocation.country.slug}/{data.about.intro_firstlocation.slug}" data-sveltekit-noscroll>
|
||||
<img src={getAssetUrlKey(data.about.intro_firstlocation.country.flag.id, 'square-small')} width="32" height="32" alt={data.about.intro_firstlocation.country.flag.title}>
|
||||
<span>Naarm Australia (Melbourne)</span>
|
||||
</a>
|
||||
</figcaption>
|
||||
</figure>
|
||||
|
||||
<h2 class="title-small" data-reveal>{about.creation_title}</h2>
|
||||
<h2 class="title-small" data-reveal>{data.about.creation_title}</h2>
|
||||
<div class="heading text-huge" data-reveal>
|
||||
{@html about.creation_heading}
|
||||
{@html data.about.creation_heading}
|
||||
</div>
|
||||
|
||||
<div class="text text-small" data-reveal>
|
||||
{@html about.creation_text}
|
||||
{@html data.about.creation_text}
|
||||
</div>
|
||||
|
||||
<figure class="picture portrait-photo" data-reveal-image>
|
||||
<Image
|
||||
class="shadow-box-dark"
|
||||
id={about.creation_portrait.id}
|
||||
alt={about.creation_portrait.title}
|
||||
id={data.about.creation_portrait.id}
|
||||
alt={data.about.creation_portrait.title}
|
||||
sizeKey="photo-list"
|
||||
sizes={{
|
||||
small: { width: 400 },
|
||||
@@ -250,7 +250,7 @@
|
||||
/>
|
||||
</figure>
|
||||
<span class="portrait-photo__caption text-info">
|
||||
{about.creation_portrait_caption}
|
||||
{data.about.creation_portrait_caption}
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
@@ -260,8 +260,8 @@
|
||||
<figure class="picture" data-reveal-image>
|
||||
<Image
|
||||
class="shadow-box-dark"
|
||||
id={about.present_image.id}
|
||||
alt={about.present_image.title}
|
||||
id={data.about.present_image.id}
|
||||
alt={data.about.present_image.title}
|
||||
sizeKey="photo-list"
|
||||
sizes={{
|
||||
small: { width: 400 },
|
||||
@@ -272,26 +272,26 @@
|
||||
/>
|
||||
</figure>
|
||||
|
||||
<h2 class="title-small" data-reveal>{about.present_title}</h2>
|
||||
<h2 class="title-small" data-reveal>{data.about.present_title}</h2>
|
||||
<div class="text text-small" data-reveal>
|
||||
<p>{about.present_text}</p>
|
||||
<p>{data.about.present_text}</p>
|
||||
</div>
|
||||
|
||||
<div class="heading text-big" data-reveal>
|
||||
{@html about.present_heading}
|
||||
{@html data.about.present_heading}
|
||||
</div>
|
||||
|
||||
<div class="conclusion text-small" data-reveal>
|
||||
<p>{about.present_conclusion}</p>
|
||||
<p>{data.about.present_conclusion}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{#if about.image_showcase}
|
||||
{#if data.about.image_showcase}
|
||||
<div class="about__showcase container grid">
|
||||
<Image
|
||||
id={about.image_showcase.id}
|
||||
alt={about.image_showcase.title}
|
||||
id={data.about.image_showcase.id}
|
||||
alt={data.about.image_showcase.title}
|
||||
sizeKey="showcase"
|
||||
sizes={{
|
||||
small: { width: 400 },
|
||||
@@ -307,15 +307,18 @@
|
||||
<div class="container grid">
|
||||
<aside>
|
||||
<div class="heading">
|
||||
<h2 class="title-medium">{about.process_title}</h2>
|
||||
<p class="text-xsmall">{about.process_subtitle}</p>
|
||||
<h2 class="title-medium">{data.about.process_title}</h2>
|
||||
<p class="text-xsmall">{data.about.process_subtitle}</p>
|
||||
</div>
|
||||
|
||||
<ol>
|
||||
{#each about.process_steps as { title }, index}
|
||||
{#each data.about.process_steps as { title }, index}
|
||||
<li class:is-active={index === currentStep}>
|
||||
<a href="#step-{index + 1}" class="title-big"
|
||||
on:click|preventDefault={() => {
|
||||
<a
|
||||
class="title-big"
|
||||
href="#step-{index + 1}"
|
||||
onclick={(event) => {
|
||||
event.preventDefault()
|
||||
currentStep = index
|
||||
sendEvent('aboutStepSwitch')
|
||||
}}
|
||||
@@ -328,7 +331,7 @@
|
||||
</aside>
|
||||
|
||||
<div class="steps">
|
||||
{#each about.process_steps as { text, image, video_mp4, video_webm }, index}
|
||||
{#each data.about.process_steps as { text, image, video_mp4, video_webm }, index}
|
||||
{#if index === currentStep}
|
||||
<ProcessStep
|
||||
{index} {text}
|
||||
@@ -347,8 +350,9 @@
|
||||
<section class="about__photos" bind:this={photosGridEl}>
|
||||
<div class="container-wide">
|
||||
<div class="photos-grid" style:--parallax-y="{parallaxPhotos}px">
|
||||
{#each photos as { image: { id }, title }, index}
|
||||
<AboutGridPhoto class="grid-photo"
|
||||
{#each data.photos as { image: { id }, title }, index}
|
||||
<AboutGridPhoto
|
||||
class="grid-photo"
|
||||
{id}
|
||||
alt={title}
|
||||
disabled={fadedPhotosIndexes.includes(index)}
|
||||
@@ -360,9 +364,9 @@
|
||||
|
||||
<section class="about__interest container grid">
|
||||
<div class="container grid">
|
||||
<h2 class="title-xl">{about.contact_title}</h2>
|
||||
<h2 class="title-xl">{data.about.contact_title}</h2>
|
||||
<div class="blocks">
|
||||
{#each about.contact_blocks as { title, text, link, button }}
|
||||
{#each data.about.contact_blocks as { title, text, link, button }}
|
||||
<div class="block">
|
||||
<h3 class="text-label">{title}</h3>
|
||||
<div class="text text-normal">
|
||||
@@ -370,25 +374,25 @@
|
||||
</div>
|
||||
<div class="button-container">
|
||||
{#if link}
|
||||
{#key emailCopied === link}
|
||||
<div class="wrap"
|
||||
in:fly={{ y: 4, duration: 325, easing: quartOutSvelte, delay: 250 }}
|
||||
out:fade={{ duration: 250, easing: quartOutSvelte }}
|
||||
use:mailtoClipboard
|
||||
on:copied={({ detail }) => {
|
||||
emailCopied = detail.email
|
||||
// Clear timeout and add timeout to hide message
|
||||
clearTimeout(emailCopiedTimeout)
|
||||
emailCopiedTimeout = setTimeout(() => emailCopied = null, 2500)
|
||||
}}
|
||||
>
|
||||
{#if emailCopied !== link}
|
||||
<Button size="small" url="mailto:{link}" text={button} />
|
||||
{:else}
|
||||
<span class="clipboard">Email copied in clipboard</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/key}
|
||||
{#key emailCopied === link}
|
||||
<div class="wrap"
|
||||
in:fly={{ y: 4, duration: 325, easing: quartOutSvelte, delay: 250 }}
|
||||
out:fade={{ duration: 250, easing: quartOutSvelte }}
|
||||
use:mailtoClipboard
|
||||
oncopied={(email: string) => {
|
||||
emailCopied = email
|
||||
// Clear timeout and add timeout to hide message
|
||||
clearTimeout(emailCopiedTimeout)
|
||||
emailCopiedTimeout = setTimeout(() => emailCopied = null, 2500)
|
||||
}}
|
||||
>
|
||||
{#if emailCopied !== link}
|
||||
<Button size="small" url="mailto:{link}" text={button} />
|
||||
{:else}
|
||||
<span class="clipboard">Email copied in clipboard</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/key}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { navigating } from '$app/stores'
|
||||
import { onMount } from 'svelte'
|
||||
import { stagger, timeline } from 'motion'
|
||||
import { DELAY } from '$utils/constants'
|
||||
import { quartOut } from 'svelte/easing'
|
||||
@@ -14,11 +13,11 @@
|
||||
import Heading from '$components/molecules/Heading/Heading.svelte'
|
||||
import InteractiveGlobe from '$components/organisms/InteractiveGlobe/InteractiveGlobe.svelte'
|
||||
|
||||
export let data
|
||||
let { data } = $props()
|
||||
const { credit } = data
|
||||
|
||||
|
||||
onMount(() => {
|
||||
$effect(() => {
|
||||
/**
|
||||
* Animations
|
||||
*/
|
||||
@@ -77,6 +76,31 @@
|
||||
<h2 class="title-small">{title}</h2>
|
||||
<ul>
|
||||
{#each credits as { name, role, website }}
|
||||
<li>
|
||||
<dl>
|
||||
<dt>
|
||||
{#if website}
|
||||
<h3>
|
||||
<a href={website} rel="noopener external" target="_blank" tabindex="0">{name}</a>
|
||||
</h3>
|
||||
{:else}
|
||||
<h3>{name}</h3>
|
||||
{/if}
|
||||
</dt>
|
||||
<dd>
|
||||
{role}
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<div class="credits__category grid">
|
||||
<h2 class="title-small">Photography</h2>
|
||||
<ul>
|
||||
{#each credit as { name, website, location }}
|
||||
<li>
|
||||
<dl>
|
||||
<dt>
|
||||
@@ -89,52 +113,27 @@
|
||||
{/if}
|
||||
</dt>
|
||||
<dd>
|
||||
{role}
|
||||
<ul data-sveltekit-noscroll>
|
||||
{#each location as loc}
|
||||
{#if loc.location_id}
|
||||
<li>
|
||||
<a href="/{loc.location_id.country.slug}/{loc.location_id.slug}" tabindex="0">
|
||||
<Image
|
||||
id={loc.location_id.country.flag.id}
|
||||
sizeKey="square-small"
|
||||
width={16}
|
||||
height={16}
|
||||
alt="Flag of {loc.location_id.country.slug}"
|
||||
/>
|
||||
<span>{loc.location_id.name}</span>
|
||||
</a>
|
||||
</li>
|
||||
{/if}
|
||||
{/each}
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<div class="credits__category grid">
|
||||
<h2 class="title-small">Photography</h2>
|
||||
<ul>
|
||||
{#each credit as { name, website, location }}
|
||||
<li>
|
||||
<dl>
|
||||
<dt>
|
||||
{#if website}
|
||||
<h3>
|
||||
<a href={website} rel="noopener external" target="_blank" tabindex="0">{name}</a>
|
||||
</h3>
|
||||
{:else}
|
||||
<h3>{name}</h3>
|
||||
{/if}
|
||||
</dt>
|
||||
<dd>
|
||||
<ul data-sveltekit-noscroll>
|
||||
{#each location as loc}
|
||||
{#if loc.location_id}
|
||||
<li>
|
||||
<a href="/{loc.location_id.country.slug}/{loc.location_id.slug}" tabindex="0">
|
||||
<Image
|
||||
id={loc.location_id.country.flag.id}
|
||||
sizeKey="square-small"
|
||||
width={16}
|
||||
height={16}
|
||||
alt="Flag of {loc.location_id.country.slug}"
|
||||
/>
|
||||
<span>{loc.location_id.name}</span>
|
||||
</a>
|
||||
</li>
|
||||
{/if}
|
||||
{/each}
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<script lang="ts">
|
||||
import { page, navigating } from '$app/stores'
|
||||
import { goto } from '$app/navigation'
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import { getContext } from 'svelte'
|
||||
import { fly } from 'svelte/transition'
|
||||
import { quartOut as quartOutSvelte } from 'svelte/easing'
|
||||
import dayjs from 'dayjs'
|
||||
@@ -13,7 +13,6 @@
|
||||
import { stagger, timeline } from 'motion'
|
||||
import { DELAY } from '$utils/constants'
|
||||
import { map, lerp } from 'utils/math'
|
||||
import { throttle } from 'utils/actions'
|
||||
import { getAssetUrlKey } from '$utils/api'
|
||||
import { quartOut } from '$animations/easings'
|
||||
import { PUBLIC_FILTERS_DEFAULT_COUNTRY, PUBLIC_FILTERS_DEFAULT_SORT, PUBLIC_GRID_INCREMENT } from '$env/static/public'
|
||||
@@ -30,64 +29,53 @@
|
||||
import ShopModule from '$components/organisms/ShopModule/ShopModule.svelte'
|
||||
import NewsletterModule from '$components/organisms/NewsletterModule/NewsletterModule.svelte'
|
||||
|
||||
export let data
|
||||
let { data } = $props()
|
||||
|
||||
let { photos, totalPhotos }: { photos: any[], totalPhotos: number } = data
|
||||
$: ({ photos, totalPhotos } = data)
|
||||
let photos = $state<any[]>(data.photos)
|
||||
const totalPhotos = $derived<number>(data.totalPhotos)
|
||||
const { filteredCountryExists, settings }: { filteredCountryExists: boolean, settings: any } = data
|
||||
const { countries, locations }: any = getContext('global')
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
let photosGridEl: HTMLElement
|
||||
let photosGridEl = $state<HTMLElement>()
|
||||
let observerPhotos: IntersectionObserver
|
||||
let mutationPhotos: MutationObserver
|
||||
let scrollY: number
|
||||
let innerWidth: number, innerHeight: number
|
||||
let scrollY = $state<number>()
|
||||
let innerWidth = $state<number>()
|
||||
let innerHeight = $state<number>()
|
||||
|
||||
|
||||
/**
|
||||
* Filters
|
||||
*/
|
||||
const defaultCountry: string = PUBLIC_FILTERS_DEFAULT_COUNTRY
|
||||
const defaultSort: string = PUBLIC_FILTERS_DEFAULT_SORT
|
||||
const defaultCountry = PUBLIC_FILTERS_DEFAULT_COUNTRY
|
||||
const defaultSort = PUBLIC_FILTERS_DEFAULT_SORT
|
||||
const urlFiltersParams = new URLSearchParams()
|
||||
let filtered: boolean
|
||||
let filterCountry = $page.url.searchParams.get('country') || defaultCountry
|
||||
let filterSort = $page.url.searchParams.get('sort') || defaultSort
|
||||
let countryFlagId: string
|
||||
$: filtered = filterCountry !== defaultCountry || filterSort !== defaultSort
|
||||
$: latestPhoto = photos && photos[0]
|
||||
$: currentCountry = countries.find((country: any) => country.slug === filterCountry)
|
||||
let filterCountry = $state($page.url.searchParams.get('country') || defaultCountry)
|
||||
let filterSort = $state($page.url.searchParams.get('sort') || defaultSort)
|
||||
const filtered = $derived(filterCountry !== defaultCountry || filterSort !== defaultSort)
|
||||
const latestPhoto = $derived(photos && photos[0])
|
||||
const currentCountry = $derived(countries.find((country: any) => country.slug === filterCountry))
|
||||
|
||||
// Pages related informations
|
||||
let currentPage = 1
|
||||
let ended: boolean
|
||||
let currentPhotosAmount: number
|
||||
$: currentPhotosAmount = photos && photos.length
|
||||
$: ended = currentPhotosAmount === totalPhotos
|
||||
let currentPage = $state(1)
|
||||
const currentPhotosAmount = $derived(photos?.length)
|
||||
const ended = $derived(currentPhotosAmount === totalPhotos)
|
||||
|
||||
|
||||
/**
|
||||
* Container margins
|
||||
*/
|
||||
let scrollProgress: number
|
||||
let sideMargins: number = innerWidth < 1200 ? 16 : 8
|
||||
$: viewportScroll = (innerHeight / innerWidth) <= 0.6 ? innerHeight * 1.5 : innerHeight
|
||||
|
||||
// Define sides margin on scroll
|
||||
const setSidesMargin = throttle(() => {
|
||||
if (window.innerWidth >= 992) {
|
||||
scrollProgress = map(scrollY, 0, viewportScroll, 0, 1, true)
|
||||
sideMargins = lerp(innerWidth < 1200 ? 16 : 8, 30, scrollProgress)
|
||||
}
|
||||
}, 50)
|
||||
const viewportScroll = $derived((innerHeight / innerWidth) <= 0.6 ? innerHeight * 1.5 : innerHeight)
|
||||
const scrollProgress = $derived(map(scrollY, 0, viewportScroll, 0, 1, true))
|
||||
const sideMargins = $derived(lerp(innerWidth < 1200 ? 16 : 8, 30, scrollProgress))
|
||||
|
||||
|
||||
/**
|
||||
* Handle URL query params
|
||||
*/
|
||||
$: countryFlagId = currentCountry ? currentCountry.flag.id : undefined
|
||||
const countryFlagId = $derived(currentCountry ? currentCountry.flag.id : undefined)
|
||||
|
||||
// Update URL filtering params from filter values
|
||||
const applyFilters = () => {
|
||||
@@ -103,7 +91,7 @@
|
||||
* Define small photo size from index
|
||||
* With different grid patterns depending on window width
|
||||
*/
|
||||
$: isSmall = (index: number) => {
|
||||
const isSmall = (index: number) => {
|
||||
let modulo = index % 5
|
||||
let notOn = [0]
|
||||
|
||||
@@ -122,21 +110,21 @@
|
||||
/**
|
||||
* Filters change events
|
||||
*/
|
||||
// Country select
|
||||
/** Country select */
|
||||
const handleCountryChange = ({ detail: value }) => {
|
||||
filterCountry = value === defaultCountry ? defaultCountry : value
|
||||
currentPage = 1
|
||||
applyFilters()
|
||||
}
|
||||
|
||||
// Sort select
|
||||
/** Sort select */
|
||||
const handleSortChange = ({ detail: value }) => {
|
||||
filterSort = value === defaultSort ? defaultSort : value
|
||||
currentPage = 1
|
||||
applyFilters()
|
||||
}
|
||||
|
||||
// Reset filters
|
||||
/** Reset filters */
|
||||
const resetFiltered = () => {
|
||||
filterCountry = defaultCountry
|
||||
filterSort = defaultSort
|
||||
@@ -148,7 +136,7 @@
|
||||
/**
|
||||
* Load photos
|
||||
*/
|
||||
// [function] Load photos helper
|
||||
/** Load photos helper */
|
||||
const loadPhotos = async (page: number) => {
|
||||
const res = await fetch('/api/data', {
|
||||
method: 'POST',
|
||||
@@ -194,7 +182,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Load more photos from CTA
|
||||
/** Load more photos from CTA */
|
||||
const loadMorePhotos = async () => {
|
||||
// Append more photos from API including options and page
|
||||
const newPhotos: any = await loadPhotos(currentPage + 1)
|
||||
@@ -207,14 +195,11 @@
|
||||
// Increment the current page
|
||||
currentPage++
|
||||
}
|
||||
|
||||
// Increment the currently visible amount of photos
|
||||
currentPhotosAmount += newPhotos.length
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onMount(() => {
|
||||
$effect(() => {
|
||||
/**
|
||||
* Observers
|
||||
*/
|
||||
@@ -290,15 +275,12 @@
|
||||
image={getAssetUrlKey(settings.seo_image_photos.id, 'share-image')}
|
||||
/>
|
||||
|
||||
<svelte:window
|
||||
bind:scrollY bind:innerWidth bind:innerHeight
|
||||
on:scroll={setSidesMargin}
|
||||
/>
|
||||
<svelte:window bind:scrollY bind:innerWidth bind:innerHeight />
|
||||
|
||||
|
||||
<main class="photos-page">
|
||||
<section class="photos-page__intro">
|
||||
<ScrollingTitle tag="h1" text="Houses">
|
||||
<ScrollingTitle tag="h1" label="Houses">
|
||||
<SplitText text="Houses" mode="chars" />
|
||||
</ScrollingTitle>
|
||||
|
||||
@@ -324,7 +306,7 @@
|
||||
selected: filterCountry === slug,
|
||||
}))
|
||||
]}
|
||||
on:change={handleCountryChange}
|
||||
onchange={handleCountryChange}
|
||||
value={filterCountry}
|
||||
>
|
||||
{#if countryFlagId}
|
||||
@@ -356,7 +338,7 @@
|
||||
selected: filterSort === 'oldest'
|
||||
},
|
||||
]}
|
||||
on:change={handleSortChange}
|
||||
onchange={handleSortChange}
|
||||
value={filterSort}
|
||||
>
|
||||
<svg class="icon" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" aria-label="Sort icon">
|
||||
@@ -368,8 +350,9 @@
|
||||
|
||||
<div class="filters__actions">
|
||||
{#if filtered}
|
||||
<button class="reset button-link"
|
||||
on:click={resetFiltered}
|
||||
<button
|
||||
class="reset button-link"
|
||||
onclick={resetFiltered}
|
||||
transition:fly={{ y: 4, duration: 600, easing: quartOutSvelte }}
|
||||
>
|
||||
Reset
|
||||
@@ -422,7 +405,7 @@
|
||||
size="large"
|
||||
color="beige"
|
||||
text={!ended ? 'See more photos' : "You've seen it all!"}
|
||||
on:click={loadMorePhotos}
|
||||
onclick={loadMorePhotos}
|
||||
disabled={ended}
|
||||
/>
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { navigating } from '$app/stores'
|
||||
import { onMount } from 'svelte'
|
||||
import { stagger, timeline } from 'motion'
|
||||
import { DELAY } from '$utils/constants'
|
||||
import { quartOut } from '$animations/easings'
|
||||
@@ -15,13 +14,12 @@
|
||||
import NewsletterIssue from '$components/molecules/NewsletterIssue/NewsletterIssue.svelte'
|
||||
import InteractiveGlobe from '$components/organisms/InteractiveGlobe/InteractiveGlobe.svelte'
|
||||
|
||||
export let data
|
||||
let { data } = $props()
|
||||
|
||||
const { issues } = data
|
||||
const latestIssue = issues[0]
|
||||
const latestIssue = $derived(data.issues[0])
|
||||
|
||||
|
||||
onMount(() => {
|
||||
$effect(() => {
|
||||
/**
|
||||
* Animations
|
||||
*/
|
||||
@@ -79,10 +77,10 @@
|
||||
<NewsletterIssue size="large" date={latestIssue.date_sent} {...latestIssue} />
|
||||
</div>
|
||||
|
||||
{#if issues.length > 1}
|
||||
{#if data.issues.length > 1}
|
||||
<h2 class="title-small">Past Issues</h2>
|
||||
<ul>
|
||||
{#each issues.slice(1) as { issue, title, date_sent: date, link, thumbnail }}
|
||||
{#each data.issues.slice(1) as { issue, title, date_sent: date, link, thumbnail }}
|
||||
<li class="issue-container">
|
||||
<NewsletterIssue {issue} {title} {link} {thumbnail} {date} />
|
||||
</li>
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
import Metas from '$components/Metas.svelte'
|
||||
import Heading from '$components/molecules/Heading/Heading.svelte'
|
||||
|
||||
export let data
|
||||
const { legal } = data
|
||||
let { data } = $props()
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
</script>
|
||||
@@ -26,7 +25,7 @@
|
||||
|
||||
<section class="terms__categories">
|
||||
<div class="container grid">
|
||||
{#each legal.terms as { title, text }, index}
|
||||
{#each data.legal.terms as { title, text }, index}
|
||||
<article class="terms__section grid">
|
||||
<h2 class="title-small">{index + 1}. {title}</h2>
|
||||
<div class="text text-info">
|
||||
@@ -37,7 +36,7 @@
|
||||
|
||||
<footer>
|
||||
<p class="text-info">
|
||||
Updated: <time datetime={dayjs(legal.date_updated).format('YYYY-MM-DD')}>{dayjs().to(dayjs(legal.date_updated))}</time>
|
||||
Updated: <time datetime={dayjs(data.legal.date_updated).format('YYYY-MM-DD')}>{dayjs().to(dayjs(data.legal.date_updated))}</time>
|
||||
</p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
import { page } from '$app/stores'
|
||||
import { beforeNavigate, afterNavigate } from '$app/navigation'
|
||||
import { PUBLIC_ANALYTICS_DOMAIN } from '$env/static/public'
|
||||
import { setContext, onMount } from 'svelte'
|
||||
import { setContext } from 'svelte'
|
||||
import { fade } from 'svelte/transition'
|
||||
import { DELAY, DURATION } from '$utils/constants'
|
||||
import { pageLoading, previousPage } from '$utils/stores'
|
||||
@@ -35,10 +35,9 @@
|
||||
import Toast from '$components/molecules/Toast/Toast.svelte'
|
||||
import Footer from '$components/organisms/Footer/Footer.svelte'
|
||||
|
||||
export let data
|
||||
let { data, children } = $props()
|
||||
|
||||
let innerHeight: number
|
||||
$: innerHeight && document.body.style.setProperty('--vh', `${innerHeight}px`)
|
||||
let innerHeight = $state<number>()
|
||||
|
||||
// Fonts to preload
|
||||
const fonts = [
|
||||
@@ -77,17 +76,18 @@
|
||||
}
|
||||
})
|
||||
|
||||
$: if (browser) {
|
||||
|
||||
$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)
|
||||
}
|
||||
|
||||
|
||||
onMount(() => {
|
||||
// Avoid FOUC
|
||||
document.body.style.opacity = '1'
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
in:fade={{ duration: DURATION.PAGE_IN, delay: DELAY.PAGE_LOADING }}
|
||||
out:fade={{ duration: DURATION.PAGE_OUT }}
|
||||
>
|
||||
<slot />
|
||||
{@render children()}
|
||||
|
||||
{#if !$page.params.photo}
|
||||
<Footer />
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { navigating } from '$app/stores'
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import { getContext } from 'svelte'
|
||||
import { timeline, stagger } from 'motion'
|
||||
import { DELAY } from '$utils/constants'
|
||||
import { smoothScroll } from '$utils/stores'
|
||||
@@ -26,15 +26,15 @@
|
||||
import ShopModule from '$components/organisms/ShopModule/ShopModule.svelte'
|
||||
import NewsletterModule from '$components/organisms/NewsletterModule/NewsletterModule.svelte'
|
||||
|
||||
export let data
|
||||
let { data } = $props()
|
||||
|
||||
const { photos } = data
|
||||
const { settings, locations }: any = getContext('global')
|
||||
|
||||
let scrollY: number, innerHeight: number
|
||||
let scrollY = $state<number>()
|
||||
let innerHeight = $state<number>()
|
||||
|
||||
|
||||
onMount(() => {
|
||||
$effect(() => {
|
||||
/**
|
||||
* Animations
|
||||
*/
|
||||
@@ -81,7 +81,8 @@
|
||||
|
||||
|
||||
<main class="homepage">
|
||||
<section class="homepage__intro"
|
||||
<section
|
||||
class="homepage__intro"
|
||||
use:reveal={{
|
||||
animation: { opacity: [0, 1] },
|
||||
options: {
|
||||
@@ -108,7 +109,7 @@
|
||||
size="medium"
|
||||
url="#locations"
|
||||
text="Explore locations"
|
||||
on:click={() => $smoothScroll.scrollTo('#locations', { duration: 2 })}
|
||||
onclick={() => $smoothScroll.scrollTo('#locations', { duration: 2 })}
|
||||
>
|
||||
<IconEarth animate={true} />
|
||||
</Button>
|
||||
@@ -116,7 +117,7 @@
|
||||
</section>
|
||||
|
||||
<section class="homepage__photos">
|
||||
<Collage {photos} />
|
||||
<Collage photos={data.photos} />
|
||||
</section>
|
||||
|
||||
<div class="homepage__ctas">
|
||||
@@ -124,28 +125,13 @@
|
||||
|
||||
<ListCTAs>
|
||||
<li>
|
||||
<BoxCTA
|
||||
url="/photos"
|
||||
icon="photos"
|
||||
label="Browse all photos"
|
||||
alt="Photos"
|
||||
/>
|
||||
<BoxCTA url="/photos" icon="photos" label="Browse all photos" alt="Photos" />
|
||||
</li>
|
||||
<li>
|
||||
<BoxCTA
|
||||
url="/shop"
|
||||
icon="bag"
|
||||
label="Shop our products"
|
||||
alt="Shopping bag"
|
||||
/>
|
||||
<BoxCTA url="/shop" icon="bag" label="Shop our products" alt="Shopping bag" />
|
||||
</li>
|
||||
<li>
|
||||
<BoxCTA
|
||||
url="/about"
|
||||
icon="compass"
|
||||
label="Learn about the project"
|
||||
alt="Compass"
|
||||
/>
|
||||
<BoxCTA url="/about" icon="compass" label="Learn about the project" alt="Compass" />
|
||||
</li>
|
||||
</ListCTAs>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user