Create a component for scrolling huge titles

This commit is contained in:
2021-11-16 22:35:42 +01:00
parent 4b05186662
commit ed62030b29
8 changed files with 111 additions and 13 deletions

View File

@@ -17,6 +17,7 @@
"lint": "eslint --ignore-path .gitignore ." "lint": "eslint --ignore-path .gitignore ."
}, },
"dependencies": { "dependencies": {
"animejs": "^3.2.1",
"dayjs": "^1.10.7", "dayjs": "^1.10.7",
"embla-carousel": "^5.0.1", "embla-carousel": "^5.0.1",
"focus-visible": "^5.2.0", "focus-visible": "^5.2.0",
@@ -26,6 +27,7 @@
"@sveltejs/adapter-node": "next", "@sveltejs/adapter-node": "next",
"@sveltejs/adapter-vercel": "next", "@sveltejs/adapter-vercel": "next",
"@sveltejs/kit": "next", "@sveltejs/kit": "next",
"@types/animejs": "^3.1.4",
"@typescript-eslint/eslint-plugin": "^5.3.1", "@typescript-eslint/eslint-plugin": "^5.3.1",
"@typescript-eslint/parser": "^5.3.1", "@typescript-eslint/parser": "^5.3.1",
"eslint": "^8.2.0", "eslint": "^8.2.0",

12
pnpm-lock.yaml generated
View File

@@ -4,8 +4,10 @@ specifiers:
'@sveltejs/adapter-node': next '@sveltejs/adapter-node': next
'@sveltejs/adapter-vercel': next '@sveltejs/adapter-vercel': next
'@sveltejs/kit': next '@sveltejs/kit': next
'@types/animejs': ^3.1.4
'@typescript-eslint/eslint-plugin': ^5.3.1 '@typescript-eslint/eslint-plugin': ^5.3.1
'@typescript-eslint/parser': ^5.3.1 '@typescript-eslint/parser': ^5.3.1
animejs: ^3.2.1
dayjs: ^1.10.7 dayjs: ^1.10.7
embla-carousel: ^5.0.1 embla-carousel: ^5.0.1
eslint: ^8.2.0 eslint: ^8.2.0
@@ -21,6 +23,7 @@ specifiers:
typescript: ^4.4.4 typescript: ^4.4.4
dependencies: dependencies:
animejs: 3.2.1
dayjs: 1.10.7 dayjs: 1.10.7
embla-carousel: 5.0.1 embla-carousel: 5.0.1
focus-visible: 5.2.0 focus-visible: 5.2.0
@@ -30,6 +33,7 @@ devDependencies:
'@sveltejs/adapter-node': 1.0.0-next.55 '@sveltejs/adapter-node': 1.0.0-next.55
'@sveltejs/adapter-vercel': 1.0.0-next.31 '@sveltejs/adapter-vercel': 1.0.0-next.31
'@sveltejs/kit': 1.0.0-next.196_sass@1.43.4+svelte@3.44.1 '@sveltejs/kit': 1.0.0-next.196_sass@1.43.4+svelte@3.44.1
'@types/animejs': 3.1.4
'@typescript-eslint/eslint-plugin': 5.3.1_4653b7803b7453f5f37717b7e1448517 '@typescript-eslint/eslint-plugin': 5.3.1_4653b7803b7453f5f37717b7e1448517
'@typescript-eslint/parser': 5.3.1_eslint@8.2.0+typescript@4.4.4 '@typescript-eslint/parser': 5.3.1_eslint@8.2.0+typescript@4.4.4
eslint: 8.2.0 eslint: 8.2.0
@@ -161,6 +165,10 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@types/animejs/3.1.4:
resolution: {integrity: sha512-WUjeFT2SXd6intfE6cg6eL1jk/JL88JqM2gC4WqO4iHLmbCvHUq6aoLK13lGpDWs4FtS2PHoYraJZ0dEx99Dyg==}
dev: true
/@types/json-schema/7.0.9: /@types/json-schema/7.0.9:
resolution: {integrity: sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==} resolution: {integrity: sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==}
dev: true dev: true
@@ -308,6 +316,10 @@ packages:
uri-js: 4.4.1 uri-js: 4.4.1
dev: true dev: true
/animejs/3.2.1:
resolution: {integrity: sha512-sWno3ugFryK5nhiDm/2BKeFCpZv7vzerWUcUPyAZLDhMek3+S/p418ldZJbJXo5ZUOpfm2kP2XRO4NJcULMy9A==}
dev: false
/ansi-colors/4.1.1: /ansi-colors/4.1.1:
resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==}
engines: {node: '>=6'} engines: {node: '>=6'}

View File

@@ -35,4 +35,11 @@
{/each} {/each}
</span> </span>
{/if} {/if}
{:else}
<span class={classes}>
{#each split as char, i}
<span class="char" style="--i-c: {i};">{char}</span>
{/each}
</span>
{/if} {/if}

View File

@@ -0,0 +1,41 @@
<script lang="ts">
import { map } from '$utils/functions'
export let tag: string
export let label: string = undefined
export let parallax: number = undefined
export let offset: number = 0
let scrollY: number
let titleEl: HTMLElement
$: if (titleEl) {
const start = titleEl.offsetTop + offset
const end = titleEl.offsetTop + (titleEl.offsetHeight + offset) * 0.9
parallax = map(scrollY, start, end, 0, 1, true)
}
const classes = [
'scrolling-title',
'title-huge',
$$props.class
].join(' ').trim()
</script>
<svelte:window bind:scrollY />
{#if tag === 'h1'}
<h1 class={classes} aria-label={label}
bind:this={titleEl}
style="--parallax-x: {parallax};"
>
<slot />
</h1>
{:else if tag === 'p'}
<p class={classes} aria-label={label}
bind:this={titleEl}
style="--parallax-x: {parallax};"
>
<slot />
</p>
{/if}

View File

@@ -3,8 +3,10 @@
import { page } from '$app/stores' import { page } from '$app/stores'
// Components // Components
import Metas from '$components/Metas.svelte' import Metas from '$components/Metas.svelte'
import SplitText from '$components/SplitText.svelte'
import Button from '$components/atoms/Button.svelte' import Button from '$components/atoms/Button.svelte'
import IconEarth from '$components/atoms/IconEarth.svelte' import IconEarth from '$components/atoms/IconEarth.svelte'
import ScrollingTitle from '$components/atoms/ScrollingTitle.svelte'
import BoxCTA from '$components/atoms/BoxCTA.svelte' import BoxCTA from '$components/atoms/BoxCTA.svelte'
import DiscoverText from '$components/atoms/DiscoverText.svelte' import DiscoverText from '$components/atoms/DiscoverText.svelte'
import PhotoCard from '$components/molecules/PhotoCard.svelte' import PhotoCard from '$components/molecules/PhotoCard.svelte'
@@ -17,8 +19,13 @@
const { settings, locations }: any = getContext('global') const { settings, locations }: any = getContext('global')
const { path } = $page const { path } = $page
let scrollY: number, innerHeight: number
let introTitleParallax = 0
</script> </script>
<svelte:window bind:scrollY bind:innerHeight />
<Metas <Metas
title="Houses Of" title="Houses Of"
description="" description=""
@@ -27,15 +34,19 @@
<main class="homepage"> <main class="homepage">
<section class="homepage__intro"> <section class="homepage__intro">
<h1 style="display: none;">Houses Of The World</h1> <ScrollingTitle tag="h1" class="homepage__title--houses" label="Houses of the World" parallax={introTitleParallax} offsetTop={100}>
<p class="homepage__title--houses title-huge">Houses</p> <SplitText text="Houses" mode="chars" />
<p class="homepage__description text-medium"> </ScrollingTitle>
{settings.description}
</p>
<Button text="Explore locations" url="{path}#locations"> <div class="homepage__headline">
<IconEarth animate={true} /> <p class="text-medium">
</Button> {settings.description}
</p>
<Button text="Explore locations" url="{path}#locations">
<IconEarth animate={true} />
</Button>
</div>
</section> </section>
<section class="homepage__photos"> <section class="homepage__photos">
@@ -79,7 +90,10 @@
<section class="homepage__locations" id="locations"> <section class="homepage__locations" id="locations">
<InteractiveGlobe /> <InteractiveGlobe />
<p class="homepage__title--world title-huge">World</p>
<ScrollingTitle tag="p" class="homepage__title--world" parallax={introTitleParallax} offset={-1 * innerHeight / 2}>
<SplitText text="World" mode="chars" />
</ScrollingTitle>
<Locations {locations} /> <Locations {locations} />
</section> </section>

View File

@@ -0,0 +1,5 @@
.scrolling-title {
transform: translate3d(calc(-1px * var(--parallax-x) * 100), 0, 0);
transition: transform 1.2s var(--ease-quart);
will-change: transform;
}

View File

@@ -2,6 +2,7 @@
.homepage { .homepage {
// Site title // Site title
&__title { &__title {
// Houses
&--houses { &--houses {
margin: -20px 0 0; margin: -20px 0 0;
color: $color-secondary; color: $color-secondary;
@@ -9,8 +10,15 @@
@include bp (sm) { @include bp (sm) {
margin-top: -100px; margin-top: -100px;
margin-left: calc(-1 * clamp(24px, 6vw, 64px));
}
span {
transition: none;
letter-spacing: -0.06em;
} }
} }
// World
&--world { &--world {
color: $color-primary-tertiary20; color: $color-primary-tertiary20;
text-align: center; text-align: center;
@@ -62,14 +70,22 @@
} }
} }
} }
// Text // Headline
&__description { &__headline {
max-width: 350px; max-width: 350px;
margin: 100px auto 32px; margin: 100px auto 0;
@include bp (sm) { @include bp (sm) {
margin: 20px auto 32px;
max-width: 524px; max-width: 524px;
margin-top: 20px;
}
p {
margin-bottom: 24px;
@include bp (sm) {
margin-bottom: 32px;
}
} }
} }

View File

@@ -43,6 +43,7 @@
@import "atoms/discover"; @import "atoms/discover";
@import "atoms/box-cta"; @import "atoms/box-cta";
@import "atoms/site-title"; @import "atoms/site-title";
@import "atoms/scrolling-title";
@import "atoms/photo"; @import "atoms/photo";
// Molecules // Molecules