Aktueller Stand

This commit is contained in:
2026-01-17 17:19:11 +01:00
parent 056d798fbe
commit 07f41f3ed6

View File

@@ -527,6 +527,27 @@ export default function CalendarBoard() {
setFormOpen(true);
};
const applyTruncatedTitles = (root: HTMLElement) => {
const elements = Array.from(
root.querySelectorAll<HTMLElement>(".event-shell .truncate")
);
elements.forEach((element) => {
const text = element.textContent?.trim();
if (!text) {
element.removeAttribute("title");
return;
}
const isTruncated =
element.scrollWidth > element.clientWidth ||
element.scrollHeight > element.clientHeight;
if (isTruncated) {
element.setAttribute("title", text);
} else {
element.removeAttribute("title");
}
});
};
const calendarEvents = useMemo(
() =>
events.map((event) => ({
@@ -1061,6 +1082,10 @@ export default function CalendarBoard() {
</div>
);
}}
eventDidMount={(info) => {
if (!info.el) return;
requestAnimationFrame(() => applyTruncatedTitles(info.el));
}}
height="auto"
datesSet={(arg) => {
setActiveRange({
@@ -1467,57 +1492,77 @@ export default function CalendarBoard() {
</td>
</tr>
) : (
displayedEvents.map((event) => (
<tr
key={event.id}
data-bucket={getDateBucket(event.startAt)}
className={`border-t border-slate-200 ${
getDateBucket(event.startAt) === "past"
? "bg-slate-50 text-slate-500"
: getDateBucket(event.startAt) === "today"
? "bg-amber-50/60"
: getDateBucket(event.startAt) === "tomorrow"
? "bg-emerald-50/60"
: "bg-sky-50/40"
}`}
>
{isAdmin && (
<td className="py-3 pr-3 pl-2">
<input
type="checkbox"
aria-label={`${event.title} auswählen`}
checked={bulkSelection.has(event.id)}
onChange={() => toggleBulkSelection(event.id)}
/>
displayedEvents.map((event) => {
const categoryName = event.category?.name || "Ohne Kategorie";
const locationLabel = formatLocation(event.location);
return (
<tr
key={event.id}
data-bucket={getDateBucket(event.startAt)}
className={`border-t border-slate-200 ${
getDateBucket(event.startAt) === "past"
? "bg-slate-50 text-slate-500"
: getDateBucket(event.startAt) === "today"
? "bg-amber-50/60"
: getDateBucket(event.startAt) === "tomorrow"
? "bg-emerald-50/60"
: "bg-sky-50/40"
}`}
>
{isAdmin && (
<td className="py-3 pr-3 pl-2">
<input
type="checkbox"
aria-label={`${event.title} auswählen`}
checked={bulkSelection.has(event.id)}
onChange={() => toggleBulkSelection(event.id)}
/>
</td>
)}
<td className="py-3 pr-3 pl-2 whitespace-nowrap">
{new Date(event.startAt).toLocaleString("de-DE", {
dateStyle: "medium",
timeStyle: "short"
})}
</td>
)}
<td className="py-3 pr-3 pl-2 whitespace-nowrap">
{new Date(event.startAt).toLocaleString("de-DE", {
dateStyle: "medium",
timeStyle: "short"
})}
</td>
<td className="py-3 pr-3 font-medium">{event.title}</td>
<td className="py-3 pr-3">
{event.category?.name || "Ohne Kategorie"}
</td>
<td className="py-3 pr-3">
<div className="flex items-center justify-between gap-2">
<span className="flex-1">{formatLocation(event.location)}</span>
{event.locationLat && event.locationLng && (
<a
className="inline-flex items-center justify-center rounded-full border border-slate-200 p-1 text-slate-600 hover:bg-slate-100"
href={`https://maps.google.com/?q=${event.locationLat},${event.locationLng}&z=14`}
target="_blank"
rel="noreferrer"
title="Google Maps"
aria-label="Google Maps"
<td className="py-3 pr-3 font-medium">
<span
className="block max-w-[200px] truncate sm:max-w-[280px] lg:max-w-[420px] xl:max-w-[520px] 2xl:max-w-[640px]"
title={event.title}
>
{event.title}
</span>
</td>
<td className="py-3 pr-3">
<span
className="block max-w-[160px] truncate sm:max-w-[220px] lg:max-w-[280px] xl:max-w-[320px]"
title={categoryName}
>
{categoryName}
</span>
</td>
<td className="py-3 pr-3">
<div className="flex items-center justify-between gap-2">
<span
className="min-w-0 flex-1 truncate"
title={locationLabel}
>
<IconMapPin />
</a>
)}
</div>
</td>
{locationLabel}
</span>
{event.locationLat && event.locationLng && (
<a
className="inline-flex items-center justify-center rounded-full border border-slate-200 p-1 text-slate-600 hover:bg-slate-100"
href={`https://maps.google.com/?q=${event.locationLat},${event.locationLng}&z=14`}
target="_blank"
rel="noreferrer"
title="Google Maps"
aria-label="Google Maps"
>
<IconMapPin />
</a>
)}
</div>
</td>
<td className="py-3 pr-3">
<div className="flex flex-nowrap gap-1">
{canManageView && (
@@ -1577,8 +1622,9 @@ export default function CalendarBoard() {
</button>
</div>
</td>
</tr>
))
</tr>
);
})
)}
</tbody>
</table>