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>
This commit is contained in:
@@ -206,6 +206,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<div class="add-cal-dropdown hidden" id="add-cal-dropdown">
|
<div class="add-cal-dropdown hidden" id="add-cal-dropdown">
|
||||||
<button data-action="local">Lokaler Kalender</button>
|
<button data-action="local">Lokaler Kalender</button>
|
||||||
|
<button data-action="birthday" data-i18n="birthday_calendar_type">Geburtstagskalender</button>
|
||||||
<button data-action="caldav">CalDAV-Konto</button>
|
<button data-action="caldav">CalDAV-Konto</button>
|
||||||
<button data-action="ical">iCal-URL abonnieren</button>
|
<button data-action="ical">iCal-URL abonnieren</button>
|
||||||
<button data-action="google">Google Kalender</button>
|
<button data-action="google">Google Kalender</button>
|
||||||
@@ -934,6 +935,7 @@
|
|||||||
<h4 class="panel-title" data-i18n="settings_nav_calendars">Kalender</h4>
|
<h4 class="panel-title" data-i18n="settings_nav_calendars">Kalender</h4>
|
||||||
<div class="accounts-add-row">
|
<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-local">+ Lokal</button>
|
||||||
|
<button class="btn btn-secondary btn-sm" id="settings-btn-add-birthday" data-i18n="birthday_add_btn">+ Geburtstage</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-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-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-ha">+ Home Assistant</button>
|
||||||
|
|||||||
@@ -1367,6 +1367,10 @@ function bindSidebar() {
|
|||||||
dropdown.classList.add('hidden');
|
dropdown.classList.add('hidden');
|
||||||
openLocalCalModal();
|
openLocalCalModal();
|
||||||
};
|
};
|
||||||
|
dropdown.querySelector('[data-action="birthday"]').onclick = () => {
|
||||||
|
dropdown.classList.add('hidden');
|
||||||
|
addBirthdayCalendar();
|
||||||
|
};
|
||||||
dropdown.querySelector('[data-action="ical"]').onclick = () => {
|
dropdown.querySelector('[data-action="ical"]').onclick = () => {
|
||||||
dropdown.classList.add('hidden');
|
dropdown.classList.add('hidden');
|
||||||
openICalSubModal();
|
openICalSubModal();
|
||||||
@@ -2588,6 +2592,19 @@ async function ensureBirthdayCalendar() {
|
|||||||
return cal;
|
return cal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Explicit "add birthday calendar" action (sidebar dropdown + settings). Only
|
||||||
|
* one per account — if one exists, just inform the user. */
|
||||||
|
async function addBirthdayCalendar() {
|
||||||
|
if (birthdayCalendar()) { showToast(t('birthday_calendar_exists')); return; }
|
||||||
|
try {
|
||||||
|
await ensureBirthdayCalendar();
|
||||||
|
renderBirthdaySettings();
|
||||||
|
renderCalendarTable();
|
||||||
|
fetchAndRender();
|
||||||
|
showToast(t('calendar_created', { name: t('birthday_calendar_name') }));
|
||||||
|
} catch (e) { showToast(e.message, true); }
|
||||||
|
}
|
||||||
|
|
||||||
// ── Birthday Modal (manual entry) ─────────────────────────
|
// ── Birthday Modal (manual entry) ─────────────────────────
|
||||||
function fillBirthdayDateSelects() {
|
function fillBirthdayDateSelects() {
|
||||||
const daySel = document.getElementById('birthday-day');
|
const daySel = document.getElementById('birthday-day');
|
||||||
@@ -3595,21 +3612,11 @@ function renderBirthdaySettings() {
|
|||||||
container.innerHTML = '';
|
container.innerHTML = '';
|
||||||
const cal = birthdayCalendar();
|
const cal = birthdayCalendar();
|
||||||
if (!cal) {
|
if (!cal) {
|
||||||
|
// Creation lives in the add row ("+ Geburtstage") / sidebar dropdown now.
|
||||||
const hint = document.createElement('div');
|
const hint = document.createElement('div');
|
||||||
hint.className = 'form-hint';
|
hint.className = 'form-hint';
|
||||||
hint.textContent = t('birthday_activate_hint');
|
hint.textContent = t('birthday_settings_hint');
|
||||||
const btn = document.createElement('button');
|
container.append(hint);
|
||||||
btn.className = 'btn btn-primary btn-sm';
|
|
||||||
btn.textContent = t('birthday_activate');
|
|
||||||
btn.onclick = async () => {
|
|
||||||
try {
|
|
||||||
await ensureBirthdayCalendar();
|
|
||||||
renderBirthdaySettings();
|
|
||||||
renderCalendarTable();
|
|
||||||
showToast(t('calendar_created', { name: t('birthday_calendar_name') }));
|
|
||||||
} catch (e) { showToast(e.message, true); }
|
|
||||||
};
|
|
||||||
container.append(hint, btn);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const status = document.createElement('div');
|
const status = document.createElement('div');
|
||||||
@@ -3724,12 +3731,14 @@ function initResizableCalTable(table) {
|
|||||||
const ths = Array.from(table.tHead.rows[0].cells);
|
const ths = Array.from(table.tHead.rows[0].cells);
|
||||||
let saved = null;
|
let saved = null;
|
||||||
try { saved = JSON.parse(localStorage.getItem('calTableColWidths') || 'null'); } catch { saved = null; }
|
try { saved = JSON.parse(localStorage.getItem('calTableColWidths') || 'null'); } catch { saved = null; }
|
||||||
// Measure natural widths, then lock to px + fixed layout so dragging one
|
// Lock to px + fixed layout so dragging one column doesn't reflow the others.
|
||||||
// column doesn't reflow the others.
|
// Sensible defaults per column (Name / Herkunft / Sichtbar / Benachrichtigungen
|
||||||
const natural = ths.map(th => th.offsetWidth);
|
// / Export-Import / Sync / trash); user drags override and persist.
|
||||||
|
const DEFAULTS = [200, 90, 80, 150, 240, 90, 44];
|
||||||
ths.forEach((th, i) => {
|
ths.forEach((th, i) => {
|
||||||
const w = (Array.isArray(saved) && saved[i]) ? saved[i] : natural[i];
|
const w = (Array.isArray(saved) && saved[i]) ? saved[i]
|
||||||
th.style.width = Math.max(60, w || 80) + 'px';
|
: (DEFAULTS[i] || th.offsetWidth || 100);
|
||||||
|
th.style.width = Math.max(50, w) + 'px';
|
||||||
});
|
});
|
||||||
table.style.tableLayout = 'fixed';
|
table.style.tableLayout = 'fixed';
|
||||||
const sync = () => {
|
const sync = () => {
|
||||||
@@ -4329,6 +4338,10 @@ function bindSettingsModal() {
|
|||||||
const btn = document.getElementById(id);
|
const btn = document.getElementById(id);
|
||||||
if (btn) btn.addEventListener('click', () => { closeModal('modal-settings'); fn(); });
|
if (btn) btn.addEventListener('click', () => { closeModal('modal-settings'); fn(); });
|
||||||
});
|
});
|
||||||
|
// Birthday calendar is created inline (no modal) — keep settings open so the
|
||||||
|
// new calendar + its options show up immediately.
|
||||||
|
const bdayBtn = document.getElementById('settings-btn-add-birthday');
|
||||||
|
if (bdayBtn) bdayBtn.addEventListener('click', () => addBirthdayCalendar());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Profile Modal ─────────────────────────────────────────
|
// ── Profile Modal ─────────────────────────────────────────
|
||||||
|
|||||||
@@ -299,6 +299,10 @@ const translations = {
|
|||||||
birthday_color_hint: 'Farbe und Sichtbarkeit änderst du in der Seitenleiste.',
|
birthday_color_hint: 'Farbe und Sichtbarkeit änderst du in der Seitenleiste.',
|
||||||
birthday_devices_title: 'Geburtstage kommen von diesen Geräten:',
|
birthday_devices_title: 'Geburtstage kommen von diesen Geräten:',
|
||||||
birthday_devices_count: '{n} Geburtstage',
|
birthday_devices_count: '{n} Geburtstage',
|
||||||
|
birthday_calendar_type: 'Geburtstagskalender',
|
||||||
|
birthday_add_btn: '+ Geburtstage',
|
||||||
|
birthday_calendar_exists: 'Geburtstagskalender existiert bereits',
|
||||||
|
birthday_settings_hint: 'Lege einen Geburtstagskalender über „+ Geburtstage" oben an.',
|
||||||
error_name_url: 'Bitte Name und URL eingeben',
|
error_name_url: 'Bitte Name und URL eingeben',
|
||||||
ical_subscribed: '"{name}" abonniert',
|
ical_subscribed: '"{name}" abonniert',
|
||||||
google_synced: 'Kalender synchronisiert',
|
google_synced: 'Kalender synchronisiert',
|
||||||
@@ -643,6 +647,10 @@ const translations = {
|
|||||||
birthday_color_hint: 'Change colour and visibility in the sidebar.',
|
birthday_color_hint: 'Change colour and visibility in the sidebar.',
|
||||||
birthday_devices_title: 'Birthdays come from these devices:',
|
birthday_devices_title: 'Birthdays come from these devices:',
|
||||||
birthday_devices_count: '{n} birthdays',
|
birthday_devices_count: '{n} birthdays',
|
||||||
|
birthday_calendar_type: 'Birthday calendar',
|
||||||
|
birthday_add_btn: '+ Birthdays',
|
||||||
|
birthday_calendar_exists: 'Birthday calendar already exists',
|
||||||
|
birthday_settings_hint: 'Add a birthday calendar via “+ Birthdays” above.',
|
||||||
error_name_url: 'Please enter a name and URL',
|
error_name_url: 'Please enter a name and URL',
|
||||||
ical_subscribed: '"{name}" subscribed',
|
ical_subscribed: '"{name}" subscribed',
|
||||||
google_synced: 'Calendar synced',
|
google_synced: 'Calendar synced',
|
||||||
|
|||||||
Reference in New Issue
Block a user