feat: refactor BlogCard, ProjectCard, and ProjectModal components to use new type definitions and improve structure
This commit is contained in:
@@ -1,21 +1,7 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import styles from '@styles/BlogCard.module.scss';
|
||||
|
||||
export interface BlogPostProps {
|
||||
id: string;
|
||||
slug: string;
|
||||
title: string;
|
||||
excerpt: string;
|
||||
image: string;
|
||||
category: string;
|
||||
date: string;
|
||||
author: string;
|
||||
commentCount: number;
|
||||
readTime: string;
|
||||
featured?: boolean;
|
||||
tags: string[];
|
||||
content: string;
|
||||
}
|
||||
import type {BlogPostProps} from '../untils/BlogPostProps';
|
||||
|
||||
interface BlogCardProps {
|
||||
post: BlogPostProps;
|
||||
|
||||
@@ -1,32 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
import style from '@styles/Project.module.scss'
|
||||
|
||||
export interface ProjectTech {
|
||||
name: string;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
export interface ProjectProps {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
image: string;
|
||||
category: Category[];
|
||||
featured?: boolean;
|
||||
technologies: ProjectTech[];
|
||||
links: {
|
||||
github?: string;
|
||||
demo?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Category {
|
||||
[key: string]: string;
|
||||
fullName: string;
|
||||
shortName: string;
|
||||
icon: string;
|
||||
}
|
||||
import type {ProjectTech, Category, ProjectProps } from '../untils/ProjectProps'
|
||||
|
||||
interface ProjectCardProps {
|
||||
project: ProjectProps;
|
||||
|
||||
+149
-137
@@ -1,154 +1,166 @@
|
||||
import type { ProjectProps } from './ProjectCard';
|
||||
import type { ProjectProps } from '../untils/ProjectProps';
|
||||
|
||||
import style from '@styles/Project.module.scss'
|
||||
|
||||
|
||||
interface ProjectModalProps {
|
||||
project: ProjectProps | null;
|
||||
project: ProjectProps | null;
|
||||
}
|
||||
|
||||
export const ProjectModal: React.FC<ProjectModalProps> = ({ project }) => {
|
||||
if (!project) return null;
|
||||
if (!project) return null;
|
||||
|
||||
return (
|
||||
<div className="modal fade" id="shadowguardianModal" tabIndex={-1} aria-labelledby="shadowguardianModalLabel" aria-hidden="true">
|
||||
<div className="modal-dialog modal-xl modal-dialog-scrollable">
|
||||
<div className={`modal-content ${style.modalContent}`}>
|
||||
<div className="modal-header">
|
||||
<h5 className={style.modalHeader} id="shadowguardianModalLabel">
|
||||
{project.title}
|
||||
</h5>
|
||||
<button type="button" className={`btn-close ${style.btnClose}`} data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div className={`modal-body ${style.modalBody}`}>
|
||||
<div className="mb-4">
|
||||
<img src="/api/placeholder/1000/400" className="img-fluid rounded mb-3" alt="ShadowGuardian Project" />
|
||||
<div className="row">
|
||||
<div className="col-md-8">
|
||||
<p>ShadowGuardian is a comprehensive security monitoring system designed for both residential and commercial applications. Built on a foundation of STM32 microcontrollers, it provides reliable, secure monitoring with extremely low power consumption, allowing for battery operation of up to 2 years.</p>
|
||||
<p>The system features end-to-end encryption for all communications, ensuring that sensitive security data remains private. Its modular architecture allows for easy expansion with additional sensors and integration with existing home automation systems.</p>
|
||||
</div>
|
||||
<div className="col-md-4">
|
||||
<div className="card h-100">
|
||||
<div className="card-header">
|
||||
<h5 className="mb-0">Project Overview</h5>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<p><strong>Duration:</strong> 6 months</p>
|
||||
<p><strong>Role:</strong> Lead Developer</p>
|
||||
<p><strong>Status:</strong> Completed</p>
|
||||
<p><strong>Client:</strong> ConnectedWorld Technologies</p>
|
||||
return (
|
||||
<div className="modal fade" id="shadowguardianModal" tabIndex={-1} aria-labelledby="shadowguardianModalLabel" aria-hidden="true">
|
||||
<div className="modal-dialog modal-xl modal-dialog-scrollable">
|
||||
<div className={`modal-content ${style.modalContent}`}>
|
||||
<div className={`modal-header ${style.modalHeader}`}>
|
||||
<h5 className={style.modalHeader} id="shadowguardianModalLabel">
|
||||
{project.title}
|
||||
</h5>
|
||||
<button type="button" className={`btn-close ${style.btnClose}`} data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div className={`modal-body ${style.modalBody}`}>
|
||||
<div className="mb-4">
|
||||
<img src={project.image} className="img-fluid rounded mb-3" alt={project.title} />
|
||||
<div className={`row ${style.row}`}>
|
||||
<div className="col-md-8">
|
||||
{
|
||||
project.projectDetails ? project.projectDetails.descriptions.map((desc, index) => (
|
||||
<p key={index} className="mb-3">{desc}</p>
|
||||
)) :
|
||||
<p>{project.description}</p>
|
||||
}
|
||||
</div>
|
||||
<div className="col-md-4">
|
||||
<div className={`card h-100 ${style.card}`}>
|
||||
<div className={`card-header ${style.cardHeader}`}>
|
||||
<h5 className="mb-0">Project Overview</h5>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
{project.projectDetails && project.projectDetails.startDate && project.projectDetails.endDate ? (
|
||||
<p><strong>Duration:</strong> {new Date(project.projectDetails.startDate).toLocaleDateString()} - {new Date(project.projectDetails.endDate).toLocaleDateString()}</p>
|
||||
) : (
|
||||
<p><strong>Duration:</strong> Ongoing</p>
|
||||
)
|
||||
}
|
||||
{
|
||||
project.projectDetails && project.projectDetails.role ? (
|
||||
<p><strong>Role:</strong> {project.projectDetails.role}</p>
|
||||
) : (
|
||||
<p><strong>Role:</strong> Developer</p>
|
||||
)
|
||||
}
|
||||
{
|
||||
project.projectDetails && project.projectDetails.client ? (
|
||||
<p><strong>Client:</strong> {project.projectDetails.client}</p>
|
||||
) : (
|
||||
<p><strong>Client:</strong> Internal Project</p>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{
|
||||
project.projectDetails?.keyFeatures && project.projectDetails.keyFeatures.length > 0 && (
|
||||
<>
|
||||
<h4 className="mt-4 mb-3">Key Features</h4>
|
||||
{
|
||||
project.projectDetails?.keyFeatures.map((feature, index) => (
|
||||
<p key={index} className="mb-2">
|
||||
<i className="fas fa-check-circle text-success me-2"></i>
|
||||
{feature}
|
||||
</p>
|
||||
))
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 className="mt-4 mb-3">Technologies Used</h4>
|
||||
<div className="mb-4">
|
||||
<span className="tech-chip">
|
||||
<i className="devicon-cplusplus-plain tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">C++</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="fas fa-microchip tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">STM32F4</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="fas fa-wifi tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">ESP32</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="fas fa-shield-alt tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">AES-256</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="devicon-react-original tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">React Native</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="fas fa-broadcast-tower tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">BLE 5.0</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="fas fa-network-wired tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">Zigbee</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="fas fa-server tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">Node.js</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="fas fa-database tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">PostgreSQL</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="devicon-docker-plain tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">Docker</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{
|
||||
project.projectDetails?.gallery && project.projectDetails?.gallery.length > 0 && (
|
||||
<>
|
||||
<h4 className="mt-4 mb-3">Gallery</h4>
|
||||
<div className="row">
|
||||
<div className="col-md-4 col-6">
|
||||
{
|
||||
project.projectDetails.gallery.map((image, index) => (
|
||||
<div key={index} className="gallery-item">
|
||||
<img src={image} alt={`Gallery Image ${index + 1}`} className="gallery-image"></img>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<div className={`modal-footer ${style.modalFooter}`}>
|
||||
<a href="#" className={`btn btn-outline-secondary ${style.btnOutlineSecondary}`}>
|
||||
<i className="fab fa-github btn-icon"></i>Source Code
|
||||
</a>
|
||||
<a href="#" className={`btn btn-outline-secondary ${style.btnOutlineSecondary}`}>
|
||||
<i className="fas fa-external-link-alt btn-icon"></i>Live Demo
|
||||
</a>
|
||||
<a href="#" className={`btn btn-outline-secondary ${style.btnOutlineSecondary}`}>
|
||||
<i className="fas fa-book btn-icon"></i>Documentation
|
||||
</a>
|
||||
<button type="button" className={`btn btn-secondary`} data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 className="mt-4 mb-3">Key Features</h4>
|
||||
<ul className="features-list">
|
||||
<li>Military-grade AES-256 encryption for all data transmission</li>
|
||||
<li>Ultra-low power consumption with intelligent sleep modes</li>
|
||||
<li>Modular sensor architecture supporting motion, contact, glass-break, and environmental sensors</li>
|
||||
<li>Local processing to reduce cloud dependency and improve response times</li>
|
||||
<li>Mesh networking for extended coverage without Wi-Fi dependencies</li>
|
||||
<li>Real-time notifications via mobile app (iOS and Android)</li>
|
||||
<li>Integration with popular home automation platforms including HomeKit, Google Home, and Alexa</li>
|
||||
<li>Tamper detection and notification system</li>
|
||||
<li>Optional cellular backup connection for critical deployments</li>
|
||||
</ul>
|
||||
|
||||
<h4 className="mt-4 mb-3">Technologies Used</h4>
|
||||
<div className="mb-4">
|
||||
<span className="tech-chip">
|
||||
<i className="devicon-cplusplus-plain tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">C++</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="fas fa-microchip tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">STM32F4</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="fas fa-wifi tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">ESP32</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="fas fa-shield-alt tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">AES-256</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="devicon-react-original tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">React Native</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="fas fa-broadcast-tower tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">BLE 5.0</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="fas fa-network-wired tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">Zigbee</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="fas fa-server tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">Node.js</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="fas fa-database tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">PostgreSQL</span>
|
||||
</span>
|
||||
<span className="tech-chip">
|
||||
<i className="devicon-docker-plain tech-chip-icon"></i>
|
||||
<span className="tech-chip-name">Docker</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h4 className="mt-4 mb-3">Gallery</h4>
|
||||
<div className="row">
|
||||
<div className="col-md-4 col-6">
|
||||
<div className="gallery-item">
|
||||
<img src="/api/placeholder/300/300" alt="ShadowGuardian Hub" className="gallery-image"></img>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-4 col-6">
|
||||
<div className="gallery-item">
|
||||
<img src="/api/placeholder/300/300" alt="ShadowGuardian Sensor" className="gallery-image"></img>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-4 col-6">
|
||||
<div className="gallery-item">
|
||||
<img src="/api/placeholder/300/300" alt="Mobile App Dashboard" className="gallery-image" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-4 col-6">
|
||||
<div className="gallery-item">
|
||||
<img src="/api/placeholder/300/300" alt="Door Sensor Installation" className="gallery-image" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-4 col-6">
|
||||
<div className="gallery-item">
|
||||
<img src="/api/placeholder/300/300" alt="System Architecture Diagram" className="gallery-image" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-4 col-6">
|
||||
<div className="gallery-item">
|
||||
<img src="/api/placeholder/300/300" alt="PCB Design" className="gallery-image" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`modal-footer ${style.modalFooter}`}>
|
||||
<a href="#" className={`btn btn-outline-secondary ${style.btnOutlineSecondary}`}>
|
||||
<i className="fab fa-github btn-icon"></i>Source Code
|
||||
</a>
|
||||
<a href="#" className={`btn btn-outline-secondary ${style.btnOutlineSecondary}`}>
|
||||
<i className="fas fa-external-link-alt btn-icon"></i>Live Demo
|
||||
</a>
|
||||
<a href="#" className={`btn btn-outline-secondary ${style.btnOutlineSecondary}`}>
|
||||
<i className="fas fa-book btn-icon"></i>Documentation
|
||||
</a>
|
||||
<button type="button" className={`btn btn-secondary`} data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { BlogPostProps } from "../components/BlogCard";
|
||||
import type {BlogPostProps} from '../untils/BlogPostProps'
|
||||
|
||||
export const blogPostsData: BlogPostProps[] = [
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ProjectProps, Category } from "../components/ProjectCard";
|
||||
import type { ProjectProps, Category } from "../untils/ProjectProps";
|
||||
|
||||
type CategoryMap = Record<string, Category>
|
||||
export const Categories: CategoryMap = {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useState } from 'react';
|
||||
import { PageHeader } from '../components/PageHeader';
|
||||
import { ProjectCard, type ProjectProps } from '../components/ProjectCard';
|
||||
import { ProjectCard } from '../components/ProjectCard';
|
||||
import { ProjectModal } from '../components/ProjectModal';
|
||||
import { projectsData, Categories } from '../data/projectsData';
|
||||
import type {ProjectProps} from '../untils/ProjectProps';
|
||||
|
||||
import style from '@styles/Project.module.scss'
|
||||
|
||||
@@ -15,6 +16,10 @@ export const Projects = () => {
|
||||
? projectsData
|
||||
: projectsData.filter(project => project.category.some(cat => cat.shortName.toLowerCase() === activeFilter));
|
||||
|
||||
|
||||
if (selectedProject == null && filteredProjects.length > 0)
|
||||
setSelectedProject(filteredProjects[0]);
|
||||
|
||||
const categories = Categories;
|
||||
|
||||
const featuredProject = projectsData.find(project => project.featured);
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
export interface BlogPostProps {
|
||||
id: string;
|
||||
slug: string;
|
||||
title: string;
|
||||
excerpt: string;
|
||||
image: string;
|
||||
category: string;
|
||||
date: string;
|
||||
author: string;
|
||||
commentCount: number;
|
||||
readTime: string;
|
||||
featured?: boolean;
|
||||
tags: string[];
|
||||
content: string;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
export interface ProjectProps {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
projectDetails?: ProjectDetails;
|
||||
image: string;
|
||||
category: Category[];
|
||||
featured?: boolean;
|
||||
technologies: ProjectTech[];
|
||||
links: {
|
||||
github?: string;
|
||||
demo?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ProjectDetails {
|
||||
descriptions: string[];
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
dateFormatted?: string;
|
||||
role: string;
|
||||
status: string;
|
||||
client: string;
|
||||
keyFeatures: string[];
|
||||
gallery: string[];
|
||||
}
|
||||
|
||||
export interface Category {
|
||||
[key: string]: string;
|
||||
fullName: string;
|
||||
shortName: string;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
export interface ProjectTech {
|
||||
name: string;
|
||||
icon: string;
|
||||
}
|
||||
Reference in New Issue
Block a user