summaryrefslogtreecommitdiff
path: root/app/routes/home.tsx
diff options
context:
space:
mode:
authoryyamashita <yyamashita@hetzner.yyamashita.com>2026-08-15 18:57:59 +0900
committeryyamashita <yyamashita@hetzner.yyamashita.com>2026-08-15 18:57:59 +0900
commit59a9f4984c3acd29bc746a78e30849f50fa555ee (patch)
treeb9dab024c0c5d1d68e023b8f49eb0716b97965bd /app/routes/home.tsx
parenta100fb28f92fa7c5d2cf701d118c4c7b898c9bf2 (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.tsx108
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>
+ );
}