react-os-shell 0.2.44 → 0.2.45

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 (31) hide show
  1. package/dist/{Calendar-4UQDQ3NT.js → Calendar-PKRZ5MBU.js} +153 -54
  2. package/dist/Calendar-PKRZ5MBU.js.map +1 -0
  3. package/dist/{CurrencyConverter-TXBFDFG2.js → CurrencyConverter-5N44NZ6Z.js} +3 -3
  4. package/dist/{CurrencyConverter-TXBFDFG2.js.map → CurrencyConverter-5N44NZ6Z.js.map} +1 -1
  5. package/dist/{Email-HRBZUWPY.js → Email-CR6XS2AD.js} +4 -4
  6. package/dist/{Email-HRBZUWPY.js.map → Email-CR6XS2AD.js.map} +1 -1
  7. package/dist/{GeminiChat-ITU46EH4.js → GeminiChat-XTEBZIVK.js} +3 -3
  8. package/dist/{GeminiChat-ITU46EH4.js.map → GeminiChat-XTEBZIVK.js.map} +1 -1
  9. package/dist/{PomodoroTimer-PRP5CZ3S.js → PomodoroTimer-FHSOLF3O.js} +49 -49
  10. package/dist/PomodoroTimer-FHSOLF3O.js.map +1 -0
  11. package/dist/TodoList-7JZ2SLDI.js +494 -0
  12. package/dist/TodoList-7JZ2SLDI.js.map +1 -0
  13. package/dist/{WorldClock-QO5PVJQQ.js → WorldClock-XHM7WAUV.js} +43 -97
  14. package/dist/WorldClock-XHM7WAUV.js.map +1 -0
  15. package/dist/apps/index.d.ts +4 -1
  16. package/dist/apps/index.js +10 -8
  17. package/dist/apps/index.js.map +1 -1
  18. package/dist/chunk-25L4DIKH.js +90 -0
  19. package/dist/chunk-25L4DIKH.js.map +1 -0
  20. package/dist/{chunk-62MVMTBT.js → chunk-5VXRBUEH.js} +20 -3
  21. package/dist/chunk-5VXRBUEH.js.map +1 -0
  22. package/dist/{chunk-46LICZUM.js → chunk-MVWEL34Y.js} +3 -2
  23. package/dist/chunk-MVWEL34Y.js.map +1 -0
  24. package/dist/index.js +2 -2
  25. package/dist/styles.css +6 -4
  26. package/package.json +1 -1
  27. package/dist/Calendar-4UQDQ3NT.js.map +0 -1
  28. package/dist/PomodoroTimer-PRP5CZ3S.js.map +0 -1
  29. package/dist/WorldClock-QO5PVJQQ.js.map +0 -1
  30. package/dist/chunk-46LICZUM.js.map +0 -1
  31. package/dist/chunk-62MVMTBT.js.map +0 -1
@@ -8,77 +8,21 @@ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
8
8
 
9
9
  var SETTINGS_KEY = "world_clock_appearance";
10
10
  var DEFAULT_CITIES = ["London", "Shanghai", "New York"];
11
- function AnalogClockWithMeridiem({ tz, now, size = 30 }) {
12
- let h24 = 0, m = 0;
11
+ function digitalTime(tz, now) {
13
12
  try {
14
13
  const parts = new Intl.DateTimeFormat("en-US", {
15
14
  timeZone: tz,
16
15
  hour: "numeric",
17
16
  minute: "2-digit",
18
- hour12: false
17
+ hour12: true
19
18
  }).formatToParts(now);
20
- h24 = parseInt(parts.find((p) => p.type === "hour")?.value || "0", 10);
21
- if (h24 === 24) h24 = 0;
22
- m = parseInt(parts.find((p) => p.type === "minute")?.value || "0", 10);
19
+ const h = parts.find((p) => p.type === "hour")?.value || "12";
20
+ const m = parts.find((p) => p.type === "minute")?.value || "00";
21
+ const ampm = (parts.find((p) => p.type === "dayPeriod")?.value || "").toUpperCase();
22
+ return { time: `${h}:${m}`, ampm };
23
23
  } catch {
24
+ return { time: "", ampm: "" };
24
25
  }
25
- const ampm = h24 >= 12 ? "PM" : "AM";
26
- const hourAngle = (h24 % 12 + m / 60) * 30 - 90;
27
- const minuteAngle = m * 6 - 90;
28
- const r = size / 2;
29
- const hLen = r * 0.52;
30
- const mLen = r * 0.78;
31
- const hRad = hourAngle * Math.PI / 180;
32
- const mRad = minuteAngle * Math.PI / 180;
33
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-0.5 shrink-0 text-gray-700", children: [
34
- /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, style: { color: "currentColor" }, children: [
35
- /* @__PURE__ */ jsx(
36
- "circle",
37
- {
38
- cx: r,
39
- cy: r,
40
- r: r - 0.6,
41
- fill: "currentColor",
42
- fillOpacity: 0.05,
43
- stroke: "currentColor",
44
- strokeOpacity: 0.4,
45
- strokeWidth: 0.8
46
- }
47
- ),
48
- [0, 90, 180, 270].map((deg) => {
49
- const a = (deg - 90) * Math.PI / 180;
50
- const dx = r + Math.cos(a) * (r * 0.83);
51
- const dy = r + Math.sin(a) * (r * 0.83);
52
- return /* @__PURE__ */ jsx("circle", { cx: dx, cy: dy, r: 0.85, fill: "currentColor", fillOpacity: 0.55 }, deg);
53
- }),
54
- /* @__PURE__ */ jsx(
55
- "line",
56
- {
57
- x1: r,
58
- y1: r,
59
- x2: r + Math.cos(hRad) * hLen,
60
- y2: r + Math.sin(hRad) * hLen,
61
- stroke: "currentColor",
62
- strokeWidth: 1.6,
63
- strokeLinecap: "round"
64
- }
65
- ),
66
- /* @__PURE__ */ jsx(
67
- "line",
68
- {
69
- x1: r,
70
- y1: r,
71
- x2: r + Math.cos(mRad) * mLen,
72
- y2: r + Math.sin(mRad) * mLen,
73
- stroke: "currentColor",
74
- strokeWidth: 1.1,
75
- strokeLinecap: "round"
76
- }
77
- ),
78
- /* @__PURE__ */ jsx("circle", { cx: r, cy: r, r: 1.3, fill: "currentColor" })
79
- ] }),
80
- /* @__PURE__ */ jsx("span", { className: "text-[8.5px] font-medium tracking-[0.12em] text-gray-500", children: ampm })
81
- ] });
82
26
  }
