Aktueller Stand
This commit is contained in:
@@ -1582,7 +1582,134 @@ export default function CalendarBoard() {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="overflow-x-auto">
|
||||
<div className="md:hidden space-y-2">
|
||||
{displayedEvents.length === 0 ? (
|
||||
<p className="rounded-xl border border-slate-200 bg-white px-3 py-4 text-sm text-slate-600">
|
||||
Keine Termine für die aktuelle Auswahl.
|
||||
</p>
|
||||
) : (
|
||||
displayedEvents.map((event) => {
|
||||
const categoryName = event.category?.name || "Ohne Kategorie";
|
||||
const locationLabel = formatLocation(event.location);
|
||||
const dateLabel = new Date(event.startAt).toLocaleString("de-DE", {
|
||||
dateStyle: "medium",
|
||||
timeStyle: "short"
|
||||
});
|
||||
const bucket = getDateBucket(event.startAt);
|
||||
const bucketClass =
|
||||
bucket === "past"
|
||||
? "bg-slate-50 text-slate-500"
|
||||
: bucket === "today"
|
||||
? "bg-amber-50/60"
|
||||
: bucket === "tomorrow"
|
||||
? "bg-emerald-50/60"
|
||||
: "bg-sky-50/40";
|
||||
return (
|
||||
<div
|
||||
key={event.id}
|
||||
className={`rounded-xl border border-slate-200 p-2 ${bucketClass}`}
|
||||
>
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div className="min-w-0 space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-[0.2em] text-slate-500">
|
||||
{dateLabel}
|
||||
</p>
|
||||
<p className="text-sm font-semibold" title={event.title}>
|
||||
{event.title}
|
||||
</p>
|
||||
<div className="flex flex-wrap items-center gap-2 text-[11px] text-slate-600">
|
||||
<span className="truncate" title={categoryName}>
|
||||
{categoryName}
|
||||
</span>
|
||||
<span>•</span>
|
||||
<span className="truncate" title={locationLabel}>
|
||||
{locationLabel}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{isAdmin && (
|
||||
<input
|
||||
type="checkbox"
|
||||
aria-label={`${event.title} auswählen`}
|
||||
checked={bulkSelection.has(event.id)}
|
||||
onChange={() => toggleBulkSelection(event.id)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-2 flex items-center justify-between gap-2">
|
||||
<div className="flex flex-nowrap items-center gap-1">
|
||||
{canManageView && (
|
||||
<ViewToggleButton
|
||||
isSelected={selectedEventIds.has(event.id)}
|
||||
onClick={() => toggleEvent(event.id)}
|
||||
size="sm"
|
||||
/>
|
||||
)}
|
||||
{isAdmin && (
|
||||
<button
|
||||
type="button"
|
||||
className="rounded-full border border-slate-200 p-1.5 text-slate-600"
|
||||
onClick={() => {
|
||||
setEditStatus(null);
|
||||
setEditError(null);
|
||||
setEditEvent(event);
|
||||
setIsEditOpen(true);
|
||||
}}
|
||||
aria-label="Termin bearbeiten"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
className="h-3.5 w-3.5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<path
|
||||
d="M4 20h4l10-10-4-4L4 16v4z"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path d="M13 7l4 4" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className="rounded-full border border-slate-200 p-1.5 text-slate-600"
|
||||
onClick={() => setDetailsEvent(event)}
|
||||
aria-label="Termin Details"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
className="h-3.5 w-3.5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<circle cx="12" cy="12" r="9" />
|
||||
<path d="M12 8h.01M12 12v4" strokeLinecap="round" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
{event.locationLat && event.locationLng && (
|
||||
<a
|
||||
className="inline-flex items-center justify-center rounded-full border border-slate-200 p-1.5 text-slate-600"
|
||||
href={`https://maps.google.com/?q=${event.locationLat},${event.locationLng}&z=14`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
title="Google Maps"
|
||||
aria-label="Google Maps"
|
||||
>
|
||||
<IconMapPin className="h-3.5 w-3.5" />
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
<div className="hidden overflow-x-auto md:block">
|
||||
<table className="list-table w-full table-fixed text-left text-sm">
|
||||
<thead className="text-xs uppercase tracking-[0.2em] text-slate-500">
|
||||
<tr>
|
||||
@@ -2551,9 +2678,9 @@ function SortIcon({
|
||||
);
|
||||
}
|
||||
|
||||
function IconMapPin() {
|
||||
function IconMapPin({ className = "h-4 w-4" }: { className?: string }) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<svg viewBox="0 0 24 24" className={className} fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<path d="M12 21s6-6.5 6-11a6 6 0 10-12 0c0 4.5 6 11 6 11z" strokeLinecap="round" strokeLinejoin="round" />
|
||||
<circle cx="12" cy="10" r="2.5" />
|
||||
</svg>
|
||||
|
||||
Reference in New Issue
Block a user