Files
Portfolio/src/components-vite/ProjectShowcase.tsx
T
damjan_savicandClaude Opus 4.5 b1ec7b4d61 Migrate from Vite to Next.js 15 with SSR
- Replace Vite + React Router with Next.js 15 App Router
- Implement i18n with next-intl (URL-based: /de, /en, /sr)
- Add SSR/SSG for all pages (48 static pages generated)
- Setup Supabase SSR client for auth
- Migrate all pages: Home, About, Portfolio, Blog, Contact, Login, Dashboard, Imprint, Privacy, Terms
- Add Docker support with standalone output
- Replace i18next with next-intl JSON translations
- Use next/image for optimized images

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 01:00:33 +01:00

161 lines
6.1 KiB
TypeScript

import React from 'react';
import { ExternalLink, Github, Globe, Zap, TrendingUp, Users } from 'lucide-react';
import { ProjectSchema } from './schemas/ProjectSchema';
interface ProjectShowcaseProps {
project: {
id: string;
title: string;
description: string;
technicalChallenge: string;
businessImpact: {
roi?: string;
performanceGain?: string;
usersImpacted?: string;
};
technologies: string[];
category: string;
dateCreated: string;
liveUrl?: string;
githubUrl?: string;
screenshotUrl?: string;
features: string[];
codeExample?: string;
};
}
export function ProjectShowcase({ project }: ProjectShowcaseProps) {
return (
<article className="project-showcase bg-zinc-900 rounded-lg overflow-hidden">
<ProjectSchema project={project} />
{/* Hero Section with Screenshot */}
{project.screenshotUrl && (
<div className="relative aspect-video">
<img
src={project.screenshotUrl}
alt={`Screenshot of ${project.title}`}
className="w-full h-full object-cover"
loading="lazy"
/>
<div className="absolute inset-0 bg-gradient-to-t from-zinc-900 via-transparent to-transparent" />
</div>
)}
<div className="p-8 space-y-8">
{/* Title and Description */}
<header>
<h2 className="text-3xl font-bold text-white mb-4">{project.title}</h2>
<p className="text-lg text-zinc-300 leading-relaxed">{project.description}</p>
</header>
{/* For Recruiters: Technical Challenge */}
<section className="technical-challenge">
<div className="flex items-center gap-2 mb-3">
<Zap className="h-5 w-5 text-blue-500" />
<h3 className="text-xl font-semibold text-white">Technical Challenge</h3>
</div>
<p className="text-zinc-300 bg-zinc-800/50 p-4 rounded-lg border border-zinc-700">
{project.technicalChallenge}
</p>
</section>
{/* For Clients: Business Impact */}
<section className="business-impact">
<div className="flex items-center gap-2 mb-3">
<TrendingUp className="h-5 w-5 text-green-500" />
<h3 className="text-xl font-semibold text-white">Business Impact</h3>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{project.businessImpact.roi && (
<div className="bg-zinc-800/50 p-4 rounded-lg border border-zinc-700">
<p className="text-sm text-zinc-400 mb-1">ROI</p>
<p className="text-2xl font-bold text-green-400">{project.businessImpact.roi}</p>
</div>
)}
{project.businessImpact.performanceGain && (
<div className="bg-zinc-800/50 p-4 rounded-lg border border-zinc-700">
<p className="text-sm text-zinc-400 mb-1">Performance</p>
<p className="text-2xl font-bold text-blue-400">{project.businessImpact.performanceGain}</p>
</div>
)}
{project.businessImpact.usersImpacted && (
<div className="bg-zinc-800/50 p-4 rounded-lg border border-zinc-700">
<p className="text-sm text-zinc-400 mb-1">Users Impacted</p>
<p className="text-2xl font-bold text-purple-400">{project.businessImpact.usersImpacted}</p>
</div>
)}
</div>
</section>
{/* Technology Stack with Keywords */}
<section className="tech-stack">
<h3 className="text-xl font-semibold text-white mb-3">Technologies Used</h3>
<div className="flex flex-wrap gap-2">
{project.technologies.map(tech => (
<span
key={tech}
className="tech-tag px-3 py-1 bg-zinc-800 border border-zinc-700 text-zinc-300 rounded-full text-sm hover:border-zinc-600 transition-colors"
>
{tech}
</span>
))}
</div>
</section>
{/* Key Features */}
{project.features && project.features.length > 0 && (
<section className="features">
<h3 className="text-xl font-semibold text-white mb-3">Key Features</h3>
<ul className="space-y-2">
{project.features.map((feature, index) => (
<li key={index} className="flex items-start gap-2">
<span className="text-blue-500 mt-0.5"></span>
<span className="text-zinc-300">{feature}</span>
</li>
))}
</ul>
</section>
)}
{/* Code Quality Showcase */}
{project.codeExample && (
<section className="code-showcase">
<h3 className="text-xl font-semibold text-white mb-3">Code Example</h3>
<pre className="bg-zinc-950 p-4 rounded-lg overflow-x-auto border border-zinc-800">
<code className="text-sm text-zinc-300 font-mono">
{project.codeExample}
</code>
</pre>
</section>
)}
{/* Links */}
<div className="project-links flex gap-4 pt-4">
{project.liveUrl && (
<a
href={project.liveUrl}
rel="noopener noreferrer"
target="_blank"
className="flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors"
>
<Globe className="h-4 w-4" />
View Live Project
</a>
)}
{project.githubUrl && (
<a
href={project.githubUrl}
rel="noopener noreferrer"
target="_blank"
className="flex items-center gap-2 px-4 py-2 bg-zinc-800 hover:bg-zinc-700 text-white border border-zinc-700 rounded-lg transition-colors"
>
<Github className="h-4 w-4" />
View on GitHub
</a>
)}
</div>
</div>
</article>
);
}