Commit Graph

226 Commits

Author SHA1 Message Date
Scarriffle
6365f99ac0 feat: persist active settings tab in URL hash (v55)
URL gains &stab=<panel> when settings are open (e.g. #...&settings=1&stab=accounts).
Tab switches update the URL; reload reopens settings on the same tab.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 20:52:14 +02:00
Scarriffle
d04e2952cb fix: replace reminders checkbox with bell icon in calendar table (v54)
Bell-on = Benachrichtigungen aktiv, Bell-off (durchgestrichen) = stumm.
Gleiche Logik wie Auge-Icon für Sichtbarkeit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 20:48:12 +02:00
Scarriffle
c5fd5b4e55 fix: calendar table visibility column uses eye icon instead of checkbox (v53)
Replace misleading "Ausgeblendet" checkbox with eye-open/eye-off icon button.
Sichtbar column: eye-open = shown, eye-off = hidden (dimmed). Clicking toggles.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 20:45:33 +02:00
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
Scarriffle
2c59d873f3 fix: UTF-8 encoding for iCal subscriptions + default_event_duration_minutes setting
Force resp.encoding='utf-8' in _fetch_ics so umlauts (ö/ä/ü) from sources
like Ferienwiki.de are decoded correctly instead of showing as ö/ä/ü.

Add default_event_duration_minutes to UserSettings (nullable int, same pattern
as default_reminder_minutes) with DB migration, GET/PUT in settings_router.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 19:34:43 +02:00
Scarriffle
c515e9d7e1 feat: safe HTML descriptions, custom reminder picker, synced default event duration
- Render event descriptions as sanitized HTML (links/line breaks) instead of
  raw escaped text; no script execution
- Reminder picker: presets + custom number+unit (minutes/hours/days/weeks)
- Grey out + hint the reminder editor when a calendar's notifications are off
  (reminders are kept, just not fired)
- New synced setting default_event_duration_minutes (default 60) for new events

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 10:00:52 +02:00
Scarriffle
e6bc7eab9d Web: replace chevron chars with clip-path pointed bar ends in overflow popup
All-day continuation bars now use CSS clip-path polygon for the tapered
arrow shape; bars stay inset within the popup (no edge bleed). Version v51.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 20:32:29 +02:00
Scarriffle
70aaec3401 Web: enhance overflow popup with styled all-day bars and continuation arrows
All-day events in the "+N weitere" popup now render as colored bars matching
the month-grid style: continues-left/right arrows when the event spans beyond
the selected day. Timed events keep dot+time+title format. Version bump v50.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 20:02:04 +02:00
Scarriffle
900abcdb7a Web: remove version from tab title, fix month event packing, add day overflow popup
- Tab title shows only "Calendarr" (version stays in sidebar/impressum)
- Fix lane assignment in month view: use 2D per-column occupancy grid instead of
  global colEnd tracking; eliminates empty rows caused by non-overlapping events
  being pushed to lower lanes
- "+N weitere" now opens an inline popup listing all events for that day
  (all-day first, then by time); clicking an event opens its detail popup
- Double-click on day cell navigates to day view (was already implemented)
- Remove hardcoded "v18" from login screen impressum button
- Bump version to v49

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 18:06:54 +02:00
Scarriffle
0c8fbb86e8 Web: date picker commits on leave, close day context menu on event click
- Date picker: clicking a day only selects it now; the choice is committed
  when you leave the picker (click outside) or press Save — for both date and
  datetime modes (previously datetime discarded on click-away, and date
  committed instantly on click, neither of which was wanted).
- The day right-click context menu ("Neuen Termin erstellen") now closes when
  an event popup opens (the event row stops propagation, so its own
  outside-click closer never fired).
- version v47 -> v48.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 21:32:51 +02:00
Scarriffle
367087450e Web: custom calendar dropdown in the event editor (shows group icon)
A native <select> can't render the group icon SVG, so the calendar picker
is replaced with a styled dropdown: colour dot + group icon + name, grouped
by account/source with a "Groups" section. The native <select> is kept
hidden as the value holder + change-event source, so all existing save and
private/reminder-row logic is unchanged. Click-outside / Escape close it.

version v46 -> v47.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 20:38:47 +02:00
Scarriffle
c684a424eb Web: caret/selection fix, reminder options & labels, group mute, rounded modal
- Stop the blinking text caret / selection on non-editable UI chrome
  (headings, buttons, icons, dropdowns): body is user-select:none, with text
  selection opted back in for inputs/textareas. Felt like an editable field.
- Reminder options trimmed to 5/15/30 min, 1 h, 1 day, 1 week (dropped 10 min,
  2 h, 2 days; added 1 week). Labels now read "5 Minuten vorher", "1 Tag
  vorher", "1 Woche vorher" instead of "vor 5 Min." / "vor 1 Tag(en)".
- Group calendars can now be muted (reminder bell) in the sidebar when owned.
- Event modal corners rounded (20px) to match the pill buttons.
- version v45 -> v46.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 20:32:01 +02:00
Scarriffle
db43bad432 Web: reminders UI, per-calendar reminder toggle, popup/grid polish
- Event popup: new "Reminders" section for local events — show/add/remove
  multiple reminders, prefilled with the global default on new events; sent
  in the local create/update body and synced like any other event field.
- Sidebar calendar list: per-calendar reminder bell toggle (PUTs the new
  reminders_enabled flag); disabled state shown dimmed.
- Date picker: a day click now commits immediately in date-only mode instead
  of requiring an extra "Save" click.
- Start/End: moving the end before the start now shifts the start back
  (mirroring the start handler) instead of showing an error toast.
- Calendar dropdown: group calendars moved under a "Groups" optgroup; dropped
  the 👥 emoji prefix (a native <select> can't render the icon SVG).
- Month grid: selectedDate defaults to today so the highlight no longer
  follows the cells while navigating before any click.
- Today cell tint now derives from --today-color instead of hardcoded blue.
- version v44 -> v45.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 19:33:40 +02:00
Scarriffle
14dea01053 Add per-calendar reminders_enabled flag (server)
New boolean column on every calendar type (CalDAV, local, Google, Home
Assistant, iCal subscription), default ON so existing data is unchanged.
Lets a calendar be shown without generating reminders/notifications.

- models.py: reminders_enabled on the five calendar models
- main.py _migrate(): ALTER TABLE ADD COLUMN for each table
- caldav/google/homeassistant/local/ical routers: expose the flag in the
  calendar serialization and accept it in the calendar/subscription update
  endpoints

Clients map event -> (source, calendar_id) -> reminders_enabled to skip
scheduling notifications for disabled calendars.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:16:45 +02:00
Scarriffle
bff9a244e7 feat: per-event reminders + default reminder setting (server)
local_events gains a `reminders` TEXT column (comma-separated minutes-before-
start, like exdate); EventCreate/EventUpdate accept a `reminders: [int]` list
and build_local_event_dict emits it back as a list. user_settings gains
`default_reminder_minutes` (nullable int, null = off), exposed/updatable via
/api/settings (explicit null persists as off). Migrations added in _migrate().
Clients (iOS/Android) schedule the OS notifications locally from these.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 16:07:19 +02:00
Scarriffle
fc00bf9114 feat(web): group members in the sidebar + per-user member colours
Moved the group member filter from a top bar into the left sidebar (a
"Mitglieder" section that replaces the personal calendar list while a group is
active). Each member row has a checkbox (show/hide their events) and a colour
dot that opens the colour picker to recolour that member just for this viewer —
stored per-device in localStorage and applied over the server colour. Bumped v44.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 20:32:45 +02:00
Scarriffle
817ce075d4 feat(web): non-emoji group icons (inline SVG) for consistent cross-platform look
Group icons are semantic keys rendered as inline SVG (mirroring iOS SF Symbols /
Android Material) in the picker, group list and sidebar flags — instead of OS
emoji that vary per platform. Legacy emoji values still render as a fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 20:25:40 +02:00
Scarriffle
4b7e5799bf refactor: group icons are semantic keys, not emoji (display_title drops glyph)
Group icons move from OS-emoji (which render differently per platform) to
semantic keys rendered natively per client. The combined view's display_title
therefore no longer embeds an icon glyph — group-calendar events are
distinguished by their colour; only the owner/creator first-name is prefixed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 19:20:31 +02:00
Scarriffle
12c14e3c02 feat(web): hide individual member calendars in the group view
In the group overlay a per-member filter bar appears under the banner: tap a
member (or the group calendar) to hide/show their events, Outlook-style.
Filtering is client-side by event owner; members + colours load from the group
detail. Bumped version.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 18:16:25 +02:00
Scarriffle
447c3ddab1 feat(web): render server display_title in the group combined view
Use the server-provided display_title (group icon + owner prefix) instead of
the client-side prefix, so web/iOS/Android show group events identically.
Falls back to the local prefix for older servers. Bumped to v41.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 17:54:22 +02:00
Scarriffle
6869a15bb8 fix(security): stop private-event leak in merge read + harden busy masking, uploads, profile
Findings from the security review:
- HIGH: private local events leaked in full (title/location/description) to
  anyone who could READ a shared or group calendar via GET /api/caldav/events —
  the private_event_visibility rule was only enforced in /groups/{id}/combined.
  Now enforced in the merge read too, via a shared helper (apply_event_privacy)
  so the two paths can't drift.
- HIGH: 'busy' masking was a blacklist that still leaked creator identity,
  source-calendar name, recurrence rule and per-event colour. Replaced with a
  whitelist (mask_busy_event): only timing/identity/render fields survive.
- MEDIUM: .ics import had no size limit (raw = await file.read()) → memory DoS.
  Now capped at 5 MB (413), read before creating any calendar.
- LOW/INFO: profile email now checked for uniqueness + basic format; display
  name / username / email length-capped and control-chars stripped.

Deferred (tracked): RRULE expansion cap at the trust boundary, SQLite
PRAGMA foreign_keys + ON DELETE cascade, and JWT-by-user-id + token version.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 17:49:56 +02:00
Scarriffle
0d15af736d feat: server-side display_title for the group combined view
The group-event icon + owner-name prefix was being done per-client (iOS only),
so web/Android were inconsistent. The /groups/{id}/combined endpoint now emits
a decorated `display_title` per event (group's own icon for group-calendar
events, owner first-name for other members' events) while keeping the raw
`title` for editing. All clients can render this identically. 18 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 17:30:38 +02:00
Scarriffle
f834ae5773 feat(web): modernize event popup (glass, colour accent, icon rows, animation)
The event detail popup looked plainly "HTML". Redesigned it: translucent
glass surface (backdrop-blur), the event's colour as an accent strip + tinted
header + glowing dot, body rows with subtle leading icons (time/location/notes/
calendar/creator), rounded 16px corners, layered shadow, and a soft scale+fade
entrance (respecting prefers-reduced-motion). Body rows restructured to
icon+text; JS now drives row visibility and sets --ev-color. Bumped to v40.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 09:06:09 +02:00
Scarriffle
7be77da59f feat: Einstellungen in Kapitel (Profil/Darstellung/Ansicht/Kalender)
- Settings-Sidebar mit Kapiteln: Profil, Darstellung, Ansicht, Kalender,
  Benutzerverwaltung (statt eines langen "Darstellung"-Panels).
- Neues "Profil"-Kapitel: Anzeigename + Login-Name ändern, E-Mail, plus
  Privatsphäre (private Sichtbarkeit) und "Für Gruppen sichtbarer Kalender".
- "Konten" → "Kalender" umbenannt. Version v39.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 19:05:39 +02:00
Scarriffle
8d605ab2cd fix: Monatszelle am Monatswechsel nicht mehr vertikal zentriert
Mein voriges flex/align-center hat "1 JUN" in die Mitte der ganzen Zelle
geschoben. Jetzt: Tageszahl bleibt oben links (wie alle Tage), Monatskürzel
sitzt klein/dezent inline daneben (cell-day inline-flex + kleiner Marker).
Version v38.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 19:00:53 +02:00
Scarriffle
a992d97796 feat: server-definierte Gruppenfarben (per API) + Gruppentermine überall erstellen
- Pro Mitglied eine Farbe (group_members.color, auto aus Palette, vom Owner
  oder Mitglied selbst änderbar via PUT /groups/{id}/members/{uid}/color).
- Gruppentermin-Farbe = Farbe des Gruppenkalenders.
- API liefert Farben aus: GET /groups & /groups/{id} (member.color,
  group_calendar_color), GET /groups/{id}/combined (display_color pro Event)
  -> Apps können dieselben Farben anzeigen. Test ergänzt (18 grün).
- Web nutzt display_color; Gruppenkalender im Termin-Editor mit 👥 markiert
  (Gruppentermine ohne Gruppenansicht erstellbar); Mitglieder-Farben im
  Verwalten-Dialog editierbar. Version v37.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:52:40 +02:00
Scarriffle
b0f1497bc8 fix: Monatsansicht-Layout bei Monatswechsel + Gruppenkalender in Sidebar
- Monatsmarker ("JUN") sitzt jetzt inline neben der Tageszahl ("1 JUN") statt
  darüber -> einheitliche Zeilenhöhe; Termine der Woche rutschen nicht mehr
  nach unten und überlappen nicht mehr mit "+X weitere".
- Gruppenkalender erscheint in "Meine Kalender" (mit 👥-Markierung) und kann
  aus-/eingeblendet werden; Besitzer kann ihn umfärben. Recolor fremder
  Kalender abgefangen (nur Besitzer). Version v36.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:45:49 +02:00
Scarriffle
fd7f7ddfe0 feat: Gruppentermin-Button in der Gruppenansicht + Banner in Akzentfarbe
- "+ Gruppentermin"-Button im Gruppenansicht-Banner: oeffnet den Editor mit
  dem Gruppenkalender vorausgewaehlt -> jeder kann direkt eintragen.
- Banner + aktive Gruppe nutzen jetzt die Akzentfarbe (color-mix, Fallback)
  statt Blau. Version v35.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:38:35 +02:00
Scarriffle
7429a309c3 feat: wählbares Gruppen-Icon, geteilter Kalender markiert, Ersteller bei Gruppen-Terminen
- Gruppe: wählbares Emoji-Icon (groups.icon-Spalte + PUT /api/groups/{id});
  wird in der Sidebar statt des Zahnrads angezeigt; Verwalten jetzt klares "⋯".
  Gruppe umbenennen möglich (war vorher gesperrt).
- "Meine Kalender": der aktuell für Gruppen sichtbare Kalender wird mit 👥
  gekennzeichnet.
- Gruppenansicht: Gruppenkalender-Termine zeigen, wer sie hinzugefügt hat
  (👥 Vorname: Titel) und sind nach Ersteller eingefärbt; jeder kann weiterhin
  Termine im Gruppenkalender anlegen. Version v34.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:34:59 +02:00
Scarriffle
682f9613ec feat: schönere Gruppenansicht – Vorname statt Initialen + Farbe pro Person
Kombinierte Ansicht: kryptisches "[SC]"-Initialen-Präfix ersetzt durch den
Vornamen ("Guido: Titel") für fremde Termine; eigene Termine ohne Präfix;
Gruppen-Termine mit 👥. Zusätzlich feste Farbkodierung pro Besitzer, damit
jedes Mitglied als Gruppe lesbar ist. Version v33.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:01:55 +02:00
Scarriffle
2033cf99d4 feat: Anzeigename im Web (Profil bearbeiten + Anzeige)
- Profil: Anzeigename + Login-Name editierbar (vorher Benutzername read-only).
  Login-Namenwechsel speichert den frisch zurueckgegebenen Token.
- Menue/Dropdown und "Erstellt von"/Picker zeigen den Anzeigenamen.
- localStorage-User um display_name ergaenzt. Version v32.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 17:49:19 +02:00
Scarriffle
f9923b022e feat: Login-Name vs. Anzeigename (Server)
- Neue Spalte users.display_name (Original-Schreibweise); username bleibt der
  lowercase Login-Name. Setup/Create setzen display_name aus der Eingabe.
- Login bleibt case-insensitive (Anzeigename eingeben funktioniert -> wird
  lowercased -> trifft den Login-Namen).
- Profil: PUT /api/profile/ kann display_name UND username (Login-Name) aendern;
  bei Login-Namen-Wechsel kommt ein frischer Token zurueck (JWT sub haengt am
  Namen). Stabile interne ID (Integer-PK) traegt alle Verweise -> Umbenennen
  bricht Shares/Gruppen/creator_id nicht.
- display_name ueberall ausgeliefert/genutzt (me, profile, users, directory,
  shares, Gruppen-Mitglieder, creator/owner, ORGANIZER-Export).
- Migration + Backfill (display_name = username). Tests ergaenzt (17 gruen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 17:40:38 +02:00
Scarriffle
28a7cbe94e fix: kaputtes Plus-Icon + Kalendernamen nicht vorzeitig abschneiden
- Plus-Icon (Kalender/Gruppen hinzufuegen): fehlerhafter SVG-Pfad (v11 statt
  v6) -> korrekter, symmetrischer Plus-Pfad.
- Entfernen/Auge-Button per display:none statt opacity:0 -> reserviert keinen
  Platz mehr; Kalendername nutzt volle Breite und kuerzt erst beim Hover
  (wenn das Auge erscheint). Version v31.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 17:31:39 +02:00
Scarriffle
cc4ccc7d81 feat: Live-Vorschau beim Kalender-Sortieren
Beim Ziehen wandert die Zeile jetzt live zwischen die anderen, die Liste
macht sichtbar Platz an der Zielposition. Container-dragover wird nur einmal
gebunden (kein Listener-Stacking pro Render). Version v30.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 17:29:41 +02:00
Scarriffle
c62b3df33a fix: Kalenderquelle als Tooltip statt inline (Namen nicht mehr abgeschnitten)
Die Quelle/Konto stand inline rechts und hat die Kalendernamen abgeschnitten.
Jetzt im title-Tooltip des Eintrags ("Name · Quelle"); der Name nutzt die
volle Breite. Version v29.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 17:25:47 +02:00
Scarriffle
8d2f487607 feat: flache sortierbare Kalenderliste (Drag&Drop) + Fixes
- Sidebar: eine flache Kalenderliste statt Quellen-Gruppen; Quelle/Konto
  klein-grau inline rechts neben dem Namen; per Drag&Drop sortierbar
  (Reihenfolge pro Geraet in localStorage).
- Gruppenkalender serverseitig auch beim Besitzer als group:true markiert
  -> erscheint nicht mehr in der "Fuer Gruppen sichtbar"-Auswahl und nicht
  in der normalen Kalenderliste (nur unter Gruppen).
- Settings-URL-State: uiSettingsOpen wird beim Init aus der URL gesetzt,
  bevor das erste writeUrlState() es ueberschreibt -> Reload bleibt jetzt
  wirklich in den Einstellungen.
- Auswahl-Markierungen (Mitglieder/Gruppen-Sichtbar) in Akzentfarbe,
  CSS-gezeichnet statt blauer Emoji. Version v28.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 17:23:28 +02:00
Scarriffle
c7185a128e fix: Import-500 bei doppelten UIDs, Picker-UI & Settings-URL-State
- Import: Dedupe doppelter UIDs innerhalb der Datei (Nextcloud exportiert
  wiederkehrende Termine als mehrere VEVENTs gleicher UID) -> kein
  UNIQUE-constraint-500 mehr; Commit abgesichert. Test ergaenzt (15 gruen).
- Picker (Gruppen-Sichtbarkeit + Mitglieder): als <div>-Zeilen statt <label>,
  damit die globale ".form-group label"-Uppercase/Grau-Regel das Layout nicht
  mehr zerschiesst. Saubere .pick-row-Optik (Checkbox/Radio links, Name links).
- Einstellungen haben jetzt eigenen URL-State (#...&settings=1): Reload/Cache-
  leeren bleibt in den Einstellungen statt zur Kalenderansicht zu springen.
- Version v27.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 17:15:17 +02:00
Scarriffle
8abeefcb5a feat: Gruppen-Sichtbarkeit in Einstellungen + "Mit dir geteilt"-Sektion + Import-Fehler
- Einstellungen: neuer "Kalender"-Abschnitt – Radio-Auswahl, welcher eigene
  Kalender fuer Gruppenmitglieder sichtbar ist (group_visible_calendar_id).
- Sidebar: geteilte Kalender in eigener Sektion "Mit dir geteilt" (mit
  Besitzername) statt inline bei "Meine Kalender"; Gruppenkalender dort
  ausgeblendet (erscheinen unter Gruppen).
- Lokale Checkbox tolerant: geteilte/Gruppen-Kalender werden client-seitig
  ein-/ausgeblendet (kein 404-PUT als Nicht-Besitzer).
- Import-Fehler: zeigt HTTP-Status / "Datei zu gross" statt "unbekannter
  Fehler" (z.B. nginx 413). Version v26.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 17:02:03 +02:00
Scarriffle
06ba9c2bb1 feat: Gruppen-Sichtbarkeit – genau ein designierter Kalender pro Person
Neues user_settings.group_visible_calendar_id: jedes Mitglied waehlt EINEN
lokalen Kalender, der in seinen Gruppen sichtbar ist. Die kombinierte
Ansicht ueberlagert nur diesen (statt aller) Kalender je Mitglied + den
Gruppenkalender; private Termine weiter gefiltert. Settings GET/PUT erweitert
(nullbar). Tests angepasst + ergaenzt (14 gruen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 16:57:42 +02:00
Scarriffle
479da29bc4 fix: Gruppen-Mitgliederliste sauber ausrichten (Checkbox links, Name links)
Eigene .group-member-item-Klasse statt der generischen Picker-Klasse —
behebt versetzte Checkboxen / rechtsbuendige Namen. Version v25.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 16:47:58 +02:00
Scarriffle
f018f33f69 fix: JS/CSS immer revalidieren (no-cache) + Version v24
Bisher bekamen /static/js und /static/css max-age=7200. Da index.html
no-cache ist, konnte eine frische HTML mit 2h-altem, gecachtem JS/CSS
gepaart werden — neue Features (z.B. Gruppen-Button) ohne passenden
Handler. JS/CSS revalidieren jetzt bei jedem Load (304 wenn unveraendert);
Icons & uebrige Assets behalten 2h. Deploys greifen so sofort beim Reload.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 16:42:21 +02:00
Scarriffle
e8a13ba33c feat: Gruppen im Web-Frontend + Gruppenkalender in /local/calendars
- Sidebar-Sektion "Gruppen": Liste, Erstellen (Name + Mitglieder-Picker),
  Verwalten (Mitglieder hinzufuegen/entfernen), Loeschen.
- Gruppenansicht: laedt /api/groups/{id}/combined fuer den sichtbaren
  Bereich; Event-Titel werden mit Besitzer-Initialen bzw. Gruppen-Icon
  praefixt; Banner mit "Gruppenansicht verlassen".
- Server: GET /api/local/calendars liefert nun auch Gruppenkalender
  (group:true, read_write) fuer Mitglieder, damit sie im Editor waehlbar
  sind. Test ergaenzt (13 gruen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 16:37:08 +02:00
Scarriffle
8d2a697f8b feat: Web-Frontend – Sharing, iCal Import/Export, Ersteller & Privat-Flag
- Ersteller-Zeile im Event-Popup (nur wenn Ersteller != aktueller User).
- Privat-Toggle im Event-Editor (nur lokale Kalender) + Sichtbarkeits-
  Auswahl (hidden|busy) in den Einstellungen.
- Lokale Kalender in Settings & Sidebar: Teilen/Importieren/Exportieren-
  Aktionen (nur eigene; geteilte mit "geteilt von"-Badge, kein Loeschen).
- Share-Modal: Benutzerverzeichnis mit Suche, read/read_write, Freigaben
  entfernen.
- api.js: download()-Helper fuer iCal-Export (Blob).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 16:30:47 +02:00
Scarriffle
32268a18b2 feat: Kalender-Sharing, Gruppen, iCal Import/Export & Ersteller (Server)
Kollaborations-Features ausschliesslich fuer lokale Kalender:

- Sharing: calendar_shares-Tabelle, GET/POST/DELETE /api/local/calendars/{id}/shares
  (nur Besitzer), GET /api/users/directory, geteilte Kalender in
  GET /api/local/calendars (shared_by/permission/owned) und im Merge-Read.
- Gruppen: groups/group_members/group_calendars + /api/groups-Router inkl.
  kombinierter Ansicht /api/groups/{id}/combined (owner + is_group_event).
- Ersteller: local_events.creator_id (serverseitig gesetzt) + creator_name_external
  aus ORGANIZER; creator-Feld in allen lokalen Event-Responses.
- Private-Flag: local_events.is_private + user_settings.private_event_visibility
  (hidden|busy), Filterung in der Gruppenansicht.
- iCal Import/Export: ical_io.py, POST /api/local/calendars/{id}/import,
  POST /api/local/import, GET /api/local/calendars/{id}/export.
- Zentraler Berechtigungs-Helper (permissions.py) und gemeinsamer Event-Dict-
  Builder (local_events_util.py) ersetzen die Nur-Besitzer-Filter.
- pytest-Suite (12 Tests) fuer Sharing, Gruppen, Parser, Private-Filterung.

Additiv & rueckwaertskompatibel; Migrationen in main.py._migrate().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 16:05:18 +02:00
Scarriffle
362cc7212c fix(version): Sidebar-Copyright wird jetzt auch aus version.js befuellt 2026-05-19 10:22:13 +02:00
Scarriffle
275e5a2ae0 fix: unaufgeloeste Merge-Konflikt-Marker aus i18n/calendar/week/css entfernt
Beim letzten Beta->Master-Merge sind die <<<<<<< / ======= / >>>>>>>
Marker mit committet worden. Das hat i18n.js mit einem SyntaxError beim
Parsen abgebrochen und damit den gesamten Frontend-Start kaputt gemacht
(=> komplett schwarze Seite, weil applyTheme nie lief).

Acht Bloecke aufgeloest, in allen Faellen die HEAD-Seite behalten
(neue Features: copy-Key, URL-State, all-day-continues-Logik, Event-
Popup-Header). v22 / sw cache v22.
2026-05-19 10:18:49 +02:00
Scarriffle
f102f02cb9 fix(version): Tab-Titel + Impressum dynamisch aus version.js
Vorher waren "Calendarr v18" in index.html hardcoded und wurden bei
Releases nie mit gebumpt — v19/v20 wurden zwar in version.js gepflegt,
landeten aber nie im Tab-Titel. Jetzt liest calendar.js APP_VERSION
direkt aus version.js und setzt sowohl document.title als auch das
Impressum-Footer-Label, damit das nicht mehr auseinanderlaufen kann.

v21 / sw cache v21
2026-05-19 10:12:32 +02:00
Scarriffle
43575f9042 fix(theme): Defaults weiss-auf-schwarz + Kontrast-Sicherheitsbremse
- Default-Schriftfarbe = #FFFFFF, Default-Hintergrund = #000000
- Wenn Schrift- und Hintergrundfarbe zu wenig Kontrast haben (< 2.5:1),
  wird automatisch auf weiss-auf-schwarz zurueckgefallen. So kann
  man sich nicht mehr in eine unsichtbare Seite manoevrieren.
- Color-Picker zeigt jetzt die wirksame Default-Farbe in der Vorschau
  (statt leer/transparent), auch wenn keine Override gesetzt ist.
2026-05-19 10:06:12 +02:00
Scarriffle
fd7562966a fix(settings): Schrift-/Linien-/Hintergrundfarbe — Live-Vorschau + Hex ohne '#'
- Live-Vorschau beim Tippen statt erst bei Blur (input-Event)
- Hex-Werte werden auch ohne fuehrendes '#' akzeptiert ("ff0000" -> "#FF0000")
- Reset-Button wendet Standardwerte sofort an
- v19 / sw cache v19
2026-05-19 09:57:40 +02:00
Scarriffle
8f9eafe561 feat(settings): Schriftfarbe, Linienfarbe und Hintergrundfarbe per Color-Picker
Die bisherigen Stufen-Wähler ("Dunkel/Mittel/Hell/Maximum" und
"Kaum/Subtil/Normal/Stark") für Schrift- bzw. Linienkontrast sind durch
echte Hex-Color-Picker ersetzt. Zusätzlich kann jetzt auch die
Hintergrundfarbe der Seite frei gewählt werden.

Wenn ein Override gesetzt ist:
- text_color → setzt --text-1 direkt, --text-2/--text-3 werden
  daraus per shadeHex(-0.25 / -0.55) abgeleitet, damit der Hue passt
- line_color → setzt --border, --border-light wird leicht abgedunkelt
- bg_color → setzt --bg-app, daraus werden Topbar/Sidebar/Surface/
  Hover/Active per shadeHex(+0.10…+0.40) konsistent hochskaliert

Per "Reset"-Knopf wird der Override geleert und die alte Stufen-Logik
(falls noch vorhanden) bzw. der Default-Theme greift wieder.

Backend:
- 3 neue nullable VARCHAR(7)-Spalten in user_settings (text_color,
  line_color, bg_color) inkl. Migrationen in main.py
- settings_router nutzt model_dump(exclude_unset=True) und respektiert
  explizite null-Werte nur für diese 3 Override-Felder, damit Reset
  funktioniert

Auch enthalten: Auflösen der Merge-Konflikte in sw.js, index.html,
version.js (HEAD-Stand v17 behalten) und Bump auf v18.
2026-05-19 09:49:45 +02:00