From 855760e39c786ed32a633aa4757dfee8b5e3e918 Mon Sep 17 00:00:00 2001 From: mARTin Date: Wed, 18 Mar 2026 00:10:38 +0100 Subject: [PATCH] feat: kanban drag fix, project targets, calendar/simple view polish - Fix kanban drag: remove confusing card tilt, ensure dragOver always calls preventDefault so drops work reliably across all browsers - Add project drop targets bar in kanban: drag tasks onto project chips to assign/unassign projects - Add "Create Project" button to kanban filter bar - Right-align kanban filter bar - Use ProjectIcon (FontAwesome) in kanban cards instead of raw emoji - Calendar view: Google Calendar-inspired styling (subtle grid lines, smaller time labels, cleaner borders) - Simple view: TeuxDeux-inspired styling (uppercase headers, thick bottom border, flat borderless task items, minimal aesthetic) v1.47.0 Co-Authored-By: Claude Opus 4.6 --- package.json | 2 +- src/app/globals.css | 117 ++++++++++++++++++++++++++++++++-- src/components/WeeklyView.tsx | 63 ++++++++++++++---- 3 files changed, 163 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index b4fcebf..4dc9b87 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "my-weekly-todo-list", - "version": "1.46.0", + "version": "1.47.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 e84caf8..673cb2e 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1718,6 +1718,7 @@ h3 { background: var(--weekly-bg, #fff); flex-shrink: 0; flex-wrap: wrap; + justify-content: flex-end; } .kanban-filter-search { @@ -1865,7 +1866,8 @@ h3 { .kanban-card:active { cursor: grabbing; - transform: rotate(2deg); + opacity: 0.8; + box-shadow: 0 4px 12px rgba(0,0,0,0.15); } .kanban-card-done { @@ -3782,31 +3784,132 @@ h3 { border-right: none !important; } -/* Calendar View (Google Calendar Style - vertical lines) */ +/* Calendar View (Google Calendar Style) */ .calendar-view.time-grid-on .weekly-day-column { - border-right: 1px solid #e0e0e0; + border-right: 1px solid #dadce0; margin: 0 !important; } +.calendar-view .time-column { + border-right: 1px solid #dadce0; +} +.calendar-view .time-column-header { + border-bottom: 1px solid #dadce0; +} +.calendar-view .time-slot { + border-bottom: 1px solid #f1f3f4; +} +.calendar-view .time-slot:nth-child(even) { + border-bottom: 1px solid #dadce0; +} +.calendar-view .time-slot-label { + color: #70757a; + font-size: 0.65rem; + font-weight: 400; +} +.calendar-view .weekly-day-header { + border-bottom: 1px solid #dadce0; + font-weight: 500; +} +.calendar-view .time-slot-event { + border-radius: 4px; + border-left: none; + font-size: 0.8rem; +} .dark-mode .calendar-view.time-grid-on .weekly-day-column { border-right: 1px solid #333; } +.dark-mode .calendar-view .time-column { + border-right: 1px solid #333; +} +.dark-mode .calendar-view .time-slot { + border-bottom: 1px solid #2a2a2a; +} +.dark-mode .calendar-view .time-slot:nth-child(even) { + border-bottom: 1px solid #333; +} +.dark-mode .calendar-view .time-slot-label { + color: #9aa0a6; +} +.dark-mode .calendar-view .weekly-day-header { + border-bottom: 1px solid #333; +} -/* Simple View (Original Style with Spacing) */ +/* Simple View (TeuxDeux Style) */ .simple-view .weekly-day-column { border-left: 0px !important; - margin: 0 10px !important; + border-right: 1px solid #e8e8e8 !important; + margin: 0 !important; overflow-x: hidden !important; word-wrap: break-word; } - +.simple-view .weekly-day-column:last-child { + border-right: none !important; +} .simple-view .time-column { border-right: 0px !important; + display: none !important; } - .simple-view .time-slot-event { left: 0 !important; right: 0 !important; } +.simple-view .weekly-day-header { + text-transform: uppercase; + letter-spacing: 0.05em; + font-weight: 700; + font-size: 0.75rem; + padding: 12px 8px 8px; + border-bottom: 2px solid #222; +} +.dark-mode .simple-view .weekly-day-header { + border-bottom: 2px solid #666; +} +.dark-mode .simple-view .weekly-day-column { + border-right: 1px solid #333 !important; +} +.simple-view .task-item { + border: none !important; + border-bottom: 1px solid #eee !important; + border-radius: 0 !important; + padding: 8px 4px !important; + background: transparent !important; + box-shadow: none !important; +} +.dark-mode .simple-view .task-item { + border-bottom: 1px solid #333 !important; +} +.simple-view .task-item:hover { + background: rgba(0,0,0,0.02) !important; +} +.dark-mode .simple-view .task-item:hover { + background: rgba(255,255,255,0.03) !important; +} + +/* Kanban project drop targets */ +.kanban-project-targets { + display: flex; + gap: 6px; + padding: 8px 12px; + border-bottom: 1px solid var(--weekly-border, #e5e7eb); + background: var(--weekly-bg-alt, #f8f9fa); + flex-wrap: wrap; + flex-shrink: 0; +} +.kanban-project-chip { + display: flex; + align-items: center; + gap: 4px; + padding: 4px 10px; + border-radius: 16px; + font-size: 0.75rem; + border: 2px solid transparent; + cursor: default; + transition: border-color 0.15s, box-shadow 0.15s; +} +.kanban-project-chip-drag-over { + border-color: var(--weekly-accent, #6366f1); + box-shadow: 0 0 0 2px rgba(99,102,241,0.2); +} diff --git a/src/components/WeeklyView.tsx b/src/components/WeeklyView.tsx index 272e1cd..388b45f 100644 --- a/src/components/WeeklyView.tsx +++ b/src/components/WeeklyView.tsx @@ -5543,8 +5543,8 @@ export default function WeeklyView() {
{[ - { key: "simple", icon: }, - { key: "calendar", icon: }, + { key: "simple", icon: }, + { key: "calendar", icon: }, { key: "list", icon: }, { key: "kanban", icon: }, ].map((v) => ( @@ -5830,14 +5830,14 @@ export default function WeeklyView() { className={`p-1.5 rounded transition-colors ${viewStyle === "simple" ? "bg-white shadow-sm text-black dark:bg-gray-700 dark:text-white" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`} title={t.simpleView} > - + )} +
+ {/* Project drop targets — drag tasks here to assign */} + {projects.length > 0 && ( +
+ {projects.map(p => ( +
+ + {p.name} +
+ ))} +
+ + {language === "de" ? "Kein Projekt" : "No project"} +
+
+ )}
{kanbanStages.map((stage) => { const stageTasks = filteredKanbanTasks.filter(t => (t.kanbanStage || null) === stage.id);