Update site — significant redesign
This commit is contained in:
parent
835363030c
commit
de1a33bd60
1 changed files with 41 additions and 163 deletions
|
|
@ -10,11 +10,7 @@ export function generateStaticParams() {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateMetadata({
|
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {
|
||||||
params,
|
|
||||||
}: {
|
|
||||||
params: Promise<{ slug: string }>;
|
|
||||||
}) {
|
|
||||||
const { slug } = await params;
|
const { slug } = await params;
|
||||||
const project = getProjectBySlug(slug);
|
const project = getProjectBySlug(slug);
|
||||||
if (!project) return { title: "Project Not Found" };
|
if (!project) return { title: "Project Not Found" };
|
||||||
|
|
@ -42,14 +38,7 @@ export async function generateMetadata({
|
||||||
siteName: "Wild Dragon",
|
siteName: "Wild Dragon",
|
||||||
type: "website",
|
type: "website",
|
||||||
locale: "en_US",
|
locale: "en_US",
|
||||||
images: [
|
images: [{ url: project.thumbnail, width: 1200, height: 630, alt: `${project.client} — ${project.category}` }],
|
||||||
{
|
|
||||||
url: project.thumbnail,
|
|
||||||
width: 1200,
|
|
||||||
height: 630,
|
|
||||||
alt: `${project.client} — ${project.category}`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
|
|
@ -60,11 +49,7 @@ export async function generateMetadata({
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function ProjectPage({
|
export default async function ProjectPage({ params }: { params: Promise<{ slug: string }> }) {
|
||||||
params,
|
|
||||||
}: {
|
|
||||||
params: Promise<{ slug: string }>;
|
|
||||||
}) {
|
|
||||||
const { slug } = await params;
|
const { slug } = await params;
|
||||||
const project = getProjectBySlug(slug);
|
const project = getProjectBySlug(slug);
|
||||||
|
|
||||||
|
|
@ -78,39 +63,26 @@ export default async function ProjectPage({
|
||||||
name: project.title,
|
name: project.title,
|
||||||
description: project.summary,
|
description: project.summary,
|
||||||
serviceType: project.category,
|
serviceType: project.category,
|
||||||
provider: {
|
provider: { "@id": "https://www.wilddragon.net/#organization" },
|
||||||
"@id": "https://www.wilddragon.net/#organization",
|
|
||||||
},
|
|
||||||
areaServed: "United States",
|
areaServed: "United States",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Find previous and next projects for navigation
|
|
||||||
const currentIndex = projects.findIndex((p) => p.slug === project.slug);
|
const currentIndex = projects.findIndex((p) => p.slug === project.slug);
|
||||||
const prevProject = currentIndex > 0 ? projects[currentIndex - 1] : null;
|
const prevProject = currentIndex > 0 ? projects[currentIndex - 1] : null;
|
||||||
const nextProject =
|
const nextProject = currentIndex < projects.length - 1 ? projects[currentIndex + 1] : null;
|
||||||
currentIndex < projects.length - 1 ? projects[currentIndex + 1] : null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="min-h-screen bg-white">
|
<main className="min-h-screen bg-white">
|
||||||
<script
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }} />
|
||||||
type="application/ld+json"
|
|
||||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Header bar */}
|
{/* Header bar */}
|
||||||
<nav className="fixed top-0 left-0 right-0 z-50 bg-white/95 backdrop-blur-lg shadow-sm py-3.5">
|
<nav className="fixed top-0 left-0 right-0 z-50 bg-white/95 backdrop-blur-lg shadow-sm py-3.5">
|
||||||
<div className="max-w-6xl mx-auto px-6 flex items-center justify-between">
|
<div className="max-w-6xl mx-auto px-6 flex items-center justify-between">
|
||||||
<Link
|
<Link href="/#projects" className="flex items-center gap-2 text-[13px] text-muted hover:text-primary transition-colors duration-200 group">
|
||||||
href="/#projects"
|
|
||||||
className="flex items-center gap-2 text-[13px] text-muted hover:text-primary transition-colors duration-200 group"
|
|
||||||
>
|
|
||||||
<ArrowLeft size={15} className="group-hover:-translate-x-0.5 transition-transform duration-200" />
|
<ArrowLeft size={15} className="group-hover:-translate-x-0.5 transition-transform duration-200" />
|
||||||
Back to Projects
|
Back to Projects
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link href="/" className="font-mono text-[10px] tracking-[0.2em] uppercase text-muted hover:text-primary transition-colors duration-200">
|
||||||
href="/"
|
|
||||||
className="font-mono text-[10px] tracking-[0.2em] uppercase text-muted hover:text-primary transition-colors duration-200"
|
|
||||||
>
|
|
||||||
Wild Dragon
|
Wild Dragon
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -120,19 +92,11 @@ export default async function ProjectPage({
|
||||||
<section className="pt-32 pb-16 bg-primary">
|
<section className="pt-32 pb-16 bg-primary">
|
||||||
<div className="max-w-6xl mx-auto px-6">
|
<div className="max-w-6xl mx-auto px-6">
|
||||||
<div className="flex items-center gap-3 mb-5">
|
<div className="flex items-center gap-3 mb-5">
|
||||||
<span className="px-3 py-1.5 text-[10px] font-mono tracking-wider uppercase bg-accent/10 text-accent rounded-md">
|
<span className="px-3 py-1.5 text-[10px] font-mono tracking-wider uppercase bg-accent/10 text-accent rounded-md">{project.category}</span>
|
||||||
{project.category}
|
<span className="font-mono text-[11px] text-neutral-500">{project.year}</span>
|
||||||
</span>
|
|
||||||
<span className="font-mono text-[11px] text-neutral-500">
|
|
||||||
{project.year}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-4xl md:text-5xl lg:text-6xl font-semibold text-white leading-tight mb-6">
|
<h1 className="text-4xl md:text-5xl lg:text-6xl font-semibold text-white leading-tight mb-6">{project.client}</h1>
|
||||||
{project.client}
|
<p className="text-lg md:text-xl text-neutral-400 max-w-3xl leading-relaxed">{project.summary}</p>
|
||||||
</h1>
|
|
||||||
<p className="text-lg md:text-xl text-neutral-400 max-w-3xl leading-relaxed">
|
|
||||||
{project.summary}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
@ -140,14 +104,7 @@ export default async function ProjectPage({
|
||||||
<section className="bg-neutral-100">
|
<section className="bg-neutral-100">
|
||||||
<div className="max-w-6xl mx-auto">
|
<div className="max-w-6xl mx-auto">
|
||||||
<div className="relative h-64 md:h-[28rem] overflow-hidden">
|
<div className="relative h-64 md:h-[28rem] overflow-hidden">
|
||||||
<Image
|
<Image src={project.thumbnail} alt={`${project.client} — ${project.category} broadcast facility`} fill className="object-cover" sizes="100vw" priority />
|
||||||
src={project.thumbnail}
|
|
||||||
alt={`${project.client} — ${project.category} broadcast facility`}
|
|
||||||
fill
|
|
||||||
className="object-cover"
|
|
||||||
sizes="100vw"
|
|
||||||
priority
|
|
||||||
/>
|
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-white/10 to-transparent" />
|
<div className="absolute inset-0 bg-gradient-to-t from-white/10 to-transparent" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -159,43 +116,29 @@ export default async function ProjectPage({
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-16">
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-16">
|
||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<div className="lg:col-span-2">
|
<div className="lg:col-span-2">
|
||||||
<h2 className="text-2xl font-semibold text-primary mb-8">
|
<h2 className="text-2xl font-semibold text-primary mb-8">Overview</h2>
|
||||||
Overview
|
|
||||||
</h2>
|
|
||||||
<div className="space-y-5 text-muted leading-[1.8]">
|
<div className="space-y-5 text-muted leading-[1.8]">
|
||||||
{project.description.map((paragraph: string, i: number) => (
|
{project.description.map((paragraph: string, i: number) => (
|
||||||
<p key={i}>{paragraph}</p>
|
<p key={i}>{paragraph}</p>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Highlights */}
|
<h3 className="text-lg font-semibold text-primary mt-14 mb-6">Key Highlights</h3>
|
||||||
<h3 className="text-lg font-semibold text-primary mt-14 mb-6">
|
|
||||||
Key Highlights
|
|
||||||
</h3>
|
|
||||||
<ul className="space-y-4">
|
<ul className="space-y-4">
|
||||||
{project.highlights.map((highlight: string, i: number) => (
|
{project.highlights.map((highlight: string, i: number) => (
|
||||||
<li key={i} className="flex items-start gap-3">
|
<li key={i} className="flex items-start gap-3">
|
||||||
<span className="w-1.5 h-1.5 rounded-full bg-accent mt-2.5 shrink-0" />
|
<span className="w-1.5 h-1.5 rounded-full bg-accent mt-2.5 shrink-0" />
|
||||||
<span className="text-muted leading-relaxed">
|
<span className="text-muted leading-relaxed">{highlight}</span>
|
||||||
{highlight}
|
|
||||||
</span>
|
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{/* CTA */}
|
|
||||||
<div className="mt-16 p-8 rounded-xl bg-surface-dark border border-neutral-100">
|
<div className="mt-16 p-8 rounded-xl bg-surface-dark border border-neutral-100">
|
||||||
<h4 className="text-base font-semibold text-primary mb-3">
|
<h4 className="text-base font-semibold text-primary mb-3">Interested in a similar project?</h4>
|
||||||
Interested in a similar project?
|
|
||||||
</h4>
|
|
||||||
<p className="text-sm text-muted mb-5 leading-relaxed">
|
<p className="text-sm text-muted mb-5 leading-relaxed">
|
||||||
I bring the same engineering discipline and attention to detail to
|
I bring the same engineering discipline and attention to detail to every facility I design. Let's discuss how I can help with your project.
|
||||||
every facility I design. Let's discuss how I can help with your project.
|
|
||||||
</p>
|
</p>
|
||||||
<a
|
<a href="mailto:zgaetano@wilddragon.net" className="inline-flex items-center gap-2 px-6 py-2.5 bg-accent text-white text-sm font-medium rounded-md hover:bg-accent-light transition-all duration-200">
|
||||||
href="mailto:zgaetano@wilddragon.net"
|
|
||||||
className="inline-flex items-center gap-2 px-6 py-2.5 bg-accent text-white text-sm font-medium rounded-md hover:bg-accent-light transition-all duration-200"
|
|
||||||
>
|
|
||||||
Get in Touch
|
Get in Touch
|
||||||
<ExternalLink size={13} />
|
<ExternalLink size={13} />
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -205,68 +148,34 @@ export default async function ProjectPage({
|
||||||
{/* Sidebar */}
|
{/* Sidebar */}
|
||||||
<div className="space-y-10">
|
<div className="space-y-10">
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-mono text-[10px] tracking-[0.2em] uppercase text-muted mb-3">
|
<h4 className="font-mono text-[10px] tracking-[0.2em] uppercase text-muted mb-3">Client</h4>
|
||||||
Client
|
|
||||||
</h4>
|
|
||||||
<p className="text-primary font-medium">{project.client}</p>
|
<p className="text-primary font-medium">{project.client}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-mono text-[10px] tracking-[0.2em] uppercase text-muted mb-3">
|
<h4 className="font-mono text-[10px] tracking-[0.2em] uppercase text-muted mb-3">Year</h4>
|
||||||
Year
|
|
||||||
</h4>
|
|
||||||
<p className="text-primary font-medium">{project.year}</p>
|
<p className="text-primary font-medium">{project.year}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-mono text-[10px] tracking-[0.2em] uppercase text-muted mb-3">
|
<h4 className="font-mono text-[10px] tracking-[0.2em] uppercase text-muted mb-3">Scope of Work</h4>
|
||||||
Scope of Work
|
|
||||||
</h4>
|
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{project.scope.map((item: string) => (
|
{project.scope.map((item: string) => (
|
||||||
<span
|
<span key={item} className="px-3 py-1.5 text-xs font-medium bg-neutral-50 border border-neutral-100 text-muted rounded-md">{item}</span>
|
||||||
key={item}
|
|
||||||
className="px-3 py-1.5 text-xs font-medium bg-neutral-50 border border-neutral-100 text-muted rounded-md"
|
|
||||||
>
|
|
||||||
{item}
|
|
||||||
</span>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-mono text-[10px] tracking-[0.2em] uppercase text-muted mb-3">
|
<h4 className="font-mono text-[10px] tracking-[0.2em] uppercase text-muted mb-3">Technologies</h4>
|
||||||
Technologies
|
|
||||||
</h4>
|
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{project.technologies.map((tech: string) => (
|
{project.technologies.map((tech: string) => (
|
||||||
<span
|
<span key={tech} className="px-3 py-1.5 text-xs font-medium bg-accent/5 text-accent rounded-md">{tech}</span>
|
||||||
key={tech}
|
|
||||||
className="px-3 py-1.5 text-xs font-medium bg-accent/5 text-accent rounded-md"
|
|
||||||
>
|
|
||||||
{tech}
|
|
||||||
</span>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Quick nav to other projects */}
|
|
||||||
<div className="pt-6 border-t border-neutral-100">
|
<div className="pt-6 border-t border-neutral-100">
|
||||||
<h4 className="font-mono text-[10px] tracking-[0.2em] uppercase text-muted mb-4">
|
<h4 className="font-mono text-[10px] tracking-[0.2em] uppercase text-muted mb-4">Other Projects</h4>
|
||||||
Other Projects
|
|
||||||
</h4>
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{projects
|
{projects.filter((p) => p.slug !== project.slug).slice(0, 4).map((p) => (
|
||||||
.filter((p) => p.slug !== project.slug)
|
<Link key={p.slug} href={`/projects/${p.slug}`} className="block text-[13px] text-muted hover:text-accent transition-colors duration-200 py-1">{p.client}</Link>
|
||||||
.slice(0, 4)
|
|
||||||
.map((p) => (
|
|
||||||
<Link
|
|
||||||
key={p.slug}
|
|
||||||
href={`/projects/${p.slug}`}
|
|
||||||
className="block text-[13px] text-muted hover:text-accent transition-colors duration-200 py-1"
|
|
||||||
>
|
|
||||||
{p.client}
|
|
||||||
</Link>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -280,48 +189,24 @@ export default async function ProjectPage({
|
||||||
<div className="max-w-6xl mx-auto px-6">
|
<div className="max-w-6xl mx-auto px-6">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 divide-y md:divide-y-0 md:divide-x divide-neutral-200">
|
<div className="grid grid-cols-1 md:grid-cols-2 divide-y md:divide-y-0 md:divide-x divide-neutral-200">
|
||||||
{prevProject ? (
|
{prevProject ? (
|
||||||
<Link
|
<Link href={`/projects/${prevProject.slug}`} className="group flex items-center gap-4 py-10 pr-8 hover:bg-neutral-50 transition-colors duration-200">
|
||||||
href={`/projects/${prevProject.slug}`}
|
<ArrowLeft size={18} className="text-neutral-300 group-hover:text-accent group-hover:-translate-x-1 transition-all duration-200 shrink-0" />
|
||||||
className="group flex items-center gap-4 py-10 pr-8 hover:bg-neutral-50 transition-colors duration-200"
|
|
||||||
>
|
|
||||||
<ArrowLeft
|
|
||||||
size={18}
|
|
||||||
className="text-neutral-300 group-hover:text-accent group-hover:-translate-x-1 transition-all duration-200 shrink-0"
|
|
||||||
/>
|
|
||||||
<div>
|
<div>
|
||||||
<p className="font-mono text-[10px] tracking-wider uppercase text-muted mb-1">
|
<p className="font-mono text-[10px] tracking-wider uppercase text-muted mb-1">Previous</p>
|
||||||
Previous
|
<p className="text-sm font-medium text-primary group-hover:text-accent transition-colors duration-200">{prevProject.client}</p>
|
||||||
</p>
|
|
||||||
<p className="text-sm font-medium text-primary group-hover:text-accent transition-colors duration-200">
|
|
||||||
{prevProject.client}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : <div className="py-10" />}
|
||||||
<div className="py-10" />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{nextProject ? (
|
{nextProject ? (
|
||||||
<Link
|
<Link href={`/projects/${nextProject.slug}`} className="group flex items-center justify-end gap-4 py-10 pl-8 hover:bg-neutral-50 transition-colors duration-200">
|
||||||
href={`/projects/${nextProject.slug}`}
|
|
||||||
className="group flex items-center justify-end gap-4 py-10 pl-8 hover:bg-neutral-50 transition-colors duration-200"
|
|
||||||
>
|
|
||||||
<div className="text-right">
|
<div className="text-right">
|
||||||
<p className="font-mono text-[10px] tracking-wider uppercase text-muted mb-1">
|
<p className="font-mono text-[10px] tracking-wider uppercase text-muted mb-1">Next</p>
|
||||||
Next
|
<p className="text-sm font-medium text-primary group-hover:text-accent transition-colors duration-200">{nextProject.client}</p>
|
||||||
</p>
|
|
||||||
<p className="text-sm font-medium text-primary group-hover:text-accent transition-colors duration-200">
|
|
||||||
{nextProject.client}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<ArrowRight
|
<ArrowRight size={18} className="text-neutral-300 group-hover:text-accent group-hover:translate-x-1 transition-all duration-200 shrink-0" />
|
||||||
size={18}
|
|
||||||
className="text-neutral-300 group-hover:text-accent group-hover:translate-x-1 transition-all duration-200 shrink-0"
|
|
||||||
/>
|
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : <div className="py-10" />}
|
||||||
<div className="py-10" />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
@ -329,15 +214,8 @@ export default async function ProjectPage({
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<footer className="py-10 bg-primary">
|
<footer className="py-10 bg-primary">
|
||||||
<div className="max-w-6xl mx-auto px-6 flex flex-col md:flex-row items-center justify-between gap-4">
|
<div className="max-w-6xl mx-auto px-6 flex flex-col md:flex-row items-center justify-between gap-4">
|
||||||
<Link
|
<Link href="/" className="font-mono text-[10px] tracking-[0.2em] uppercase text-neutral-600 hover:text-neutral-400 transition-colors duration-200">Wild Dragon</Link>
|
||||||
href="/"
|
<p className="text-[11px] text-neutral-700">© {new Date().getFullYear()} Zachary Gaetano</p>
|
||||||
className="font-mono text-[10px] tracking-[0.2em] uppercase text-neutral-600 hover:text-neutral-400 transition-colors duration-200"
|
|
||||||
>
|
|
||||||
Wild Dragon
|
|
||||||
</Link>
|
|
||||||
<p className="text-[11px] text-neutral-700">
|
|
||||||
© {new Date().getFullYear()} Zachary Gaetano
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue