Create a component for scrolling huge titles
This commit is contained in:
@@ -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
12
pnpm-lock.yaml
generated
@@ -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'}
|
||||||
|
|||||||
@@ -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}
|
||||||
41
src/components/atoms/ScrollingTitle.svelte
Normal file
41
src/components/atoms/ScrollingTitle.svelte
Normal 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}
|
||||||
@@ -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>
|
||||||
|
|||||||
5
src/style/atoms/_scrolling-title.scss
Normal file
5
src/style/atoms/_scrolling-title.scss
Normal 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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user