feat: add SKIP button to Focus Mode

Focus Mode now shows a SKIP button that moves to the next task of the day
without completing the current one. Skipped task ids are tracked in
WeeklyView and filtered out of the focus queue, so completing a task still
picks the correct next one; the list is cleared when Focus Mode closes.
The timer resets on each new task, and the button is disabled when no other
task is left for today.

Also drops the standalone "Element Colors" and "Weekend Colors" sections from
Styling settings (those controls live in the CSS Variables panel since
1.113.1) and enlarges the CSS variable swatches.

v1.114.0

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mARTin-B78 2026-09-01 17:37:17 +02:00
parent 9ce5664621
commit 7e3e30ec83
6 changed files with 66 additions and 182 deletions

View File

@ -2,6 +2,19 @@
All notable changes to this project are documented in this file.
## [1.114.0] - 2026-09-01
### Added
- Focus Mode: "SKIP" button to move on to the next task of the day without completing the
current one. Skipped tasks are remembered until Focus Mode is closed, and the timer
resets for each new task. The button is disabled when no other task is left for today.
### Changed
- Styling settings: removed the standalone "Element Colors" and "Weekend Colors" sections —
those controls now live only in the CSS Variables panel (added there in 1.113.1).
- Styling settings: larger, borderless color swatches and bigger labels in the CSS Variables
panel.
## [1.113.1] - 2026-07-08
### Changed

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "my-weekly-todo-list",
"version": "1.104.1",
"version": "1.114.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "my-weekly-todo-list",
"version": "1.104.1",
"version": "1.114.0",
"license": "MIT",
"dependencies": {
"@auth/prisma-adapter": "^2.11.1",

View File

@ -1,6 +1,6 @@
{
"name": "my-weekly-todo-list",
"version": "1.113.1",
"version": "1.114.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": {

View File

@ -11,9 +11,11 @@ interface FocusModeOverlayProps {
duration: number; // in minutes
onClose: () => void;
onComplete: (taskId: string) => void;
onSkip?: (taskId: string) => void;
hasNext?: boolean;
}
export default function FocusModeOverlay({ task, duration, onClose, onComplete }: FocusModeOverlayProps) {
export default function FocusModeOverlay({ task, duration, onClose, onComplete, onSkip, hasNext }: FocusModeOverlayProps) {
const [timeLeft, setTimeLeft] = useState(duration * 60);
const [isActive, setIsActive] = useState(false);
const [isCompleting, setIsCompleting] = useState(false);
@ -51,6 +53,12 @@ export default function FocusModeOverlay({ task, duration, onClose, onComplete }
setTimeLeft(duration * 60);
};
const handleSkip = () => {
if (!task || !onSkip) return;
onSkip(task.id);
handleReset(); // Fresh timer for the next task
};
const handleComplete = async () => {
if (!task) return;
setIsCompleting(true);
@ -127,6 +135,16 @@ export default function FocusModeOverlay({ task, duration, onClose, onComplete }
<button className="focus-btn secondary" onClick={handleReset}>
RESET
</button>
{task && onSkip && (
<button
className="focus-btn secondary"
onClick={handleSkip}
disabled={!hasNext || isCompleting}
title={hasNext ? 'Skip to the next task' : 'No other task left today'}
>
SKIP
</button>
)}
{task && (
<button className="focus-btn success" onClick={handleComplete} disabled={isCompleting}>
{isCompleting ? 'COMPLETING...' : 'COMPLETE TASK'}
@ -249,6 +267,13 @@ export default function FocusModeOverlay({ task, duration, onClose, onComplete }
.focus-btn.secondary:hover {
border-color: white;
}
.focus-btn:disabled {
opacity: 0.4;
cursor: not-allowed;
}
.focus-btn:disabled:hover {
transform: none;
}
.focus-btn.success {
background: #009a9a; /* Weekly Teal */
color: white;

View File

@ -358,9 +358,9 @@ function CssVariablesEditor({
onChange={onChange}
style={{
width: "32px",
height: "22px",
height: "32px",
cursor: "pointer",
border: "1px solid var(--weekly-settings-input-border)",
border: "none",
borderRadius: "4px",
background: "transparent",
flexShrink: 0,
@ -368,7 +368,7 @@ function CssVariablesEditor({
/>
<span
style={{
fontSize: "0.72rem",
fontSize: "0.85rem",
color: "var(--weekly-settings-label)",
overflow: "hidden",
textOverflow: "ellipsis",
@ -3790,171 +3790,7 @@ function SettingsSidebar({
</div>
</div>
{/* Element Colors */}
<div
style={{
background: "var(--weekly-settings-item-bg)",
padding: "12px",
borderRadius: "8px",
marginBottom: "12px",
}}
>
<label
style={{
display: "block",
fontSize: "0.85rem",
fontWeight: 600,
color: "var(--weekly-settings-label)",
marginBottom: "8px",
}}
>
Element Colors
</label>
<div
style={{
display: "grid",
gridTemplateColumns: "1fr 1fr",
gap: "12px",
}}
>
<div>
<label
style={{
display: "block",
fontSize: "0.75rem",
color: "var(--weekly-settings-label)",
marginBottom: "4px",
}}
>
Today Highlight
</label>
<input
type="color"
value={profile.todayHighlightColor || "#f0fafa"}
onChange={(e) =>
saveFieldDebounced("todayHighlightColor", e.target.value)
}
style={{
width: "100%",
height: "30px",
cursor: "pointer",
border: "none",
background: "transparent",
}}
/>
</div>
<div>
<label
style={{
display: "block",
fontSize: "0.75rem",
color: "var(--weekly-settings-label)",
marginBottom: "4px",
}}
>
Past Days
</label>
<input
type="color"
value={profile.pastDayColor || "#a6a6a7"}
onChange={(e) =>
saveFieldDebounced("pastDayColor", e.target.value)
}
style={{
width: "100%",
height: "30px",
cursor: "pointer",
border: "none",
background: "transparent",
}}
/>
</div>
</div>
</div>
{/* Weekend Colors */}
<div
style={{
background: "var(--weekly-settings-item-bg)",
padding: "12px",
borderRadius: "8px",
marginBottom: "12px",
}}
>
<label
style={{
display: "block",
fontSize: "0.85rem",
fontWeight: 600,
color: "var(--weekly-settings-label)",
marginBottom: "8px",
}}
>
Weekend Highlight Colors
</label>
<div
style={{
display: "grid",
gridTemplateColumns: "1fr 1fr",
gap: "12px",
}}
>
<div>
<label
style={{
display: "block",
fontSize: "0.75rem",
color: "var(--weekly-settings-label)",
marginBottom: "4px",
}}
>
Saturday
</label>
<input
type="color"
value={profile.weekendColorSat || "#666666"}
onChange={(e) =>
saveFieldDebounced("weekendColorSat", e.target.value)
}
style={{
width: "100%",
height: "30px",
cursor: "pointer",
border: "none",
background: "transparent",
}}
/>
</div>
<div>
<label
style={{
display: "block",
fontSize: "0.75rem",
color: "var(--weekly-settings-label)",
marginBottom: "4px",
}}
>
Sunday
</label>
<input
type="color"
value={profile.weekendColorSun || "#dc2626"}
onChange={(e) =>
saveFieldDebounced("weekendColorSun", e.target.value)
}
style={{
width: "100%",
height: "30px",
cursor: "pointer",
border: "none",
background: "transparent",
}}
/>
</div>
</div>
</div>
{/* CSS Variables */}
{/* CSS Variables (includes Element Colors / Weekend Highlight Colors groups) */}
<CssVariablesEditor profile={profile} setProfile={setProfile} saveSetting={saveSetting} />
{/* Custom CSS */}

View File

@ -1250,6 +1250,7 @@ export default function WeeklyView() {
const [selectedTaskForRecurrence, setSelectedTaskForRecurrence] =
useState<Task | null>(null);
const [showFocusMode, setShowFocusMode] = useState(false);
const [focusSkippedIds, setFocusSkippedIds] = useState<string[]>([]);
const [showSchedule, setShowSchedule] = useState(true);
const [focusBreakDuration, setFocusBreakDuration] = useState(5);
const [weekdayFormat, setWeekdayFormat] = useState<"long" | "short" | "narrow" | "custom">("long");
@ -9382,9 +9383,8 @@ export default function WeeklyView() {
)}
{/* Focus Mode Overlay */}
{
showFocusMode && (
<FocusModeOverlay
task={(() => {
showFocusMode && (() => {
const focusQueue = (() => {
// Logic to find the "Next Task"
// 1. Tasks for today with start time, sorted by time
// 2. Tasks for today without start time, sorted by order
@ -9424,13 +9424,23 @@ export default function WeeklyView() {
return a.order - b.order;
});
return activeTasks.length > 0 ? activeTasks[0] : null;
})()}
return activeTasks.filter((t) => !focusSkippedIds.includes(t.id));
})();
return (
<FocusModeOverlay
task={focusQueue.length > 0 ? focusQueue[0] : null}
hasNext={focusQueue.length > 1}
onSkip={(taskId) => setFocusSkippedIds((prev) => [...prev, taskId])}
duration={focusTimerDuration}
onClose={() => setShowFocusMode(false)}
onClose={() => {
setShowFocusMode(false);
setFocusSkippedIds([]);
}}
onComplete={(taskId) => toggleTask(taskId)}
/>
)
);
})()
}
{/* Settings Sidebar */}