From 184e6947707ecdf07dfa3a5cbc6e51cf9440e93a Mon Sep 17 00:00:00 2001 From: yyamashita Date: Sun, 10 May 2026 00:21:04 +0900 Subject: Add members table with membership period and note support Replace band_artists + member_periods with a single members table (id, band_id, artist_id, role, since, until, note, order_index). Each row represents one membership period, so rejoining artists get multiple rows. Existing band_artists data is auto-migrated on startup. Export format bumped to version 3. Co-Authored-By: Claude Sonnet 4.6 --- app/routes/artist-by-uuid.tsx | 53 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 11 deletions(-) (limited to 'app/routes/artist-by-uuid.tsx') diff --git a/app/routes/artist-by-uuid.tsx b/app/routes/artist-by-uuid.tsx index 6eb06a7..a65525b 100644 --- a/app/routes/artist-by-uuid.tsx +++ b/app/routes/artist-by-uuid.tsx @@ -1,18 +1,29 @@ import { data, Link, useLoaderData } from "react-router"; import type { LoaderFunctionArgs } from "react-router"; -import { getArtistBands, getArtistById, getArtistLinks, getArtistRevisions } from "~/lib/db.server"; +import { getArtistById, getArtistLinks, getArtistMembers, getArtistRevisions, type ArtistMemberRow } from "~/lib/db.server"; export async function loader({ params }: LoaderFunctionArgs) { const artist = getArtistById(params.uuid!); if (!artist) throw data("Not found", { status: 404 }); const links = getArtistLinks(artist.id); - const bands = getArtistBands(artist.id); + const memberships = getArtistMembers(artist.id); const revisions = getArtistRevisions(artist.id); - return { artist, links, bands, latest: revisions[0] ?? null }; + return { artist, links, memberships, latest: revisions[0] ?? null }; +} + +function periodLabel(m: ArtistMemberRow): string | null { + if (!m.since && !m.until) return null; + const from = m.since || "?"; + const to = m.until || "現在"; + return `${from} 〜 ${to}`; } export default function ArtistDetail() { - const { artist, links, bands, latest } = useLoaderData(); + const { artist, links, memberships, latest } = useLoaderData(); + + // group by band_id + const bandIds = [...new Set(memberships.map((m) => m.band_id))]; + return (
@@ -23,16 +34,36 @@ export default function ArtistDetail() {
- {bands.length > 0 && ( + {bandIds.length > 0 && (

バンド

    - {bands.map((b) => ( -
  • - {b.band_name} - {b.role && {b.role}} -
  • - ))} + {bandIds.map((bandId) => { + const group = memberships.filter((m) => m.band_id === bandId); + const first = group[0]; + return ( +
  • +
    + {first.band_name} + {first.role && {first.role}} +
    + {group.some((m) => m.since || m.until || m.note) && ( +
      + {group.map((m) => { + const label = periodLabel(m); + if (!label && !m.note) return null; + return ( +
    • + {label && {label}} + {m.note && {m.note}} +
    • + ); + })} +
    + )} +
  • + ); + })}
)} -- cgit v1.2.3