react-os-shell 0.2.67 → 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.
Files changed (69) hide show
  1. package/README.md +35 -15
  2. package/dist/{Browser-OH3E6TIZ.js → Browser-H5KDP5OH.js} +3 -3
  3. package/dist/{Browser-OH3E6TIZ.js.map → Browser-H5KDP5OH.js.map} +1 -1
  4. package/dist/{Calculator-DBSWD2RM.js → Calculator-QQ7NF53Q.js} +4 -4
  5. package/dist/{Calculator-DBSWD2RM.js.map → Calculator-QQ7NF53Q.js.map} +1 -1
  6. package/dist/{Calendar-5S3MOTVB.js → Calendar-J6L7FGHS.js} +175 -108
  7. package/dist/Calendar-J6L7FGHS.js.map +1 -0
  8. package/dist/{CurrencyConverter-TDAW7VME.js → CurrencyConverter-YHOGBUPH.js} +4 -4
  9. package/dist/{CurrencyConverter-TDAW7VME.js.map → CurrencyConverter-YHOGBUPH.js.map} +1 -1
  10. package/dist/{Documents-R4DZLBJU.js → Documents-6DYALASM.js} +3 -3
  11. package/dist/{Documents-R4DZLBJU.js.map → Documents-6DYALASM.js.map} +1 -1
  12. package/dist/Email-U2U5Z4DL.js +475 -0
  13. package/dist/Email-U2U5Z4DL.js.map +1 -0
  14. package/dist/Files-T62M4V5I.js +11 -0
  15. package/dist/{Files-XD7SWQSG.js.map → Files-T62M4V5I.js.map} +1 -1
  16. package/dist/{Minesweeper-YWYMJQN6.js → Minesweeper-S2JHXYLX.js} +3 -3
  17. package/dist/{Minesweeper-YWYMJQN6.js.map → Minesweeper-S2JHXYLX.js.map} +1 -1
  18. package/dist/{Notepad-F3BJYZJL.js → Notepad-2YF7X3XO.js} +3 -3
  19. package/dist/{Notepad-F3BJYZJL.js.map → Notepad-2YF7X3XO.js.map} +1 -1
  20. package/dist/{PomodoroTimer-VLPDNV7W.js → PomodoroTimer-3J7Z3NVQ.js} +4 -4
  21. package/dist/{PomodoroTimer-VLPDNV7W.js.map → PomodoroTimer-3J7Z3NVQ.js.map} +1 -1
  22. package/dist/Preview-WM6ZP5PZ.js +8 -0
  23. package/dist/{Preview-XOCYZM4T.js.map → Preview-WM6ZP5PZ.js.map} +1 -1
  24. package/dist/Spreadsheet-ZIE2SXAF.js +6 -0
  25. package/dist/{Spreadsheet-7NEC5RBR.js.map → Spreadsheet-ZIE2SXAF.js.map} +1 -1
  26. package/dist/{TodoList-7JZ2SLDI.js → TodoList-QGXCDEIE.js} +18 -204
  27. package/dist/TodoList-QGXCDEIE.js.map +1 -0
  28. package/dist/{Weather-HLXHNBM4.js → Weather-2GFPSZ5V.js} +4 -4
  29. package/dist/{Weather-HLXHNBM4.js.map → Weather-2GFPSZ5V.js.map} +1 -1
  30. package/dist/{WorldClock-HIWKHF6U.js → WorldClock-P4JR5I6X.js} +4 -4
  31. package/dist/{WorldClock-HIWKHF6U.js.map → WorldClock-P4JR5I6X.js.map} +1 -1
  32. package/dist/apps/index.d.ts +2 -5
  33. package/dist/apps/index.js +23 -26
  34. package/dist/apps/index.js.map +1 -1
  35. package/dist/chunk-57B3WALN.js +114 -0
  36. package/dist/chunk-57B3WALN.js.map +1 -0
  37. package/dist/{chunk-GAC6D4LN.js → chunk-62FC2FHC.js} +94 -23
  38. package/dist/chunk-62FC2FHC.js.map +1 -0
  39. package/dist/{chunk-HAUVCQNK.js → chunk-ATQVRDDQ.js} +3 -3
  40. package/dist/{chunk-HAUVCQNK.js.map → chunk-ATQVRDDQ.js.map} +1 -1
  41. package/dist/{chunk-GP4Y3VCB.js → chunk-KMGWSDEI.js} +480 -4
  42. package/dist/chunk-KMGWSDEI.js.map +1 -0
  43. package/dist/{chunk-KFRHMW57.js → chunk-O6FJZAFM.js} +3 -3
  44. package/dist/{chunk-KFRHMW57.js.map → chunk-O6FJZAFM.js.map} +1 -1
  45. package/dist/{chunk-VG5ZM3QD.js → chunk-SEV7UXGN.js} +4 -4
  46. package/dist/{chunk-VG5ZM3QD.js.map → chunk-SEV7UXGN.js.map} +1 -1
  47. package/dist/{chunk-EXYMMWOS.js → chunk-ZBRFMK3E.js} +4 -4
  48. package/dist/{chunk-EXYMMWOS.js.map → chunk-ZBRFMK3E.js.map} +1 -1
  49. package/dist/index.d.ts +55 -1
  50. package/dist/index.js +242 -136
  51. package/dist/index.js.map +1 -1
  52. package/package.json +10 -3
  53. package/dist/Calendar-5S3MOTVB.js.map +0 -1
  54. package/dist/Email-OAQ76CET.js +0 -1883
  55. package/dist/Email-OAQ76CET.js.map +0 -1
  56. package/dist/Files-XD7SWQSG.js +0 -12
  57. package/dist/GeminiChat-XTEBZIVK.js +0 -184
  58. package/dist/GeminiChat-XTEBZIVK.js.map +0 -1
  59. package/dist/Preview-XOCYZM4T.js +0 -8
  60. package/dist/Spreadsheet-7NEC5RBR.js +0 -7
  61. package/dist/TodoList-7JZ2SLDI.js.map +0 -1
  62. package/dist/chunk-5VXRBUEH.js +0 -104
  63. package/dist/chunk-5VXRBUEH.js.map +0 -1
  64. package/dist/chunk-62EP7CNW.js +0 -485
  65. package/dist/chunk-62EP7CNW.js.map +0 -1
  66. package/dist/chunk-GAC6D4LN.js.map +0 -1
  67. package/dist/chunk-GP4Y3VCB.js.map +0 -1
  68. package/dist/chunk-MVWEL34Y.js +0 -209
  69. package/dist/chunk-MVWEL34Y.js.map +0 -1
@@ -1,9 +1,8 @@
1
- import { isDemoMode, getDemoCalendarEvents } from './chunk-5VXRBUEH.js';
2
1
  import { useTodoTasks } from './chunk-25L4DIKH.js';
3
- import { useGoogleAuth, getGoogleAccessToken } from './chunk-MVWEL34Y.js';
2
+ import { useMailAuth, getMailClient } from './chunk-57B3WALN.js';
4
3
  import { useShellPrefs } from './chunk-36VM54SC.js';
5
4
  import { toast_default } from './chunk-WIJ45SYD.js';
6
- import { Modal, ModalActions } from './chunk-GAC6D4LN.js';
5
+ import { Modal, ModalActions } from './chunk-62FC2FHC.js';
7
6
  import './chunk-PLGHQ7QW.js';
8
7
  import './chunk-SSA762W5.js';
