diff options
Diffstat (limited to 'app/routes/band-by-uuid.tsx')
| -rw-r--r-- | app/routes/band-by-uuid.tsx | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/app/routes/band-by-uuid.tsx b/app/routes/band-by-uuid.tsx new file mode 100644 index 0000000..c55472e --- /dev/null +++ b/app/routes/band-by-uuid.tsx @@ -0,0 +1,108 @@ +import { data, Link, useLoaderData } from "react-router"; +import type { LoaderFunctionArgs } from "react-router"; +import { + getBandById, + getBandLinks, + getBandArtists, + 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 links = getBandLinks(band.id); + const artists = getBandArtists(band.id); + const revisions = getBandRevisions(band.id); + return { band, links, artists, latest: revisions[0] ?? null }; +} + +export default function BandDetail() { + const { band, links, artists, latest } = useLoaderData<typeof loader>(); + return ( + <main className="max-w-3xl mx-auto px-4 py-8"> + <div className="flex items-start justify-between mb-6"> + <div> + <h1 className="text-2xl font-bold">{band.name}</h1> + {band.area && <p className="text-gray-400 mt-1 text-sm">{band.area}</p>} + </div> + <div className="flex items-center gap-3 text-sm shrink-0 ml-4"> + <Link + to={`/bands/of/${band.id}/history`} + className="text-gray-400 hover:text-gray-200 transition-colors" + > + 履歴 + </Link> + <Link + to={`/bands/of/${band.id}/edit`} + className="bg-gray-800 hover:bg-gray-700 text-gray-200 px-3 py-1.5 rounded transition-colors" + > + 編集 + </Link> + </div> + </div> + + {artists.length > 0 && ( + <section className="mb-6"> + <h2 className="text-xs font-medium text-gray-500 uppercase tracking-wider mb-3"> + メンバー + </h2> + <ul className="space-y-2"> + {artists.map((a) => ( + <li key={a.artist_id} className="flex items-center gap-3"> + <Link + to={`/artists/of/${a.artist_id}`} + className="text-blue-400 hover:text-blue-300 transition-colors font-medium" + > + {a.artist_name} + </Link> + {a.role && ( + <span className="text-gray-400 text-sm">{a.role}</span> + )} + </li> + ))} + </ul> + </section> + )} + + {links.length > 0 && ( + <section className="mb-6"> + <h2 className="text-xs font-medium text-gray-500 uppercase tracking-wider mb-3"> + リンク + </h2> + <ul className="space-y-1.5"> + {links.map((l) => ( + <li key={l.id}> + <a + href={l.url} + target="_blank" + rel="noopener noreferrer" + className="text-blue-400 hover:text-blue-300 transition-colors text-sm" + > + {l.label} + </a> + </li> + ))} + </ul> + </section> + )} + + <hr className="border-gray-800 my-6" /> + <div className="text-xs text-gray-600 space-y-1 font-mono"> + <p>/bands/of/{band.id}</p> + <p> + <Link + to={`/bands/named/${band.slug}`} + className="hover:text-gray-400 transition-colors" + > + /bands/named/{band.slug} + </Link> + </p> + {latest && ( + <p className="font-sans text-gray-500 mt-2"> + 最終更新: {latest.created_at} — {latest.message} + </p> + )} + </div> + </main> + ); +} |
