summaryrefslogtreecommitdiff
path: root/app/routes
diff options
context:
space:
mode:
authoryyamashita <yyamashita@mosquit.one>2026-05-07 10:22:07 +0900
committeryyamashita <yyamashita@mosquit.one>2026-05-07 10:22:07 +0900
commit8aa1986661199e919df354dc0a5a2819155f023a (patch)
tree2c2c6fa400bb914508daa543ca723639efa96821 /app/routes
parent0cd5fb770ca9bd3f304d9556a4b33a4ad4f45e7e (diff)
Add list view toggle to event listing
Adds EventListRow component and a card/list toggle (persisted in ?view= URL param) so users can switch between the grid card layout and a compact single-row list layout. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'app/routes')
-rw-r--r--app/routes/events._index.tsx35
1 files changed, 33 insertions, 2 deletions
diff --git a/app/routes/events._index.tsx b/app/routes/events._index.tsx
index 1917ace..174c81e 100644
--- a/app/routes/events._index.tsx
+++ b/app/routes/events._index.tsx
@@ -2,6 +2,7 @@ import { useLoaderData, useSearchParams, Link } from "react-router";
import type { Route } from "./+types/events._index";
import { queryEvents, getVenues } from "~/lib/db.server";
import EventCard from "~/components/EventCard";
+import EventListRow from "~/components/EventListRow";
import FilterBar from "~/components/FilterBar";
function defaultWindow() {
@@ -34,7 +35,15 @@ export async function loader({ request }: Route.LoaderArgs) {
export default function EventsIndex() {
const { events, venues, page, hasMore, date_from, date_to } = useLoaderData<typeof loader>();
- const [searchParams] = useSearchParams();
+ const [searchParams, setSearchParams] = useSearchParams();
+ const view = (searchParams.get("view") ?? "card") as "card" | "list";
+
+ function switchView(next: "card" | "list") {
+ const next_params = new URLSearchParams(searchParams);
+ next_params.set("view", next);
+ next_params.delete("page");
+ setSearchParams(next_params, { preventScrollReset: true });
+ }
return (
<div className="min-h-screen bg-gray-950 text-gray-100">
@@ -49,8 +58,24 @@ export default function EventsIndex() {
</header>
<main className="max-w-6xl mx-auto px-4 py-8">
- <div className="mb-6">
+ <div className="mb-6 flex items-center justify-between">
<h1 className="text-2xl font-bold">イベント一覧</h1>
+ <div className="flex rounded-lg overflow-hidden border border-gray-700 text-sm">
+ <button
+ onClick={() => switchView("card")}
+ className={`px-3 py-1.5 transition-colors ${view === "card" ? "bg-indigo-600 text-white" : "bg-gray-800 text-gray-400 hover:text-white"}`}
+ title="カード表示"
+ >
+ ▦
+ </button>
+ <button
+ onClick={() => switchView("list")}
+ className={`px-3 py-1.5 transition-colors ${view === "list" ? "bg-indigo-600 text-white" : "bg-gray-800 text-gray-400 hover:text-white"}`}
+ title="リスト表示"
+ >
+ ☰
+ </button>
+ </div>
</div>
<FilterBar venues={venues} defaultDateFrom={date_from} defaultDateTo={date_to} />
@@ -60,6 +85,12 @@ export default function EventsIndex() {
<p className="text-lg">イベントが見つかりません</p>
<p className="mt-2 text-sm">スクレイパーを実行してデータを取得してください: <code>npm run scrape</code></p>
</div>
+ ) : view === "list" ? (
+ <div className="mt-6 flex flex-col gap-1.5">
+ {events.map((event) => (
+ <EventListRow key={event.id} event={event} />
+ ))}
+ </div>
) : (
<div className="mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{events.map((event) => (