Aktueller Stand
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user