diff options
| author | yyamashita <yyamashita@hetzner.yyamashita.com> | 2026-08-15 18:57:59 +0900 |
|---|---|---|
| committer | yyamashita <yyamashita@hetzner.yyamashita.com> | 2026-08-15 18:57:59 +0900 |
| commit | 59a9f4984c3acd29bc746a78e30849f50fa555ee (patch) | |
| tree | b9dab024c0c5d1d68e023b8f49eb0716b97965bd /app/routes/home.tsx | |
| parent | a100fb28f92fa7c5d2cf701d118c4c7b898c9bf2 (diff) | |
Add Claude-powered band auto-registration from live info text
Extracts band/artist names from pasted live info via Claude (API or CLI
adapter), matches against existing bands, and lets the user review and
bulk-register new ones through a polling job queue. Also adds a
livehouse events import script and recent-bands/artists home page
sections.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'app/routes/home.tsx')
| -rw-r--r-- | app/routes/home.tsx | 108 |
1 files changed, 105 insertions, 3 deletions
diff --git a/app/routes/home.tsx b/app/routes/home.tsx index 9795ba8..591585d 100644 --- a/app/routes/home.tsx +++ b/app/routes/home.tsx @@ -1,9 +1,111 @@ -import { redirect } from "react-router"; +import { Link, useLoaderData } from "react-router"; +import { listBands, listArtists, listBandLists, listRecentBands, listRecentArtists } from "~/lib/db.server"; export function loader() { - return redirect("/bands"); + return { + bandCount: listBands().length, + artistCount: listArtists().length, + listCount: listBandLists().length, + recentBands: listRecentBands(8), + recentArtists: listRecentArtists(8), + }; } export default function Home() { - return null; + const { bandCount, artistCount, listCount, recentBands, recentArtists } = useLoaderData<typeof loader>(); + return ( + <main> + <div style={{ marginBottom: "2.5rem" }}> + <h1 style={{ fontSize: "2rem", fontWeight: 700, color: "#f9fafb", marginBottom: ".5rem" }}> + whois.band + </h1> + <p className="muted">バンドとアーティストの情報管理サイト</p> + </div> + + <div style={{ display: "flex", flexDirection: "column", gap: "1px", background: "#1f2937", border: "1px solid #1f2937", borderRadius: "6px", overflow: "hidden", marginBottom: "2.5rem" }}> + <SectionRow to="/bands" label="Bands" count={bandCount} newTo="/bands/new" /> + <SectionRow to="/artists" label="Artists" count={artistCount} newTo="/artists/new" /> + <SectionRow to="/lists" label="Lists" count={listCount} newTo="/lists/new" /> + </div> + + <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "2rem" }}> + <RecentSection title="最近追加されたバンド" viewAllTo="/bands"> + {recentBands.length === 0 ? ( + <p className="muted" style={{ fontSize: ".875rem" }}>まだありません</p> + ) : ( + <ul className="band-list"> + {recentBands.map((band) => ( + <li key={band.id}> + <Link to={`/bands/of/${band.id}`}>{band.name}</Link> + {band.status === "hiatus" && ( + <span className="muted" style={{ fontSize: ".75rem" }}>活動休止</span> + )} + </li> + ))} + </ul> + )} + </RecentSection> + + <RecentSection title="最近追加されたアーティスト" viewAllTo="/artists"> + {recentArtists.length === 0 ? ( + <p className="muted" style={{ fontSize: ".875rem" }}>まだありません</p> + ) : ( + <ul className="band-list"> + {recentArtists.map((artist) => ( + <li key={artist.id}> + <Link to={`/artists/of/${artist.id}`}>{artist.name}</Link> + </li> + ))} + </ul> + )} + </RecentSection> + </div> + </main> + ); +} + +function SectionRow({ + to, + label, + count, + newTo, +}: { + to: string; + label: string; + count: number; + newTo: string; +}) { + return ( + <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: ".875rem 1.25rem", background: "#0f1117" }}> + <div style={{ display: "flex", alignItems: "baseline", gap: "1rem" }}> + <Link to={to} style={{ fontWeight: 600, fontSize: "1rem", color: "#e5e7eb" }}> + {label} + </Link> + <span className="muted" style={{ fontSize: ".8rem" }}>{count}件</span> + </div> + <Link to={newTo} className="btn" style={{ fontSize: ".8rem" }}> + + 追加 + </Link> + </div> + ); +} + +function RecentSection({ + title, + viewAllTo, + children, +}: { + title: string; + viewAllTo: string; + children: React.ReactNode; +}) { + return ( + <section style={{ marginBottom: 0 }}> + <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: ".75rem" }}> + <h2 style={{ margin: 0 }}>{title}</h2> + <Link to={viewAllTo} className="muted" style={{ fontSize: ".75rem" }}>すべて見る</Link> + </div> + {children} + </section> + ); } |
