Files
Calendarr/frontend/index.html
Scarriffle d1c5b66230 feat: web settings restructure + popup drag + calendar management table (v52)
- Remove "Ansicht" tab; move Kalenderansicht to top of Darstellung
- Reorder Darstellung: Kalenderansicht → Sprache → Stundenhöhe → Farben
- Move Standard-Termindauer to Profil tab as contrast-button selector
- Replace per-source account sections in Kalender tab with unified
  calendar management table (Name/Herkunft/Ausgeblendet/Benachrichtigungen/
  Export·Import/Sync/Delete) covering all calendar sources
- Add "Konto hinzufügen" buttons (Lokal/CalDAV/iCal/HA/Google) to Kalender tab
- Popup drag-to-move via pointer capture on .popup-header

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 20:36:09 +02:00

1072 lines
58 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, viewport-fit=cover" />
<!-- Title wird beim Laden aus version.js dynamisch gesetzt -->
<title>Calendarr</title>
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg" />
<link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#4285f4" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="Calendarr" />
<link rel="apple-touch-icon" href="/icons/icon-192.png" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.6.2/cropper.min.css" />
<link rel="stylesheet" href="/static/css/app.css" />
</head>
<body>
<!-- ─── SETUP SCREEN ─────────────────────────────────────── -->
<div id="screen-setup" class="auth-screen hidden">
<div class="auth-card">
<div class="auth-logo">
<svg class="logo-icon" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
<h1>Calendarr</h1>
</div>
<h2>Ersteinrichtung</h2>
<p class="auth-sub">Erstelle den Administrator-Account</p>
<form id="setup-form">
<div class="form-group">
<label>Benutzername</label>
<input type="text" id="setup-username" required autocomplete="username" />
</div>
<div class="form-group">
<label>E-Mail (optional)</label>
<input type="email" id="setup-email" autocomplete="email" />
</div>
<div class="form-group">
<label>Passwort</label>
<input type="password" id="setup-password" required autocomplete="new-password" />
</div>
<div class="form-group">
<label>Passwort wiederholen</label>
<input type="password" id="setup-password2" required autocomplete="new-password" />
</div>
<div id="setup-error" class="form-error hidden"></div>
<button type="submit" class="btn btn-primary btn-full">Admin-Account erstellen</button>
</form>
</div>
</div>
<!-- ─── LOGIN SCREEN ─────────────────────────────────────── -->
<div id="screen-login" class="auth-screen hidden">
<div class="auth-card">
<div class="auth-logo">
<svg class="logo-icon" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
<div>
<h1>Calendarr</h1>
<p class="auth-tagline">das minimalistische Kalender Frontend</p>
</div>
</div>
<h2>Anmelden</h2>
<form id="login-form">
<div class="form-group">
<label>Benutzername</label>
<input type="text" id="login-username" required autocomplete="username" />
</div>
<div class="form-group">
<label>Passwort</label>
<input type="password" id="login-password" required autocomplete="current-password" />
</div>
<div class="form-group hidden" id="login-totp-row">
<label>2FA-Code</label>
<input type="text" id="login-totp" placeholder="6-stelliger Code" maxlength="6" inputmode="numeric" autocomplete="one-time-code" />
</div>
<label class="toggle-label" style="margin-bottom:14px">
<input type="checkbox" id="login-remember" /> Angemeldet bleiben
</label>
<div id="login-error" class="form-error hidden"></div>
<button type="submit" class="btn btn-primary btn-full">Anmelden</button>
</form>
</div>
<button class="impressum-link" onclick="openImpressum()">©&nbsp;2026&nbsp;Scarriffleservices</button>
</div>
<!-- ─── MAIN APP ──────────────────────────────────────────── -->
<div id="app" class="hidden">
<!-- TOP BAR -->
<header class="topbar">
<div class="topbar-left">
<button class="icon-btn" id="sidebar-toggle" title="Seitenleiste">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg>
</button>
<div class="topbar-logo">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
<span class="logo-text">Calendarr</span>
</div>
</div>
<div class="topbar-center">
<button class="btn btn-ghost" id="btn-today" data-i18n="btn_today">Heute</button>
<button class="icon-btn" id="btn-prev">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>
</button>
<button class="icon-btn" id="btn-next">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
</button>
<h2 id="view-title" class="view-title"></h2>
</div>
<div class="topbar-right">
<div class="view-switcher">
<button class="view-btn" data-view="quarter" data-i18n="view_quarter">Quartal</button>
<button class="view-btn" data-view="month" data-i18n="view_month">Monat</button>
<button class="view-btn" data-view="week" data-i18n="view_week">Woche</button>
<button class="view-btn" data-view="day" data-i18n="view_day">Tag</button>
<button class="view-btn" data-view="agenda" data-i18n="view_agenda">Termine</button>
</div>
<div class="view-mobile-wrapper">
<button class="icon-btn" id="btn-view-mobile" title="Ansicht wechseln" aria-label="Ansicht wechseln">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z"/></svg>
</button>
<div id="view-mobile-dropdown" class="user-dropdown hidden" style="right:0;top:50px;min-width:180px">
<button class="dropdown-item" data-mobile-view="quarter" data-i18n="view_quarter">Quartal</button>
<button class="dropdown-item" data-mobile-view="month" data-i18n="view_month">Monat</button>
<button class="dropdown-item" data-mobile-view="week" data-i18n="view_week">Woche</button>
<button class="dropdown-item" data-mobile-view="day" data-i18n="view_day">Tag</button>
<button class="dropdown-item" data-mobile-view="agenda" data-i18n="view_agenda">Termine</button>
<button class="dropdown-item" id="btn-today-mobile" style="border-top:1px solid var(--border)" data-i18n="btn_today">Heute</button>
</div>
</div>
<button class="icon-btn" id="btn-settings" data-i18n-title="settings_title" title="Einstellungen">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z"/></svg>
</button>
<div class="user-menu-wrapper">
<div class="user-avatar" id="user-avatar" title="Benutzer"></div>
<div class="user-dropdown hidden" id="user-dropdown">
<div class="dropdown-user" id="dropdown-username"></div>
<button class="dropdown-item" id="btn-profile">
<svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></svg>
<span data-i18n="btn_profile">Profil</span>
</button>
<button class="dropdown-item dropdown-item-mobile-only" id="btn-settings-from-user">
<svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16"><path d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z"/></svg>
<span data-i18n="settings_title">Einstellungen</span>
</button>
<button class="dropdown-item" id="btn-logout">
<svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16"><path d="M17 7l-1.41 1.41L18.17 11H8v2h10.17l-2.58 2.58L17 17l5-5zM4 5h8V3H4c-1.1 0-2 .9-2 2v24c0 1.1.9 2 2 2h8v-2H4V5z"/></svg>
<span data-i18n="btn_logout">Abmelden</span>
</button>
</div>
</div>
</div>
</header>
<!-- CONTENT -->
<div class="content-wrapper">
<!-- SIDEBAR -->
<aside class="sidebar" id="sidebar">
<div class="sidebar-inner">
<button class="btn btn-fab" id="btn-create-event">
<svg viewBox="0 0 24 24" fill="currentColor" width="24" height="24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
<span data-i18n="btn_create">Erstellen</span>
</button>
<!-- Mini Calendar -->
<div class="mini-cal" id="mini-cal">
<div class="mini-cal-header">
<button class="icon-btn mini-btn" id="mini-prev">&#8249;</button>
<span id="mini-title" class="mini-title"></span>
<button class="icon-btn mini-btn" id="mini-next">&#8250;</button>
</div>
<div class="mini-cal-grid">
<div class="mini-dow">Mo</div><div class="mini-dow">Di</div>
<div class="mini-dow">Mi</div><div class="mini-dow">Do</div>
<div class="mini-dow">Fr</div><div class="mini-dow">Sa</div>
<div class="mini-dow">So</div>
</div>
<div class="mini-cal-days" id="mini-days"></div>
</div>
<!-- Group members (shown only in the group overlay; hide/show people) -->
<div class="cal-list hidden" id="group-members">
<div class="cal-list-header">
<span data-i18n="group_members">Mitglieder</span>
</div>
<div id="group-members-items"></div>
</div>
<!-- Calendar List -->
<div class="cal-list" id="cal-list">
<div class="cal-list-header">
<span data-i18n="my_calendars">Meine Kalender</span>
<div class="add-cal-dropdown-wrap">
<button class="icon-btn mini-btn" id="btn-add-cal" title="Kalender hinzufügen">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
</button>
<div class="add-cal-dropdown hidden" id="add-cal-dropdown">
<button data-action="local">Lokaler Kalender</button>
<button data-action="caldav">CalDAV-Konto</button>
<button data-action="ical">iCal-URL abonnieren</button>
<button data-action="google">Google Kalender</button>
<button data-action="homeassistant">Home Assistant</button>
</div>
</div>
</div>
<div id="cal-list-items"></div>
</div>
<!-- Groups -->
<div class="cal-list" id="group-list">
<div class="cal-list-header">
<span data-i18n="groups_title">Gruppen</span>
<button class="icon-btn mini-btn" id="btn-add-group" data-i18n-title="group_create" title="Gruppe erstellen">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
</button>
</div>
<div id="group-list-items"></div>
</div>
</div>
<button class="sidebar-copyright" id="sidebar-copyright" onclick="openImpressum()">©&nbsp;2026&nbsp;Scarriffleservices</button>
</aside>
<div id="sidebar-backdrop" class="sidebar-backdrop"></div>
<!-- MAIN VIEW -->
<main class="main-view" id="main-view">
<div id="group-view-banner" class="group-view-banner hidden">
<span id="group-view-label"></span>
<div style="flex:1"></div>
<button class="btn btn-primary btn-sm" id="group-view-new-event" data-i18n="group_new_event">+ Gruppentermin</button>
<button class="btn btn-ghost btn-sm" id="group-view-exit" data-i18n="group_exit">Gruppenansicht verlassen</button>
</div>
<div id="view-container"></div>
</main>
</div><!-- content-wrapper -->
</div><!-- app -->
<!-- ─── MODALS ────────────────────────────────────────────── -->
<!-- Event Modal -->
<div id="modal-event" class="modal-overlay hidden">
<div class="modal-card" style="max-width:520px">
<div class="modal-header">
<h3 id="modal-event-title-label">Termin erstellen</h3>
<button class="icon-btn modal-close" data-modal="modal-event">&times;</button>
</div>
<div class="modal-body">
<div class="form-group">
<input type="text" id="ev-title" placeholder="Titel hinzufügen" class="input-title" />
</div>
<div class="form-row">
<label class="toggle-label">
<input type="checkbox" id="ev-allday" /> Ganztägig
</label>
</div>
<div class="form-row" id="ev-time-row">
<div class="form-group half">
<label>Start</label>
<input type="hidden" id="ev-start" />
<div class="dt-display" id="ev-start-display" tabindex="0" role="button">
<span class="dt-display-text"></span>
<svg class="dt-display-icon" viewBox="0 0 24 24" fill="currentColor" width="16" height="16"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.1 0-2 .9-2 2v24a2 2 0 002 2h14a2 2 0 002-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v21zM7 10h5v17H7z"/></svg>
</div>
</div>
<div class="form-group half">
<label>Ende</label>
<input type="hidden" id="ev-end" />
<div class="dt-display" id="ev-end-display" tabindex="0" role="button">
<span class="dt-display-text"></span>
<svg class="dt-display-icon" viewBox="0 0 24 24" fill="currentColor" width="16" height="16"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.1 0-2 .9-2 2v24a2 2 0 002 2h14a2 2 0 002-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v21zM7 10h5v17H7z"/></svg>
</div>
</div>
</div>
<div class="form-row" id="ev-date-row" style="display:none">
<div class="form-group half">
<label>Start</label>
<input type="hidden" id="ev-start-date" />
<div class="dt-display" id="ev-start-date-display" tabindex="0" role="button">
<span class="dt-display-text"></span>
<svg class="dt-display-icon" viewBox="0 0 24 24" fill="currentColor" width="16" height="16"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.1 0-2 .9-2 2v24a2 2 0 002 2h14a2 2 0 002-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v21zM7 10h5v17H7z"/></svg>
</div>
</div>
<div class="form-group half">
<label>Ende</label>
<input type="hidden" id="ev-end-date" />
<div class="dt-display" id="ev-end-date-display" tabindex="0" role="button">
<span class="dt-display-text"></span>
<svg class="dt-display-icon" viewBox="0 0 24 24" fill="currentColor" width="16" height="16"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.1 0-2 .9-2 2v24a2 2 0 002 2h14a2 2 0 002-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v21zM7 10h5v17H7z"/></svg>
</div>
</div>
</div>
<div class="form-group">
<label id="ev-rec-label">Wiederholung</label>
<select id="ev-recurrence">
<option value="">Keine</option>
<option value="FREQ=DAILY">Täglich</option>
<option value="FREQ=WEEKLY">Wöchentlich</option>
<option value="FREQ=MONTHLY">Monatlich</option>
<option value="FREQ=YEARLY">Jährlich</option>
<option value="custom">Benutzerdefiniert…</option>
</select>
</div>
<div id="ev-recurrence-custom" class="form-group hidden">
<div class="form-row" style="gap:8px;align-items:center">
<label style="white-space:nowrap" id="ev-rec-every-label">Alle</label>
<input type="number" id="ev-rec-interval" value="1" min="1" max="99" style="width:60px" />
<select id="ev-rec-freq">
<option value="DAILY">Tage</option>
<option value="WEEKLY">Wochen</option>
<option value="MONTHLY">Monate</option>
</select>
</div>
<div id="ev-rec-weekdays" class="rec-weekdays hidden">
<button type="button" class="rec-day-btn" data-day="MO">Mo</button>
<button type="button" class="rec-day-btn" data-day="TU">Di</button>
<button type="button" class="rec-day-btn" data-day="WE">Mi</button>
<button type="button" class="rec-day-btn" data-day="TH">Do</button>
<button type="button" class="rec-day-btn" data-day="FR">Fr</button>
<button type="button" class="rec-day-btn" data-day="SA">Sa</button>
<button type="button" class="rec-day-btn" data-day="SU">So</button>
</div>
<div class="form-row" style="gap:8px;align-items:center;margin-top:8px">
<label id="ev-rec-ends-label">Endet</label>
<select id="ev-rec-end-type">
<option value="never">Nie</option>
<option value="count">Nach Anzahl</option>
<option value="until">Am Datum</option>
</select>
</div>
<div id="ev-rec-end-count" class="hidden" style="margin-top:4px">
<input type="number" id="ev-rec-count" value="10" min="1" max="999" style="width:80px" />
<span id="ev-rec-occ-label"> Termine</span>
</div>
<div id="ev-rec-end-until" class="hidden" style="margin-top:4px">
<input type="hidden" id="ev-rec-until" />
<div class="dt-display" id="ev-rec-until-display" tabindex="0" role="button">
<span class="dt-display-text"></span>
<svg class="dt-display-icon" viewBox="0 0 24 24" fill="currentColor" width="16" height="16"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.1 0-2 .9-2 2v24a2 2 0 002 2h14a2 2 0 002-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v21zM7 10h5v17H7z"/></svg>
</div>
</div>
</div>
<div class="form-group">
<label>Kalender</label>
<!-- Hidden native select stays the value holder + change-event source;
the custom dropdown below renders colour dots and group icons. -->
<select id="ev-calendar" class="cal-native-hidden"></select>
<div class="cal-select" id="ev-cal-select">
<button type="button" class="cal-select-trigger" id="ev-cal-trigger" aria-haspopup="listbox" aria-expanded="false">
<span class="cal-select-current" id="ev-cal-current"></span>
<svg class="cal-select-chevron" viewBox="0 0 24 24" width="18" height="18" fill="currentColor"><path d="M7 10l5 5 5-5z"/></svg>
</button>
<div class="cal-select-menu hidden" id="ev-cal-menu" role="listbox"></div>
</div>
</div>
<div class="form-row" id="ev-private-row" style="display:none">
<label class="toggle-label">
<input type="checkbox" id="ev-private" /> <span data-i18n="event_private">Privat</span>
</label>
</div>
<div class="form-group">
<label>Ort</label>
<input type="text" id="ev-location" placeholder="Ort hinzufügen" />
</div>
<div class="form-group">
<label>Beschreibung</label>
<textarea id="ev-description" placeholder="Beschreibung hinzufügen" rows="3"></textarea>
</div>
<div class="form-group">
<label>Farbe</label>
<div class="ev-color-row">
<input type="text" id="ev-color-hex" class="ev-color-hex" maxlength="7" placeholder="#4285f4" spellcheck="false" />
<div class="ev-color-preview" id="ev-color-preview" title="Farbe wählen"></div>
</div>
</div>
<div class="form-group" id="ev-reminders-group" style="display:none">
<label data-i18n="reminders">Benachrichtigungen</label>
<div id="ev-reminders-hint" class="form-hint" style="display:none" data-i18n="reminders_calendar_off">Für diesen Kalender sind Benachrichtigungen deaktiviert Erinnerungen werden nicht ausgeführt.</div>
<div id="ev-reminders-list" class="ev-reminders-list"></div>
<button type="button" class="btn btn-ghost btn-sm" id="ev-reminder-add" data-i18n="reminder_add">Benachrichtigung hinzufügen</button>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-danger hidden" id="ev-delete">Löschen</button>
<div style="flex:1"></div>
<button class="btn btn-ghost" data-modal="modal-event">Abbrechen</button>
<button class="btn btn-primary" id="ev-save">Speichern</button>
</div>
</div>
</div>
<!-- Create Group Modal -->
<div id="modal-group" class="modal-overlay hidden">
<div class="modal-card" style="max-width:480px">
<div class="modal-header">
<h3 id="group-modal-title" data-i18n="group_create">Gruppe erstellen</h3>
<button class="icon-btn modal-close" data-modal="modal-group">&times;</button>
</div>
<div class="modal-body">
<div class="form-group">
<label data-i18n="group_name">Name</label>
<input type="text" id="group-name" data-i18n-placeholder="group_name_ph" placeholder="Gruppenname" />
</div>
<div class="form-group">
<label data-i18n="group_icon">Icon</label>
<div id="group-icon-picker" class="group-icon-picker"></div>
</div>
<div class="form-group">
<label data-i18n="group_members">Mitglieder</label>
<div id="group-member-picker" class="share-user-picker"></div>
</div>
<div class="form-group" id="group-colors-group" style="display:none">
<label data-i18n="group_member_colors">Farben der Mitglieder</label>
<div id="group-member-colors"></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-danger hidden" id="group-delete" data-i18n="group_delete">Gruppe löschen</button>
<div style="flex:1"></div>
<button class="btn btn-ghost" data-modal="modal-group" data-i18n="cancel">Abbrechen</button>
<button class="btn btn-primary" id="group-save" data-i18n="save">Speichern</button>
</div>
</div>
</div>
<!-- Share Calendar Modal -->
<div id="modal-share" class="modal-overlay hidden">
<div class="modal-card" style="max-width:480px">
<div class="modal-header">
<h3 data-i18n="share_title">Kalender teilen</h3>
<button class="icon-btn modal-close" data-modal="modal-share">&times;</button>
</div>
<div class="modal-body">
<h4 class="panel-title" data-i18n="share_current">Aktuelle Freigaben</h4>
<div id="share-current-list" class="accounts-list"></div>
<h4 class="panel-title" style="margin-top:20px" data-i18n="share_add">Benutzer hinzufügen</h4>
<div class="form-row" style="gap:8px;align-items:center">
<input type="text" id="share-user-search" data-i18n-placeholder="share_search" placeholder="Benutzer suchen…" style="flex:1" />
<select id="share-permission">
<option value="read" data-i18n="perm_read">Nur lesen</option>
<option value="read_write" data-i18n="perm_read_write">Lesen &amp; schreiben</option>
</select>
</div>
<div id="share-user-picker" class="share-user-picker"></div>
</div>
<div class="modal-footer">
<div style="flex:1"></div>
<button class="btn btn-primary" data-modal="modal-share" data-i18n="done">Fertig</button>
</div>
</div>
</div>
<!-- Delete Confirm Modal -->
<div id="modal-delete-confirm" class="modal-overlay hidden">
<div class="modal-card" style="max-width:400px">
<div class="modal-header">
<h3 id="delete-confirm-title">Termin löschen</h3>
<button class="icon-btn modal-close" data-modal="modal-delete-confirm">&times;</button>
</div>
<div class="modal-body">
<p id="delete-confirm-text"></p>
<div id="delete-series-options" class="hidden" style="margin-top:12px">
<label class="toggle-label" style="display:block;margin-bottom:8px">
<input type="radio" name="delete-scope" value="single" checked /> Nur diesen Termin
</label>
<label class="toggle-label" style="display:block">
<input type="radio" name="delete-scope" value="all" /> Alle Serienelemente
</label>
</div>
</div>
<div class="modal-footer">
<div style="flex:1"></div>
<button class="btn btn-ghost" data-modal="modal-delete-confirm">Abbrechen</button>
<button class="btn btn-danger" id="delete-confirm-ok">Löschen</button>
</div>
</div>
</div>
<!-- Event Detail Popup -->
<div id="popup-event" class="event-popup hidden">
<div class="popup-header">
<div class="popup-color-dot" id="popup-color-dot"></div>
<h4 id="popup-title"></h4>
<div class="popup-toolbar">
<button class="popup-icon-btn" id="popup-edit" title="Bearbeiten" aria-label="Bearbeiten">
<svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></svg>
</button>
<button class="popup-icon-btn" id="popup-copy" title="Kopieren" aria-label="Kopieren">
<svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>
</button>
<button class="popup-icon-btn popup-icon-btn-danger" id="popup-delete" title="Löschen" aria-label="Löschen">
<svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></svg>
</button>
<button class="popup-icon-btn popup-icon-btn-close" id="popup-close" title="Schließen" aria-label="Schließen">
<svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</div>
</div>
<div class="popup-body">
<div class="popup-row" id="popup-row-time">
<svg class="popup-row-icon" viewBox="0 0 24 24"><path d="M12 2a10 10 0 100 20 10 10 0 000-20zm0 18a8 8 0 110-16 8 8 0 010 16zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67V7z"/></svg>
<span id="popup-time"></span>
</div>
<div class="popup-row" id="popup-row-location" style="display:none">
<svg class="popup-row-icon" viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5A2.5 2.5 0 1112 6.5a2.5 2.5 0 010 5z"/></svg>
<span id="popup-location"></span>
</div>
<div class="popup-row popup-row-desc" id="popup-row-description" style="display:none">
<svg class="popup-row-icon" viewBox="0 0 24 24"><path d="M3 5h18v2H3V5zm0 6h18v2H3v-2zm0 6h12v2H3v-2z"/></svg>
<span id="popup-description"></span>
</div>
<div class="popup-row" id="popup-row-calendar">
<svg class="popup-row-icon" viewBox="0 0 24 24"><path d="M19 4h-1V2h-2v2H8V2H6v2H5a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2V6a2 2 0 00-2-2zm0 16H5V10h14v10zm0-12H5V6h14v2z"/></svg>
<span id="popup-calendar"></span>
</div>
<div class="popup-row" id="popup-row-creator" style="display:none">
<svg class="popup-row-icon" viewBox="0 0 24 24"><path d="M12 12a5 5 0 100-10 5 5 0 000 10zm0 2c-5.33 0-8 2.67-8 6v2h16v-2c0-3.33-2.67-6-8-6z"/></svg>
<span id="popup-creator"></span>
</div>
</div>
<div id="popup-copy-menu" class="popup-copy-menu hidden"></div>
</div>
<!-- Add CalDAV Account Modal -->
<div id="modal-account" class="modal-overlay hidden">
<div class="modal-card" style="max-width:480px">
<div class="modal-header">
<h3>CalDAV-Konto hinzufügen</h3>
<button class="icon-btn modal-close" data-modal="modal-account">&times;</button>
</div>
<div class="modal-body">
<div class="form-group">
<label>Anzeigename</label>
<input type="text" id="acc-name" placeholder="z.B. Mein Nextcloud" />
</div>
<div class="form-group">
<label>CalDAV-URL</label>
<input type="url" id="acc-url" placeholder="https://cloud.example.com/remote.php/dav" />
</div>
<div class="form-group">
<label>Benutzername</label>
<input type="text" id="acc-username" autocomplete="username" />
</div>
<div class="form-group">
<label>Passwort</label>
<input type="password" id="acc-password" autocomplete="current-password" />
</div>
<div class="form-group">
<label>Farbe</label>
<div class="ev-color-row">
<input type="text" id="acc-color-hex" class="ev-color-hex" maxlength="7" value="#4285f4" spellcheck="false" />
<div class="ev-color-preview" id="acc-color-preview" style="background:#4285f4" title="Farbe wählen"></div>
</div>
</div>
<div id="acc-error" class="form-error hidden"></div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" data-modal="modal-account">Abbrechen</button>
<button class="btn btn-primary" id="acc-save">Verbinden</button>
</div>
</div>
</div>
<!-- Local Calendar Modal -->
<div id="modal-local-cal" class="modal-overlay hidden">
<div class="modal-card" style="max-width:400px">
<div class="modal-header">
<h3>Lokalen Kalender erstellen</h3>
<button class="icon-btn modal-close" data-modal="modal-local-cal">&times;</button>
</div>
<div class="modal-body">
<div class="form-group">
<label>Name</label>
<input type="text" id="local-cal-name" placeholder="z.B. Persönlich" />
</div>
<div class="form-group">
<label>Farbe</label>
<div class="ev-color-row">
<input type="text" id="local-cal-color-hex" class="ev-color-hex" maxlength="7" value="#34a853" spellcheck="false" />
<div class="ev-color-preview" id="local-cal-color-preview" style="background:#34a853" title="Farbe wählen"></div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" data-modal="modal-local-cal">Abbrechen</button>
<button class="btn btn-primary" id="local-cal-save">Erstellen</button>
</div>
</div>
</div>
<!-- iCal Subscription Modal -->
<div id="modal-ical-sub" class="modal-overlay hidden">
<div class="modal-card" style="max-width:480px">
<div class="modal-header">
<h3>iCal-URL abonnieren</h3>
<button class="icon-btn modal-close" data-modal="modal-ical-sub">&times;</button>
</div>
<div class="modal-body">
<div class="form-group">
<label>Name</label>
<input type="text" id="ical-sub-name" placeholder="z.B. Feiertage" />
</div>
<div class="form-group">
<label>iCal-URL</label>
<input type="url" id="ical-sub-url" placeholder="https://example.com/calendar.ics" />
</div>
<div class="form-group">
<label>Farbe</label>
<div class="ev-color-row">
<input type="text" id="ical-sub-color-hex" class="ev-color-hex" maxlength="7" value="#46bdc6" spellcheck="false" />
<div class="ev-color-preview" id="ical-sub-color-preview" style="background:#46bdc6" title="Farbe wählen"></div>
</div>
</div>
<div class="form-group">
<label>Aktualisierung</label>
<select id="ical-sub-refresh">
<option value="15">Alle 15 Minuten</option>
<option value="30">Alle 30 Minuten</option>
<option value="60" selected>Stündlich</option>
<option value="360">Alle 6 Stunden</option>
<option value="1440">Täglich</option>
</select>
</div>
<div id="ical-sub-error" class="form-error hidden"></div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" data-modal="modal-ical-sub">Abbrechen</button>
<button class="btn btn-primary" id="ical-sub-save">Abonnieren</button>
</div>
</div>
</div>
<!-- Home Assistant Account Modal -->
<div id="modal-ha-account" class="modal-overlay hidden">
<div class="modal-card" style="max-width:480px">
<div class="modal-header">
<h3>Home Assistant verbinden</h3>
<button class="icon-btn modal-close" data-modal="modal-ha-account">&times;</button>
</div>
<div class="modal-body">
<div class="form-group">
<label>Anzeigename</label>
<input type="text" id="ha-account-name" placeholder="z.B. Mein Home Assistant" />
</div>
<div class="form-group">
<label>Home Assistant URL</label>
<input type="url" id="ha-account-url" placeholder="http://homeassistant.local:8123" />
</div>
<div style="margin-bottom:16px">
<div style="font-size:12px;font-weight:500;text-transform:uppercase;letter-spacing:.5px;color:var(--text-2);margin-bottom:8px">Anmeldemethode</div>
<div style="display:flex;gap:20px">
<label style="display:flex;align-items:center;gap:6px;cursor:pointer;color:var(--text-1);font-size:14px">
<input type="radio" name="ha-auth-method" value="oauth" id="ha-auth-oauth" checked style="width:auto;accent-color:var(--primary)" /> Mit Home Assistant anmelden
</label>
<label style="display:flex;align-items:center;gap:6px;cursor:pointer;color:var(--text-1);font-size:14px">
<input type="radio" name="ha-auth-method" value="token" id="ha-auth-token" style="width:auto;accent-color:var(--primary)" /> Long-Lived Token
</label>
</div>
</div>
<div id="ha-oauth-info" style="margin-bottom:16px;padding:10px 12px;background:var(--bg-app);border-radius:var(--radius-sm);font-size:13px;color:var(--text-2);line-height:1.5">
Du wirst zur Login-Seite deiner Home Assistant Instanz weitergeleitet und nach erfolgreichem Login wieder zurück zu Calendarr.
</div>
<div class="form-group hidden" id="ha-token-group">
<label>Long-Lived Access Token</label>
<input type="password" id="ha-account-token" placeholder="Token aus Profil → Sicherheit" autocomplete="off" />
</div>
<div id="ha-account-error" class="form-error hidden"></div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" data-modal="modal-ha-account">Abbrechen</button>
<button class="btn btn-primary" id="ha-account-save">Mit Home Assistant anmelden</button>
</div>
</div>
</div>
<!-- Settings Page -->
<div id="modal-settings" class="modal-overlay hidden">
<div class="settings-page-card">
<div class="settings-page-header">
<button class="icon-btn modal-close" data-modal="modal-settings" style="margin-right:8px">
<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>
</button>
<button class="icon-btn settings-nav-toggle" id="settings-nav-toggle" title="Menü" aria-label="Menü">
<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg>
</button>
<h3 data-i18n="settings_title">Einstellungen</h3>
<button class="btn btn-primary" id="settings-save" style="margin-left:auto" data-i18n="save">Speichern</button>
</div>
<div class="settings-page-body">
<div class="settings-nav-backdrop" id="settings-nav-backdrop"></div>
<nav class="settings-nav">
<button class="settings-nav-btn active" data-panel="profile" data-i18n="settings_nav_profile">Profil</button>
<button class="settings-nav-btn" data-panel="general" data-i18n="settings_nav_appearance">Darstellung</button>
<button class="settings-nav-btn" data-panel="accounts" data-i18n="settings_nav_calendars">Kalender</button>
<button class="settings-nav-btn hidden" data-panel="users" id="settings-nav-users" data-i18n="settings_nav_users">Benutzerverwaltung</button>
</nav>
<div class="settings-panels">
<!-- Profil: Name, Privatsphäre, geteilter Kalender -->
<div class="settings-panel active" id="settings-panel-profile">
<h4 class="panel-title" data-i18n="profile_account">Konto</h4>
<div class="form-group">
<label data-i18n="profile_display_name">Anzeigename</label>
<input type="text" id="cfg-display-name" data-i18n-placeholder="profile_display_name_ph" placeholder="Anzeigename" />
</div>
<div class="form-group">
<label data-i18n="profile_login_name">Login-Name</label>
<input type="text" id="cfg-login-name" spellcheck="false" autocapitalize="none" />
<p class="panel-desc" data-i18n="profile_login_name_desc">Klein geschrieben, fürs Anmelden. Groß-/Kleinschreibung egal.</p>
</div>
<div class="form-group">
<label>E-Mail</label>
<input type="email" id="cfg-email" placeholder="Keine E-Mail hinterlegt" />
</div>
<button class="btn btn-primary btn-sm" id="cfg-profile-save" data-i18n="save">Speichern</button>
<h4 class="panel-title" style="margin-top:24px" data-i18n="settings_privacy">Privatsphäre</h4>
<p class="panel-desc" data-i18n="settings_private_visibility_desc">Wie private Termine für andere Gruppenmitglieder erscheinen</p>
<div class="form-group">
<label data-i18n="settings_private_visibility">Private Termine für Gruppenmitglieder</label>
<select id="cfg-private-visibility">
<option value="busy" data-i18n="private_visibility_busy">Als „Beschäftigt“ anzeigen</option>
<option value="hidden" data-i18n="private_visibility_hidden">Ausblenden</option>
</select>
</div>
<h4 class="panel-title" style="margin-top:24px" data-i18n="settings_default_duration">Standard-Termindauer</h4>
<div class="contrast-selector" id="cfg-event-duration">
<button class="contrast-btn" data-val="15">15 min</button>
<button class="contrast-btn" data-val="30">30 min</button>
<button class="contrast-btn" data-val="45">45 min</button>
<button class="contrast-btn" data-val="60">1 h</button>
<button class="contrast-btn" data-val="90">1,5 h</button>
<button class="contrast-btn" data-val="120">2 h</button>
</div>
<h4 class="panel-title" style="margin-top:24px" data-i18n="settings_calendars">Geteilter Kalender</h4>
<p class="panel-desc" data-i18n="settings_group_visible_desc">Wähle, welcher deiner Kalender für deine Gruppenmitglieder sichtbar ist</p>
<div class="form-group">
<label data-i18n="settings_group_visible">Für Gruppen sichtbarer Kalender</label>
<div id="cfg-group-visible-list" class="cal-radio-list"></div>
</div>
</div>
<!-- Darstellung: Kalenderansicht, Sprache, Stundenhöhe, Farben -->
<div class="settings-panel" id="settings-panel-general">
<h4 class="panel-title" data-i18n="settings_calendar_view">Kalenderansicht</h4>
<div class="form-group">
<label data-i18n="settings_default_view">Standardansicht</label>
<select id="cfg-default-view">
<option value="month" data-i18n="view_month">Monat</option>
<option value="week" data-i18n="view_week">Woche</option>
<option value="day" data-i18n="view_day">Tag</option>
<option value="quarter" data-i18n="view_quarter">Quartal</option>
<option value="agenda" data-i18n="view_agenda">Termine</option>
</select>
</div>
<div class="form-group">
<label data-i18n="settings_week_start">Erster Wochentag</label>
<select id="cfg-week-start">
<option value="monday" data-i18n="week_start_monday">Montag</option>
<option value="sunday" data-i18n="week_start_sunday">Sonntag</option>
</select>
</div>
<div class="form-group">
<label class="toggle-label">
<input type="checkbox" id="cfg-dim-past" />
<span data-i18n="settings_dim_past">Vergangene Termine ausgrauen</span>
</label>
</div>
<h4 class="panel-title" style="margin-top:24px" data-i18n="settings_language">Sprache</h4>
<div class="form-group">
<select id="cfg-language">
<option value="de">Deutsch</option>
<option value="en">English</option>
</select>
</div>
<h4 class="panel-title" style="margin-top:24px" data-i18n="settings_hour_height">Stundenhöhe (Wochen- &amp; Tagesansicht)</h4>
<p class="panel-desc" data-i18n="settings_hour_height_desc">Wie viel Platz eine Stunde in der Zeitrasteransicht einnimmt</p>
<div class="contrast-selector" id="cfg-hour-height" data-setting="hour_height">
<button class="contrast-btn" data-val="28"><span class="hour-preview">━━</span><span class="contrast-lbl" data-i18n="hour_compact">Kompakt</span></button>
<button class="contrast-btn" data-val="44"><span class="hour-preview">━━━</span><span class="contrast-lbl" data-i18n="hour_normal">Normal</span></button>
<button class="contrast-btn" data-val="60"><span class="hour-preview">━━━━</span><span class="contrast-lbl" data-i18n="hour_comfort">Komfort</span></button>
<button class="contrast-btn" data-val="80"><span class="hour-preview">━━━━━</span><span class="contrast-lbl" data-i18n="hour_large">Gross</span></button>
</div>
<h4 class="panel-title" style="margin-top:24px" data-i18n="settings_colors">Farben</h4>
<div class="form-group">
<label data-i18n="settings_primary_color">Primärfarbe</label>
<div class="ev-color-row">
<input type="text" id="cfg-primary-hex" class="ev-color-hex" maxlength="7" spellcheck="false" />
<div class="ev-color-preview" id="cfg-primary-preview" data-i18n-title="color_pick" title="Farbe wählen"></div>
</div>
</div>
<div class="form-group">
<label data-i18n="settings_accent_color">Akzentfarbe</label>
<div class="ev-color-row">
<input type="text" id="cfg-accent-hex" class="ev-color-hex" maxlength="7" spellcheck="false" />
<div class="ev-color-preview" id="cfg-accent-preview" data-i18n-title="color_pick" title="Farbe wählen"></div>
</div>
</div>
<div class="form-group">
<label data-i18n="settings_today_color">Heutige-Tag-Farbe</label>
<div class="ev-color-row">
<input type="text" id="cfg-today-hex" class="ev-color-hex" maxlength="7" spellcheck="false" />
<div class="ev-color-preview" id="cfg-today-preview" data-i18n-title="color_pick" title="Farbe wählen"></div>
</div>
</div>
<div class="form-group">
<label data-i18n="settings_month_divider_color">Monatswechsel-Linie</label>
<div class="ev-color-row">
<input type="text" id="cfg-month-divider-hex" class="ev-color-hex" maxlength="7" spellcheck="false" />
<div class="ev-color-preview" id="cfg-month-divider-preview" data-i18n-title="color_pick" title="Farbe wählen"></div>
</div>
</div>
<div class="form-group">
<label data-i18n="settings_month_label_color">Monatskürzel</label>
<div class="ev-color-row">
<input type="text" id="cfg-month-label-hex" class="ev-color-hex" maxlength="7" spellcheck="false" />
<div class="ev-color-preview" id="cfg-month-label-preview" data-i18n-title="color_pick" title="Farbe wählen"></div>
</div>
</div>
<div class="form-group">
<label data-i18n="settings_text_color">Schriftfarbe</label>
<div class="ev-color-row">
<input type="text" id="cfg-text-color-hex" class="ev-color-hex" maxlength="7" spellcheck="false" placeholder="auto" />
<div class="ev-color-preview" id="cfg-text-color-preview" data-i18n-title="color_pick" title="Farbe wählen"></div>
<button type="button" class="btn btn-ghost btn-sm" id="cfg-text-color-reset" data-i18n="reset" title="Zurücksetzen">Reset</button>
</div>
</div>
<div class="form-group">
<label data-i18n="settings_line_color">Linienfarbe</label>
<div class="ev-color-row">
<input type="text" id="cfg-line-color-hex" class="ev-color-hex" maxlength="7" spellcheck="false" placeholder="auto" />
<div class="ev-color-preview" id="cfg-line-color-preview" data-i18n-title="color_pick" title="Farbe wählen"></div>
<button type="button" class="btn btn-ghost btn-sm" id="cfg-line-color-reset" data-i18n="reset" title="Zurücksetzen">Reset</button>
</div>
</div>
<div class="form-group">
<label data-i18n="settings_bg_color">Hintergrundfarbe</label>
<div class="ev-color-row">
<input type="text" id="cfg-bg-color-hex" class="ev-color-hex" maxlength="7" spellcheck="false" placeholder="auto" />
<div class="ev-color-preview" id="cfg-bg-color-preview" data-i18n-title="color_pick" title="Farbe wählen"></div>
<button type="button" class="btn btn-ghost btn-sm" id="cfg-bg-color-reset" data-i18n="reset" title="Zurücksetzen">Reset</button>
</div>
</div>
</div>
<!-- Kalender: einheitliche Tabelle aller Kalender aus allen Quellen -->
<div class="settings-panel" id="settings-panel-accounts">
<h4 class="panel-title" data-i18n="settings_nav_calendars">Kalender</h4>
<div class="accounts-add-row">
<button class="btn btn-secondary btn-sm" id="settings-btn-add-local">+ Lokal</button>
<button class="btn btn-secondary btn-sm" id="settings-btn-add-caldav">+ CalDAV</button>
<button class="btn btn-secondary btn-sm" id="settings-btn-add-ical">+ iCal</button>
<button class="btn btn-secondary btn-sm" id="settings-btn-add-ha">+ Home Assistant</button>
<button class="btn btn-secondary btn-sm" id="settings-btn-add-google">+ Google</button>
</div>
<div id="cal-settings-table" style="margin-top:16px;overflow-x:auto"></div>
</div>
<!-- Benutzerverwaltung -->
<div class="settings-panel" id="settings-panel-users">
<h4 class="panel-title"><span data-i18n="settings_nav_users">Benutzerverwaltung</span> <span class="badge-admin">Admin</span></h4>
<div id="users-list"></div>
<button class="btn btn-secondary" id="btn-add-user" style="margin-top:12px" data-i18n="users_add">Benutzer hinzufügen</button>
<div id="add-user-form" class="hidden" style="margin-top:12px">
<div class="form-group">
<label data-i18n="username">Benutzername</label>
<input type="text" id="new-username" />
</div>
<div class="form-group">
<label>Passwort</label>
<input type="password" id="new-password" />
</div>
<label class="toggle-label" style="margin-bottom:8px">
<input type="checkbox" id="new-is-admin" /> Administrator
</label>
<button class="btn btn-primary" id="new-user-save">Erstellen</button>
</div>
</div>
</div><!-- settings-panels -->
</div><!-- settings-page-body -->
</div><!-- settings-page-card -->
</div>
<!-- Profile Modal -->
<div id="modal-profile" class="modal-overlay hidden">
<div class="modal-card" style="max-width:540px">
<div class="modal-header">
<h3>Profil</h3>
<button class="icon-btn modal-close" data-modal="modal-profile">&times;</button>
</div>
<div class="modal-body">
<!-- Avatar Section -->
<div class="profile-avatar-section">
<div class="profile-avatar" id="profile-avatar">
<span id="profile-avatar-letter"></span>
<img id="profile-avatar-img" class="hidden" />
</div>
<div class="profile-avatar-actions">
<button class="btn btn-secondary btn-sm" id="profile-avatar-upload">Bild hochladen</button>
<button class="btn btn-ghost btn-sm hidden" id="profile-avatar-remove">Entfernen</button>
<input type="file" id="profile-avatar-input" accept="image/jpeg,image/png,image/webp" class="hidden" />
<div class="profile-username" id="profile-display-name"></div>
</div>
</div>
<!-- Account Info -->
<div class="settings-section">
<h4 data-i18n="profile_account">Konto</h4>
<div class="form-group">
<label data-i18n="profile_display_name">Anzeigename</label>
<input type="text" id="profile-display-name-input" data-i18n-placeholder="profile_display_name_ph" placeholder="Anzeigename" />
</div>
<div class="form-group">
<label data-i18n="profile_login_name">Login-Name</label>
<input type="text" id="profile-username" spellcheck="false" autocapitalize="none" />
<p class="panel-desc" data-i18n="profile_login_name_desc">Klein geschrieben, fürs Anmelden. Groß-/Kleinschreibung egal.</p>
</div>
<div class="form-group">
<label>E-Mail</label>
<input type="email" id="profile-email" placeholder="Keine E-Mail hinterlegt" />
</div>
<button class="btn btn-primary btn-sm" id="profile-save-info" data-i18n="save">Speichern</button>
</div>
<!-- Password -->
<div class="settings-section">
<h4>Passwort ändern</h4>
<div class="form-group">
<label>Aktuelles Passwort</label>
<input type="password" id="profile-pw-current" autocomplete="current-password" />
</div>
<div class="form-group">
<label>Neues Passwort</label>
<input type="password" id="profile-pw-new" autocomplete="new-password" />
</div>
<div class="form-group">
<label>Neues Passwort wiederholen</label>
<input type="password" id="profile-pw-confirm" autocomplete="new-password" />
</div>
<button class="btn btn-primary btn-sm" id="profile-pw-save">Passwort ändern</button>
</div>
<!-- 2FA -->
<div class="settings-section">
<h4>Zwei-Faktor-Authentifizierung</h4>
<div id="2fa-status">
<div id="2fa-disabled-section">
<p class="text-muted">2FA ist deaktiviert. Schütze dein Konto mit einem Authenticator.</p>
<button class="btn btn-primary btn-sm" id="2fa-setup-btn">2FA einrichten</button>
</div>
<div id="2fa-setup-section" class="hidden">
<p class="text-muted">Scanne den QR-Code mit deiner Authenticator-App (z.B. Bitwarden, Google Authenticator).</p>
<div class="totp-qr-wrapper">
<img id="2fa-qr-img" />
</div>
<div class="form-group">
<label>Oder gib diesen Schlüssel manuell ein</label>
<div class="totp-secret-row">
<code id="2fa-secret-code"></code>
<button class="btn btn-ghost btn-sm" id="2fa-copy-secret" title="Kopieren">
<svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16"><path d="M16 1H4c-1.1 0-2 .9-2 2v24h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v24c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v24z"/></svg>
</button>
</div>
</div>
<div class="form-group">
<label>Bestätigungscode eingeben</label>
<input type="text" id="2fa-verify-code" placeholder="6-stelliger Code" maxlength="6" inputmode="numeric" autocomplete="one-time-code" />
</div>
<button class="btn btn-primary btn-sm" id="2fa-enable-btn">Aktivieren</button>
<button class="btn btn-ghost btn-sm" id="2fa-cancel-btn">Abbrechen</button>
</div>
<div id="2fa-enabled-section" class="hidden">
<p class="text-success">2FA ist aktiviert.</p>
<div class="form-group">
<label>Passwort zum Deaktivieren</label>
<input type="password" id="2fa-disable-pw" autocomplete="current-password" />
</div>
<button class="btn btn-danger btn-sm" id="2fa-disable-btn">2FA deaktivieren</button>
</div>
</div>
</div>
<!-- Calendars -->
<div class="settings-section">
<h4>Meine Kalender</h4>
<div id="profile-calendars"></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" data-modal="modal-profile">Schließen</button>
</div>
</div>
</div>
<!-- Avatar Crop Modal -->
<div id="modal-crop" class="modal-overlay hidden" style="z-index:1000">
<div class="modal-card" style="max-width:480px">
<div class="modal-header">
<h3>Bildausschnitt wählen</h3>
<button class="icon-btn modal-close" data-modal="modal-crop">&times;</button>
</div>
<div class="modal-body" style="padding:0">
<div class="crop-container">
<img id="crop-image" />
</div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" data-modal="modal-crop">Abbrechen</button>
<button class="btn btn-primary" id="crop-save">Zuschneiden & Hochladen</button>
</div>
</div>
</div>
<!-- Toast -->
<!-- Floating action button (mobile only — create event) -->
<button id="btn-create-fab" class="create-fab" title="Termin erstellen" aria-label="Termin erstellen">
<svg viewBox="0 0 24 24" fill="currentColor" width="28" height="28"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
</button>
<div id="toast" class="toast hidden"></div>
<!-- Impressum Modal -->
<div id="modal-impressum" class="modal-overlay hidden" style="z-index:1100" onclick="if(event.target===this)closeImpressum()">
<div class="modal-card" style="max-width:460px">
<div class="modal-header">
<h3>Impressum</h3>
<button class="icon-btn" style="font-size:20px;line-height:1" onclick="closeImpressum()">&times;</button>
</div>
<div class="modal-body" style="line-height:1.7">
<p><strong>Scarriffleservices</strong><br>
Software &amp; Webentwicklung</p>
<p>Diese Software wurde von Scarriffleservices mit grösster Sorgfalt entwickelt und bereitgestellt. Alle Rechte vorbehalten &copy; 2026 Scarriffleservices.</p>
<p><strong>Datenspeicherung</strong><br>
Alle Anwendungsdaten werden auf dem Server gespeichert und verarbeitet, auf dem diese Calendarr-Instanz betrieben wird. Der Speicherort hängt damit vom Betreiber des jeweiligen Servers ab. Bei Nutzung der Google&nbsp;Kalender-Anbindung werden Daten über die Google&nbsp;API ausgetauscht; für diese Daten gelten die Datenschutzbestimmungen von Google. Bei Nutzung der Home&nbsp;Assistant-Anbindung werden Daten mit der jeweiligen Home&nbsp;Assistant-Instanz ausgetauscht. Home&nbsp;Assistant ist ein Projekt der Open&nbsp;Home&nbsp;Foundation.</p>
<p><strong>Haftungsausschluss</strong><br>
Trotz sorgfältiger Erstellung wird keine Haftung für die Richtigkeit, Vollständigkeit oder Aktualität der bereitgestellten Inhalte übernommen. Die Nutzung erfolgt auf eigene Verantwortung.</p>
<p><strong>Kontakt</strong><br>
<a href="mailto:scarriffleservices@gmail.com">scarriffleservices@gmail.com</a></p>
</div>
<div class="modal-footer" style="justify-content:space-between;align-items:center">
<span id="impressum-version" style="font-size:12px;color:var(--text-3)">Calendarr</span>
<button class="btn btn-ghost" onclick="closeImpressum()">Schliessen</button>
</div>
</div>
</div>
<script>
function openImpressum() {
document.getElementById('modal-impressum').classList.remove('hidden');
}
function closeImpressum() {
document.getElementById('modal-impressum').classList.add('hidden');
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.6.2/cropper.min.js"></script>
<script type="module" src="/static/js/app.js"></script>
</body>
</html>