refactor: migrate to Svelte 5
use runes ($props, $state, $derived, $effect, etc)
This commit is contained in:
@@ -2,20 +2,31 @@
|
||||
import { cx } from 'classix'
|
||||
import Image from './Image.svelte'
|
||||
|
||||
export let id: string
|
||||
export let alt: string
|
||||
export let disabled = false
|
||||
let {
|
||||
id,
|
||||
alt,
|
||||
disabled = false,
|
||||
...props
|
||||
}: {
|
||||
id: string
|
||||
alt: string
|
||||
disabled?: boolean
|
||||
class?: string
|
||||
} = $props()
|
||||
|
||||
let hovering = false
|
||||
let timer: ReturnType<typeof setTimeout> | number = null
|
||||
let hovering = $state(false)
|
||||
let timer: ReturnType<typeof setTimeout>
|
||||
|
||||
$: classes = cx(
|
||||
const classes = $derived(cx(
|
||||
hovering ? 'is-hovered' : undefined,
|
||||
disabled ? 'is-disabled' : undefined,
|
||||
$$props.class
|
||||
)
|
||||
props.class,
|
||||
))
|
||||
|
||||
// Hovering functions
|
||||
|
||||
/**
|
||||
* Hovering functions
|
||||
*/
|
||||
const handleMouseEnter = () => {
|
||||
clearTimeout(timer)
|
||||
hovering = true
|
||||
@@ -26,9 +37,10 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<figure class={classes}
|
||||
on:mouseenter={handleMouseEnter}
|
||||
on:mouseleave={handleMouseLeave}
|
||||
<figure
|
||||
class={classes}
|
||||
onmouseenter={handleMouseEnter}
|
||||
onmouseleave={handleMouseLeave}
|
||||
>
|
||||
<Image
|
||||
{id}
|
||||
|
||||
@@ -23,8 +23,13 @@
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
export let text: string
|
||||
export let size = 'small'
|
||||
let {
|
||||
text,
|
||||
size = 'small',
|
||||
}: {
|
||||
text: string
|
||||
size?: string
|
||||
} = $props()
|
||||
</script>
|
||||
|
||||
<div class="badge badge--{size}">
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
margin-left: 20px;
|
||||
color: $color-secondary-light;
|
||||
text-align: left;
|
||||
font-weight: 300;
|
||||
font-weight: 400;
|
||||
|
||||
@include bp (sm) {
|
||||
margin-left: 0;
|
||||
|
||||
@@ -5,10 +5,17 @@
|
||||
<script lang="ts">
|
||||
import Icon from '$components/atoms/Icon.svelte'
|
||||
|
||||
export let icon: string
|
||||
export let alt: string
|
||||
export let label: string
|
||||
export let url: string
|
||||
let {
|
||||
icon,
|
||||
alt,
|
||||
label,
|
||||
url,
|
||||
}: {
|
||||
icon: string
|
||||
alt: string
|
||||
label: string
|
||||
url: string
|
||||
} = $props()
|
||||
</script>
|
||||
|
||||
<a href={url} class="box-cta">
|
||||
|
||||
@@ -6,56 +6,71 @@
|
||||
import { cx } from 'classix'
|
||||
import SplitText from '$components/SplitText.svelte'
|
||||
|
||||
export let text: string
|
||||
export let url: string = undefined
|
||||
export let color: string = undefined
|
||||
export let size: 'xsmall' | 'small' | 'medium' | 'large'
|
||||
export let effect = 'link-3d'
|
||||
export let disabled: boolean = undefined
|
||||
export let slotPosition = 'before'
|
||||
let {
|
||||
text,
|
||||
url,
|
||||
color,
|
||||
size,
|
||||
effect = 'link-3d',
|
||||
disabled,
|
||||
slotPosition = 'before',
|
||||
onclick,
|
||||
children,
|
||||
...props
|
||||
}: {
|
||||
text: string
|
||||
url?: string
|
||||
color?: string
|
||||
size: 'xsmall' | 'small' | 'medium' | 'large'
|
||||
effect?: string
|
||||
disabled?: boolean
|
||||
slotPosition?: 'before' | 'after'
|
||||
onclick?: any
|
||||
children?: any
|
||||
class?: string
|
||||
} = $props()
|
||||
|
||||
let tag: 'a' | 'button'
|
||||
$: tag = url ? 'a' : 'button'
|
||||
|
||||
$: classes = cx(
|
||||
const tag = $derived(url ? 'a' : 'button')
|
||||
const classes = $derived(cx(
|
||||
'button',
|
||||
effect ? effect : undefined,
|
||||
effect,
|
||||
...[color, size].map(variant => variant && `button--${variant}`),
|
||||
Object.keys($$slots).length !== 0 ? `has-icon-${slotPosition}` : undefined,
|
||||
$$props.class,
|
||||
)
|
||||
children && `has-icon-${slotPosition}`,
|
||||
props.class,
|
||||
))
|
||||
|
||||
// Define external links
|
||||
$: isExternal = /^(http|https):\/\//i.test(url)
|
||||
$: isProtocol = /^(mailto|tel):/i.test(url)
|
||||
$: rel = isExternal ? 'external noopener' : null
|
||||
$: target = isExternal ? '_blank' : null
|
||||
const isExternal = $derived(/^(http|https):\/\//i.test(url))
|
||||
const isProtocol = $derived(/^(mailto|tel):/i.test(url))
|
||||
const rel = $derived(isExternal ? 'external noopener' : null)
|
||||
const target = $derived(isExternal ? '_blank' : null)
|
||||
</script>
|
||||
|
||||
{#if tag === 'button'}
|
||||
<button class={classes} tabindex="0" {disabled} on:click>
|
||||
{#if slotPosition === 'before'}
|
||||
<slot />
|
||||
<button class={classes} tabindex="0" {disabled} {onclick}>
|
||||
{#if children && slotPosition === 'before'}
|
||||
{@render children()}
|
||||
{/if}
|
||||
<SplitText {text} clone={true} />
|
||||
{#if slotPosition === 'after'}
|
||||
<slot />
|
||||
{#if children && slotPosition === 'after'}
|
||||
{@render children()}
|
||||
{/if}
|
||||
</button>
|
||||
{:else if tag === 'a'}
|
||||
<a
|
||||
href={url} class={classes}
|
||||
href={url}
|
||||
class={classes}
|
||||
{target} {rel}
|
||||
data-sveltekit-noscroll={isExternal || isProtocol ? 'off' : ''}
|
||||
tabindex="0"
|
||||
on:click
|
||||
{onclick}
|
||||
>
|
||||
{#if slotPosition === 'before'}
|
||||
<slot />
|
||||
{#if children && slotPosition === 'before'}
|
||||
{@render children()}
|
||||
{/if}
|
||||
<SplitText {text} clone={true} />
|
||||
{#if slotPosition === 'after'}
|
||||
<slot />
|
||||
{#if children && slotPosition === 'after'}
|
||||
{@render children()}
|
||||
{/if}
|
||||
</a>
|
||||
{/if}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
</script>
|
||||
|
||||
<div class="button-cart">
|
||||
<ButtonCircle color="purple" on:click={openCart}>
|
||||
<ButtonCircle color="purple" onclick={openCart}>
|
||||
<Icon icon="bag" label="Cart icon" />
|
||||
{#if $cartAmount > 0}
|
||||
<span class="quantity" transition:scale={{ start: 0.6, duration: 400, easing: quartOut }}>{$cartAmount}</span>
|
||||
|
||||
@@ -5,42 +5,58 @@
|
||||
<script lang="ts">
|
||||
import { cx } from 'classix'
|
||||
|
||||
export let tag = 'button'
|
||||
export let url: string = undefined
|
||||
export let color: string = undefined
|
||||
export let size: string = undefined
|
||||
export let type: 'button' | 'reset' | 'submit' = undefined
|
||||
export let clone = false
|
||||
export let disabled: boolean = undefined
|
||||
export let label: string = undefined
|
||||
let {
|
||||
tag = 'button',
|
||||
url,
|
||||
color,
|
||||
size,
|
||||
type,
|
||||
clone = false,
|
||||
disabled,
|
||||
label,
|
||||
children,
|
||||
onclick,
|
||||
...props
|
||||
}: {
|
||||
tag?: string
|
||||
url?: string
|
||||
color?: string
|
||||
size?: string
|
||||
type?: 'button' | 'reset' | 'submit'
|
||||
clone?: boolean
|
||||
disabled?: boolean
|
||||
label?: string
|
||||
children?: any
|
||||
onclick?: any
|
||||
class?: string
|
||||
} = $props()
|
||||
|
||||
const className = 'button-circle'
|
||||
$: classes = cx(
|
||||
className,
|
||||
...[color, size].map(variant => variant && `${className}--${variant}`),
|
||||
const buttonClass = 'button-circle'
|
||||
const classes = $derived(cx(
|
||||
buttonClass,
|
||||
...[color, size].map(variant => variant && `${buttonClass}--${variant}`),
|
||||
clone ? 'has-clone' : null,
|
||||
$$props.class
|
||||
)
|
||||
props.class,
|
||||
))
|
||||
</script>
|
||||
|
||||
{#snippet content()}
|
||||
{#if clone}
|
||||
{#each Array(2) as _}
|
||||
{@render children()}
|
||||
{/each}
|
||||
{:else}
|
||||
{@render children()}
|
||||
{/if}
|
||||
{/snippet}
|
||||
|
||||
|
||||
{#if tag === 'a'}
|
||||
<a href={url} class={classes} tabindex="0" aria-label={label} on:click>
|
||||
{#if clone}
|
||||
{#each Array(2) as _}
|
||||
<slot />
|
||||
{/each}
|
||||
{:else}
|
||||
<slot />
|
||||
{/if}
|
||||
<a href={url} class={classes} tabindex="0" aria-label={label} {onclick}>
|
||||
{@render content()}
|
||||
</a>
|
||||
{:else}
|
||||
<button {type} class={classes} disabled={disabled} tabindex="0" aria-label={label} on:click>
|
||||
{#if clone}
|
||||
{#each Array(2) as _}
|
||||
<slot />
|
||||
{/each}
|
||||
{:else}
|
||||
<slot />
|
||||
{/if}
|
||||
<button {type} class={classes} disabled={disabled} tabindex="0" aria-label={label} {onclick}>
|
||||
{@render content()}
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
<script lang="ts">
|
||||
import { cx } from 'classix'
|
||||
|
||||
export let icon: string
|
||||
export let label: string = undefined
|
||||
|
||||
$: classes = cx($$props.class)
|
||||
let {
|
||||
icon,
|
||||
label,
|
||||
...props
|
||||
}: {
|
||||
icon: string
|
||||
label?: string
|
||||
class?: string
|
||||
} = $props()
|
||||
</script>
|
||||
|
||||
<svg class={classes} aria-label={label} width="32" height="32">
|
||||
<svg class={props.class} aria-label={label} width="32" height="32">
|
||||
<use xlink:href="#icon-{icon}" />
|
||||
</svg>
|
||||
|
||||
@@ -18,11 +18,17 @@
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
export let color: string = undefined
|
||||
export let flip = false
|
||||
let {
|
||||
color,
|
||||
flip = false,
|
||||
}: {
|
||||
color?: string
|
||||
flip?: boolean
|
||||
} = $props()
|
||||
</script>
|
||||
|
||||
<svg width="12" height="14"
|
||||
<svg
|
||||
width="12" height="14"
|
||||
class="arrow arrow--{color}"
|
||||
class:arrow--flip={flip}
|
||||
>
|
||||
|
||||
@@ -9,12 +9,18 @@
|
||||
<script lang="ts">
|
||||
import { cx } from 'classix'
|
||||
|
||||
export let animate = false
|
||||
let {
|
||||
animate = false,
|
||||
...props
|
||||
}: {
|
||||
animate?: boolean
|
||||
class?: string
|
||||
} = $props()
|
||||
|
||||
$: classes = cx(
|
||||
const classes = $derived(cx(
|
||||
'icon-earth',
|
||||
$$props.class,
|
||||
)
|
||||
props.class,
|
||||
))
|
||||
</script>
|
||||
|
||||
<svg class={classes} width="48" height="48" viewBox="0 0 48 48" fill="none">
|
||||
|
||||
@@ -1,16 +1,31 @@
|
||||
<script lang="ts">
|
||||
import { getAssetUrlKey } from '$utils/api'
|
||||
|
||||
export let src: string = undefined
|
||||
export let id: string = undefined
|
||||
export let sizeKey: string = undefined
|
||||
export let sizes: Sizes = undefined
|
||||
export let width: number = sizes?.medium?.width
|
||||
export let height: number = sizes?.medium?.height
|
||||
export let ratio: number = undefined
|
||||
export let alt: string
|
||||
export let lazy = true
|
||||
export let decoding: 'auto' | 'sync' | 'async' = 'auto'
|
||||
let {
|
||||
src,
|
||||
id,
|
||||
sizeKey,
|
||||
sizes,
|
||||
width = sizes?.medium?.width,
|
||||
height = sizes?.medium?.height,
|
||||
ratio,
|
||||
alt,
|
||||
lazy = true,
|
||||
decoding,
|
||||
...props
|
||||
}: {
|
||||
src?: string
|
||||
id?: string
|
||||
sizeKey?: string
|
||||
sizes?: Sizes
|
||||
width?: number
|
||||
height?: number
|
||||
ratio?: number
|
||||
alt: string
|
||||
lazy?: boolean
|
||||
decoding?: 'auto' | 'sync' | 'async'
|
||||
class?: string
|
||||
} = $props()
|
||||
|
||||
interface Sizes {
|
||||
small?: { width?: number; height?: number }
|
||||
@@ -29,19 +44,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: imgWidth = sizes?.small?.width || width
|
||||
$: imgHeight = sizes?.small?.height || height
|
||||
$: imgSrc = id ? getAssetUrlKey(id, `${sizeKey}-small`) : src
|
||||
$: srcSet = sizes
|
||||
? [
|
||||
const imgWidth = $derived(sizes?.small?.width || width)
|
||||
const imgHeight = $derived(sizes?.small?.height || height)
|
||||
const imgSrc = $derived(id ? getAssetUrlKey(id, `${sizeKey}-small`) : src)
|
||||
const srcSet = $derived(
|
||||
sizes ? [
|
||||
`${getAssetUrlKey(id, `${sizeKey}-small`)} 345w`,
|
||||
sizes.medium && `${getAssetUrlKey(id, `${sizeKey}-medium`)} 768w`,
|
||||
sizes.large && `${getAssetUrlKey(id, `${sizeKey}-large`)} 1280w`,
|
||||
]
|
||||
: [getAssetUrlKey(id, sizeKey)]
|
||||
] : [getAssetUrlKey(id, sizeKey)]
|
||||
)
|
||||
</script>
|
||||
|
||||
<picture class={$$props.class}>
|
||||
<picture class={props.class}>
|
||||
<img
|
||||
src={imgSrc}
|
||||
sizes={sizes ? '(min-width: 1200px) 864px, (min-width: 992px) 708px, (min-width: 768px) 540px, 100%' : undefined}
|
||||
@@ -52,4 +67,4 @@
|
||||
loading={lazy ? 'lazy' : undefined}
|
||||
{decoding}
|
||||
/>
|
||||
</picture>
|
||||
</picture>
|
||||
|
||||
@@ -12,39 +12,53 @@
|
||||
import { map } from 'utils/math'
|
||||
import reveal from '$animations/reveal'
|
||||
|
||||
export let tag: string
|
||||
export let label: string = undefined
|
||||
export let parallax: number = undefined
|
||||
export let offsetStart: number = undefined
|
||||
export let offsetEnd: number = undefined
|
||||
export let animate = true
|
||||
let {
|
||||
tag,
|
||||
label,
|
||||
parallax,
|
||||
offsetStart,
|
||||
offsetEnd,
|
||||
animate = true,
|
||||
children,
|
||||
...props
|
||||
}: {
|
||||
tag: string
|
||||
label?: string
|
||||
parallax?: number
|
||||
offsetStart?: number
|
||||
offsetEnd?: number
|
||||
animate?: boolean
|
||||
class?: string
|
||||
children?: any
|
||||
} = $props()
|
||||
|
||||
let scrollY: number
|
||||
let innerWidth: number
|
||||
let innerHeight: number
|
||||
let titleEl: HTMLElement
|
||||
let isLarger: boolean
|
||||
|
||||
// Define default values
|
||||
$: if (titleEl && !offsetStart && !offsetEnd) {
|
||||
offsetStart = titleEl.offsetTop - innerHeight * (innerWidth < 768 ? 0.2 : 0.75)
|
||||
offsetEnd = titleEl.offsetTop + innerHeight * (innerWidth < 768 ? 0.5 : 0.5)
|
||||
}
|
||||
let scrollY = $state<number>()
|
||||
let innerWidth = $state<number>()
|
||||
let innerHeight = $state<number>()
|
||||
let titleEl = $state<HTMLElement>()
|
||||
|
||||
// Check if title is larger than viewport to translate it
|
||||
$: isLarger = titleEl && titleEl.offsetWidth >= innerWidth
|
||||
const isLarger = $derived<boolean>(titleEl && titleEl.offsetWidth >= innerWidth)
|
||||
|
||||
// Calculate the parallax value
|
||||
$: if (titleEl) {
|
||||
const toTranslate = 100 - (innerWidth / titleEl.offsetWidth * 100)
|
||||
parallax = isLarger ? map(scrollY, offsetStart, offsetEnd, 0, -toTranslate, true) : 0
|
||||
}
|
||||
$effect(() => {
|
||||
// Define default values
|
||||
if (titleEl && !offsetStart && !offsetEnd) {
|
||||
offsetStart = titleEl.offsetTop - innerHeight * (innerWidth < 768 ? 0.2 : 0.75)
|
||||
offsetEnd = titleEl.offsetTop + innerHeight * (innerWidth < 768 ? 0.5 : 0.5)
|
||||
}
|
||||
|
||||
$: classes = cx(
|
||||
// Calculate the parallax value
|
||||
if (titleEl) {
|
||||
const toTranslate = 100 - (innerWidth / titleEl.offsetWidth * 100)
|
||||
parallax = isLarger ? map(scrollY, offsetStart, offsetEnd, 0, -toTranslate, true) : 0
|
||||
}
|
||||
})
|
||||
|
||||
const classes = $derived(cx(
|
||||
'scrolling-title',
|
||||
'title-huge',
|
||||
$$props.class
|
||||
)
|
||||
props.class,
|
||||
))
|
||||
|
||||
const revealOptions = animate ? {
|
||||
children: '.char',
|
||||
@@ -65,9 +79,10 @@
|
||||
|
||||
<svelte:element this={tag}
|
||||
bind:this={titleEl}
|
||||
class={classes} aria-label={label}
|
||||
class={classes}
|
||||
aria-label={label}
|
||||
style:--parallax-x="{parallax}%"
|
||||
use:reveal={revealOptions}
|
||||
>
|
||||
<slot />
|
||||
{@render children()}
|
||||
</svelte:element>
|
||||
|
||||
@@ -7,8 +7,13 @@
|
||||
import reveal from '$animations/reveal'
|
||||
import { DURATION } from '$utils/constants'
|
||||
|
||||
export let variant = 'lines'
|
||||
export let tag = 'h1'
|
||||
let {
|
||||
variant = 'lines',
|
||||
tag = 'h1',
|
||||
}: {
|
||||
variant?: 'inline' | 'lines'
|
||||
tag?: string
|
||||
} = $props()
|
||||
</script>
|
||||
|
||||
{#if tag === 'h1'}
|
||||
|
||||
Reference in New Issue
Block a user