react-os-shell 0.2.43 → 0.2.44

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 (59) hide show
  1. package/dist/{Browser-5ZCLRIRU.js → Browser-LSJORULM.js} +3 -3
  2. package/dist/{Browser-5ZCLRIRU.js.map → Browser-LSJORULM.js.map} +1 -1
  3. package/dist/{Calculator-OHL2AZ52.js → Calculator-ZKEH53OV.js} +4 -4
  4. package/dist/{Calculator-OHL2AZ52.js.map → Calculator-ZKEH53OV.js.map} +1 -1
  5. package/dist/{Calendar-6AHL3UJY.js → Calendar-4UQDQ3NT.js} +3 -3
  6. package/dist/{Calendar-6AHL3UJY.js.map → Calendar-4UQDQ3NT.js.map} +1 -1
  7. package/dist/{CurrencyConverter-XZVZ7XOF.js → CurrencyConverter-TXBFDFG2.js} +56 -50
  8. package/dist/CurrencyConverter-TXBFDFG2.js.map +1 -0
  9. package/dist/{Documents-IPVZ47JX.js → Documents-CQVIIFZV.js} +3 -3
  10. package/dist/{Documents-IPVZ47JX.js.map → Documents-CQVIIFZV.js.map} +1 -1
  11. package/dist/{Email-Z7FDKAFD.js → Email-HRBZUWPY.js} +3 -3
  12. package/dist/{Email-Z7FDKAFD.js.map → Email-HRBZUWPY.js.map} +1 -1
  13. package/dist/Files-ITIKVHIE.js +8 -0
  14. package/dist/{Files-KEHRZ2UY.js.map → Files-ITIKVHIE.js.map} +1 -1
  15. package/dist/{Minesweeper-NGN4O6C4.js → Minesweeper-QGUPDVRS.js} +3 -3
  16. package/dist/{Minesweeper-NGN4O6C4.js.map → Minesweeper-QGUPDVRS.js.map} +1 -1
  17. package/dist/{Notepad-W3YYZ3GS.js → Notepad-74CQPZCV.js} +3 -3
  18. package/dist/{Notepad-W3YYZ3GS.js.map → Notepad-74CQPZCV.js.map} +1 -1
  19. package/dist/PomodoroTimer-PRP5CZ3S.js +627 -0
  20. package/dist/PomodoroTimer-PRP5CZ3S.js.map +1 -0
  21. package/dist/Preview-4MBQI66Q.js +7 -0
  22. package/dist/{Preview-4354N46U.js.map → Preview-4MBQI66Q.js.map} +1 -1
  23. package/dist/{Spreadsheet-FCFII6DW.js → Spreadsheet-MKXPPSKV.js} +3 -3
  24. package/dist/{Spreadsheet-FCFII6DW.js.map → Spreadsheet-MKXPPSKV.js.map} +1 -1
  25. package/dist/Weather-YXSCSPQT.js +424 -0
  26. package/dist/Weather-YXSCSPQT.js.map +1 -0
  27. package/dist/WorldClock-QO5PVJQQ.js +250 -0
  28. package/dist/WorldClock-QO5PVJQQ.js.map +1 -0
  29. package/dist/apps/index.d.ts +6 -10
  30. package/dist/apps/index.js +18 -18
  31. package/dist/apps/index.js.map +1 -1
  32. package/dist/chunk-7CCHEEYC.js +94 -0
  33. package/dist/chunk-7CCHEEYC.js.map +1 -0
  34. package/dist/{chunk-T2NQXP2J.js → chunk-7M3BBAHQ.js} +10 -4
  35. package/dist/chunk-7M3BBAHQ.js.map +1 -0
  36. package/dist/{chunk-IY7JJVHR.js → chunk-DUUANLLE.js} +3 -3
  37. package/dist/{chunk-IY7JJVHR.js.map → chunk-DUUANLLE.js.map} +1 -1
  38. package/dist/chunk-MK3HLUO4.js +380 -0
  39. package/dist/chunk-MK3HLUO4.js.map +1 -0
  40. package/dist/{chunk-2SRU4BYH.js → chunk-MTLVXT2C.js} +4 -4
  41. package/dist/{chunk-2SRU4BYH.js.map → chunk-MTLVXT2C.js.map} +1 -1
  42. package/dist/{chunk-TVOBLSSV.js → chunk-UK2AA3J6.js} +3 -3
  43. package/dist/{chunk-TVOBLSSV.js.map → chunk-UK2AA3J6.js.map} +1 -1
  44. package/dist/index.d.ts +16 -1
  45. package/dist/index.js +4089 -11
  46. package/dist/index.js.map +1 -1
  47. package/package.json +1 -1
  48. package/dist/CurrencyConverter-XZVZ7XOF.js.map +0 -1
  49. package/dist/Files-KEHRZ2UY.js +0 -8
  50. package/dist/PomodoroTimer-T2J5NDJR.js +0 -196
  51. package/dist/PomodoroTimer-T2J5NDJR.js.map +0 -1
  52. package/dist/Preview-4354N46U.js +0 -7
  53. package/dist/Weather-XTADR7Z3.js +0 -266
  54. package/dist/Weather-XTADR7Z3.js.map +0 -1
  55. package/dist/WorldClock-OFK2EA2H.js +0 -126
  56. package/dist/WorldClock-OFK2EA2H.js.map +0 -1
  57. package/dist/chunk-7KZWBIDL.js +0 -4144
  58. package/dist/chunk-7KZWBIDL.js.map +0 -1
  59. package/dist/chunk-T2NQXP2J.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-os-shell",
3
- "version": "0.2.43",
3
+ "version": "0.2.44",
4
4
  "description": "Desktop-style React UI shell — windows, taskbar, start menu, sticky notes, frosted glass theming, and 17 bundled apps including a PDF Preview viewer.",
5
5
  "license": "MIT",
6
6
  "author": "Victor Y. Mau",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/apps/CurrencyConverter.tsx"],"names":[],"mappings":"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","file":"CurrencyConverter-XZVZ7XOF.js","sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport { useWidgetSettings } from '../shell/Modal';\nimport WidgetSettingsModal, { loadAppearance, type WidgetAppearance } from '../shell/WidgetSettingsModal';\n\nconst ALL_CURRENCIES = ['USD', 'CNY', 'AUD', 'GBP', 'EUR', 'JPY', 'CAD', 'THB', 'NZD', 'SGD', 'HKD', 'CHF', 'KRW', 'INR', 'MXN', 'BRL'];\n\nconst DEFAULT_PAIRS: [string, string][] = [\n ['USD', 'CNY'], ['USD', 'AUD'], ['GBP', 'USD'], ['USD', 'JPY'], ['USD', 'CAD'],\n];\n\nconst PAIRS_KEY = 'currency_pairs';\nconst SETTINGS_KEY = 'currency_appearance';\nconst CACHE_KEY = 'currency_rates_cache';\nconst CACHE_TTL = 3600000;\n\ntype CacheEntry = { rates: Record<string, number>; timestamp: number };\n\nfunction getCached(base: string): Record<string, number> | null {\n try { const c: Record<string, CacheEntry> = JSON.parse(localStorage.getItem(CACHE_KEY) || '{}'); const e = c[base]; if (e && Date.now() - e.timestamp < CACHE_TTL) return e.rates; } catch {} return null;\n}\nfunction setCache(base: string, rates: Record<string, number>) {\n try { const c = JSON.parse(localStorage.getItem(CACHE_KEY) || '{}'); c[base] = { rates, timestamp: Date.now() }; localStorage.setItem(CACHE_KEY, JSON.stringify(c)); } catch {}\n}\nfunction loadPairs(): [string, string][] {\n try { const s = JSON.parse(localStorage.getItem(PAIRS_KEY) || ''); if (Array.isArray(s) && s.length) return s; } catch {} return DEFAULT_PAIRS;\n}\n\nconst FLAG: Record<string, string> = {\n USD: '\\u{1F1FA}\\u{1F1F8}', CNY: '\\u{1F1E8}\\u{1F1F3}', AUD: '\\u{1F1E6}\\u{1F1FA}',\n GBP: '\\u{1F1EC}\\u{1F1E7}', JPY: '\\u{1F1EF}\\u{1F1F5}', CAD: '\\u{1F1E8}\\u{1F1E6}',\n EUR: '\\u{1F1EA}\\u{1F1FA}', THB: '\\u{1F1F9}\\u{1F1ED}', NZD: '\\u{1F1F3}\\u{1F1FF}',\n SGD: '\\u{1F1F8}\\u{1F1EC}', HKD: '\\u{1F1ED}\\u{1F1F0}', CHF: '\\u{1F1E8}\\u{1F1ED}',\n KRW: '\\u{1F1F0}\\u{1F1F7}', INR: '\\u{1F1EE}\\u{1F1F3}', MXN: '\\u{1F1F2}\\u{1F1FD}',\n BRL: '\\u{1F1E7}\\u{1F1F7}',\n};\n\nexport default function CurrencyConverter() {\n const [pairs, setPairs] = useState(loadPairs);\n const [appearance, setAppearance] = useState(() => loadAppearance(SETTINGS_KEY));\n const [allRates, setAllRates] = useState<Record<string, Record<string, number>>>({});\n const [updated, setUpdated] = useState<Date | null>(null);\n const [loading, setLoading] = useState(false);\n const [settingsOpen, setSettingsOpen] = useState(false);\n const [configPairs, setConfigPairs] = useState<[string, string][]>([]);\n const [configAppearance, setConfigAppearance] = useState<WidgetAppearance>(appearance);\n const [newFrom, setNewFrom] = useState('USD');\n const [newTo, setNewTo] = useState('CNY');\n\n useWidgetSettings(useCallback(() => {\n setConfigPairs([...pairs]);\n setConfigAppearance({ ...appearance });\n setSettingsOpen(true);\n }, [pairs, appearance]));\n\n useEffect(() => {\n const bases = [...new Set(pairs.map(([from]) => from))];\n let mounted = true;\n async function fetchAll() {\n setLoading(true);\n const result: Record<string, Record<string, number>> = {};\n for (const base of bases) {\n const cached = getCached(base);\n if (cached) { result[base] = cached; continue; }\n try { const res = await fetch(`https://open.er-api.com/v6/latest/${base}`); const data = await res.json(); if (data.rates) { result[base] = data.rates; setCache(base, data.rates); } } catch {}\n }\n if (mounted) { setAllRates(result); setUpdated(new Date()); setLoading(false); }\n }\n fetchAll();\n return () => { mounted = false; };\n }, [pairs]);\n\n const saveSettings = () => {\n if (configPairs.length === 0) return;\n setPairs(configPairs); setAppearance(configAppearance);\n localStorage.setItem(PAIRS_KEY, JSON.stringify(configPairs));\n localStorage.setItem(SETTINGS_KEY, JSON.stringify(configAppearance));\n setSettingsOpen(false);\n };\n\n return (\n <>\n {/* Theme-aware background — `--window-content-rgb` resolves to white in\n * light mode and the dark Catppuccin base in dark mode (and the per-\n * theme tint for pink / green / grey / blue). Hard-coded white\n * previously made the widget unreadable in dark mode. */}\n <div className=\"flex flex-col h-full rounded-lg\"\n style={{ backgroundColor: `rgb(var(--window-content-rgb) / ${appearance.activeOpacity / 100})`, backdropFilter: appearance.activeBlur > 0 ? `blur(${appearance.activeBlur}px)` : undefined }}>\n <div className=\"px-3 py-2 space-y-0.5 flex-1\">\n {loading && <div className=\"text-xs text-gray-400 text-center py-4\">Loading rates...</div>}\n {pairs.map(([from, to], idx) => {\n const rate = allRates[from]?.[to];\n return (\n <button key={`${from}-${to}-${idx}`} onClick={() => {\n const swapped: [string, string][] = pairs.map((p, i) => i === idx ? [p[1], p[0]] : p);\n setPairs(swapped);\n localStorage.setItem(PAIRS_KEY, JSON.stringify(swapped));\n }}\n className=\"flex items-center justify-between py-1.5 border-b border-gray-200/50 last:border-0 w-full hover:bg-gray-100/50 rounded transition-colors cursor-pointer\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-base\">{FLAG[from] || ''}</span>\n <span className=\"text-xs font-medium text-gray-500\">{from}</span>\n <svg className=\"h-3 w-3 text-gray-300\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4\" /></svg>\n <span className=\"text-base\">{FLAG[to] || ''}</span>\n <span className=\"text-xs font-medium text-gray-500\">{to}</span>\n </div>\n <div className=\"text-sm font-mono font-semibold text-gray-800\">\n {rate != null ? rate.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 4 }) : '—'}\n </div>\n </button>\n );\n })}\n </div>\n {updated && <div className=\"text-[9px] text-gray-400 text-center py-1\">Updated {updated.toLocaleTimeString()}</div>}\n </div>\n\n <WidgetSettingsModal open={settingsOpen} onClose={() => setSettingsOpen(false)} title=\"Currency Settings\"\n appearance={configAppearance} onAppearanceChange={setConfigAppearance} onSave={saveSettings}>\n <div>\n <h3 className=\"text-sm font-semibold text-gray-700 mb-2\">Currency Pairs</h3>\n <div className=\"space-y-1 mb-2\">\n {configPairs.map(([f, t], i) => (\n <div key={i} className=\"flex items-center justify-between py-1 px-2 bg-gray-50 rounded\">\n <span className=\"text-sm\">{FLAG[f] || ''} {f} → {FLAG[t] || ''} {t}</span>\n <button onClick={() => setConfigPairs(p => p.filter((_, idx) => idx !== i))} className=\"text-red-400 hover:text-red-600\">&times;</button>\n </div>\n ))}\n </div>\n <div className=\"flex items-center gap-2\">\n <select value={newFrom} onChange={e => setNewFrom(e.target.value)}\n className=\"bg-gray-50 border border-gray-200 rounded px-2 py-1 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500\">\n {ALL_CURRENCIES.map(c => <option key={c}>{c}</option>)}\n </select>\n <span className=\"text-gray-400\">→</span>\n <select value={newTo} onChange={e => setNewTo(e.target.value)}\n className=\"bg-gray-50 border border-gray-200 rounded px-2 py-1 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500\">\n {ALL_CURRENCIES.map(c => <option key={c}>{c}</option>)}\n </select>\n <button onClick={() => { if (newFrom !== newTo) setConfigPairs(p => [...p, [newFrom, newTo]]); }}\n className=\"text-sm font-medium text-blue-600 hover:text-blue-800 px-2\">+ Add</button>\n </div>\n </div>\n </WidgetSettingsModal>\n </>\n );\n}\n"]}
