feat: Add hour titles, make list titles sticky

This commit is contained in:
Matej Stieranka 2025-07-03 15:06:48 +02:00
parent 6110d965a6
commit 6288e716d0
8 changed files with 64 additions and 45 deletions

View file

@ -1,4 +1,4 @@
import { groupEventsByLine } from "@/common/utils"; import { groupEventsByLine, groupEventsByStartTime } from "@/common/utils";
import { EventCard } from "@/components/EventCard"; import { EventCard } from "@/components/EventCard";
import { EventList } from "@/components/EventList"; import { EventList } from "@/components/EventList";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
@ -11,6 +11,7 @@ import {
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { getAllLines, getEventsForDate } from "@/db"; import { getAllLines, getEventsForDate } from "@/db";
import { line } from "drizzle-orm/pg-core";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
export default async function ScheduleByDate({ export default async function ScheduleByDate({
@ -35,11 +36,12 @@ export default async function ScheduleByDate({
if (events.length === 0) { if (events.length === 0) {
return notFound(); return notFound();
} }
const groupedEvents = groupEventsByLine(events); const eventsByLine = groupEventsByLine(events);
const eventsByTime = groupEventsByStartTime(events);
const allLines = await getAllLines(); const allLines = await getAllLines();
return ( return (
<div className="flex flex-col items-center justify-items-center p-8 pb-20 gap-4 sm:p-20 w-full"> <div className="flex flex-col items-center justify-items-center pb-20 w-full">
<div className="flex flex-col sm:flex-row justify-between items-center w-full gap-2 mb-4"> <div className="flex flex-col sm:flex-row justify-between items-center w-full gap-2 p-8">
<h1 className="text-3xl font-bold"> <h1 className="text-3xl font-bold">
{parsedDate.toLocaleDateString(["cs-CZ"], { {parsedDate.toLocaleDateString(["cs-CZ"], {
weekday: "long", weekday: "long",
@ -71,14 +73,25 @@ export default async function ScheduleByDate({
</div> </div>
<main className="flex flex-col gap-8 items-center"> <main className="flex flex-col gap-8 items-center">
{group === "line" && {group === "line" &&
groupedEvents.map((line) => ( eventsByLine.map((line) => (
<EventList <EventList
key={line.lineId} key={line.lineId}
events={line.events} events={line.events}
title={allLines.find((l) => l.id === line.lineId)?.name} title={allLines.find((l) => l.id === line.lineId)?.name}
/> />
))} ))}
{group !== "line" && <EventList events={events} showLine />} {group !== "line" &&
eventsByTime.map((time) => (
<EventList
key={time.startTime.toISOString()}
events={time.events}
title={`Od ${time.startTime.toLocaleTimeString("cs-CZ", {
hour12: false,
hour: "numeric",
minute: "2-digit",
})}`}
/>
))}
</main> </main>
</div> </div>
); );

View file

@ -23,8 +23,8 @@ export default async function FavoritesPage({
}); });
return ( return (
<div className="flex flex-col items-center justify-items-center p-8 pb-20 gap-4 sm:p-20 w-full"> <div className="flex flex-col items-center justify-items-center pb-20 w-full">
<div className="flex flex-col sm:flex-row justify-between items-center w-full gap-2 mb-4"> <div className="flex flex-col sm:flex-row justify-between items-center w-full gap-2 p-8">
<h1 className="text-3xl font-bold">Oblíbené</h1> <h1 className="text-3xl font-bold">Oblíbené</h1>
<ShowElapsedSwitch defaultValue={false} /> <ShowElapsedSwitch defaultValue={false} />
</div> </div>

View file

@ -38,7 +38,7 @@ export default async function RootLayout({
<SidebarProvider> <SidebarProvider>
<AppSidebar /> <AppSidebar />
<SidebarInset> <SidebarInset>
<header className="bg-background sticky top-0 flex h-16 shrink-0 items-center gap-2 border-b px-4"> <header className="bg-background sticky top-0 flex h-16 shrink-0 z-10 items-center gap-2 border-b px-4">
<SidebarTrigger className="-ml-1" /> <SidebarTrigger className="-ml-1" />
<Separator orientation="vertical" className="mr-2 h-4" /> <Separator orientation="vertical" className="mr-2 h-4" />
<div className="flex-grow"> <div className="flex-grow">

View file

@ -23,7 +23,7 @@ export default async function ScheduleByLine({
const lineData = groupEventsByDate(events); const lineData = groupEventsByDate(events);
return ( return (
<div className="flex flex-col items-center justify-items-center p-8 pb-20 gap-4 sm:p-20 w-full"> <div className="flex flex-col items-center justify-items-center pb-20 w-full">
<div className="flex flex-col items-center text-center"> <div className="flex flex-col items-center text-center">
<h1 className="text-3xl font-bold mb-4">{lineInfo.name}</h1> <h1 className="text-3xl font-bold mb-4">{lineInfo.name}</h1>
<h6 className="text-gray-500 mb-4">{lineInfo.description}</h6> <h6 className="text-gray-500 mb-4">{lineInfo.description}</h6>

View file

@ -7,21 +7,23 @@ export default async function FavoritesPage() {
const groupedEvents = groupEventsByStartTime(nowEvents); const groupedEvents = groupEventsByStartTime(nowEvents);
return ( return (
<div className="flex flex-col items-center justify-items-center p-8 pb-20 gap-4 sm:p-20 w-full"> <div className="flex flex-col items-center justify-items-center pb-20 w-full">
<div className="flex flex-col sm:flex-row justify-between items-center w-full gap-2 mb-4"> <div className="flex flex-col sm:flex-row justify-between items-center w-full gap-2 p-8">
<h1 className="text-3xl font-bold">Kam jít?</h1> <h1 className="text-3xl font-bold">Kam jít?</h1>
</div> </div>
<main className="flex flex-col gap-8 w-full"> <main className="flex flex-col gap-8 w-full">
{groupedEvents.map(({events, startTime}) => ( {groupedEvents.map(({ events, startTime }) => (
<div key={startTime.toISOString()} className="w-full"> <div key={startTime.toISOString()} className="w-full">
<h2 className="text-2xl font-semibold mb-4"> <EventList
Od {new Date(startTime).toLocaleTimeString("cs-CZ", { title={`Od ${new Date(startTime).toLocaleTimeString("cs-CZ", {
hour: "2-digit", hour: "2-digit",
minute: "2-digit", minute: "2-digit",
hour12: false, hour12: false,
})} })}`}
</h2> events={events}
<EventList events={events} showDate showLine /> showDate
showLine
/>
</div> </div>
))} ))}
</main> </main>

View file

@ -13,7 +13,7 @@ export default async function Home({ searchParams }: HomePageProps) {
console.log("Message from searchParams:", message); console.log("Message from searchParams:", message);
return ( return (
<div className="flex flex-col items-center justify-items-center p-8 pb-20 gap-4 sm:p-20 w-full"> <div className="flex flex-col items-center justify-items-center pb-20 w-full">
<main className="flex flex-col gap-[32px] w-full items-center sm:items-start"> <main className="flex flex-col gap-[32px] w-full items-center sm:items-start">
{message && ( {message && (
<Alert variant="default"> <Alert variant="default">

View file

@ -10,7 +10,7 @@ export default async function SearchPage({ searchParams }: SearchPageProps) {
const query = (await searchParams).q || ""; const query = (await searchParams).q || "";
const results = query ? await searchEvents(query) : []; const results = query ? await searchEvents(query) : [];
return ( return (
<div className="flex flex-col items-center justify-items-center p-8 pb-20 gap-4 sm:p-20 w-full"> <div className="flex flex-col items-center justify-items-center pb-20 w-full">
<main className="flex flex-col gap-8 items-center w-full"> <main className="flex flex-col gap-8 items-center w-full">
<h1 className="text-3xl font-bold mb-4 w-full"> <h1 className="text-3xl font-bold mb-4 w-full">
Výsledky hledání pro "{query}" Výsledky hledání pro "{query}"

View file

@ -14,10 +14,13 @@ export function EventList({
}) { }) {
return ( return (
<div className="space-y-2 w-full"> <div className="space-y-2 w-full">
{title && <h2 className="text-2xl font-bold">{title}</h2>} {title && (
{events.length === 0 && ( <h2 className="text-2xl font-bold sticky top-16 bg-white dark:bg-black px-8 py-4">
<p className="text-gray-500">Žádné události.</p> {title}
</h2>
)} )}
{events.length === 0 && <p className="text-gray-500 px-8">Žádné události.</p>}
<div className="flex flex-col gap-2 px-8">
{events.map((event) => ( {events.map((event) => (
<EventCard <EventCard
key={event.id} key={event.id}
@ -27,5 +30,6 @@ export function EventList({
/> />
))} ))}
</div> </div>
</div>
); );
} }