114 lines
4.1 KiB
TypeScript
114 lines
4.1 KiB
TypeScript
export const dynamic = "force-dynamic";
|
|
|
|
import type { Metadata } from "next";
|
|
import Link from "next/link";
|
|
import { notFound } from "next/navigation";
|
|
import { getTranscriptionsByPlace } from "@/lib/transcriptions";
|
|
import { buildOgMeta } from "@/lib/og";
|
|
import { PageHeader } from "@/components/layout/page-header";
|
|
import { Card, CardContent } from "@/components/ui/card";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { Calendar, Clock } from "lucide-react";
|
|
import { PlayAudioButton } from "@/app/(app)/transcriptions/[slug]/play-audio-button";
|
|
|
|
export async function generateMetadata({
|
|
params,
|
|
}: {
|
|
params: Promise<{ place: string }>;
|
|
}): Promise<Metadata> {
|
|
const { place: encodedPlace } = await params;
|
|
const place = decodeURIComponent(encodedPlace);
|
|
const transcriptions = await getTranscriptionsByPlace(place);
|
|
return buildOgMeta({
|
|
title: "Transcriptions",
|
|
detail: `${transcriptions.length} transcriptions from ${place}`,
|
|
quote: `Lectures and conversations of Śrīla Prabhupāda in ${place}.`,
|
|
});
|
|
}
|
|
|
|
export default async function TranscriptionsByPlacePage({
|
|
params,
|
|
}: {
|
|
params: Promise<{ place: string }>;
|
|
}) {
|
|
const { place: encodedPlace } = await params;
|
|
const place = decodeURIComponent(encodedPlace);
|
|
|
|
const transcriptions = await getTranscriptionsByPlace(place);
|
|
if (transcriptions.length === 0) notFound();
|
|
|
|
return (
|
|
<div className="min-h-screen bg-background">
|
|
<PageHeader sticky>
|
|
<Link
|
|
href="/transcriptions?view=place"
|
|
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
|
>
|
|
← Transcriptions by Place
|
|
</Link>
|
|
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
|
Transcriptions in {place}
|
|
</h1>
|
|
<p className="mt-1 text-sm text-muted-foreground">
|
|
{transcriptions.length} transcriptions
|
|
</p>
|
|
</PageHeader>
|
|
|
|
<main className="max-w-5xl mx-auto px-6 py-8">
|
|
<Card className="overflow-hidden">
|
|
<CardContent className="p-0 divide-y divide-border">
|
|
{transcriptions.map((t) => (
|
|
<Link
|
|
key={t.slug}
|
|
href={`/transcriptions/${t.slug}`}
|
|
className="flex items-center px-5 py-3.5 gap-3 hover:bg-muted transition-colors"
|
|
>
|
|
<div className="min-w-0 flex-1">
|
|
<div className="flex items-center gap-2 flex-wrap">
|
|
<p className="font-medium text-foreground text-sm">
|
|
{t.name}
|
|
</p>
|
|
<Badge
|
|
variant={t.type === "lecture" ? "default" : "secondary"}
|
|
className="text-[10px] px-1.5 py-0"
|
|
>
|
|
{t.type === "lecture" ? "Lecture" : "Conversation"}
|
|
</Badge>
|
|
</div>
|
|
<div className="flex flex-wrap items-center gap-x-3 gap-y-1 mt-1 text-xs text-muted-foreground">
|
|
{t.date && (
|
|
<span className="flex items-center gap-1">
|
|
<Calendar className="size-3" />
|
|
{t.date}
|
|
</span>
|
|
)}
|
|
{t.reference && (
|
|
<span className="text-primary/70">{t.reference}</span>
|
|
)}
|
|
{t.durationMinutes && t.durationMinutes > 0 && (
|
|
<span className="flex items-center gap-1">
|
|
<Clock className="size-3" />
|
|
{t.durationMinutes} min
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
{t.audioUrl && (
|
|
<PlayAudioButton
|
|
audioUrl={t.audioUrl}
|
|
title={t.name}
|
|
subtitle={[t.date, t.place].filter(Boolean).join(" · ")}
|
|
sourceUrl={`/transcriptions/${t.slug}`}
|
|
type={t.type}
|
|
variant="compact"
|
|
/>
|
|
)}
|
|
</Link>
|
|
))}
|
|
</CardContent>
|
|
</Card>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|