Skip to content

Commit fc114b4

Browse files
committed
feat: standardize terminal animation font sizes across all pages using Hero section style
1 parent 9e1299d commit fc114b4

File tree

4 files changed

+232
-233
lines changed

4 files changed

+232
-233
lines changed

src/components/sections/AboutSection.tsx

Lines changed: 40 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { motion, AnimatePresence } from 'framer-motion'
66
import Badge from '@/components/ui/Badge'
77
import { usePathname } from 'next/navigation'
88
import { getTerminalPath } from '@/lib/utils'
9+
import { TYPING_CONFIGS } from '@/lib/typing-config'
910

1011
// Define types for our content
1112
interface FavoriteItem {
@@ -156,43 +157,46 @@ export default function AboutSection() {
156157
const pathname = usePathname()
157158
const terminalPath = getTerminalPath(pathname)
158159

159-
const [activeStory, setActiveStory] = useState<string | null>(null);
160-
const [activeCategory, setActiveCategory] = useState<string>("Personal");
160+
// Get the typing configuration for this page
161+
const typingConfig = TYPING_CONFIGS.personal
161162

162-
// Typing animation states
163-
const [greetingText, setGreetingText] = useState("");
164-
const [descriptionText, setDescriptionText] = useState("");
165-
const [currentTypingIndex, setCurrentTypingIndex] = useState(0);
163+
// State for each line of text
164+
const [typedLines, setTypedLines] = useState<string[]>(new Array(typingConfig.lines.length).fill(''))
165+
const [currentLineIndex, setCurrentLineIndex] = useState(0)
166+
const [currentCharIndex, setCurrentCharIndex] = useState(0)
167+
168+
// Additional state for the AboutSection functionality
169+
const [activeStory, setActiveStory] = useState<string | null>(null)
170+
const [activeCategory, setActiveCategory] = useState<string>("Personal")
166171

167172
// Typing effect
168173
useEffect(() => {
169-
let timeout: NodeJS.Timeout;
174+
if (currentLineIndex >= typingConfig.lines.length) return
170175

171-
// Type greeting text
172-
if (currentTypingIndex === 0) {
173-
if (greetingText.length < typingContent.greeting.length) {
174-
timeout = setTimeout(() => {
175-
setGreetingText(typingContent.greeting.slice(0, greetingText.length + 1));
176-
}, 50);
177-
} else {
178-
// Move to next text after a pause
179-
timeout = setTimeout(() => {
180-
setCurrentTypingIndex(1);
181-
}, 500);
182-
}
183-
}
176+
const currentLine = typingConfig.lines[currentLineIndex]
177+
const currentLineText = currentLine.content
184178

185-
// Type description text
186-
else if (currentTypingIndex === 1) {
187-
if (descriptionText.length < typingContent.description.length) {
188-
timeout = setTimeout(() => {
189-
setDescriptionText(typingContent.description.slice(0, descriptionText.length + 1));
190-
}, 20);
191-
}
179+
if (currentCharIndex < currentLineText.length) {
180+
const timeout = setTimeout(() => {
181+
setCurrentCharIndex(prev => prev + 1)
182+
setTypedLines(prev => {
183+
const newLines = [...prev]
184+
newLines[currentLineIndex] = currentLineText.slice(0, currentCharIndex + 1)
185+
return newLines
186+
})
187+
}, typingConfig.speed)
188+
189+
return () => clearTimeout(timeout)
190+
} else {
191+
// Line is complete, move to next line after delay
192+
const timeout = setTimeout(() => {
193+
setCurrentLineIndex(prev => prev + 1)
194+
setCurrentCharIndex(0)
195+
}, 1000)
196+
197+
return () => clearTimeout(timeout)
192198
}
193-
194-
return () => clearTimeout(timeout);
195-
}, [greetingText, descriptionText, currentTypingIndex]);
199+
}, [currentLineIndex, currentCharIndex, typingConfig])
196200

197201
// Helper function to split comma-separated values into arrays
198202
const splitValues = (value: string, label?: string): string[] => {
@@ -229,24 +233,15 @@ export default function AboutSection() {
229233
</div>
230234
</div>
231235

232-
<div className="font-mono text-left">
233-
{/* Greeting Text */}
234-
<div className="text-2xl md:text-3xl text-primary-sunset-orange font-bold mb-4">
235-
{greetingText}
236-
{greetingText.length < typingContent.greeting.length && (
237-
<span className="animate-pulse"></span>
238-
)}
239-
</div>
240-
241-
{/* Description Text */}
242-
{greetingText === typingContent.greeting && (
243-
<div className="text-lg text-primary-blue">
244-
{descriptionText}
245-
{descriptionText.length < typingContent.description.length && (
236+
<div className={typingConfig.containerClassName}>
237+
{typingConfig.lines.map((line, index) => (
238+
<div key={line.id} className={line.className}>
239+
{typedLines[index]}
240+
{typedLines[index].length < line.content.length && currentLineIndex === index && (
246241
<span className="animate-pulse"></span>
247242
)}
248243
</div>
249-
)}
244+
))}
250245
</div>
251246
</div>
252247
</motion.div>

src/components/sections/HeroSection.tsx

Lines changed: 36 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -4,101 +4,48 @@ import { useState, useEffect } from 'react'
44
import { motion } from 'framer-motion'
55
import { usePathname } from 'next/navigation'
66
import { 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

219
export 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

Comments
 (0)