summaryrefslogtreecommitdiff
path: root/app/routes/search.tsx
diff options
context:
space:
mode:
authoryyamashita <yyamashita@hetzner.yyamashita.com>2026-08-15 20:12:25 +0900
committeryyamashita <yyamashita@hetzner.yyamashita.com>2026-08-15 20:12:25 +0900
commitb9e06d9a139e6d9a6d509f500beee97d0d071602 (patch)
tree1e131cac0c65471da6b17ca1abff258412f8816f /app/routes/search.tsx
parent1777cdbf812959e39a2b2abc142afc2fe8932938 (diff)
Add site-wide search for bands and artists
Adds a nav search box and /search route backed by a LIKE-based searchAll() query over band name/area/description and artist name.
Diffstat (limited to 'app/routes/search.tsx')
-rw-r--r--app/routes/search.tsx73
1 files changed, 73 insertions, 0 deletions
diff --git a/app/routes/search.tsx b/app/routes/search.tsx
new file mode 100644
index 0000000..a4c03b7
--- /dev/null
+++ b/app/routes/search.tsx
@@ -0,0 +1,73 @@
+import { Form, Link, useLoaderData } from "react-router";
+import type { Route } from "./+types/search";
+import { searchAll } from "~/lib/db.server";
+
+export function loader({ request }: Route.LoaderArgs) {
+ const q = new URL(request.url).searchParams.get("q")?.trim() ?? "";
+ if (!q) return { q, bands: [], artists: [] };
+ const { bands, artists } = searchAll(q);
+ return { q, bands, artists };
+}
+
+export default function Search() {
+ const { q, bands, artists } = useLoaderData<typeof loader>();
+ const hasResults = bands.length > 0 || artists.length > 0;
+
+ return (
+ <main>
+ <div className="page-header">
+ <h1>検索</h1>
+ </div>
+
+ <Form method="get" action="/search" style={{ marginBottom: "1.5rem" }}>
+ <input
+ type="search"
+ name="q"
+ defaultValue={q}
+ placeholder="バンド名・アーティスト名で検索"
+ autoFocus
+ />
+ </Form>
+
+ {!q ? (
+ <p className="muted">検索キーワードを入力してください。</p>
+ ) : !hasResults ? (
+ <p className="muted">「{q}」に一致する結果が見つかりませんでした。</p>
+ ) : (
+ <>
+ {bands.length > 0 && (
+ <section>
+ <h2>Bands</h2>
+ <ul className="band-list">
+ {bands.map((band) => (
+ <li key={band.id}>
+ <Link to={`/bands/of/${band.id}`}>{band.name}</Link>
+ {band.area && (
+ <span className="muted" style={{ fontSize: ".75rem" }}>{band.area}</span>
+ )}
+ {band.status === "hiatus" && (
+ <span className="muted" style={{ fontSize: ".75rem" }}>活動休止</span>
+ )}
+ </li>
+ ))}
+ </ul>
+ </section>
+ )}
+
+ {artists.length > 0 && (
+ <section>
+ <h2>Artists</h2>
+ <ul className="band-list">
+ {artists.map((artist) => (
+ <li key={artist.id}>
+ <Link to={`/artists/of/${artist.id}`}>{artist.name}</Link>
+ </li>
+ ))}
+ </ul>
+ </section>
+ )}
+ </>
+ )}
+ </main>
+ );
+}