Fix notes popup positioning, reposition task actions to avoid overlap, and improve Apple Calendar sync

This commit is contained in:
mARTin 2026-02-24 12:58:19 +01:00
parent 368928c016
commit 279d1a4c49
5 changed files with 41 additions and 23 deletions

View File

@ -967,35 +967,45 @@ h3 {
color: var(--weekly-text); color: var(--weekly-text);
} }
/* Action Buttons Styling */ /* Action Buttons Styling - Float above task on hover to avoid overlap */
.task-actions { .task-actions {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 2px; gap: 2px;
position: absolute; position: absolute;
right: 0; right: 0;
top: 0; top: -26px; /* Position above the task item */
bottom: 0; background: var(--weekly-bg, white);
z-index: 10; border: 1px solid var(--weekly-border, #e0e0e0);
padding-left: 8px; border-radius: 6px;
padding-right: 4px; box-shadow: 0 2px 8px rgba(0,0,0,0.12);
z-index: 100;
padding: 2px 4px;
flex-wrap: nowrap; flex-wrap: nowrap;
pointer-events: auto;
} }
/* Time-grid tasks: show actions below task text as a dropdown toolbar */ /* Time-grid tasks: show actions above task text as a floating toolbar on hover */
.time-slot-task > .task-actions { .time-slot-task > .task-actions {
position: absolute; position: absolute;
top: auto; top: -28px; /* Float above the task */
bottom: auto;
left: 0; left: 0;
right: auto; right: auto;
margin-top: 0; margin-top: 0;
background: var(--weekly-bg, white); background: var(--weekly-bg, white);
border: 1px solid var(--weekly-border, #e0e0e0); border: 1px solid var(--weekly-border, #e0e0e0);
border-radius: 6px; border-radius: 6px;
box-shadow: 0 2px 8px rgba(0,0,0,0.12); box-shadow: 0 4px 12px rgba(0,0,0,0.15);
padding: 2px 4px; padding: 2px 4px;
z-index: 20; z-index: 100; /* Ensure it stays above everything */
display: flex !important; /* Force flex even if default is hidden */
pointer-events: auto;
}
/* Ensure actions don't get clipped by the scrolling container */
.time-slots-container {
overflow-y: auto;
overflow-x: visible;
} }
.dark .time-slot-task > .task-actions { .dark .time-slot-task > .task-actions {

View File

@ -331,8 +331,8 @@ export function GridTaskBlock({
)} )}
<button className="task-action-btn delete text-red-500 hover:text-red-700 hover:bg-red-100/50 dark:hover:bg-red-900/30 rounded" onClick={(e) => { e.stopPropagation(); deleteTask(task.id); }} title="Delete"> <button className="task-action-btn delete text-red-500 hover:text-red-700 hover:bg-red-100/50 dark:hover:bg-red-900/30 rounded" onClick={(e) => { e.stopPropagation(); deleteTask(task.id); }} title="Delete">
<svg viewBox="0 0 24 24" width="12" height="12" stroke="currentColor" strokeWidth="2.5" fill="none" strokeLinecap="round" strokeLinejoin="round"> <svg viewBox="0 0 24 24" width="12" height="12" stroke="currentColor" strokeWidth="2.5" fill="none" strokeLinecap="round" strokeLinejoin="round">
<line x1="18" y1="6" x2="6" y2="18" /> <polyline points="3 6 5 6 21 6"></polyline>
<line x1="6" y1="6" x2="18" y2="18" /> <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
</svg> </svg>
</button> </button>
</div> </div>

View File

@ -5854,7 +5854,7 @@ function TaskItem({
</span> </span>
</span> </span>
<div className="task-actions absolute right-0 top-0 bottom-0 flex items-center bg-white/95 dark:bg-gray-800/95 pl-2 pr-1 shadow-[-12px_0_12px_-4px_rgba(255,255,255,0.95)] dark:shadow-[-12px_0_12px_-4px_rgba(31,41,55,0.95)] z-20"> <div className="task-actions z-20">
{/* Complete */} {/* Complete */}
<button <button
className={`task-action-btn ${task.completed ? "active text-green-600 dark:text-green-500" : ""}`} className={`task-action-btn ${task.completed ? "active text-green-600 dark:text-green-500" : ""}`}
@ -6028,8 +6028,8 @@ function TaskItem({
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
> >
<line x1="18" y1="6" x2="6" y2="18"></line> <polyline points="3 6 5 6 21 6"></polyline>
<line x1="6" y1="6" x2="18" y2="18"></line> <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
</svg> </svg>
</button> </button>
</div> </div>

View File

@ -11,6 +11,7 @@ export interface AppleCalendarEvent {
endDate: string; endDate: string;
description?: string; description?: string;
location?: string; location?: string;
url?: string;
} }
export interface AppleCalendar { export interface AppleCalendar {
@ -165,7 +166,8 @@ export const getUpcomingEvents = async (
startDate: exIsAllDay ? exStart.toISOString().slice(0, 10) : exStart.toISOString(), startDate: exIsAllDay ? exStart.toISOString().slice(0, 10) : exStart.toISOString(),
endDate: exIsAllDay ? exEnd.toISOString().slice(0, 10) : exEnd.toISOString(), endDate: exIsAllDay ? exEnd.toISOString().slice(0, 10) : exEnd.toISOString(),
description: exEvent.description, description: exEvent.description,
location: exEvent.location location: exEvent.location,
url: exVevent.getFirstPropertyValue('url')?.toString() || undefined
}); });
} }
}); });
@ -197,7 +199,8 @@ export const getUpcomingEvents = async (
startDate: isAllDayRecurring ? occStart.toISOString().slice(0, 10) : occStart.toISOString(), startDate: isAllDayRecurring ? occStart.toISOString().slice(0, 10) : occStart.toISOString(),
endDate: isAllDayRecurring ? occEnd.toISOString().slice(0, 10) : occEnd.toISOString(), endDate: isAllDayRecurring ? occEnd.toISOString().slice(0, 10) : occEnd.toISOString(),
description: event.description, description: event.description,
location: event.location location: event.location,
url: vevent.getFirstPropertyValue('url')?.toString() || undefined
}); });
} }
} catch (expandErr: any) { } catch (expandErr: any) {
@ -217,7 +220,8 @@ export const getUpcomingEvents = async (
startDate: isAllDay ? start.toISOString().slice(0, 10) : start.toISOString(), startDate: isAllDay ? start.toISOString().slice(0, 10) : start.toISOString(),
endDate: isAllDay ? end.toISOString().slice(0, 10) : end.toISOString(), endDate: isAllDay ? end.toISOString().slice(0, 10) : end.toISOString(),
description: event.description, description: event.description,
location: event.location location: event.location,
url: vevent.getFirstPropertyValue('url')?.toString() || undefined
}); });
} }
}); });
@ -338,7 +342,8 @@ END:VCALENDAR`;
startDate: eventData.start.dateTime || eventData.start.date || '', startDate: eventData.start.dateTime || eventData.start.date || '',
endDate: eventData.end.dateTime || eventData.end.date || '', endDate: eventData.end.dateTime || eventData.end.date || '',
description: eventData.description, description: eventData.description,
location: eventData.location location: eventData.location,
url: eventData.url
}; };
} catch (error) { } catch (error) {
console.error('[APPLE CALENDAR] Error creating event:', error); console.error('[APPLE CALENDAR] Error creating event:', error);
@ -553,7 +558,8 @@ export const updateEvent = async (
startDate: event.startDate.toString(), startDate: event.startDate.toString(),
endDate: event.endDate.toString(), endDate: event.endDate.toString(),
description: event.description, description: event.description,
location: event.location location: event.location,
url: vevent.getFirstPropertyValue('url')?.toString() || undefined
}; };
} catch (error) { } catch (error) {

View File

@ -360,6 +360,7 @@ export const getCalendarEvents = async (
date: startIsAllDay ? event.endDate : undefined, date: startIsAllDay ? event.endDate : undefined,
}, },
location: event.location, location: event.location,
url: event.url,
source: 'apple' as const, source: 'apple' as const,
calendarId, calendarId,
calendarTitle: calendars.find(c => c.id === calendarId)?.title || 'Apple Calendar', calendarTitle: calendars.find(c => c.id === calendarId)?.title || 'Apple Calendar',
@ -751,6 +752,7 @@ export const updateCalendarEvent = async (
start: { dateTime: updatedEvent.startDate }, start: { dateTime: updatedEvent.startDate },
end: { dateTime: updatedEvent.endDate }, end: { dateTime: updatedEvent.endDate },
location: updatedEvent.location, location: updatedEvent.location,
url: updatedEvent.url,
source: 'apple', source: 'apple',
calendarId, calendarId,
calendarTitle: '', calendarTitle: '',