react-os-shell 0.2.68 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -15
- package/dist/{Browser-UGZQMWKW.js → Browser-H5KDP5OH.js} +3 -3
- package/dist/{Browser-UGZQMWKW.js.map → Browser-H5KDP5OH.js.map} +1 -1
- package/dist/{Calculator-3ZXNXWDH.js → Calculator-QQ7NF53Q.js} +4 -4
- package/dist/{Calculator-3ZXNXWDH.js.map → Calculator-QQ7NF53Q.js.map} +1 -1
- package/dist/{Calendar-ON4AQ54T.js → Calendar-J6L7FGHS.js} +175 -108
- package/dist/Calendar-J6L7FGHS.js.map +1 -0
- package/dist/{CurrencyConverter-ACTLK72N.js → CurrencyConverter-YHOGBUPH.js} +4 -4
- package/dist/{CurrencyConverter-ACTLK72N.js.map → CurrencyConverter-YHOGBUPH.js.map} +1 -1
- package/dist/{Documents-STDXQ7I4.js → Documents-6DYALASM.js} +3 -3
- package/dist/{Documents-STDXQ7I4.js.map → Documents-6DYALASM.js.map} +1 -1
- package/dist/Email-U2U5Z4DL.js +475 -0
- package/dist/Email-U2U5Z4DL.js.map +1 -0
- package/dist/Files-T62M4V5I.js +11 -0
- package/dist/{Files-ASKLEUNU.js.map → Files-T62M4V5I.js.map} +1 -1
- package/dist/{Minesweeper-CZNIO75H.js → Minesweeper-S2JHXYLX.js} +3 -3
- package/dist/{Minesweeper-CZNIO75H.js.map → Minesweeper-S2JHXYLX.js.map} +1 -1
- package/dist/{Notepad-ZYYH4ZXN.js → Notepad-2YF7X3XO.js} +3 -3
- package/dist/{Notepad-ZYYH4ZXN.js.map → Notepad-2YF7X3XO.js.map} +1 -1
- package/dist/{PomodoroTimer-2MNIEAUM.js → PomodoroTimer-3J7Z3NVQ.js} +4 -4
- package/dist/{PomodoroTimer-2MNIEAUM.js.map → PomodoroTimer-3J7Z3NVQ.js.map} +1 -1
- package/dist/Preview-WM6ZP5PZ.js +8 -0
- package/dist/{Preview-U72UL74H.js.map → Preview-WM6ZP5PZ.js.map} +1 -1
- package/dist/Spreadsheet-ZIE2SXAF.js +6 -0
- package/dist/{Spreadsheet-T7Y7PRD6.js.map → Spreadsheet-ZIE2SXAF.js.map} +1 -1
- package/dist/{TodoList-7JZ2SLDI.js → TodoList-QGXCDEIE.js} +18 -204
- package/dist/TodoList-QGXCDEIE.js.map +1 -0
- package/dist/{Weather-DYCTCB6T.js → Weather-2GFPSZ5V.js} +4 -4
- package/dist/{Weather-DYCTCB6T.js.map → Weather-2GFPSZ5V.js.map} +1 -1
- package/dist/{WorldClock-XL4OMFOY.js → WorldClock-P4JR5I6X.js} +4 -4
- package/dist/{WorldClock-XL4OMFOY.js.map → WorldClock-P4JR5I6X.js.map} +1 -1
- package/dist/apps/index.d.ts +2 -5
- package/dist/apps/index.js +23 -26
- package/dist/apps/index.js.map +1 -1
- package/dist/chunk-57B3WALN.js +114 -0
- package/dist/chunk-57B3WALN.js.map +1 -0
- package/dist/{chunk-4SHZ7BZO.js → chunk-62FC2FHC.js} +92 -21
- package/dist/chunk-62FC2FHC.js.map +1 -0
- package/dist/{chunk-FXAOT23O.js → chunk-ATQVRDDQ.js} +3 -3
- package/dist/{chunk-FXAOT23O.js.map → chunk-ATQVRDDQ.js.map} +1 -1
- package/dist/{chunk-GP4Y3VCB.js → chunk-KMGWSDEI.js} +480 -4
- package/dist/chunk-KMGWSDEI.js.map +1 -0
- package/dist/{chunk-SU6XVJND.js → chunk-O6FJZAFM.js} +3 -3
- package/dist/{chunk-SU6XVJND.js.map → chunk-O6FJZAFM.js.map} +1 -1
- package/dist/{chunk-YL47AVBA.js → chunk-SEV7UXGN.js} +4 -4
- package/dist/{chunk-YL47AVBA.js.map → chunk-SEV7UXGN.js.map} +1 -1
- package/dist/{chunk-L2AFKNSQ.js → chunk-ZBRFMK3E.js} +4 -4
- package/dist/{chunk-L2AFKNSQ.js.map → chunk-ZBRFMK3E.js.map} +1 -1
- package/dist/index.d.ts +55 -1
- package/dist/index.js +241 -135
- package/dist/index.js.map +1 -1
- package/package.json +10 -3
- package/dist/Calendar-ON4AQ54T.js.map +0 -1
- package/dist/Email-5WL3TWC6.js +0 -1883
- package/dist/Email-5WL3TWC6.js.map +0 -1
- package/dist/Files-ASKLEUNU.js +0 -12
- package/dist/GeminiChat-XTEBZIVK.js +0 -184
- package/dist/GeminiChat-XTEBZIVK.js.map +0 -1
- package/dist/Preview-U72UL74H.js +0 -8
- package/dist/Spreadsheet-T7Y7PRD6.js +0 -7
- package/dist/TodoList-7JZ2SLDI.js.map +0 -1
- package/dist/chunk-4SHZ7BZO.js.map +0 -1
- package/dist/chunk-5VXRBUEH.js +0 -104
- package/dist/chunk-5VXRBUEH.js.map +0 -1
- package/dist/chunk-GP4Y3VCB.js.map +0 -1
- package/dist/chunk-MUXDKEOC.js +0 -485
- package/dist/chunk-MUXDKEOC.js.map +0 -1
- package/dist/chunk-MVWEL34Y.js +0 -209
- package/dist/chunk-MVWEL34Y.js.map +0 -1
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import { useGoogleAuth, getGoogleAccessToken } from './chunk-MVWEL34Y.js';
|
|
2
|
-
import { toast_default } from './chunk-WIJ45SYD.js';
|
|
3
|
-
import { useState, useRef, useEffect } from 'react';
|
|
4
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
|
-
|
|
6
|
-
var GEMINI_API = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent";
|
|
7
|
-
function GeminiChat() {
|
|
8
|
-
const { isConnected, user, connect, disconnect, hasClientId, setClientId, loading: authLoading, error: authError } = useGoogleAuth();
|
|
9
|
-
const [messages, setMessages] = useState([]);
|
|
10
|
-
const [input, setInput] = useState("");
|
|
11
|
-
const [loading, setLoading] = useState(false);
|
|
12
|
-
const [clientIdInput, setClientIdInput] = useState("");
|
|
13
|
-
const scrollRef = useRef(null);
|
|
14
|
-
const inputRef = useRef(null);
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight, behavior: "smooth" });
|
|
17
|
-
}, [messages]);
|
|
18
|
-
const sendMessage = async () => {
|
|
19
|
-
const text = input.trim();
|
|
20
|
-
if (!text || loading) return;
|
|
21
|
-
const token = getGoogleAccessToken();
|
|
22
|
-
if (!token) {
|
|
23
|
-
toast_default.error("Google session expired. Please reconnect.");
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
const userMsg = { role: "user", content: text, timestamp: /* @__PURE__ */ new Date() };
|
|
27
|
-
setMessages((prev) => [...prev, userMsg]);
|
|
28
|
-
setInput("");
|
|
29
|
-
setLoading(true);
|
|
30
|
-
try {
|
|
31
|
-
const contents = [...messages, userMsg].map((m) => ({
|
|
32
|
-
role: m.role === "model" ? "model" : "user",
|
|
33
|
-
parts: [{ text: m.content }]
|
|
34
|
-
}));
|
|
35
|
-
const res = await fetch(`${GEMINI_API}`, {
|
|
36
|
-
method: "POST",
|
|
37
|
-
headers: {
|
|
38
|
-
Authorization: `Bearer ${token}`,
|
|
39
|
-
"Content-Type": "application/json"
|
|
40
|
-
},
|
|
41
|
-
body: JSON.stringify({ contents })
|
|
42
|
-
});
|
|
43
|
-
if (!res.ok) {
|
|
44
|
-
const err = await res.json().catch(() => ({}));
|
|
45
|
-
throw new Error(err.error?.message || `API error ${res.status}`);
|
|
46
|
-
}
|
|
47
|
-
const data = await res.json();
|
|
48
|
-
const reply = data.candidates?.[0]?.content?.parts?.[0]?.text || "No response.";
|
|
49
|
-
setMessages((prev) => [...prev, { role: "model", content: reply, timestamp: /* @__PURE__ */ new Date() }]);
|
|
50
|
-
} catch (err) {
|
|
51
|
-
toast_default.error(err.message || "Failed to get response from Gemini.");
|
|
52
|
-
setMessages((prev) => [...prev, { role: "model", content: `Error: ${err.message}`, timestamp: /* @__PURE__ */ new Date() }]);
|
|
53
|
-
}
|
|
54
|
-
setLoading(false);
|
|
55
|
-
setTimeout(() => inputRef.current?.focus(), 50);
|
|
56
|
-
};
|
|
57
|
-
const clearChat = () => {
|
|
58
|
-
setMessages([]);
|
|
59
|
-
};
|
|
60
|
-
if (!isConnected) {
|
|
61
|
-
return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsxs("div", { className: "text-center max-w-md space-y-4 px-6", children: [
|
|
62
|
-
/* @__PURE__ */ jsx("div", { className: "h-16 w-16 mx-auto rounded-2xl bg-gradient-to-br from-blue-500 via-purple-500 to-pink-500 flex items-center justify-center", children: /* @__PURE__ */ jsx("svg", { className: "h-8 w-8 text-white", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09zM18.259 8.715L18 9.75l-.259-1.035a3.375 3.375 0 00-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 002.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 002.455 2.456L21.75 6l-1.036.259a3.375 3.375 0 00-2.455 2.456zM16.894 20.567L16.5 21.75l-.394-1.183a2.25 2.25 0 00-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 001.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 001.423 1.423l1.183.394-1.183.394a2.25 2.25 0 00-1.423 1.423z" }) }) }),
|
|
63
|
-
/* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "Gemini AI" }),
|
|
64
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: "Connect your Google account to chat with Gemini AI." }),
|
|
65
|
-
!hasClientId ? /* @__PURE__ */ jsxs("div", { className: "text-left space-y-2 bg-gray-50 rounded-lg p-4", children: [
|
|
66
|
-
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium text-gray-700", children: "Google OAuth Client ID" }),
|
|
67
|
-
/* @__PURE__ */ jsx(
|
|
68
|
-
"input",
|
|
69
|
-
{
|
|
70
|
-
value: clientIdInput,
|
|
71
|
-
onChange: (e) => setClientIdInput(e.target.value),
|
|
72
|
-
placeholder: "123456789.apps.googleusercontent.com",
|
|
73
|
-
className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:ring-blue-500"
|
|
74
|
-
}
|
|
75
|
-
),
|
|
76
|
-
/* @__PURE__ */ jsx(
|
|
77
|
-
"button",
|
|
78
|
-
{
|
|
79
|
-
onClick: () => {
|
|
80
|
-
if (clientIdInput.trim()) setClientId(clientIdInput.trim());
|
|
81
|
-
},
|
|
82
|
-
disabled: !clientIdInput.trim(),
|
|
83
|
-
className: "w-full bg-gray-900 text-white px-4 py-2 text-sm font-medium rounded-lg hover:bg-gray-800 disabled:opacity-40",
|
|
84
|
-
children: "Save Client ID"
|
|
85
|
-
}
|
|
86
|
-
),
|
|
87
|
-
/* @__PURE__ */ jsx("p", { className: "text-[10px] text-gray-400", children: 'Enable "Generative Language API" in your Google Cloud project' })
|
|
88
|
-
] }) : /* @__PURE__ */ jsxs(
|
|
89
|
-
"button",
|
|
90
|
-
{
|
|
91
|
-
onClick: connect,
|
|
92
|
-
disabled: authLoading,
|
|
93
|
-
className: "inline-flex items-center gap-2 bg-white border border-gray-300 shadow-sm px-6 py-2.5 text-sm font-medium rounded-lg hover:bg-gray-50 disabled:opacity-50",
|
|
94
|
-
children: [
|
|
95
|
-
/* @__PURE__ */ jsxs("svg", { className: "h-5 w-5", viewBox: "0 0 24 24", children: [
|
|
96
|
-
/* @__PURE__ */ jsx("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z", fill: "#4285F4" }),
|
|
97
|
-
/* @__PURE__ */ jsx("path", { d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z", fill: "#34A853" }),
|
|
98
|
-
/* @__PURE__ */ jsx("path", { d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z", fill: "#FBBC05" }),
|
|
99
|
-
/* @__PURE__ */ jsx("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z", fill: "#EA4335" })
|
|
100
|
-
] }),
|
|
101
|
-
authLoading ? "Connecting..." : "Sign in with Google"
|
|
102
|
-
]
|
|
103
|
-
}
|
|
104
|
-
),
|
|
105
|
-
authError && /* @__PURE__ */ jsx("p", { className: "text-sm text-red-600", children: authError })
|
|
106
|
-
] }) });
|
|
107
|
-
}
|
|
108
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
|
|
109
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-2 border-b border-gray-200 shrink-0", children: [
|
|
110
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
111
|
-
/* @__PURE__ */ jsx("div", { className: "h-6 w-6 rounded-lg bg-gradient-to-br from-blue-500 via-purple-500 to-pink-500 flex items-center justify-center", children: /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5 text-white", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z" }) }) }),
|
|
112
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-gray-900", children: "Gemini" }),
|
|
113
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400", children: "2.5 Flash" })
|
|
114
|
-
] }),
|
|
115
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
116
|
-
/* @__PURE__ */ jsx("button", { onClick: clearChat, className: "text-xs text-gray-500 hover:text-gray-700", children: "Clear" }),
|
|
117
|
-
/* @__PURE__ */ jsxs(
|
|
118
|
-
"button",
|
|
119
|
-
{
|
|
120
|
-
onClick: () => window.dispatchEvent(new Event("open-google-connect")),
|
|
121
|
-
title: "Google Services",
|
|
122
|
-
className: "flex items-center gap-2 hover:bg-gray-100 rounded-md px-1.5 py-1 transition-colors",
|
|
123
|
-
children: [
|
|
124
|
-
user?.picture ? /* @__PURE__ */ jsx("img", { src: user.picture, alt: "", className: "h-6 w-6 rounded-full" }) : /* @__PURE__ */ jsx("div", { className: "h-6 w-6 rounded-full bg-gray-200" }),
|
|
125
|
-
/* @__PURE__ */ jsxs("div", { className: "text-left", children: [
|
|
126
|
-
/* @__PURE__ */ jsx("p", { className: "text-[11px] font-medium text-gray-900", children: user?.name }),
|
|
127
|
-
/* @__PURE__ */ jsx("p", { className: "text-[10px] text-gray-500", children: user?.email })
|
|
128
|
-
] })
|
|
129
|
-
]
|
|
130
|
-
}
|
|
131
|
-
)
|
|
132
|
-
] })
|
|
133
|
-
] }),
|
|
134
|
-
/* @__PURE__ */ jsxs("div", { ref: scrollRef, className: "flex-1 overflow-y-auto px-4 py-4 space-y-4", children: [
|
|
135
|
-
messages.length === 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full text-center", children: /* @__PURE__ */ jsxs("div", { children: [
|
|
136
|
-
/* @__PURE__ */ jsx("div", { className: "h-12 w-12 mx-auto mb-3 rounded-xl bg-gradient-to-br from-blue-500/10 via-purple-500/10 to-pink-500/10 flex items-center justify-center", children: /* @__PURE__ */ jsx("svg", { className: "h-6 w-6 text-purple-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z" }) }) }),
|
|
137
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: "Ask Gemini anything" }),
|
|
138
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 mt-1", children: "Powered by Google AI" })
|
|
139
|
-
] }) }),
|
|
140
|
-
messages.map((msg, i) => /* @__PURE__ */ jsx("div", { className: `flex ${msg.role === "user" ? "justify-end" : "justify-start"}`, children: /* @__PURE__ */ jsxs("div", { className: `max-w-[80%] rounded-2xl px-4 py-2.5 ${msg.role === "user" ? "bg-blue-600 text-white" : "bg-gray-100 text-gray-900"}`, children: [
|
|
141
|
-
/* @__PURE__ */ jsx("div", { className: "text-sm whitespace-pre-wrap leading-relaxed", children: msg.content }),
|
|
142
|
-
/* @__PURE__ */ jsx("p", { className: `text-[10px] mt-1 ${msg.role === "user" ? "text-blue-200" : "text-gray-400"}`, children: msg.timestamp.toLocaleTimeString(void 0, { hour: "2-digit", minute: "2-digit" }) })
|
|
143
|
-
] }) }, i)),
|
|
144
|
-
loading && /* @__PURE__ */ jsx("div", { className: "flex justify-start", children: /* @__PURE__ */ jsx("div", { className: "bg-gray-100 rounded-2xl px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
145
|
-
/* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-full bg-gray-400 animate-bounce", style: { animationDelay: "0ms" } }),
|
|
146
|
-
/* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-full bg-gray-400 animate-bounce", style: { animationDelay: "150ms" } }),
|
|
147
|
-
/* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-full bg-gray-400 animate-bounce", style: { animationDelay: "300ms" } })
|
|
148
|
-
] }) }) })
|
|
149
|
-
] }),
|
|
150
|
-
/* @__PURE__ */ jsx("div", { className: "px-4 py-3 border-t border-gray-200 shrink-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2", children: [
|
|
151
|
-
/* @__PURE__ */ jsx(
|
|
152
|
-
"textarea",
|
|
153
|
-
{
|
|
154
|
-
ref: inputRef,
|
|
155
|
-
value: input,
|
|
156
|
-
onChange: (e) => setInput(e.target.value),
|
|
157
|
-
onKeyDown: (e) => {
|
|
158
|
-
if (e.key === "Enter" && !e.shiftKey) {
|
|
159
|
-
e.preventDefault();
|
|
160
|
-
sendMessage();
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
placeholder: "Message Gemini...",
|
|
164
|
-
rows: 1,
|
|
165
|
-
className: "flex-1 rounded-xl border border-gray-300 px-4 py-2.5 text-sm resize-none focus:border-blue-500 focus:ring-blue-500 max-h-32",
|
|
166
|
-
style: { minHeight: "42px" }
|
|
167
|
-
}
|
|
168
|
-
),
|
|
169
|
-
/* @__PURE__ */ jsx(
|
|
170
|
-
"button",
|
|
171
|
-
{
|
|
172
|
-
onClick: sendMessage,
|
|
173
|
-
disabled: loading || !input.trim(),
|
|
174
|
-
className: "shrink-0 bg-blue-600 text-white rounded-xl p-2.5 hover:bg-blue-700 disabled:opacity-40 transition-colors",
|
|
175
|
-
children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 12L3.269 3.126A59.768 59.768 0 0121.485 12 59.77 59.77 0 013.27 20.876L5.999 12zm0 0h7.5" }) })
|
|
176
|
-
}
|
|
177
|
-
)
|
|
178
|
-
] }) })
|
|
179
|
-
] });
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export { GeminiChat as default };
|
|
183
|
-
//# sourceMappingURL=GeminiChat-XTEBZIVK.js.map
|
|
184
|
-
//# sourceMappingURL=GeminiChat-XTEBZIVK.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/apps/GeminiChat.tsx"],"names":[],"mappings":"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","file":"GeminiChat-XTEBZIVK.js","sourcesContent":["import { useState, useRef, useEffect } from 'react';\nimport useGoogleAuth, { getGoogleAccessToken } from '../hooks/useGoogleAuth';\nimport toast from '../shell/toast';\n\ninterface ChatMessage {\n role: 'user' | 'model';\n content: string;\n timestamp: Date;\n}\n\nconst GEMINI_API = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent';\n\nexport default function GeminiChat() {\n const { isConnected, user, connect, disconnect, hasClientId, setClientId, loading: authLoading, error: authError } = useGoogleAuth();\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [input, setInput] = useState('');\n const [loading, setLoading] = useState(false);\n const [clientIdInput, setClientIdInput] = useState('');\n const scrollRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLTextAreaElement>(null);\n\n useEffect(() => {\n scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight, behavior: 'smooth' });\n }, [messages]);\n\n const sendMessage = async () => {\n const text = input.trim();\n if (!text || loading) return;\n\n const token = getGoogleAccessToken();\n if (!token) { toast.error('Google session expired. Please reconnect.'); return; }\n\n const userMsg: ChatMessage = { role: 'user', content: text, timestamp: new Date() };\n setMessages(prev => [...prev, userMsg]);\n setInput('');\n setLoading(true);\n\n try {\n // Build conversation history for context\n const contents = [...messages, userMsg].map(m => ({\n role: m.role === 'model' ? 'model' : 'user',\n parts: [{ text: m.content }],\n }));\n\n const res = await fetch(`${GEMINI_API}`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ contents }),\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({}));\n throw new Error(err.error?.message || `API error ${res.status}`);\n }\n\n const data = await res.json();\n const reply = data.candidates?.[0]?.content?.parts?.[0]?.text || 'No response.';\n setMessages(prev => [...prev, { role: 'model', content: reply, timestamp: new Date() }]);\n } catch (err: any) {\n toast.error(err.message || 'Failed to get response from Gemini.');\n setMessages(prev => [...prev, { role: 'model', content: `Error: ${err.message}`, timestamp: new Date() }]);\n }\n setLoading(false);\n setTimeout(() => inputRef.current?.focus(), 50);\n };\n\n const clearChat = () => {\n setMessages([]);\n };\n\n // ── Not connected ──\n if (!isConnected) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"text-center max-w-md space-y-4 px-6\">\n <div className=\"h-16 w-16 mx-auto rounded-2xl bg-gradient-to-br from-blue-500 via-purple-500 to-pink-500 flex items-center justify-center\">\n <svg className=\"h-8 w-8 text-white\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09zM18.259 8.715L18 9.75l-.259-1.035a3.375 3.375 0 00-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 002.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 002.455 2.456L21.75 6l-1.036.259a3.375 3.375 0 00-2.455 2.456zM16.894 20.567L16.5 21.75l-.394-1.183a2.25 2.25 0 00-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 001.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 001.423 1.423l1.183.394-1.183.394a2.25 2.25 0 00-1.423 1.423z\" /></svg>\n </div>\n <h2 className=\"text-lg font-semibold text-gray-900\">Gemini AI</h2>\n <p className=\"text-sm text-gray-500\">Connect your Google account to chat with Gemini AI.</p>\n\n {!hasClientId ? (\n <div className=\"text-left space-y-2 bg-gray-50 rounded-lg p-4\">\n <label className=\"block text-xs font-medium text-gray-700\">Google OAuth Client ID</label>\n <input value={clientIdInput} onChange={e => setClientIdInput(e.target.value)} placeholder=\"123456789.apps.googleusercontent.com\"\n className=\"w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:ring-blue-500\" />\n <button onClick={() => { if (clientIdInput.trim()) setClientId(clientIdInput.trim()); }} disabled={!clientIdInput.trim()}\n className=\"w-full bg-gray-900 text-white px-4 py-2 text-sm font-medium rounded-lg hover:bg-gray-800 disabled:opacity-40\">Save Client ID</button>\n <p className=\"text-[10px] text-gray-400\">Enable \"Generative Language API\" in your Google Cloud project</p>\n </div>\n ) : (\n <button onClick={connect} disabled={authLoading}\n className=\"inline-flex items-center gap-2 bg-white border border-gray-300 shadow-sm px-6 py-2.5 text-sm font-medium rounded-lg hover:bg-gray-50 disabled:opacity-50\">\n <svg className=\"h-5 w-5\" viewBox=\"0 0 24 24\"><path d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z\" fill=\"#4285F4\"/><path d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\" fill=\"#34A853\"/><path d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\" fill=\"#FBBC05\"/><path d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\" fill=\"#EA4335\"/></svg>\n {authLoading ? 'Connecting...' : 'Sign in with Google'}\n </button>\n )}\n {authError && <p className=\"text-sm text-red-600\">{authError}</p>}\n </div>\n </div>\n );\n }\n\n // ── Connected: Chat UI ──\n return (\n <div className=\"flex flex-col h-full\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-2 border-b border-gray-200 shrink-0\">\n <div className=\"flex items-center gap-2\">\n <div className=\"h-6 w-6 rounded-lg bg-gradient-to-br from-blue-500 via-purple-500 to-pink-500 flex items-center justify-center\">\n <svg className=\"h-3.5 w-3.5 text-white\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z\" /></svg>\n </div>\n <span className=\"text-sm font-semibold text-gray-900\">Gemini</span>\n <span className=\"text-xs text-gray-400\">2.5 Flash</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <button onClick={clearChat} className=\"text-xs text-gray-500 hover:text-gray-700\">Clear</button>\n <button onClick={() => window.dispatchEvent(new Event('open-google-connect'))} title=\"Google Services\"\n className=\"flex items-center gap-2 hover:bg-gray-100 rounded-md px-1.5 py-1 transition-colors\">\n {user?.picture ? (\n <img src={user.picture} alt=\"\" className=\"h-6 w-6 rounded-full\" />\n ) : (\n <div className=\"h-6 w-6 rounded-full bg-gray-200\" />\n )}\n <div className=\"text-left\">\n <p className=\"text-[11px] font-medium text-gray-900\">{user?.name}</p>\n <p className=\"text-[10px] text-gray-500\">{user?.email}</p>\n </div>\n </button>\n </div>\n </div>\n\n {/* Messages */}\n <div ref={scrollRef} className=\"flex-1 overflow-y-auto px-4 py-4 space-y-4\">\n {messages.length === 0 && (\n <div className=\"flex items-center justify-center h-full text-center\">\n <div>\n <div className=\"h-12 w-12 mx-auto mb-3 rounded-xl bg-gradient-to-br from-blue-500/10 via-purple-500/10 to-pink-500/10 flex items-center justify-center\">\n <svg className=\"h-6 w-6 text-purple-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z\" /></svg>\n </div>\n <p className=\"text-sm text-gray-500\">Ask Gemini anything</p>\n <p className=\"text-xs text-gray-400 mt-1\">Powered by Google AI</p>\n </div>\n </div>\n )}\n {messages.map((msg, i) => (\n <div key={i} className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}>\n <div className={`max-w-[80%] rounded-2xl px-4 py-2.5 ${msg.role === 'user' ? 'bg-blue-600 text-white' : 'bg-gray-100 text-gray-900'}`}>\n <div className=\"text-sm whitespace-pre-wrap leading-relaxed\">{msg.content}</div>\n <p className={`text-[10px] mt-1 ${msg.role === 'user' ? 'text-blue-200' : 'text-gray-400'}`}>\n {msg.timestamp.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })}\n </p>\n </div>\n </div>\n ))}\n {loading && (\n <div className=\"flex justify-start\">\n <div className=\"bg-gray-100 rounded-2xl px-4 py-3\">\n <div className=\"flex items-center gap-1.5\">\n <div className=\"w-2 h-2 rounded-full bg-gray-400 animate-bounce\" style={{ animationDelay: '0ms' }} />\n <div className=\"w-2 h-2 rounded-full bg-gray-400 animate-bounce\" style={{ animationDelay: '150ms' }} />\n <div className=\"w-2 h-2 rounded-full bg-gray-400 animate-bounce\" style={{ animationDelay: '300ms' }} />\n </div>\n </div>\n </div>\n )}\n </div>\n\n {/* Input */}\n <div className=\"px-4 py-3 border-t border-gray-200 shrink-0\">\n <div className=\"flex items-end gap-2\">\n <textarea\n ref={inputRef}\n value={input}\n onChange={e => setInput(e.target.value)}\n onKeyDown={e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } }}\n placeholder=\"Message Gemini...\"\n rows={1}\n className=\"flex-1 rounded-xl border border-gray-300 px-4 py-2.5 text-sm resize-none focus:border-blue-500 focus:ring-blue-500 max-h-32\"\n style={{ minHeight: '42px' }}\n />\n <button onClick={sendMessage} disabled={loading || !input.trim()}\n className=\"shrink-0 bg-blue-600 text-white rounded-xl p-2.5 hover:bg-blue-700 disabled:opacity-40 transition-colors\">\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 12L3.269 3.126A59.768 59.768 0 0121.485 12 59.77 59.77 0 013.27 20.876L5.999 12zm0 0h7.5\" /></svg>\n </button>\n </div>\n </div>\n </div>\n );\n}\n"]}
|
package/dist/Preview-U72UL74H.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export { Preview as default, setPdfPreview } from './chunk-FXAOT23O.js';
|
|
2
|
-
import './chunk-KUIPWCTJ.js';
|
|
3
|
-
import './chunk-WIJ45SYD.js';
|
|
4
|
-
import './chunk-4SHZ7BZO.js';
|
|
5
|
-
import './chunk-PLGHQ7QW.js';
|
|
6
|
-
import './chunk-SSA762W5.js';
|
|
7
|
-
//# sourceMappingURL=Preview-U72UL74H.js.map
|
|
8
|
-
//# sourceMappingURL=Preview-U72UL74H.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export { Spreadsheet as default, setSpreadsheetPreview } from './chunk-MUXDKEOC.js';
|
|
2
|
-
import './chunk-GP4Y3VCB.js';
|
|
3
|
-
import './chunk-4SHZ7BZO.js';
|
|
4
|
-
import './chunk-PLGHQ7QW.js';
|
|
5
|
-
import './chunk-SSA762W5.js';
|
|
6
|
-
//# sourceMappingURL=Spreadsheet-T7Y7PRD6.js.map
|
|
7
|
-
//# sourceMappingURL=Spreadsheet-T7Y7PRD6.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/apps/_googleTasks.ts","../src/apps/TodoList.tsx"],"names":[],"mappings":"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","file":"TodoList-7JZ2SLDI.js","sourcesContent":["/**\n * Google Tasks REST helpers — used by the Todo List app to two-way sync\n * with `tasks.googleapis.com`. Mirrors the lightweight pattern used by\n * Calendar.tsx (no SDK, just `fetch` + bearer token).\n *\n * • `fetchGoogleTasks(token)` — pull all tasks from the user's\n * `@default` list and map them to local `TodoTask` shape.\n * • `pushGoogleTask(token, task)` — POST (new) or PATCH (existing).\n * • `deleteGoogleTask(token, gtaskId, listId?)` — DELETE.\n *\n * Conflict policy is last-write-wins on `updated` timestamps, owned by\n * the caller (TodoList.tsx). These helpers just talk HTTP.\n */\n\nimport type { TodoTask } from './_todoTypes';\n\nconst TASKS_API = 'https://tasks.googleapis.com/tasks/v1';\nconst DEFAULT_LIST = '@default';\n\ninterface GoogleTaskPayload {\n id?: string;\n title?: string;\n notes?: string;\n status?: 'needsAction' | 'completed';\n due?: string; // RFC 3339 timestamp — Google stores due as a date-only field but in datetime form\n updated?: string;\n completed?: string;\n deleted?: boolean;\n}\n\ninterface GoogleTasksListResponse {\n items?: GoogleTaskPayload[];\n}\n\n/** Convert YYYY-MM-DD → RFC 3339 timestamp at noon UTC (Google's\n * expected representation for date-only `due`). */\nfunction dueToIso(date: string | undefined): string | undefined {\n if (!date) return undefined;\n return `${date}T12:00:00.000Z`;\n}\n\n/** Convert RFC 3339 → YYYY-MM-DD. */\nfunction dueFromIso(iso: string | undefined): string | undefined {\n if (!iso) return undefined;\n return iso.slice(0, 10);\n}\n\nfunction mapFromGoogle(g: GoogleTaskPayload, listId: string, ts: string): TodoTask {\n return {\n id: `gtask-${g.id}`,\n name: g.title || '',\n done: g.status === 'completed',\n dueDate: dueFromIso(g.due),\n notes: g.notes,\n gtaskId: g.id,\n gtaskListId: listId,\n syncedAt: ts,\n createdAt: g.updated || ts,\n updatedAt: g.updated || ts,\n };\n}\n\nfunction mapToGoogle(task: TodoTask): GoogleTaskPayload {\n return {\n title: task.name,\n notes: task.notes,\n status: task.done ? 'completed' : 'needsAction',\n due: dueToIso(task.dueDate),\n };\n}\n\nexport async function fetchGoogleTasks(token: string, listId: string = DEFAULT_LIST): Promise<TodoTask[]> {\n const res = await fetch(`${TASKS_API}/lists/${listId}/tasks?showCompleted=true&showHidden=false&maxResults=200`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) throw new Error(`Google Tasks fetch failed: ${res.status}`);\n const data: GoogleTasksListResponse = await res.json();\n const ts = new Date().toISOString();\n return (data.items || []).filter(g => !g.deleted && g.id).map(g => mapFromGoogle(g, listId, ts));\n}\n\n/** POST a new task or PATCH an existing one (decided by `task.gtaskId`).\n * Returns the merged TodoTask with `gtaskId` / `gtaskListId` / `syncedAt` populated. */\nexport async function pushGoogleTask(token: string, task: TodoTask): Promise<TodoTask> {\n const listId = task.gtaskListId || DEFAULT_LIST;\n const payload = mapToGoogle(task);\n const isUpdate = !!task.gtaskId;\n const url = isUpdate\n ? `${TASKS_API}/lists/${listId}/tasks/${task.gtaskId}`\n : `${TASKS_API}/lists/${listId}/tasks`;\n const res = await fetch(url, {\n method: isUpdate ? 'PATCH' : 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(payload),\n });\n if (!res.ok) throw new Error(`Google Tasks push failed: ${res.status}`);\n const g: GoogleTaskPayload = await res.json();\n const ts = new Date().toISOString();\n return {\n ...task,\n gtaskId: g.id,\n gtaskListId: listId,\n syncedAt: ts,\n };\n}\n\nexport async function deleteGoogleTask(token: string, gtaskId: string, listId: string = DEFAULT_LIST): Promise<void> {\n const res = await fetch(`${TASKS_API}/lists/${listId}/tasks/${gtaskId}`, {\n method: 'DELETE',\n headers: { Authorization: `Bearer ${token}` },\n });\n // 404 means \"already gone\" — treat as success.\n if (!res.ok && res.status !== 404) throw new Error(`Google Tasks delete failed: ${res.status}`);\n}\n","import { useEffect, useMemo, useState, useCallback, useRef } from 'react';\nimport { useTodoTasks } from './_todoStore';\nimport type { TodoTask } from './_todoTypes';\nimport useGoogleAuth, { getGoogleAccessToken } from '../hooks/useGoogleAuth';\nimport { fetchGoogleTasks, pushGoogleTask, deleteGoogleTask } from './_googleTasks';\nimport { isDemoMode, getDemoTasks } from './google-demo-fixtures';\nimport toast from '../shell/toast';\nimport { confirm } from '../shell/ConfirmDialog';\n\ntype Filter = 'today' | 'upcoming' | 'all' | 'done';\n\nconst FILTERS: { id: Filter; label: string }[] = [\n { id: 'today', label: 'Today' },\n { id: 'upcoming', label: 'Upcoming' },\n { id: 'all', label: 'All' },\n { id: 'done', label: 'Done' },\n];\n\nfunction todayStr(): string {\n return new Date().toISOString().slice(0, 10);\n}\n\nfunction fmtDueLabel(due: string): string {\n const d = new Date(due + 'T00:00:00');\n const today = new Date(); today.setHours(0, 0, 0, 0);\n const diffDays = Math.round((d.getTime() - today.getTime()) / (24 * 3600 * 1000));\n if (diffDays === 0) return 'Today';\n if (diffDays === 1) return 'Tomorrow';\n if (diffDays === -1) return 'Yesterday';\n if (diffDays > 0 && diffDays < 7) return d.toLocaleDateString(undefined, { weekday: 'short' });\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n}\n\nfunction isOverdue(t: TodoTask): boolean {\n return !t.done && !!t.dueDate && t.dueDate < todayStr();\n}\n\nexport default function TodoList() {\n const { tasks, addTask, updateTask, removeTask, toggleDone, setAllTasks } = useTodoTasks();\n const google = useGoogleAuth();\n const [filter, setFilter] = useState<Filter>('today');\n const [editingId, setEditingId] = useState<string | null>(null);\n const [adding, setAdding] = useState(false);\n const [syncing, setSyncing] = useState(false);\n const [lastSync, setLastSync] = useState<string | null>(null);\n const demoMode = isDemoMode();\n\n // ── Demo-mode seed ──\n // First mount in demo mode and the user has no tasks yet → seed with\n // the canned `getDemoTasks()` list so the UI isn't empty when there's\n // no Google connection.\n const seededRef = useRef(false);\n useEffect(() => {\n if (seededRef.current) return;\n seededRef.current = true;\n if (demoMode && !google.isConnected && tasks.length === 0) {\n setAllTasks(getDemoTasks());\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // ── Google Tasks pull (on mount + manual sync button) ──\n const syncFromGoogle = useCallback(async () => {\n const token = getGoogleAccessToken();\n if (!token) { toast.info('Connect Google to sync tasks.'); return; }\n setSyncing(true);\n try {\n const remote = await fetchGoogleTasks(token);\n // Merge: keep local-only tasks (no gtaskId), replace synced ones\n // by gtaskId with the remote version (last-write-wins on\n // updatedAt vs Google's `updated`).\n const remoteByGid = new Map(remote.map(t => [t.gtaskId!, t]));\n const merged: TodoTask[] = [];\n for (const local of tasks) {\n if (!local.gtaskId) { merged.push(local); continue; }\n const r = remoteByGid.get(local.gtaskId);\n if (!r) {\n // Existed remotely before — Google deleted it. Drop locally.\n continue;\n }\n // Keep local id stable; absorb fresh fields.\n merged.push({\n ...local,\n name: r.name,\n done: r.done,\n dueDate: r.dueDate,\n notes: r.notes,\n syncedAt: r.syncedAt,\n updatedAt: r.updatedAt,\n });\n remoteByGid.delete(local.gtaskId);\n }\n // Anything left in the map is new from Google — append.\n for (const r of remoteByGid.values()) merged.push(r);\n setAllTasks(merged);\n setLastSync(new Date().toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }));\n toast.info(`Synced ${remote.length} tasks from Google`);\n } catch (e: any) {\n toast.info(`Sync failed: ${e?.message ?? 'unknown error'}`);\n } finally {\n setSyncing(false);\n }\n }, [tasks, setAllTasks]);\n\n // Auto-pull on mount when connected.\n useEffect(() => {\n if (google.isConnected) syncFromGoogle();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [google.isConnected]);\n\n // ── Push local changes to Google (fire-and-forget) ──\n const pushIfConnected = useCallback(async (task: TodoTask) => {\n const token = getGoogleAccessToken();\n if (!token || !google.isConnected) return;\n try {\n const synced = await pushGoogleTask(token, task);\n if (synced.gtaskId !== task.gtaskId || synced.gtaskListId !== task.gtaskListId) {\n updateTask(task.id, { gtaskId: synced.gtaskId, gtaskListId: synced.gtaskListId, syncedAt: synced.syncedAt });\n } else {\n updateTask(task.id, { syncedAt: synced.syncedAt });\n }\n } catch (e: any) {\n toast.info(`Couldn't push to Google: ${e?.message ?? 'unknown'}`);\n }\n }, [google.isConnected, updateTask]);\n\n // ── Filtered view ──\n const today = todayStr();\n const visible = useMemo(() => {\n const sorted = [...tasks].sort((a, b) => {\n // Done tasks always sink to the bottom.\n if (a.done !== b.done) return a.done ? 1 : -1;\n // Overdue first, then today, then by due date, then by createdAt.\n const aOver = isOverdue(a), bOver = isOverdue(b);\n if (aOver !== bOver) return aOver ? -1 : 1;\n if (a.dueDate && b.dueDate && a.dueDate !== b.dueDate) return a.dueDate < b.dueDate ? -1 : 1;\n if (!!a.dueDate !== !!b.dueDate) return a.dueDate ? -1 : 1;\n return a.createdAt.localeCompare(b.createdAt);\n });\n if (filter === 'today') return sorted.filter(t => !t.done && (t.dueDate === today || isOverdue(t)));\n if (filter === 'upcoming') return sorted.filter(t => !t.done && t.dueDate && t.dueDate > today);\n if (filter === 'done') return sorted.filter(t => t.done);\n return sorted;\n }, [tasks, filter, today]);\n\n const counts = useMemo(() => ({\n today: tasks.filter(t => !t.done && (t.dueDate === today || isOverdue(t))).length,\n upcoming: tasks.filter(t => !t.done && t.dueDate && t.dueDate > today).length,\n all: tasks.filter(t => !t.done).length,\n done: tasks.filter(t => t.done).length,\n }), [tasks, today]);\n\n // ── Action handlers ──\n const handleAdd = (input: { name: string; dueDate?: string; estimated?: number }) => {\n const id = addTask(input);\n setAdding(false);\n const fresh = { ...input, id, done: false, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() } as TodoTask;\n pushIfConnected(fresh);\n };\n\n const handleToggle = (id: string) => {\n const t = tasks.find(x => x.id === id);\n if (!t) return;\n toggleDone(id);\n pushIfConnected({ ...t, done: !t.done });\n };\n\n const handleEdit = (id: string, patch: Partial<TodoTask>) => {\n updateTask(id, patch);\n const t = tasks.find(x => x.id === id);\n if (t) pushIfConnected({ ...t, ...patch });\n };\n\n const handleDelete = async (id: string) => {\n const t = tasks.find(x => x.id === id);\n if (!t) return;\n const ok = await confirm({\n title: 'Delete this task?',\n message: `“${t.name}” will be removed from the Todo List, the Pomodoro widget, and Google Tasks (if synced). This can't be undone.`,\n confirmLabel: 'Delete',\n variant: 'danger',\n });\n if (!ok) return;\n removeTask(id);\n setEditingId(null);\n if (t.gtaskId) {\n const token = getGoogleAccessToken();\n if (token) {\n try { await deleteGoogleTask(token, t.gtaskId, t.gtaskListId); }\n catch (e: any) { toast.info(`Couldn't delete on Google: ${e?.message ?? 'unknown'}`); }\n }\n }\n };\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* Header — filter pills + sync chip + add button */}\n <div className=\"flex items-center justify-between gap-3 px-4 py-2 border-b border-gray-200 shrink-0\">\n <div className=\"flex items-center gap-1\">\n {FILTERS.map(f => {\n const count = counts[f.id];\n const active = filter === f.id;\n return (\n <button key={f.id} onClick={() => setFilter(f.id)}\n className={`px-2.5 py-1 text-xs font-medium rounded-md transition-colors flex items-center gap-1.5 ${active ? 'bg-blue-600 text-white' : 'text-gray-600 hover:bg-gray-100'}`}>\n <span>{f.label}</span>\n <span className={`text-[10px] tabular-nums ${active ? 'text-white/80' : 'text-gray-400'}`}>{count}</span>\n </button>\n );\n })}\n </div>\n <div className=\"flex items-center gap-2\">\n {google.isConnected ? (\n <button onClick={syncFromGoogle} disabled={syncing}\n title={lastSync ? `Last synced ${lastSync}` : 'Sync with Google Tasks'}\n className=\"flex items-center gap-1.5 px-2 py-1 text-[11px] rounded-md border border-gray-200 text-gray-600 hover:bg-gray-50 disabled:opacity-50\">\n <span className=\"h-1.5 w-1.5 rounded-full bg-green-500\" />\n <span>Google</span>\n <svg className={`h-3 w-3 ${syncing ? 'animate-spin' : ''}`} fill=\"none\" stroke=\"currentColor\" strokeWidth={2} viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n </button>\n ) : (\n <button onClick={() => window.dispatchEvent(new Event('open-google-connect'))}\n className=\"flex items-center gap-1.5 px-2 py-1 text-[11px] rounded-md border border-gray-200 text-gray-500 hover:bg-gray-50\">\n Connect Google Tasks\n </button>\n )}\n <button onClick={() => setAdding(a => !a)}\n className=\"flex items-center gap-1 px-2.5 py-1 text-xs font-medium rounded-md bg-blue-600 text-white hover:bg-blue-700\">\n <svg className=\"h-3.5 w-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2.5}>\n <path strokeLinecap=\"round\" d=\"M12 5v14M5 12h14\" />\n </svg>\n <span>Add</span>\n </button>\n </div>\n </div>\n\n {/* List */}\n <div className=\"flex-1 overflow-y-auto\">\n {adding && (\n <AddTaskRow onSubmit={handleAdd} onCancel={() => setAdding(false)} />\n )}\n {visible.length === 0 && !adding && (\n <div className=\"flex flex-col items-center justify-center h-full text-center px-6 text-gray-400\">\n <svg className=\"h-10 w-10 mb-2 text-gray-300\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.5}>\n <rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"2\" />\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9 12l2 2 4-4\" />\n </svg>\n <p className=\"text-sm\">{filter === 'done' ? 'No completed tasks yet.' : 'Nothing here. Add a task to get started.'}</p>\n </div>\n )}\n {visible.map(task => (\n <TaskRow\n key={task.id}\n task={task}\n editing={editingId === task.id}\n onToggle={() => handleToggle(task.id)}\n onClick={() => setEditingId(editingId === task.id ? null : task.id)}\n onSave={(patch) => { handleEdit(task.id, patch); setEditingId(null); }}\n onDelete={() => handleDelete(task.id)}\n onCancelEdit={() => setEditingId(null)}\n />\n ))}\n </div>\n </div>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────\n// Row + add form\n// ─────────────────────────────────────────────────────────────────────\n\nfunction TaskRow({ task, editing, onToggle, onClick, onSave, onDelete, onCancelEdit }: {\n task: TodoTask;\n editing: boolean;\n onToggle: () => void;\n onClick: () => void;\n onSave: (patch: Partial<TodoTask>) => void;\n onDelete: () => void;\n onCancelEdit: () => void;\n}) {\n if (editing) {\n return <EditDrawer task={task} onSave={onSave} onCancel={onCancelEdit} onDelete={onDelete} />;\n }\n const dueLabel = task.dueDate ? fmtDueLabel(task.dueDate) : null;\n const overdue = isOverdue(task);\n const pomos = (task.estimated || task.completed)\n ? `${task.completed ?? 0}/${task.estimated ?? '?'}`\n : null;\n return (\n <div\n onClick={onClick}\n className=\"flex items-center gap-3 px-4 py-2.5 border-b border-gray-200 cursor-pointer hover:bg-gray-50 transition-colors\">\n <button onClick={(e) => { e.stopPropagation(); onToggle(); }}\n className=\"shrink-0\">\n {task.done ? (\n <svg className=\"h-5 w-5 text-blue-600\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path d=\"M10 0a10 10 0 100 20 10 10 0 000-20zm-1 14.5l-4.5-4.5 1.4-1.4 3.1 3.1 6.1-6.1 1.4 1.4z\" />\n </svg>\n ) : (\n <svg className=\"h-5 w-5 text-gray-300 hover:text-gray-500\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} viewBox=\"0 0 24 24\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n </svg>\n )}\n </button>\n <span className={`flex-1 text-sm truncate ${task.done ? 'line-through text-gray-400' : 'text-gray-800'}`}>\n {task.name || <span className=\"italic text-gray-400\">(untitled)</span>}\n </span>\n {pomos && (\n <span className=\"shrink-0 text-[11px] tabular-nums text-gray-500\" title=\"Pomodoros completed / estimated\">\n 🍅 {pomos}\n </span>\n )}\n {dueLabel && (\n <span className={`shrink-0 text-[11px] font-medium px-1.5 py-0.5 rounded ${overdue ? 'bg-red-100 text-red-700' : task.dueDate === todayStr() ? 'bg-blue-100 text-blue-700' : 'bg-gray-100 text-gray-600'}`}>\n {dueLabel}\n </span>\n )}\n {task.gtaskId && (\n <span title=\"Synced with Google Tasks\" className=\"h-1.5 w-1.5 rounded-full bg-green-500 shrink-0\" />\n )}\n </div>\n );\n}\n\nfunction EditDrawer({ task, onSave, onCancel, onDelete }: {\n task: TodoTask;\n onSave: (patch: Partial<TodoTask>) => void;\n onCancel: () => void;\n onDelete: () => void;\n}) {\n const [name, setName] = useState(task.name);\n const [dueDate, setDueDate] = useState(task.dueDate || '');\n const [estimated, setEstimated] = useState(task.estimated ?? 0);\n const [notes, setNotes] = useState(task.notes || '');\n\n const submit = () => onSave({\n name: name.trim(),\n dueDate: dueDate || undefined,\n estimated: estimated > 0 ? estimated : undefined,\n notes: notes.trim() || undefined,\n });\n\n return (\n <div className=\"px-4 py-3 border-b border-gray-200 bg-gray-50\">\n <input autoFocus value={name} onChange={e => setName(e.target.value)}\n onKeyDown={e => { if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) submit(); if (e.key === 'Escape') onCancel(); }}\n placeholder=\"Task name\"\n className=\"w-full text-sm font-medium bg-white border border-gray-200 rounded px-2 py-1.5 focus:outline-none focus:ring-1 focus:ring-blue-500\" />\n <div className=\"grid grid-cols-2 gap-2 mt-2\">\n <label className=\"flex flex-col text-[10px] font-semibold text-gray-500 uppercase tracking-wide\">\n Due\n <input type=\"date\" value={dueDate} onChange={e => setDueDate(e.target.value)}\n className=\"mt-0.5 text-sm bg-white border border-gray-200 rounded px-2 py-1 text-gray-800 focus:outline-none focus:ring-1 focus:ring-blue-500\" />\n </label>\n <label className=\"flex flex-col text-[10px] font-semibold text-gray-500 uppercase tracking-wide\">\n Est. pomos\n <input type=\"number\" min={0} max={20} value={estimated}\n onChange={e => setEstimated(Math.max(0, Math.min(20, parseInt(e.target.value, 10) || 0)))}\n className=\"mt-0.5 text-sm bg-white border border-gray-200 rounded px-2 py-1 text-gray-800 focus:outline-none focus:ring-1 focus:ring-blue-500\" />\n </label>\n </div>\n <textarea value={notes} onChange={e => setNotes(e.target.value)}\n placeholder=\"Notes (optional)\"\n rows={2}\n className=\"mt-2 w-full text-xs bg-white border border-gray-200 rounded px-2 py-1.5 text-gray-700 focus:outline-none focus:ring-1 focus:ring-blue-500 resize-none\" />\n <div className=\"flex items-center justify-between mt-2\">\n <button onClick={onDelete} className=\"text-xs text-red-600 hover:text-red-700\">\n Delete\n </button>\n <div className=\"flex gap-2\">\n <button onClick={onCancel} className=\"px-3 py-1 text-xs text-gray-600 hover:bg-gray-100 rounded\">Cancel</button>\n <button onClick={submit} className=\"px-3 py-1 text-xs font-semibold bg-blue-600 text-white rounded hover:bg-blue-700\">Save</button>\n </div>\n </div>\n </div>\n );\n}\n\nfunction AddTaskRow({ onSubmit, onCancel }: {\n onSubmit: (input: { name: string; dueDate?: string; estimated?: number }) => void;\n onCancel: () => void;\n}) {\n const [name, setName] = useState('');\n const [dueDate, setDueDate] = useState('');\n const [estimated, setEstimated] = useState(0);\n\n const submit = () => {\n const trimmed = name.trim();\n if (!trimmed) return;\n onSubmit({\n name: trimmed,\n dueDate: dueDate || undefined,\n estimated: estimated > 0 ? estimated : undefined,\n });\n };\n\n return (\n <div className=\"px-4 py-3 border-b border-gray-200 bg-blue-50/40\">\n <input autoFocus value={name} onChange={e => setName(e.target.value)}\n onKeyDown={e => { if (e.key === 'Enter') submit(); if (e.key === 'Escape') onCancel(); }}\n placeholder=\"What do you need to do?\"\n className=\"w-full text-sm font-medium bg-white border border-gray-200 rounded px-2 py-1.5 focus:outline-none focus:ring-1 focus:ring-blue-500\" />\n <div className=\"flex items-center gap-2 mt-2\">\n <label className=\"flex items-center gap-1.5 text-[10px] font-semibold text-gray-500 uppercase tracking-wide\">\n Due\n <input type=\"date\" value={dueDate} onChange={e => setDueDate(e.target.value)}\n className=\"text-xs bg-white border border-gray-200 rounded px-1.5 py-0.5 text-gray-800 focus:outline-none focus:ring-1 focus:ring-blue-500\" />\n </label>\n <label className=\"flex items-center gap-1.5 text-[10px] font-semibold text-gray-500 uppercase tracking-wide\">\n Est. pomos\n <input type=\"number\" min={0} max={20} value={estimated}\n onChange={e => setEstimated(Math.max(0, Math.min(20, parseInt(e.target.value, 10) || 0)))}\n className=\"w-12 text-xs bg-white border border-gray-200 rounded px-1.5 py-0.5 text-right text-gray-800 focus:outline-none focus:ring-1 focus:ring-blue-500\" />\n </label>\n <div className=\"flex-1\" />\n <button onClick={onCancel} className=\"px-3 py-1 text-xs text-gray-600 hover:bg-gray-100 rounded\">Cancel</button>\n <button onClick={submit} className=\"px-3 py-1 text-xs font-semibold bg-blue-600 text-white rounded hover:bg-blue-700\">Add</button>\n </div>\n </div>\n );\n}\n"]}
|