Refactor: Rearrange header, streamline settings, fix task hover icons, and overhaul recurring task manager

This commit is contained in:
mARTin 2026-02-13 20:12:31 +01:00
parent 0e854b6e9b
commit a834b440a5
3 changed files with 174 additions and 222 deletions

View File

@ -790,18 +790,20 @@ h3 {
background: none; background: none;
border: none; border: none;
cursor: pointer; cursor: pointer;
padding: 4px; padding: 2px;
width: 20px;
height: 20px;
color: var(--weekly-text-light); color: var(--weekly-text-light);
border-radius: 4px; border-radius: 4px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
transition: color 0.15s; transition: all 0.15s;
} }
.task-action-btn:hover { .task-action-btn:hover {
color: var(--weekly-text); color: var(--weekly-text);
background: rgba(0,0,0,0.05); background: rgba(0,0,0,0.08);
} }
/* Specific button styles */ /* Specific button styles */

View File

@ -1,96 +1,107 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react'; import React from 'react';
import { Repeat, X, Trash2 } from 'lucide-react';
interface RecurringTasksManagerProps { interface RecurringTasksManagerProps {
isOpen: boolean; isOpen: boolean;
onClose: () => void; onClose: () => void;
tasks: any[]; tasks: any[];
onStopRecurring: (task: any) => void;
} }
export default function RecurringTasksManager({ isOpen, onClose, tasks }: RecurringTasksManagerProps) { export default function RecurringTasksManager({ isOpen, onClose, tasks, onStopRecurring }: RecurringTasksManagerProps) {
if (!isOpen) return null; if (!isOpen) return null;
// Filter tasks that are recurring // Filter and group recurring tasks by series signature
const recurringTasks = tasks.filter(t => t.isRecurring); // We use title + recurrence settings as the identity of a "series"
const seriesGroups = new Map<string, any>();
tasks.filter(t => t.isRecurring).forEach(t => {
// Only include those that aren't already ended
if (t.recurrenceEndDate && new Date(t.recurrenceEndDate) < new Date()) {
return;
}
const signature = `${t.title}-${t.recurrenceInterval || 1}-${t.recurrenceUnit || 'weeks'}-${t.recurrenceTime || ''}`;
// Keep the latest instance to represent the series
const existing = seriesGroups.get(signature);
if (!existing || (t.scheduledDate && new Date(t.scheduledDate) > new Date(existing.scheduledDate || 0))) {
seriesGroups.set(signature, t);
}
});
const groupedTasks = Array.from(seriesGroups.values());
return ( return (
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4" onClick={onClose}> <div className="fixed inset-0 bg-black/50 z-[3000] flex items-center justify-center p-4 animate-fadeIn" onClick={onClose}>
<div className="bg-white rounded-lg shadow-2xl w-[800px] max-w-full h-[600px] flex flex-col" onClick={e => e.stopPropagation()}> <div className="bg-white dark:bg-gray-900 rounded-xl shadow-2xl w-[600px] max-w-full overflow-hidden flex flex-col animate-scaleIn" onClick={e => e.stopPropagation()}>
<div className="p-6 flex items-center justify-between border-b border-gray-100"> <div className="p-5 flex items-center justify-between border-b border-gray-100 dark:border-gray-800">
<h2 className="text-xl font-bold text-gray-800">Recurring to-dos</h2> <div className="flex items-center gap-3">
<button onClick={onClose} className="text-gray-400 hover:text-gray-600 font-bold text-xl"> <div className="p-2 bg-teal-100 dark:bg-teal-900/30 rounded-lg text-teal-600">
&times; <Repeat size={20} />
</div>
<h2 className="text-lg font-bold text-gray-800 dark:text-white">Wiederkehrende Aufgaben</h2>
</div>
<button onClick={onClose} className="p-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-full text-gray-400 transition-colors">
<X size={20} />
</button> </button>
</div> </div>
<div className="flex-1 overflow-y-auto p-8"> <div className="flex-1 overflow-y-auto p-6">
{recurringTasks.length === 0 ? ( {groupedTasks.length === 0 ? (
<div className="flex flex-col items-start max-w-lg"> <div className="flex flex-col items-center justify-center py-12 text-center">
<p className="text-gray-600 mb-6"> <div className="w-16 h-16 bg-gray-50 dark:bg-gray-800 rounded-full flex items-center justify-center text-gray-300 mb-4">
You don&apos;t have any recurring to-dos yet. <Repeat size={32} />
</div>
<p className="text-gray-500 dark:text-gray-400 max-w-xs">
Du hast momentan keine aktiven wiederkehrenden Aufgaben.
</p> </p>
<button className="bg-[#333] text-white px-4 py-2 rounded text-sm font-medium flex items-center gap-2 hover:bg-black transition-colors mb-8">
<span>+</span> Recurring to-do
</button>
<p className="text-gray-800 font-medium mb-4">Or, type a frequency to the end of a to-do.</p>
<div className="bg-gray-100 p-8 rounded mb-8 w-full flex items-center justify-center">
<div className="bg-white p-6 shadow-sm rounded text-center w-64">
<div className="text-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1">OCT 5, 2023</div>
<div className="text-xl font-bold text-gray-900 uppercase tracking-wider mb-4">THURSDAY</div>
<div className="h-6 w-1 bg-black animate-pulse mx-auto"></div>
</div>
</div>
<div className="grid grid-cols-2 gap-8 text-sm w-full">
<div>
<h4 className="italic text-gray-500 mb-2">Frequencies:</h4>
<ul className="text-gray-500 italic space-y-1">
<li>every day</li>
<li>every week</li>
<li>every other week</li>
<li>every month</li>
<li>every year</li>
</ul>
</div>
<div>
<h4 className="italic text-gray-500 mb-2">Examples:</h4>
<ul className="text-gray-500 italic space-y-1">
<li>Brush teeth every day</li>
<li>Management meeting every week</li>
<li>Piano lessons every other week</li>
<li>Pay rent every month</li>
<li>Garret&apos;s birthday every year</li>
</ul>
</div>
</div>
</div> </div>
) : ( ) : (
<div className="space-y-4"> <div className="space-y-3">
{recurringTasks.map(task => ( {groupedTasks.map(task => (
<div key={task.id} className="flex items-center justify-between p-4 bg-gray-50 rounded border border-gray-100"> <div key={task.id} className="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-800/50 rounded-xl border border-gray-100 dark:border-gray-700/50 hover:border-teal-200 dark:hover:border-teal-900/50 transition-all">
<div> <div className="flex-1 min-w-0 pr-4">
<div className="font-medium text-gray-900">{task.title}</div> <div className="font-semibold text-gray-900 dark:text-white truncate" title={task.title}>
<div className="text-xs text-gray-500 mt-1"> {task.title}
Repeats every {task.recurrenceInterval} {task.recurrenceUnit} </div>
<div className="flex items-center gap-2 mt-1">
<span className="text-xs px-2 py-0.5 bg-teal-50 dark:bg-teal-900/20 text-teal-600 dark:text-teal-400 rounded-md font-medium capitalize">
Alle {task.recurrenceInterval === 1 ? '' : task.recurrenceInterval} {
task.recurrenceUnit === 'days' ? 'Tage' :
task.recurrenceUnit === 'weeks' ? 'Wochen' :
task.recurrenceUnit === 'months' ? 'Monate' : 'Jahre'
}
</span>
{task.recurrenceTime && (
<span className="text-[10px] text-gray-400">
um {task.recurrenceTime} Uhr
</span>
)}
</div> </div>
</div> </div>
<button className="text-red-500 text-sm hover:underline">Stop Details</button> <button
onClick={() => {
if (confirm(`Serie "${task.title}" wirklich beenden?`)) {
onStopRecurring(task);
}
}}
className="flex items-center gap-2 px-3 py-2 bg-red-50 hover:bg-red-100 dark:bg-red-900/10 dark:hover:bg-red-900/20 text-red-600 dark:text-red-400 rounded-lg text-xs font-bold transition-colors group"
>
<Trash2 size={14} className="group-hover:scale-110 transition-transform" />
Serie beenden
</button>
</div> </div>
))} ))}
</div> </div>
)} )}
</div> </div>
<div className="p-4 border-t border-gray-100 flex justify-end"> <div className="p-3 bg-gray-50 dark:bg-gray-900 border-t border-gray-100 dark:border-gray-800 flex justify-center">
<button <p className="text-[10px] text-gray-400 font-medium">
onClick={onClose} Tipp: Du kannst Aufgaben jederzeit beim Bearbeiten wiederkehrend machen.
className="w-10 h-10 bg-[#333] rounded-full flex items-center justify-center text-white hover:bg-black transition-colors text-xl font-bold" </p>
>
+
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -323,7 +323,6 @@ export default function WeeklyView() {
const [somedayLists, setSomedayLists] = useState<SomedayList[]>([]); const [somedayLists, setSomedayLists] = useState<SomedayList[]>([]);
const [editingTaskId, setEditingTaskId] = useState<string | null>(null); const [editingTaskId, setEditingTaskId] = useState<string | null>(null);
const [showSettings, setShowSettings] = useState(false); const [showSettings, setShowSettings] = useState(false);
const [showPreferences, setShowPreferences] = useState(false);
const [showDatePicker, setShowDatePicker] = useState(false); const [showDatePicker, setShowDatePicker] = useState(false);
const [isAddingSomedayList, setIsAddingSomedayList] = useState(false); const [isAddingSomedayList, setIsAddingSomedayList] = useState(false);
const [newSomedayListName, setNewSomedayListName] = useState(''); const [newSomedayListName, setNewSomedayListName] = useState('');
@ -1522,16 +1521,32 @@ export default function WeeklyView() {
{/* Refactored Header: Left, Center, Right */} {/* Refactored Header: Left, Center, Right */}
<header className="flex items-center justify-between w-full px-4 py-2 border-b border-gray-200 bg-white dark:bg-gray-900 dark:border-gray-700 dark:text-white transition-colors duration-200"> <header className="flex items-center justify-between w-full px-4 py-2 border-b border-gray-200 bg-white dark:bg-gray-900 dark:border-gray-700 dark:text-white transition-colors duration-200">
{/* LEFT SECTION: Days to Show & Time Range */} {/* LEFT SECTION: Slot Duration & Days to Show */}
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
{/* Slot Duration */}
{showTimeGrid && (
<div className="flex items-center gap-1 bg-gray-100 dark:bg-gray-800 rounded p-1" title="Slot Duration">
<Clock size={16} className="text-gray-500 mr-1" />
{[15, 30, 60].map(duration => (
<button
key={duration}
onClick={() => setCellDuration(duration as CellDuration)}
className={`px-2 py-0.5 text-xs rounded transition-colors ${cellDuration === duration ? 'bg-white shadow-sm font-bold text-black' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700'}`}
>
{duration}m
</button>
))}
</div>
)}
{/* Days to Show */} {/* Days to Show */}
<div className="flex items-center gap-1 bg-gray-100 rounded p-1" title="Days to show"> <div className="flex items-center gap-1 bg-gray-100 dark:bg-gray-800 rounded p-1" title="Days to show">
<LayoutGrid size={16} className="text-gray-500 mr-1" /> <LayoutGrid size={16} className="text-gray-500 mr-1" />
{[1, 3, 5, 7].map(num => ( {[1, 3, 5, 7].map(num => (
<button <button
key={num} key={num}
onClick={() => setViewDays(num)} onClick={() => setViewDays(num)}
className={`px-2 py-0.5 text-xs rounded transition-colors ${viewDays === num ? 'bg-white shadow-sm font-bold text-black' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-200'}`} className={`px-2 py-0.5 text-xs rounded transition-colors ${viewDays === num ? 'bg-white shadow-sm font-bold text-black' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700'}`}
> >
{num} {num}
</button> </button>
@ -1540,7 +1555,7 @@ export default function WeeklyView() {
{/* Time Range */} {/* Time Range */}
{showTimeGrid && ( {showTimeGrid && (
<div className="flex items-center gap-2 text-xs text-gray-500 bg-gray-100 rounded p-1 px-2" title="Visible Hours"> <div className="flex items-center gap-2 text-xs text-gray-500 bg-gray-100 dark:bg-gray-800 rounded p-1 px-2" title="Visible Hours">
<Clock size={16} className="text-gray-500" /> <Clock size={16} className="text-gray-500" />
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<input <input
@ -1549,7 +1564,7 @@ export default function WeeklyView() {
max={endHour - 1} max={endHour - 1}
value={startHour} value={startHour}
onChange={(e) => setStartHour(Math.max(0, Math.min(parseInt(e.target.value) || 0, endHour - 1)))} onChange={(e) => setStartHour(Math.max(0, Math.min(parseInt(e.target.value) || 0, endHour - 1)))}
className="w-12 p-0.5 border border-gray-200 rounded text-center bg-transparent focus:outline-none focus:border-teal-500" className="w-10 p-0.5 border border-gray-200 dark:border-gray-700 rounded text-center bg-transparent focus:outline-none focus:border-teal-500"
/> />
<span>-</span> <span>-</span>
<input <input
@ -1558,20 +1573,33 @@ export default function WeeklyView() {
max="24" max="24"
value={endHour} value={endHour}
onChange={(e) => setEndHour(Math.max(startHour + 1, Math.min(parseInt(e.target.value) || 24, 24)))} onChange={(e) => setEndHour(Math.max(startHour + 1, Math.min(parseInt(e.target.value) || 24, 24)))}
className="w-12 p-0.5 border border-gray-200 rounded text-center bg-transparent focus:outline-none focus:border-teal-500" className="w-10 p-0.5 border border-gray-200 dark:border-gray-700 rounded text-center bg-transparent focus:outline-none focus:border-teal-500"
/> />
</div> </div>
</div> </div>
)} )}
{/* Day/Night Mode Switch */} {/* View Style Toggles */}
<div className="flex items-center gap-1 bg-gray-100 dark:bg-gray-800 rounded p-1" title="View Style">
<button <button
onClick={() => setDarkMode(!darkMode)} onClick={() => setShowTimeGrid(!showTimeGrid)}
className="p-1.5 rounded-md hover:bg-gray-100 transition-colors" className={`px-2 py-0.5 text-xs rounded transition-colors ${showTimeGrid ? 'bg-white shadow-sm font-bold text-black' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700'}`}
title={darkMode ? "Switch to Light Mode" : "Switch to Dark Mode"}
> >
{darkMode ? <Sun size={18} className="text-yellow-500" /> : <Moon size={18} className="text-gray-500" />} Time Grid
</button> </button>
<button
onClick={() => setViewStyle('grid')}
className={`px-2 py-0.5 text-xs rounded transition-colors ${!showTimeGrid && viewStyle === 'grid' ? 'bg-white shadow-sm font-bold text-black' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700'}`}
>
Grid
</button>
<button
onClick={() => setViewStyle('list')}
className={`px-2 py-0.5 text-xs rounded transition-colors ${!showTimeGrid && viewStyle === 'list' ? 'bg-white shadow-sm font-bold text-black' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700'}`}
>
List
</button>
</div>
</div> </div>
{/* CENTER SECTION: Week/Year, Motto, Focus Mode */} {/* CENTER SECTION: Week/Year, Motto, Focus Mode */}
@ -1638,27 +1666,14 @@ export default function WeeklyView() {
{/* RIGHT SECTION: Navigation & Tools */} {/* RIGHT SECTION: Navigation & Tools */}
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
{/* Date Picker Toggle */} {/* Day/Night Mode Switch */}
<div className="relative">
<button <button
className={`p-1.5 hover:bg-gray-100 rounded-md transition-colors ${showDatePicker ? 'text-teal-600 bg-teal-50' : 'text-gray-500 hover:text-black'}`} onClick={() => setDarkMode(!darkMode)}
onClick={() => setShowDatePicker(!showDatePicker)} className="p-1.5 rounded-md hover:bg-gray-100 transition-colors"
title="Jump to date" title={darkMode ? "Switch to Light Mode" : "Switch to Dark Mode"}
> >
<Calendar size={18} /> {darkMode ? <Sun size={18} className="text-yellow-500" /> : <Moon size={18} className="text-gray-500" />}
</button> </button>
{showDatePicker && (
<SimpleDatePicker
selected={currentWeekStart}
onSelect={(date) => {
setCurrentWeekStart(getStartOfWeek(date, weekStartDay));
setShowDatePicker(false);
}}
onClose={() => setShowDatePicker(false)}
language={language}
/>
)}
</div>
{/* Navigation Controls */} {/* Navigation Controls */}
<div className="flex items-center bg-gray-100 rounded-lg p-0.5"> <div className="flex items-center bg-gray-100 rounded-lg p-0.5">
@ -1672,16 +1687,13 @@ export default function WeeklyView() {
Today Today
</button> </button>
<button className="p-1 hover:bg-white hover:shadow-sm rounded text-gray-500 hover:text-black transition-all" onClick={goToNextDay} title="Next Day"> <button className="p-1 hover:bg-white hover:shadow-sm rounded text-gray-500 hover:text-black transition-all" onClick={goToNextDay} title="Next Day">
<ChevronRight size={16} /> <ChevronLeft size={16} className="rotate-180" />
</button> </button>
<button className="p-1 hover:bg-white hover:shadow-sm rounded text-gray-500 hover:text-black transition-all" onClick={goToNextWeek} title="Next Week"> <button className="p-1 hover:bg-white hover:shadow-sm rounded text-gray-500 hover:text-black transition-all" onClick={goToNextWeek} title="Next Week">
<ChevronsRight size={16} /> <ChevronsLeft size={16} className="rotate-180" />
</button> </button>
</div> </div>
{/* Divider */}
<div className="h-4 w-px bg-gray-300 mx-1"></div>
{/* Search */} {/* Search */}
<button <button
className="p-1.5 hover:bg-gray-100 rounded-md text-gray-500 hover:text-black transition-colors" className="p-1.5 hover:bg-gray-100 rounded-md text-gray-500 hover:text-black transition-colors"
@ -1700,13 +1712,9 @@ export default function WeeklyView() {
<Repeat size={18} /> <Repeat size={18} />
</button> </button>
{/* Settings - Actually triggers User Menu in original code? No, settings was separate. */}
{/* Original code had UserMenu handling settings. And a separate sync indicator. */}
{/* The prompt asked for: Search | Settings | User Menu */}
<button <button
className="p-1.5 hover:bg-gray-100 rounded-md text-gray-500 hover:text-black transition-colors" className="p-1.5 hover:bg-gray-100 rounded-md text-gray-500 hover:text-black transition-colors"
onClick={() => setShowPreferences(true)} onClick={() => setShowSettings(true)}
title="Settings" title="Settings"
> >
<Settings size={18} /> <Settings size={18} />
@ -1715,7 +1723,7 @@ export default function WeeklyView() {
{/* User Menu */} {/* User Menu */}
<UserMenu <UserMenu
userEmail={session?.user?.email} userEmail={session?.user?.email}
onOpenSettings={() => setShowPreferences(true)} onOpenSettings={() => setShowSettings(true)}
trigger={ trigger={
<button className="p-1.5 hover:bg-gray-100 rounded-md text-gray-500 hover:text-black transition-colors" title="User Menu"> <button className="p-1.5 hover:bg-gray-100 rounded-md text-gray-500 hover:text-black transition-colors" title="User Menu">
<User size={18} /> <User size={18} />
@ -2533,7 +2541,38 @@ export default function WeeklyView() {
<RecurringTasksManager <RecurringTasksManager
isOpen={isRecurringTasksOpen} isOpen={isRecurringTasksOpen}
onClose={() => setIsRecurringTasksOpen(false)} onClose={() => setIsRecurringTasksOpen(false)}
tasks={tasks} // Pass tasks to manager tasks={tasks}
onStopRecurring={async (task) => {
const idToUpdate = task.id.startsWith('virtual-') ? task.id.split('-')[1] : task.id;
const dateStr = new Date().toISOString();
// Update locally
setTasks(prev => prev.map(t => {
const isMatch = t.title === task.title &&
t.userId === task.userId &&
t.recurrenceInterval === task.recurrenceInterval &&
t.recurrenceUnit === task.recurrenceUnit;
if (isMatch) {
return { ...t, recurrenceEndDate: new Date(dateStr) };
}
return t;
}));
// Update DB
try {
await fetch('/api/tasks', {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: idToUpdate,
recurrenceEndDate: dateStr
})
});
fetchTasks();
} catch (error) {
console.error('Failed to stop recurring series:', error);
}
}}
/> />
{/* Recurrence Modal */} {/* Recurrence Modal */}
{ {
@ -2660,106 +2699,6 @@ export default function WeeklyView() {
) )
} }
{/* Preferences Slide-in Panel */}
<div className={`preferences-panel ${showPreferences ? 'open' : ''}`}>
<div className="preferences-panel-content">
<h3 style={{ fontSize: '1.2rem', fontWeight: 400, marginBottom: '1.5rem', color: '#fff' }}>Preferences</h3>
{/* Columns (View Days) */}
<div className="pref-row">
<span className="pref-label">Columns</span>
<div className="pref-options">
{[1, 3, 5, 7].map(n => (
<button key={n} className={`pref-option-btn ${viewDays === n ? 'active' : ''}`}
onClick={() => setViewDays(n as any)}>{n}</button>
))}
</div>
</div>
{/* Show Time Grid */}
<div className="pref-row">
<span className="pref-label">Time grid</span>
<div className="pref-options">
<button className={`pref-toggle ${showTimeGrid ? 'active' : ''}`}
onClick={() => setShowTimeGrid(!showTimeGrid)}>
{showTimeGrid ? '◉' : '○'}
</button>
</div>
</div>
{showTimeGrid && (
<div className="pref-row">
<span className="pref-label">Slot duration</span>
<div className="pref-options">
{[15, 30, 60].map(n => (
<button key={n} className={`pref-option-btn ${cellDuration === n ? 'active' : ''}`}
onClick={() => setCellDuration(n as CellDuration)}>{n}m</button>
))}
</div>
</div>
)}
{/* View Style */}
<div className="pref-row">
<span className="pref-label">View style</span>
<div className="pref-options">
<button className={`pref-option-btn ${viewStyle === 'grid' ? 'active' : ''}`}
onClick={() => setViewStyle('grid')}>Grid</button>
<button className={`pref-option-btn ${viewStyle === 'list' ? 'active' : ''}`}
onClick={() => setViewStyle('list')}>List</button>
</div>
</div>
{/* Show Someday */}
<div className="pref-row">
<span className="pref-label">Someday</span>
<div className="pref-options">
<button className={`pref-toggle ${showSomeday ? 'active' : ''}`}
onClick={() => setShowSomeday(!showSomeday)}>
{showSomeday ? '◉' : '○'}
</button>
</div>
</div>
{/* Show All Day */}
<div className="pref-row">
<span className="pref-label">All-day events</span>
<div className="pref-options">
<button className={`pref-toggle ${showAllDay ? 'active' : ''}`}
onClick={() => setShowAllDay(!showAllDay)}>
{showAllDay ? '◉' : '○'}
</button>
</div>
</div>
{/* Lines */}
<div className="pref-row">
<span className="pref-label">Protect events</span>
<div className="pref-options">
<button className={`pref-toggle ${protectEventTimes ? 'active' : ''}`}
onClick={() => setProtectEventTimes(!protectEventTimes)}>
{protectEventTimes ? '◉' : '○'}
</button>
</div>
</div>
<div style={{ borderTop: '1px solid rgba(255,255,255,0.1)', margin: '1rem 0' }} />
{/* Full Settings Link */}
<button
className="pref-full-settings-btn"
onClick={() => { setShowPreferences(false); setShowSettings(true); }}
>
Full Settings
</button>
</div>
{/* Close chevron */}
<button className="preferences-close-btn" onClick={() => setShowPreferences(false)}>
</button>
</div>
{showPreferences && <div className="preferences-overlay" onClick={() => setShowPreferences(false)} />}
{ {
selectedTaskForNotes && ( selectedTaskForNotes && (
@ -3090,7 +3029,7 @@ function TaskItem({ task, isEditing, onToggle, onEdit, onUpdate, onDelete, onNot
> >
{/* Edit */} {/* Edit */}
<button className="task-action-btn" onClick={(e) => { e.stopPropagation(); onEdit(); }} title="Edit"> <button className="task-action-btn" onClick={(e) => { e.stopPropagation(); onEdit(); }} title="Edit">
<svg viewBox="0 0 24 24" width={variant === 'minimal' ? "14" : "16"} height={variant === 'minimal' ? "14" : "16"} stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg> <svg viewBox="0 0 24 24" width="12" height="12" stroke="currentColor" strokeWidth="2.5" fill="none" strokeLinecap="round" strokeLinejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>
</button> </button>
{/* Recurrence */} {/* Recurrence */}
@ -3099,7 +3038,7 @@ function TaskItem({ task, isEditing, onToggle, onEdit, onUpdate, onDelete, onNot
onClick={(e) => { e.stopPropagation(); onRecurrence(); }} onClick={(e) => { e.stopPropagation(); onRecurrence(); }}
title={task.isRecurring ? "Edit recurrence" : "Make recurring"} title={task.isRecurring ? "Edit recurrence" : "Make recurring"}
> >
<svg viewBox="0 0 24 24" width={variant === 'minimal' ? "14" : "16"} height={variant === 'minimal' ? "14" : "16"} stroke="currentColor" strokeWidth="2" 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">
<polyline points="23 4 23 10 17 10"></polyline> <polyline points="23 4 23 10 17 10"></polyline>
<path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path> <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
</svg> </svg>
@ -3111,7 +3050,7 @@ function TaskItem({ task, isEditing, onToggle, onEdit, onUpdate, onDelete, onNot
onClick={(e) => { e.stopPropagation(); setIsNotesOpen(!isNotesOpen); }} onClick={(e) => { e.stopPropagation(); setIsNotesOpen(!isNotesOpen); }}
title="Notes" title="Notes"
> >
<svg viewBox="0 0 24 24" width={variant === 'minimal' ? "14" : "16"} height={variant === 'minimal' ? "14" : "16"} stroke="currentColor" strokeWidth="2" 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="3" y1="12" x2="21" y2="12"></line> <line x1="3" y1="12" x2="21" y2="12"></line>
<line x1="3" y1="6" x2="21" y2="6"></line> <line x1="3" y1="6" x2="21" y2="6"></line>
<line x1="3" y1="18" x2="21" y2="18"></line> <line x1="3" y1="18" x2="21" y2="18"></line>
@ -3125,7 +3064,7 @@ function TaskItem({ task, isEditing, onToggle, onEdit, onUpdate, onDelete, onNot
onClick={(e) => { e.stopPropagation(); onRollToggle(); }} onClick={(e) => { e.stopPropagation(); onRollToggle(); }}
title={task.isRolling ? "Disable rolling" : "Enable rolling"} title={task.isRolling ? "Disable rolling" : "Enable rolling"}
> >
<svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" strokeWidth="2" 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">
<polyline points="1 4 1 10 7 10"></polyline> <polyline points="1 4 1 10 7 10"></polyline>
<path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"></path> <path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"></path>
</svg> </svg>
@ -3134,7 +3073,7 @@ function TaskItem({ task, isEditing, onToggle, onEdit, onUpdate, onDelete, onNot
{/* Delete */} {/* Delete */}
<button className="task-action-btn delete" onClick={(e) => { e.stopPropagation(); onDelete(); }} title="Delete"> <button className="task-action-btn delete" onClick={(e) => { e.stopPropagation(); onDelete(); }} title="Delete">
<svg viewBox="0 0 24 24" width={variant === 'minimal' ? "14" : "16"} height={variant === 'minimal' ? "14" : "16"} stroke="currentColor" strokeWidth="2" 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="5" y1="12" x2="19" y2="12"></line> <line x1="5" y1="12" x2="19" y2="12"></line>
</svg> </svg>
</button> </button>