Fixed tailwind markdown beahviour and improved aesthetics on the project details page
This commit is contained in:
parent
471b251fd7
commit
49e62d5e2f
|
|
@ -1,5 +1,4 @@
|
|||
@import "tailwindcss";
|
||||
|
||||
@plugin "@tailwindcss/typography";
|
||||
|
||||
:root {
|
||||
|
|
@ -26,3 +25,9 @@ body {
|
|||
color: var(--foreground);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.prose {
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
|
|
|||
138
app/projects/[category]/[slug]/page copy.tsx
Normal file
138
app/projects/[category]/[slug]/page copy.tsx
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
"use client";
|
||||
|
||||
import { use } from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import Link from "next/link";
|
||||
import { ArrowLeft, ExternalLink, Github, ShieldCheck, Cpu, Users } from "lucide-react";
|
||||
import { PROJECT_REGISTRY } from "@/data/projects";
|
||||
import Mermaid from "@/components/Mermaid";
|
||||
import ProjectShowcase from "@/components/ProjectShowcase";
|
||||
import ImageCarousel from "@/components/ImageCarousel";
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
|
||||
|
||||
|
||||
export default function ProjectDetail({ params }: { params: Promise<{ category: string, slug: string }> }) {
|
||||
const { category, slug } = use(params);
|
||||
const project = PROJECT_REGISTRY.find((p) => p.slug === slug);
|
||||
|
||||
if (!project) return <div>Project Not Found</div>;
|
||||
|
||||
if (!project) return <div className="p-24 text-white font-mono">Project Log Not Found.</div>;
|
||||
|
||||
return (
|
||||
<main className="min-h-screen bg-[#0a0a0a] text-white p-6 md:p-12 lg:p-24">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
|
||||
{/* Navigation */}
|
||||
<Link href={`/projects/${category}`} className="flex items-center gap-2 text-neutral-500 hover:text-white transition-colors mb-12 font-mono text-[10px] uppercase tracking-widest">
|
||||
<ArrowLeft size={12} /> Back to {category}
|
||||
</Link>
|
||||
|
||||
{/* Header Section */}
|
||||
<header className="grid grid-cols-1 lg:grid-cols-2 gap-12 mb-20">
|
||||
<motion.div initial={{ opacity: 0, x: -20 }} animate={{ opacity: 1, x: 0 }}>
|
||||
<h1 className="text-6xl font-bold tracking-tighter mb-4">{project.title}</h1>
|
||||
<p className="text-blue-500 font-mono text-sm uppercase tracking-widest mb-6">{project.subtitle}</p>
|
||||
<p className="text-neutral-400 text-lg leading-relaxed">{project.description}</p>
|
||||
|
||||
<div className="flex gap-4 mt-8">
|
||||
{project.liveUrl && (
|
||||
<a href={project.liveUrl} className="flex items-center gap-2 bg-white text-black px-6 py-3 rounded-full font-bold text-sm hover:bg-neutral-200 transition-all">
|
||||
Launch Site <ExternalLink size={14} />
|
||||
</a>
|
||||
)}
|
||||
|
||||
{project?.repoUrl && (
|
||||
<a href={project.repoUrl} className="flex items-center gap-2 border border-neutral-800 px-6 py-3 rounded-full font-bold text-sm hover:bg-neutral-900 transition-all">
|
||||
View Source <Github size={14} />
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Senior Stats Sidebar */}
|
||||
<motion.div initial={{ opacity: 0, x: 20 }} animate={{ opacity: 1, x: 0 }} className="bg-neutral-900/30 border border-neutral-800 p-8 rounded-3xl h-fit">
|
||||
<div className="space-y-8">
|
||||
<div className="flex items-center gap-4">
|
||||
<ShieldCheck className="text-blue-500" />
|
||||
<div>
|
||||
<p className="text-[10px] text-neutral-500 uppercase font-mono tracking-tighter">My Role</p>
|
||||
<p className="text-sm font-semibold">{project.role}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<Cpu className="text-purple-500" />
|
||||
<div>
|
||||
<p className="text-[10px] text-neutral-500 uppercase font-mono tracking-tighter">Stack</p>
|
||||
<p className="text-sm font-semibold">{project.stack.join(", ")}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<Users className="text-green-500" />
|
||||
<div>
|
||||
<p className="text-[10px] text-neutral-500 uppercase font-mono tracking-tighter">Impact</p>
|
||||
<p className="text-sm font-semibold">{project.metrics.join(" • ")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</header>
|
||||
|
||||
|
||||
<section className="mb-20">
|
||||
{/* Desktop Showcase View */}
|
||||
<div className="hidden lg:block">
|
||||
<ProjectShowcase images={project.images} />
|
||||
</div>
|
||||
|
||||
{/* Mobile Carousel View */}
|
||||
<div className="block lg:hidden">
|
||||
<ImageCarousel images={project.images} />
|
||||
</div>
|
||||
|
||||
<p className="mt-4 text-center text-[10px] font-mono text-neutral-600 uppercase tracking-[0.2em]">
|
||||
Interactive Gallery — Select or swipe to explore
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* SYSTEM ARCHITECTURE (New Mermaid Section) */}
|
||||
{project.mermaidChart && (
|
||||
<section className="mb-8">
|
||||
<div className="flex items-center gap-3 mb-8">
|
||||
<h3 className="text-[10px] font-mono text-blue-500 uppercase tracking-[0.3em] font-bold">
|
||||
TECHNICAL_ARCH // 01
|
||||
</h3>
|
||||
<div className="h-px flex-1 bg-neutral-900" />
|
||||
<h2 className="text-xl font-bold tracking-tighter">System Architecture Log</h2>
|
||||
</div>
|
||||
|
||||
<div className="bg-neutral-900/20 rounded-3xl border border-neutral-800/50 p-4 md:p-12">
|
||||
<Mermaid chart={project.mermaidChart} />
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Engineering Narrative */}
|
||||
{/* Updated Engineering Narrative Header */}
|
||||
<article className="w-full py-12 border-t border-neutral-900 mt-16">
|
||||
<div className="flex items-center gap-3 mb-12">
|
||||
<h3 className="text-[10px] font-mono text-purple-500 uppercase tracking-[0.3em] font-bold">
|
||||
PROJECT_LOG // 02
|
||||
</h3>
|
||||
<div className="h-px flex-1 bg-neutral-900" />
|
||||
<h2 className="text-xl font-bold tracking-tighter">The Engineering Story</h2>
|
||||
</div>
|
||||
|
||||
<div className="prose prose-invert prose-neutral max-w-none text-left
|
||||
prose-p:text-neutral-400 prose-p:leading-relaxed prose-p:text-[16px]
|
||||
prose-h4:text-white prose-h4:text-sm prose-h4:mb-2 prose-h4:mt-8
|
||||
prose-strong:text-white prose-strong:font-bold">
|
||||
<ReactMarkdown>{project.engineeringStory}</ReactMarkdown>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
|
@ -115,19 +115,20 @@ export default function ProjectDetail({ params }: { params: Promise<{ category:
|
|||
)}
|
||||
|
||||
{/* Engineering Narrative */}
|
||||
<article className="w-full max-w-3xl mx-auto px-6 py-20 border-t border-neutral-900 mt-20">
|
||||
<h2 className="text-2xl font-bold mb-10 italic underline decoration-blue-500 underline-offset-8 text-left text-white">
|
||||
The Engineering Story
|
||||
</h2>
|
||||
|
||||
<div className="prose prose-invert prose-neutral max-w-none text-left
|
||||
prose-h4:text-blue-400 prose-h4:font-mono prose-h4:uppercase prose-h4:text-[10px] prose-h4:tracking-[0.2em]
|
||||
prose-p:text-neutral-400 prose-p:leading-relaxed">
|
||||
<ReactMarkdown>
|
||||
{project.engineeringStory}
|
||||
</ReactMarkdown>
|
||||
{/* Updated Engineering Narrative Header */}
|
||||
<section className="w-full pb-20 mt-12">
|
||||
<div className="flex items-center gap-3 mb-12">
|
||||
<h3 className="text-[10px] font-mono text-blue-500 uppercase tracking-[0.3em] font-bold">
|
||||
PROJECT LOG // {project.storyLabel || "NARRATIVE"}
|
||||
</h3>
|
||||
<div className="h-px flex-1 bg-neutral-900" />
|
||||
<h2 className="text-xl font-bold tracking-tighter">The Engineering Story</h2>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<div className="prose prose-invert prose-neutral max-w-none text-left">
|
||||
<ReactMarkdown>{project.engineeringStory}</ReactMarkdown>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -36,37 +36,43 @@ export const PROJECT_REGISTRY: Project[] = [
|
|||
liveUrl: "https://ratoong.com",
|
||||
isPrivate: false,
|
||||
mermaidChart: `
|
||||
graph TD
|
||||
graph LR
|
||||
subgraph Client_Side [Frontend]
|
||||
A[Angular Web App]:::traffic
|
||||
end
|
||||
|
||||
subgraph Firebase_GCP [Cloud Infrastructure]
|
||||
direction TB
|
||||
Hub((Firebase SDK)):::hub
|
||||
|
||||
B[Firebase Auth]:::node
|
||||
C[Firestore DB]:::node
|
||||
D[Cloud Functions]:::node
|
||||
E[Partner API Proxy]:::node
|
||||
end
|
||||
|
||||
%% Move APIs to a vertical stack to save horizontal width %%
|
||||
subgraph External [Third Party]
|
||||
direction TB
|
||||
F[Weather API]:::traffic
|
||||
G[Google Maps API]:::traffic
|
||||
H[Affiliate Partners]:::traffic
|
||||
end
|
||||
|
||||
A <-->|Real-time Sync| C
|
||||
A -->|Auth Request| B
|
||||
A -->|Triggers| D
|
||||
D -->|Fetch & Normalize| F
|
||||
D -->|Geocoding| G
|
||||
D -->|Affiliate Logic| H
|
||||
E -->|Read Data| C
|
||||
A ==> Hub
|
||||
Hub -->|Identity| B
|
||||
Hub <-->|Data Sync| C
|
||||
Hub -->|Triggers| D
|
||||
|
||||
D --> F
|
||||
D --> G
|
||||
D --> H
|
||||
E -.->|Internal Access| C
|
||||
|
||||
%% Styles %%
|
||||
classDef traffic fill:#2563eb,stroke:#3b82f6,color:#fff
|
||||
classDef node fill:#16a34a,stroke:#4285F4,color:#fff
|
||||
classDef node fill:#16a34a,stroke:#22c55e,color:#fff
|
||||
classDef hub fill:#f59e0b,stroke:#d97706,color:#fff,stroke-width:2px
|
||||
`,
|
||||
storyLabel: "DATA // UI EFFICIENCY",
|
||||
},
|
||||
{
|
||||
slug: "datasaur",
|
||||
|
|
@ -82,6 +88,7 @@ export const PROJECT_REGISTRY: Project[] = [
|
|||
repoUrl: "https://git.georgew.dev/georgew/datasaur",
|
||||
liveUrl: "https://ratoong.com",
|
||||
engineeringStory: "In this high-stakes medical environment, I implemented a custom audit logging system that ensured every state change was immutable...",
|
||||
storyLabel: "DATA EFFICIENCY",
|
||||
isPrivate: true,
|
||||
},
|
||||
{
|
||||
|
|
@ -98,6 +105,7 @@ export const PROJECT_REGISTRY: Project[] = [
|
|||
images: ["/ratoong-hero.jpg", "/ratoong-dashboard.jpg"],
|
||||
liveUrl: "https://ratoong.com",
|
||||
isPrivate: true,
|
||||
storyLabel: "DATA EFFICIENCY",
|
||||
},
|
||||
{
|
||||
slug: "flutter-1",
|
||||
|
|
@ -113,6 +121,7 @@ export const PROJECT_REGISTRY: Project[] = [
|
|||
repoUrl: "https://git.georgew.dev/georgew/datasaur",
|
||||
liveUrl: "https://ratoong.com",
|
||||
engineeringStory: "In this high-stakes medical environment, I implemented a custom audit logging system that ensured every state change was immutable...",
|
||||
storyLabel: "DATA EFFICIENCY",
|
||||
isPrivate: true,
|
||||
},
|
||||
{
|
||||
|
|
@ -129,6 +138,7 @@ export const PROJECT_REGISTRY: Project[] = [
|
|||
repoUrl: "https://git.georgew.dev/georgew/datasaur",
|
||||
liveUrl: "https://ratoong.com",
|
||||
engineeringStory: "In this high-stakes medical environment, I implemented a custom audit logging system that ensured every state change was immutable...",
|
||||
storyLabel: "DATA EFFICIENCY",
|
||||
isPrivate: true,
|
||||
},
|
||||
];
|
||||
9384
package-lock.json
generated
Normal file
9384
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -9,6 +9,7 @@
|
|||
"lint": "eslint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/upgrade": "^4.1.18",
|
||||
"framer-motion": "^12.29.2",
|
||||
"lucide-react": "^0.563.0",
|
||||
"mermaid": "^11.12.2",
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ export interface Project {
|
|||
metrics: string[];
|
||||
description: string;
|
||||
engineeringStory: string;
|
||||
storyLabel?: string;
|
||||
images: string[];
|
||||
liveUrl?: string;
|
||||
repoUrl?: string;
|
||||
|
|
|
|||
Loading…
Reference in a new issue