Skip to content

Commit 4469766

Browse files
committed
added image previews and removed buggy animation
1 parent 721f2af commit 4469766

File tree

2 files changed

+310
-198
lines changed

2 files changed

+310
-198
lines changed

generator.py

Lines changed: 46 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@
8686
"title": "PyAerial",
8787
"description": "A better plane tracker for AERPAW, successor to airstrik.py.",
8888
"link": "https://github.com/quantumbagel/PyAerial",
89-
"skills": ["Python", "MavSDK", "Docker", "MongoDB", "ADS-B"]
89+
"skills": ["Python", "MavSDK", "Docker", "MongoDB", "ADS-B"],
90+
"hover_image": "https://quantumbagel.github.io/PyAerial/social-preview.png"
9091
},
9192
{
9293
"category": "internship",
@@ -206,30 +207,56 @@ def generate_skill_bar(skill):
206207

207208

208209
def generate_project_card(project):
209-
"""Generates a single project card."""
210-
# Generate skill pills
210+
"""
211+
Generates a single project card with advanced hover effects.
212+
213+
Expects a project dictionary with keys: 'category', 'image',
214+
'hover_image', 'title', 'description', 'skills', and 'link'.
215+
"""
216+
# Gracefully handle projects that may not have a hover image
217+
# It will use the main image as a fallback to prevent errors
218+
hover_image_src = project.get('hover_image', project.get('image'))
219+
220+
# Generate HTML for skill pills if they exist
211221
skills_html = ""
212222
if project.get("skills"):
213223
pills_html = "".join([
214-
f'<span class="inline-block bg-gray-200 dark:bg-gray-600 text-gray-700 dark:text-gray-300 text-xs font-medium mr-2 mb-2 px-3 py-1 rounded-full">{skill}</span>'
215-
for skill in project['skills']])
224+
f'<span class="inline-block bg-gray-200 dark:bg-gray-600 text-gray-700 dark:text-gray-300 text-xs font-medium mr-2 mb-2 px-3 py-1 rounded-full">{skill}</span>'
225+
for skill in project['skills']
226+
])
216227
skills_html = f'<div class="flex flex-wrap mt-4">{pills_html}</div>'
217228

218-
return f"""
219-
<div class="project-card {project['category']}">
220-
<div class="bg-gray-50 dark:bg-gray-700/50 rounded-lg overflow-hidden group transform hover:scale-105 transition-transform duration-300 shadow-md hover:shadow-2xl flex flex-col h-full">
221-
<img src="{project['image']}" class="w-full h-48 object-cover" alt="{project['title']} Project">
222-
<div class="p-6 flex flex-col flex-grow">
223-
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-2">{project['title']}</h3>
224-
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4 flex-grow">{project['description']}</p>
225-
<div class="mt-auto">
226-
{skills_html}
227-
{'<a href="' + project['link'] + '" class="text-blue-500 font-semibold hover:underline mt-4 inline-block">View Project &rarr;</a>"' if project['link'] is not None else ""}
228-
</div>
229-
</div>
230-
</div>
231-
</div>"""
229+
# Generate HTML for the link if it exists
230+
link_html = ""
231+
if project.get("link"):
232+
link_html = f'<a href="{project["link"]}" class="text-blue-500 font-semibold hover:underline mt-4 inline-block">View Project &rarr;</a>'
232233

234+
# Return the complete card HTML using an f-string
235+
return f"""
236+
<div class="project-card {project.get('category', 'other')} group relative hover:z-10">
237+
<div class="bg-gray-50 dark:bg-gray-700/50 rounded-lg overflow-hidden transform group-hover:scale-110 transition-transform duration-300 shadow-md hover:shadow-2xl flex flex-col h-full">
238+
239+
<div class="relative h-48 transition-all duration-300 overflow-hidden bg-gray-100 dark:bg-gray-800">
240+
<img src="{project.get('image')}"
241+
class="absolute w-full h-full object-cover transition-transform duration-300 group-hover:scale-110 flex items-center justify-center text-gray-500 dark:text-gray-400"
242+
alt="{project.get('title')} Project">
243+
244+
<img src="{hover_image_src}"
245+
class="absolute w-full h-full object-cover opacity-0 transition-all duration-300 group-hover:opacity-100 group-hover:scale-110 flex items-center justify-center text-gray-500 dark:text-gray-400"
246+
alt="{project.get('title')} Preview">
247+
</div>
248+
249+
<div class="p-6 flex flex-col flex-grow">
250+
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-2">{project.get('title')}</h3>
251+
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4 flex-grow">{project.get('description')}</p>
252+
<div class="mt-auto">
253+
{skills_html}
254+
{link_html}
255+
</div>
256+
</div>
257+
</div>
258+
</div>
259+
"""
233260

234261
def create_html_structure():
235262
"""Builds the final HTML file content by assembling all components."""
@@ -300,9 +327,6 @@ def create_html_structure():
300327
color: #000000 !important;
301328
background-color: #EFF6FF;
302329
}}
303-
.skill-bar-fill {{
304-
transition: width 0.8s ease-in-out;
305-
}}
306330
</style>
307331
</head>
308332
<body class="bg-gray-100 dark:bg-gray-900 text-gray-800 dark:text-gray-200">
@@ -502,21 +526,6 @@ def create_html_structure():
502526
503527
window.addEventListener('scroll', handleEdgeCases);
504528
handleEdgeCases(); // Run once on load to set the correct initial state
505-
506-
// Animate skill bars on scroll (This part remains the same)
507-
const skillsSection = document.getElementById('skills');
508-
const skillBars = document.querySelectorAll('.skill-bar-fill');
509-
const skillObserver = new IntersectionObserver((entries) => {{ entries.forEach(entry => {{ if (entry.isIntersecting) {{ skillBars.forEach(bar => {{ const width = bar.style.width;
510-
bar.style.width = '0%';
511-
setTimeout(() => {{ bar.style.width = width;
512-
}}, 100);
513-
}});
514-
skillObserver.unobserve(skillsSection);
515-
}}
516-
}});
517-
}}, {{ threshold: 0.5 }});
518-
if (skillsSection) {{ skillObserver.observe(skillsSection);
519-
}}
520529
}});
521530
</script>
522531
</body>

0 commit comments

Comments
 (0)