Skip to content

Commit 40eb851

Browse files
committed
Focus stopwatch & tab title that asks for attention
1 parent 5a93ad5 commit 40eb851

2 files changed

Lines changed: 79 additions & 31 deletions

File tree

src/components/FocusMode.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,16 @@ export const FocusMode = ({ onExit }: FocusModeProps) => {
1818
return () => clearInterval(timer);
1919
}, []);
2020

21-
const handleKeyDown = (e: KeyboardEvent) => {
22-
if (e.key === 'Escape') {
23-
onExit();
24-
}
25-
};
26-
2721
useEffect(() => {
22+
const handleKeyDown = (e: KeyboardEvent) => {
23+
if (e.key === 'Escape') {
24+
onExit();
25+
}
26+
};
27+
2828
document.addEventListener('keydown', handleKeyDown);
2929
return () => document.removeEventListener('keydown', handleKeyDown);
30-
}, []);
30+
}, [onExit]);
3131

3232
return (
3333
<div className="fixed inset-0 bg-gradient-to-br from-background via-background to-purple-900/20 flex items-center justify-center z-50">

src/pages/Index.tsx

Lines changed: 72 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { QuickAdd } from "@/components/QuickAdd";
77
import { FocusMode } from "@/components/FocusMode";
88
import { NoteViewer } from "@/components/NoteViewer";
99
import { indexedDBStorage } from "@/utils/indexedDBStorage";
10+
import { toast } from "@/hooks/use-toast";
1011

1112
export interface Note {
1213
id: string;
@@ -31,6 +32,39 @@ const Index = () => {
3132
const [selectedNote, setSelectedNote] = useState<Note | null>(null);
3233
const [isNoteViewerOpen, setIsNoteViewerOpen] = useState(false);
3334
const [isLoading, setIsLoading] = useState(true);
35+
const [focusTime, setFocusTime] = useState(0); // in seconds
36+
37+
useEffect(() => {
38+
let timer: NodeJS.Timeout | null = null;
39+
if (focusMode) {
40+
timer = setInterval(() => {
41+
setFocusTime((prev) => prev + 1);
42+
}, 1000);
43+
} else {
44+
setFocusTime(0); // reset when not in focus mode
45+
}
46+
return () => {
47+
if (timer) clearInterval(timer);
48+
};
49+
}, [focusMode]);
50+
51+
52+
useEffect(() => { // Handle page visibility changes to update the title
53+
const originalTitle = document.title;
54+
const handleVisibilityChange = () => {
55+
if (document.hidden) {
56+
document.title = "Come back!";
57+
} else {
58+
document.title = originalTitle;
59+
}
60+
};
61+
document.addEventListener("visibilitychange", handleVisibilityChange);
62+
return () => {
63+
document.removeEventListener("visibilitychange", handleVisibilityChange);
64+
document.title = originalTitle;
65+
};
66+
}, []);
67+
3468

3569
// Load data from IndexedDB on mount
3670
useEffect(() => {
@@ -41,16 +75,16 @@ const Index = () => {
4175
indexedDBStorage.loadNotes(),
4276
indexedDBStorage.loadTasks()
4377
]);
44-
78+
4579
setNotes(loadedNotes);
4680
setTasks(loadedTasks);
4781
} catch (error) {
4882
console.error('Error loading data from IndexedDB:', error);
49-
83+
5084
// Fallback to localStorage if IndexedDB fails
5185
const savedNotes = localStorage.getItem('noted-notes');
5286
const savedTasks = localStorage.getItem('noted-tasks');
53-
87+
5488
if (savedNotes) {
5589
try {
5690
const parsedNotes = JSON.parse(savedNotes).map((note: Note) => ({
@@ -62,7 +96,7 @@ const Index = () => {
6296
console.error('Error loading notes from localStorage:', error);
6397
}
6498
}
65-
99+
66100
if (savedTasks) {
67101
try {
68102
const parsedTasks = JSON.parse(savedTasks).map((task: Task) => ({
@@ -121,7 +155,7 @@ const Index = () => {
121155
};
122156

123157
const updateNote = (id: string, content: string) => {
124-
setNotes(prev => prev.map(note =>
158+
setNotes(prev => prev.map(note =>
125159
note.id === id ? { ...note, content } : note
126160
));
127161
};
@@ -136,13 +170,13 @@ const Index = () => {
136170
};
137171

138172
const toggleTask = (id: string) => {
139-
setTasks(prev => prev.map(task =>
140-
task.id === id
141-
? {
142-
...task,
143-
completed: !task.completed,
144-
completedAt: !task.completed ? new Date() : undefined
145-
}
173+
setTasks(prev => prev.map(task =>
174+
task.id === id
175+
? {
176+
...task,
177+
completed: !task.completed,
178+
completedAt: !task.completed ? new Date() : undefined
179+
}
146180
: task
147181
));
148182
};
@@ -165,15 +199,15 @@ const Index = () => {
165199
setNotes(prev => {
166200
const note = prev.find(n => n.id === id);
167201
if (!note) return prev;
168-
202+
169203
const pinnedCount = prev.filter(n => n.pinned).length;
170-
204+
171205
// If trying to pin and already have 3 pinned notes, don't allow
172206
if (!note.pinned && pinnedCount >= 3) {
173207
return prev;
174208
}
175-
176-
return prev.map(n =>
209+
210+
return prev.map(n =>
177211
n.id === id ? { ...n, pinned: !n.pinned } : n
178212
);
179213
});
@@ -201,7 +235,21 @@ const Index = () => {
201235
});
202236

203237
if (focusMode) {
204-
return <FocusMode onExit={() => setFocusMode(false)} />;
238+
return <FocusMode onExit={() => {
239+
setFocusMode(false);
240+
if (focusTime / 60 >= 5) {
241+
toast({
242+
title: "Laser Sharp.",
243+
description: `You kept your focus for ${Math.floor(focusTime / 60)} minutes.`,
244+
});
245+
} else {
246+
toast({
247+
title: "Distraction Detected!",
248+
description: `You were in focus mode for less than 5 minutes. Try to focus longer next time.`,
249+
variant: "destructive",
250+
});
251+
}
252+
}} />;
205253
}
206254

207255
// Sort notes to show pinned ones first
@@ -225,32 +273,32 @@ const Index = () => {
225273
return (
226274
<div className="min-h-screen bg-gradient-to-br from-background via-background to-purple-900/20">
227275
{/* Fixed header on mobile, static on larger screens */}
228-
<Header
229-
onFocusMode={() => setFocusMode(true)}
276+
<Header
277+
onFocusMode={() => setFocusMode(true)}
230278
notes={notes}
231279
tasks={tasks}
232280
/>
233-
281+
234282
{/* Main content with top padding only for mobile fixed header */}
235283
<div className="container mx-auto px-4 pt-20 sm:pt-6 pb-6 space-y-6">
236284
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
237285
{/* Main content area */}
238286
<div className="lg:col-span-2 space-y-6">
239287
<QuickAdd onAddNote={addNote} onAddTask={addTask} />
240-
<NotesGrid
241-
notes={sortedNotes}
288+
<NotesGrid
289+
notes={sortedNotes}
242290
onDeleteNote={deleteNote}
243291
onUpdateNote={updateNote}
244292
onConvertToTask={convertNoteToTask}
245293
onTogglePin={togglePinNote}
246294
onViewNote={handleViewNote}
247295
/>
248296
</div>
249-
297+
250298
{/* Sidebar */}
251299
<div className="space-y-6">
252300
<PomodoroTimer />
253-
<TasksList
301+
<TasksList
254302
tasks={tasks}
255303
onToggleTask={toggleTask}
256304
onDeleteTask={deleteTask}

0 commit comments

Comments
 (0)