refactor(components): improve layout and animation consistency in Features and Hero components

This commit is contained in:
taroj1205 2025-06-06 11:50:12 +12:00
parent 427dea3416
commit 1017d52859
No known key found for this signature in database
GPG key ID: 0FCB6CFFE0981AB7
2 changed files with 47 additions and 26 deletions

View file

@ -46,10 +46,10 @@ const featureList = [
<section <section
id="features" id="features"
class="relative flex w-full flex-col items-center gap-8 py-8 text-center sm:gap-12 sm:py-12 xl:gap-16 xl:py-36" class="relative flex w-full flex-col items-center gap-8 py-8 text-center sm:gap-12 sm:py-12 xl:gap-24 xl:py-36"
> >
<!-- Section Header --> <!-- Section Header -->
<div class="flex w-full flex-col items-center gap-4 sm:gap-6 xl:gap-12"> <div class="flex w-full flex-col items-center gap-4 sm:gap-6">
<h2 class="text-3xl sm:text-4xl md:text-6xl"> <h2 class="text-3xl sm:text-4xl md:text-6xl">
{ {
(titles || features.titles).map(title => { (titles || features.titles).map(title => {
@ -70,7 +70,7 @@ const featureList = [
} }
</h2> </h2>
<p <p
class="max-w-2xl text-base sm:text-lg" class="max-w-4xl text-base sm:text-lg"
style="transform: translateY(20px); opacity: 0.001; filter: blur(4px)" style="transform: translateY(20px); opacity: 0.001; filter: blur(4px)"
> >
<span class="opacity-80">{features.description}</span> <span class="opacity-80">{features.description}</span>
@ -78,25 +78,23 @@ const featureList = [
</div> </div>
<!-- Features Layout --> <!-- Features Layout -->
<div class="space-between flex w-full flex-col gap-12 sm:gap-16 xl:gap-24"> <div id="showcase" class="flex w-full flex-col gap-12 sm:gap-16 xl:gap-36">
{ {
featureList.map((feature, index) => ( featureList.map((feature, index) => (
<div <div class="flex w-full flex-col items-center gap-6 xl:gap-12">
class={`flex w-full flex-col items-center gap-6 xl:gap-12 ${index % 2 === 0 ? 'xl:flex-row-reverse' : 'xl:flex-row'}`}
>
<div class="flex flex-col items-center gap-4"> <div class="flex flex-col items-center gap-4">
<h3 class="text-2xl font-bold opacity-0 blur-sm sm:text-3xl xl:text-4xl"> <h3 class="text-3xl font-bold opacity-0 blur-sm sm:text-4xl xl:text-5xl">
{feature.title} {feature.title}
</h3> </h3>
<p <p
class="text-base leading-relaxed sm:text-lg" class="max-w-3xl text-center text-base leading-relaxed sm:text-lg"
style="transform: translateY(20px); opacity: 0.001; filter: blur(4px)" style="transform: translateY(20px); opacity: 0.001; filter: blur(4px)"
> >
<span class="opacity-80">{feature.description}</span> <span class="opacity-80">{feature.description}</span>
</p> </p>
</div> </div>
<Video <Video
class="max-h-[450px] w-[800px] rounded-xl border-2 border-dark object-cover shadow-lg" class="w-full rounded-xl object-cover shadow-lg"
style="transform: translateY(20px); opacity: 0.001; filter: blur(4px)" style="transform: translateY(20px); opacity: 0.001; filter: blur(4px)"
name={feature.video} name={feature.video}
autoplay autoplay
@ -117,22 +115,38 @@ const featureList = [
function initAnimations() { function initAnimations() {
const debug = false const debug = false
const elements = document.querySelectorAll( const elements = document.querySelectorAll('#features h2 b, #features > div > p')
'#features h2 b, #features h3, #features p, #features video' const showcase = document.getElementById('showcase') as HTMLElement
)
animate(elements, { animate(elements, {
opacity: { from: 0.001, to: 1 }, opacity: { from: 0.001, to: 1 },
translateY: { from: 20, to: 0 }, translateY: { from: 20, to: 0 },
filter: { from: 'blur(4px)', to: 'blur(0px)' }, filter: { from: 'blur(4px)', to: 'blur(0px)' },
duration: 300, duration: 300,
delay: stagger(150), delay: stagger(200),
ease: 'cubicBezier(0.25, 0.1, 0.25, 1)', ease: 'cubicBezier(0.25, 0.1, 0.25, 1)',
autoplay: onScroll({ autoplay: onScroll({
target: '#features', target: '#features',
debug, debug,
}), }),
}) })
for (const element of showcase.children) {
const target = element.querySelectorAll('p, h3, video')
animate(target, {
opacity: { from: 0.001, to: 1 },
translateY: { from: 20, to: 0 },
filter: { from: 'blur(4px)', to: 'blur(0px)' },
duration: 300,
delay: stagger(150),
ease: 'cubicBezier(0.25, 0.1, 0.25, 1)',
autoplay: onScroll({
target,
enter: 'bottom-=200 top',
debug,
}),
})
}
} }
initAnimations() initAnimations()
</script> </script>

View file

@ -17,7 +17,10 @@ const {
} = getUI(locale) } = getUI(locale)
--- ---
<header id="header" class="flex w-full flex-col items-center gap-12 py-32 text-center lg:gap-16"> <header
id="header"
class="flex w-full flex-col items-center gap-12 py-16 text-center lg:gap-16 lg:py-32"
>
<div class="flex h-full flex-col items-center justify-center gap-6 md:gap-12"> <div class="flex h-full flex-col items-center justify-center gap-6 md:gap-12">
<div class="flex flex-col items-center justify-center gap-4 md:gap-8"> <div class="flex flex-col items-center justify-center gap-4 md:gap-8">
<div> <div>
@ -49,19 +52,13 @@ const {
<div <div
class="flex w-2/3 flex-col items-center justify-center gap-3 sm:gap-6 md:w-fit md:flex-row" class="flex w-2/3 flex-col items-center justify-center gap-3 sm:gap-6 md:w-fit md:flex-row"
> >
<div <div style="transform: translateY(20px); opacity: 0.001; filter: blur(4px)">
class="hero__link-group_button"
style="transform: translateY(20px); opacity: 0.001; filter: blur(4px)"
>
<Button class="w-fit" href={getLocalePath('/download')} isPrimary> <Button class="w-fit" href={getLocalePath('/download')} isPrimary>
{hero.buttons.beta} {hero.buttons.beta}
<ArrowRightIcon class="size-4" /> <ArrowRightIcon class="size-4" />
</Button> </Button>
</div> </div>
<div <div style="transform: translateY(20px); opacity: 0.001; filter: blur(4px)">
class="hero__link-group_button"
style="transform: translateY(20px); opacity: 0.001; filter: blur(4px)"
>
<Button class="w-fit" href={getLocalePath('/donate')}> <Button class="w-fit" href={getLocalePath('/donate')}>
{hero.buttons.support} {hero.buttons.support}
</Button> </Button>
@ -78,7 +75,7 @@ const {
playsinline playsinline
preload="none" preload="none"
class="rounded-xl" class="rounded-xl"
style="transform: translateY(20px); opacity: 0.001; filter: blur(4px)" style="transform: translateY(20px) scale(0.6); opacity: 0.001; filter: blur(4px); transform-origin: top;"
/> />
</header> </header>
@ -89,13 +86,12 @@ const {
const debug = false const debug = false
const elements = document.querySelectorAll( const elements = document.querySelectorAll(
'#header h1 b, #header p, #header .hero__link-group_button, #header video, #header ul' '#header h1 b, #header p, #header div:has(a), #header video, #header ul'
) )
animate(elements, { animate(elements, {
// @ts-expect-error - element is HTMLElement // @ts-expect-error - element is HTMLElement
opacity: element => { opacity: element => {
// if ul is the element, return 0.8
if (element.tagName === 'UL') { if (element.tagName === 'UL') {
return { from: 0.001, to: 0.8 } return { from: 0.001, to: 0.8 }
} }
@ -111,6 +107,17 @@ const {
debug, debug,
}), }),
}) })
animate('#header video', {
scale: { from: 0.6, to: 1 },
ease: 'cubicBezier(0.25, 0.1, 0.25, 1)',
autoplay: onScroll({
enter: 'bottom-=100 top',
leave: 'top+=100 bottom',
sync: true,
debug,
}),
})
} }
initAnimations() initAnimations()
</script> </script>