From b8d24d292d99c8da285092ce923b5e2b546d8f45 Mon Sep 17 00:00:00 2001 From: yyamashita Date: Sat, 9 May 2026 00:27:19 +0900 Subject: Implement band/artist management with version history Full CRUD for bands and artists: UUID + slug URLs, dynamic link editor, band-artist associations with roles, per-edit revision snapshots (message + IP). Add README and CLAUDE.md. Co-Authored-By: Claude Sonnet 4.6 --- app/routes/band-history.tsx | 61 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 app/routes/band-history.tsx (limited to 'app/routes/band-history.tsx') diff --git a/app/routes/band-history.tsx b/app/routes/band-history.tsx new file mode 100644 index 0000000..11e2f2f --- /dev/null +++ b/app/routes/band-history.tsx @@ -0,0 +1,61 @@ +import { data, Link, useLoaderData } from "react-router"; +import type { LoaderFunctionArgs } from "react-router"; +import { getBandById, getBandRevisions } from "~/lib/db.server"; + +export async function loader({ params }: LoaderFunctionArgs) { + const band = getBandById(params.uuid!); + if (!band) throw data("Not found", { status: 404 }); + const revisions = getBandRevisions(band.id); + return { band, revisions }; +} + +export default function BandHistory() { + const { band, revisions } = useLoaderData(); + return ( +
+
+ + ← + +

{band.name} — 編集履歴

+
+ + {revisions.length === 0 ? ( +

履歴がありません。

+ ) : ( +
    + {revisions.map((rev, i) => { + let snap: { name?: string; area?: string; links?: unknown[]; artists?: unknown[] } = {}; + try { snap = JSON.parse(rev.snapshot); } catch { /* ignore */ } + return ( +
  1. +
    +
    +

    {rev.message}

    +

    + {rev.created_at} · {rev.ip_address} +

    +
    + {i === 0 && ( + 最新 + )} +
    +
    +

    名前: {snap.name ?? "—"}

    + {snap.area &&

    拠点: {snap.area}

    } +

    + リンク: {snap.links?.length ?? 0}件 / メンバー:{" "} + {snap.artists?.length ?? 0}人 +

    +
    +
  2. + ); + })} +
+ )} +
+ ); +} -- cgit v1.2.3