kalender und fixes

This commit is contained in:
th committed 2026-04-08 17:24:55 +02:00
1 parent 940d9bbde4
commit 416ca9e854
14 files changed
+376 -71

No files matched your search

+56 -4
View File
@@ -4,6 +4,7 @@ import { $, esc } from './util.js';
import { state } from './state.js';
import { stripMd, getTodos } from './markdown.js';
import { autoSync, getCalConfig, getAllCalConfigs } from './caldav.js';
import { renderCardHtml } from './board.js';
const overlay = $('calendar');
const grid = $('cal-grid');
@@ -138,6 +139,12 @@ function isAppointment(card) {
return tags.includes('termin') || card.caldav_uid || /^\d{4}-\d{2}-\d{2}\s*[—-]\s*.+/.test(card.title);
}
let calHover = null, calHoverTimer = null;
function clearCalHover() {
if (calHoverTimer) { clearTimeout(calHoverTimer); calHoverTimer = null; }
if (calHover) { calHover.remove(); calHover = null; }
}
function render() {
title.textContent = `${MONTHS[viewMonth]} ${viewYear}`;
@@ -234,11 +241,44 @@ function render() {
grid.innerHTML = html;
// Hover card preview — clear any stale popups from previous render
clearCalHover();
// Click on card item → open card (hide calendar, restore on return)
grid.querySelectorAll('[data-card-id]').forEach(el => {
let clickTimer = null;
el.addEventListener('mouseenter', () => {
clearCalHover();
calHoverTimer = setTimeout(() => {
const card = state.cards.find(c => c.id == el.dataset.cardId);
if (!card) return;
const rect = el.getBoundingClientRect();
const textEl = el.querySelector('.truncate') || el;
const textRect = textEl.getBoundingClientRect();
calHover = document.createElement('div');
Object.assign(calHover.style, {
position: 'fixed', zIndex: '210', width: '280px',
filter: 'drop-shadow(0 8px 24px rgba(0,0,0,0.4))',
});
const left = textRect.right + 4;
const useLeft = left + 290 < window.innerWidth;
calHover.style.left = (useLeft ? left : textRect.left - 284) + 'px';
calHover.style.top = Math.min(rect.top - 10, window.innerHeight - 320) + 'px';
calHover.innerHTML = renderCardHtml(card);
calHover.addEventListener('mouseenter', () => { if (calHoverTimer) { clearTimeout(calHoverTimer); calHoverTimer = null; } });
calHover.addEventListener('mouseleave', () => clearCalHover());
calHover.addEventListener('mouseover', e => e.stopPropagation());
document.body.appendChild(calHover);
}, 400);
});
el.addEventListener('mouseleave', () => {
if (calHoverTimer) { clearTimeout(calHoverTimer); calHoverTimer = null; }
setTimeout(() => { if (calHover && !calHover.matches(':hover')) clearCalHover(); }, 150);
});
el.addEventListener('click', e => {
e.stopPropagation();
clearCalHover();
if (clickTimer) return;
clickTimer = setTimeout(() => {
clickTimer = null;
@@ -250,6 +290,7 @@ function render() {
});
el.addEventListener('dblclick', e => {
e.stopPropagation();
clearCalHover();
if (clickTimer) { clearTimeout(clickTimer); clickTimer = null; }
closeDayPopup();
state._returnToCalendar = true;
@@ -425,15 +466,26 @@ function openDayPopup(ds, cellEl) {
});
});
// Close on click outside
// Close on click outside or ESC
setTimeout(() => {
const closeHandler = e => {
const clickHandler = e => {
if (dayPopup && !dayPopup.contains(e.target)) {
closeDayPopup();
document.removeEventListener('click', closeHandler);
cleanup();
}
};
document.addEventListener('click', closeHandler);
const keyHandler = e => {
if (e.key === 'Escape') {
closeDayPopup();
cleanup();
}
};
const cleanup = () => {
document.removeEventListener('click', clickHandler);
document.removeEventListener('keydown', keyHandler);
};
document.addEventListener('click', clickHandler);
document.addEventListener('keydown', keyHandler);
}, 0);
}