Smooth scroll

This commit is contained in:
tree🌴 2023-02-21 12:51:42 +01:00
parent bb088b601c
commit cee2fee853
2 changed files with 55 additions and 40 deletions

View file

@ -39,4 +39,15 @@ export function animateText (ev, interval = 50) {
} }
}, interval * i) }, interval * i)
} }
}
export async function handleAnchorClick (event) {
event.preventDefault()
const link = event.currentTarget
const anchorId = new URL(link.href).hash.replace('#', '')
const anchor = document.getElementById(anchorId || 'intro')
return window.scrollTo({
top: anchor.offsetTop,
behavior: 'smooth'
})
} }

View file

@ -3,19 +3,21 @@
export let data; export let data;
import SvelteMarkdown from 'svelte-markdown'; import SvelteMarkdown from 'svelte-markdown';
import { animateText } from '$lib/helpers'; import { animateText, handleAnchorClick } from '$lib/helpers';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
let navbar = false; let navbar = false;
let choosed = null;
let lastScrollTop = null;
const menu = [ const menu = [
{ title: 'Homepage', url: '', hidden: true }, { title: 'intro', name: '#', url: '' },
{ title: 'About', url: '#about' }, { title: 'About', url: '#about' },
{ title: 'Speakers', url: '#speakers' }, { title: 'Speakers', url: '#speakers' },
{ title: 'Program', url: '#program' }, { title: 'Program', url: '#program' },
{ title: 'Sponsors', url: '#sponsors' }, { title: 'Sponsors', url: '#sponsors' },
{ title: 'FAQ', url: '#faq' },
{ title: 'Ticket', url: '#ticket', class: 'button' }, { title: 'Ticket', url: '#ticket', class: 'button' },
{ title: 'FAQ', url: '#faq', hidden: true }
]; ];
const homepageAnimation = () => { const homepageAnimation = () => {
@ -25,43 +27,41 @@
} }
} }
function locationHashUpdateTick () {
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
if (lastScrollTop === scrollTop) {
return null;
} else {
lastScrollTop = scrollTop
}
const arr = []
for (const mi of menu) {
const el = document.getElementById(mi.title.toLowerCase())
const pos = el.getBoundingClientRect()
//console.log(mi.title, pos.top, pos.bottom)
if (pos.top <= 100 && pos.bottom > 100) {
arr.push([ mi, pos.top, pos.bottom ])
}
}
choosed = arr[arr.length-1]
if (choosed) {
//console.log('choosed = ', choosed[0].title)
const currentHash = window.location.hash
const hash = choosed[0].url
if (hash !== currentHash) {
if (hash === '') {
history.replaceState(null, null, ' ');
} else {
history.replaceState(null, null, hash);
}
}
}
}
onMount(async () => { onMount(async () => {
setTimeout(homepageAnimation, 0) // initial animation setTimeout(homepageAnimation, 0) // initial animation
setInterval(homepageAnimation, 10000) // every 10 seconds setInterval(homepageAnimation, 10000) // every 10 seconds
setInterval(locationHashUpdateTick, 1000) // every 1 seconds
let lastScrollTop = null
setInterval(() => {
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
if (lastScrollTop === scrollTop) {
return null;
} else {
lastScrollTop = scrollTop
}
console.log('x')
const arr = []
for (const mi of menu) {
const el = document.getElementById(mi.title.toLowerCase())
const pos = el.getBoundingClientRect()
//console.log(mi.title, pos.top, pos.bottom)
if (pos.top <= 100 && pos.bottom > 100) {
arr.push([ mi, pos.top, pos.bottom ])
}
}
const choosed = arr[arr.length-1]
if (choosed) {
//console.log('choosed = ', choosed[0].title)
const currentHash = window.location.hash
const hash = choosed[0].url
if (hash !== currentHash) {
if (hash === '') {
history.replaceState(null, null, ' ');
} else {
history.replaceState(null, null, hash);
}
}
}
}, 1000)
}); });
</script> </script>
@ -77,9 +77,13 @@
<!--h1 class="text-2xl uppercase">{data.config.title}</h1--> <!--h1 class="text-2xl uppercase">{data.config.title}</h1-->
</div> </div>
<div class="flex items-center gap-6 text-xl"> <div class="flex items-center gap-6 text-xl">
<button class="md:hidden text-3xl" on:click={() => navbar = !navbar}>☰</button> <button class="md:hidden text-3xl" on:click={(ev) => (navbar = !navbar)}>☰</button>
{#each menu.filter(i => !i.hidden) as mi} {#each menu.filter(i => !i.hidden) as mi}
<div class="hidden md:block"><a class="{mi.class ? mi.class : 'hover:underline'}" href={mi.url} on:mouseenter={animateText}>{mi.title.toUpperCase()}</a></div> <div class="hidden md:block">
<a class="{mi.class ? mi.class : 'hover:underline'} {choosed && mi.url === choosed[0].url ? 'font-bold underline' : null}" href={mi.url} on:mouseenter={animateText} on:click={handleAnchorClick}>
{mi.name?.toUpperCase() || mi.title.toUpperCase()}
</a>
</div>
{/each} {/each}
</div> </div>
</div> </div>
@ -95,7 +99,7 @@
{/if} {/if}
</div> </div>
<div class="w-full h-screen" id="homepage"> <div class="w-full h-screen" id="intro">
<div class="w-full h-full flex items-center text-center"> <div class="w-full h-full flex items-center text-center">
<div class="mx-auto px-4"> <div class="mx-auto px-4">
<div class="text-5xl md:text-8xl font-bold mb-4 md:mb-8 animation-crypt" on:mouseenter={animateText}> <div class="text-5xl md:text-8xl font-bold mb-4 md:mb-8 animation-crypt" on:mouseenter={animateText}>