diff --git a/package.json b/package.json index bbbb992..ada8fc9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "my-weekly-todo-list", - "version": "1.66.1", + "version": "1.67.0", "description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view", "main": "index.js", "scripts": { diff --git a/src/app/globals.css b/src/app/globals.css index 0f6b38b..d305128 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -3100,6 +3100,52 @@ h3 { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); } +/* Event icons row (recurring, note, provider) */ +.event-icons-row { + position: absolute; + bottom: 2px; + right: 4px; + display: flex; + align-items: center; + gap: 3px; + opacity: 0.5; + z-index: 2; +} + +.event-note-icon { + position: relative; + cursor: help; + display: flex; + align-items: center; +} + +.event-note-icon::after { + content: attr(data-note); + position: absolute; + bottom: 100%; + right: 0; + background: var(--weekly-bg, #222); + color: var(--weekly-text, #fff); + padding: 6px 10px; + border-radius: 6px; + font-size: 0.7rem; + white-space: pre-wrap; + max-width: 220px; + max-height: 120px; + overflow: hidden; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25); + opacity: 0; + pointer-events: none; + transition: opacity 0.15s; + z-index: 100; + line-height: 1.3; +} + +.event-note-icon:hover::after { + opacity: 1; +} + + /* Make day columns scrollable when using time grid */ .time-grid-wrapper .weekly-days-grid { flex: 1; diff --git a/src/components/WeeklyView.tsx b/src/components/WeeklyView.tsx index 2695503..c5cede9 100644 --- a/src/components/WeeklyView.tsx +++ b/src/components/WeeklyView.tsx @@ -2225,6 +2225,7 @@ export default function WeeklyView() { eventId: string; mode: 'move' | 'resize-top' | 'resize-bottom'; startY: number; + startX: number; originalStartTime: string; originalEndTime: string; currentStartTime: string; @@ -3731,6 +3732,7 @@ export default function WeeklyView() { eventId: event.id, mode, startY: e.clientY, + startX: e.clientX, originalStartTime: event.startTime, originalEndTime: event.endTime, currentStartTime: event.startTime, @@ -3746,8 +3748,9 @@ export default function WeeklyView() { const handleMouseMove = (e: MouseEvent) => { const deltaY = e.clientY - eventDragState.startY; + const deltaX = e.clientX - eventDragState.startX; // Require minimum 3px movement to start actual drag - if (!eventDragState.hasMoved && Math.abs(deltaY) < 3) return; + if (!eventDragState.hasMoved && Math.abs(deltaY) < 3 && Math.abs(deltaX) < 3) return; if (!eventDragState.hasMoved) { setEventDragState(prev => prev ? { ...prev, hasMoved: true } : null); } @@ -3756,8 +3759,25 @@ export default function WeeklyView() { const origEnd = new Date(eventDragState.originalEndTime); if (eventDragState.mode === 'move') { - const newStart = new Date(origStart.getTime() + deltaMinutes * 60000); - const newEnd = new Date(origEnd.getTime() + deltaMinutes * 60000); + // Detect day column under cursor for cross-day drag + let dayOffset = 0; + const dayColumns = document.querySelectorAll('.weekly-day-column'); + if (dayColumns.length > 0) { + const origDate = `${origStart.getFullYear()}-${String(origStart.getMonth() + 1).padStart(2, '0')}-${String(origStart.getDate()).padStart(2, '0')}`; + let origColIndex = -1; + let hoverColIndex = -1; + dayColumns.forEach((col, i) => { + const rect = col.getBoundingClientRect(); + const colDate = col.getAttribute('data-date'); + if (colDate === origDate) origColIndex = i; + if (e.clientX >= rect.left && e.clientX <= rect.right) hoverColIndex = i; + }); + if (origColIndex >= 0 && hoverColIndex >= 0) { + dayOffset = hoverColIndex - origColIndex; + } + } + const newStart = new Date(origStart.getTime() + deltaMinutes * 60000 + dayOffset * 86400000); + const newEnd = new Date(origEnd.getTime() + deltaMinutes * 60000 + dayOffset * 86400000); setEventDragState(prev => prev ? { ...prev, currentStartTime: newStart.toISOString(), currentEndTime: newEnd.toISOString() } : null); } else if (eventDragState.mode === 'resize-bottom') { const newEnd = new Date(origEnd.getTime() + deltaMinutes * 60000); @@ -3776,6 +3796,11 @@ export default function WeeklyView() { if (!eventDragState) return; const startChanged = eventDragState.currentStartTime !== eventDragState.originalStartTime; const endChanged = eventDragState.currentEndTime !== eventDragState.originalEndTime; + // Set drag-ended ref immediately (before async) to prevent click from opening popup + if (eventDragState.hasMoved) { + dragJustEndedRef.current = true; + setTimeout(() => { dragJustEndedRef.current = false; }, 300); + } if (eventDragState.hasMoved && (startChanged || endChanged)) { // Optimistically update the UI setRawCalendarEvents(prev => prev.map(ev => @@ -3811,12 +3836,7 @@ export default function WeeklyView() { )); } } - const didMove = eventDragState.hasMoved; setEventDragState(null); - if (didMove) { - dragJustEndedRef.current = true; - setTimeout(() => { dragJustEndedRef.current = false; }, 200); - } }; document.addEventListener('mousemove', handleMouseMove); @@ -7355,6 +7375,7 @@ export default function WeeklyView() {