Commit Graph

243 Commits

Author SHA1 Message Date
Scarriffle
995d9bb5b4 feat(web): every sidebar calendar can be hidden (shared, birthday, ical too)
Equal rights for all calendar types: the sidebar remove button is now a uniform
"hide" (eye) for every calendar instead of delete-for-some / nothing-for-shared.

- Owned local (incl. birthday) and iCal now hide via the server sidebar_hidden
  flag (delete stays available in Settings' calendar table).
- Calendars shared with me get a per-device sidebar hide (they can't carry a
  server flag); their events are filtered out while hidden, and the Settings
  calendar table's "shared with me" rows gain an un-hide eye toggle.
- External caldav/google/ha unchanged.

Group calendars intentionally left as-is for now.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 12:46:53 +02:00
Scarriffle
4c7cdc362a feat(web): link Impressum version to Gitea source repo
The version line in the Impressum footer ("Calendarr vNN") is now a
subtle link to the Calendarr Gitea repo (git.scarriffle.com), opening
in a new tab. Styled to stay muted at rest and reveal as a link on
hover. Bump APP_VERSION v87 -> v88.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 17:01:20 +02:00
Scarriffle
37e5507261 feat(web): admin theme import + branding dimension hints
- Admin default-theme editor: "Theme importieren" button loads a .theme.json
  into the editor (colours only, live preview) so an imported theme can be set
  as the instance default (still confirmed via "Standard speichern").
- Branding: drop the "Standard" placeholder; show pixel-dimension hints instead
  (logo shown at max 150×40, favicon 128×128). Logo preview box now mirrors its
  real topbar footprint.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 14:33:59 +02:00
Scarriffle
22a58e0d9f feat(web): set built-in DEFAULT_COLORS to the green brand palette
Replaces the blue defaults with the provided green theme (primary #58B900,
accent #45A148, today #6FB669, greens for month/selected/today-bg, etc.). These
apply when no admin instance theme is set. THEME.md defaults table updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 14:21:03 +02:00
Scarriffle
cea96660d9 feat(web): admin area with instance default theme, custom logo/favicon; .theme.json export
- Admin settings tab (admin-only) now holds user management plus a server-wide
  default theme editor (live preview + discard) and logo/favicon branding.
- New singleton InstanceSettings model + /api/instance router (public GET for
  the login screen; admin-gated theme PUT and logo/favicon upload/delete,
  reusing the avatar PIL/validation pattern).
- Instance default theme is the base users inherit and the target a per-colour
  "Reset" returns to (baseColor: instance default -> built-in).
- Custom favicon overrides the primary-colour tinting; custom logo replaces the
  top-left glyph+text, hard-capped so it only scales down and never breaks layout.
  Branding + defaults load before login (public endpoint).
- Theme export now uses the recognised .theme.json extension (old .theme still
  imports); import stays partial/unknown-key aware.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 14:19:15 +02:00
Scarriffle
6316ed3a6b feat(web): theme import/export, more themable colors, hideable local/ical calendars
Theme:
- Export/import themes via UI as <date>_<time>.theme (JSON, readable keys,
  link to THEME.md). Import is partial-aware: only present params are written
  (server accepts partial); prompts before importing files with unknown params.
- Dynamic favicon + theme-color tinted to the primary colour on load/save.
- New themable colours: general hover-highlight, day hover/selected/bg,
  today background, plus two unified sidebar action-icon colours
  (inactive/active) covering bell, hide, delete and read-only icons.
- All new colours are per-setting syncable; documented in THEME.md.

UX:
- Styled confirm dialog (#modal-confirm) replaces window.confirm() for
  calendar delete and account disconnect.
- Birthday/local calendars and iCal subscriptions can now be hidden from the
  sidebar via Settings (new sidebar_hidden column + hide toggle).

Backend: additive nullable columns + idempotent migrations for user_settings
colours and local_calendars/ical_subscriptions.sidebar_hidden.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 13:20:30 +02:00
Scarriffle
a7802778b6 Web: expose month-navigation mode as a named dropdown
New 'Monatswechsel' setting (synced flag already existed as month_view_paged):
- Continuous scroll (week): current behaviour — wheel scrolls by a week,
  buttons/swipe jump 4 weeks.
- Page by page (month): wheel navigation is disabled; buttons and horizontal
  swipe jump a whole calendar month.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 06:26:02 +02:00
Scarriffle
7a89cc44f8 Web: settings page nav/header follow the surface colour too
The settings modal's own left nav and header were on --bg-app; point them at
--bg-sidebar / --bg-topbar so they track surface_color like the main sidebar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 22:08:22 +02:00
Scarriffle
131f6b496d Add configurable surface/sidebar colour + clearer sync-icon state
- new user_settings.surface_color (nullable, device-local default, not synced):
  drives the web sidebar / top bar / surfaces; NULL derives from bg_color as
  before. Added to schema, migration, GET/PUT, NULLABLE_OVERRIDES, DEFAULT_SYNC.
- web: surface colour row in the settings table; applyTheme derives the whole
  surface family from it
- web: per-row sync icon now has real styling — ON shows the primary-tinted
  glyph on a pill, OFF shows a slashed, muted glyph (was previously unstyled,
  so synced/not-synced looked identical)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 22:01:16 +02:00
Scarriffle
4ab07ddcc3 Web polish from testing feedback + admin role toggle
- style the settings-table dropdowns for the dark theme (were white)
- share-icon picker on one even row (no lopsided wrap)
- more breathing room between colour hex and swatch
- user management: promote/demote admin (new PUT /users/{id}/admin,
  guarded against self-change and removing the last admin)
- calendar management table: clip/ellipsis cells so narrow columns no
  longer overlap (full-width detail rows still wrap)
- centralise default colours: utils.applyTheme now derives every fallback
  from settings-sync.DEFAULT_COLORS (single place for coders to edit)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 21:25:01 +02:00
Scarriffle
137694ed98 Web: unified settings sync table with per-setting sync toggles
Replace the ad-hoc appearance panel with a uniform table (sync icon | name |
value): dropdowns instead of button groups, every colour with a reset to a
canonical default, a per-row sync toggle, and a global "sync all" master
switch.

- new settings-sync.js: canonical default colours, declarative table
  definition, browser-local value copy, effective-value resolution
- calendar.js: generalised sync engine (pull applies only synced keys from the
  server, save pushes only synced keys + the flag map), unified the two save
  buttons into one, dropped the dead text/line-contrast code, moved default
  duration into the appearance table, effective UI language on load
- account settings (private visibility, group calendar, hide profile) stay in a
  dedicated profile block, not the sync table
- app.css: settings table / sync toggle / sync icon styles
- i18n: sync-all / sync-this / share-icon strings; sw cache bump

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 21:07:26 +02:00
Scarriffle
1f1eb582ed Birthdays: explicit "Birthday calendar" add type + tidier table defaults (web)
- add "Geburtstagskalender" to the sidebar +calendar dropdown and a "+ Geburtstage"
  button to Settings > Calendars; both call ensureBirthdayCalendar (server enforces
  one per account) and toast "already exists" if present
- Settings birthday section: when none exists, just a hint pointing to "+ Geburtstage"
  (creation lives in the add area now, not a separate activate button)
- resizable calendar table: sensible default column widths instead of raw measured
- i18n de/en

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 21:34:38 +02:00
Scarriffle
0ce77ccdf8 Add drag-resizable columns to the calendar settings table
Column widths are draggable via a handle on each header's right edge and
persisted in localStorage (re-applied on re-render). Uses fixed table layout
locked to measured px widths so resizing one column doesn't reflow the others.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 21:06:36 +02:00
Scarriffle
1a30b4066a Fix: don't squeeze the Kalender settings table into the 680px column
The reading-column max-width added for the profile panel also constrained the
wide calendar table, forcing a half-width horizontal scroll. Exempt
#settings-panel-accounts so the table uses the full width.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 20:49:26 +02:00
Scarriffle
aa12b83302 Birthday sync-device list + guard group-visible against birthday calendar
- new BirthdaySyncDevice table + /api/birthdays/sync-report & /devices so the
  web can show "birthdays come from these devices" (iOS reports its device on
  each Contacts sync)
- settings: reject setting a birthday calendar as the group-visible calendar
  (it can still be shared directly)
- web: Settings > Calendars > Birthdays shows the device list; exclude birthday
  calendars from the group-visible picker

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 18:52:02 +02:00
Scarriffle
19258096e2 Tidy settings layout (web)
- constrain settings panels to a 680px reading column so fields no longer
  stretch edge-to-edge on wide screens (main "looks bad" cause)
- fix the app-password "Erstellen" button rendering centred below the input:
  .app-pw-create inherited flex-direction:column from .form-group; force row so
  it sits inline to the right of the field

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 04:31:12 +02:00
Scarriffle
6baa07379f Rework birthdays to a single calendar + UI fixes (web)
- one dedicated birthday calendar per user; enable it in Settings > Calendars
  (or from the New-birthday dialog) — it then shows in the sidebar like any
  calendar (colour/visibility)
- New-birthday dialog: no target picker; day/month selects + a year field that
  hides when "year unknown"; fixed the year-unknown checkbox layout
- create split-button is now one seamless pill; the caret opens the menu
- Settings > Calendars gains a Birthdays section (enable + notify-days-before)
- removed the birthday toggle from the generic new-calendar modal
- profile settings: right-align the section save button for consistency
- bump service-worker cache to v25 so assets refresh

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 04:20:49 +02:00
Scarriffle
eb0684b99c Add birthday feature (web)
- views render display_title (age) and a cake icon for is_birthday events
  (month/week/agenda + quarter tooltip) via shared eventTitle/birthdayIconSvg
- create split-button caret opens a menu: new event / new birthday
- new birthday modal: name + date + "year unknown" + target birthday calendar,
  saved as an all-day FREQ=YEARLY local event with birth_year
- local-calendar modal gains a "birthday calendar" toggle + "notify N days before"
- i18n de/en strings

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 22:10:52 +02:00
Scarriffle
d426f8985c style(web): dark-mode the share modal's add-user search + permission select
The user-search input and permission dropdown in the share modal were raw white
browser controls. Style them like the rest of the app (dark bg, border, radius,
focus ring) and give the user checkboxes the primary accent colour. v80.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 13:25:03 +02:00
Scarriffle
89a1355149 fix(web): inverted condition broke hiding shared calendars
The per-device hide branch was gated on owned!==false (my own calendars) instead
of owned===false (shared with me), so unchecking a shared calendar hit the
owner-only enabled PUT and 404'd. Swap to owned===false.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 10:32:34 +02:00
Scarriffle
f844ded57d fix(web): hide edit/delete for others' events; persistent hide for shared calendars
Bug 1 — a calendar shared with me stayed visible after unchecking it: the hide
was a one-shot cache filter the server undid on refetch. Add a per-device
hidden set (localStorage 'hiddenLocalCalendars'), honoured in filterEvents
(normal view) and used to drive the checkbox state, so it survives refetch/reload.

Bug 2 — in the group combined view, other members' events showed edit/delete and
403'd on save. The combined endpoint now emits read_only (editable = the group
calendar OR my own events), via a read_only param threaded through
build_local_event_dict/expand_recurring_local. The event popup and edit modal now
treat read_only events as read-only (copy still allowed). Test added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 10:11:46 +02:00
Scarriffle
ec85a5b5f3 fix(web): show dialogs opened from settings on top of the settings page
The settings modal is a full-screen OPAQUE overlay at z-index 500. Dialogs
opened from within it (share, add-account, color picker) share z-index 500 but
sit earlier in the DOM, so they rendered BEHIND the opaque settings page — the
Share button appeared to "do nothing". Drop the settings page to z-index 400 so
real modals stack above it. v79.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 22:31:03 +02:00
Scarriffle
af64e191ec fix(web): reset checkbox size inside .form-group so the label isn't squeezed
The global ".form-group input" rule (width:100% + padding + border) also hit the
directory-hidden checkbox, blowing it up to a full-width field that pushed the
label text into a narrow wrapping column. Reset the checkbox to a small native
box (16px, no padding/border/background) so the label reads normally beside it.
v78.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 22:23:28 +02:00
Scarriffle
52bc7066db fix(web): settings modal — table crash, tab restore, checkbox layout
Three separate settings bugs (all pre-existing, exposed once the modal actually
opened):

1. renderCalendarTable() referenced a bare `owned` variable (undefined in that
   scope; should be cal.owned) → ReferenceError on the first owned local calendar
   → renderAllAccounts threw → the calendar table never rendered. This was the
   ROOT cause of "settings won't open" (it threw out of openSettingsModal); the
   earlier try/catch only masked it. Fixed to cal.owned.

2. On reload, writeUrlState() (via fetchAndRender) ran before openSettingsModal
   activated the saved tab and wrote the HTML-default (Profile) tab into the URL,
   so every reload landed on Profile. Now the stab is only rewritten once the
   modal is actually shown; otherwise the saved one is preserved.

3. The directory-hidden checkbox label inherited the global ".form-group label"
   uppercase/spaced/12px styling, stretching the text into a broken column. A
   higher-specificity .checkbox-row rule restores normal inline layout.

v77.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 22:16:10 +02:00
Scarriffle
7d5530e51c fix(web): open settings modal before populating it
openSettingsModal() populated every field and ran render helpers
(renderGroupVisibleList, renderAllAccounts, initAppPasswords) BEFORE the final
openModal() call, so an error in any of them left the modal unopened — the
"settings button does nothing" report. Now the modal opens first and the
populate step runs in try/catch (errors logged, not fatal). v76.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 21:51:56 +02:00
Scarriffle
90bc4b1531 fix(web): bind UI handlers before first fetch so a data error can't kill the UI
initCalendar() awaited fetchAndRender() BEFORE binding the topbar/settings/menu
handlers, so any error from /caldav/events (e.g. a transient 500) threw out of
init and left the buttons dead — the reported "settings won't open". Same root
cause as the reload-logout bug: app wiring must not depend on event data loading.

Bind all handlers first, then fetch inside try/catch (errors are logged + shown
as a toast, no longer fatal). v75.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 21:44:32 +02:00
Scarriffle
b8a578cf53 refactor(web): use server per-user colour for shared calendars
Replace the per-device localStorage colour override with the server-backed
per-user colour: the colour dot on a shared calendar now PUTs /calendars/{id}/color
(stores the recipient's own colour server-side, synced across devices) and the
list/events already carry share.color from the server, so the localStorage
re-apply layer is removed. Owners and recipients share one code path. v74.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 21:22:33 +02:00
Scarriffle
572172c424 fix(web): stay logged in when app initialisation fails after reload
boot() ran token validation and launchApp() inside the SAME try/catch, so ANY
error during app init (a failed calendar/event fetch, a render error) cleared
the token and bounced a validly-authenticated user to the login screen — the
"logged out on every F5" bug. Now /auth/me validates the token alone; launchApp()
runs outside that catch, so a data/render error can no longer log the user out.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 21:22:33 +02:00
Scarriffle
cad48efcc6 feat(web): recolour calendars shared with me (per-device local override)
Shared calendars belong to someone else, so a server colour PUT would 403.
Instead store the recipient's chosen colour locally (localStorage 'sharedCalColors',
keyed by calendar id) and re-apply it to events on every fetch. The colour dot
on a shared calendar now opens the picker instead of showing an error.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 18:49:07 +02:00
Scarriffle
2ae8499247 fix(web): can't edit calendars shared with me; struck-pencil read-only marker
- Sidebar: don't start an inline rename on a calendar I don't own (owned=false)
  — the save would only 403. Colour picker was already gated.
- Sidebar: show a struck-through pencil icon on read-only shared calendars.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 18:38:01 +02:00
Scarriffle
79fdf4f54a feat(sharing): group-shared calendars in every member's sidebar, person share picker, hidden profiles
- Backend: co-member group_visible calendars now surface in /local/calendars
  (owned=false, shared_by=owner, read-only, group_shared) and in the normal
  /caldav/events merge (via readable_local_calendar_ids), deduped against
  direct shares / group calendars so nothing appears twice.
- Backend: new User.directory_hidden — a user can hide from sharing/group
  pickers (/users/directory), while admin user management (/users/) still lists
  them. Migration + profile GET/PUT.
- Backend: /groups/{id} members carry shares_calendar so clients can drop
  phantom rows for members who share nothing.
- Frontend: reachable "Teilen" button on owned local calendars; share modal is
  now a checkbox multi-select of users (checked = shared). Hidden-profile toggle
  in Settings → Profile. Group member filter only lists members who actually
  share (phantom fix). Calendars shared with me moved to a dedicated read-only
  "shared with me" section in the manage table.
- Tests: group_visible propagation, no-share absence, dedup, directory_hidden.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 16:35:11 +02:00
Scarriffle
f76d2783d9 feat(web): show shared calendars under the owner's name
A calendar shared with another person now appears to the recipient under the
OWNER's name (Guido's "Persönlich" shows as "Guido"), matching the iOS filter
sheet. The original calendar name moves to the sub-label / settings source
column so it stays identifiable. Sidebar list + settings table.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 14:41:31 +02:00
Scarriffle
784c9013eb feat(web): mark read-only shared calendars and hide them from the event editor
- Sidebar: a calendar shared with read access shows "· Nur lesen" next to the
  "shared with me · <owner>" label.
- Event editor calendar picker: exclude read-only shared calendars (own +
  read_write, incl. group calendars, stay) so a save can't 403.

Parity with the server/iOS/Android sharing changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 19:02:12 +02:00
Scarriffle
9fb350eb29 fix: surface all calendar sync failures, not just Google
CalDAV and Home Assistant sync failures were previously only logged
server-side, leaving clients unable to distinguish an empty calendar
from a broken sync. Unify error reporting across CalDAV, Home
Assistant, and Google into a single errors list on GET
/api/caldav/events, shaped as {source, name, message}. Messages are
fixed generic strings, never raw exception text, to avoid leaking
URLs or credential fragments. get_ha_events and get_google_events now
return (events, errors) tuples so per-calendar failures propagate to
the caller in addition to account-level failures. Frontend toast now
picks its label from err.source instead of assuming Google/err.email.
2026-07-02 18:22:11 +02:00
Scarriffle
9306d638ad fix(caldav): move app-password section to Settings → Profile where users look
The app-password UI was in the user-menu profile modal, but users manage CalDAV
in Settings, so it went unnoticed. Move the section into the Settings → Profile
panel (next to account/privacy) and drive it from openSettingsModal via a
top-level initAppPasswords().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 14:17:25 +02:00
Scarriffle
f662163185 feat(caldav): app-specific passwords so MFA accounts can use CalDAV
CalDAV clients send only user+password over Basic Auth and can't provide a TOTP
code, so account passwords would bypass 2FA. Add revocable app passwords:

- models: AppPassword table (bcrypt hash, label, last_used); auto-created via
  create_all
- profile_router: GET/POST/DELETE /profile/app-passwords (plaintext shown once)
- dav_router: Basic Auth accepts any app password; the account password is
  accepted only when 2FA is disabled
- frontend: "App-Passwörter (CalDAV)" section in the profile modal (create/show-
  once/copy/revoke) + i18n (de/en); login hint now says app password

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 13:15:35 +02:00
Scarriffle
fb32f0424f feat(caldav): username/password (Basic Auth) access with discovery + https URLs
- dav_router: add Basic-Auth principal-discovery tree at /caldav/ (and
  /.well-known/caldav) so clients can add a CalDAV account with server URL +
  username + password; lists all published calendars. Token URL /dav/{token}/
  still works without login. Handlers generalised over a base href.
- dav_util: derive the public origin from X-Forwarded-Proto/-Host (or
  PUBLIC_BASE_URL) so published URLs are https, not internal http:8080.
- local_router: expose caldav_login_url alongside caldav_url.
- frontend/i18n: show both the no-login token URL and the login URL + hint.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 12:44:16 +02:00
Scarriffle
34e701fa78 feat(pwa): auto-update service worker so new releases take effect without manual cache clearing
- app.js: reload once on SW controllerchange (guarded against loops / first
  install) and poll reg.update() hourly for long-open tabs
- sw.js: bump cache to v24 so the new (network-first) worker replaces any stale
  cache-first worker and cleans old caches on activate

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 11:24:05 +02:00
Scarriffle
661a8ea579 chore: bump APP_VERSION to v65 (cache-bust / deploy verification)
Fresh commit so a git pull visibly advances the deployed version and the PWA
service worker refreshes its cached assets. No functional change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 11:12:21 +02:00
Scarriffle
47944ed952 feat: publish local calendars via two-way CalDAV (opt-in, secret token URL)
Backend:
- LocalCalendar gains caldav_published + dav_token + dav_ctag; LocalEvent gains
  etag (migrations in main.py). bump_dav() refreshes ctag/etag on every local
  event write (create/update/delete/import).
- local_router: PUT /calendars/{id} accepts caldav_published (mints/revokes
  token), new POST /calendars/{id}/dav-token/rotate, _cal_dict exposes
  caldav_published + caldav_url.
- New dav_router mounted at root (/dav/{token}/...): a minimal two-way CalDAV
  server (OPTIONS/PROPFIND/REPORT/GET/PUT/DELETE) reusing ical_io build/parse,
  ctag-based change detection. Secret token = auth, no login.

Frontend:
- Settings calendar table: per-local-calendar publish toggle + subscribe URL
  with copy and token-rotate; i18n (de/en) and styling.

Note: reverse proxy must allow WebDAV methods (PROPFIND/REPORT/PUT/DELETE).
VALARM/reminders are not round-tripped via CalDAV.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 10:19:01 +02:00
Scarriffle
a591eb51d3 chore: bump APP_VERSION to v63 to ship mini-cal + week-view fixes
The multi-day mini-calendar and short-event week-view fixes were already
committed but not visible because the PWA served cached assets. Bump the
version so clients pick up the new JS/CSS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 10:15:41 +02:00
Scarriffle
f791160d1a fix: mini-cal marks full multi-day span; short week events show title inline
- Mini calendar: mark every day an event spans (not just the start day) so
  multi-day events (Urlaub/Ferien) show a dot across the whole range
- Week view: render short events on one line (time next to title) so the title
  stays visible; drop the location line when there's no room

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 09:42:02 +02:00
Scarriffle
906241a743 fix: agenda view scrolls to current date on render
The agenda lists the whole cached range, so clicking Today only reset scroll
to the top (earliest past event). Scroll the agenda to the current date (or the
next day with events) after rendering, so Today/mini-cal clicks land correctly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 17:13:18 +02:00
Scarriffle
2e76e63ba2 fix: event popup — allow toolbar button clicks and text selection while draggable
- Don't start a header drag when the pointer goes down on a button/link, so
  edit/copy/delete/close work again
- Make the popup body text selectable (user-select: text) for copying

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 12:15:38 +02:00
Scarriffle
6e8efb2ed5 feat(sidebar): dedicated share-icon set for group-visible indicator
Replace group-category icons with 8 sharing-specific icons in the
Darstellung picker: share (3 nodes), link, send, eye, upload, wifi,
person_add, ios_share. Uses new shareIconSvg() + SHARE_ICON_KEYS/PATHS
constants, separate from group icons. Default changes from 'people' to 'share'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 22:02:54 +02:00
Scarriffle
d6159f0639 feat: calendar rename for all sources, group icon in sidebar, configurable share icon
- Rename: Add google and homeassistant branches to the dblclick-rename
  save() handler; backend already accepted name updates for both sources
- Group icon: Pass groupIconForLocalCal(cal.id) into sidebar entries so
  the group's custom icon (home/heart/work/…) shows instead of always
  defaulting to the people icon
- Share icon: New share_calendar_icon field in UserSettings (+ migration)
  replaces the hardcoded SHARE_ICON SVG; users pick from GROUP_ICON_KEYS
  in Settings → Darstellung via a new icon-picker row

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 21:56:24 +02:00
Scarriffle
be3d4057b3 feat(sidebar): distinct share icon for groupVisible, hide scrollbars
- groupVisible calendars get a share icon instead of the people icon;
  people icon is reserved for actual group calendars
- sidebar scrollbar hidden (scrollbar-width: none + webkit)
- modal-body scrollbar hidden — fixes Impressum scroll indicator

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 21:36:36 +02:00
Scarriffle
eb9440c2b2 feat(sidebar): move group icon before calendar name
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 21:30:31 +02:00
Scarriffle
34777c78c9 fix(sidebar): min-height approach for action buttons, no overlap or jump
Instead of absolute positioning (which caused icons to overlay text),
use min-height:40px on .cal-item so the row is always tall enough for
28px mini-btns. Buttons stay in the flex flow with display:none when
hidden — no space reserved, no text truncation, no height shift on hover.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 21:24:57 +02:00
Scarriffle
0427e1189d fix(sidebar): absolute-position action buttons to prevent name truncation
Buttons (.cal-item-remove, .cal-item-bell) are now position:absolute so
they never participate in flex layout — names get full available width at
all times. Buttons fade in over the right edge of the item on hover with
no layout shift and no row-height change.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 21:18:04 +02:00