From 7b2566d985578fb2dbf040ae2a9ebaf2199ec351 Mon Sep 17 00:00:00 2001 From: seccodesmith Date: Fri, 23 May 2025 22:19:04 +0200 Subject: [PATCH] feat: enhance ProjectCard and Projects components with new styles and improved structure style: update opacity in Home styles for better visibility refactor: remove unnecessary comments in Projects component for cleaner code --- src/assets/styles/Home.module.scss | 2 +- src/assets/styles/Project.module.scss | 371 ++++++++++++++++++++++++++ src/components/ProjectCard.tsx | 31 +-- src/pages/Blog.tsx | 2 +- src/pages/Projects.tsx | 12 - 5 files changed, 389 insertions(+), 29 deletions(-) create mode 100644 src/assets/styles/Project.module.scss diff --git a/src/assets/styles/Home.module.scss b/src/assets/styles/Home.module.scss index 14129a5..be74f6f 100644 --- a/src/assets/styles/Home.module.scss +++ b/src/assets/styles/Home.module.scss @@ -73,7 +73,7 @@ color: $accent-fire; font-size: 1rem; animation: fall linear infinite; - opacity: 0.8; + opacity: 0.9; } @keyframes fall { diff --git a/src/assets/styles/Project.module.scss b/src/assets/styles/Project.module.scss new file mode 100644 index 0000000..e4b1c75 --- /dev/null +++ b/src/assets/styles/Project.module.scss @@ -0,0 +1,371 @@ +@use './variables' as *; + +.filterContainer { + margin-bottom: 2rem; +} + +.filterButton { + background-color: rgba(255, 255, 255, 0.05); + border: 1px solid $card-border; + color: $text-ash; + padding: 0.5rem 1rem; + margin: 0 0.25rem 0.5rem; + border-radius: 4px; + transition: all 0.3s ease; +} + +.filterButton:hover, +.filterButton.active { + background-color: rgba(255, 100, 0, 0.1); + border-color: rgba(255, 100, 0, 0.3); + color: $accent-fire; +} + +.filterButton.active { + border-color: $accent-fire; +} + +/* Project Cards */ +.card { + background-color: $card-bg; + border: 1px solid $card-border; + border-radius: 8px; + transition: all 0.3s ease; + margin-bottom: 1.5rem; + overflow: hidden; + height: 100%; +} + +.card:hover { + transform: translateY(-10px); + border-color: rgba(255, 100, 0, 0.3); + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4); +} + +.cardImg-top { + height: 200px; + object-fit: cover; +} + +.cardTitle { + font-size: 1.5rem; + margin-bottom: 0.75rem; +} + +.cardText { + color: $text-ash; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + line-height: 1.6; + margin-bottom: 1.5rem; +} + +.featuredCard { + position: relative; +} + +.featuredCard .cardImgTop { + height: 300px; +} + +/* Category badges */ +.categoryBadge { + position: absolute; + top: 1rem; + right: 1rem; + background-color: rgba(139, 0, 0, 0.9); + color: $text-light; + padding: 0.25rem 0.75rem; + border-radius: 4px; + font-size: 0.8rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 1px; + z-index: 1; +} + +.featuredBadge { + position: absolute; + top: 1rem; + left: 1rem; + background: linear-gradient(45deg, $accent-dragon, $accent-fire); + color: $text-light; + padding: 0.25rem 0.75rem; + border-radius: 4px; + font-size: 0.8rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 1px; + display: flex; + align-items: center; + gap: 5px; + z-index: 1; +} + +/* Tech stack */ +.techTitle { + font-size: 0.9rem; + margin-bottom: 0.625rem; + color: $text-ash; + font-family: 'Fira Code', monospace; +} + +.techStack { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-bottom: 1.5rem; +} + +.techItem { + display: inline-flex; + align-items: center; + gap: 6px; + background-color: rgba(255, 255, 255, 0.05); + padding: 5px 10px; + border-radius: 4px; + font-size: 0.8rem; + font-family: 'Fira Code', monospace; + color: $text-ash; + transition: all 0.3s ease; +} + +.techItem:hover { + background-color: rgba(255, 100, 0, 0.1); + color: $accent-fire; + transform: translateY(-2px); +} + +.techIcon { + font-size: 1rem; + color: $accent-fire; +} + +/* Project links */ +.btnOutlineSecondary { + background-color: rgba(255, 255, 255, 0.05); + border-color: $card-border; + color: $text-light; +} + +.btnOutlineSecondary:hover { + background-color: rgba(255, 100, 0, 0.1); + border-color: $accent-fire; + color: $text-light; +} + +.btnIcon { + margin-right: 0.5rem; + color: $accent-fire; +} + +/* View All Button */ +.btnPrimary { + background: linear-gradient(45deg, $accent-dragon, $accent-fire); + border: none; + padding: 0.75rem 2rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 1px; + box-shadow: 0 4px 15px rgba(139, 0, 0, 0.3); + transition: all 0.3s ease; +} + +.btnPrimary:hover { + transform: translateY(-3px); + box-shadow: 0 7px 25px rgba(139, 0, 0, 0.5); + background-color: $accent-fire; + background-image: none; +} + +/* Modal Styling */ +.modalContent { + background-color: $card-bg; + border: 1px solid $card-border; + color: $text-light; +} + +.modalHeader { + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.modalTitle { + color: $text-light; +} + +.modalFooter { + border-top: 1px solid rgba(255, 255, 255, 0.1); +} + +.btnClose { + filter: invert(1) grayscale(100%) brightness(200%); +} + +.featuresList { + padding-left: 1.5rem; + color: $text-ash; +} + +.featuresList li { + margin-bottom: 0.5rem; + position: relative; +} + +.featuresList li::before { + content: "•"; + color: $accent-fire; + position: absolute; + left: -1rem; + top: 0; + font-size: 1.2rem; +} + +.techChip { + display: inline-flex; + align-items: center; + gap: 6px; + background-color: rgba(255, 255, 255, 0.05); + padding: 8px 15px; + border-radius: 20px; + margin-right: 0.5rem; + margin-bottom: 0.5rem; + transition: all 0.3s ease; +} + +.techChip:hover { + background-color: rgba(255, 100, 0, 0.1); + transform: translateY(-3px); +} + +.techChip-icon { + color: $accent-fire; + font-size: 1.1rem; +} + +.techChip-name { + color: $text-ash; + font-size: 0.9rem; + font-family: 'Fira Code', monospace; +} + +.galleryItem { + height: 150px; + border-radius: 8px; + overflow: hidden; + transition: all 0.3s ease; + cursor: pointer; + margin-bottom: 15px; +} + +.galleryItem:hover { + transform: scale(1.05); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); +} + +.galleryImage { + width: 100%; + height: 100%; + object-fit: cover; +} + +/* Binary background effect */ +.binaryLine { + position: absolute; + font-family: 'Fira Code', monospace; + color: $accent-fire; + font-size: 0.8rem; + opacity: 0.15; + pointer-events: none; +} + +/* Ember particle effect */ +.emberParticle { + position: absolute; + width: 3px; + height: 3px; + background-color: $accent-fire; + border-radius: 50%; + opacity: 0.6; + pointer-events: none; + z-index: 2; + box-shadow: 0 0 5px $accent-fire; + animation: float 3s linear infinite; +} + +@keyframes float { + 0% { + transform: translateY(0) rotate(0deg); + opacity: 0.6; + } + + 100% { + transform: translateY(-100px) rotate(360deg); + opacity: 0; + } +} + +/* Footer */ +.footer { + background-color: $primary-dark; + padding: 3rem 0; + border-top: 1px solid rgba(255, 100, 0, 0.2); + margin-top: 3rem; +} + +.socialLinks { + display: flex; + justify-content: center; + gap: 20px; + margin-bottom: 1.5rem; +} + +.socialIcon { + font-size: 1.5rem; + color: $text-ash; + transition: all 0.3s ease; +} + +.socialIcon:hover { + color: $accent-fire; + transform: translateY(-5px); +} + +.copyright { + color: $text-ash; + font-size: 0.9rem; + text-align: center; +} + +/* Responsive adjustments */ +@media (max-width: 992px) { + .pageTitle { + font-size: 2.5rem; + } + + .featuredCard .row { + flex-direction: column; + } +} + +@media (max-width: 768px) { + .pageTitle { + font-size: 2rem; + } + + .techStack { + justify-content: center; + } +} + +@media (max-width: 576px) { + .pageTitle { + font-size: 1.8rem; + } + + .projectLinks { + flex-direction: column; + } + + .projectLinks .btn { + margin-bottom: 0.5rem; + } +} \ No newline at end of file diff --git a/src/components/ProjectCard.tsx b/src/components/ProjectCard.tsx index 6a4f293..fc339ca 100644 --- a/src/components/ProjectCard.tsx +++ b/src/components/ProjectCard.tsx @@ -1,5 +1,7 @@ import { useState } from 'react' +import style from '@styles/Project.module.scss' + export interface ProjectTech { name: string; icon: string; @@ -29,41 +31,40 @@ export const ProjectCard: React.FC = ({ project, onOpenDetails return (
setHovered(true)} onMouseLeave={() => setHovered(false)} >
- {project.title} -
{project.category[0]}
- + {project.title} +
{project.category[0]}
{project.featured && ( -
+
Featured
)}
-
-

{project.title}

-

+

+

{project.title}

+

{project.description}

-

// TECHNOLOGIES_USED

-
+

// TECHNOLOGIES_USED

+
{project.technologies.map((tech, index) => ( - + {tech.name} ))}
-
+
{project.links.github && ( - + View Code )} {project.links.demo && ( - + Live Demo diff --git a/src/pages/Blog.tsx b/src/pages/Blog.tsx index 3e6d1be..63e50af 100644 --- a/src/pages/Blog.tsx +++ b/src/pages/Blog.tsx @@ -7,7 +7,7 @@ import style from '@styles/Blog.module.scss'; export const Blog = () => { const [searchQuery, setSearchQuery] = useState(''); - const [currentPage, setCurrentPage] = useState(1); + const [currentPage, /*setCurrentPage*/] = useState(1); const filteredPosts = searchQuery ? blogPostsData.filter(post => diff --git a/src/pages/Projects.tsx b/src/pages/Projects.tsx index d2e1f0e..faf2fa0 100644 --- a/src/pages/Projects.tsx +++ b/src/pages/Projects.tsx @@ -8,23 +8,18 @@ export const Projects = () => { const [activeFilter, setActiveFilter] = useState('all'); const [selectedProject, setSelectedProject] = useState(null); - // Filter projects based on selected category const filteredProjects = activeFilter === 'all' ? projectsData : projectsData.filter(project => project.category.includes(activeFilter)); - // Get the featured project const featuredProject = projectsData.find(project => project.featured); - // Get regular projects (non-featured) const regularProjects = filteredProjects.filter(project => !project.featured); - // Handle project filter click const handleFilterClick = (filter: string) => { setActiveFilter(filter); }; - // Handle opening project details modal const handleOpenDetails = (id: string) => { const project = projectsData.find(p => p.id === id); if (project) { @@ -32,7 +27,6 @@ export const Projects = () => { } }; - // Handle closing project details modal const handleCloseDetails = () => { setSelectedProject(null); }; @@ -79,16 +73,13 @@ export const Projects = () => {
- {/* Projects Grid */}
- {/* Featured Project */} {featuredProject && (activeFilter === 'all' || featuredProject.category.includes(activeFilter)) && (
)} - {/* Regular Projects */} {regularProjects.map(project => (
@@ -96,14 +87,12 @@ export const Projects = () => { ))}
- {/* No Projects Message */} {filteredProjects.length === 0 && (

No projects found for this category.

)} - {/* View All Button */}
- {/* Project Modal */} {selectedProject && ( )}