@@ -1,8 +0,0 @@
1
- export { Files as default, openFilesInTrashMode } from './chunk-2SRU4BYH.js';
2
- import './chunk-IY7JJVHR.js';
3
- import './chunk-KUIPWCTJ.js';
4
- import './chunk-WIJ45SYD.js';
5
- import './chunk-T2NQXP2J.js';
6
- import './chunk-PLGHQ7QW.js';
7
- //# sourceMappingURL=Files-KEHRZ2UY.js.map
8
- //# sourceMappingURL=Files-KEHRZ2UY.js.map
@@ -1,196 +0,0 @@
1
- import { loadAppearance, WidgetSettingsModal } from './chunk-TVOBLSSV.js';
2
- import { useWidgetSettings } from './chunk-T2NQXP2J.js';
3
- import './chunk-PLGHQ7QW.js';
4
- import { useState, useRef, useCallback, useEffect } from 'react';
5
- import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
6
-
7
- var POMO_SETTINGS_KEY = "pomodoro_appearance";
8
- var DURATIONS = { focus: 25 * 60, short: 5 * 60, long: 15 * 60 };
9
- var LABELS = { focus: "Focus", short: "Short", long: "Long" };
10
- var COLORS = {
11
- focus: { ring: "stroke-blue-500", text: "text-blue-600" },
12
- short: { ring: "stroke-emerald-500", text: "text-emerald-600" },
13
- long: { ring: "stroke-emerald-600", text: "text-emerald-700" }
14
- };
15
- function getTodayKey() {
16
- return `pomodoro-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
17
- }
18
- function loadCount() {
19
- return parseInt(localStorage.getItem(getTodayKey()) || "0", 10);
20
- }
21
- function saveCount(n) {
22
- localStorage.setItem(getTodayKey(), String(n));
23
- }
24
- function beep() {
25
- try {
26
- const ctx = new AudioContext();
27
- const osc = ctx.createOscillator();
28
- const gain = ctx.createGain();
29
- osc.connect(gain);
30
- gain.connect(ctx.destination);
31
- osc.frequency.value = 830;
32
- osc.type = "sine";
33
- gain.gain.setValueAtTime(0.3, ctx.currentTime);
34
- gain.gain.exponentialRampToValueAtTime(1e-3, ctx.currentTime + 0.8);
35
- osc.start();
36
- osc.stop(ctx.currentTime + 0.8);
37
- setTimeout(() => ctx.close(), 1e3);
38
- } catch {
39
- }
40
- }
41
- function PomodoroTimer() {
42
- const [mode, setMode] = useState("focus");
43
- const [remaining, setRemaining] = useState(DURATIONS.focus);
44
- const [running, setRunning] = useState(false);
45
- const [count, setCount] = useState(loadCount);
46
- const [streak, setStreak] = useState(0);
47
- const intervalRef = useRef();
48
- const [appearance, setAppearance] = useState(() => loadAppearance(POMO_SETTINGS_KEY));
49
- const [settingsOpen, setSettingsOpen] = useState(false);
50
- const [configAppearance, setConfigAppearance] = useState(appearance);
51
- useWidgetSettings(useCallback(() => {
52
- setConfigAppearance({ ...appearance });
53
- setSettingsOpen(true);
54
- }, [appearance]));
55
- const total = DURATIONS[mode];
56
- const progress = 1 - remaining / total;
57
- const mm = String(Math.floor(remaining / 60)).padStart(2, "0");
58
- const ss = String(remaining % 60).padStart(2, "0");
59
- const c = COLORS[mode];
60
- const R = 54, C = 2 * Math.PI * R;
61
- const notify = useCallback((title) => {
62
- beep();
63
- if (Notification.permission === "granted") new Notification(title);
64
- else if (Notification.permission !== "denied") Notification.requestPermission();
65
- }, []);
66
- const switchMode = useCallback((next) => {
67
- setMode(next);
68
- setRemaining(DURATIONS[next]);
69
- setRunning(false);
70
- }, []);
71
- useEffect(() => {
72
- if (!running) {
73
- clearInterval(intervalRef.current);
74
- return;
75
- }
76
- intervalRef.current = setInterval(() => setRemaining((r) => {
77
- if (r <= 1) {
78
- clearInterval(intervalRef.current);
79
- return 0;
80
- }
81
- return r - 1;
82
- }), 1e3);
83
- return () => clearInterval(intervalRef.current);
84
- }, [running]);
85
- useEffect(() => {
86
- if (remaining > 0 || running === false) return;
87
- setRunning(false);
88
- if (mode === "focus") {
89
- const next = streak + 1;
90
- const newCount = count + 1;
91
- setStreak(next);
92
- setCount(newCount);
93
- saveCount(newCount);
94
- notify(next % 4 === 0 ? "Time for a long break!" : "Time for a short break!");
95
- switchMode(next % 4 === 0 ? "long" : "short");
96
- } else {
97
- notify("Back to work!");
98
- switchMode("focus");
99
- }
100
- }, [remaining, running, mode, streak, count, notify, switchMode]);
101
- const reset = () => {
102
- setRunning(false);
103
- setRemaining(DURATIONS[mode]);
104
- };
105
- return /* @__PURE__ */ jsxs(Fragment, { children: [
106
- /* @__PURE__ */ jsxs(
107
- "div",
108
- {
109
- className: "flex flex-col items-center justify-between h-full p-3 select-none",
110
- style: { opacity: appearance.activeOpacity / 100, backdropFilter: appearance.activeBlur > 0 ? `blur(${appearance.activeBlur}px)` : void 0 },
111
- children: [
112
- /* @__PURE__ */ jsx("div", { className: "flex gap-0.5 rounded-lg bg-gray-100 p-0.5 text-xs font-medium w-full", children: ["focus", "short", "long"].map((m) => /* @__PURE__ */ jsx(
113
- "button",
114
- {
115
- onClick: () => switchMode(m),
116
- className: `flex-1 px-2 py-1 rounded-md transition ${mode === m ? "bg-blue-600 text-white" : "text-gray-500 hover:bg-gray-200"}`,
117
- children: LABELS[m]
118
- },
119
- m
120
- )) }),
121
- /* @__PURE__ */ jsxs("div", { className: "relative", style: { width: 210, height: 210 }, children: [
122
- /* @__PURE__ */ jsxs("svg", { className: "w-full h-full -rotate-90", viewBox: "0 0 120 120", children: [
123
- /* @__PURE__ */ jsx("circle", { cx: "60", cy: "60", r: R, fill: "none", strokeWidth: "6", className: "stroke-gray-200" }),
124
- /* @__PURE__ */ jsx(
125
- "circle",
126
- {
127
- cx: "60",
128
- cy: "60",
129
- r: R,
130
- fill: "none",
131
- strokeWidth: "6",
132
- className: `${c.ring} transition-all duration-500`,
133
- strokeLinecap: "round",
134
- strokeDasharray: C,
135
- strokeDashoffset: C * (1 - progress)
136
- }
137
- )
138
- ] }),
139
- /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: [
140
- /* @__PURE__ */ jsxs("span", { className: `text-3xl font-mono font-bold ${c.text}`, children: [
141
- mm,
142
- ":",
143
- ss
144
- ] }),
145
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-gray-400 mt-0.5", children: LABELS[mode] })
146
- ] })
147
- ] }),
148
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2 w-full", children: [
149
- /* @__PURE__ */ jsx(
150
- "button",
151
- {
152
- onClick: () => setRunning((r) => !r),
153
- className: "flex-1 py-1.5 rounded-lg text-white font-medium text-xs bg-blue-600 hover:bg-blue-700 transition",
154
- children: running ? "Pause" : "Start"
155
- }
156
- ),
157
- /* @__PURE__ */ jsx(
158
- "button",
159
- {
160
- onClick: reset,
161
- className: "flex-1 py-1.5 rounded-lg text-xs font-medium bg-gray-200 text-gray-700 hover:bg-gray-300 transition",
162
- children: "Reset"
163
- }
164
- )
165
- ] }),
166
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs text-gray-400", children: [
167
- count > 0 ? Array.from({ length: Math.min(count, 8) }, (_, i) => /* @__PURE__ */ jsx("span", { children: "\u{1F345}" }, i)) : /* @__PURE__ */ jsx("span", { children: "No sessions yet" }),
168
- count > 8 && /* @__PURE__ */ jsxs("span", { children: [
169
- "+",
170
- count - 8
171
- ] })
172
- ] })
173
- ]
174
- }
175
- ),
176
- /* @__PURE__ */ jsx(
177
- WidgetSettingsModal,
178
- {
179
- open: settingsOpen,
180
- onClose: () => setSettingsOpen(false),
181
- title: "Pomodoro Settings",
182
- appearance: configAppearance,
183
- onAppearanceChange: setConfigAppearance,
184
- onSave: () => {
185
- setAppearance(configAppearance);
186
- localStorage.setItem(POMO_SETTINGS_KEY, JSON.stringify(configAppearance));
187
- setSettingsOpen(false);
188
- }
189
- }
190
- )
191
- ] });
192
- }
193
-
194
- export { PomodoroTimer as default };
195
- //# sourceMappingURL=PomodoroTimer-T2J5NDJR.js.map
196
- //# sourceMappingURL=PomodoroTimer-T2J5NDJR.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/apps/PomodoroTimer.tsx"],"names":[],"mappings":"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","file":"PomodoroTimer-T2J5NDJR.js","sourcesContent":["import { useState, useEffect, useCallback, useRef } from 'react';\nimport { useWidgetSettings } from '../shell/Modal';\nimport WidgetSettingsModal, { loadAppearance, type WidgetAppearance } from '../shell/WidgetSettingsModal';\n\ntype Mode = 'focus' | 'short' | 'long';\nconst POMO_SETTINGS_KEY = 'pomodoro_appearance';\nconst DURATIONS: Record<Mode, number> = { focus: 25 * 60, short: 5 * 60, long: 15 * 60 };\nconst LABELS: Record<Mode, string> = { focus: 'Focus', short: 'Short', long: 'Long' };\nconst COLORS: Record<Mode, { ring: string; text: string }> = {\n focus: { ring: 'stroke-blue-500', text: 'text-blue-600' },\n short: { ring: 'stroke-emerald-500', text: 'text-emerald-600' },\n long: { ring: 'stroke-emerald-600', text: 'text-emerald-700' },\n};\n\nfunction getTodayKey() { return `pomodoro-${new Date().toISOString().slice(0, 10)}`; }\nfunction loadCount() { return parseInt(localStorage.getItem(getTodayKey()) || '0', 10); }\nfunction saveCount(n: number) { localStorage.setItem(getTodayKey(), String(n)); }\n\nfunction beep() {\n try {\n const ctx = new AudioContext();\n const osc = ctx.createOscillator();\n const gain = ctx.createGain();\n osc.connect(gain); gain.connect(ctx.destination);\n osc.frequency.value = 830; osc.type = 'sine';\n gain.gain.setValueAtTime(0.3, ctx.currentTime);\n gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.8);\n osc.start(); osc.stop(ctx.currentTime + 0.8);\n setTimeout(() => ctx.close(), 1000);\n } catch { /* silent fallback */ }\n}\n\nexport default function PomodoroTimer() {\n const [mode, setMode] = useState<Mode>('focus');\n const [remaining, setRemaining] = useState(DURATIONS.focus);\n const [running, setRunning] = useState(false);\n const [count, setCount] = useState(loadCount);\n const [streak, setStreak] = useState(0);\n const intervalRef = useRef<ReturnType<typeof setInterval>>();\n const [appearance, setAppearance] = useState(() => loadAppearance(POMO_SETTINGS_KEY));\n const [settingsOpen, setSettingsOpen] = useState(false);\n const [configAppearance, setConfigAppearance] = useState<WidgetAppearance>(appearance);\n\n useWidgetSettings(useCallback(() => {\n setConfigAppearance({ ...appearance });\n setSettingsOpen(true);\n }, [appearance]));\n\n const total = DURATIONS[mode];\n const progress = 1 - remaining / total;\n const mm = String(Math.floor(remaining / 60)).padStart(2, '0');\n const ss = String(remaining % 60).padStart(2, '0');\n const c = COLORS[mode];\n const R = 54, C = 2 * Math.PI * R;\n\n const notify = useCallback((title: string) => {\n beep();\n if (Notification.permission === 'granted') new Notification(title);\n else if (Notification.permission !== 'denied') Notification.requestPermission();\n }, []);\n\n const switchMode = useCallback((next: Mode) => {\n setMode(next); setRemaining(DURATIONS[next]); setRunning(false);\n }, []);\n\n useEffect(() => {\n if (!running) { clearInterval(intervalRef.current); return; }\n intervalRef.current = setInterval(() => setRemaining(r => {\n if (r <= 1) { clearInterval(intervalRef.current); return 0; }\n return r - 1;\n }), 1000);\n return () => clearInterval(intervalRef.current);\n }, [running]);\n\n useEffect(() => {\n if (remaining > 0 || running === false) return;\n setRunning(false);\n if (mode === 'focus') {\n const next = streak + 1;\n const newCount = count + 1;\n setStreak(next); setCount(newCount); saveCount(newCount);\n notify(next % 4 === 0 ? 'Time for a long break!' : 'Time for a short break!');\n switchMode(next % 4 === 0 ? 'long' : 'short');\n } else {\n notify('Back to work!');\n switchMode('focus');\n }\n }, [remaining, running, mode, streak, count, notify, switchMode]);\n\n const reset = () => { setRunning(false); setRemaining(DURATIONS[mode]); };\n\n return (\n <>\n <div className=\"flex flex-col items-center justify-between h-full p-3 select-none\"\n style={{ opacity: appearance.activeOpacity / 100, backdropFilter: appearance.activeBlur > 0 ? `blur(${appearance.activeBlur}px)` : undefined }}>\n {/* Mode tabs */}\n <div className=\"flex gap-0.5 rounded-lg bg-gray-100 p-0.5 text-xs font-medium w-full\">\n {(['focus', 'short', 'long'] as Mode[]).map(m => (\n <button key={m} onClick={() => switchMode(m)}\n className={`flex-1 px-2 py-1 rounded-md transition ${mode === m ? 'bg-blue-600 text-white' : 'text-gray-500 hover:bg-gray-200'}`}>\n {LABELS[m]}\n </button>\n ))}\n </div>\n\n {/* Circular timer */}\n <div className=\"relative\" style={{ width: 210, height: 210 }}>\n <svg className=\"w-full h-full -rotate-90\" viewBox=\"0 0 120 120\">\n <circle cx=\"60\" cy=\"60\" r={R} fill=\"none\" strokeWidth=\"6\" className=\"stroke-gray-200\" />\n <circle cx=\"60\" cy=\"60\" r={R} fill=\"none\" strokeWidth=\"6\"\n className={`${c.ring} transition-all duration-500`}\n strokeLinecap=\"round\" strokeDasharray={C} strokeDashoffset={C * (1 - progress)} />\n </svg>\n <div className=\"absolute inset-0 flex flex-col items-center justify-center\">\n <span className={`text-3xl font-mono font-bold ${c.text}`}>{mm}:{ss}</span>\n <span className=\"text-[10px] text-gray-400 mt-0.5\">{LABELS[mode]}</span>\n </div>\n </div>\n\n {/* Controls */}\n <div className=\"flex gap-2 w-full\">\n <button onClick={() => setRunning(r => !r)}\n className=\"flex-1 py-1.5 rounded-lg text-white font-medium text-xs bg-blue-600 hover:bg-blue-700 transition\">\n {running ? 'Pause' : 'Start'}\n </button>\n <button onClick={reset}\n className=\"flex-1 py-1.5 rounded-lg text-xs font-medium bg-gray-200 text-gray-700 hover:bg-gray-300 transition\">\n Reset\n </button>\n </div>\n\n {/* Session dots */}\n <div className=\"flex items-center gap-1 text-xs text-gray-400\">\n {count > 0 ? Array.from({ length: Math.min(count, 8) }, (_, i) => (\n <span key={i}>&#x1F345;</span>\n )) : <span>No sessions yet</span>}\n {count > 8 && <span>+{count - 8}</span>}\n </div>\n </div>\n <WidgetSettingsModal open={settingsOpen} onClose={() => setSettingsOpen(false)} title=\"Pomodoro Settings\"\n appearance={configAppearance} onAppearanceChange={setConfigAppearance}\n onSave={() => { setAppearance(configAppearance); localStorage.setItem(POMO_SETTINGS_KEY, JSON.stringify(configAppearance)); setSettingsOpen(false); }} />\n </>\n );\n}\n"]}
@@ -1,7 +0,0 @@
1
- export { Preview as default, setPdfPreview } from './chunk-IY7JJVHR.js';
2
- import './chunk-KUIPWCTJ.js';
3
- import './chunk-WIJ45SYD.js';
4
- import './chunk-T2NQXP2J.js';
5
- import './chunk-PLGHQ7QW.js';
6
- //# sourceMappingURL=Preview-4354N46U.js.map
7
- //# sourceMappingURL=Preview-4354N46U.js.map
@@ -1,266 +0,0 @@
1
- import { useShellPrefs } from './chunk-36VM54SC.js';
2
- import { loadAppearance, WidgetSettingsModal } from './chunk-TVOBLSSV.js';
3
- import { useWidgetSettings } from './chunk-T2NQXP2J.js';
4
- import './chunk-PLGHQ7QW.js';
5
- import { useState, useEffect, useCallback } from 'react';
6
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
-
8
- var WMO = {
9
- 0: ["Clear Sky", "\u2600\uFE0F", "\u{1F319}", "from-sky-400 to-blue-500", "from-indigo-800 to-slate-900"],
10
- 1: ["Mainly Clear", "\u{1F324}\uFE0F", "\u{1F319}", "from-sky-400 to-blue-500", "from-indigo-800 to-slate-900"],
11
- 2: ["Partly Cloudy", "\u26C5", "\u2601\uFE0F", "from-sky-400 to-blue-400", "from-indigo-700 to-slate-800"],
12
- 3: ["Overcast", "\u2601\uFE0F", "\u2601\uFE0F", "from-gray-400 to-gray-500", "from-gray-700 to-slate-800"],
13
- 45: ["Foggy", "\u{1F32B}\uFE0F", "\u{1F32B}\uFE0F", "from-gray-400 to-gray-500", "from-gray-700 to-slate-800"],
14
- 48: ["Foggy", "\u{1F32B}\uFE0F", "\u{1F32B}\uFE0F", "from-gray-400 to-gray-500", "from-gray-700 to-slate-800"],
15
- 51: ["Light Drizzle", "\u{1F326}\uFE0F", "\u{1F327}\uFE0F", "from-gray-400 to-blue-500", "from-gray-700 to-indigo-800"],
16
- 53: ["Drizzle", "\u{1F327}\uFE0F", "\u{1F327}\uFE0F", "from-gray-500 to-blue-600", "from-gray-700 to-indigo-800"],
17
- 55: ["Heavy Drizzle", "\u{1F327}\uFE0F", "\u{1F327}\uFE0F", "from-gray-500 to-blue-600", "from-gray-700 to-indigo-800"],
18
- 61: ["Light Rain", "\u{1F326}\uFE0F", "\u{1F327}\uFE0F", "from-gray-400 to-blue-500", "from-gray-700 to-indigo-800"],
19
- 63: ["Rain", "\u{1F327}\uFE0F", "\u{1F327}\uFE0F", "from-gray-500 to-blue-600", "from-gray-700 to-indigo-800"],
20
- 65: ["Heavy Rain", "\u{1F327}\uFE0F", "\u{1F327}\uFE0F", "from-gray-600 to-blue-700", "from-gray-700 to-indigo-900"],
21
- 71: ["Light Snow", "\u{1F328}\uFE0F", "\u{1F328}\uFE0F", "from-blue-200 to-blue-400", "from-blue-800 to-slate-900"],
22
- 73: ["Snow", "\u2744\uFE0F", "\u2744\uFE0F", "from-blue-300 to-blue-500", "from-blue-800 to-slate-900"],
23
- 75: ["Heavy Snow", "\u2744\uFE0F", "\u2744\uFE0F", "from-blue-400 to-blue-600", "from-blue-800 to-slate-900"],
24
- 80: ["Rain Showers", "\u{1F327}\uFE0F", "\u{1F327}\uFE0F", "from-gray-500 to-blue-600", "from-gray-700 to-indigo-800"],
25
- 82: ["Heavy Showers", "\u{1F327}\uFE0F", "\u{1F327}\uFE0F", "from-gray-600 to-blue-700", "from-gray-700 to-indigo-900"],
26
- 95: ["Thunderstorm", "\u26C8\uFE0F", "\u26C8\uFE0F", "from-gray-700 to-indigo-800", "from-gray-800 to-indigo-950"],
27
- 96: ["Thunderstorm", "\u26C8\uFE0F", "\u26C8\uFE0F", "from-gray-700 to-indigo-800", "from-gray-800 to-indigo-950"],
28
- 99: ["Thunderstorm", "\u26C8\uFE0F", "\u26C8\uFE0F", "from-gray-700 to-indigo-900", "from-gray-800 to-indigo-950"]
29
- };
30
- var getCondition = (code, isDay = true) => {
31
- const entry = WMO[code] || ["Unknown", "\u2753", "\u2753", "from-gray-400 to-gray-500", "from-gray-700 to-slate-800"];
32
- return [entry[0], isDay ? entry[1] : entry[2], isDay ? entry[3] : entry[4]];
33
- };
34
- var AVAILABLE_CITIES = {
35
- "Sydney": { lat: -33.8688, lon: 151.2093 },
36
- "London": { lat: 51.5074, lon: -0.1278 },
37
- "Los Angeles": { lat: 34.0522, lon: -118.2437 },
38
- "Shanghai": { lat: 31.2304, lon: 121.4737 },
39
- "New York": { lat: 40.7128, lon: -74.006 },
40
- "Tokyo": { lat: 35.6762, lon: 139.6503 },
41
- "Dubai": { lat: 25.2048, lon: 55.2708 },
42
- "Singapore": { lat: 1.3521, lon: 103.8198 },
43
- "Hong Kong": { lat: 22.3193, lon: 114.1694 },
44
- "Paris": { lat: 48.8566, lon: 2.3522 },
45
- "Berlin": { lat: 52.52, lon: 13.405 },
46
- "Mumbai": { lat: 19.076, lon: 72.8777 },
47
- "Bangkok": { lat: 13.7563, lon: 100.5018 },
48
- "Melbourne": { lat: -37.8136, lon: 144.9631 },
49
- "Toronto": { lat: 43.6532, lon: -79.3832 },
50
- "Miami": { lat: 25.7617, lon: -80.1918 },
51
- "Chicago": { lat: 41.8781, lon: -87.6298 },
52
- "Auckland": { lat: -36.8485, lon: 174.7633 }
53
- };
54
- var DEFAULT_CITIES = ["Sydney", "London", "Los Angeles", "Shanghai"];
55
- var STORAGE_KEY = "weather_cities";
56
- var SETTINGS_KEY = "weather_appearance";
57
- var CACHE_KEY = "weather_multi_cache";
58
- var CACHE_TTL = 30 * 60 * 1e3;
59
- var DEFAULT_PREFS = { useFahrenheit: false, showLocalTime: false, use24Hour: false };
60
- function loadCities() {
61
- try {
62
- const s = JSON.parse(localStorage.getItem(STORAGE_KEY) || "");
63
- if (Array.isArray(s) && s.length) return s;
64
- } catch {
65
- }
66
- return DEFAULT_CITIES;
67
- }
68
- var toF = (c) => Math.round(c * 9 / 5 + 32);
69
- function getTimeInTz(timezone, use24Hour = false) {
70
- try {
71
- const now = /* @__PURE__ */ new Date();
72
- const h24Parts = new Intl.DateTimeFormat("en-US", { timeZone: timezone, hour: "numeric", minute: "2-digit", hour12: false }).formatToParts(now);
73
- const h24 = parseInt(h24Parts.find((p) => p.type === "hour")?.value || "0");
74
- const m = parseInt(h24Parts.find((p) => p.type === "minute")?.value || "0");
75
- if (use24Hour) {
76
- return { hours: h24, minutes: m, text: `${String(h24).padStart(2, "0")}:${String(m).padStart(2, "0")}` };
77
- }
78
- const parts = new Intl.DateTimeFormat("en-US", { timeZone: timezone, hour: "numeric", minute: "2-digit", hour12: true }).formatToParts(now);
79
- const h12 = parseInt(parts.find((p) => p.type === "hour")?.value || "12");
80
- const period = parts.find((p) => p.type === "dayPeriod")?.value || "";
81
- return { hours: h24, minutes: m, text: `${h12}:${String(m).padStart(2, "0")} ${period}` };
82
- } catch {
83
- return { hours: 0, minutes: 0, text: "" };
84
- }
85
- }
86
- function Weather() {
87
- const [cities, setCities] = useState(loadCities);
88
- const [appearance, setAppearance] = useState(() => loadAppearance(SETTINGS_KEY));
89
- const [data, setData] = useState([]);
90
- const [loading, setLoading] = useState(true);
91
- const [, setTick] = useState(0);
92
- useEffect(() => {
93
- const t2 = setInterval(() => setTick((n) => n + 1), 6e4);
94
- return () => clearInterval(t2);
95
- }, []);
96
- const [settingsOpen, setSettingsOpen] = useState(false);
97
- const [configCities, setConfigCities] = useState([]);
98
- const [configAppearance, setConfigAppearance] = useState(appearance);
99
- const { prefs: shellPrefs, save: saveShellPrefs } = useShellPrefs();
100
- const prefs = { ...DEFAULT_PREFS, ...shellPrefs.weather_prefs ?? {} };
101
- const [configPrefs, setConfigPrefs] = useState(prefs);
102
- useWidgetSettings(useCallback(() => {
103
- setConfigCities([...cities]);
104
- setConfigAppearance({ ...appearance });
105
- setConfigPrefs({ ...prefs });
106
- setSettingsOpen(true);
107
- }, [cities, appearance, prefs]));
108
- const fetchAll = useCallback(async (cityList, force = false) => {
109
- if (!force) {
110
- try {
111
- const cached = JSON.parse(localStorage.getItem(CACHE_KEY) || "{}");
112
- const key = cityList.join(",");
113
- if (cached[key] && Date.now() - cached[key].ts < CACHE_TTL) {
114
- setData(cached[key].data);
115
- setLoading(false);
116
- return;
117
- }
118
- } catch {
119
- }
120
- }
121
- setLoading(true);
122
- const results = [];
123
- for (const city of cityList) {
124
- const coords = AVAILABLE_CITIES[city];
125
- if (!coords) continue;
126
- try {
127
- const res = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${coords.lat}&longitude=${coords.lon}&current=temperature_2m,weather_code,is_day&daily=temperature_2m_max,temperature_2m_min&forecast_days=1&timezone=auto`);
128
- const w = await res.json();
129
- results.push({ city, temp: Math.round(w.current.temperature_2m), code: w.current.weather_code, high: Math.round(w.daily.temperature_2m_max[0]), low: Math.round(w.daily.temperature_2m_min[0]), isDay: w.current.is_day === 1, timezone: w.timezone || "UTC" });
130
- } catch {
131
- }
132
- }
133
- setData(results);
134
- setLoading(false);
135
- try {
136
- const c = JSON.parse(localStorage.getItem(CACHE_KEY) || "{}");
137
- c[cityList.join(",")] = { data: results, ts: Date.now() };
138
- localStorage.setItem(CACHE_KEY, JSON.stringify(c));
139
- } catch {
140
- }
141
- }, []);
142
- useEffect(() => {
143
- fetchAll(cities);
144
- }, [cities, fetchAll]);
145
- const saveSettings = () => {
146
- if (configCities.length === 0) return;
147
- setCities(configCities);
148
- setAppearance(configAppearance);
149
- saveShellPrefs({ weather_prefs: configPrefs });
150
- localStorage.setItem(STORAGE_KEY, JSON.stringify(configCities));
151
- localStorage.setItem(SETTINGS_KEY, JSON.stringify(configAppearance));
152
- setSettingsOpen(false);
153
- };
154
- const t = (c) => prefs.useFahrenheit ? `${toF(c)}\xB0F` : `${c}\xB0`;
155
- if (loading && data.length === 0) {
156
- return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full bg-gradient-to-b from-sky-400 to-blue-500 rounded-lg text-white/70 text-sm", children: "Loading..." });
157
- }
158
- const dynamicHeight = data.length * 96 + 16;
159
- return /* @__PURE__ */ jsxs(Fragment, { children: [
160
- /* @__PURE__ */ jsx(
161
- "div",
162
- {
163
- className: "flex flex-col rounded-lg text-white overflow-hidden",
164
- style: {
165
- minHeight: dynamicHeight,
166
- backgroundColor: `rgba(15, 23, 42, ${appearance.activeOpacity / 100})`,
167
- // slate-900 with alpha
168
- backdropFilter: appearance.activeBlur > 0 ? `blur(${appearance.activeBlur}px)` : void 0
169
- },
170
- children: /* @__PURE__ */ jsx("div", { className: "flex-1 flex flex-col gap-2 p-2", children: data.map((d) => {
171
- const [condition] = getCondition(d.code, d.isDay);
172
- const rowBg = d.isDay ? "bg-gradient-to-br from-sky-400 via-sky-300 to-sky-500" : "bg-gradient-to-br from-slate-800 via-blue-950 to-slate-900";
173
- return /* @__PURE__ */ jsxs("div", { className: `rounded-2xl px-4 py-3 flex flex-col justify-between gap-3 ${rowBg}`, children: [
174
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
175
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
176
- /* @__PURE__ */ jsx("div", { className: "text-lg font-semibold leading-tight truncate", children: d.city }),
177
- prefs.showLocalTime && /* @__PURE__ */ jsx("div", { className: "text-xs opacity-90 mt-0.5 tabular-nums", children: getTimeInTz(d.timezone, prefs.use24Hour).text })
178
- ] }),
179
- /* @__PURE__ */ jsx("div", { className: "text-4xl font-extralight leading-none tracking-tight tabular-nums shrink-0", children: t(d.temp) })
180
- ] }),
181
- /* @__PURE__ */ jsxs("div", { className: "flex items-end justify-between text-[11px]", children: [
182
- /* @__PURE__ */ jsx("span", { className: "opacity-95", children: condition }),
183
- /* @__PURE__ */ jsxs("span", { className: "opacity-90 tabular-nums", children: [
184
- "H:",
185
- t(d.high),
186
- " L:",
187
- t(d.low)
188
- ] })
189
- ] })
190
- ] }, d.city);
191
- }) })
192
- }
193
- ),
194
- /* @__PURE__ */ jsxs(
195
- WidgetSettingsModal,
196
- {
197
- open: settingsOpen,
198
- onClose: () => setSettingsOpen(false),
199
- title: "Weather Settings",
200
- appearance: configAppearance,
201
- onAppearanceChange: setConfigAppearance,
202
- onSave: saveSettings,
203
- children: [
204
- /* @__PURE__ */ jsx("div", { className: "space-y-3", children: /* @__PURE__ */ jsxs("div", { children: [
205
- /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-700 mb-2", children: "Display" }),
206
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-2", children: [
207
- /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-600 w-24", children: "Temperature" }),
208
- /* @__PURE__ */ jsx("div", { className: "flex gap-1", children: [{ key: false, label: "\xB0C" }, { key: true, label: "\xB0F" }].map((o) => /* @__PURE__ */ jsx(
209
- "button",
210
- {
211
- onClick: () => setConfigPrefs((p) => ({ ...p, useFahrenheit: o.key })),
212
- className: `px-3 py-1 text-xs font-medium rounded-lg border transition-colors ${configPrefs.useFahrenheit === o.key ? "bg-blue-600 text-white border-blue-600" : "bg-white text-gray-700 border-gray-300 hover:bg-gray-50"}`,
213
- children: o.label
214
- },
215
- String(o.key)
216
- )) })
217
- ] }),
218
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-2", children: [
219
- /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-600 w-24", children: "Time Format" }),
220
- /* @__PURE__ */ jsx("div", { className: "flex gap-1", children: [{ key: false, label: "AM/PM" }, { key: true, label: "24H" }].map((o) => /* @__PURE__ */ jsx(
221
- "button",
222
- {
223
- onClick: () => setConfigPrefs((p) => ({ ...p, use24Hour: o.key })),
224
- className: `px-3 py-1 text-xs font-medium rounded-lg border transition-colors ${configPrefs.use24Hour === o.key ? "bg-blue-600 text-white border-blue-600" : "bg-white text-gray-700 border-gray-300 hover:bg-gray-50"}`,
225
- children: o.label
226
- },
227
- String(o.key)
228
- )) })
229
- ] }),
230
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 cursor-pointer", children: [
231
- /* @__PURE__ */ jsx(
232
- "input",
233
- {
234
- type: "checkbox",
235
- checked: configPrefs.showLocalTime,
236
- onChange: (e) => setConfigPrefs((p) => ({ ...p, showLocalTime: e.target.checked })),
237
- className: "rounded border-gray-300 text-blue-600 h-3.5 w-3.5"
238
- }
239
- ),
240
- /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-600", children: "Show local time" })
241
- ] })
242
- ] }) }),
243
- /* @__PURE__ */ jsxs("div", { children: [
244
- /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-700 mb-2", children: "Cities" }),
245
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-1 max-h-48 overflow-y-auto", children: Object.keys(AVAILABLE_CITIES).map((city) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm py-1 cursor-pointer hover:bg-gray-50 rounded px-2", children: [
246
- /* @__PURE__ */ jsx(
247
- "input",
248
- {
249
- type: "checkbox",
250
- checked: configCities.includes(city),
251
- onChange: () => setConfigCities((prev) => prev.includes(city) ? prev.filter((c) => c !== city) : [...prev, city]),
252
- className: "rounded border-gray-300 text-blue-600 focus:ring-blue-500 h-3.5 w-3.5"
253
- }
254
- ),
255
- city
256
- ] }, city)) })
257
- ] })
258
- ]
259
- }
260
- )
261
- ] });
262
- }
263
-
264
- export { Weather as default };
265
- //# sourceMappingURL=Weather-XTADR7Z3.js.map
266
- //# sourceMappingURL=Weather-XTADR7Z3.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/apps/Weather.tsx"],"names":["t"],"mappings":";;;;;;;AAMA,IAAM,GAAA,GAAgE;AAAA,EACpE,GAAG,CAAC,WAAA,EAAa,cAAA,EAAM,WAAA,EAAM,4BAA4B,8BAA8B,CAAA;AAAA,EACvF,GAAG,CAAC,cAAA,EAAgB,iBAAA,EAAO,WAAA,EAAM,4BAA4B,8BAA8B,CAAA;AAAA,EAC3F,GAAG,CAAC,eAAA,EAAiB,QAAA,EAAK,cAAA,EAAM,4BAA4B,8BAA8B,CAAA;AAAA,EAC1F,GAAG,CAAC,UAAA,EAAY,cAAA,EAAM,cAAA,EAAM,6BAA6B,4BAA4B,CAAA;AAAA,EACrF,IAAI,CAAC,OAAA,EAAS,iBAAA,EAAO,iBAAA,EAAO,6BAA6B,4BAA4B,CAAA;AAAA,EACrF,IAAI,CAAC,OAAA,EAAS,iBAAA,EAAO,iBAAA,EAAO,6BAA6B,4BAA4B,CAAA;AAAA,EACrF,IAAI,CAAC,eAAA,EAAiB,iBAAA,EAAO,iBAAA,EAAO,6BAA6B,6BAA6B,CAAA;AAAA,EAC9F,IAAI,CAAC,SAAA,EAAW,iBAAA,EAAO,iBAAA,EAAO,6BAA6B,6BAA6B,CAAA;AAAA,EACxF,IAAI,CAAC,eAAA,EAAiB,iBAAA,EAAO,iBAAA,EAAO,6BAA6B,6BAA6B,CAAA;AAAA,EAC9F,IAAI,CAAC,YAAA,EAAc,iBAAA,EAAO,iBAAA,EAAO,6BAA6B,6BAA6B,CAAA;AAAA,EAC3F,IAAI,CAAC,MAAA,EAAQ,iBAAA,EAAO,iBAAA,EAAO,6BAA6B,6BAA6B,CAAA;AAAA,EACrF,IAAI,CAAC,YAAA,EAAc,iBAAA,EAAO,iBAAA,EAAO,6BAA6B,6BAA6B,CAAA;AAAA,EAC3F,IAAI,CAAC,YAAA,EAAc,iBAAA,EAAO,iBAAA,EAAO,6BAA6B,4BAA4B,CAAA;AAAA,EAC1F,IAAI,CAAC,MAAA,EAAQ,cAAA,EAAM,cAAA,EAAM,6BAA6B,4BAA4B,CAAA;AAAA,EAClF,IAAI,CAAC,YAAA,EAAc,cAAA,EAAM,cAAA,EAAM,6BAA6B,4BAA4B,CAAA;AAAA,EACxF,IAAI,CAAC,cAAA,EAAgB,iBAAA,EAAO,iBAAA,EAAO,6BAA6B,6BAA6B,CAAA;AAAA,EAC7F,IAAI,CAAC,eAAA,EAAiB,iBAAA,EAAO,iBAAA,EAAO,6BAA6B,6BAA6B,CAAA;AAAA,EAC9F,IAAI,CAAC,cAAA,EAAgB,cAAA,EAAM,cAAA,EAAM,+BAA+B,6BAA6B,CAAA;AAAA,EAC7F,IAAI,CAAC,cAAA,EAAgB,cAAA,EAAM,cAAA,EAAM,+BAA+B,6BAA6B,CAAA;AAAA,EAC7F,IAAI,CAAC,cAAA,EAAgB,cAAA,EAAM,cAAA,EAAM,+BAA+B,6BAA6B;AAC/F,CAAA;AAEA,IAAM,YAAA,GAAe,CAAC,IAAA,EAAc,KAAA,GAAQ,IAAA,KAAS;AACnD,EAAA,MAAM,KAAA,GAAQ,IAAI,IAAI,CAAA,IAAK,CAAC,SAAA,EAAW,QAAA,EAAK,QAAA,EAAK,2BAAA,EAA6B,4BAA4B,CAAA;AAC1G,EAAA,OAAO,CAAC,KAAA,CAAM,CAAC,CAAA,EAAG,KAAA,GAAQ,MAAM,CAAC,CAAA,GAAI,KAAA,CAAM,CAAC,GAAG,KAAA,GAAQ,KAAA,CAAM,CAAC,CAAA,GAAI,KAAA,CAAM,CAAC,CAAC,CAAA;AAC5E,CAAA;AAEA,IAAM,gBAAA,GAAiE;AAAA,EACrE,QAAA,EAAU,EAAE,GAAA,EAAK,QAAA,EAAU,KAAK,QAAA,EAAS;AAAA,EACzC,QAAA,EAAU,EAAE,GAAA,EAAK,OAAA,EAAS,KAAK,OAAA,EAAQ;AAAA,EACvC,aAAA,EAAe,EAAE,GAAA,EAAK,OAAA,EAAS,KAAK,SAAA,EAAU;AAAA,EAC9C,UAAA,EAAY,EAAE,GAAA,EAAK,OAAA,EAAS,KAAK,QAAA,EAAS;AAAA,EAC1C,UAAA,EAAY,EAAE,GAAA,EAAK,OAAA,EAAS,KAAK,OAAA,EAAS;AAAA,EAC1C,OAAA,EAAS,EAAE,GAAA,EAAK,OAAA,EAAS,KAAK,QAAA,EAAS;AAAA,EACvC,OAAA,EAAS,EAAE,GAAA,EAAK,OAAA,EAAS,KAAK,OAAA,EAAQ;AAAA,EACtC,WAAA,EAAa,EAAE,GAAA,EAAK,MAAA,EAAQ,KAAK,QAAA,EAAS;AAAA,EAC1C,WAAA,EAAa,EAAE,GAAA,EAAK,OAAA,EAAS,KAAK,QAAA,EAAS;AAAA,EAC3C,OAAA,EAAS,EAAE,GAAA,EAAK,OAAA,EAAS,KAAK,MAAA,EAAO;AAAA,EACrC,QAAA,EAAU,EAAE,GAAA,EAAK,KAAA,EAAS,KAAK,MAAA,EAAQ;AAAA,EACvC,QAAA,EAAU,EAAE,GAAA,EAAK,MAAA,EAAS,KAAK,OAAA,EAAQ;AAAA,EACvC,SAAA,EAAW,EAAE,GAAA,EAAK,OAAA,EAAS,KAAK,QAAA,EAAS;AAAA,EACzC,WAAA,EAAa,EAAE,GAAA,EAAK,QAAA,EAAU,KAAK,QAAA,EAAS;AAAA,EAC5C,SAAA,EAAW,EAAE,GAAA,EAAK,OAAA,EAAS,KAAK,QAAA,EAAS;AAAA,EACzC,OAAA,EAAS,EAAE,GAAA,EAAK,OAAA,EAAS,KAAK,QAAA,EAAS;AAAA,EACvC,SAAA,EAAW,EAAE,GAAA,EAAK,OAAA,EAAS,KAAK,QAAA,EAAS;AAAA,EACzC,UAAA,EAAY,EAAE,GAAA,EAAK,QAAA,EAAU,KAAK,QAAA;AACpC,CAAA;AAEA,IAAM,cAAA,GAAiB,CAAC,QAAA,EAAU,QAAA,EAAU,eAAe,UAAU,CAAA;AACrE,IAAM,WAAA,GAAc,gBAAA;AACpB,IAAM,YAAA,GAAe,oBAAA;AACrB,IAAM,SAAA,GAAY,qBAAA;AAClB,IAAM,SAAA,GAAY,KAAK,EAAA,GAAK,GAAA;AAI5B,IAAM,gBAA8B,EAAE,aAAA,EAAe,OAAO,aAAA,EAAe,KAAA,EAAO,WAAW,KAAA,EAAM;AAEnG,SAAS,UAAA,GAAuB;AAC9B,EAAA,IAAI;AAAE,IAAA,MAAM,IAAI,IAAA,CAAK,KAAA,CAAM,aAAa,OAAA,CAAQ,WAAW,KAAK,EAAE,CAAA;AAAG,IAAA,IAAI,MAAM,OAAA,CAAQ,CAAC,CAAA,IAAK,CAAA,CAAE,QAAQ,OAAO,CAAA;AAAA,EAAG,CAAA,CAAA,MAAQ;AAAA,EAAC;AAC1H,EAAA,OAAO,cAAA;AACT;AAEA,IAAM,GAAA,GAAM,CAAC,CAAA,KAAc,IAAA,CAAK,MAAM,CAAA,GAAI,CAAA,GAAI,IAAI,EAAE,CAAA;AAEpD,SAAS,WAAA,CAAY,QAAA,EAAkB,SAAA,GAAY,KAAA,EAAyD;AAC1G,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,IAAA,MAAM,WAAW,IAAI,IAAA,CAAK,cAAA,CAAe,OAAA,EAAS,EAAE,QAAA,EAAU,QAAA,EAAU,IAAA,EAAM,SAAA,EAAW,QAAQ,SAAA,EAAW,MAAA,EAAQ,OAAO,CAAA,CAAE,cAAc,GAAG,CAAA;AAC9I,IAAA,MAAM,GAAA,GAAM,QAAA,CAAS,QAAA,CAAS,IAAA,CAAK,CAAA,CAAA,KAAK,EAAE,IAAA,KAAS,MAAM,CAAA,EAAG,KAAA,IAAS,GAAG,CAAA;AACxE,IAAA,MAAM,CAAA,GAAI,QAAA,CAAS,QAAA,CAAS,IAAA,CAAK,CAAA,CAAA,KAAK,EAAE,IAAA,KAAS,QAAQ,CAAA,EAAG,KAAA,IAAS,GAAG,CAAA;AACxE,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,OAAO,EAAE,OAAO,GAAA,EAAK,OAAA,EAAS,GAAG,IAAA,EAAM,CAAA,EAAG,MAAA,CAAO,GAAG,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAC,IAAI,MAAA,CAAO,CAAC,EAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA,EAAG;AAAA,IACzG;AACA,IAAA,MAAM,QAAQ,IAAI,IAAA,CAAK,cAAA,CAAe,OAAA,EAAS,EAAE,QAAA,EAAU,QAAA,EAAU,IAAA,EAAM,SAAA,EAAW,QAAQ,SAAA,EAAW,MAAA,EAAQ,MAAM,CAAA,CAAE,cAAc,GAAG,CAAA;AAC1I,IAAA,MAAM,GAAA,GAAM,QAAA,CAAS,KAAA,CAAM,IAAA,CAAK,CAAA,CAAA,KAAK,EAAE,IAAA,KAAS,MAAM,CAAA,EAAG,KAAA,IAAS,IAAI,CAAA;AACtE,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,CAAA,CAAA,KAAK,EAAE,IAAA,KAAS,WAAW,GAAG,KAAA,IAAS,EAAA;AACjE,IAAA,OAAO,EAAE,KAAA,EAAO,GAAA,EAAK,SAAS,CAAA,EAAG,IAAA,EAAM,GAAG,GAAG,CAAA,CAAA,EAAI,MAAA,CAAO,CAAC,EAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA,EAAG;AAAA,EAC1F,CAAA,CAAA,MAAQ;AAAE,IAAA,OAAO,EAAE,KAAA,EAAO,CAAA,EAAG,OAAA,EAAS,CAAA,EAAG,MAAM,EAAA,EAAG;AAAA,EAAG;AACvD;AA0Be,SAAR,OAAA,GAA2B;AAChC,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAS,UAAU,CAAA;AAC/C,EAAA,MAAM,CAAC,YAAY,aAAa,CAAA,GAAI,SAAS,MAAM,cAAA,CAAe,YAAY,CAAC,CAAA;AAC/E,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,QAAA,CAAwB,EAAE,CAAA;AAClD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,IAAI,CAAA;AAE3C,EAAA,MAAM,GAAG,OAAO,CAAA,GAAI,SAAS,CAAC,CAAA;AAC9B,EAAA,SAAA,CAAU,MAAM;AAAE,IAAA,MAAMA,EAAAA,GAAI,YAAY,MAAM,OAAA,CAAQ,OAAK,CAAA,GAAI,CAAC,GAAG,GAAK,CAAA;AAAG,IAAA,OAAO,MAAM,cAAcA,EAAC,CAAA;AAAA,EAAG,CAAA,EAAG,EAAE,CAAA;AAC/G,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,SAAS,KAAK,CAAA;AACtD,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,QAAA,CAAmB,EAAE,CAAA;AAC7D,EAAA,MAAM,CAAC,gBAAA,EAAkB,mBAAmB,CAAA,GAAI,SAA2B,UAAU,CAAA;AAGrF,EAAA,MAAM,EAAE,KAAA,EAAO,UAAA,EAAY,IAAA,EAAM,cAAA,KAAmB,aAAA,EAAc;AAClE,EAAA,MAAM,KAAA,GAAsB,EAAE,GAAG,aAAA,EAAe,GAAI,UAAA,CAAW,aAAA,IAA6C,EAAC,EAAG;AAChH,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAuB,KAAK,CAAA;AAElE,EAAA,iBAAA,CAAkB,YAAY,MAAM;AAClC,IAAA,eAAA,CAAgB,CAAC,GAAG,MAAM,CAAC,CAAA;AAC3B,IAAA,mBAAA,CAAoB,EAAE,GAAG,UAAA,EAAY,CAAA;AACrC,IAAA,cAAA,CAAe,EAAE,GAAG,KAAA,EAAO,CAAA;AAC3B,IAAA,eAAA,CAAgB,IAAI,CAAA;AAAA,EACtB,GAAG,CAAC,MAAA,EAAQ,UAAA,EAAY,KAAK,CAAC,CAAC,CAAA;AAE/B,EAAA,MAAM,QAAA,GAAW,WAAA,CAAY,OAAO,QAAA,EAAoB,QAAQ,KAAA,KAAU;AACxE,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,IAAI;AACF,QAAA,MAAM,SAAS,IAAA,CAAK,KAAA,CAAM,aAAa,OAAA,CAAQ,SAAS,KAAK,IAAI,CAAA;AACjE,QAAA,MAAM,GAAA,GAAM,QAAA,CAAS,IAAA,CAAK,GAAG,CAAA;AAC7B,QAAA,IAAI,MAAA,CAAO,GAAG,CAAA,IAAK,IAAA,CAAK,GAAA,KAAQ,MAAA,CAAO,GAAG,CAAA,CAAE,EAAA,GAAK,SAAA,EAAW;AAC1D,UAAA,OAAA,CAAQ,MAAA,CAAO,GAAG,CAAA,CAAE,IAAI,CAAA;AAAG,UAAA,UAAA,CAAW,KAAK,CAAA;AAAG,UAAA;AAAA,QAChD;AAAA,MACF,CAAA,CAAA,MAAQ;AAAA,MAAC;AAAA,IACX;AACA,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,MAAM,UAAyB,EAAC;AAChC,IAAA,KAAA,MAAW,QAAQ,QAAA,EAAU;AAC3B,MAAA,MAAM,MAAA,GAAS,iBAAiB,IAAI,CAAA;AACpC,MAAA,IAAI,CAAC,MAAA,EAAQ;AACb,MAAA,IAAI;AACF,QAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,CAAA,gDAAA,EAAmD,OAAO,GAAG,CAAA,WAAA,EAAc,MAAA,CAAO,GAAG,CAAA,qHAAA,CAAuH,CAAA;AACpO,QAAA,MAAM,CAAA,GAAI,MAAM,GAAA,CAAI,IAAA,EAAK;AACzB,QAAA,OAAA,CAAQ,KAAK,EAAE,IAAA,EAAM,MAAM,IAAA,CAAK,KAAA,CAAM,EAAE,OAAA,CAAQ,cAAc,CAAA,EAAG,IAAA,EAAM,EAAE,OAAA,CAAQ,YAAA,EAAc,MAAM,IAAA,CAAK,KAAA,CAAM,EAAE,KAAA,CAAM,kBAAA,CAAmB,CAAC,CAAC,GAAG,GAAA,EAAK,IAAA,CAAK,MAAM,CAAA,CAAE,KAAA,CAAM,mBAAmB,CAAC,CAAC,GAAG,KAAA,EAAO,CAAA,CAAE,QAAQ,MAAA,KAAW,CAAA,EAAG,UAAU,CAAA,CAAE,QAAA,IAAY,OAAO,CAAA;AAAA,MAChQ,CAAA,CAAA,MAAQ;AAAA,MAAC;AAAA,IACX;AACA,IAAA,OAAA,CAAQ,OAAO,CAAA;AAAG,IAAA,UAAA,CAAW,KAAK,CAAA;AAClC,IAAA,IAAI;AAAE,MAAA,MAAM,IAAI,IAAA,CAAK,KAAA,CAAM,aAAa,OAAA,CAAQ,SAAS,KAAK,IAAI,CAAA;AAAG,MAAA,CAAA,CAAE,QAAA,CAAS,IAAA,CAAK,GAAG,CAAC,CAAA,GAAI,EAAE,IAAA,EAAM,OAAA,EAAS,EAAA,EAAI,IAAA,CAAK,GAAA,EAAI,EAAE;AAAG,MAAA,YAAA,CAAa,OAAA,CAAQ,SAAA,EAAW,IAAA,CAAK,SAAA,CAAU,CAAC,CAAC,CAAA;AAAA,IAAG,CAAA,CAAA,MAAQ;AAAA,IAAC;AAAA,EAC/L,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM;AAAE,IAAA,QAAA,CAAS,MAAM,CAAA;AAAA,EAAG,CAAA,EAAG,CAAC,MAAA,EAAQ,QAAQ,CAAC,CAAA;AAEzD,EAAA,MAAM,eAAe,MAAM;AACzB,IAAA,IAAI,YAAA,CAAa,WAAW,CAAA,EAAG;AAC/B,IAAA,SAAA,CAAU,YAAY,CAAA;AACtB,IAAA,aAAA,CAAc,gBAAgB,CAAA;AAC9B,IAAA,cAAA,CAAe,EAAE,aAAA,EAAe,WAAA,EAAa,CAAA;AAC7C,IAAA,YAAA,CAAa,OAAA,CAAQ,WAAA,EAAa,IAAA,CAAK,SAAA,CAAU,YAAY,CAAC,CAAA;AAC9D,IAAA,YAAA,CAAa,OAAA,CAAQ,YAAA,EAAc,IAAA,CAAK,SAAA,CAAU,gBAAgB,CAAC,CAAA;AACnE,IAAA,eAAA,CAAgB,KAAK,CAAA;AAAA,EACvB,CAAA;AAEA,EAAA,MAAM,CAAA,GAAI,CAAC,CAAA,KAAc,KAAA,CAAM,aAAA,GAAgB,CAAA,EAAG,GAAA,CAAI,CAAC,CAAC,CAAA,KAAA,CAAA,GAAO,CAAA,EAAG,CAAC,CAAA,IAAA,CAAA;AAEnE,EAAA,IAAI,OAAA,IAAW,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG;AAChC,IAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,oHAAA,EAAqH,QAAA,EAAA,YAAA,EAAU,CAAA;AAAA,EACvJ;AAKA,EAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,MAAA,GAAS,EAAA,GAAK,EAAA;AAEzC,EAAA,uBACE,IAAA,CAAA,QAAA,EAAA,EAKE,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QAAI,SAAA,EAAU,qDAAA;AAAA,QACb,KAAA,EAAO;AAAA,UACL,SAAA,EAAW,aAAA;AAAA,UACX,eAAA,EAAiB,CAAA,iBAAA,EAAoB,UAAA,CAAW,aAAA,GAAgB,GAAG,CAAA,CAAA,CAAA;AAAA;AAAA,UACnE,gBAAgB,UAAA,CAAW,UAAA,GAAa,IAAI,CAAA,KAAA,EAAQ,UAAA,CAAW,UAAU,CAAA,GAAA,CAAA,GAAQ;AAAA,SACnF;AAAA,QAKA,8BAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gCAAA,EACZ,QAAA,EAAA,IAAA,CAAK,IAAI,CAAA,CAAA,KAAK;AACb,UAAA,MAAM,CAAC,SAAS,CAAA,GAAI,aAAa,CAAA,CAAE,IAAA,EAAM,EAAE,KAAK,CAAA;AAChD,UAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,KAAA,GACZ,uDAAA,GACA,4DAAA;AACJ,UAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAiB,SAAA,EAAW,CAAA,0DAAA,EAA6D,KAAK,CAAA,CAAA,EAC7F,QAAA,EAAA;AAAA,4BAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,wCAAA,EACb,QAAA,EAAA;AAAA,8BAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,gBAAA,EACb,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,8CAAA,EAAgD,QAAA,EAAA,CAAA,CAAE,IAAA,EAAK,CAAA;AAAA,gBACrE,KAAA,CAAM,aAAA,oBACL,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wCAAA,EACZ,QAAA,EAAA,WAAA,CAAY,CAAA,CAAE,QAAA,EAAU,KAAA,CAAM,SAAS,CAAA,CAAE,IAAA,EAC5C;AAAA,eAAA,EAEJ,CAAA;AAAA,kCACC,KAAA,EAAA,EAAI,SAAA,EAAU,8EACZ,QAAA,EAAA,CAAA,CAAE,CAAA,CAAE,IAAI,CAAA,EACX;AAAA,aAAA,EACF,CAAA;AAAA,4BACA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4CAAA,EACb,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,YAAA,EAAc,QAAA,EAAA,SAAA,EAAU,CAAA;AAAA,8BACxC,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,yBAAA,EAA0B,QAAA,EAAA;AAAA,gBAAA,IAAA;AAAA,gBAAG,CAAA,CAAE,EAAE,IAAI,CAAA;AAAA,gBAAE,KAAA;AAAA,gBAAI,CAAA,CAAE,EAAE,GAAG;AAAA,eAAA,EAAE;AAAA,aAAA,EACtE;AAAA,WAAA,EAAA,EAjBQ,EAAE,IAkBZ,CAAA;AAAA,QAEJ,CAAC,CAAA,EACH;AAAA;AAAA,KACF;AAAA,oBAEA,IAAA;AAAA,MAAC,mBAAA;AAAA,MAAA;AAAA,QAAoB,IAAA,EAAM,YAAA;AAAA,QAAc,OAAA,EAAS,MAAM,eAAA,CAAgB,KAAK,CAAA;AAAA,QAAG,KAAA,EAAM,kBAAA;AAAA,QACpF,UAAA,EAAY,gBAAA;AAAA,QAAkB,kBAAA,EAAoB,mBAAA;AAAA,QAAqB,MAAA,EAAQ,YAAA;AAAA,QAC/E,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,WAAA,EACb,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EACC,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,0CAAA,EAA2C,QAAA,EAAA,SAAA,EAAO,CAAA;AAAA,4BAChE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,8BAAA,EACb,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,4BAAA,EAA6B,QAAA,EAAA,aAAA,EAAW,CAAA;AAAA,kCACvD,KAAA,EAAA,EAAI,SAAA,EAAU,cACX,QAAA,EAAA,CAAC,EAAE,KAAK,KAAA,EAAO,KAAA,EAAO,SAAK,EAAG,EAAE,KAAK,IAAA,EAAM,KAAA,EAAO,SAAM,CAAA,CAAY,IAAI,CAAA,CAAA,qBACxE,GAAA;AAAA,gBAAC,QAAA;AAAA,gBAAA;AAAA,kBAA2B,OAAA,EAAS,MAAM,cAAA,CAAe,CAAA,CAAA,MAAM,EAAE,GAAG,CAAA,EAAG,aAAA,EAAe,CAAA,CAAE,GAAA,EAAI,CAAE,CAAA;AAAA,kBAC7F,WAAW,CAAA,kEAAA,EAAqE,WAAA,CAAY,kBAAkB,CAAA,CAAE,GAAA,GAAM,2CAA2C,yDAAyD,CAAA,CAAA;AAAA,kBACzN,QAAA,EAAA,CAAA,CAAE;AAAA,iBAAA;AAAA,gBAFQ,MAAA,CAAO,EAAE,GAAG;AAAA,eAI1B,CAAA,EACH;AAAA,aAAA,EACF,CAAA;AAAA,4BACA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,8BAAA,EACb,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,4BAAA,EAA6B,QAAA,EAAA,aAAA,EAAW,CAAA;AAAA,kCACvD,KAAA,EAAA,EAAI,SAAA,EAAU,cACX,QAAA,EAAA,CAAC,EAAE,KAAK,KAAA,EAAO,KAAA,EAAO,SAAQ,EAAG,EAAE,KAAK,IAAA,EAAM,KAAA,EAAO,OAAO,CAAA,CAAY,IAAI,CAAA,CAAA,qBAC5E,GAAA;AAAA,gBAAC,QAAA;AAAA,gBAAA;AAAA,kBAA2B,OAAA,EAAS,MAAM,cAAA,CAAe,CAAA,CAAA,MAAM,EAAE,GAAG,CAAA,EAAG,SAAA,EAAW,CAAA,CAAE,GAAA,EAAI,CAAE,CAAA;AAAA,kBACzF,WAAW,CAAA,kEAAA,EAAqE,WAAA,CAAY,cAAc,CAAA,CAAE,GAAA,GAAM,2CAA2C,yDAAyD,CAAA,CAAA;AAAA,kBACrN,QAAA,EAAA,CAAA,CAAE;AAAA,iBAAA;AAAA,gBAFQ,MAAA,CAAO,EAAE,GAAG;AAAA,eAI1B,CAAA,EACH;AAAA,aAAA,EACF,CAAA;AAAA,4BACA,IAAA,CAAC,OAAA,EAAA,EAAM,SAAA,EAAU,wCAAA,EACf,QAAA,EAAA;AAAA,8BAAA,GAAA;AAAA,gBAAC,OAAA;AAAA,gBAAA;AAAA,kBAAM,IAAA,EAAK,UAAA;AAAA,kBAAW,SAAS,WAAA,CAAY,aAAA;AAAA,kBAAe,QAAA,EAAU,CAAA,CAAA,KAAK,cAAA,CAAe,CAAA,CAAA,MAAM,EAAE,GAAG,CAAA,EAAG,aAAA,EAAe,CAAA,CAAE,MAAA,CAAO,OAAA,EAAQ,CAAE,CAAA;AAAA,kBACvI,SAAA,EAAU;AAAA;AAAA,eAAoD;AAAA,8BAChE,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uBAAA,EAAwB,QAAA,EAAA,iBAAA,EAAe;AAAA,aAAA,EACzD;AAAA,WAAA,EACF,CAAA,EACF,CAAA;AAAA,+BACC,KAAA,EAAA,EACC,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,0CAAA,EAA2C,QAAA,EAAA,QAAA,EAAM,CAAA;AAAA,4BAC/D,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iDAAA,EACZ,QAAA,EAAA,MAAA,CAAO,IAAA,CAAK,gBAAgB,CAAA,CAAE,GAAA,CAAI,CAAA,IAAA,qBACjC,IAAA,CAAC,OAAA,EAAA,EAAiB,WAAU,mFAAA,EAC1B,QAAA,EAAA;AAAA,8BAAA,GAAA;AAAA,gBAAC,OAAA;AAAA,gBAAA;AAAA,kBAAM,IAAA,EAAK,UAAA;AAAA,kBAAW,OAAA,EAAS,YAAA,CAAa,QAAA,CAAS,IAAI,CAAA;AAAA,kBACxD,UAAU,MAAM,eAAA,CAAgB,UAAQ,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,GAAI,IAAA,CAAK,MAAA,CAAO,CAAA,CAAA,KAAK,MAAM,IAAI,CAAA,GAAI,CAAC,GAAG,IAAA,EAAM,IAAI,CAAC,CAAA;AAAA,kBAC5G,SAAA,EAAU;AAAA;AAAA,eAAwE;AAAA,cACnF;AAAA,aAAA,EAAA,EAJS,IAKZ,CACD,CAAA,EACH;AAAA,WAAA,EACF;AAAA;AAAA;AAAA;AACF,GAAA,EACF,CAAA;AAEJ","file":"Weather-XTADR7Z3.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';\n\n// [condition, day emoji, night emoji, day gradient, night gradient]\nconst WMO: Record<number, [string, string, string, string, string]> = {\n 0: ['Clear Sky', '☀️', '🌙', 'from-sky-400 to-blue-500', 'from-indigo-800 to-slate-900'],\n 1: ['Mainly Clear', '🌤️', '🌙', 'from-sky-400 to-blue-500', 'from-indigo-800 to-slate-900'],\n 2: ['Partly Cloudy', '⛅', '☁️', 'from-sky-400 to-blue-400', 'from-indigo-700 to-slate-800'],\n 3: ['Overcast', '☁️', '☁️', 'from-gray-400 to-gray-500', 'from-gray-700 to-slate-800'],\n 45: ['Foggy', '🌫️', '🌫️', 'from-gray-400 to-gray-500', 'from-gray-700 to-slate-800'],\n 48: ['Foggy', '🌫️', '🌫️', 'from-gray-400 to-gray-500', 'from-gray-700 to-slate-800'],\n 51: ['Light Drizzle', '🌦️', '🌧️', 'from-gray-400 to-blue-500', 'from-gray-700 to-indigo-800'],\n 53: ['Drizzle', '🌧️', '🌧️', 'from-gray-500 to-blue-600', 'from-gray-700 to-indigo-800'],\n 55: ['Heavy Drizzle', '🌧️', '🌧️', 'from-gray-500 to-blue-600', 'from-gray-700 to-indigo-800'],\n 61: ['Light Rain', '🌦️', '🌧️', 'from-gray-400 to-blue-500', 'from-gray-700 to-indigo-800'],\n 63: ['Rain', '🌧️', '🌧️', 'from-gray-500 to-blue-600', 'from-gray-700 to-indigo-800'],\n 65: ['Heavy Rain', '🌧️', '🌧️', 'from-gray-600 to-blue-700', 'from-gray-700 to-indigo-900'],\n 71: ['Light Snow', '🌨️', '🌨️', 'from-blue-200 to-blue-400', 'from-blue-800 to-slate-900'],\n 73: ['Snow', '❄️', '❄️', 'from-blue-300 to-blue-500', 'from-blue-800 to-slate-900'],\n 75: ['Heavy Snow', '❄️', '❄️', 'from-blue-400 to-blue-600', 'from-blue-800 to-slate-900'],\n 80: ['Rain Showers', '🌧️', '🌧️', 'from-gray-500 to-blue-600', 'from-gray-700 to-indigo-800'],\n 82: ['Heavy Showers', '🌧️', '🌧️', 'from-gray-600 to-blue-700', 'from-gray-700 to-indigo-900'],\n 95: ['Thunderstorm', '⛈️', '⛈️', 'from-gray-700 to-indigo-800', 'from-gray-800 to-indigo-950'],\n 96: ['Thunderstorm', '⛈️', '⛈️', 'from-gray-700 to-indigo-800', 'from-gray-800 to-indigo-950'],\n 99: ['Thunderstorm', '⛈️', '⛈️', 'from-gray-700 to-indigo-900', 'from-gray-800 to-indigo-950'],\n};\n\nconst getCondition = (code: number, isDay = true) => {\n const entry = WMO[code] || ['Unknown', '❓', '❓', 'from-gray-400 to-gray-500', 'from-gray-700 to-slate-800'];\n return [entry[0], isDay ? entry[1] : entry[2], isDay ? entry[3] : entry[4]] as [string, string, string];\n};\n\nconst AVAILABLE_CITIES: Record<string, { lat: number; lon: number }> = {\n 'Sydney': { lat: -33.8688, lon: 151.2093 },\n 'London': { lat: 51.5074, lon: -0.1278 },\n 'Los Angeles': { lat: 34.0522, lon: -118.2437 },\n 'Shanghai': { lat: 31.2304, lon: 121.4737 },\n 'New York': { lat: 40.7128, lon: -74.0060 },\n 'Tokyo': { lat: 35.6762, lon: 139.6503 },\n 'Dubai': { lat: 25.2048, lon: 55.2708 },\n 'Singapore': { lat: 1.3521, lon: 103.8198 },\n 'Hong Kong': { lat: 22.3193, lon: 114.1694 },\n 'Paris': { lat: 48.8566, lon: 2.3522 },\n 'Berlin': { lat: 52.5200, lon: 13.4050 },\n 'Mumbai': { lat: 19.0760, lon: 72.8777 },\n 'Bangkok': { lat: 13.7563, lon: 100.5018 },\n 'Melbourne': { lat: -37.8136, lon: 144.9631 },\n 'Toronto': { lat: 43.6532, lon: -79.3832 },\n 'Miami': { lat: 25.7617, lon: -80.1918 },\n 'Chicago': { lat: 41.8781, lon: -87.6298 },\n 'Auckland': { lat: -36.8485, lon: 174.7633 },\n};\n\nconst DEFAULT_CITIES = ['Sydney', 'London', 'Los Angeles', 'Shanghai'];\nconst STORAGE_KEY = 'weather_cities';\nconst SETTINGS_KEY = 'weather_appearance';\nconst CACHE_KEY = 'weather_multi_cache';\nconst CACHE_TTL = 30 * 60 * 1000;\n\ninterface CityWeather { city: string; temp: number; code: number; high: number; low: number; isDay: boolean; timezone: string }\ninterface WeatherPrefs { useFahrenheit: boolean; showLocalTime: boolean; use24Hour: boolean }\nconst DEFAULT_PREFS: WeatherPrefs = { useFahrenheit: false, showLocalTime: false, use24Hour: false };\n\nfunction loadCities(): string[] {\n try { const s = JSON.parse(localStorage.getItem(STORAGE_KEY) || ''); if (Array.isArray(s) && s.length) return s; } catch {}\n return DEFAULT_CITIES;\n}\n\nconst toF = (c: number) => Math.round(c * 9 / 5 + 32);\n\nfunction getTimeInTz(timezone: string, use24Hour = false): { hours: number; minutes: number; text: string } {\n try {\n const now = new Date();\n const h24Parts = new Intl.DateTimeFormat('en-US', { timeZone: timezone, hour: 'numeric', minute: '2-digit', hour12: false }).formatToParts(now);\n const h24 = parseInt(h24Parts.find(p => p.type === 'hour')?.value || '0');\n const m = parseInt(h24Parts.find(p => p.type === 'minute')?.value || '0');\n if (use24Hour) {\n return { hours: h24, minutes: m, text: `${String(h24).padStart(2, '0')}:${String(m).padStart(2, '0')}` };\n }\n const parts = new Intl.DateTimeFormat('en-US', { timeZone: timezone, hour: 'numeric', minute: '2-digit', hour12: true }).formatToParts(now);\n const h12 = parseInt(parts.find(p => p.type === 'hour')?.value || '12');\n const period = parts.find(p => p.type === 'dayPeriod')?.value || '';\n return { hours: h24, minutes: m, text: `${h12}:${String(m).padStart(2, '0')} ${period}` };\n } catch { return { hours: 0, minutes: 0, text: '' }; }\n}\n\n/** Tiny analog clock SVG */\nfunction MiniClock({ hours, minutes, size = 20 }: { hours: number; minutes: number; size?: number }) {\n const r = size / 2;\n const hAngle = ((hours % 12) + minutes / 60) * 30 - 90;\n const mAngle = minutes * 6 - 90;\n const hRad = (hAngle * Math.PI) / 180;\n const mRad = (mAngle * Math.PI) / 180;\n const hLen = r * 0.5;\n const mLen = r * 0.7;\n return (\n <svg width={size} height={size} className=\"shrink-0\">\n <circle cx={r} cy={r} r={r - 1} fill=\"rgba(255,255,255,0.15)\" stroke=\"rgba(255,255,255,0.4)\" strokeWidth={1} />\n {/* Hour hand */}\n <line x1={r} y1={r} x2={r + Math.cos(hRad) * hLen} y2={r + Math.sin(hRad) * hLen}\n stroke=\"white\" strokeWidth={1.5} strokeLinecap=\"round\" />\n {/* Minute hand */}\n <line x1={r} y1={r} x2={r + Math.cos(mRad) * mLen} y2={r + Math.sin(mRad) * mLen}\n stroke=\"white\" strokeWidth={1} strokeLinecap=\"round\" />\n {/* Center dot */}\n <circle cx={r} cy={r} r={1} fill=\"white\" />\n </svg>\n );\n}\n\nexport default function Weather() {\n const [cities, setCities] = useState(loadCities);\n const [appearance, setAppearance] = useState(() => loadAppearance(SETTINGS_KEY));\n const [data, setData] = useState<CityWeather[]>([]);\n const [loading, setLoading] = useState(true);\n // Tick every minute so clocks update\n const [, setTick] = useState(0);\n useEffect(() => { const t = setInterval(() => setTick(n => n + 1), 60000); return () => clearInterval(t); }, []);\n const [settingsOpen, setSettingsOpen] = useState(false);\n const [configCities, setConfigCities] = useState<string[]>([]);\n const [configAppearance, setConfigAppearance] = useState<WidgetAppearance>(appearance);\n // Prefs live in the consumer-supplied prefs adapter so they persist\n // reliably across re-mounts without the local useState/localStorage dance.\n const { prefs: shellPrefs, save: saveShellPrefs } = useShellPrefs();\n const prefs: WeatherPrefs = { ...DEFAULT_PREFS, ...(shellPrefs.weather_prefs as WeatherPrefs | undefined ?? {}) };\n const [configPrefs, setConfigPrefs] = useState<WeatherPrefs>(prefs);\n\n useWidgetSettings(useCallback(() => {\n setConfigCities([...cities]);\n setConfigAppearance({ ...appearance });\n setConfigPrefs({ ...prefs });\n setSettingsOpen(true);\n }, [cities, appearance, prefs]));\n\n const fetchAll = useCallback(async (cityList: string[], force = false) => {\n if (!force) {\n try {\n const cached = JSON.parse(localStorage.getItem(CACHE_KEY) || '{}');\n const key = cityList.join(',');\n if (cached[key] && Date.now() - cached[key].ts < CACHE_TTL) {\n setData(cached[key].data); setLoading(false); return;\n }\n } catch {}\n }\n setLoading(true);\n const results: CityWeather[] = [];\n for (const city of cityList) {\n const coords = AVAILABLE_CITIES[city];\n if (!coords) continue;\n try {\n const res = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${coords.lat}&longitude=${coords.lon}&current=temperature_2m,weather_code,is_day&daily=temperature_2m_max,temperature_2m_min&forecast_days=1&timezone=auto`);\n const w = await res.json();\n results.push({ city, temp: Math.round(w.current.temperature_2m), code: w.current.weather_code, high: Math.round(w.daily.temperature_2m_max[0]), low: Math.round(w.daily.temperature_2m_min[0]), isDay: w.current.is_day === 1, timezone: w.timezone || 'UTC' });\n } catch {}\n }\n setData(results); setLoading(false);\n try { const c = JSON.parse(localStorage.getItem(CACHE_KEY) || '{}'); c[cityList.join(',')] = { data: results, ts: Date.now() }; localStorage.setItem(CACHE_KEY, JSON.stringify(c)); } catch {}\n }, []);\n\n useEffect(() => { fetchAll(cities); }, [cities, fetchAll]);\n\n const saveSettings = () => {\n if (configCities.length === 0) return;\n setCities(configCities);\n setAppearance(configAppearance);\n saveShellPrefs({ weather_prefs: configPrefs });\n localStorage.setItem(STORAGE_KEY, JSON.stringify(configCities));\n localStorage.setItem(SETTINGS_KEY, JSON.stringify(configAppearance));\n setSettingsOpen(false);\n };\n\n const t = (c: number) => prefs.useFahrenheit ? `${toF(c)}°F` : `${c}°`;\n\n if (loading && data.length === 0) {\n return <div className=\"flex items-center justify-center h-full bg-gradient-to-b from-sky-400 to-blue-500 rounded-lg text-white/70 text-sm\">Loading...</div>;\n }\n\n // Cards are ~88 px tall (px-4 py-3 + 2 stacked text rows) + 8 px gap. Add\n // 16 px for the panel's own p-2 padding so the widget never collapses below\n // its rendered height.\n const dynamicHeight = data.length * 96 + 16;\n\n return (\n <>\n {/* Outer panel sets the user-tunable translucency via background alpha\n * (NOT `opacity`, which would also fade the row colors into gray) and\n * carries the rounded clip. Rows fill the panel edge-to-edge so each\n * city's day/night gradient reads at full saturation. */}\n <div className=\"flex flex-col rounded-lg text-white overflow-hidden\"\n style={{\n minHeight: dynamicHeight,\n backgroundColor: `rgba(15, 23, 42, ${appearance.activeOpacity / 100})`, // slate-900 with alpha\n backdropFilter: appearance.activeBlur > 0 ? `blur(${appearance.activeBlur}px)` : undefined,\n }}>\n {/* iOS-style city cards — each its own rounded tile sitting on the\n * panel's slate backdrop so the day/night gradient pops. Layout:\n * city + time on top-left, large temperature on top-right,\n * condition + H/L on the bottom row. */}\n <div className=\"flex-1 flex flex-col gap-2 p-2\">\n {data.map(d => {\n const [condition] = getCondition(d.code, d.isDay);\n const rowBg = d.isDay\n ? 'bg-gradient-to-br from-sky-400 via-sky-300 to-sky-500'\n : 'bg-gradient-to-br from-slate-800 via-blue-950 to-slate-900';\n return (\n <div key={d.city} className={`rounded-2xl px-4 py-3 flex flex-col justify-between gap-3 ${rowBg}`}>\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-lg font-semibold leading-tight truncate\">{d.city}</div>\n {prefs.showLocalTime && (\n <div className=\"text-xs opacity-90 mt-0.5 tabular-nums\">\n {getTimeInTz(d.timezone, prefs.use24Hour).text}\n </div>\n )}\n </div>\n <div className=\"text-4xl font-extralight leading-none tracking-tight tabular-nums shrink-0\">\n {t(d.temp)}\n </div>\n </div>\n <div className=\"flex items-end justify-between text-[11px]\">\n <span className=\"opacity-95\">{condition}</span>\n <span className=\"opacity-90 tabular-nums\">H:{t(d.high)} L:{t(d.low)}</span>\n </div>\n </div>\n );\n })}\n </div>\n </div>\n\n <WidgetSettingsModal open={settingsOpen} onClose={() => setSettingsOpen(false)} title=\"Weather Settings\"\n appearance={configAppearance} onAppearanceChange={setConfigAppearance} onSave={saveSettings}>\n <div className=\"space-y-3\">\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={() => setConfigPrefs(p => ({ ...p, useFahrenheit: o.key }))}\n className={`px-3 py-1 text-xs font-medium rounded-lg border transition-colors ${configPrefs.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 <div className=\"flex items-center gap-3 mb-2\">\n <span className=\"text-sm text-gray-600 w-24\">Time Format</span>\n <div className=\"flex gap-1\">\n {([{ key: false, label: 'AM/PM' }, { key: true, label: '24H' }] as const).map(o => (\n <button key={String(o.key)} onClick={() => setConfigPrefs(p => ({ ...p, use24Hour: o.key }))}\n className={`px-3 py-1 text-xs font-medium rounded-lg border transition-colors ${configPrefs.use24Hour === 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 <label className=\"flex items-center gap-2 cursor-pointer\">\n <input type=\"checkbox\" checked={configPrefs.showLocalTime} onChange={e => setConfigPrefs(p => ({ ...p, showLocalTime: e.target.checked }))}\n className=\"rounded border-gray-300 text-blue-600 h-3.5 w-3.5\" />\n <span className=\"text-sm text-gray-600\">Show local time</span>\n </label>\n </div>\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-48 overflow-y-auto\">\n {Object.keys(AVAILABLE_CITIES).map(city => (\n <label key={city} 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(city)}\n onChange={() => setConfigCities(prev => prev.includes(city) ? prev.filter(c => c !== city) : [...prev, city])}\n className=\"rounded border-gray-300 text-blue-600 focus:ring-blue-500 h-3.5 w-3.5\" />\n {city}\n </label>\n ))}\n </div>\n </div>\n </WidgetSettingsModal>\n </>\n );\n}\n"]}