forked from veda/www_veda_2025
feat: add typewriter animation effect to hero text
- Added typewriter-effect package for animated text rendering - Implemented sequential typing animation for welcome message and signature - Added client-side rendering check to prevent hydration issues - Adjusted text opacity and timing delays for better readability - Created invisible placeholder text to maintain layout during animation loading
This commit is contained in:
@@ -1,9 +1,19 @@
|
||||
'use client'
|
||||
|
||||
import Image from 'next/image'
|
||||
import { useState, useEffect } from 'react'
|
||||
import Typewriter from 'typewriter-effect'
|
||||
import { Button } from '@/components/Button'
|
||||
import { Container } from '@/components/Container'
|
||||
import BgNoise from '@/components/BgNoise'
|
||||
|
||||
export function Hero() {
|
||||
const [isClient, setIsClient] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setIsClient(true)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="relative -mt-20 min-h-screen">
|
||||
@@ -37,18 +47,68 @@ export function Hero() {
|
||||
<div className="relative">
|
||||
<div
|
||||
className="bg-cover bg-center -mt-14"
|
||||
style={{ backgroundImage: 'url(/images/paper.jpg)' }}
|
||||
style={{ backgroundImage: 'url(/images/paper.jpg)', opacity: '0.9' }}
|
||||
>
|
||||
<div className="px-6 py-24 lg:px-8">
|
||||
<div className="mx-auto max-w-2xl text-left">
|
||||
<p className="font-script text-2xl text-love-red mb-2 font-typewriter">Mon cher,</p>
|
||||
<p className="font-typewriter text-xl max-w-2xl mx-auto leading-relaxed">
|
||||
If you find yourself here, you’ve survived the noise.<br />
|
||||
Sit, let the glass sweat a little.<br />
|
||||
The band will start soon, and perhaps someone will meet your eyes before the chorus ends.<br />
|
||||
If not, the night still owes you a dance.
|
||||
<p className="font-script text-2xl text-love-red mb-2 font-typewriter relative">
|
||||
<span className="invisible">Mon cher,</span>
|
||||
{isClient && (
|
||||
<span className="absolute top-0 left-0">
|
||||
<Typewriter
|
||||
options={{
|
||||
delay: 75,
|
||||
}}
|
||||
onInit={(typewriter) => {
|
||||
typewriter.typeString('Mon cher,').start()
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
</p>
|
||||
<p className="font-typewriter text-xl max-w-2xl mx-auto leading-relaxed relative">
|
||||
<span className="invisible" dangerouslySetInnerHTML={{ __html: 'If you find yourself here, you’ve survived the noise.<br />Sit, let the glass sweat a little.<br />The band will start soon, and perhaps someone will meet your eyes before the chorus ends.<br />If not, the night still owes you a dance.' }} />
|
||||
{isClient && (
|
||||
<span className="absolute top-0 left-0">
|
||||
<Typewriter
|
||||
options={{
|
||||
delay: 50,
|
||||
}}
|
||||
onInit={(typewriter) => {
|
||||
typewriter
|
||||
.pauseFor(2000)
|
||||
.typeString(
|
||||
'If you find yourself here, you’ve survived the noise.<br />',
|
||||
)
|
||||
.pauseFor(500)
|
||||
.typeString('Sit, let the glass sweat a little.<br />')
|
||||
.pauseFor(500)
|
||||
.typeString(
|
||||
'The band will start soon, and perhaps someone will meet your eyes before the chorus ends.<br />',
|
||||
)
|
||||
.pauseFor(500)
|
||||
.typeString('If not, the night still owes you a dance.')
|
||||
.start()
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
</p>
|
||||
<p className="font-script text-xl text-love-red mt-6 font-typewriter relative">
|
||||
<span className="invisible">— M.N.</span>
|
||||
{isClient && (
|
||||
<span className="absolute top-0 left-0">
|
||||
<Typewriter
|
||||
onInit={(typewriter) => {
|
||||
typewriter
|
||||
.pauseFor(17000)
|
||||
.typeString('— M.N.')
|
||||
.start()
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
</p>
|
||||
<p className="font-script text-xl text-love-red mt-6 font-typewriter">— M.N.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user