feat: CalDAV-URLs im Kalender-Menue anzeigen

Im Drei-Punkte-Menue jedes Kalenders wird jetzt ein Info-Block mit
den CalDAV-URLs angezeigt:

* Auto-Discovery URL fuer Thunderbird / DAVx5 / Apple Calendar
* Direkt-URL fuer diesen speziellen Kalender (z.B. Outlook
  CalDAV-Synchronizer)
* Kurz-Hinweis welcher Client welche URL nimmt

Jede URL hat ein Kopier-Icon. Ergaenzt den bestehenden iCal-Link
um die bidirektionale Sync-Moeglichkeit ueber CalDAV.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Hacker 2026-04-12 13:08:11 +02:00
parent fda9e685a9
commit ce4faedd88
1 changed files with 40 additions and 0 deletions

View File

@ -203,6 +203,29 @@
</div>
</div>
<div class="field caldav-block">
<label><i class="pi pi-info-circle"></i> CalDAV-Zugang (native Sync)</label>
<p class="caldav-hint">
Im Handy/Laptop-Kalender als CalDAV-Account hinzufuegen. Benutzername
und Passwort sind deine normalen Mini-Cloud-Zugangsdaten.
</p>
<div class="url-row">
<strong>Auto-Discovery</strong>
<code>{{ origin }}/dav/</code>
<Button icon="pi pi-copy" text size="small" title="Kopieren" @click="copyText(origin + '/dav/')" />
</div>
<div class="url-row">
<strong>Dieser Kalender (direkt)</strong>
<code>{{ origin }}/dav/{{ username }}/cal-{{ selectedCal.id }}/</code>
<Button icon="pi pi-copy" text size="small" title="Kopieren"
@click="copyText(`${origin}/dav/${username}/cal-${selectedCal.id}/`)" />
</div>
<div class="caldav-clients">
<div><strong>Thunderbird / DAVx5 / Apple</strong>: Auto-Discovery-URL benutzen</div>
<div><strong>Outlook (CalDAV-Synchronizer)</strong>: Direkt-URL</div>
</div>
</div>
<Button v-if="selectedCal.permission === 'owner'" label="Kalender loeschen"
severity="danger" text size="small" @click="confirmDeleteCal = true" />
</div>
@ -239,6 +262,7 @@
<script setup>
import { ref, computed, onMounted, reactive, watch } from 'vue'
import { useToast } from 'primevue/usetoast'
import { useAuthStore } from '../stores/auth'
import apiClient from '../api/client'
import Button from 'primevue/button'
import Dialog from 'primevue/dialog'
@ -253,6 +277,9 @@ import rrulePlugin from '@fullcalendar/rrule'
import deLocale from '@fullcalendar/core/locales/de'
const toast = useToast()
const auth = useAuthStore()
const origin = computed(() => window.location.origin)
const username = computed(() => auth.user?.username || '')
const calendars = ref([])
const visibleCalendars = reactive({})
const fcRef = ref(null)
@ -789,6 +816,11 @@ function copyIcal() {
toast.add({ severity: 'info', summary: 'Link kopiert', life: 2000 })
}
function copyText(text) {
navigator.clipboard.writeText(text)
toast.add({ severity: 'info', summary: 'Kopiert', life: 1500 })
}
async function deleteCalendar() {
if (!selectedCal.value) return
await apiClient.delete(`/calendars/${selectedCal.value.id}`)
@ -868,6 +900,14 @@ onMounted(async () => {
.ical-block { border-top: 1px solid var(--p-surface-200); padding-top: 1rem; margin-top: 1rem; }
.ical-url { font-size: 0.8rem; display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
.ical-url code { background: var(--p-surface-100); padding: 0.25rem 0.5rem; border-radius: 4px; word-break: break-all; }
.caldav-block { border-top: 1px solid var(--p-surface-200); padding-top: 1rem; margin-top: 1rem; }
.caldav-hint { font-size: 0.8rem; color: var(--p-text-muted-color); margin: 0 0 0.75rem; }
.url-row { display: flex; gap: 0.5rem; align-items: center; margin-bottom: 0.5rem; flex-wrap: wrap; }
.url-row strong { min-width: 160px; font-size: 0.8rem; }
.url-row code { background: var(--p-surface-100); padding: 0.25rem 0.5rem; border-radius: 4px;
font-size: 0.8rem; word-break: break-all; flex: 1; }
.caldav-clients { font-size: 0.75rem; color: var(--p-text-muted-color); margin-top: 0.5rem; }
.caldav-clients div { margin-bottom: 0.15rem; }
.hint-badge { font-size: 0.75rem; color: var(--p-primary-700); display: inline-flex; gap: 0.25rem; align-items: center; }
.fc-event-content-inner { display: flex; align-items: center; gap: 0.2rem; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding: 0 2px; }
.fc-event-content-inner .fc-icon { flex-shrink: 0; font-size: 0.85em; }