83
27
  function WorldClock() {
84
28
  const { prefs, save } = useShellPrefs();
@@ -149,51 +93,53 @@ function WorldClock() {
149
93
  /* @__PURE__ */ jsx(
150
94
  "div",
151
95
  {
152
- className: "rounded-2xl overflow-hidden",
96
+ className: "h-full",
153
97
  style: {
154
98
  backgroundColor: `rgb(var(--taskbar-bg-rgb, 243 244 246) / ${appearance.activeOpacity / 100})`,
155
99
  backdropFilter: appearance.activeBlur > 0 ? `blur(${appearance.activeBlur}px)` : void 0
156
100
  },
157
- children: /* @__PURE__ */ jsxs("div", { className: "px-1 py-1", children: [
101
+ children: /* @__PURE__ */ jsxs("div", { className: "divide-y divide-gray-200", children: [
158
102
  loading && cities.every((c) => !data[c]) && /* @__PURE__ */ jsx("div", { className: "px-3 py-6 text-center text-xs text-gray-500", children: "Loading\u2026" }),
159
- cities.map((cityName, i) => {
103
+ cities.map((cityName) => {
160
104
  const w = data[cityName];
161
105
  const tz = AVAILABLE_CITIES[cityName]?.tz ?? "UTC";
162
- const last = i === cities.length - 1;
106
+ const { time, ampm } = digitalTime(tz, now);
163
107
  if (!w) {
164
- return /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-3 px-3 py-3 ${last ? "" : "border-b border-gray-200"}`, children: [
165
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
166
- /* @__PURE__ */ jsx("div", { className: "text-[15px] font-semibold tracking-tight leading-tight truncate text-gray-900", children: cityName }),
167
- /* @__PURE__ */ jsx("div", { className: "text-[11px] text-gray-500 leading-tight", children: "\u2026" })
108
+ return /* @__PURE__ */ jsxs("div", { className: "px-4 py-3", children: [
109
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-2", children: [
110
+ /* @__PURE__ */ jsx("span", { className: "text-[15px] font-semibold tracking-tight text-gray-900 truncate", children: cityName }),
111
+ /* @__PURE__ */ jsxs("span", { className: "tabular-nums text-[13px] font-medium text-gray-500", children: [
112
+ time,
113
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] ml-0.5 opacity-70", children: ampm })
114
+ ] })
168
115
  ] }),
169
- /* @__PURE__ */ jsx(AnalogClockWithMeridiem, { tz, now })
116
+ /* @__PURE__ */ jsx("div", { className: "text-[11px] text-gray-400 mt-1", children: "Loading weather\u2026" })
170
117
  ] }, cityName);
171
118
  }
172
119
  const [condition, emoji] = getCondition(w.code, w.isDay);
173
- return /* @__PURE__ */ jsxs(
174
- "div",
175
- {
176
- className: `flex items-center gap-3 px-3 py-3 ${last ? "" : "border-b border-gray-200"}`,
177
- children: [
178
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
179
- /* @__PURE__ */ jsx("div", { className: "text-[15px] font-semibold tracking-tight leading-tight truncate text-gray-900", children: cityName }),
180
- /* @__PURE__ */ jsx("div", { className: "text-[11px] text-gray-500 leading-tight truncate mt-0.5", children: condition })
120
+ return /* @__PURE__ */ jsxs("div", { className: "px-4 py-3", children: [
121
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-2", children: [
122
+ /* @__PURE__ */ jsx("span", { className: "text-[15px] font-semibold tracking-tight text-gray-900 truncate", children: cityName }),
123
+ /* @__PURE__ */ jsx("span", { className: "text-[26px] font-extralight leading-none tabular-nums tracking-tight text-gray-900 shrink-0", children: formatTemp(w.temp) })
124
+ ] }),
125
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 mt-1.5 text-[11px]", children: [
126
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 min-w-0 text-gray-500", children: [
127
+ /* @__PURE__ */ jsx("span", { className: "text-base leading-none shrink-0", children: emoji }),
128
+ /* @__PURE__ */ jsxs("span", { className: "tabular-nums font-semibold text-gray-700 shrink-0", children: [
129
+ time,
130
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] font-medium ml-0.5 opacity-70", children: ampm })
181
131
  ] }),
182
- /* @__PURE__ */ jsx(AnalogClockWithMeridiem, { tz, now }),
183
- /* @__PURE__ */ jsx("span", { className: "text-[22px] leading-none shrink-0", children: emoji }),
184
- /* @__PURE__ */ jsxs("div", { className: "text-right shrink-0 min-w-[52px]", children: [
185
- /* @__PURE__ */ jsx("div", { className: "text-[22px] font-extralight leading-none tabular-nums tracking-tight text-gray-900", children: formatTemp(w.temp) }),
186
- /* @__PURE__ */ jsxs("div", { className: "text-[10px] text-gray-500 tabular-nums mt-1", children: [
187
- "H:",
188
- formatTemp(w.high),
189
- " L:",
190
- formatTemp(w.low)
191
- ] })
192
- ] })
193
- ]
194
- },
195
- cityName
196
- );
132
+ /* @__PURE__ */ jsx("span", { className: "text-gray-300 shrink-0", children: "\xB7" }),
133
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: condition })
134
+ ] }),
135
+ /* @__PURE__ */ jsxs("span", { className: "tabular-nums text-gray-500 shrink-0", children: [
136
+ "H:",
137
+ formatTemp(w.high),
138
+ " L:",
139
+ formatTemp(w.low)
140
+ ] })
141
+ ] })
142
+ ] }, cityName);
197
143
  })
198
144
  ] })
199
145
  }
@@ -246,5 +192,5 @@ function WorldClock() {
246
192
  }
247
193
 
248
194
  export { WorldClock as default };
249
- //# sourceMappingURL=WorldClock-QO5PVJQQ.js.map
250
- //# sourceMappingURL=WorldClock-QO5PVJQQ.js.map
195
+ //# sourceMappingURL=WorldClock-XHM7WAUV.js.map
196
+ //# sourceMappingURL=WorldClock-XHM7WAUV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/apps/WorldClock.tsx"],"names":[],"mappings":"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","file":"WorldClock-XHM7WAUV.js","sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport { useWidgetSettings } from '../shell/Modal';\nimport WidgetSettingsModal, { loadAppearance, type WidgetAppearance } from '../shell/WidgetSettingsModal';\nimport { useShellPrefs } from '../shell/ShellPrefs';\nimport { AVAILABLE_CITIES, fetchCityWeather, getCondition, toFahrenheit, type CityWeather } from './_weatherData';\n\nconst SETTINGS_KEY = 'world_clock_appearance';\nconst DEFAULT_CITIES = ['London', 'Shanghai', 'New York'];\n\ninterface WeatherPrefs { useFahrenheit: boolean }\n\n/**\n * Resolve the local time for the supplied IANA timezone into a digital\n * `12:34` + `AM` / `PM` pair. Used by the World Clock rows.\n */\nfunction digitalTime(tz: string, now: Date): { time: string; ampm: string } {\n try {\n const parts = new Intl.DateTimeFormat('en-US', {\n timeZone: tz, hour: 'numeric', minute: '2-digit', hour12: true,\n }).formatToParts(now);\n const h = parts.find(p => p.type === 'hour')?.value || '12';\n const m = parts.find(p => p.type === 'minute')?.value || '00';\n const ampm = (parts.find(p => p.type === 'dayPeriod')?.value || '').toUpperCase();\n return { time: `${h}:${m}`, ampm };\n } catch { return { time: '', ampm: '' }; }\n}\n\n/**\n * World Clock widget — multi-city list. Each row pairs a tiny analogue\n * clock (minimal-style: ring, four cardinal dots, two hands) with the\n * city's current weather. The weather emoji doubles as a day/night cue\n * (☀ vs 🌙 for clear, the same icons for everything else). Reads the\n * shared Open-Meteo cache so it doesn't re-hit the API when the Weather\n * widget already has the data.\n */\nexport default function WorldClock() {\n const { prefs, save } = useShellPrefs();\n const [appearance, setAppearance] = useState(() => loadAppearance(SETTINGS_KEY));\n const [settingsOpen, setSettingsOpen] = useState(false);\n const [configCities, setConfigCities] = useState<string[]>([]);\n const [configAppearance, setConfigAppearance] = useState<WidgetAppearance>(appearance);\n\n const wxPrefs: WeatherPrefs = {\n useFahrenheit: !!(prefs.weather_prefs as WeatherPrefs | undefined)?.useFahrenheit,\n };\n const [configWxPrefs, setConfigWxPrefs] = useState(wxPrefs);\n\n // Tick once every 30 s so the analogue minute-hands drift smoothly. We\n // don't show seconds so faster polling is wasted re-renders.\n const [now, setNow] = useState(() => new Date());\n useEffect(() => {\n const t = setInterval(() => setNow(new Date()), 30 * 1000);\n return () => clearInterval(t);\n }, []);\n\n // Resolve the saved city list and migrate the legacy IANA-timezone\n // format (`Europe/London`) over to the new city-name format\n // (`London`).\n const tzToCity: Record<string, string> = Object.fromEntries(\n Object.entries(AVAILABLE_CITIES).map(([city, info]) => [info.tz, city])\n );\n const rawClocks = prefs.world_clocks as string[] | undefined;\n const cities: string[] = (() => {\n if (!Array.isArray(rawClocks) || rawClocks.length === 0) return DEFAULT_CITIES;\n const out: string[] = [];\n for (const v of rawClocks) {\n const asCity = AVAILABLE_CITIES[v] ? v : tzToCity[v];\n if (asCity && !out.includes(asCity)) out.push(asCity);\n }\n return out.length ? out : DEFAULT_CITIES;\n })();\n\n const [data, setData] = useState<Record<string, CityWeather>>({});\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n (async () => {\n const next: Record<string, CityWeather> = {};\n await Promise.all(cities.map(async c => {\n const w = await fetchCityWeather(c);\n if (w) next[c] = w;\n }));\n if (!cancelled) { setData(next); setLoading(false); }\n })();\n return () => { cancelled = true; };\n }, [cities.join(',')]);\n\n useWidgetSettings(useCallback(() => {\n setConfigCities([...cities]);\n setConfigAppearance({ ...appearance });\n setConfigWxPrefs({ ...wxPrefs });\n setSettingsOpen(true);\n }, [cities.join(','), appearance, wxPrefs.useFahrenheit]));\n\n const saveSettings = () => {\n if (configCities.length === 0) return;\n save({\n world_clocks: configCities,\n weather_prefs: { ...(prefs.weather_prefs as object | undefined ?? {}), useFahrenheit: configWxPrefs.useFahrenheit },\n });\n setAppearance(configAppearance);\n localStorage.setItem(SETTINGS_KEY, JSON.stringify(configAppearance));\n setSettingsOpen(false);\n };\n\n const formatTemp = (c: number) => wxPrefs.useFahrenheit ? `${toFahrenheit(c)}°` : `${c}°`;\n\n return (\n <>\n {/* Theme-aware panel — same colour as the taskbar so all dashboard\n * widgets read as a coordinated set across light and dark themes.\n * Rows use `divide-y` rather than per-row border classes so the\n * last row never paints a stray separator line at the panel's\n * bottom edge. */}\n <div className=\"h-full\"\n style={{\n backgroundColor: `rgb(var(--taskbar-bg-rgb, 243 244 246) / ${appearance.activeOpacity / 100})`,\n backdropFilter: appearance.activeBlur > 0 ? `blur(${appearance.activeBlur}px)` : undefined,\n }}>\n <div className=\"divide-y divide-gray-200\">\n {loading && cities.every(c => !data[c]) && (\n <div className=\"px-3 py-6 text-center text-xs text-gray-500\">Loading…</div>\n )}\n {cities.map((cityName) => {\n const w = data[cityName];\n const tz = AVAILABLE_CITIES[cityName]?.tz ?? 'UTC';\n const { time, ampm } = digitalTime(tz, now);\n if (!w) {\n return (\n <div key={cityName} className=\"px-4 py-3\">\n <div className=\"flex items-baseline justify-between gap-2\">\n <span className=\"text-[15px] font-semibold tracking-tight text-gray-900 truncate\">{cityName}</span>\n <span className=\"tabular-nums text-[13px] font-medium text-gray-500\">{time}<span className=\"text-[9px] ml-0.5 opacity-70\">{ampm}</span></span>\n </div>\n <div className=\"text-[11px] text-gray-400 mt-1\">Loading weather…</div>\n </div>\n );\n }\n const [condition, emoji] = getCondition(w.code, w.isDay);\n return (\n <div key={cityName} className=\"px-4 py-3\">\n {/* Top — city name on the left, big temperature on the right. */}\n <div className=\"flex items-baseline justify-between gap-2\">\n <span className=\"text-[15px] font-semibold tracking-tight text-gray-900 truncate\">{cityName}</span>\n <span className=\"text-[26px] font-extralight leading-none tabular-nums tracking-tight text-gray-900 shrink-0\">{formatTemp(w.temp)}</span>\n </div>\n\n {/* Bottom — emoji · digital time · condition on the left;\n H/L on the right. */}\n <div className=\"flex items-center justify-between gap-2 mt-1.5 text-[11px]\">\n <div className=\"flex items-center gap-1.5 min-w-0 text-gray-500\">\n <span className=\"text-base leading-none shrink-0\">{emoji}</span>\n <span className=\"tabular-nums font-semibold text-gray-700 shrink-0\">\n {time}<span className=\"text-[9px] font-medium ml-0.5 opacity-70\">{ampm}</span>\n </span>\n <span className=\"text-gray-300 shrink-0\">·</span>\n <span className=\"truncate\">{condition}</span>\n </div>\n <span className=\"tabular-nums text-gray-500 shrink-0\">H:{formatTemp(w.high)} L:{formatTemp(w.low)}</span>\n </div>\n </div>\n );\n })}\n </div>\n </div>\n\n <WidgetSettingsModal open={settingsOpen} onClose={() => setSettingsOpen(false)} title=\"World Clock Settings\"\n appearance={configAppearance} onAppearanceChange={setConfigAppearance} onSave={saveSettings}>\n <div>\n <h3 className=\"text-sm font-semibold text-gray-700 mb-2\">Display</h3>\n <div className=\"flex items-center gap-3 mb-2\">\n <span className=\"text-sm text-gray-600 w-24\">Temperature</span>\n <div className=\"flex gap-1\">\n {([{ key: false, label: '°C' }, { key: true, label: '°F' }] as const).map(o => (\n <button key={String(o.key)} onClick={() => setConfigWxPrefs(p => ({ ...p, useFahrenheit: o.key }))}\n className={`px-3 py-1 text-xs font-medium rounded-lg border transition-colors ${configWxPrefs.useFahrenheit === o.key ? 'bg-blue-600 text-white border-blue-600' : 'bg-white text-gray-700 border-gray-300 hover:bg-gray-50'}`}>\n {o.label}\n </button>\n ))}\n </div>\n </div>\n <p className=\"text-[10px] text-gray-400 mt-1\">Shared with the Weather widget.</p>\n </div>\n <div>\n <h3 className=\"text-sm font-semibold text-gray-700 mb-2\">Cities</h3>\n <div className=\"grid grid-cols-2 gap-1 max-h-56 overflow-y-auto\">\n {Object.keys(AVAILABLE_CITIES).map(name => (\n <label key={name} className=\"flex items-center gap-2 text-sm py-1 cursor-pointer hover:bg-gray-50 rounded px-2\">\n <input type=\"checkbox\" checked={configCities.includes(name)}\n onChange={() => setConfigCities(prev => prev.includes(name) ? prev.filter(c => c !== name) : [...prev, name])}\n className=\"rounded border-gray-300 text-blue-600 focus:ring-blue-500 h-3.5 w-3.5\" />\n {name}\n </label>\n ))}\n </div>\n </div>\n </WidgetSettingsModal>\n </>\n );\n}\n"]}
@@ -53,6 +53,8 @@ declare function Checkers$1(): react_jsx_runtime.JSX.Element;
53
53
 
54
54
  declare function Chess$1(): react_jsx_runtime.JSX.Element;
55
55
 
56
+ declare function TodoList$1(): react_jsx_runtime.JSX.Element;
57
+
56
58
  /**
57
59
  * World Clock widget — multi-city list. Each row pairs a tiny analogue
58
60
  * clock (minimal-style: ring, four cardinal dots, two hands) with the
@@ -82,6 +84,7 @@ declare const CurrencyConverter: react.LazyExoticComponent<typeof CurrencyConver
82
84
  declare const PomodoroTimer: react.LazyExoticComponent<typeof PomodoroTimer$1>;
83
85
  declare const Notepad: react.LazyExoticComponent<typeof Notepad$1>;
84
86
  declare const WorldClock: react.LazyExoticComponent<typeof WorldClock$1>;
87
+ declare const TodoList: react.LazyExoticComponent<typeof TodoList$1>;
85
88
  declare const Chess: react.LazyExoticComponent<typeof Chess$1>;
86
89
  declare const Checkers: react.LazyExoticComponent<typeof Checkers$1>;
87
90
  declare const Sudoku: react.LazyExoticComponent<typeof Sudoku$1>;
@@ -102,4 +105,4 @@ declare const documentApps: WindowRegistry;
102
105
  declare const webApps: WindowRegistry;
103
106
  declare const bundledApps: WindowRegistry;
104
107
 
105
- export { Browser, Calculator, Calendar, Checkers, Chess, CurrencyConverter, Documents, Email, Files, Game2048, GeminiChat, Minesweeper, Notepad, type PdfPreviewData, PomodoroTimer, Preview, Spreadsheet, Sudoku, Tetris, Weather, WorldClock, bundledApps, documentApps, gameApps, googleApps, openFilesInTrashMode, setPdfPreview, utilityApps, webApps };
108
+ export { Browser, Calculator, Calendar, Checkers, Chess, CurrencyConverter, Documents, Email, Files, Game2048, GeminiChat, Minesweeper, Notepad, type PdfPreviewData, PomodoroTimer, Preview, Spreadsheet, Sudoku, Tetris, TodoList, Weather, WorldClock, bundledApps, documentApps, gameApps, googleApps, openFilesInTrashMode, setPdfPreview, utilityApps, webApps };
@@ -9,19 +9,20 @@ import { lazy } from 'react';
9
9
  var Calculator = lazy(() => import('../Calculator-ZKEH53OV.js'));
10
10
  var Spreadsheet = lazy(() => import('../Spreadsheet-MKXPPSKV.js'));
11
11
  var Weather = lazy(() => import('../Weather-YXSCSPQT.js'));
12
- var CurrencyConverter = lazy(() => import('../CurrencyConverter-TXBFDFG2.js'));
13
- var PomodoroTimer = lazy(() => import('../PomodoroTimer-PRP5CZ3S.js'));
12
+ var CurrencyConverter = lazy(() => import('../CurrencyConverter-5N44NZ6Z.js'));
13
+ var PomodoroTimer = lazy(() => import('../PomodoroTimer-FHSOLF3O.js'));
14
14
  var Notepad = lazy(() => import('../Notepad-74CQPZCV.js'));
15
- var WorldClock = lazy(() => import('../WorldClock-QO5PVJQQ.js'));
15
+ var WorldClock = lazy(() => import('../WorldClock-XHM7WAUV.js'));
16
+ var TodoList = lazy(() => import('../TodoList-7JZ2SLDI.js'));
16
17
  var Chess = lazy(() => import('../Chess-C5BY45NA.js'));
17
18
  var Checkers = lazy(() => import('../Checkers-MIAHIKJH.js'));
18
19
  var Sudoku = lazy(() => import('../Sudoku-XHLYCEVT.js'));
19
20
  var Tetris = lazy(() => import('../Tetris-ZHCZYL24.js'));
20
21
  var Game2048 = lazy(() => import('../Game2048-3RH3ELRD.js'));
21
22
  var Minesweeper = lazy(() => import('../Minesweeper-QGUPDVRS.js'));
22
- var Email = lazy(() => import('../Email-HRBZUWPY.js'));
23
- var GeminiChat = lazy(() => import('../GeminiChat-ITU46EH4.js'));
24
- var Calendar = lazy(() => import('../Calendar-4UQDQ3NT.js'));
23
+ var Email = lazy(() => import('../Email-CR6XS2AD.js'));
24
+ var GeminiChat = lazy(() => import('../GeminiChat-XTEBZIVK.js'));
25
+ var Calendar = lazy(() => import('../Calendar-PKRZ5MBU.js'));
25
26
  var Preview = lazy(() => import('../Preview-4MBQI66Q.js'));
26
27
  var Documents = lazy(() => import('../Documents-CQVIIFZV.js'));
27
28
  var Files = lazy(() => import('../Files-ITIKVHIE.js'));
@@ -33,7 +34,8 @@ var utilityApps = {
33
34
  "/weather": { component: Weather, label: "Weather", size: "sm", utility: true, widget: true, autoHeight: true, dimensions: [320, 400] },
34
35
  "/currency": { component: CurrencyConverter, label: "Currency Converter", size: "sm", utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },
35
36
  "/pomodoro": { component: PomodoroTimer, label: "Pomodoro Timer", size: "sm", utility: true, widget: true, autoHeight: true, dimensions: [320, 600] },
36
- "/world-clock": { component: WorldClock, label: "World Clock", size: "sm", utility: true, widget: true, autoHeight: true, dimensions: [320, 480] }
37
+ "/world-clock": { component: WorldClock, label: "World Clock", size: "sm", utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },
38
+ "/todo": { component: TodoList, label: "Todo List", size: "md", dimensions: [560, 640] }
37
39
  };
38
40
  var gameApps = {
39
41
  "/chess": { component: Chess, label: "Chess", size: "lg", compact: true },
@@ -64,6 +66,6 @@ var bundledApps = {
64
66
  ...webApps
65
67
  };
66
68
 
67
- export { Browser, Calculator, Calendar, Checkers, Chess, CurrencyConverter, Documents, Email, Files, Game2048, GeminiChat, Minesweeper, Notepad, PomodoroTimer, Preview, Spreadsheet, Sudoku, Tetris, Weather, WorldClock, bundledApps, documentApps, gameApps, googleApps, utilityApps, webApps };
69
+ export { Browser, Calculator, Calendar, Checkers, Chess, CurrencyConverter, Documents, Email, Files, Game2048, GeminiChat, Minesweeper, Notepad, PomodoroTimer, Preview, Spreadsheet, Sudoku, Tetris, TodoList, Weather, WorldClock, bundledApps, documentApps, gameApps, googleApps, utilityApps, webApps };
68
70
  //# sourceMappingURL=index.js.map
69
71
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/apps/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Bundled apps — pre-built window registry entries for the 16 apps that ship\n * with `react-os-shell`. Consumers compose them into their own registry via\n * `createWindowRegistry`:\n *\n * import { createWindowRegistry } from 'react-os-shell';\n * import { bundledApps } from 'react-os-shell/apps';\n * import { erpEntities } from './shell-config';\n *\n * const windows = createWindowRegistry(bundledApps, erpEntities);\n *\n * Subsets are also exported (`utilityApps`, `gameApps`, `googleApps`) so a\n * consumer can pick-and-choose without importing every component.\n *\n * NOTE: 3 apps require consumer-supplied persistence (Calendar / Notepad for\n * stored content, Minesweeper for leaderboard). They're exported individually\n * but absent from `bundledApps` — wire the prefs provider to opt them in.\n * WorldClock uses `useShellPrefs()` so it lives in `bundledApps`; without a\n * consumer-supplied prefs adapter the city list won't survive a reload.\n */\nimport { lazy } from 'react';\nimport type { WindowRegistry } from '../windowRegistry/types';\n\n// ── Utility apps ──\nconst Calculator = lazy(() => import('./Calculator'));\nconst Spreadsheet = lazy(() => import('./Spreadsheet'));\nconst Weather = lazy(() => import('./Weather'));\nconst CurrencyConverter = lazy(() => import('./CurrencyConverter'));\nconst PomodoroTimer = lazy(() => import('./PomodoroTimer'));\nconst Notepad = lazy(() => import('./Notepad'));\nconst WorldClock = lazy(() => import('./WorldClock'));\n\n// ── Games ──\nconst Chess = lazy(() => import('./Chess'));\nconst Checkers = lazy(() => import('./Checkers'));\nconst Sudoku = lazy(() => import('./Sudoku'));\nconst Tetris = lazy(() => import('./Tetris'));\nconst Game2048 = lazy(() => import('./Game2048'));\nconst Minesweeper = lazy(() => import('./Minesweeper'));\n\n// ── Google apps ──\nconst Email = lazy(() => import('./Email'));\nconst GeminiChat = lazy(() => import('./GeminiChat'));\nconst Calendar = lazy(() => import('./Calendar'));\n\n// ── Document apps ──\nconst Preview = lazy(() => import('./Preview'));\nconst Documents = lazy(() => import('./Documents'));\nconst Files = lazy(() => import('./Files'));\n\n// ── Web ──\nconst Browser = lazy(() => import('./Browser'));\n\nexport const utilityApps: WindowRegistry = {\n '/calculator': { component: Calculator, label: 'Calculator', size: 'sm', allowPinOnTop: true, utility: true, widget: true, autoHeight: true, dimensions: [280, 420] },\n '/spreadsheet': { component: Spreadsheet, label: 'Spreadsheets', size: '2xl', appStyle: true, multiInstance: true },\n '/notepad': { component: Notepad, label: 'Notepad', size: 'lg', allowPinOnTop: true },\n '/weather': { component: Weather, label: 'Weather', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 400] },\n '/currency': { component: CurrencyConverter, label: 'Currency Converter', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },\n '/pomodoro': { component: PomodoroTimer, label: 'Pomodoro Timer', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 600] },\n '/world-clock': { component: WorldClock, label: 'World Clock', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },\n};\n\nexport const gameApps: WindowRegistry = {\n '/chess': { component: Chess, label: 'Chess', size: 'lg', compact: true },\n '/checkers': { component: Checkers, label: 'Checkers', size: 'lg', compact: true },\n '/sudoku': { component: Sudoku, label: 'Sudoku', size: 'sm', compact: true, dimensions: [360, 535] },\n '/tetris': { component: Tetris, label: 'Tetris', size: 'md', compact: true, dimensions: [452, 618] },\n '/2048': { component: Game2048, label: '2048', size: 'sm', compact: true },\n '/minesweeper': { component: Minesweeper, label: 'Minesweeper', size: 'sm', compact: true },\n};\n\nexport const googleApps: WindowRegistry = {\n '/email': { component: Email, label: 'Email', size: '2xl', appStyle: true },\n '/gemini': { component: GeminiChat, label: 'Gemini AI', size: 'lg' },\n '/calendar': { component: Calendar, label: 'Calendar', size: 'xl' },\n};\n\nexport const documentApps: WindowRegistry = {\n '/preview': { component: Preview, label: 'Preview', size: '2xl', appStyle: true, multiInstance: true },\n '/documents': { component: Documents, label: 'Documents', size: 'xl', appStyle: true, multiInstance: true },\n '/files': { component: Files, label: 'Files', size: 'xl', appStyle: true },\n};\n\nexport const webApps: WindowRegistry = {\n '/browser': { component: Browser, label: 'Browser', size: '2xl', appStyle: true, multiInstance: true },\n};\n\nexport const bundledApps: WindowRegistry = {\n ...utilityApps,\n ...gameApps,\n ...googleApps,\n ...documentApps,\n ...webApps,\n};\n\nexport {\n Calculator,\n Spreadsheet,\n Notepad,\n Weather,\n CurrencyConverter,\n PomodoroTimer,\n WorldClock,\n Chess,\n Checkers,\n Sudoku,\n Tetris,\n Game2048,\n Minesweeper,\n Email,\n GeminiChat,\n Calendar,\n Preview,\n Documents,\n Files,\n Browser,\n};\n\nexport { setPdfPreview } from './Preview';\nexport { openFilesInTrashMode } from './Files';\nexport type { PdfPreviewData } from './Preview';\n"]}
1
+ {"version":3,"sources":["../../src/apps/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Bundled apps — pre-built window registry entries for the 16 apps that ship\n * with `react-os-shell`. Consumers compose them into their own registry via\n * `createWindowRegistry`:\n *\n * import { createWindowRegistry } from 'react-os-shell';\n * import { bundledApps } from 'react-os-shell/apps';\n * import { erpEntities } from './shell-config';\n *\n * const windows = createWindowRegistry(bundledApps, erpEntities);\n *\n * Subsets are also exported (`utilityApps`, `gameApps`, `googleApps`) so a\n * consumer can pick-and-choose without importing every component.\n *\n * NOTE: 3 apps require consumer-supplied persistence (Calendar / Notepad for\n * stored content, Minesweeper for leaderboard). They're exported individually\n * but absent from `bundledApps` — wire the prefs provider to opt them in.\n * WorldClock uses `useShellPrefs()` so it lives in `bundledApps`; without a\n * consumer-supplied prefs adapter the city list won't survive a reload.\n */\nimport { lazy } from 'react';\nimport type { WindowRegistry } from '../windowRegistry/types';\n\n// ── Utility apps ──\nconst Calculator = lazy(() => import('./Calculator'));\nconst Spreadsheet = lazy(() => import('./Spreadsheet'));\nconst Weather = lazy(() => import('./Weather'));\nconst CurrencyConverter = lazy(() => import('./CurrencyConverter'));\nconst PomodoroTimer = lazy(() => import('./PomodoroTimer'));\nconst Notepad = lazy(() => import('./Notepad'));\nconst WorldClock = lazy(() => import('./WorldClock'));\nconst TodoList = lazy(() => import('./TodoList'));\n\n// ── Games ──\nconst Chess = lazy(() => import('./Chess'));\nconst Checkers = lazy(() => import('./Checkers'));\nconst Sudoku = lazy(() => import('./Sudoku'));\nconst Tetris = lazy(() => import('./Tetris'));\nconst Game2048 = lazy(() => import('./Game2048'));\nconst Minesweeper = lazy(() => import('./Minesweeper'));\n\n// ── Google apps ──\nconst Email = lazy(() => import('./Email'));\nconst GeminiChat = lazy(() => import('./GeminiChat'));\nconst Calendar = lazy(() => import('./Calendar'));\n\n// ── Document apps ──\nconst Preview = lazy(() => import('./Preview'));\nconst Documents = lazy(() => import('./Documents'));\nconst Files = lazy(() => import('./Files'));\n\n// ── Web ──\nconst Browser = lazy(() => import('./Browser'));\n\nexport const utilityApps: WindowRegistry = {\n '/calculator': { component: Calculator, label: 'Calculator', size: 'sm', allowPinOnTop: true, utility: true, widget: true, autoHeight: true, dimensions: [280, 420] },\n '/spreadsheet': { component: Spreadsheet, label: 'Spreadsheets', size: '2xl', appStyle: true, multiInstance: true },\n '/notepad': { component: Notepad, label: 'Notepad', size: 'lg', allowPinOnTop: true },\n '/weather': { component: Weather, label: 'Weather', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 400] },\n '/currency': { component: CurrencyConverter, label: 'Currency Converter', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },\n '/pomodoro': { component: PomodoroTimer, label: 'Pomodoro Timer', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 600] },\n '/world-clock': { component: WorldClock, label: 'World Clock', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },\n '/todo': { component: TodoList, label: 'Todo List', size: 'md', dimensions: [560, 640] },\n};\n\nexport const gameApps: WindowRegistry = {\n '/chess': { component: Chess, label: 'Chess', size: 'lg', compact: true },\n '/checkers': { component: Checkers, label: 'Checkers', size: 'lg', compact: true },\n '/sudoku': { component: Sudoku, label: 'Sudoku', size: 'sm', compact: true, dimensions: [360, 535] },\n '/tetris': { component: Tetris, label: 'Tetris', size: 'md', compact: true, dimensions: [452, 618] },\n '/2048': { component: Game2048, label: '2048', size: 'sm', compact: true },\n '/minesweeper': { component: Minesweeper, label: 'Minesweeper', size: 'sm', compact: true },\n};\n\nexport const googleApps: WindowRegistry = {\n '/email': { component: Email, label: 'Email', size: '2xl', appStyle: true },\n '/gemini': { component: GeminiChat, label: 'Gemini AI', size: 'lg' },\n '/calendar': { component: Calendar, label: 'Calendar', size: 'xl' },\n};\n\nexport const documentApps: WindowRegistry = {\n '/preview': { component: Preview, label: 'Preview', size: '2xl', appStyle: true, multiInstance: true },\n '/documents': { component: Documents, label: 'Documents', size: 'xl', appStyle: true, multiInstance: true },\n '/files': { component: Files, label: 'Files', size: 'xl', appStyle: true },\n};\n\nexport const webApps: WindowRegistry = {\n '/browser': { component: Browser, label: 'Browser', size: '2xl', appStyle: true, multiInstance: true },\n};\n\nexport const bundledApps: WindowRegistry = {\n ...utilityApps,\n ...gameApps,\n ...googleApps,\n ...documentApps,\n ...webApps,\n};\n\nexport {\n Calculator,\n Spreadsheet,\n Notepad,\n Weather,\n CurrencyConverter,\n PomodoroTimer,\n WorldClock,\n TodoList,\n Chess,\n Checkers,\n Sudoku,\n Tetris,\n Game2048,\n Minesweeper,\n Email,\n GeminiChat,\n Calendar,\n Preview,\n Documents,\n Files,\n Browser,\n};\n\nexport { setPdfPreview } from './Preview';\nexport { openFilesInTrashMode } from './Files';\nexport type { PdfPreviewData } from './Preview';\n"]}
@@ -0,0 +1,90 @@
1
+ import { useShellPrefs } from './chunk-36VM54SC.js';
2
+ import { useMemo, useCallback } from 'react';
3
+
4
+ var POMODORO_LEGACY_KEY = "pomodoro_tasks";
5
+ var POMODORO_LEGACY_MIGRATED_FLAG = "pomodoro_tasks_migrated";
6
+ function uid() {
7
+ return Math.random().toString(36).slice(2, 11);
8
+ }
9
+ function nowIso() {
10
+ return (/* @__PURE__ */ new Date()).toISOString();
11
+ }
12
+ function useTodoTasks() {
13
+ const { prefs, save } = useShellPrefs();
14
+ const tasks = useMemo(() => {
15
+ const raw = prefs.todo_tasks;
16
+ return Array.isArray(raw) ? raw : [];
17
+ }, [prefs.todo_tasks]);
18
+ const writeTasks = useCallback((next) => {
19
+ save({ todo_tasks: next });
20
+ }, [save]);
21
+ const addTask = useCallback((input) => {
22
+ const id = uid();
23
+ const ts = nowIso();
24
+ const task = {
25
+ done: false,
26
+ ...input,
27
+ // Ensure name is trimmed and id/timestamps overwrite anything the
28
+ // caller might have passed in.
29
+ name: input.name.trim(),
30
+ id,
31
+ createdAt: ts,
32
+ updatedAt: ts
33
+ };
34
+ writeTasks([...tasks, task]);
35
+ return id;
36
+ }, [tasks, writeTasks]);
37
+ const updateTask = useCallback((id, patch) => {
38
+ const next = tasks.map((t) => t.id === id ? { ...t, ...patch, id: t.id, updatedAt: nowIso() } : t);
39
+ writeTasks(next);
40
+ }, [tasks, writeTasks]);
41
+ const removeTask = useCallback((id) => {
42
+ writeTasks(tasks.filter((t) => t.id !== id));
43
+ }, [tasks, writeTasks]);
44
+ const toggleDone = useCallback((id) => {
45
+ const target = tasks.find((t) => t.id === id);
46
+ if (!target) return;
47
+ updateTask(id, { done: !target.done });
48
+ }, [tasks, updateTask]);
49
+ return { tasks, addTask, updateTask, removeTask, toggleDone, setAllTasks: writeTasks };
50
+ }
51
+ function migratePomodoroTasksOnce(currentTasks, setAllTasks) {
52
+ try {
53
+ if (localStorage.getItem(POMODORO_LEGACY_MIGRATED_FLAG)) return;
54
+ const raw = localStorage.getItem(POMODORO_LEGACY_KEY);
55
+ if (!raw) {
56
+ localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, "1");
57
+ return;
58
+ }
59
+ const legacy = JSON.parse(raw);
60
+ if (!Array.isArray(legacy) || legacy.length === 0) {
61
+ localStorage.removeItem(POMODORO_LEGACY_KEY);
62
+ localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, "1");
63
+ return;
64
+ }
65
+ const ts = nowIso();
66
+ const migrated = legacy.filter((t) => typeof t?.name === "string").map((t) => ({
67
+ id: t.id || uid(),
68
+ name: String(t.name),
69
+ done: !!t.done,
70
+ estimated: typeof t.estimated === "number" ? t.estimated : void 0,
71
+ completed: typeof t.completed === "number" ? t.completed : void 0,
72
+ createdAt: ts,
73
+ updatedAt: ts
74
+ }));
75
+ const existingIds = new Set(currentTasks.map((t) => t.id));
76
+ const additions = migrated.filter((t) => !existingIds.has(t.id));
77
+ setAllTasks([...additions, ...currentTasks]);
78
+ localStorage.removeItem(POMODORO_LEGACY_KEY);
79
+ localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, "1");
80
+ } catch {
81
+ try {
82
+ localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, "1");
83
+ } catch {
84
+ }
85
+ }
86
+ }
87
+
88
+ export { migratePomodoroTasksOnce, useTodoTasks };
89
+ //# sourceMappingURL=chunk-25L4DIKH.js.map
90
+ //# sourceMappingURL=chunk-25L4DIKH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/apps/_todoStore.ts"],"names":[],"mappings":"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","file":"chunk-25L4DIKH.js","sourcesContent":["/**\n * Shared task store — wraps `useShellPrefs()` so the Todo List app, the\n * Pomodoro widget, and the Calendar app all read/write the same array\n * at `prefs.todo_tasks`. Mutations bump `updatedAt` so Google-Tasks\n * sync (when enabled) can use last-write-wins conflict resolution.\n *\n * `migratePomodoroTasksOnce()` is a one-shot escape hatch: when the\n * Pomodoro widget mounts the first time after this refactor, it copies\n * any existing tasks from the legacy `localStorage.pomodoro_tasks` key\n * into the shared store and removes the old key. After that mount it's\n * a no-op.\n */\n\nimport { useCallback, useMemo } from 'react';\nimport { useShellPrefs } from '../shell/ShellPrefs';\nimport type { TodoTask } from './_todoTypes';\n\nconst POMODORO_LEGACY_KEY = 'pomodoro_tasks';\nconst POMODORO_LEGACY_MIGRATED_FLAG = 'pomodoro_tasks_migrated';\n\nfunction uid(): string {\n return Math.random().toString(36).slice(2, 11);\n}\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\nexport interface UseTodoTasks {\n tasks: TodoTask[];\n /** Add a new task. Returns the id of the freshly-added task. */\n addTask: (input: Partial<Omit<TodoTask, 'id' | 'createdAt' | 'updatedAt'>> & { name: string }) => string;\n /** Patch any subset of fields on a task by id. `updatedAt` is auto-bumped. */\n updateTask: (id: string, patch: Partial<TodoTask>) => void;\n /** Remove a task by id. Used by both Pomodoro's kebab menu and TodoList's delete action. */\n removeTask: (id: string) => void;\n /** Flip `done`. Same as `updateTask(id, { done: !done })` but faster to type at call sites. */\n toggleDone: (id: string) => void;\n /** Replace the entire list. Used by Google Tasks sync after a pull. */\n setAllTasks: (tasks: TodoTask[]) => void;\n}\n\nexport function useTodoTasks(): UseTodoTasks {\n const { prefs, save } = useShellPrefs();\n const tasks: TodoTask[] = useMemo(() => {\n const raw = prefs.todo_tasks;\n return Array.isArray(raw) ? (raw as TodoTask[]) : [];\n }, [prefs.todo_tasks]);\n\n const writeTasks = useCallback((next: TodoTask[]) => {\n save({ todo_tasks: next });\n }, [save]);\n\n const addTask = useCallback<UseTodoTasks['addTask']>((input) => {\n const id = uid();\n const ts = nowIso();\n const task: TodoTask = {\n done: false,\n ...input,\n // Ensure name is trimmed and id/timestamps overwrite anything the\n // caller might have passed in.\n name: input.name.trim(),\n id,\n createdAt: ts,\n updatedAt: ts,\n };\n writeTasks([...tasks, task]);\n return id;\n }, [tasks, writeTasks]);\n\n const updateTask = useCallback<UseTodoTasks['updateTask']>((id, patch) => {\n const next = tasks.map(t => t.id === id ? { ...t, ...patch, id: t.id, updatedAt: nowIso() } : t);\n writeTasks(next);\n }, [tasks, writeTasks]);\n\n const removeTask = useCallback<UseTodoTasks['removeTask']>((id) => {\n writeTasks(tasks.filter(t => t.id !== id));\n }, [tasks, writeTasks]);\n\n const toggleDone = useCallback<UseTodoTasks['toggleDone']>((id) => {\n const target = tasks.find(t => t.id === id);\n if (!target) return;\n updateTask(id, { done: !target.done });\n }, [tasks, updateTask]);\n\n return { tasks, addTask, updateTask, removeTask, toggleDone, setAllTasks: writeTasks };\n}\n\n/**\n * One-time migration: pull any tasks the Pomodoro widget previously\n * persisted to `localStorage.pomodoro_tasks` into the shared store.\n * Called from PomodoroTimer's mount effect — safe to invoke on every\n * mount, since the migrated flag stays set after the first run.\n *\n * Pass `setAllTasks` from `useTodoTasks()` so the migration can fold\n * the legacy entries in alongside any tasks the user has already added\n * elsewhere (i.e. via the new TodoList app).\n */\nexport function migratePomodoroTasksOnce(\n currentTasks: TodoTask[],\n setAllTasks: (next: TodoTask[]) => void,\n): void {\n try {\n if (localStorage.getItem(POMODORO_LEGACY_MIGRATED_FLAG)) return;\n const raw = localStorage.getItem(POMODORO_LEGACY_KEY);\n if (!raw) {\n localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1');\n return;\n }\n const legacy: Array<{ id?: string; name?: string; estimated?: number; completed?: number; done?: boolean }>\n = JSON.parse(raw);\n if (!Array.isArray(legacy) || legacy.length === 0) {\n localStorage.removeItem(POMODORO_LEGACY_KEY);\n localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1');\n return;\n }\n const ts = nowIso();\n const migrated: TodoTask[] = legacy\n .filter(t => typeof t?.name === 'string')\n .map(t => ({\n id: t.id || uid(),\n name: String(t.name),\n done: !!t.done,\n estimated: typeof t.estimated === 'number' ? t.estimated : undefined,\n completed: typeof t.completed === 'number' ? t.completed : undefined,\n createdAt: ts,\n updatedAt: ts,\n }));\n // Fold migrated tasks in first so the legacy list keeps its position\n // ahead of anything the user added via the new app.\n const existingIds = new Set(currentTasks.map(t => t.id));\n const additions = migrated.filter(t => !existingIds.has(t.id));\n setAllTasks([...additions, ...currentTasks]);\n localStorage.removeItem(POMODORO_LEGACY_KEY);\n localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1');\n } catch {\n // Don't block startup on corrupt localStorage — just mark it migrated.\n try { localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1'); } catch {}\n }\n}\n"]}
@@ -81,7 +81,24 @@ function getDemoCalendarEvents() {
81
81
  function isDemoMode() {
82
82
  return typeof window !== "undefined" && window.__REACT_OS_SHELL_DEMO_MODE__ === true;
83
83
  }
84
+ function getDemoTasks() {
85
+ const now = /* @__PURE__ */ new Date();
86
+ const ts = now.toISOString();
87
+ const dateAt = (dayOffset) => {
88
+ const d = new Date(now);
89
+ d.setDate(now.getDate() + dayOffset);
90
+ return d.toISOString().split("T")[0];
91
+ };
92
+ return [
93
+ { id: "demo-todo-1", name: "Review pull request", done: false, dueDate: dateAt(0), estimated: 2, completed: 1, createdAt: ts, updatedAt: ts },
94
+ { id: "demo-todo-2", name: "Draft the Q2 retrospective", done: false, dueDate: dateAt(0), estimated: 3, completed: 0, createdAt: ts, updatedAt: ts },
95
+ { id: "demo-todo-3", name: "Buy birthday card for Maya", done: false, dueDate: dateAt(2), createdAt: ts, updatedAt: ts },
96
+ { id: "demo-todo-4", name: "Update onboarding doc", done: false, dueDate: dateAt(5), estimated: 4, completed: 0, createdAt: ts, updatedAt: ts },
97
+ { id: "demo-todo-5", name: "Reply to investor email", done: true, estimated: 1, completed: 1, createdAt: ts, updatedAt: ts },
98
+ { id: "demo-todo-6", name: 'Read "Working in Public"', done: false, createdAt: ts, updatedAt: ts }
99
+ ];
100
+ }
84
101
 
85
- export { getDemoCalendarEvents, getDemoEmails, isDemoMode };
86
- //# sourceMappingURL=chunk-62MVMTBT.js.map
87
- //# sourceMappingURL=chunk-62MVMTBT.js.map
102
+ export { getDemoCalendarEvents, getDemoEmails, getDemoTasks, isDemoMode };
103
+ //# sourceMappingURL=chunk-5VXRBUEH.js.map
104
+ //# sourceMappingURL=chunk-5VXRBUEH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/apps/google-demo-fixtures.ts"],"names":[],"mappings":"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","file":"chunk-5VXRBUEH.js","sourcesContent":["/**\n * Demo-mode fixtures for the Google apps (Email, Calendar). Used when\n * `window.__REACT_OS_SHELL_DEMO_MODE__ === true` so the demo deployment\n * can show populated UIs without requiring a Google OAuth Client ID.\n *\n * Imported only by the demo-mode renderers — the real Gmail/Calendar\n * code paths never touch this file.\n */\n\nexport interface DemoEmail {\n id: string;\n from: string;\n subject: string;\n snippet: string;\n body: string;\n receivedAt: string; // relative to now\n unread: boolean;\n}\n\n// Shape matches Calendar.tsx's CalendarEvent so demo fixtures can be\n// dropped straight into its events list without translation.\nexport interface DemoCalendarEvent {\n id: string;\n title: string;\n date: string; // YYYY-MM-DD\n start_time?: string; // HH:MM\n end_time?: string; // HH:MM\n color: string; // matches the COLORS keys in Calendar.tsx\n description?: string;\n}\n\n// Shape matches TodoTask in `_todoTypes.ts` — used by the Todo List app's\n// demo-mode fallback when the user hasn't connected Google.\nexport interface DemoTodoTask {\n id: string;\n name: string;\n done: boolean;\n dueDate?: string; // YYYY-MM-DD\n estimated?: number;\n completed?: number;\n notes?: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport function getDemoEmails(): DemoEmail[] {\n const now = Date.now();\n const m = (mins: number) => new Date(now - mins * 60_000).toISOString();\n return [\n {\n id: 'demo-1',\n from: 'Calendar <calendar-noreply@example.com>',\n subject: 'Reminder: Design review at 3:00 PM',\n snippet: 'You have a design review starting in 30 minutes with the platform team…',\n body: 'You have a design review starting in 30 minutes with the platform team. Agenda is in the doc — please skim before joining.',\n receivedAt: m(15),\n unread: true,\n },\n {\n id: 'demo-2',\n from: 'Sam Patel <sam@example.com>',\n subject: 'Re: STEP file from procurement',\n snippet: \"Got it — I'll drop the file in the shared folder by EOD. Let me know if the cap thickness needs to change.\",\n body: \"Got it — I'll drop the file in the shared folder by EOD. Let me know if the cap thickness needs to change.\\n\\nThanks,\\nSam\",\n receivedAt: m(85),\n unread: true,\n },\n {\n id: 'demo-3',\n from: 'GitHub <noreply@github.com>',\n subject: '[react-os-shell] PR #42 ready for review',\n snippet: 'A new pull request has been opened in your repository react-os-shell.',\n body: 'A new pull request has been opened in your repository react-os-shell.\\n\\n#42: feat(preview): capped section view\\n\\nView on GitHub: https://github.com/...',\n receivedAt: m(180),\n unread: false,\n },\n {\n id: 'demo-4',\n from: 'Stripe <noreply@stripe.com>',\n subject: 'Your Stripe payout has been processed',\n snippet: 'Your payout of $1,247.32 has been deposited to your bank account.',\n body: 'Your payout of $1,247.32 has been deposited to your bank account ending in 4242.\\n\\nView details in your Dashboard.',\n receivedAt: m(310),\n unread: false,\n },\n {\n id: 'demo-5',\n from: 'Maya Lin <maya.lin@example.com>',\n subject: 'Lunch tomorrow?',\n snippet: 'I have a couple options open — that ramen place on 4th, or the new Korean place near you?',\n body: 'I have a couple options open — that ramen place on 4th, or the new Korean place near you? 12:30?',\n receivedAt: m(720),\n unread: false,\n },\n {\n id: 'demo-6',\n from: 'AWS Billing <no-reply@aws.amazon.com>',\n subject: 'Your monthly AWS invoice',\n snippet: 'Your invoice for the period ending Apr 30 is now available.',\n body: 'Your invoice for the period ending April 30 is now available in the AWS console. Total: $84.21.',\n receivedAt: m(1440),\n unread: false,\n },\n ];\n}\n\n// 6 events scattered across the current week. The dates are recomputed\n// relative to \"now\" each time the function runs, so the demo always\n// feels current.\nexport function getDemoCalendarEvents(): DemoCalendarEvent[] {\n const now = new Date();\n const dayOfWeek = now.getDay();\n const weekStart = new Date(now);\n weekStart.setDate(now.getDate() - dayOfWeek);\n const dateAt = (dayOffset: number) => {\n const d = new Date(weekStart);\n d.setDate(weekStart.getDate() + dayOffset);\n return d.toISOString().split('T')[0];\n };\n return [\n { id: 'demo-event-1', title: 'Standup', date: dateAt(1), start_time: '09:30', end_time: '10:00', color: 'blue' },\n { id: 'demo-event-2', title: 'Design review', date: dateAt(2), start_time: '15:00', end_time: '16:00', color: 'purple', description: 'Platform team — Conference Room B' },\n { id: 'demo-event-3', title: 'Lunch with Maya', date: dateAt(3), start_time: '12:30', end_time: '13:30', color: 'orange', description: 'Ramen on 4th' },\n { id: 'demo-event-4', title: '1:1 with manager',date: dateAt(3), start_time: '16:00', end_time: '16:30', color: 'green' },\n { id: 'demo-event-5', title: 'Sprint planning', date: dateAt(4), start_time: '10:00', end_time: '11:30', color: 'pink' },\n { id: 'demo-event-6', title: 'Focus time', date: dateAt(5), start_time: '14:00', end_time: '17:00', color: 'gray' },\n ];\n}\n\nexport function isDemoMode(): boolean {\n return typeof window !== 'undefined' && (window as any).__REACT_OS_SHELL_DEMO_MODE__ === true;\n}\n\n// Demo Todo tasks. Mix of completed / pending / due-today items so the\n// Todo List app, the Pomodoro widget, and the Calendar deadline badge\n// all have something to render in demo mode without a Google sign-in.\nexport function getDemoTasks(): DemoTodoTask[] {\n const now = new Date();\n const ts = now.toISOString();\n const dateAt = (dayOffset: number) => {\n const d = new Date(now);\n d.setDate(now.getDate() + dayOffset);\n return d.toISOString().split('T')[0];\n };\n return [\n { id: 'demo-todo-1', name: 'Review pull request', done: false, dueDate: dateAt(0), estimated: 2, completed: 1, createdAt: ts, updatedAt: ts },\n { id: 'demo-todo-2', name: 'Draft the Q2 retrospective', done: false, dueDate: dateAt(0), estimated: 3, completed: 0, createdAt: ts, updatedAt: ts },\n { id: 'demo-todo-3', name: 'Buy birthday card for Maya', done: false, dueDate: dateAt(2), createdAt: ts, updatedAt: ts },\n { id: 'demo-todo-4', name: 'Update onboarding doc', done: false, dueDate: dateAt(5), estimated: 4, completed: 0, createdAt: ts, updatedAt: ts },\n { id: 'demo-todo-5', name: 'Reply to investor email', done: true, estimated: 1, completed: 1, createdAt: ts, updatedAt: ts },\n { id: 'demo-todo-6', name: 'Read \"Working in Public\"', done: false, createdAt: ts, updatedAt: ts },\n ];\n}\n"]}
@@ -8,6 +8,7 @@ var SCOPES = [
8
8
  "https://www.googleapis.com/auth/gmail.modify",
9
9
  "https://www.googleapis.com/auth/calendar.readonly",
10
10
  "https://www.googleapis.com/auth/calendar.events",
11
+ "https://www.googleapis.com/auth/tasks",
11
12
  "https://www.googleapis.com/auth/generative-language.retriever"
12
13
  ].join(" ");
13
14
  var TOKEN_KEY = "google_access_token";
@@ -204,5 +205,5 @@ function useGoogleAuth() {
204
205
  }
205
206
 
206
207
  export { getGoogleAccessToken, useGoogleAuth };
207
- //# sourceMappingURL=chunk-46LICZUM.js.map
208
- //# sourceMappingURL=chunk-46LICZUM.js.map
208
+ //# sourceMappingURL=chunk-MVWEL34Y.js.map
209
+ //# sourceMappingURL=chunk-MVWEL34Y.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useGoogleAuth.ts"],"names":[],"mappings":"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","file":"chunk-MVWEL34Y.js","sourcesContent":["/**\n * Google OAuth2 hook for Gmail, Calendar, Tasks, and Gemini access.\n *\n * Uses Google Identity Services (GIS) to get an access token with combined scopes.\n * Requires a Google Cloud OAuth2 Client ID configured in System Settings.\n *\n * Scopes requested:\n * - Gmail: read, compose, send, modify\n * - Calendar: read, write events\n * - Tasks: read/write (Todo List app)\n * - Gemini: generative language (via Vertex AI or Google AI)\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\n\nconst SCOPES = [\n 'https://www.googleapis.com/auth/gmail.readonly',\n 'https://www.googleapis.com/auth/gmail.compose',\n 'https://www.googleapis.com/auth/gmail.send',\n 'https://www.googleapis.com/auth/gmail.modify',\n 'https://www.googleapis.com/auth/calendar.readonly',\n 'https://www.googleapis.com/auth/calendar.events',\n 'https://www.googleapis.com/auth/tasks',\n 'https://www.googleapis.com/auth/generative-language.retriever',\n].join(' ');\n\nconst TOKEN_KEY = 'google_access_token';\nconst TOKEN_EXPIRY_KEY = 'google_token_expiry';\nconst USER_KEY = 'google_user_info';\nconst CLIENT_ID_KEY = 'google_oauth_client_id';\n\ninterface GoogleUser {\n email: string;\n name: string;\n picture: string;\n}\n\ninterface GoogleAuthState {\n isConnected: boolean;\n user: GoogleUser | null;\n accessToken: string | null;\n loading: boolean;\n error: string | null;\n connect: () => void;\n disconnect: () => void;\n getClientId: () => string;\n setClientId: (id: string) => void;\n hasClientId: boolean;\n}\n\n// Load GIS script\nlet gisLoaded = false;\nlet gisLoadPromise: Promise<void> | null = null;\n\nfunction loadGisScript(): Promise<void> {\n if (gisLoaded) return Promise.resolve();\n if (gisLoadPromise) return gisLoadPromise;\n\n gisLoadPromise = new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = 'https://accounts.google.com/gsi/client';\n script.async = true;\n script.defer = true;\n script.onload = () => { gisLoaded = true; resolve(); };\n script.onerror = () => reject(new Error('Failed to load Google Identity Services'));\n document.head.appendChild(script);\n });\n return gisLoadPromise;\n}\n\nfunction isTokenValid(): boolean {\n const expiry = localStorage.getItem(TOKEN_EXPIRY_KEY);\n if (!expiry) return false;\n return Date.now() < parseInt(expiry, 10) - 60000; // 1 min buffer\n}\n\nexport function getGoogleAccessToken(): string | null {\n if (!isTokenValid()) return null;\n return localStorage.getItem(TOKEN_KEY);\n}\n\nexport function getGoogleClientId(): string {\n return localStorage.getItem(CLIENT_ID_KEY) || '';\n}\n\nexport default function useGoogleAuth(): GoogleAuthState {\n const [accessToken, setAccessToken] = useState<string | null>(() => isTokenValid() ? localStorage.getItem(TOKEN_KEY) : null);\n const [user, setUser] = useState<GoogleUser | null>(() => {\n try { const u = localStorage.getItem(USER_KEY); return u ? JSON.parse(u) : null; } catch { return null; }\n });\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const clientRef = useRef<any>(null);\n // Tracks an in-flight silent renewal so handleTokenResponse can suppress\n // its loading/error UI when the request didn't come from a user click.\n const silentInFlightRef = useRef(false);\n // setTimeout handle for the next scheduled silent renewal.\n const refreshTimerRef = useRef<number | null>(null);\n\n const clientId = getGoogleClientId();\n const hasClientId = !!clientId;\n\n const setClientId = useCallback((id: string) => {\n localStorage.setItem(CLIENT_ID_KEY, id);\n window.dispatchEvent(new Event('google-client-id-changed'));\n }, []);\n\n // Fetch user info from Google\n const fetchUserInfo = useCallback(async (token: string) => {\n try {\n const res = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (res.ok) {\n const data = await res.json();\n const userInfo: GoogleUser = { email: data.email, name: data.name, picture: data.picture };\n localStorage.setItem(USER_KEY, JSON.stringify(userInfo));\n setUser(userInfo);\n }\n } catch { /* ignore */ }\n }, []);\n\n const cancelRefreshTimer = useCallback(() => {\n if (refreshTimerRef.current !== null) {\n window.clearTimeout(refreshTimerRef.current);\n refreshTimerRef.current = null;\n }\n }, []);\n\n // Schedule a silent refresh to fire ~60s before the current token expires.\n // Google reissues a fresh token without showing UI when the user's Google\n // session is still active and they previously granted consent.\n const scheduleSilentRefresh = useCallback(() => {\n cancelRefreshTimer();\n const expiry = parseInt(localStorage.getItem(TOKEN_EXPIRY_KEY) || '0', 10);\n if (!expiry) return;\n const delay = Math.max(0, expiry - Date.now() - 60_000);\n refreshTimerRef.current = window.setTimeout(() => {\n refreshTimerRef.current = null;\n if (!clientRef.current) return;\n silentInFlightRef.current = true;\n try {\n clientRef.current.requestAccessToken({ prompt: '' });\n } catch {\n silentInFlightRef.current = false;\n }\n }, delay);\n }, [cancelRefreshTimer]);\n\n const handleTokenResponse = useCallback((response: any) => {\n const wasSilent = silentInFlightRef.current;\n silentInFlightRef.current = false;\n if (response.error) {\n if (wasSilent) {\n // Silent renewal failed (user signed out of Google, revoked access,\n // session expired, etc.). Drop the token quietly — the consumer\n // sees `isConnected = false` and the Connect button reappears.\n localStorage.removeItem(TOKEN_KEY);\n localStorage.removeItem(TOKEN_EXPIRY_KEY);\n setAccessToken(null);\n } else {\n setError(response.error);\n }\n setLoading(false);\n return;\n }\n const token = response.access_token;\n const expiresIn = response.expires_in || 3600;\n localStorage.setItem(TOKEN_KEY, token);\n localStorage.setItem(TOKEN_EXPIRY_KEY, String(Date.now() + expiresIn * 1000));\n setAccessToken(token);\n setError(null);\n setLoading(false);\n if (!wasSilent) fetchUserInfo(token);\n // Chain the next silent refresh.\n scheduleSilentRefresh();\n }, [fetchUserInfo, scheduleSilentRefresh]);\n\n // Initialize GIS client. Once ready, schedule a silent refresh if we\n // already hold a valid token (e.g. user just reopened the tab with time\n // left on the clock) — and if the token has actually expired, request a\n // fresh one silently so they don't have to click Connect again.\n useEffect(() => {\n if (!clientId) return;\n loadGisScript().then(() => {\n const google = (window as any).google;\n if (!google?.accounts?.oauth2) return;\n clientRef.current = google.accounts.oauth2.initTokenClient({\n client_id: clientId,\n scope: SCOPES,\n callback: handleTokenResponse,\n });\n if (isTokenValid()) {\n scheduleSilentRefresh();\n } else if (localStorage.getItem(TOKEN_KEY)) {\n // We had a token last session but it's now expired. Try silent\n // renewal — succeeds if the Google session is still alive.\n silentInFlightRef.current = true;\n try {\n clientRef.current.requestAccessToken({ prompt: '' });\n } catch {\n silentInFlightRef.current = false;\n }\n }\n }).catch(err => setError(err.message));\n return () => cancelRefreshTimer();\n }, [clientId, handleTokenResponse, scheduleSilentRefresh, cancelRefreshTimer]);\n\n const connect = useCallback(() => {\n if (!clientRef.current) {\n setError('Google client not initialized. Check your Client ID.');\n return;\n }\n setLoading(true);\n setError(null);\n clientRef.current.requestAccessToken({ prompt: 'consent' });\n }, []);\n\n const disconnect = useCallback(() => {\n cancelRefreshTimer();\n const token = localStorage.getItem(TOKEN_KEY);\n if (token) {\n const google = (window as any).google;\n if (google?.accounts?.oauth2) {\n google.accounts.oauth2.revoke(token);\n }\n }\n localStorage.removeItem(TOKEN_KEY);\n localStorage.removeItem(TOKEN_EXPIRY_KEY);\n localStorage.removeItem(USER_KEY);\n setAccessToken(null);\n setUser(null);\n }, [cancelRefreshTimer]);\n\n // Belt-and-suspenders expiry check. Most expiries are caught by the\n // scheduled refresh above; this fires every 30s if the timer ever\n // misses (e.g. setTimeout drift after long sleep).\n useEffect(() => {\n const interval = setInterval(() => {\n if (accessToken && !isTokenValid()) {\n setAccessToken(null);\n // Try one silent refresh before giving up.\n if (clientRef.current && !silentInFlightRef.current) {\n silentInFlightRef.current = true;\n try { clientRef.current.requestAccessToken({ prompt: '' }); }\n catch { silentInFlightRef.current = false; }\n }\n }\n }, 30000);\n return () => clearInterval(interval);\n }, [accessToken]);\n\n return {\n isConnected: !!accessToken && isTokenValid(),\n user,\n accessToken,\n loading,\n error,\n connect,\n disconnect,\n getClientId: () => clientId,\n setClientId,\n hasClientId,\n };\n}\n"]}
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { useEmailUnreadCount } from './chunk-PDFQNHW7.js';
2
2
  import { formatDate } from './chunk-NSU7OHPC.js';
3
3
  export { formatDate } from './chunk-NSU7OHPC.js';
4
- import { useGoogleAuth } from './chunk-46LICZUM.js';
5
4
  import { subscribePomo, getPomoSnapshot } from './chunk-MK3HLUO4.js';
5
+ import { useGoogleAuth } from './chunk-MVWEL34Y.js';
6
6
  import { useShellPrefs } from './chunk-36VM54SC.js';
7
7
  export { ShellPrefsProvider, useLocalStoragePrefs, useShellPrefs } from './chunk-36VM54SC.js';
8
8
  import { playNotification, playStartup, soundsEnabled, getSoundConfig, SOUND_PACK_KEYS, SOUND_PACKS, SOUND_TYPES, SOUND_TYPE_LABELS, playLogout, setSoundForType, previewSound, setAllSounds } from './chunk-D7PYW2QS.js';
@@ -862,7 +862,7 @@ function StatusBadge({ status }) {
862
862
  }
863
863
 
864
864
  // src/version.ts
865
- var VERSION = "0.2.44" ;
865
+ var VERSION = "0.2.45" ;
866
866
  var APP_VERSION = VERSION;
867
867
 
868
868
  // src/changelog.ts
package/dist/styles.css CHANGED
@@ -140,10 +140,12 @@
140
140
  [data-theme="dark"] .border-blue-400\/60 { border-color: rgba(96, 165, 250, 0.45) !important; }
141
141
  [data-theme="dark"] .hover\:bg-gray-200\/40:hover { background-color: rgba(49, 50, 68, 0.4) !important; }
142
142
 
143
- /* Inputs */
144
- [data-theme="dark"] input:not([type="checkbox"]):not([type="radio"]):not([type="color"]):not([type="file"]),
145
- [data-theme="dark"] select,
146
- [data-theme="dark"] textarea {
143
+ /* Inputs — apply the form-input dark styling, but skip elements that
144
+ explicitly opt into a transparent background (e.g. the start-menu
145
+ search) so they keep their parent's frosted-glass tile. */
146
+ [data-theme="dark"] input:not(.bg-transparent):not([type="checkbox"]):not([type="radio"]):not([type="color"]):not([type="file"]),
147
+ [data-theme="dark"] select:not(.bg-transparent),
148
+ [data-theme="dark"] textarea:not(.bg-transparent) {
147
149
  background-color: #181825 !important;
148
150
  border-color: #45475a !important;
149
151
  color: #cdd6f4 !important;