Files
zeekayandHanzo Dev 95f32feb48 Name the canonical address of each page
This is a static export served with trailing slashes, so several paths
reach the same document and a search engine has to guess which is the page.
Each route names its own; a single one in the layout would have pointed
every page at the homepage, which is worse than having none.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-28 08:00:51 -07:00

379 lines
17 KiB
TypeScript

import { notFound } from 'next/navigation'
import { Header } from '@/components/header'
import { Footer } from '@/components/footer'
import { FundingCard } from '@/components/funding-card'
import { getDAO, daos } from '@/lib/daos'
import {
MarketHypothesisSection,
ResearchAreasSection,
TokenomicsSection,
TeamSection,
RoadmapSection,
ValueCaptureSection,
ResourcesSection,
NewsSection,
ResearchArtifactsSection,
} from '@/components/dao-sections'
import { DAOTabs } from '@/components/dao-tabs'
export function generateStaticParams() {
return daos.map((dao) => ({
dao: dao.id,
}))
}
// Every DAO page served the site-wide title, so eight pages were
// indistinguishable to a search engine, a shared link and a screen reader
// announcing the document.
export async function generateMetadata({ params }: { params: Promise<{ dao: string }> }) {
const { dao: daoId } = await params
const dao = getDAO(daoId)
if (!dao) return { title: 'Not found | Zoo Fund' }
return {
title: `${dao.name} | Zoo Fund`,
description: dao.tagline,
alternates: { canonical: `/${dao.id}` },
openGraph: {
type: 'website',
siteName: 'Zoo Fund',
title: `${dao.name} | Zoo Fund`,
description: dao.tagline,
url: `https://zoo.fund/${dao.id}`,
},
twitter: {
card: 'summary',
title: `${dao.name} | Zoo Fund`,
description: dao.tagline,
},
}
}
export default async function DAOPage({ params }: { params: Promise<{ dao: string }> }) {
const { dao: daoId } = await params
const dao = getDAO(daoId)
if (!dao) {
notFound()
}
return (
<>
<Header />
<main>
{/* Hero Section */}
<section className="section-padding-lg border-b border-white/10">
<div className="container">
<div className="grid grid-cols-1 lg:grid-cols-[1fr_400px] gap-6 lg:gap-12 items-start">
<div>
<h1 className="text-responsive-h1 font-black mb-4 tracking-tight">
{dao.emoji} {dao.name}
</h1>
<p className="text-xl text-white/70 mb-8">
{dao.tagline}
</p>
<div className="text-white/80 space-y-4 mb-8">
<p>{dao.description}</p>
{dao.partners && (
<p>
<strong>Partner Organizations:</strong> {dao.partners}
</p>
)}
</div>
</div>
<FundingCard dao={dao} />
</div>
</div>
</section>
{/* About Section */}
<section className="section-padding border-b border-white/10">
<div className="container">
<h2 className="text-responsive-h2 font-bold mb-6">About {dao.name}</h2>
<div className="prose prose-invert max-w-none">
<p className="text-white/80 text-lg leading-relaxed">
{dao.mission}
</p>
</div>
{/* DAO Stats */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mt-12">
{/* No treasury card. The figure was a literal in lib/daos.ts and
the line under it read "Multisig:" followed by nothing, because
no DAO here publishes an address. A balance nobody can check,
labelled with a link that does not exist, is not a statistic. */}
<div className="bg-white/3 border border-white/10 rounded-xl p-6">
<h3 className="text-lg font-semibold mb-2">👥 Members</h3>
<p className="text-2xl font-bold text-[#667eea]">{dao.members}</p>
<p className="text-xs text-white/60 mt-2">
Token Holders
</p>
</div>
<div className="bg-white/3 border border-white/10 rounded-xl p-6">
<h3 className="text-lg font-semibold mb-2">🗳️ Proposals</h3>
<p className="text-2xl font-bold text-[#667eea]">{dao.proposals}</p>
</div>
<div className="bg-white/3 border border-white/10 rounded-xl p-6">
<h3 className="text-lg font-semibold mb-2">🎯 Goal</h3>
<p className="text-2xl font-bold text-[#667eea]">{dao.goal}</p>
<p className="text-xs text-white/60 mt-2">
Funding Target
</p>
</div>
</div>
</div>
</section>
{/* Governance Tabs Section */}
<section className="section-padding-lg border-b border-white/10">
<DAOTabs
tabs={[
{
id: 'overview',
label: 'Overview',
content: (
<div className="space-y-12">
{/* Market Hypothesis */}
{dao.marketHypothesis && (
<div>
<h3 className="text-2xl font-bold mb-6">Market Hypothesis</h3>
<div className="prose prose-invert max-w-none">
<p className="text-white/80 text-lg leading-relaxed">
{dao.marketHypothesis}
</p>
</div>
</div>
)}
{/* Latest Research & News */}
{dao.news && dao.news.length > 0 && (
<div>
<h3 className="text-2xl font-bold mb-6">Latest Research & News</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{dao.news.map((item, index) => (
<a
key={index}
href={item.url}
target="_blank"
rel="noopener noreferrer"
className="group bg-white/3 border border-white/10 rounded-xl p-6 hover:border-[#667eea]/50 hover:bg-white/5 transition-all"
>
<div className="flex items-center gap-2 mb-3">
<span className="text-xs px-2 py-1 bg-[#667eea]/20 text-[#667eea] rounded-full">
{item.date}
</span>
</div>
<h3 className="text-xl font-bold mb-3 group-hover:text-[#667eea] transition-colors">
{item.title}
</h3>
<p className="text-sm text-white/70">{item.description}</p>
</a>
))}
</div>
</div>
)}
</div>
),
},
{
id: 'research',
label: 'Research',
content: (
<div className="space-y-12">
{/* Research Artifacts & Datasets */}
{dao.researchArtifacts && dao.researchArtifacts.length > 0 && (
<div>
<h3 className="text-2xl font-bold mb-6">Research Artifacts & Datasets</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{dao.researchArtifacts.map((artifact, index) => (
<a
key={index}
href={artifact.zipUrl}
target="_blank"
rel="noopener noreferrer"
className="group bg-white/3 border border-white/10 rounded-xl p-6 hover:border-[#667eea]/50 hover:bg-white/5 transition-all"
>
<div className="flex items-center gap-3 mb-4">
<span className="text-3xl">📊</span>
<div>
<h3 className="font-bold group-hover:text-[#667eea] transition-colors">
{artifact.title}
</h3>
<p className="text-xs text-white/60">{artifact.format}</p>
</div>
</div>
<p className="text-sm text-white/70 mb-3">{artifact.description}</p>
{artifact.size && (
<p className="text-xs text-white/60">Size: {artifact.size}</p>
)}
</a>
))}
</div>
</div>
)}
{/* Research Focus Areas */}
{dao.researchAreas && dao.researchAreas.length > 0 && (
<div>
<h3 className="text-2xl font-bold mb-6">Research Focus Areas</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{dao.researchAreas.map((area, index) => (
<div
key={index}
className="bg-white/3 border border-white/10 rounded-xl p-6"
>
<div className="text-4xl mb-4">{area.icon}</div>
<h3 className="text-xl font-bold mb-2">{area.title}</h3>
<p className="text-sm text-white/70">{area.description}</p>
</div>
))}
</div>
</div>
)}
</div>
),
},
{
id: 'about',
label: 'About',
content: (
<div className="space-y-12">
{/* Tokenomics */}
{dao.tokenomics && (
<div>
<h3 className="text-2xl font-bold mb-6">Tokenomics</h3>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
{/* Distribution */}
<div className="bg-white/3 border border-white/10 rounded-xl p-6">
<h3 className="text-xl font-bold mb-4">Token Distribution</h3>
<div className="space-y-3">
{dao.tokenomics.distribution.map((item, index) => (
<div key={index} className="flex justify-between items-center">
<span className="text-white/80">{item.label}</span>
<span className="font-bold text-[#667eea]">{item.percentage}%</span>
</div>
))}
</div>
</div>
{/* Utility */}
<div className="bg-white/3 border border-white/10 rounded-xl p-6">
<h3 className="text-xl font-bold mb-4">Token Utility</h3>
<ul className="space-y-2">
{dao.tokenomics.utility.map((item, index) => (
<li key={index} className="flex items-start gap-2">
<span className="text-[#667eea] mt-1">•</span>
<span className="text-white/80">{item}</span>
</li>
))}
</ul>
</div>
</div>
</div>
)}
{/* Team & Community */}
{dao.team && dao.team.length > 0 && (
<div>
<h3 className="text-2xl font-bold mb-6">Team & Community</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{dao.team.map((member, index) => (
<div
key={index}
className="bg-white/3 border border-white/10 rounded-xl p-6"
>
<div className="text-4xl mb-3">{member.avatar}</div>
<h3 className="text-lg font-bold mb-1">{member.name}</h3>
<p className="text-sm text-[#667eea] mb-3">{member.role}</p>
<p className="text-sm text-white/70">{member.bio}</p>
</div>
))}
</div>
</div>
)}
{/* Project Roadmap */}
{dao.roadmap && dao.roadmap.length > 0 && (
<div>
<h3 className="text-2xl font-bold mb-6">Project Roadmap</h3>
<div className="space-y-6">
{dao.roadmap.map((milestone, index) => (
<div
key={index}
className="bg-white/3 border border-white/10 rounded-xl p-6"
>
<div className="flex items-start gap-4">
<div className="text-3xl">📅</div>
<div className="flex-1">
<div className="flex items-center gap-3 mb-2">
<h3 className="text-xl font-bold">{milestone.title}</h3>
<span
className={`px-3 py-1 text-xs font-semibold rounded-full ${
milestone.status === 'completed'
? 'bg-green-500/20 text-green-300'
: milestone.status === 'in-progress'
? 'bg-blue-500/20 text-blue-300'
: 'bg-white/10 text-white/60'
}`}
>
{milestone.status}
</span>
</div>
<p className="text-white/60 text-sm mb-2">{milestone.date}</p>
<p className="text-white/80">{milestone.description}</p>
</div>
</div>
</div>
))}
</div>
</div>
)}
{/* Value Capture Model */}
{dao.valueCaptureModel && (
<div>
<h3 className="text-2xl font-bold mb-6">Value Capture Model</h3>
<div className="bg-white/3 border border-white/10 rounded-xl p-8">
<p className="text-white/80 text-lg leading-relaxed">
{dao.valueCaptureModel}
</p>
</div>
</div>
)}
{/* Recommended Reads */}
{dao.resources && dao.resources.length > 0 && (
<div>
<h3 className="text-2xl font-bold mb-6">Recommended Reads</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{dao.resources.map((resource, index) => (
<a
key={index}
href={resource.url}
target="_blank"
rel="noopener noreferrer"
className="group bg-white/3 border border-white/10 rounded-xl p-6 hover:border-[#667eea]/50 hover:bg-white/5 transition-all"
>
<h3 className="font-bold mb-2 group-hover:text-[#667eea] transition-colors">
{resource.title}
</h3>
<p className="text-sm text-white/60 capitalize">{resource.type}</p>
</a>
))}
</div>
</div>
)}
</div>
),
},
]}
/>
</section>
</main>
<Footer />
</>
)
}