refactoring
This commit is contained in:
parent
d99c0e2429
commit
2169c2994b
|
|
@ -0,0 +1,58 @@
|
|||
import type { Service } from '../data/Service';
|
||||
|
||||
interface FeatureCardsGridProps {
|
||||
featureCards: Service[];
|
||||
}
|
||||
|
||||
export default function FeatureCardsGrid({ featureCards }: FeatureCardsGridProps) {
|
||||
return (
|
||||
<div
|
||||
id="features"
|
||||
className="about-section__features"
|
||||
aria-labelledby="features-heading"
|
||||
>
|
||||
<h3 id="features-heading" className="sr-only">My Areas of Expertise</h3>
|
||||
|
||||
<div className="about-section__features-grid">
|
||||
{featureCards.map((card, index) => {
|
||||
const IconComponent = card.icon;
|
||||
const cardId = card.title.toLowerCase().replaceAll(/\s+/g, '-');
|
||||
return (
|
||||
<article
|
||||
key={cardId}
|
||||
className={`about-section__feature-card about-section__feature-card--${card.colorClass}`}
|
||||
aria-labelledby={`feature-${cardId}-title`}
|
||||
aria-describedby={`feature-${cardId}-description`}
|
||||
>
|
||||
<header className="about-section__feature-header">
|
||||
<IconComponent
|
||||
className={`about-section__feature-icon about-section__feature-icon--${card.colorClass}`}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<h4
|
||||
id={`feature-${cardId}-title`}
|
||||
className={`about-section__feature-title about-section__feature-title--${card.colorClass}`}
|
||||
>
|
||||
{card.title}
|
||||
</h4>
|
||||
</header>
|
||||
<div className="about-section__feature-content">
|
||||
<p
|
||||
id={`feature-${cardId}-description`}
|
||||
className={`about-section__feature-description about-section__feature-description--${card.colorClass}`}
|
||||
>
|
||||
{card.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Status indicator for screen readers */}
|
||||
<div className="sr-only">
|
||||
Expertise area {index + 1} of {featureCards.length}
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { Code, Palette, ShieldCheck, Eye } from 'lucide-react';
|
||||
import { useLanguage } from '../../contexts/LanguageContext';
|
||||
import FeatureCardsGrid from '../FeatureCardsGrid';
|
||||
import type { Service } from '../../data/Service';
|
||||
import saschaImage from '../../assets/sascha.png';
|
||||
|
||||
|
|
@ -28,7 +29,7 @@ export default function AboutSection(props: AboutSectionProps = {}) {
|
|||
icon: [Code, Palette, ShieldCheck, Eye][index] || Code,
|
||||
title: card.title,
|
||||
description: card.description,
|
||||
colorClass: ["primary", "secondary", "tertiary", "quaternary"][index] || "primary"
|
||||
colorClass: (["primary", "secondary", "tertiary", "quaternary"][index] || "primary") as "primary" | "secondary" | "tertiary" | "quaternary"
|
||||
}))
|
||||
} = props;
|
||||
|
||||
|
|
@ -79,54 +80,7 @@ export default function AboutSection(props: AboutSectionProps = {}) {
|
|||
</main>
|
||||
|
||||
{/* Feature Cards Grid */}
|
||||
<div
|
||||
id="features"
|
||||
className="about-section__features"
|
||||
aria-labelledby="features-heading"
|
||||
>
|
||||
<h3 id="features-heading" className="sr-only">My Areas of Expertise</h3>
|
||||
|
||||
<div className="about-section__features-grid">
|
||||
{featureCards.map((card, index) => {
|
||||
const IconComponent = card.icon;
|
||||
const cardId = card.title.toLowerCase().replaceAll(/\s+/g, '-');
|
||||
return (
|
||||
<article
|
||||
key={cardId}
|
||||
className={`about-section__feature-card about-section__feature-card--${card.colorClass}`}
|
||||
aria-labelledby={`feature-${cardId}-title`}
|
||||
aria-describedby={`feature-${cardId}-description`}
|
||||
>
|
||||
<header className="about-section__feature-header">
|
||||
<IconComponent
|
||||
className={`about-section__feature-icon about-section__feature-icon--${card.colorClass}`}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<h4
|
||||
id={`feature-${cardId}-title`}
|
||||
className={`about-section__feature-title about-section__feature-title--${card.colorClass}`}
|
||||
>
|
||||
{card.title}
|
||||
</h4>
|
||||
</header>
|
||||
<div className="about-section__feature-content">
|
||||
<p
|
||||
id={`feature-${cardId}-description`}
|
||||
className={`about-section__feature-description about-section__feature-description--${card.colorClass}`}
|
||||
>
|
||||
{card.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Status indicator for screen readers */}
|
||||
<div className="sr-only">
|
||||
Expertise area {index + 1} of {featureCards.length}
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<FeatureCardsGrid featureCards={featureCards} />
|
||||
</div>
|
||||
</section >
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { Award } from 'lucide-react';
|
||||
import { useLanguage } from '../../contexts/LanguageContext';
|
||||
import { certificationsData } from '../../config/certifications-config';
|
||||
import type { Certification } from '../../data/Certification';
|
||||
|
||||
interface CertificationsSectionProps {
|
||||
|
|
@ -17,12 +18,7 @@ export default function CertificationsSection(props: CertificationsSectionProps
|
|||
const {
|
||||
title = texts.title,
|
||||
subtitle = texts.subtitle,
|
||||
certifications = texts.certificationItems.map((cert, index) => ({
|
||||
name: cert.name,
|
||||
issuer: cert.issuer,
|
||||
year: ["2025", "2025", "2020", "2020", "2015"][index] || "2025",
|
||||
icon: ""
|
||||
}))
|
||||
certifications = certificationsData
|
||||
} = props;
|
||||
|
||||
// Sort certifications by year in descending order (newest first)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
import { certifications } from './locales/en/certifications';
|
||||
import type { Certification } from '../data/Certification';
|
||||
|
||||
const getCertificationText = (id: number) => {
|
||||
const item = certifications.certificationItems.find(c => c.id === id);
|
||||
if (!item) throw new Error(`Certification with id ${id} not found`);
|
||||
return item;
|
||||
};
|
||||
|
||||
export const certificationsData: Certification[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: getCertificationText(1).name,
|
||||
issuer: getCertificationText(1).issuer,
|
||||
year: '2025',
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: getCertificationText(2).name,
|
||||
issuer: getCertificationText(2).issuer,
|
||||
year: '2025',
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: getCertificationText(3).name,
|
||||
issuer: getCertificationText(3).issuer,
|
||||
year: '2020',
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: getCertificationText(4).name,
|
||||
issuer: getCertificationText(4).issuer,
|
||||
year: '2020',
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: getCertificationText(5).name,
|
||||
issuer: getCertificationText(5).issuer,
|
||||
year: '2015',
|
||||
icon: '',
|
||||
},
|
||||
].sort((a, b) => Number.parseInt(b.year) - Number.parseInt(a.year));
|
||||
|
|
@ -3,22 +3,27 @@ export const certifications = {
|
|||
subtitle: 'Meine beruflichen Qualifikationen und kontinuierliche Weiterbildung',
|
||||
certificationItems: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Practical Prompt Engineering Masterclass: Hands-On Learning',
|
||||
issuer: 'Udemy Kurs - Asif Farooqi, Abdullah Dar',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Understanding Typescript',
|
||||
issuer: 'Udemy Kurs - Maximilian Schwarzmüller',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Angular Step by Step',
|
||||
issuer: 'Udemy Kurs - Shivprasad Koirala',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Angular and Typescript',
|
||||
issuer: 'LinkedIn TestDome',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Bachelor of Science in Informatik',
|
||||
issuer: 'TU Darmstadt',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,22 +3,27 @@ export const certifications = {
|
|||
subtitle: 'My professional qualifications and continuous learning',
|
||||
certificationItems: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Practical Prompt Engineering Masterclass: Hands-On Learning',
|
||||
issuer: 'Udemy Lecture - Asif Farooqi, Abdullah Dar',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Understanding Typescript',
|
||||
issuer: 'Udemy Lecture - Maximilian Schwarzmüller',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Angular Step by Step',
|
||||
issuer: 'Udemy Lecture - Shivprasad Koirala',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Angular and Typescript',
|
||||
issuer: 'LinkedIn TestDome',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Bachelor of Science in Computer Science',
|
||||
issuer: 'TU Darmstadt',
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue