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:
parent
9ce5664621
commit
7e3e30ec83
13
CHANGELOG.md
13
CHANGELOG.md
@ -2,6 +2,19 @@
|
|||||||
|
|
||||||
All notable changes to this project are documented in this file.
|
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
|
## [1.113.1] - 2026-07-08
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "my-weekly-todo-list",
|
"name": "my-weekly-todo-list",
|
||||||
"version": "1.104.1",
|
"version": "1.114.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "my-weekly-todo-list",
|
"name": "my-weekly-todo-list",
|
||||||
"version": "1.104.1",
|
"version": "1.114.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@auth/prisma-adapter": "^2.11.1",
|
"@auth/prisma-adapter": "^2.11.1",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "my-weekly-todo-list",
|
"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",
|
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -11,9 +11,11 @@ interface FocusModeOverlayProps {
|
|||||||
duration: number; // in minutes
|
duration: number; // in minutes
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onComplete: (taskId: string) => 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 [timeLeft, setTimeLeft] = useState(duration * 60);
|
||||||
const [isActive, setIsActive] = useState(false);
|
const [isActive, setIsActive] = useState(false);
|
||||||
const [isCompleting, setIsCompleting] = useState(false);
|
const [isCompleting, setIsCompleting] = useState(false);
|
||||||
@ -51,6 +53,12 @@ export default function FocusModeOverlay({ task, duration, onClose, onComplete }
|
|||||||
setTimeLeft(duration * 60);
|
setTimeLeft(duration * 60);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSkip = () => {
|
||||||
|
if (!task || !onSkip) return;
|
||||||
|
onSkip(task.id);
|
||||||
|
handleReset(); // Fresh timer for the next task
|
||||||
|
};
|
||||||
|
|
||||||
const handleComplete = async () => {
|
const handleComplete = async () => {
|
||||||
if (!task) return;
|
if (!task) return;
|
||||||
setIsCompleting(true);
|
setIsCompleting(true);
|
||||||
@ -127,6 +135,16 @@ export default function FocusModeOverlay({ task, duration, onClose, onComplete }
|
|||||||
<button className="focus-btn secondary" onClick={handleReset}>
|
<button className="focus-btn secondary" onClick={handleReset}>
|
||||||
RESET
|
RESET
|
||||||
</button>
|
</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 && (
|
{task && (
|
||||||
<button className="focus-btn success" onClick={handleComplete} disabled={isCompleting}>
|
<button className="focus-btn success" onClick={handleComplete} disabled={isCompleting}>
|
||||||
{isCompleting ? 'COMPLETING...' : 'COMPLETE TASK'}
|
{isCompleting ? 'COMPLETING...' : 'COMPLETE TASK'}
|
||||||
@ -249,6 +267,13 @@ export default function FocusModeOverlay({ task, duration, onClose, onComplete }
|
|||||||
.focus-btn.secondary:hover {
|
.focus-btn.secondary:hover {
|
||||||
border-color: white;
|
border-color: white;
|
||||||
}
|
}
|
||||||
|
.focus-btn:disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.focus-btn:disabled:hover {
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
.focus-btn.success {
|
.focus-btn.success {
|
||||||
background: #009a9a; /* Weekly Teal */
|
background: #009a9a; /* Weekly Teal */
|
||||||
color: white;
|
color: white;
|
||||||
|
|||||||
@ -358,9 +358,9 @@ function CssVariablesEditor({
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
style={{
|
style={{
|
||||||
width: "32px",
|
width: "32px",
|
||||||
height: "22px",
|
height: "32px",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
border: "1px solid var(--weekly-settings-input-border)",
|
border: "none",
|
||||||
borderRadius: "4px",
|
borderRadius: "4px",
|
||||||
background: "transparent",
|
background: "transparent",
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
@ -368,7 +368,7 @@ function CssVariablesEditor({
|
|||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: "0.72rem",
|
fontSize: "0.85rem",
|
||||||
color: "var(--weekly-settings-label)",
|
color: "var(--weekly-settings-label)",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
@ -3790,171 +3790,7 @@ function SettingsSidebar({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Element Colors */}
|
{/* CSS Variables (includes Element Colors / Weekend Highlight Colors groups) */}
|
||||||
<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 */}
|
|
||||||
<CssVariablesEditor profile={profile} setProfile={setProfile} saveSetting={saveSetting} />
|
<CssVariablesEditor profile={profile} setProfile={setProfile} saveSetting={saveSetting} />
|
||||||
|
|
||||||
{/* Custom CSS */}
|
{/* Custom CSS */}
|
||||||
|
|||||||
@ -1250,6 +1250,7 @@ export default function WeeklyView() {
|
|||||||
const [selectedTaskForRecurrence, setSelectedTaskForRecurrence] =
|
const [selectedTaskForRecurrence, setSelectedTaskForRecurrence] =
|
||||||
useState<Task | null>(null);
|
useState<Task | null>(null);
|
||||||
const [showFocusMode, setShowFocusMode] = useState(false);
|
const [showFocusMode, setShowFocusMode] = useState(false);
|
||||||
|
const [focusSkippedIds, setFocusSkippedIds] = useState<string[]>([]);
|
||||||
const [showSchedule, setShowSchedule] = useState(true);
|
const [showSchedule, setShowSchedule] = useState(true);
|
||||||
const [focusBreakDuration, setFocusBreakDuration] = useState(5);
|
const [focusBreakDuration, setFocusBreakDuration] = useState(5);
|
||||||
const [weekdayFormat, setWeekdayFormat] = useState<"long" | "short" | "narrow" | "custom">("long");
|
const [weekdayFormat, setWeekdayFormat] = useState<"long" | "short" | "narrow" | "custom">("long");
|
||||||
@ -9382,9 +9383,8 @@ export default function WeeklyView() {
|
|||||||
)}
|
)}
|
||||||
{/* Focus Mode Overlay */}
|
{/* Focus Mode Overlay */}
|
||||||
{
|
{
|
||||||
showFocusMode && (
|
showFocusMode && (() => {
|
||||||
<FocusModeOverlay
|
const focusQueue = (() => {
|
||||||
task={(() => {
|
|
||||||
// Logic to find the "Next Task"
|
// Logic to find the "Next Task"
|
||||||
// 1. Tasks for today with start time, sorted by time
|
// 1. Tasks for today with start time, sorted by time
|
||||||
// 2. Tasks for today without start time, sorted by order
|
// 2. Tasks for today without start time, sorted by order
|
||||||
@ -9424,13 +9424,23 @@ export default function WeeklyView() {
|
|||||||
return a.order - b.order;
|
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}
|
duration={focusTimerDuration}
|
||||||
onClose={() => setShowFocusMode(false)}
|
onClose={() => {
|
||||||
|
setShowFocusMode(false);
|
||||||
|
setFocusSkippedIds([]);
|
||||||
|
}}
|
||||||
onComplete={(taskId) => toggleTask(taskId)}
|
onComplete={(taskId) => toggleTask(taskId)}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
|
})()
|
||||||
}
|
}
|
||||||
|
|
||||||
{/* Settings Sidebar */}
|
{/* Settings Sidebar */}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user