From 8aa1986661199e919df354dc0a5a2819155f023a Mon Sep 17 00:00:00 2001 From: yyamashita Date: Thu, 7 May 2026 10:22:07 +0900 Subject: 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 --- app/components/EventListRow.tsx | 65 +++++++++++++++++++++++++++++++++++++++++ app/routes/events._index.tsx | 35 ++++++++++++++++++++-- 2 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 app/components/EventListRow.tsx (limited to 'app') diff --git a/app/components/EventListRow.tsx b/app/components/EventListRow.tsx new file mode 100644 index 0000000..24f5f59 --- /dev/null +++ b/app/components/EventListRow.tsx @@ -0,0 +1,65 @@ +import { Link } from "react-router"; +import type { Event } from "~/lib/db.server"; + +interface Props { + event: Event; +} + +export default function EventListRow({ event }: Props) { + const formattedDate = formatDate(event.date); + const timeLabel = buildTimeLabel(event.open_time, event.start_time); + + return ( + + {/* Date */} + + {formattedDate} + {timeLabel && ( + {timeLabel} + )} + + + {/* Venue */} + + {event.venue_name} + {event.venue_area ? `(${event.venue_area})` : ""} + + + {/* Title + artist */} + + + {event.title} + + {event.artist && ( + + {event.artist} + + )} + + + {/* Price */} + {event.price ? ( + ¥{event.price} + ) : ( + + )} + + ); +} + +function formatDate(iso: string): string { + const [y, m, d] = iso.split("-"); + const days = ["日", "月", "火", "水", "木", "金", "土"]; + const dayIdx = new Date(`${iso}T00:00:00`).getDay(); + return `${y}/${m}/${d}(${days[dayIdx]})`; +} + +function buildTimeLabel(open: string | null, start: string | null): string { + const parts: string[] = []; + if (open) parts.push(`OPEN ${open}`); + if (start) parts.push(`START ${start}`); + return parts.join(" / "); +} 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(); - 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 (
@@ -49,8 +58,24 @@ export default function EventsIndex() {
-
+

イベント一覧

+
+ + +
@@ -60,6 +85,12 @@ export default function EventsIndex() {

イベントが見つかりません

スクレイパーを実行してデータを取得してください: npm run scrape

+ ) : view === "list" ? ( +
+ {events.map((event) => ( + + ))} +
) : (
{events.map((event) => ( -- cgit v1.2.3