Skip to content

Commit 460d046

Browse files
author
digin
committed
optimized hero
1 parent 89c6f63 commit 460d046

File tree

1 file changed

+59
-49
lines changed

1 file changed

+59
-49
lines changed

src/components/sections/Hero.jsx

+59-49
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,25 @@
1-
// src/components/sections/Hero.jsx
2-
import React from 'react';
1+
import React, { useState, useEffect } from 'react';
32
import { Link } from 'react-router-dom';
43
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
54
import { faEye, faPaperPlane } from '@fortawesome/free-solid-svg-icons';
65
import { faGithub, faLinkedinIn, faXTwitter } from '@fortawesome/free-brands-svg-icons';
76

87
const Hero = ({ content, loading }) => {
9-
// Render loading state with a layout matching the final content structure
10-
if (loading) {
11-
return (
12-
<section className="hero py-8 md:py-12">
13-
<div className="container px-4 mx-auto">
14-
<div className="hero-content flex flex-col md:flex-row items-center">
15-
<div className="hero-text w-full md:w-3/5 animate-pulse mb-8 md:mb-0">
16-
<div className="h-6 bg-gray-200 rounded w-1/3 mb-4"></div>
17-
<div className="h-12 bg-gray-200 rounded w-3/4 mb-4"></div>
18-
<div className="h-4 bg-gray-200 rounded w-2/3 mb-2"></div>
19-
<div className="h-4 bg-gray-200 rounded w-5/6 mb-2"></div>
20-
<div className="h-4 bg-gray-200 rounded w-4/6 mb-6"></div>
21-
<div className="flex flex-col sm:flex-row gap-4 mb-8">
22-
<div className="h-10 bg-gray-200 rounded-full w-full sm:w-32"></div>
23-
<div className="h-10 bg-gray-200 rounded-full w-full sm:w-32"></div>
24-
</div>
25-
<div className="flex gap-4">
26-
<div className="h-8 w-8 bg-gray-200 rounded-full"></div>
27-
<div className="h-8 w-8 bg-gray-200 rounded-full"></div>
28-
<div className="h-8 w-8 bg-gray-200 rounded-full"></div>
29-
</div>
30-
</div>
31-
32-
<div className="hero-image w-full md:w-2/5 animate-pulse">
33-
<div className="avatar mx-auto md:ml-auto md:mr-0 max-w-xs">
34-
<div className="w-full h-full bg-gray-200 rounded-lg aspect-square"></div>
35-
</div>
36-
</div>
37-
</div>
38-
</div>
39-
</section>
40-
);
41-
}
8+
const [isReady, setIsReady] = useState(false); // Single state to control rendering
429

43-
// Default metadata for static demo
10+
// Default metadata
4411
const defaultMetadata = {
4512
name: 'Digin Dominic',
4613
title: 'Software Engineer | Research Toolsmith | Data Workflow Architect',
47-
subtitle: 'I build powerful tools that bridge science and software. From high-performance image segmentation apps to intuitive 3D data visualizations, I create solutions that turn complex research into accessible, interactive, and scalable applications. Whether its automating microscopy workflows or designing end-to-end pipelines for brain mapping, my work empowers scientists with the right technology—precise, efficient, and beautiful.',
14+
subtitle: 'I build powerful tools that bridge science and software. From high-performance image segmentation apps to intuitive 3D data visualizations, I create solutions that turn complex research into accessible, interactive, and scalable applications. Whether it\'s automating microscopy workflows or designing end-to-end pipelines for brain mapping, my work empowers scientists with the right technology—precise, efficient, and beautiful.',
4815
profileImage: 'https://raw.githubusercontent.com/digin1/web-images/refs/heads/main/digin.png',
4916
primaryCta: 'View My Work',
5017
primaryCtaLink: '/projects',
5118
secondaryCta: 'Contact Me',
5219
secondaryCtaLink: '/about'
5320
};
5421

55-
// Use content from props or fall back to default
5622
const metadata = (content && content.metadata) ? content.metadata : defaultMetadata;
57-
58-
// Extract values from metadata
5923
const {
6024
name = defaultMetadata.name,
6125
title = defaultMetadata.title,
@@ -66,28 +30,72 @@ const Hero = ({ content, loading }) => {
6630
secondaryCta = defaultMetadata.secondaryCta,
6731
secondaryCtaLink = defaultMetadata.secondaryCtaLink,
6832
} = metadata;
69-
70-
// Process subtitle for multiline support
33+
7134
const processedSubtitle = subtitle.replace(/\\n/g, '\n');
7235
const paragraphs = processedSubtitle.split('\n').filter(p => p.trim() !== '');
7336

74-
return (
37+
// Preload image and control rendering
38+
useEffect(() => {
39+
if (!loading) {
40+
const img = new Image();
41+
img.onload = () => setIsReady(true);
42+
img.onerror = () => setIsReady(true); // Fallback to render content even on error
43+
img.src = profileImage;
44+
} else {
45+
setIsReady(false); // Reset when loading starts
46+
}
47+
}, [loading, profileImage]);
48+
49+
const renderLoadingSkeleton = () => (
7550
<section className="hero py-8 md:py-16">
7651
<div className="container px-4 mx-auto">
7752
<div className="hero-content flex flex-col md:flex-row items-center">
7853
<div className="hero-text w-full md:w-3/4 lg:w-3/5 order-2 md:order-1 mt-8 md:mt-0">
79-
<p className="subtitle text-base md:text-base lg:text-lg animate-fadeInUp whitespace-normal break-words leading-normal">{title}</p>
80-
<h1 className="title text-3xl md:text-4xl lg:text-5xl font-bold mt-1 mb-3 animate-fadeInUp delay-100">
54+
<div className="h-6 bg-gray-200 rounded w-1/3 mb-4"></div>
55+
<div className="h-12 bg-gray-200 rounded w-3/4 mb-4"></div>
56+
<div className="space-y-2 mb-6">
57+
<div className="h-4 bg-gray-200 rounded w-full"></div>
58+
<div className="h-4 bg-gray-200 rounded w-5/6"></div>
59+
<div className="h-4 bg-gray-200 rounded w-full"></div>
60+
<div className="h-4 bg-gray-200 rounded w-4/5"></div>
61+
</div>
62+
<div className="flex flex-col sm:flex-row gap-4 mb-8">
63+
<div className="h-10 bg-gray-200 rounded-full w-full sm:w-32"></div>
64+
<div className="h-10 bg-gray-200 rounded-full w-full sm:w-32"></div>
65+
</div>
66+
<div className="flex gap-4">
67+
<div className="h-8 w-8 bg-gray-200 rounded-full"></div>
68+
<div className="h-8 w-8 bg-gray-200 rounded-full"></div>
69+
<div className="h-8 w-8 bg-gray-200 rounded-full"></div>
70+
</div>
71+
</div>
72+
<div className="hero-image w-full md:w-2/5 order-1 md:order-2 mt-8 md:mt-0">
73+
<div className="avatar mx-auto md:ml-auto md:mr-0 max-w-xs">
74+
<div className="w-full h-auto aspect-square bg-gray-200 rounded-lg"></div>
75+
</div>
76+
</div>
77+
</div>
78+
</div>
79+
</section>
80+
);
81+
82+
const renderContent = () => (
83+
<section className="hero py-8 md:py-16">
84+
<div className="container px-4 mx-auto">
85+
<div className="hero-content flex flex-col md:flex-row items-center">
86+
<div className="hero-text w-full md:w-3/4 lg:w-3/5 order-2 md:order-1 mt-8 md:mt-0">
87+
<p className="subtitle text-base md:text-base lg:text-lg whitespace-normal break-words leading-normal">{title}</p>
88+
<h1 className="title text-3xl md:text-4xl lg:text-5xl font-bold mt-1 mb-3">
8189
Building <span className="text-primary">impactful</span> digital solutions
8290
</h1>
83-
<div className="description text-sm md:text-base animate-fadeInUp delay-200">
91+
<div className="description text-sm md:text-base">
8492
{paragraphs.map((paragraph, index) => (
8593
<p key={index} className={index > 0 ? 'mt-4' : ''}>
8694
{paragraph}
8795
</p>
8896
))}
8997
</div>
90-
<div className="flex flex-col sm:flex-row gap-4 mt-6 mb-8 animate-fadeInUp delay-300">
98+
<div className="flex flex-col sm:flex-row gap-4 mt-6 mb-8">
9199
<Link to={primaryCtaLink} className="cta-primary py-2 px-6 rounded-full bg-primary text-white text-center hover:bg-primary-dark transition">
92100
<FontAwesomeIcon icon={faEye} size="sm" className="mr-2" /> {primaryCta}
93101
</Link>
@@ -97,7 +105,7 @@ const Hero = ({ content, loading }) => {
97105
</Link>
98106
)}
99107
</div>
100-
<div className="social-links flex gap-4 animate-fadeInUp delay-400">
108+
<div className="social-links flex gap-4">
101109
<a href="https://github.com/digin1" className="social-link p-2 text-gray-600 hover:text-primary transition">
102110
<FontAwesomeIcon icon={faGithub} size="lg" />
103111
</a>
@@ -109,7 +117,7 @@ const Hero = ({ content, loading }) => {
109117
</a>
110118
</div>
111119
</div>
112-
<div className="hero-image w-full md:w-2/5 order-1 md:order-2 animate-fadeInUp delay-200 mt-8 md:mt-0">
120+
<div className="hero-image w-full md:w-2/5 order-1 md:order-2 mt-8 md:mt-0">
113121
<div className="avatar mx-auto md:ml-auto md:mr-0 max-w-xs">
114122
<img
115123
src={profileImage}
@@ -126,6 +134,8 @@ const Hero = ({ content, loading }) => {
126134
</div>
127135
</section>
128136
);
137+
138+
return loading || !isReady ? renderLoadingSkeleton() : renderContent();
129139
};
130140

131141
export default Hero;

0 commit comments

Comments
 (0)