diff --git a/src/components/GridTaskBlock.tsx b/src/components/GridTaskBlock.tsx index 9a1401a..9085e2b 100644 --- a/src/components/GridTaskBlock.tsx +++ b/src/components/GridTaskBlock.tsx @@ -180,7 +180,7 @@ export function GridTaskBlock({ boxShadow: (isNotesOpen || isSubTasksOpen || isResizing) ? "0 1px 3px rgba(0,0,0,0.05)" : "none", display: "flex", flexDirection: "column", - overflow: isNotesOpen || isSubTasksOpen ? "visible" : "hidden", + overflow: "visible", }} draggable={!editingTaskId && !isResizing} onDragStart={(e) => handleDragStart(e, task)} diff --git a/src/components/WeeklyView.tsx b/src/components/WeeklyView.tsx index 2ba0463..2c83184 100644 --- a/src/components/WeeklyView.tsx +++ b/src/components/WeeklyView.tsx @@ -539,6 +539,7 @@ export default function WeeklyView() { todayHighlightColor?: string; pastDayColor?: string; goalFallbackType?: "quote" | "next_todo" | "default"; + quoteSourceUrl?: string; goalDefaultSentence?: string; goalFontFamily?: string; goalFontSize?: string; @@ -607,7 +608,9 @@ export default function WeeklyView() { weekendColorSat: "#666666", weekendColorSun: "#dc2626", pastDayColor: "#a6a6a7", + quoteSourceUrl: "https://recite.vercel.app/api/random", }); + const [motivationalQuote, setMotivationalQuote] = useState(""); const [showSummary, setShowSummary] = useState(false); const [isAddingSomedayList, setIsAddingSomedayList] = useState(false); @@ -940,14 +943,43 @@ export default function WeeklyView() { } }; + const fetchMotivationalQuote = useCallback(async () => { + if (profile.goalFallbackType !== "quote") return; + try { + const url = profile.quoteSourceUrl || "https://recite.vercel.app/api/random"; + const res = await fetch(url); + if (!res.ok) throw new Error("Failed to fetch quote"); + const data = await res.json(); + + // Handle different JSON formats (array or object) + let quoteText = ""; + if (Array.isArray(data) && data.length > 0) { + const item = data[0]; + quoteText = item.quote || item.text || item.content || (typeof item === 'string' ? item : ""); + if (item.author) quoteText += ` - ${item.author}`; + } else if (data && typeof data === 'object') { + quoteText = data.quote || data.text || data.content || ""; + if (data.author) quoteText += ` - ${data.author}`; + } else if (typeof data === 'string') { + quoteText = data; + } + + if (quoteText) setMotivationalQuote(quoteText); + } catch (error) { + console.error("Error fetching motivational quote:", error); + setMotivationalQuote("Stay focused and productive."); + } + }, [profile.goalFallbackType, profile.quoteSourceUrl]); + // Fetch tasks on mount useEffect(() => { if (session) { fetchTasks(); fetchConnections(); fetchCalendarEvents(); + fetchMotivationalQuote(); } - }, [session]); + }, [session, fetchMotivationalQuote]); // Periodic pull-sync from Google Tasks (every 2 minutes) useEffect(() => { @@ -1104,18 +1136,21 @@ export default function WeeklyView() { setGoal(newGoal); try { await fetch("/api/goal", { - method: "PUT", + method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ weekStart: goalDateKey, - text: newGoal, + goal: newGoal, + scope: profile.goalScope || "week", }), }); - } catch (err) { - console.error("Failed to save goal:", err); + } catch (error) { + console.error("Error saving goal:", error); } }; + + const handleSomedayWheel = (e: React.WheelEvent) => { if (e.currentTarget) { e.currentTarget.scrollLeft += e.deltaY; @@ -3277,10 +3312,10 @@ export default function WeeklyView() { {/* Week & Year */}
{(isLoading || isSyncing || syncStatus === "syncing") && ( - +
)} )} - @@ -4145,7 +4181,7 @@ export default function WeeklyView() { onEdit={() => setEditingTaskId(task.id)} onUpdate={(newTitle) => updateTask(task.id, newTitle)} onDelete={() => deleteTask(task.id)} - onNotes={(notes) => updateTaskNotes(task.id, notes)} + onNotes={() => setSelectedTaskForNotes(task)} onRollToggle={() => toggleTaskRolling(task.id)} onRecurrence={() => setSelectedTaskForRecurrence(task) @@ -6274,6 +6310,7 @@ function SettingsSidebar({ todayHighlightColor?: string; pastDayColor?: string; goalFallbackType?: "quote" | "next_todo" | "default"; + quoteSourceUrl?: string; goalDefaultSentence?: string; goalFontFamily?: string; goalFontSize?: string; @@ -6316,6 +6353,8 @@ function SettingsSidebar({ hourLabelFormat: "short", showSubHourSlots: true, allDayPosition: "below", + goalFallbackType: "quote", + quoteSourceUrl: "https://recite.vercel.app/api/random", headlineFont: "Inter", headlineFontSize: "1.25rem", headlineFontWeight: "900", @@ -8833,45 +8872,7 @@ function SettingsSidebar({
- {/* Goal of the Week */} -
- - setGoal(e.target.value)} - onBlur={() => saveGoal(goal)} - onKeyDown={(e) => e.key === "Enter" && e.currentTarget.blur()} - className="weekly-input" - placeholder={t.goalOfWeek} - style={{ - width: "100%", - padding: "12px", - fontSize: "1rem", - borderRadius: "6px", - border: "1px solid var(--weekly-border)", - background: "var(--weekly-bg)", - color: "var(--weekly-settings-text)", - }} - /> -
+ {/* Replaced Goal of the Week settings block */} {/* "Do This Now" Toggle */}
Standardtext
+ {profile.goalFallbackType === "quote" && ( +
+ + + setProfile((p) => ({ + ...p, + quoteSourceUrl: e.target.value, + })) + } + className="weekly-input" + placeholder="https://recite.vercel.app/api/random" + style={{ + width: "100%", + padding: "10px", + fontSize: "0.95rem", + borderRadius: "6px", + border: "1px solid var(--weekly-border)", + background: "var(--weekly-bg)", + }} + /> +

+ URL that returns a JSON list or object of quotes (e.g. {'[{"quote":"...","author":"..."}]'} or {'{"quote":"..."}'}). +

+
+ )} {profile.goalFallbackType === "default" && (