From 8aa1986661199e919df354dc0a5a2819155f023a Mon Sep 17 00:00:00 2001
From: yyamashita <yyamashita@mosquit.one>
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 <noreply@anthropic.com>
---
 app/components/EventListRow.tsx | 65 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)
 create mode 100644 app/components/EventListRow.tsx

(limited to 'app/components/EventListRow.tsx')

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 (
+    <Link
+      to={`/events/${event.id}`}
+      className="group flex items-center gap-3 rounded-lg px-4 py-3 bg-gray-800/40 border border-gray-700/30 hover:border-indigo-500/50 hover:bg-gray-800/70 transition-all text-sm"
+    >
+      {/* Date */}
+      <span className="w-32 shrink-0 text-xs text-gray-400 tabular-nums">
+        {formattedDate}
+        {timeLabel && (
+          <span className="block text-gray-600 text-[11px]">{timeLabel}</span>
+        )}
+      </span>
+
+      {/* Venue */}
+      <span className="w-28 shrink-0 truncate rounded-full bg-gray-700/60 px-2 py-0.5 text-xs text-gray-300">
+        {event.venue_name}
+        {event.venue_area ? `（${event.venue_area}）` : ""}
+      </span>
+
+      {/* Title + artist */}
+      <span className="flex-1 min-w-0">
+        <span className="block truncate font-medium text-gray-100 group-hover:text-indigo-300 transition-colors">
+          {event.title}
+        </span>
+        {event.artist && (
+          <span className="block truncate text-xs text-indigo-300/80">
+            {event.artist}
+          </span>
+        )}
+      </span>
+
+      {/* Price */}
+      {event.price ? (
+        <span className="shrink-0 text-xs text-emerald-400">¥{event.price}</span>
+      ) : (
+        <span className="shrink-0 w-16" />
+      )}
+    </Link>
+  );
+}
+
+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(" / ");
+}
-- 
cgit v1.2.3

