← back to Nineoh Guide

apps/web/app/characters/page.tsx

54 lines

import { pool } from "@/lib/db";
import { slugify } from "@nineoh/core";

export const revalidate = 3600;
export const metadata = {
  title: "Characters",
  description: "Every main character on 90210 — profiles, who plays them, and the episodes they appear in.",
};

async function getCharacters() {
  try {
    const { rows } = await pool.query(
      `select c.name, c.description_original, cp.name as actor,
              (select count(*) from episode_guest_cast g where g.character_name = c.name)::int as appearances
         from characters c
         left join credits cr on cr.character_id = c.id and cr.credit_type='main-cast'
         left join cast_people cp on cp.id = cr.person_id
        where c.description_original is not null
        order by c.name`
    );
    return rows;
  } catch {
    return [];
  }
}

export default async function Characters() {
  const chars = await getCharacters();
  return (
    <section>
      <h1>Characters</h1>
      <p style={{ color: "var(--muted)", fontSize: 13 }}>
        The people of the 90210 ZIP code — who they are, who plays them, and where they turn up.
      </p>
      <div style={{ display: "grid", gap: 12, gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))", marginTop: 16 }}>
        {chars.map((c) => (
          <a key={c.name} className="card" href={`/characters/${slugify(c.name)}`} style={{ display: "block", color: "inherit" }}>
            <strong style={{ fontFamily: "var(--font-display)", fontSize: 16 }}>{c.name}</strong>
            {c.actor ? <span style={{ color: "var(--muted)", fontSize: 12 }}> · {c.actor}</span> : null}
            <p style={{ margin: "5px 0 0", color: "var(--ink-soft)", fontSize: 12.5, lineHeight: 1.5 }}>
              {c.description_original}
            </p>
            {c.appearances > 0 ? (
              <span className="pill" style={{ marginTop: 8, display: "inline-block" }}>
                {c.appearances} appearances
              </span>
            ) : null}
          </a>
        ))}
      </div>
    </section>
  );
}