Changes: - hero.tsx: Extended title subtitle to two lines covering all six roles: "Senior IT-Consultant · Service Manager · Technical Writer" (line 1) "KI-Automation Experte · IT-Systems Engineer · Vibe-Coder" (line 2) Uses <br> hidden on mobile, visible on sm+ screens for clean wrapping. - navbar.tsx: Added blogLinks array (Tech-Blog, KI-Blog) rendered after a visual separator (1px divider) in the desktop nav and mobile menu. Each blog link opens in a new tab with rel="noopener noreferrer" and an ExternalLink icon (3px, half-opacity) as a visual cue. Added ExternalLink import from lucide-react. - projects.tsx: Removed leftover `color` field from the "Mailserver & Groupware" entry (cleanup from prior task). Already complete from Task #4 (redesign): - contact.tsx: jh@unixweb.de, blog.unixweb.de, ki-blog.unixweb.de, joachimhummel.de all wired up with correct target="_blank" links. - projects.tsx: SafeDocs Portal (safedocsportal.com) and zensend.email already had url fields and ArrowUpRight link buttons rendering. No address or phone number anywhere on the site. No deviations from scope.
129 lines
5.2 KiB
TypeScript
129 lines
5.2 KiB
TypeScript
import { motion } from "framer-motion";
|
|
import { ArrowUpRight, Lock, Mail, Zap, Database, BarChart2, Server } from "lucide-react";
|
|
|
|
const projects = [
|
|
{
|
|
icon: Lock,
|
|
iconBg: "bg-blue-100 text-blue-600",
|
|
title: "SafeDocs Portal",
|
|
desc: "Sichere Upload-Plattform mit AES-256-GCM-Verschlüsselung, JWT-Auth, Passwort-Reset per E-Mail, Rate Limiting und Docker-Deployment.",
|
|
tags: ["AES-256-GCM", "JWT", "Docker", "Security"],
|
|
url: "https://safedocsportal.com",
|
|
type: "Vibe-Coding Projekt",
|
|
},
|
|
{
|
|
icon: Mail,
|
|
iconBg: "bg-violet-100 text-violet-600",
|
|
title: "zensend.email",
|
|
desc: "Newsletter & E-Mail-Marketing SaaS mit Double-Opt-In, DSGVO-Konformität, SPF/DKIM/DMARC, Zahlungsmodellen und Onboarding-Prozessen.",
|
|
tags: ["SaaS", "DSGVO", "SMTP", "Newsletter"],
|
|
url: "https://zensend.email",
|
|
type: "Vibe-Coding Projekt",
|
|
},
|
|
{
|
|
icon: Zap,
|
|
iconBg: "bg-amber-100 text-amber-600",
|
|
title: "KI-Automation mit n8n",
|
|
desc: "Automatisierte Bildgenerierung, Lead-Prozesse, KI-gestützte Bildprüfung und API/Webhook-Workflows für echte Geschäftsprozesse.",
|
|
tags: ["n8n", "OpenAI", "Webhooks", "Automation"],
|
|
type: "KI-Projekt",
|
|
},
|
|
{
|
|
icon: Database,
|
|
iconBg: "bg-emerald-100 text-emerald-600",
|
|
title: "Eigene KI- & RAG-Systeme",
|
|
desc: "PDF-Verarbeitung, Vektorisierung eigener Dokumente, Pinecone-Integration und eigene Wissensdatenbanken für KI-gestützte Recherche.",
|
|
tags: ["RAG", "Pinecone", "Vektoren", "LLMs"],
|
|
type: "KI-Projekt",
|
|
},
|
|
{
|
|
icon: BarChart2,
|
|
iconBg: "bg-orange-100 text-orange-600",
|
|
title: "On-Premise Monitoring",
|
|
desc: "Vollständige Monitoring-Stacks mit Grafana, Prometheus, Loki und Alloy auf Docker-Basis — transparent, nachvollziehbar, betreibbar.",
|
|
tags: ["Grafana", "Prometheus", "Loki", "Docker"],
|
|
type: "Infrastruktur",
|
|
},
|
|
{
|
|
icon: Server,
|
|
iconBg: "bg-slate-100 text-slate-600",
|
|
title: "Mailserver & Groupware",
|
|
desc: "Betrieb eigener Mailinfrastruktur mit iRedMail, Mailcow, SOGo inklusive vollständiger DNS-Konfiguration, SPF/DKIM/DMARC und Zustellbarkeitsanalyse.",
|
|
tags: ["Mailcow", "SPF/DKIM", "DNS", "IMAP"],
|
|
type: "Infrastruktur",
|
|
},
|
|
];
|
|
|
|
export function Projects() {
|
|
return (
|
|
<div className="py-24">
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true, margin: "-80px" }}
|
|
transition={{ duration: 0.6 }}
|
|
>
|
|
<div className="text-center max-w-2xl mx-auto mb-16">
|
|
<p className="section-number mb-3" data-testid="text-section-label-projects">Ausgewählte Projekte</p>
|
|
<h2 className="text-3xl md:text-4xl font-bold text-foreground mb-4" data-testid="text-section-title-projects">
|
|
Gebaut, deployed, betrieben
|
|
</h2>
|
|
<p className="text-muted-foreground text-lg">
|
|
Reale Systeme — von der sicheren Upload-Plattform bis zur Newsletter-SaaS und eigenen KI-Infrastruktur.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-5">
|
|
{projects.map((project, index) => (
|
|
<motion.div
|
|
key={index}
|
|
initial={{ opacity: 0, y: 16 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.4, delay: index * 0.07 }}
|
|
className="group flex flex-col p-6 rounded-2xl bg-white border border-border card-hover overflow-hidden relative"
|
|
data-testid={`card-project-${index}`}
|
|
>
|
|
<div className="flex items-start justify-between mb-4">
|
|
<div className="flex items-center gap-3">
|
|
<div className={`w-10 h-10 rounded-xl flex items-center justify-center ${project.iconBg}`}>
|
|
<project.icon className="w-5 h-5" />
|
|
</div>
|
|
<span className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">
|
|
{project.type}
|
|
</span>
|
|
</div>
|
|
{project.url && (
|
|
<a
|
|
href={project.url}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="w-8 h-8 rounded-lg bg-secondary flex items-center justify-center text-muted-foreground hover:bg-primary hover:text-white transition-all"
|
|
data-testid={`link-project-${index}`}
|
|
>
|
|
<ArrowUpRight className="w-4 h-4" />
|
|
</a>
|
|
)}
|
|
</div>
|
|
|
|
<h3 className="text-lg font-bold text-foreground mb-2">{project.title}</h3>
|
|
<p className="text-sm text-muted-foreground leading-relaxed mb-5 flex-grow">{project.desc}</p>
|
|
|
|
<div className="flex flex-wrap gap-2">
|
|
{project.tags.map((tag, tIndex) => (
|
|
<span
|
|
key={tIndex}
|
|
className="text-xs font-medium text-foreground/70 bg-secondary px-2.5 py-1 rounded-full border border-border"
|
|
>
|
|
{tag}
|
|
</span>
|
|
))}
|
|
</div>
|
|
</motion.div>
|
|
))}
|
|
</div>
|
|
</motion.div>
|
|
</div>
|
|
);
|
|
}
|