@@ -4,101 +4,48 @@ import { useState, useEffect } from 'react'
44import { motion } from 'framer-motion'
55import { usePathname } from 'next/navigation'
66import { getTerminalPath } from '@/lib/utils'
7-
8- // Content to be typed
9- const typingContent = {
10- welcome : "Hi! Welcome to DavidPDonohue.com!!" ,
11- intro : "I'm David, and I'll be your guide as you explore my website!" ,
12- roles : [
13- "Full Stack Web Developer," ,
14- "a Project Manager," ,
15- "an IT Professional," ,
16- "and a human being."
17- ] ,
18- description : "I'm passionate about Healthcare, FinTech, Cybersecurity, Artificial Intelligence and creating elegant, functional solutions that solve real-world problems. Feel free to explore the projects I've worked on, learn about my personal and professional journey, and discover my thoughts on technology and the world beyond tech!"
19- }
7+ import { TYPING_CONFIGS , TypingLine } from '@/lib/typing-config'
208
219export default function HeroSection ( ) {
2210 const pathname = usePathname ( )
2311 const terminalPath = getTerminalPath ( pathname )
2412
25- // State for each line of text
26- const [ welcomeText , setWelcomeText ] = useState ( "" ) ;
27- const [ introText , setIntroText ] = useState ( "" ) ;
28- const [ rolesText , setRolesText ] = useState < string [ ] > ( [ "" , "" , "" , "" ] ) ; // Initialize with 4 empty strings
29- const [ descriptionText , setDescriptionText ] = useState ( "" ) ;
13+ // Get the typing configuration for this page
14+ const typingConfig = TYPING_CONFIGS . home
3015
31- // State to track which element is currently being typed
32- const [ currentTypingIndex , setCurrentTypingIndex ] = useState ( 0 ) ;
16+ // State for each line of text
17+ const [ typedLines , setTypedLines ] = useState < string [ ] > ( new Array ( typingConfig . lines . length ) . fill ( '' ) )
18+ const [ currentLineIndex , setCurrentLineIndex ] = useState ( 0 )
19+ const [ currentCharIndex , setCurrentCharIndex ] = useState ( 0 )
3320
3421 // Typing effect
3522 useEffect ( ( ) => {
36- let timeout : NodeJS . Timeout ;
23+ if ( currentLineIndex >= typingConfig . lines . length ) return
3724
38- // Type welcome text
39- if ( currentTypingIndex === 0 ) {
40- if ( welcomeText . length < typingContent . welcome . length ) {
41- timeout = setTimeout ( ( ) => {
42- setWelcomeText ( typingContent . welcome . slice ( 0 , welcomeText . length + 1 ) ) ;
43- } , 50 ) ; // Adjust speed as needed
44- } else {
45- // Move to next text after a pause
46- timeout = setTimeout ( ( ) => {
47- setCurrentTypingIndex ( 1 ) ;
48- } , 500 ) ;
49- }
50- }
25+ const currentLine = typingConfig . lines [ currentLineIndex ]
26+ const currentLineText = currentLine . content
5127
52- // Type intro text
53- else if ( currentTypingIndex === 1 ) {
54- if ( introText . length < typingContent . intro . length ) {
55- timeout = setTimeout ( ( ) => {
56- setIntroText ( typingContent . intro . slice ( 0 , introText . length + 1 ) ) ;
57- } , 50 ) ;
58- } else {
59- timeout = setTimeout ( ( ) => {
60- setCurrentTypingIndex ( 2 ) ;
61- } , 500 ) ;
62- }
63- }
64-
65- // Type roles text (one by one)
66- else if ( currentTypingIndex >= 2 && currentTypingIndex <= 5 ) { // Changed to 5 to include the 4th role
67- const roleIndex = currentTypingIndex - 2 ;
28+ if ( currentCharIndex < currentLineText . length ) {
29+ const timeout = setTimeout ( ( ) => {
30+ setCurrentCharIndex ( prev => prev + 1 )
31+ setTypedLines ( prev => {
32+ const newLines = [ ...prev ]
33+ newLines [ currentLineIndex ] = currentLineText . slice ( 0 , currentCharIndex + 1 )
34+ return newLines
35+ } )
36+ } , typingConfig . speed )
6837
69- // Check if this role exists
70- if ( roleIndex < typingContent . roles . length ) {
71- const currentRole = typingContent . roles [ roleIndex ] ;
72- const currentTypedRole = rolesText [ roleIndex ] ;
73-
74- if ( currentTypedRole . length < currentRole . length ) {
75- timeout = setTimeout ( ( ) => {
76- const newRolesText = [ ...rolesText ] ;
77- newRolesText [ roleIndex ] = currentRole . slice ( 0 , currentTypedRole . length + 1 ) ;
78- setRolesText ( newRolesText ) ;
79- } , 50 ) ;
80- } else {
81- timeout = setTimeout ( ( ) => {
82- setCurrentTypingIndex ( currentTypingIndex + 1 ) ;
83- } , 500 ) ;
84- }
85- } else {
86- // Move to description if we've finished all roles
87- setCurrentTypingIndex ( 6 ) ; // Changed to 6 since we now have 4 roles
88- }
89- }
90-
91- // Type description text
92- else if ( currentTypingIndex === 6 ) { // Changed to 6
93- if ( descriptionText . length < typingContent . description . length ) {
94- timeout = setTimeout ( ( ) => {
95- setDescriptionText ( typingContent . description . slice ( 0 , descriptionText . length + 1 ) ) ;
96- } , 20 ) ; // Faster typing for longer text
97- }
38+ return ( ) => clearTimeout ( timeout )
39+ } else {
40+ // Line is complete, move to next line after delay
41+ const timeout = setTimeout ( ( ) => {
42+ setCurrentLineIndex ( prev => prev + 1 )
43+ setCurrentCharIndex ( 0 )
44+ } , 1000 )
45+
46+ return ( ) => clearTimeout ( timeout )
9847 }
99-
100- return ( ) => clearTimeout ( timeout ) ;
101- } , [ welcomeText , introText , rolesText , descriptionText , currentTypingIndex ] ) ;
48+ } , [ currentLineIndex , currentCharIndex , typingConfig ] )
10249
10350 return (
10451 < section className = "min-h-screen flex items-center justify-center relative overflow-hidden bg-primary-navy" >
@@ -119,58 +66,22 @@ export default function HeroSection() {
11966 </ div >
12067
12168 { /* Terminal Content */ }
122- < div className = "font-mono text-left space-y-4" >
123- { /* Welcome Text */ }
124- < div className = "text-2xl md:text-3xl lg:text-4xl text-primary-sunset-orange font-bold" >
125- { welcomeText }
126- { welcomeText . length < typingContent . welcome . length && (
127- < span className = "animate-pulse" > ▌</ span >
128- ) }
129- </ div >
130-
131- { /* Intro Text */ }
132- { welcomeText === typingContent . welcome && (
133- < div className = "text-xl text-primary-blue" >
134- { introText }
135- { introText . length < typingContent . intro . length && currentTypingIndex === 1 && (
136- < span className = "animate-pulse" > ▌</ span >
137- ) }
138- </ div >
139- ) }
140-
141- { /* Roles */ }
142- { introText === typingContent . intro && (
143- < div className = "text-xl" >
144- < span className = "text-primary-magenta" > I am a:</ span >
145- < div className = "ml-4 space-y-1" >
146- { rolesText . map ( ( role , index ) => (
147- < div key = { index } className = "text-primary-magenta" >
148- { role }
149- { role . length < ( typingContent . roles [ index ] || '' ) . length && currentTypingIndex === index + 2 && (
150- < span className = "animate-pulse" > ▌</ span >
151- ) }
152- </ div >
153- ) ) }
154- </ div >
155- </ div >
156- ) }
157-
158- { /* Description */ }
159- { rolesText [ 3 ] === typingContent . roles [ 3 ] && ( // Changed to check the 4th role
160- < div className = "text-lg text-primary-blue" >
161- { descriptionText }
162- { descriptionText . length < typingContent . description . length && (
69+ < div className = { typingConfig . containerClassName } >
70+ { typingConfig . lines . map ( ( line , index ) => (
71+ < div key = { line . id } className = { line . className } >
72+ { typedLines [ index ] }
73+ { typedLines [ index ] . length < line . content . length && currentLineIndex === index && (
16374 < span className = "animate-pulse" > ▌</ span >
16475 ) }
16576 </ div >
166- ) }
77+ ) ) }
16778 </ div >
16879 </ div >
16980
17081 { /* Social Links */ }
17182 < motion . div
17283 initial = { { opacity : 0 } }
173- animate = { { opacity : rolesText [ 3 ] === typingContent . roles [ 3 ] ? 1 : 0 } } // Changed to check the 4th role
84+ animate = { { opacity : typedLines [ typingConfig . lines . length - 1 ] === typingConfig . lines [ typingConfig . lines . length - 1 ] . content ? 1 : 0 } }
17485 transition = { { duration : 0.5 } }
17586 className = "flex justify-center gap-6 mt-12"
17687 >
0 commit comments