9
8
  import { useState, useMemo, useEffect, useCallback } from 'react';
@@ -58,15 +57,42 @@ function getWeekDays(date) {
58
57
  }
59
58
  return days;
60
59
  }
60
+ function davToLocal(ev, calendarId) {
61
+ const startIso = ev.start;
62
+ const endIso = ev.end;
63
+ const startDate = startIso.slice(0, 10);
64
+ const startTime = ev.allDay ? void 0 : startIso.slice(11, 16);
65
+ const endTime = ev.allDay ? void 0 : endIso.slice(11, 16);
66
+ return {
67
+ id: `caldav-${calendarId}-${ev.uid}`,
68
+ title: ev.summary || "(No title)",
69
+ date: startDate,
70
+ start_time: startTime,
71
+ end_time: endTime,
72
+ color: "blue",
73
+ all_day: ev.allDay,
74
+ description: ev.description || void 0,
75
+ _caldav: { calendarId, eventUid: ev.uid, etag: ev.etag }
76
+ };
77
+ }
78
+ function toDavInput(evt) {
79
+ const start = evt.all_day ? evt.date : `${evt.date}T${evt.start_time || "09:00"}:00`;
80
+ const end = evt.all_day ? evt.date : `${evt.date}T${evt.end_time || "10:00"}:00`;
81
+ return {
82
+ summary: evt.title,
83
+ description: evt.description,
84
+ start: new Date(start).toISOString(),
85
+ end: new Date(end).toISOString(),
86
+ allDay: !!evt.all_day
87
+ };
88
+ }
61
89
  function Calendar() {
62
90
  const { prefs, save } = useShellPrefs();
63
- const google = useGoogleAuth();
91
+ const { isConnected, capabilities } = useMailAuth();
92
+ const caldavEnabled = isConnected && capabilities?.caldav === true;
64
93
  const localEvents = prefs.calendar_events || [];
65
- const [googleEvents, setGoogleEvents] = useState([]);
66
- const demoEvents = useMemo(
67
- () => isDemoMode() && !google.isConnected ? getDemoCalendarEvents() : [],
68
- [google.isConnected]
69
- );
94
+ const [calendars, setCalendars] = useState([]);
95
+ const [caldavEvents, setCaldavEvents] = useState([]);
70
96
  const { tasks: todoTasks, toggleDone: toggleTodoDone } = useTodoTasks();
71
97
  const todoEvents = useMemo(
72
98
  () => todoTasks.filter((t) => !!t.dueDate).map((t) => ({
@@ -74,8 +100,6 @@ function Calendar() {
74
100
  title: t.name,
75
101
  date: t.dueDate,
76
102
  color: "gray",
77
- // Marker fields consumed by MonthView / WeekView to render a
78
- // checkbox affordance instead of the regular event button.
79
103
  _todo: true,
80
104
  _todoId: t.id,
81
105
  _done: t.done
@@ -83,63 +107,115 @@ function Calendar() {
83
107
  [todoTasks]
84
108
  );
85
109
  const events = useMemo(
86
- () => [...localEvents, ...googleEvents, ...demoEvents, ...todoEvents],
87
- [localEvents, googleEvents, demoEvents, todoEvents]
110
+ () => [...localEvents, ...caldavEvents, ...todoEvents],
111
+ [localEvents, caldavEvents, todoEvents]
88
112
  );
89
113
  const today = /* @__PURE__ */ new Date();
90
114
  const [currentDate, setCurrentDate] = useState(new Date(today.getFullYear(), today.getMonth(), 1));
91
- useEffect(() => {
92
- const token = getGoogleAccessToken();
93
- if (!token) {
94
- setGoogleEvents([]);
95
- return;
96
- }
97
- const year = currentDate.getFullYear();
98
- const month = currentDate.getMonth();
99
- const timeMin = new Date(year, month - 1, 1).toISOString();
100
- const timeMax = new Date(year, month + 2, 0).toISOString();
101
- fetch(`https://www.googleapis.com/calendar/v3/calendars/primary/events?timeMin=${timeMin}&timeMax=${timeMax}&maxResults=250&singleEvents=true&orderBy=startTime`, {
102
- headers: { Authorization: `Bearer ${token}` }
103
- }).then((r) => r.ok ? r.json() : null).then((data) => {
104
- if (!data?.items) return;
105
- const mapped = data.items.map((item) => {
106
- const isAllDay = !!item.start?.date;
107
- const startDate = isAllDay ? item.start.date : item.start?.dateTime?.split("T")[0];
108
- const startTime = isAllDay ? void 0 : item.start?.dateTime?.split("T")[1]?.slice(0, 5);
109
- const endTime = isAllDay ? void 0 : item.end?.dateTime?.split("T")[1]?.slice(0, 5);
110
- return {
111
- id: `gcal-${item.id}`,
112
- title: item.summary || "(No title)",
113
- date: startDate,
114
- start_time: startTime,
115
- end_time: endTime,
116
- color: "blue",
117
- all_day: isAllDay,
118
- description: item.description,
119
- _google: true
120
- };
121
- });
122
- setGoogleEvents(mapped);
123
- }).catch(() => setGoogleEvents([]));
124
- }, [currentDate]);
125
115
  const [view, setView] = useState("month");
126
116
  const [editingEvent, setEditingEvent] = useState(null);
127
117
  const [newEventDate, setNewEventDate] = useState(null);
118
+ useEffect(() => {
119
+ if (!caldavEnabled) {
120
+ setCalendars([]);
121
+ return;
122
+ }
123
+ getMailClient().get("/api/calendar/calendars").then((r) => setCalendars(r.data.calendars)).catch(() => setCalendars([]));
124
+ }, [caldavEnabled]);
125
+ useEffect(() => {
126
+ if (!caldavEnabled || calendars.length === 0) {
127
+ setCaldavEvents([]);
128
+ return;
129
+ }
130
+ const y = currentDate.getFullYear();
131
+ const m = currentDate.getMonth();
132
+ const start = new Date(y, m - 1, 1).toISOString();
133
+ const end = new Date(y, m + 2, 0).toISOString();
134
+ let cancelled = false;
135
+ Promise.all(
136
+ calendars.map(
137
+ (cal) => getMailClient().get(`/api/calendar/calendars/${encodeURIComponent(cal.id)}/events`, {
138
+ params: { start, end }
139
+ }).then((r) => r.data.events.map((e) => davToLocal(e, cal.id))).catch(() => [])
140
+ )
141
+ ).then((perCalendar) => {
142
+ if (cancelled) return;
143
+ setCaldavEvents(perCalendar.flat());
144
+ });
145
+ return () => {
146
+ cancelled = true;
147
+ };
148
+ }, [caldavEnabled, calendars, currentDate]);
128
149
  const saveLocalEvents = useCallback((updated) => {
129
150
  save({ calendar_events: updated });
130
151
  }, [save]);
131
- const saveEvent = (evt) => {
132
- const existing = localEvents.find((e) => e.id === evt.id);
133
- if (existing) {
134
- saveLocalEvents(localEvents.map((e) => e.id === evt.id ? evt : e));
152
+ const saveEvent = async (evt, targetCalendarId) => {
153
+ if (evt._caldav) {
154
+ try {
155
+ const input = toDavInput(evt);
156
+ const res = await getMailClient().put(
157
+ `/api/calendar/calendars/${encodeURIComponent(evt._caldav.calendarId)}/events/${encodeURIComponent(evt._caldav.eventUid)}`,
158
+ input,
159
+ { headers: { "If-Match": evt._caldav.etag } }
160
+ );
161
+ setCaldavEvents((prev) => prev.map(
162
+ (e) => e.id === evt.id ? { ...evt, _caldav: { ...evt._caldav, etag: res.data.etag } } : e
163
+ ));
164
+ toast_default.success("Event updated");
165
+ } catch (err) {
166
+ const status = err?.response?.status;
167
+ if (status === 409) {
168
+ toast_default.error("Event was modified elsewhere \u2014 refresh to see latest");
169
+ } else {
170
+ toast_default.error(extractError(err));
171
+ }
172
+ return;
173
+ }
174
+ } else if (targetCalendarId) {
175
+ try {
176
+ const input = toDavInput(evt);
177
+ const res = await getMailClient().post(
178
+ `/api/calendar/calendars/${encodeURIComponent(targetCalendarId)}/events`,
179
+ input
180
+ );
181
+ const newEvt = {
182
+ ...evt,
183
+ id: `caldav-${targetCalendarId}-${res.data.uid}`,
184
+ _caldav: { calendarId: targetCalendarId, eventUid: res.data.uid, etag: res.data.etag }
185
+ };
186
+ setCaldavEvents((prev) => [...prev, newEvt]);
187
+ toast_default.success("Event created");
188
+ } catch (err) {
189
+ toast_default.error(extractError(err));
190
+ return;
191
+ }
135
192
  } else {
136
- saveLocalEvents([...localEvents, evt]);
193
+ const existing = localEvents.find((e) => e.id === evt.id);
194
+ if (existing) {
195
+ saveLocalEvents(localEvents.map((e) => e.id === evt.id ? evt : e));
196
+ } else {
197
+ saveLocalEvents([...localEvents, evt]);
198
+ }
137
199
  }
138
200
  setEditingEvent(null);
139
201
  setNewEventDate(null);
140
202
  };
141
- const deleteEvent = (id) => {
142
- saveLocalEvents(localEvents.filter((e) => e.id !== id));
203
+ const deleteEvent = async (evt) => {
204
+ if (evt._caldav) {
205
+ try {
206
+ await getMailClient().delete(
207
+ `/api/calendar/calendars/${encodeURIComponent(evt._caldav.calendarId)}/events/${encodeURIComponent(evt._caldav.eventUid)}`,
208
+ { headers: { "If-Match": evt._caldav.etag } }
209
+ );
210
+ setCaldavEvents((prev) => prev.filter((e) => e.id !== evt.id));
211
+ toast_default.success("Event deleted");
212
+ } catch (err) {
213
+ toast_default.error(extractError(err));
214
+ return;
215
+ }
216
+ } else {
217
+ saveLocalEvents(localEvents.filter((e) => e.id !== evt.id));
218
+ }
143
219
  setEditingEvent(null);
144
220
  };
145
221
  const goToday = () => setCurrentDate(new Date(today.getFullYear(), today.getMonth(), 1));
@@ -196,45 +272,15 @@ function Calendar() {
196
272
  /* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-gray-900", children: monthLabel })
197
273
  ] }),
198
274
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
199
- google.isConnected ? /* @__PURE__ */ jsxs(
200
- "button",
275
+ /* @__PURE__ */ jsx(
276
+ "span",
201
277
  {
202
- onClick: () => window.dispatchEvent(new Event("open-google-connect")),
203
- title: "Google Services",
204
- className: "flex items-center gap-2 hover:bg-gray-50 rounded-md px-1.5 py-1 transition-colors",
205
- children: [
206
- google.user?.picture ? /* @__PURE__ */ jsx("img", { src: google.user.picture, alt: "", className: "h-6 w-6 rounded-full" }) : /* @__PURE__ */ jsx("div", { className: "h-6 w-6 rounded-full bg-gray-200" }),
207
- /* @__PURE__ */ jsxs("div", { className: "text-left", children: [
208
- /* @__PURE__ */ jsx("p", { className: "text-[11px] font-medium text-gray-900", children: google.user?.name }),
209
- /* @__PURE__ */ jsx("p", { className: "text-[10px] text-gray-500", children: google.user?.email })
210
- ] })
211
- ]
212
- }
213
- ) : /* @__PURE__ */ jsxs(
214
- "button",
215
- {
216
- onClick: () => {
217
- if (!google.hasClientId) {
218
- const id = prompt("Enter your Google OAuth Client ID\n\nCreate one at console.cloud.google.com > APIs > Credentials > OAuth 2.0 Client ID (Web application)");
219
- if (id?.trim()) google.setClientId(id.trim());
220
- return;
221
- }
222
- google.connect();
223
- },
224
- disabled: google.loading,
225
- className: "inline-flex items-center gap-1.5 border border-gray-300 bg-white rounded-md px-2 py-1 text-[10px] font-medium text-gray-600 hover:bg-gray-50 transition-colors disabled:opacity-50",
226
- children: [
227
- /* @__PURE__ */ jsxs("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", children: [
228
- /* @__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" }),
229
- /* @__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" }),
230
- /* @__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" }),
231
- /* @__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" })
232
- ] }),
233
- google.loading ? "Connecting..." : "Connect Google Calendar"
234
- ]
278
+ onClick: () => window.dispatchEvent(new Event("open-mail-connect")),
279
+ className: "text-[11px] text-gray-600 cursor-pointer hover:text-gray-900",
280
+ title: "Open mail & calendar settings",
281
+ children: caldavEnabled ? `CalDAV \xB7 ${calendars.length} calendar${calendars.length === 1 ? "" : "s"}` : "CalDAV not connected"
235
282
  }
236
283
  ),
237
- google.error && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-red-500", children: google.error }),
238
284
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-gray-200" }),
239
285
  /* @__PURE__ */ jsx("div", { className: "flex gap-1", children: ["year", "month", "week"].map((v) => /* @__PURE__ */ jsx(
240
286
  "button",
@@ -286,8 +332,9 @@ function Calendar() {
286
332
  {
287
333
  event: editingEvent,
288
334
  isNew: !!newEventDate,
335
+ calendars,
289
336
  onSave: saveEvent,
290
- onDelete: deleteEvent,
337
+ onDelete: () => deleteEvent(editingEvent),
291
338
  onClose: () => {
292
339
  setEditingEvent(null);
293
340
  setNewEventDate(null);
@@ -296,21 +343,26 @@ function Calendar() {
296
343
  )
297
344
  ] });
298
345
  }
346
+ function extractError(err) {
347
+ const r = err?.response?.data?.error;
348
+ if (r) return r;
349
+ if (err instanceof Error) return err.message;
350
+ return "Unknown error";
351
+ }
299
352
  function DayEventBadge({ evt, onEventClick, onToggleTodo, compact = false }) {
300
- const e = evt;
301
- if (e._todo && e._todoId) {
353
+ if (evt._todo && evt._todoId) {
302
354
  return compact ? /* @__PURE__ */ jsxs(
303
355
  "button",
304
356
  {
305
357
  onClick: (ev) => {
306
358
  ev.stopPropagation();
307
- onToggleTodo(e._todoId);
359
+ onToggleTodo(evt._todoId);
308
360
  },
309
- title: e.title,
310
- className: `w-full text-left flex items-center gap-1 truncate rounded px-1 py-0.5 text-[10px] leading-tight font-medium hover:bg-gray-100 transition-colors ${e._done ? "text-gray-400" : "text-gray-700"}`,
361
+ title: evt.title,
362
+ className: `w-full text-left flex items-center gap-1 truncate rounded px-1 py-0.5 text-[10px] leading-tight font-medium hover:bg-gray-100 transition-colors ${evt._done ? "text-gray-400" : "text-gray-700"}`,
311
363
  children: [
312
- /* @__PURE__ */ jsx("span", { className: "shrink-0", children: e._done ? "\u2611" : "\u2610" }),
313
- /* @__PURE__ */ jsx("span", { className: `truncate ${e._done ? "line-through" : ""}`, children: e.title || "Task" })
364
+ /* @__PURE__ */ jsx("span", { className: "shrink-0", children: evt._done ? "\u2611" : "\u2610" }),
365
+ /* @__PURE__ */ jsx("span", { className: `truncate ${evt._done ? "line-through" : ""}`, children: evt.title || "Task" })
314
366
  ]
315
367
  }
316
368
  ) : /* @__PURE__ */ jsxs(
@@ -318,12 +370,12 @@ function DayEventBadge({ evt, onEventClick, onToggleTodo, compact = false }) {
318
370
  {
319
371
  onClick: (ev) => {
320
372
  ev.stopPropagation();
321
- onToggleTodo(e._todoId);
373
+ onToggleTodo(evt._todoId);
322
374
  },
323
- className: `w-full text-left flex items-center gap-2 rounded-md px-2 py-1.5 hover:bg-gray-100 transition-colors ${e._done ? "text-gray-400" : "text-gray-700"}`,
375
+ className: `w-full text-left flex items-center gap-2 rounded-md px-2 py-1.5 hover:bg-gray-100 transition-colors ${evt._done ? "text-gray-400" : "text-gray-700"}`,
324
376
  children: [
325
- /* @__PURE__ */ jsx("span", { className: "shrink-0 text-base leading-none", children: e._done ? "\u2611" : "\u2610" }),
326
- /* @__PURE__ */ jsx("span", { className: `text-xs font-medium truncate ${e._done ? "line-through" : ""}`, children: e.title || "Task" })
377
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-base leading-none", children: evt._done ? "\u2611" : "\u2610" }),
378
+ /* @__PURE__ */ jsx("span", { className: `text-xs font-medium truncate ${evt._done ? "line-through" : ""}`, children: evt.title || "Task" })
327
379
  ]
328
380
  }
329
381
  );
@@ -456,7 +508,7 @@ function WeekView({ currentDate, eventsByDate, today, onDayClick, onEventClick,
456
508
  }) })
457
509
  ] });
458
510
  }
459
- function EventEditor({ event, isNew, onSave, onDelete, onClose }) {
511
+ function EventEditor({ event, isNew, calendars, onSave, onDelete, onClose }) {
460
512
  const [title, setTitle] = useState(event.title);
461
513
  const [date, setDate] = useState(event.date);
462
514
  const [startTime, setStartTime] = useState(event.start_time || "09:00");
@@ -464,12 +516,14 @@ function EventEditor({ event, isNew, onSave, onDelete, onClose }) {
464
516
  const [color, setColor] = useState(event.color);
465
517
  const [allDay, setAllDay] = useState(event.all_day ?? false);
466
518
  const [description, setDescription] = useState(event.description || "");
519
+ const isFromCaldav = !!event._caldav;
520
+ const [target, setTarget] = useState(isFromCaldav ? event._caldav.calendarId : "local");
467
521
  const handleSave = () => {
468
522
  if (!title.trim()) {
469
523
  toast_default.error("Event title is required.");
470
524
  return;
471
525
  }
472
- onSave({
526
+ const updated = {
473
527
  ...event,
474
528
  title: title.trim(),
475
529
  date,
@@ -478,7 +532,9 @@ function EventEditor({ event, isNew, onSave, onDelete, onClose }) {
478
532
  color,
479
533
  all_day: allDay,
480
534
  description: description.trim() || void 0
481
- });
535
+ };
536
+ const targetCal = !isFromCaldav && target !== "local" ? target : void 0;
537
+ onSave(updated, targetCal);
482
538
  };
483
539
  const inp = "block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm";
484
540
  return /* @__PURE__ */ jsxs(Modal, { open: true, onClose, title: isNew ? "New Event" : "Edit Event", size: "sm", children: [
@@ -505,6 +561,17 @@ function EventEditor({ event, isNew, onSave, onDelete, onClose }) {
505
561
  /* @__PURE__ */ jsx("input", { type: "time", value: endTime, onChange: (e) => setEndTime(e.target.value), className: inp })
506
562
  ] })
507
563
  ] }),
564
+ isNew && calendars.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
565
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: "Save to" }),
566
+ /* @__PURE__ */ jsxs("select", { value: target, onChange: (e) => setTarget(e.target.value), className: inp, children: [
567
+ /* @__PURE__ */ jsx("option", { value: "local", children: "Local (this device only)" }),
568
+ calendars.map((c) => /* @__PURE__ */ jsx("option", { value: c.id, children: c.displayName }, c.id))
569
+ ] })
570
+ ] }),
571
+ isFromCaldav && /* @__PURE__ */ jsxs("p", { className: "text-[11px] text-gray-500", children: [
572
+ "From ",
573
+ calendars.find((c) => c.id === event._caldav?.calendarId)?.displayName || "CalDAV"
574
+ ] }),
508
575
  /* @__PURE__ */ jsxs("div", { children: [
509
576
  /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: "Color" }),
510
577
  /* @__PURE__ */ jsx("div", { className: "flex gap-2", children: COLORS.map((c) => /* @__PURE__ */ jsx(
@@ -521,11 +588,11 @@ function EventEditor({ event, isNew, onSave, onDelete, onClose }) {
521
588
  /* @__PURE__ */ jsx("textarea", { value: description, onChange: (e) => setDescription(e.target.value), rows: 2, className: inp, placeholder: "Optional notes..." })
522
589
  ] })
523
590
  ] }),
524
- !isNew && /* @__PURE__ */ jsx(ModalActions, { position: "left", children: /* @__PURE__ */ jsx("button", { onClick: () => onDelete(event.id), className: "text-sm text-red-600 hover:text-red-800 font-medium", children: "Delete" }) }),
591
+ !isNew && /* @__PURE__ */ jsx(ModalActions, { position: "left", children: /* @__PURE__ */ jsx("button", { onClick: onDelete, className: "text-sm text-red-600 hover:text-red-800 font-medium", children: "Delete" }) }),
525
592
  /* @__PURE__ */ jsx(ModalActions, { children: /* @__PURE__ */ jsx("button", { onClick: handleSave, className: "bg-blue-600 text-white px-4 py-2 text-sm font-medium rounded-lg hover:bg-blue-700", children: isNew ? "Create" : "Save" }) })
526
593
  ] });
527
594
  }
528
595
 
529
596
  export { Calendar as default };
530
- //# sourceMappingURL=Calendar-5S3MOTVB.js.map
531
- //# sourceMappingURL=Calendar-5S3MOTVB.js.map
597
+ //# sourceMappingURL=Calendar-J6L7FGHS.js.map
598
+ //# sourceMappingURL=Calendar-J6L7FGHS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/apps/Calendar.tsx"],"names":[],"mappings":"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","file":"Calendar-J6L7FGHS.js","sourcesContent":["import { useState, useMemo, useCallback, useEffect } from 'react';\nimport Modal, { ModalActions } from '../shell/Modal';\nimport toast from '../shell/toast';\nimport useMailAuth from '../hooks/useMailAuth';\nimport { getMailClient } from '../api/mailClient';\nimport { useShellPrefs } from '../shell/ShellPrefs';\nimport { useTodoTasks } from './_todoStore';\n\n// ── Types ──\ninterface CalDavMeta {\n calendarId: string;\n eventUid: string;\n etag: string;\n}\n\ninterface CalendarEvent {\n id: string;\n title: string;\n date: string; // YYYY-MM-DD\n start_time?: string;\n end_time?: string;\n color: string;\n description?: string;\n all_day?: boolean;\n // Internal markers (not persisted in useShellPrefs for non-local events):\n _caldav?: CalDavMeta;\n _todo?: boolean;\n _todoId?: string;\n _done?: boolean;\n}\n\ninterface DavCalendar {\n id: string;\n displayName: string;\n color: string | null;\n ctag: string;\n readOnly: boolean;\n}\n\ninterface DavEvent {\n uid: string;\n etag: string;\n url: string;\n summary: string;\n description: string | null;\n location: string | null;\n start: string;\n end: string;\n allDay: boolean;\n recurrence: string | null;\n status: string;\n}\n\ntype ViewMode = 'year' | 'month' | 'week';\n\nconst COLORS = [\n { key: 'blue', bg: 'bg-blue-500', light: 'bg-blue-100 text-blue-800', dot: 'bg-blue-500' },\n { key: 'green', bg: 'bg-green-500', light: 'bg-green-100 text-green-800', dot: 'bg-green-500' },\n { key: 'red', bg: 'bg-red-500', light: 'bg-red-100 text-red-800', dot: 'bg-red-500' },\n { key: 'purple', bg: 'bg-purple-500', light: 'bg-purple-100 text-purple-800', dot: 'bg-purple-500' },\n { key: 'orange', bg: 'bg-orange-500', light: 'bg-orange-100 text-orange-800', dot: 'bg-orange-500' },\n { key: 'pink', bg: 'bg-pink-500', light: 'bg-pink-100 text-pink-800', dot: 'bg-pink-500' },\n { key: 'yellow', bg: 'bg-yellow-500', light: 'bg-yellow-100 text-yellow-800', dot: 'bg-yellow-500' },\n { key: 'gray', bg: 'bg-gray-500', light: 'bg-gray-100 text-gray-800', dot: 'bg-gray-500' },\n];\n\nfunction getColor(key: string) {\n return COLORS.find(c => c.key === key) || COLORS[0];\n}\n\nconst DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\n\nfunction pad(n: number) { return String(n).padStart(2, '0'); }\nfunction toDateStr(d: Date) { return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`; }\n\nfunction getMonthDays(year: number, month: number) {\n const first = new Date(year, month, 1);\n const startDay = first.getDay();\n const daysInMonth = new Date(year, month + 1, 0).getDate();\n const prevDays = new Date(year, month, 0).getDate();\n\n const cells: { date: Date; isCurrentMonth: boolean }[] = [];\n for (let i = startDay - 1; i >= 0; i--) {\n cells.push({ date: new Date(year, month - 1, prevDays - i), isCurrentMonth: false });\n }\n for (let d = 1; d <= daysInMonth; d++) {\n cells.push({ date: new Date(year, month, d), isCurrentMonth: true });\n }\n const remaining = 42 - cells.length;\n for (let d = 1; d <= remaining; d++) {\n cells.push({ date: new Date(year, month + 1, d), isCurrentMonth: false });\n }\n return cells;\n}\n\nfunction getWeekDays(date: Date) {\n const start = new Date(date);\n start.setDate(start.getDate() - start.getDay());\n const days: Date[] = [];\n for (let i = 0; i < 7; i++) {\n const d = new Date(start);\n d.setDate(d.getDate() + i);\n days.push(d);\n }\n return days;\n}\n\nfunction davToLocal(ev: DavEvent, calendarId: string): CalendarEvent {\n const startIso = ev.start;\n const endIso = ev.end;\n const startDate = startIso.slice(0, 10);\n const startTime = ev.allDay ? undefined : startIso.slice(11, 16);\n const endTime = ev.allDay ? undefined : endIso.slice(11, 16);\n return {\n id: `caldav-${calendarId}-${ev.uid}`,\n title: ev.summary || '(No title)',\n date: startDate,\n start_time: startTime,\n end_time: endTime,\n color: 'blue',\n all_day: ev.allDay,\n description: ev.description || undefined,\n _caldav: { calendarId, eventUid: ev.uid, etag: ev.etag },\n };\n}\n\nfunction toDavInput(evt: CalendarEvent): {\n summary: string;\n description?: string;\n start: string;\n end: string;\n allDay: boolean;\n} {\n const start = evt.all_day\n ? evt.date\n : `${evt.date}T${evt.start_time || '09:00'}:00`;\n const end = evt.all_day\n ? evt.date\n : `${evt.date}T${evt.end_time || '10:00'}:00`;\n return {\n summary: evt.title,\n description: evt.description,\n start: new Date(start).toISOString(),\n end: new Date(end).toISOString(),\n allDay: !!evt.all_day,\n };\n}\n\n// ── Main Component ──\nexport default function Calendar() {\n const { prefs, save } = useShellPrefs();\n const { isConnected, capabilities } = useMailAuth();\n const caldavEnabled = isConnected && capabilities?.caldav === true;\n const localEvents: CalendarEvent[] = prefs.calendar_events || [];\n\n const [calendars, setCalendars] = useState<DavCalendar[]>([]);\n const [caldavEvents, setCaldavEvents] = useState<CalendarEvent[]>([]);\n\n const { tasks: todoTasks, toggleDone: toggleTodoDone } = useTodoTasks();\n const todoEvents = useMemo<CalendarEvent[]>(\n () => todoTasks\n .filter(t => !!t.dueDate)\n .map(t => ({\n id: `todo-${t.id}`,\n title: t.name,\n date: t.dueDate!,\n color: 'gray',\n _todo: true,\n _todoId: t.id,\n _done: t.done,\n })),\n [todoTasks],\n );\n\n const events = useMemo(\n () => [...localEvents, ...caldavEvents, ...todoEvents],\n [localEvents, caldavEvents, todoEvents],\n );\n\n const today = new Date();\n const [currentDate, setCurrentDate] = useState(new Date(today.getFullYear(), today.getMonth(), 1));\n const [view, setView] = useState<ViewMode>('month');\n const [editingEvent, setEditingEvent] = useState<CalendarEvent | null>(null);\n const [newEventDate, setNewEventDate] = useState<string | null>(null);\n\n // Fetch calendars once when CalDAV becomes available\n useEffect(() => {\n if (!caldavEnabled) { setCalendars([]); return; }\n getMailClient()\n .get<{ calendars: DavCalendar[] }>('/api/calendar/calendars')\n .then(r => setCalendars(r.data.calendars))\n .catch(() => setCalendars([]));\n }, [caldavEnabled]);\n\n // Fetch events when current date changes (a 3-month window for prefetch)\n useEffect(() => {\n if (!caldavEnabled || calendars.length === 0) { setCaldavEvents([]); return; }\n const y = currentDate.getFullYear();\n const m = currentDate.getMonth();\n const start = new Date(y, m - 1, 1).toISOString();\n const end = new Date(y, m + 2, 0).toISOString();\n\n let cancelled = false;\n Promise.all(\n calendars.map(cal =>\n getMailClient()\n .get<{ events: DavEvent[] }>(`/api/calendar/calendars/${encodeURIComponent(cal.id)}/events`, {\n params: { start, end },\n })\n .then(r => r.data.events.map(e => davToLocal(e, cal.id)))\n .catch(() => [] as CalendarEvent[]),\n ),\n ).then(perCalendar => {\n if (cancelled) return;\n setCaldavEvents(perCalendar.flat());\n });\n return () => { cancelled = true; };\n }, [caldavEnabled, calendars, currentDate]);\n\n const saveLocalEvents = useCallback((updated: CalendarEvent[]) => {\n save({ calendar_events: updated });\n }, [save]);\n\n const saveEvent = async (evt: CalendarEvent, targetCalendarId?: string) => {\n // Editing an existing CalDAV event\n if (evt._caldav) {\n try {\n const input = toDavInput(evt);\n const res = await getMailClient().put<{ uid: string; etag: string }>(\n `/api/calendar/calendars/${encodeURIComponent(evt._caldav.calendarId)}/events/${encodeURIComponent(evt._caldav.eventUid)}`,\n input,\n { headers: { 'If-Match': evt._caldav.etag } },\n );\n setCaldavEvents(prev => prev.map(e =>\n e.id === evt.id\n ? { ...evt, _caldav: { ...evt._caldav!, etag: res.data.etag } }\n : e\n ));\n toast.success('Event updated');\n } catch (err) {\n const status = (err as { response?: { status?: number } })?.response?.status;\n if (status === 409) {\n toast.error('Event was modified elsewhere — refresh to see latest');\n } else {\n toast.error(extractError(err));\n }\n return;\n }\n } else if (targetCalendarId) {\n // New CalDAV event\n try {\n const input = toDavInput(evt);\n const res = await getMailClient().post<{ uid: string; etag: string; url: string }>(\n `/api/calendar/calendars/${encodeURIComponent(targetCalendarId)}/events`,\n input,\n );\n const newEvt: CalendarEvent = {\n ...evt,\n id: `caldav-${targetCalendarId}-${res.data.uid}`,\n _caldav: { calendarId: targetCalendarId, eventUid: res.data.uid, etag: res.data.etag },\n };\n setCaldavEvents(prev => [...prev, newEvt]);\n toast.success('Event created');\n } catch (err) {\n toast.error(extractError(err));\n return;\n }\n } else {\n // Local event\n const existing = localEvents.find(e => e.id === evt.id);\n if (existing) {\n saveLocalEvents(localEvents.map(e => e.id === evt.id ? evt : e));\n } else {\n saveLocalEvents([...localEvents, evt]);\n }\n }\n setEditingEvent(null);\n setNewEventDate(null);\n };\n\n const deleteEvent = async (evt: CalendarEvent) => {\n if (evt._caldav) {\n try {\n await getMailClient().delete(\n `/api/calendar/calendars/${encodeURIComponent(evt._caldav.calendarId)}/events/${encodeURIComponent(evt._caldav.eventUid)}`,\n { headers: { 'If-Match': evt._caldav.etag } },\n );\n setCaldavEvents(prev => prev.filter(e => e.id !== evt.id));\n toast.success('Event deleted');\n } catch (err) {\n toast.error(extractError(err));\n return;\n }\n } else {\n saveLocalEvents(localEvents.filter(e => e.id !== evt.id));\n }\n setEditingEvent(null);\n };\n\n // ── Navigation ──\n const goToday = () => setCurrentDate(new Date(today.getFullYear(), today.getMonth(), 1));\n const goPrev = () => {\n if (view === 'year') setCurrentDate(new Date(currentDate.getFullYear() - 1, currentDate.getMonth(), 1));\n else if (view === 'month') setCurrentDate(new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1));\n else {\n const d = new Date(currentDate);\n d.setDate(d.getDate() - 7);\n setCurrentDate(d);\n }\n };\n const goNext = () => {\n if (view === 'year') setCurrentDate(new Date(currentDate.getFullYear() + 1, currentDate.getMonth(), 1));\n else if (view === 'month') setCurrentDate(new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1));\n else {\n const d = new Date(currentDate);\n d.setDate(d.getDate() + 7);\n setCurrentDate(d);\n }\n };\n\n const monthLabel = view === 'year'\n ? String(currentDate.getFullYear())\n : currentDate.toLocaleDateString(undefined, { month: 'long', year: 'numeric' });\n\n const eventsByDate = useMemo(() => {\n const map: Record<string, CalendarEvent[]> = {};\n events.forEach(e => {\n if (!map[e.date]) map[e.date] = [];\n map[e.date].push(e);\n });\n for (const key of Object.keys(map)) {\n map[key].sort((a, b) => (a.start_time || '').localeCompare(b.start_time || ''));\n }\n return map;\n }, [events]);\n\n const handleDayClick = (dateStr: string) => {\n setNewEventDate(dateStr);\n setEditingEvent({\n id: `evt-${Date.now()}-${Math.random().toString(36).slice(2, 5)}`,\n title: '',\n date: dateStr,\n start_time: '09:00',\n end_time: '10:00',\n color: 'blue',\n all_day: false,\n });\n };\n\n return (\n <div className=\"flex flex-col h-full\">\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-3\">\n <button onClick={goToday} className=\"px-2.5 py-1 text-xs font-medium rounded-md border border-gray-300 text-gray-700 hover:bg-gray-50\">Today</button>\n <div className=\"flex items-center gap-1\">\n <button onClick={goPrev} className=\"p-1 rounded hover:bg-gray-100\">\n <svg className=\"h-4 w-4 text-gray-600\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M15.75 19.5L8.25 12l7.5-7.5\" /></svg>\n </button>\n <button onClick={goNext} className=\"p-1 rounded hover:bg-gray-100\">\n <svg className=\"h-4 w-4 text-gray-600\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M8.25 4.5l7.5 7.5-7.5 7.5\" /></svg>\n </button>\n </div>\n <h2 className=\"text-sm font-semibold text-gray-900\">{monthLabel}</h2>\n </div>\n <div className=\"flex items-center gap-2\">\n <span\n onClick={() => window.dispatchEvent(new Event('open-mail-connect'))}\n className=\"text-[11px] text-gray-600 cursor-pointer hover:text-gray-900\"\n title=\"Open mail & calendar settings\"\n >\n {caldavEnabled\n ? `CalDAV · ${calendars.length} calendar${calendars.length === 1 ? '' : 's'}`\n : 'CalDAV not connected'}\n </span>\n <div className=\"w-px h-4 bg-gray-200\" />\n <div className=\"flex gap-1\">\n {(['year', 'month', 'week'] as const).map(v => (\n <button key={v} onClick={() => setView(v)}\n className={`px-3 py-1 text-xs font-medium rounded-md transition-colors ${view === v ? 'bg-blue-600 text-white' : 'bg-white border border-gray-300 text-gray-600 hover:bg-gray-50'}`}>\n {v.charAt(0).toUpperCase() + v.slice(1)}\n </button>\n ))}\n </div>\n </div>\n </div>\n\n <div className=\"flex-1 overflow-hidden\">\n {view === 'year' ? (\n <YearView\n year={currentDate.getFullYear()}\n eventsByDate={eventsByDate}\n today={toDateStr(today)}\n onPickMonth={(m) => { setCurrentDate(new Date(currentDate.getFullYear(), m, 1)); setView('month'); }}\n onDayClick={handleDayClick}\n />\n ) : view === 'month' ? (\n <MonthView\n year={currentDate.getFullYear()}\n month={currentDate.getMonth()}\n eventsByDate={eventsByDate}\n today={toDateStr(today)}\n onDayClick={handleDayClick}\n onEventClick={setEditingEvent}\n onToggleTodo={toggleTodoDone}\n />\n ) : (\n <WeekView\n currentDate={currentDate}\n eventsByDate={eventsByDate}\n today={toDateStr(today)}\n onDayClick={handleDayClick}\n onEventClick={setEditingEvent}\n onToggleTodo={toggleTodoDone}\n />\n )}\n </div>\n\n {editingEvent && (\n <EventEditor\n event={editingEvent}\n isNew={!!newEventDate}\n calendars={calendars}\n onSave={saveEvent}\n onDelete={() => deleteEvent(editingEvent)}\n onClose={() => { setEditingEvent(null); setNewEventDate(null); }}\n />\n )}\n </div>\n );\n}\n\nfunction extractError(err: unknown): string {\n const r = (err as { response?: { data?: { error?: string } } })?.response?.data?.error;\n if (r) return r;\n if (err instanceof Error) return err.message;\n return 'Unknown error';\n}\n\nfunction DayEventBadge({ evt, onEventClick, onToggleTodo, compact = false }: {\n evt: CalendarEvent;\n onEventClick: (e: CalendarEvent) => void;\n onToggleTodo: (id: string) => void;\n compact?: boolean;\n}) {\n if (evt._todo && evt._todoId) {\n return compact ? (\n <button onClick={(ev) => { ev.stopPropagation(); onToggleTodo(evt._todoId!); }}\n title={evt.title}\n className={`w-full text-left flex items-center gap-1 truncate rounded px-1 py-0.5 text-[10px] leading-tight font-medium hover:bg-gray-100 transition-colors ${evt._done ? 'text-gray-400' : 'text-gray-700'}`}>\n <span className=\"shrink-0\">{evt._done ? '☑' : '☐'}</span>\n <span className={`truncate ${evt._done ? 'line-through' : ''}`}>{evt.title || 'Task'}</span>\n </button>\n ) : (\n <button onClick={(ev) => { ev.stopPropagation(); onToggleTodo(evt._todoId!); }}\n className={`w-full text-left flex items-center gap-2 rounded-md px-2 py-1.5 hover:bg-gray-100 transition-colors ${evt._done ? 'text-gray-400' : 'text-gray-700'}`}>\n <span className=\"shrink-0 text-base leading-none\">{evt._done ? '☑' : '☐'}</span>\n <span className={`text-xs font-medium truncate ${evt._done ? 'line-through' : ''}`}>{evt.title || 'Task'}</span>\n </button>\n );\n }\n const c = getColor(evt.color);\n return compact ? (\n <button onClick={(ev) => { ev.stopPropagation(); onEventClick(evt); }}\n className={`w-full text-left truncate rounded px-1 py-0.5 text-[10px] leading-tight font-medium ${c.light} hover:opacity-80 transition-opacity`}>\n {!evt.all_day && evt.start_time && <span className=\"text-[9px] opacity-70 mr-0.5\">{evt.start_time}</span>}\n {evt.title || 'Untitled'}\n </button>\n ) : (\n <button onClick={(ev) => { ev.stopPropagation(); onEventClick(evt); }}\n className={`w-full text-left rounded-md px-2 py-1.5 ${c.light} hover:opacity-80 transition-opacity`}>\n <p className=\"text-xs font-medium truncate\">{evt.title || 'Untitled'}</p>\n {!evt.all_day && evt.start_time && (\n <p className=\"text-[10px] opacity-70\">{evt.start_time}{evt.end_time ? ` - ${evt.end_time}` : ''}</p>\n )}\n </button>\n );\n}\n\nfunction MonthView({ year, month, eventsByDate, today, onDayClick, onEventClick, onToggleTodo }: {\n year: number; month: number; eventsByDate: Record<string, CalendarEvent[]>;\n today: string; onDayClick: (d: string) => void; onEventClick: (e: CalendarEvent) => void;\n onToggleTodo: (id: string) => void;\n}) {\n const cells = useMemo(() => getMonthDays(year, month), [year, month]);\n\n return (\n <div className=\"h-full flex flex-col\">\n <div className=\"grid grid-cols-7 border-b border-gray-200\">\n {DAYS.map(d => (\n <div key={d} className=\"px-2 py-1.5 text-[10px] font-semibold text-gray-500 uppercase text-center\">{d}</div>\n ))}\n </div>\n <div className=\"grid grid-cols-7 flex-1 auto-rows-fr\">\n {cells.map((cell, i) => {\n const dateStr = toDateStr(cell.date);\n const isToday = dateStr === today;\n const dayEvents = eventsByDate[dateStr] || [];\n return (\n <div key={i}\n onClick={() => onDayClick(dateStr)}\n className={`border-b border-r border-gray-100 px-1 py-0.5 cursor-pointer hover:bg-blue-50/50 transition-colors overflow-hidden ${!cell.isCurrentMonth ? 'bg-gray-50/50' : ''}`}\n >\n <div className={`text-[11px] font-medium mb-0.5 w-5 h-5 flex items-center justify-center rounded-full ${isToday ? 'bg-blue-600 text-white' : cell.isCurrentMonth ? 'text-gray-900' : 'text-gray-400'}`}>\n {cell.date.getDate()}\n </div>\n <div className=\"space-y-0.5\">\n {dayEvents.slice(0, 3).map(evt => <DayEventBadge key={evt.id} evt={evt} onEventClick={onEventClick} onToggleTodo={onToggleTodo} compact />)}\n {dayEvents.length > 3 && (\n <p className=\"text-[9px] text-gray-400 pl-1\">+{dayEvents.length - 3} more</p>\n )}\n </div>\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\nfunction YearView({ year, eventsByDate, today, onPickMonth, onDayClick }: {\n year: number;\n eventsByDate: Record<string, CalendarEvent[]>;\n today: string;\n onPickMonth: (month: number) => void;\n onDayClick: (dateStr: string) => void;\n}) {\n const monthShort = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n const dowShort = ['S', 'M', 'T', 'W', 'T', 'F', 'S'];\n\n return (\n <div className=\"h-full overflow-y-auto p-4\">\n <div className=\"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-x-6 gap-y-5 max-w-5xl mx-auto\">\n {monthShort.map((label, m) => {\n const cells = getMonthDays(year, m);\n return (\n <div key={m} className=\"flex flex-col\">\n <button onClick={() => onPickMonth(m)}\n className=\"self-start text-[13px] font-semibold text-blue-600 hover:text-blue-800 mb-1 px-1 -ml-1 rounded transition-colors\">\n {label}\n </button>\n <div className=\"grid grid-cols-7 mb-0.5\">\n {dowShort.map((d, i) => (\n <div key={i} className=\"text-[9px] font-medium text-gray-400 text-center\">{d}</div>\n ))}\n </div>\n <div className=\"grid grid-cols-7\">\n {cells.map((cell, i) => {\n const dateStr = toDateStr(cell.date);\n const isToday = dateStr === today;\n const hasEvents = !!eventsByDate[dateStr]?.length;\n return (\n <button key={i}\n onClick={(e) => { e.stopPropagation(); onDayClick(dateStr); }}\n className=\"relative h-6 flex items-center justify-center group\"\n tabIndex={cell.isCurrentMonth ? 0 : -1}>\n <span className={`text-[10px] tabular-nums leading-none flex items-center justify-center w-5 h-5 rounded-full transition-colors\n ${isToday\n ? 'bg-blue-600 text-white font-semibold'\n : cell.isCurrentMonth\n ? 'text-gray-700 group-hover:bg-blue-100'\n : 'text-gray-300'}`}>\n {cell.date.getDate()}\n </span>\n {hasEvents && cell.isCurrentMonth && !isToday && (\n <span className=\"absolute bottom-0 left-1/2 -translate-x-1/2 w-1 h-1 rounded-full bg-blue-500\" />\n )}\n </button>\n );\n })}\n </div>\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\nfunction WeekView({ currentDate, eventsByDate, today, onDayClick, onEventClick, onToggleTodo }: {\n currentDate: Date; eventsByDate: Record<string, CalendarEvent[]>;\n today: string; onDayClick: (d: string) => void; onEventClick: (e: CalendarEvent) => void;\n onToggleTodo: (id: string) => void;\n}) {\n const days = useMemo(() => getWeekDays(currentDate), [currentDate]);\n\n return (\n <div className=\"h-full flex flex-col\">\n <div className=\"grid grid-cols-7 border-b border-gray-200\">\n {days.map(d => {\n const dateStr = toDateStr(d);\n const isToday = dateStr === today;\n return (\n <div key={dateStr} className=\"px-2 py-2 text-center\">\n <p className=\"text-[10px] font-medium text-gray-500 uppercase\">{DAYS[d.getDay()]}</p>\n <p className={`text-lg font-semibold mt-0.5 ${isToday ? 'text-blue-600' : 'text-gray-900'}`}>{d.getDate()}</p>\n </div>\n );\n })}\n </div>\n <div className=\"grid grid-cols-7 flex-1 overflow-y-auto\">\n {days.map(d => {\n const dateStr = toDateStr(d);\n const dayEvents = eventsByDate[dateStr] || [];\n return (\n <div key={dateStr}\n onClick={() => onDayClick(dateStr)}\n className=\"border-r border-gray-100 px-1.5 py-2 cursor-pointer hover:bg-blue-50/30 transition-colors min-h-[200px]\">\n <div className=\"space-y-1\">\n {dayEvents.map(evt => <DayEventBadge key={evt.id} evt={evt} onEventClick={onEventClick} onToggleTodo={onToggleTodo} />)}\n </div>\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\nfunction EventEditor({ event, isNew, calendars, onSave, onDelete, onClose }: {\n event: CalendarEvent;\n isNew: boolean;\n calendars: DavCalendar[];\n onSave: (e: CalendarEvent, targetCalendarId?: string) => void;\n onDelete: () => void;\n onClose: () => void;\n}) {\n const [title, setTitle] = useState(event.title);\n const [date, setDate] = useState(event.date);\n const [startTime, setStartTime] = useState(event.start_time || '09:00');\n const [endTime, setEndTime] = useState(event.end_time || '10:00');\n const [color, setColor] = useState(event.color);\n const [allDay, setAllDay] = useState(event.all_day ?? false);\n const [description, setDescription] = useState(event.description || '');\n const isFromCaldav = !!event._caldav;\n const [target, setTarget] = useState<string>(isFromCaldav ? event._caldav!.calendarId : 'local');\n\n const handleSave = () => {\n if (!title.trim()) { toast.error('Event title is required.'); return; }\n const updated: CalendarEvent = {\n ...event,\n title: title.trim(),\n date,\n start_time: allDay ? undefined : startTime,\n end_time: allDay ? undefined : endTime,\n color,\n all_day: allDay,\n description: description.trim() || undefined,\n };\n const targetCal = !isFromCaldav && target !== 'local' ? target : undefined;\n onSave(updated, targetCal);\n };\n\n const inp = 'block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm';\n\n return (\n <Modal open onClose={onClose} title={isNew ? 'New Event' : 'Edit Event'} size=\"sm\">\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">Title *</label>\n <input value={title} onChange={e => setTitle(e.target.value)} className={inp} placeholder=\"Event title\" autoFocus />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">Date</label>\n <input type=\"date\" value={date} onChange={e => setDate(e.target.value)} className={inp} />\n </div>\n <label className=\"flex items-center gap-2 cursor-pointer\">\n <input type=\"checkbox\" checked={allDay} onChange={e => setAllDay(e.target.checked)} className=\"h-4 w-4 rounded border-gray-300 text-blue-600\" />\n <span className=\"text-sm text-gray-700\">All day</span>\n </label>\n {!allDay && (\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">Start</label>\n <input type=\"time\" value={startTime} onChange={e => setStartTime(e.target.value)} className={inp} />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">End</label>\n <input type=\"time\" value={endTime} onChange={e => setEndTime(e.target.value)} className={inp} />\n </div>\n </div>\n )}\n {(isNew && calendars.length > 0) && (\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">Save to</label>\n <select value={target} onChange={e => setTarget(e.target.value)} className={inp}>\n <option value=\"local\">Local (this device only)</option>\n {calendars.map(c => (\n <option key={c.id} value={c.id}>{c.displayName}</option>\n ))}\n </select>\n </div>\n )}\n {isFromCaldav && (\n <p className=\"text-[11px] text-gray-500\">\n From {calendars.find(c => c.id === event._caldav?.calendarId)?.displayName || 'CalDAV'}\n </p>\n )}\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">Color</label>\n <div className=\"flex gap-2\">\n {COLORS.map(c => (\n <button key={c.key} onClick={() => setColor(c.key)}\n className={`w-6 h-6 rounded-full ${c.bg} border-2 transition-all ${color === c.key ? 'border-gray-700 scale-110' : 'border-transparent hover:border-gray-400'}`} />\n ))}\n </div>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">Description</label>\n <textarea value={description} onChange={e => setDescription(e.target.value)} rows={2} className={inp} placeholder=\"Optional notes...\" />\n </div>\n </div>\n\n {!isNew && (\n <ModalActions position=\"left\">\n <button onClick={onDelete} className=\"text-sm text-red-600 hover:text-red-800 font-medium\">Delete</button>\n </ModalActions>\n )}\n <ModalActions>\n <button onClick={handleSave} className=\"bg-blue-600 text-white px-4 py-2 text-sm font-medium rounded-lg hover:bg-blue-700\">\n {isNew ? 'Create' : 'Save'}\n </button>\n </ModalActions>\n </Modal>\n );\n}\n"]}
@@ -1,5 +1,5 @@
1
- import { loadAppearance, WidgetSettingsModal } from './chunk-KFRHMW57.js';
2
- import { useWidgetSettings } from './chunk-GAC6D4LN.js';
1
+ import { loadAppearance, WidgetSettingsModal } from './chunk-O6FJZAFM.js';
2
+ import { useWidgetSettings } from './chunk-62FC2FHC.js';
3
3
  import './chunk-PLGHQ7QW.js';
4
4
  import './chunk-SSA762W5.js';
5
5
  import { useState, useCallback, useEffect } from 'react';
@@ -226,5 +226,5 @@ function CurrencyConverter() {
226
226
  }
227
227
 
228
228
  export { CurrencyConverter as default };
229
- //# sourceMappingURL=CurrencyConverter-TDAW7VME.js.map
230
- //# sourceMappingURL=CurrencyConverter-TDAW7VME.js.map
229
+ //# sourceMappingURL=CurrencyConverter-YHOGBUPH.js.map
230
+ //# sourceMappingURL=CurrencyConverter-YHOGBUPH.js.map