collab attachments, multi-day events, calendar improvements
- Collab buckets sync attachments alongside cards (images/PDFs/audio). New /api/collab-attachments endpoint on relay, encrypted at rest, bucket-scoped for members. - CalDAV multi-day events via **Bis:** body field. Calendar renders event on every day in range with day counter (1/6, 2/6, ...). - Calendar preserves month across close/reopen (only jumps to today on first open). - Calendar title: centered nav group with [MM-DD] Mon Y [KW-KW] — dimmed brackets, fixed width so nothing wiggles. - Editor: scratchpad uses custom confirm, autobackup-draft dialog replaced with custom styled dialog. - Scanlines theme feature removed (performance issue). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
002562b1d3
commit
ca47052768
11 files changed
+254
-64
No files matched your search
+36
-4
@@ -171,6 +171,12 @@ class CalDavSync
|
||||
$time = $zm[1];
|
||||
$timeEnd = $zm[2] ?? '';
|
||||
}
|
||||
// Multi-day: **Bis:** 2026-04-20 or **Bis:** 2026-04-20 18:00
|
||||
$endDate = ''; $endTime = '';
|
||||
if (preg_match('/\*\*Bis:\*\*\s*(\d{4}-\d{2}-\d{2})(?:\s+(\d{1,2}:\d{2}))?/i', $body, $bm)) {
|
||||
$endDate = $bm[1];
|
||||
$endTime = $bm[2] ?? '';
|
||||
}
|
||||
$location = '';
|
||||
if (preg_match('/\*\*Ort:\*\*\s*(.+)/i', $body, $lm)) $location = trim($lm[1]);
|
||||
$description = '';
|
||||
@@ -178,9 +184,19 @@ class CalDavSync
|
||||
|
||||
// Build DTSTART/DTEND
|
||||
$dateCompact = str_replace('-', '', $date);
|
||||
$endDateCompact = $endDate ? str_replace('-', '', $endDate) : '';
|
||||
if ($time) {
|
||||
$dtstart = $dateCompact . 'T' . str_replace(':', '', $time) . '00';
|
||||
if ($timeEnd) {
|
||||
if ($endDate) {
|
||||
// Multi-day with time — use end date + end time (or start time + 1h)
|
||||
$useEndTime = $endTime ?: $time;
|
||||
if (!$endTime) {
|
||||
$ts = strtotime($endDate . ' ' . $useEndTime);
|
||||
$dtend = date('Ymd\THis', $ts + 3600);
|
||||
} else {
|
||||
$dtend = $endDateCompact . 'T' . str_replace(':', '', $endTime) . '00';
|
||||
}
|
||||
} elseif ($timeEnd) {
|
||||
$dtend = $dateCompact . 'T' . str_replace(':', '', $timeEnd) . '00';
|
||||
} else {
|
||||
// Default: +1 hour
|
||||
@@ -189,8 +205,13 @@ class CalDavSync
|
||||
}
|
||||
} else {
|
||||
$dtstart = $dateCompact;
|
||||
// All-day: DTEND = next day
|
||||
$dtend = date('Ymd', strtotime($date . ' +1 day'));
|
||||
if ($endDate) {
|
||||
// Multi-day all-day: DTEND is exclusive, so +1 day after end
|
||||
$dtend = date('Ymd', strtotime($endDate . ' +1 day'));
|
||||
} else {
|
||||
// Single-day all-day: DTEND = next day
|
||||
$dtend = date('Ymd', strtotime($date . ' +1 day'));
|
||||
}
|
||||
}
|
||||
|
||||
$uid = $card['caldav_uid'] ?: 'card-' . $card['id'] . '@hyprcrd';
|
||||
@@ -224,12 +245,22 @@ class CalDavSync
|
||||
|
||||
$time = '';
|
||||
$timeEnd = '';
|
||||
$endDate = '';
|
||||
if (preg_match('/T(\d{2})(\d{2})/', $dt, $hm)) {
|
||||
$time = "{$hm[1]}:{$hm[2]}";
|
||||
}
|
||||
if (!empty($vevent['dtend']) && preg_match('/T(\d{2})(\d{2})/', $vevent['dtend'], $hm2)) {
|
||||
$timeEnd = "{$hm2[1]}:{$hm2[2]}";
|
||||
}
|
||||
// Detect multi-day event: dtend's date > dtstart's date
|
||||
if (!empty($vevent['dtend']) && preg_match('/^(\d{4})(\d{2})(\d{2})/', $vevent['dtend'], $edm)) {
|
||||
$endIso = "{$edm[1]}-{$edm[2]}-{$edm[3]}";
|
||||
// For all-day events, dtend is exclusive — subtract one day
|
||||
if (!$time && !empty($vevent['dtend']) && strpos($vevent['dtend'], 'T') === false) {
|
||||
$endIso = date('Y-m-d', strtotime($endIso . ' -1 day'));
|
||||
}
|
||||
if ($endIso > $date) $endDate = $endIso;
|
||||
}
|
||||
|
||||
$summary = $vevent['summary'] ?? 'Termin';
|
||||
$title = $summary ? "{$date} — {$summary}" : $date;
|
||||
@@ -244,7 +275,8 @@ class CalDavSync
|
||||
}
|
||||
|
||||
$zeitLine = $time ? ($timeEnd ? "{$time}-{$timeEnd}" : $time) : '';
|
||||
$body = "**Zeit:** {$zeitLine}\n**Ort:** " . ($vevent['location'] ?? '') . "\n**Teilnehmer:** \n\n---\n\n**Notizen:**\n" . ($vevent['description'] ?? '') . "\n\n{$tag}";
|
||||
$bisLine = $endDate ? ("\n**Bis:** " . $endDate . ($timeEnd && $endDate ? ' ' . $timeEnd : '')) : '';
|
||||
$body = "**Zeit:** {$zeitLine}{$bisLine}\n**Ort:** " . ($vevent['location'] ?? '') . "\n**Teilnehmer:** \n\n---\n\n**Notizen:**\n" . ($vevent['description'] ?? '') . "\n\n{$tag}";
|
||||
|
||||
// Color: birthdays pink, others orange
|
||||
$defaultColor = $isBirthdayCal ? '#fb7185' : '#fb923c';
|
||||
|
||||
Reference in new issue
Block a user