feat: links cruzados autor->/autor y parodia->/franquicia en posts
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { notFound } from "next/navigation"
|
||||
import Link from "next/link"
|
||||
import type { Metadata } from "next"
|
||||
import { getPostBySlug, getAllPosts } from "@/lib/db"
|
||||
import { getPostBySlug, getAllPosts, getAuthorSlugByName } from "@/lib/db"
|
||||
import { PostCard } from "@/components/post-card"
|
||||
import { TagBadge } from "@/components/tag-badge"
|
||||
import { ArrowLeft, BookOpen, ExternalLink } from "lucide-react"
|
||||
@@ -78,6 +78,9 @@ export default async function PostDetailPage({
|
||||
post.summary.length > 50
|
||||
)
|
||||
|
||||
// Enlaces cruzados: autor -> página de autor, parodia -> franquicia.
|
||||
const authorSlug = post.artist ? getAuthorSlugByName(post.artist) : null
|
||||
|
||||
return (
|
||||
<div className="pb-16 md:pb-0">
|
||||
<Link
|
||||
@@ -117,11 +120,23 @@ export default async function PostDetailPage({
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-2 text-xs sm:text-sm">
|
||||
{post.artist && (
|
||||
<TagBadge tag={`artist:${post.artist}`} href={`/tag/${encodeURIComponent(`artist:${post.artist}`)}`} />
|
||||
{post.artist && authorSlug && (
|
||||
<Link
|
||||
href={`/autor/${authorSlug}`}
|
||||
className="inline-flex items-center gap-1.5 rounded-full border border-[var(--border)] bg-[var(--surface)] px-2.5 py-1 text-xs text-[var(--foreground)] transition-colors hover:border-[var(--accent)] hover:text-[var(--accent)]"
|
||||
>
|
||||
<span className="text-[var(--muted)]"> artista:</span>
|
||||
{post.artist}
|
||||
</Link>
|
||||
)}
|
||||
{post.parody && (
|
||||
<TagBadge tag={`parody:${post.parody}`} href={`/tag/${encodeURIComponent(`parody:${post.parody}`)}`} />
|
||||
{post.parody && !["original", "sin parodia"].includes(post.parody) && (
|
||||
<Link
|
||||
href={`/franquicia/${encodeURIComponent(post.parody)}`}
|
||||
className="inline-flex items-center gap-1.5 rounded-full border border-[var(--border)] bg-[var(--surface)] px-2.5 py-1 text-xs text-[var(--foreground)] transition-colors hover:border-[var(--accent)] hover:text-[var(--accent)]"
|
||||
>
|
||||
<span className="text-[var(--muted)]"> franquicia:</span>
|
||||
{post.parody}
|
||||
</Link>
|
||||
)}
|
||||
{post.source && (
|
||||
<span className="tag-pill border border-[var(--border)] text-[var(--muted)]">
|
||||
|
||||
@@ -420,6 +420,23 @@ export function getAuthorBySlug(slug: string): Author | null {
|
||||
return row ? rowToAuthor(row) : null
|
||||
}
|
||||
|
||||
// Devuelve el slug de un autor por su nombre (para enlazar desde los posts).
|
||||
// Si el autor no está registrado, lo registra sobre la marcha.
|
||||
export function getAuthorSlugByName(name: string): string | null {
|
||||
const d = getDb()
|
||||
const clean = (name || "").trim()
|
||||
if (!clean || clean === "sin artista" || clean === "dummy") return null
|
||||
|
||||
d.prepare("INSERT OR IGNORE INTO authors(name, slug) VALUES (?, ?)").run(
|
||||
clean,
|
||||
slugify(clean),
|
||||
)
|
||||
const row = d.prepare("SELECT slug FROM authors WHERE name = ?").get(clean) as
|
||||
| { slug: string }
|
||||
| undefined
|
||||
return row ? row.slug : null
|
||||
}
|
||||
|
||||
export function getSeriesBySlug(slug: string): Series | null {
|
||||
const d = getDb()
|
||||
const row = d
|
||||
|
||||
Reference in New Issue
Block a user