efficient-shell 4.134.0 → 4.137.1

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 (171) hide show
  1. package/LICENSE +6 -17
  2. package/README.md +84 -8
  3. package/dist/Browser-ZX5OTOKK.js +43 -0
  4. package/dist/Calculator-4SQGOQFQ.js +29 -0
  5. package/dist/ConfirmDialog-NPKW2XHM.js +1 -0
  6. package/dist/CurrencyConverter-2KOM7L6V.js +21 -0
  7. package/dist/Documents-IZTIQYPG.js +52 -0
  8. package/dist/Files-B63KKXGZ.js +89 -0
  9. package/dist/Notepad-WA77V45J.js +25 -0
  10. package/dist/PdfViewer-RBRGEKWF.js +1 -0
  11. package/dist/PomodoroTimer-SDUBKXUS.js +99 -0
  12. package/dist/Preview-D4KOA4OI.js +187 -0
  13. package/dist/Sidebar-Y57LYXXI.js +23 -0
  14. package/dist/Spreadsheet-JX5E6WH6.js +37 -0
  15. package/dist/Stock-XAQ5WMUZ.js +16 -0
  16. package/dist/Weather-HLAGJ5LV.js +60 -0
  17. package/dist/WorldClock-IRI4VCTA.js +32 -0
  18. package/dist/apps/index.js +1 -151
  19. package/dist/brand.css +1 -1
  20. package/dist/chunk-3A46NCXK.js +29 -0
  21. package/dist/chunk-44UO7FYU.js +11 -0
  22. package/dist/chunk-466CM2TJ.js +1 -0
  23. package/dist/chunk-57MIENLJ.js +1 -0
  24. package/dist/chunk-5CRAF2AD.js +2 -0
  25. package/dist/chunk-A2OQLLYK.js +6 -0
  26. package/dist/chunk-B43AGQET.js +4 -0
  27. package/dist/chunk-BR22X7E5.js +1 -0
  28. package/dist/chunk-BUTSU7FO.js +1 -0
  29. package/dist/chunk-D65T4H6J.js +1 -0
  30. package/dist/chunk-ESL5TDNA.js +1 -0
  31. package/dist/chunk-FBDZGO3V.js +1 -0
  32. package/dist/chunk-FHTLC7HH.js +1 -0
  33. package/dist/chunk-FQLMX3IE.js +948 -0
  34. package/dist/chunk-H562R4GX.js +34 -0
  35. package/dist/chunk-JN4WXTWJ.js +106 -0
  36. package/dist/chunk-LVDRBRYU.js +1 -0
  37. package/dist/chunk-LWLCNQY7.js +1 -0
  38. package/dist/chunk-MAIHBBWT.js +1 -0
  39. package/dist/chunk-NPJH5MD7.js +13 -0
  40. package/dist/chunk-OCSOMMY2.js +1 -0
  41. package/dist/chunk-OQDWLHZI.js +1 -0
  42. package/dist/chunk-OWSAMA3I.js +23 -0
  43. package/dist/chunk-PH3PRIFP.js +5 -0
  44. package/dist/chunk-TAWKWSPN.js +9 -0
  45. package/dist/chunk-U4GTZPXP.js +1 -0
  46. package/dist/chunk-UB4JIOLD.js +2 -0
  47. package/dist/chunk-UZAJ5BF6.js +9 -0
  48. package/dist/chunk-VEGMDXT4.js +1 -0
  49. package/dist/chunk-VTVSMRFX.js +1 -0
  50. package/dist/chunk-VVAGSKW7.js +1 -0
  51. package/dist/chunk-XO43FJRM.js +19 -0
  52. package/dist/chunk-Y7BOLDRM.js +69 -0
  53. package/dist/file-intake/index.js +1 -4
  54. package/dist/{index-DZ7E7bCl.d.ts → index-DVI9DMSu.d.ts} +189 -18
  55. package/dist/index.d.ts +2 -2
  56. package/dist/index.js +639 -7473
  57. package/dist/map/index.js +20 -540
  58. package/dist/markdown/index.js +6 -184
  59. package/dist/markup/index.js +1 -135
  60. package/dist/page-tabs/index.js +21 -709
  61. package/dist/sounds-OMHXVVQ4.js +1 -0
  62. package/dist/ui/index.d.ts +1 -1
  63. package/dist/ui/index.js +1 -19
  64. package/dist/ui.css +78 -10
  65. package/package.json +4 -3
  66. package/dist/Browser-O3QZGUF2.js +0 -482
  67. package/dist/Browser-O3QZGUF2.js.map +0 -1
  68. package/dist/Calculator-L6N5X3KU.js +0 -192
  69. package/dist/Calculator-L6N5X3KU.js.map +0 -1
  70. package/dist/ConfirmDialog-LYSSZSUD.js +0 -4
  71. package/dist/ConfirmDialog-LYSSZSUD.js.map +0 -1
  72. package/dist/CurrencyConverter-64MKXB3D.js +0 -236
  73. package/dist/CurrencyConverter-64MKXB3D.js.map +0 -1
  74. package/dist/Documents-5WXXYCLI.js +0 -441
  75. package/dist/Documents-5WXXYCLI.js.map +0 -1
  76. package/dist/Files-AUURUUDN.js +0 -805
  77. package/dist/Files-AUURUUDN.js.map +0 -1
  78. package/dist/Notepad-GPXJVPB7.js +0 -410
  79. package/dist/Notepad-GPXJVPB7.js.map +0 -1
  80. package/dist/PdfViewer-HKO6P4SR.js +0 -5
  81. package/dist/PdfViewer-HKO6P4SR.js.map +0 -1
  82. package/dist/PomodoroTimer-4TQBWLP2.js +0 -633
  83. package/dist/PomodoroTimer-4TQBWLP2.js.map +0 -1
  84. package/dist/Preview-FOZYPKM2.js +0 -2959
  85. package/dist/Preview-FOZYPKM2.js.map +0 -1
  86. package/dist/Sidebar-BPU7RCZP.js +0 -291
  87. package/dist/Sidebar-BPU7RCZP.js.map +0 -1
  88. package/dist/Spreadsheet-3C66BBBF.js +0 -519
  89. package/dist/Spreadsheet-3C66BBBF.js.map +0 -1
  90. package/dist/Stock-IF4IHYLU.js +0 -158
  91. package/dist/Stock-IF4IHYLU.js.map +0 -1
  92. package/dist/Weather-725PFR7T.js +0 -431
  93. package/dist/Weather-725PFR7T.js.map +0 -1
  94. package/dist/WorldClock-UU4NZIQ7.js +0 -202
  95. package/dist/WorldClock-UU4NZIQ7.js.map +0 -1
  96. package/dist/apps/index.js.map +0 -1
  97. package/dist/chunk-2TPTHAKI.js +0 -316
  98. package/dist/chunk-2TPTHAKI.js.map +0 -1
  99. package/dist/chunk-4P44JXDS.js +0 -195
  100. package/dist/chunk-4P44JXDS.js.map +0 -1
  101. package/dist/chunk-5O42JXQE.js +0 -26
  102. package/dist/chunk-5O42JXQE.js.map +0 -1
  103. package/dist/chunk-72CQWN7O.js +0 -547
  104. package/dist/chunk-72CQWN7O.js.map +0 -1
  105. package/dist/chunk-7CCHEEYC.js +0 -94
  106. package/dist/chunk-7CCHEEYC.js.map +0 -1
  107. package/dist/chunk-BE7FZOFU.js +0 -17
  108. package/dist/chunk-BE7FZOFU.js.map +0 -1
  109. package/dist/chunk-D276EMXS.js +0 -57
  110. package/dist/chunk-D276EMXS.js.map +0 -1
  111. package/dist/chunk-D7PYW2QS.js +0 -265
  112. package/dist/chunk-D7PYW2QS.js.map +0 -1
  113. package/dist/chunk-DVZWYWSD.js +0 -26
  114. package/dist/chunk-DVZWYWSD.js.map +0 -1
  115. package/dist/chunk-ET6ID4LP.js +0 -102
  116. package/dist/chunk-ET6ID4LP.js.map +0 -1
  117. package/dist/chunk-GA35NEND.js +0 -56
  118. package/dist/chunk-GA35NEND.js.map +0 -1
  119. package/dist/chunk-GIGV2ZRW.js +0 -70
  120. package/dist/chunk-GIGV2ZRW.js.map +0 -1
  121. package/dist/chunk-IPXN646P.js +0 -14
  122. package/dist/chunk-IPXN646P.js.map +0 -1
  123. package/dist/chunk-IRWSRJ4K.js +0 -48
  124. package/dist/chunk-IRWSRJ4K.js.map +0 -1
  125. package/dist/chunk-IULP5BCD.js +0 -79
  126. package/dist/chunk-IULP5BCD.js.map +0 -1
  127. package/dist/chunk-MGGY74RY.js +0 -14
  128. package/dist/chunk-MGGY74RY.js.map +0 -1
  129. package/dist/chunk-OLJDJYSU.js +0 -13678
  130. package/dist/chunk-OLJDJYSU.js.map +0 -1
  131. package/dist/chunk-PIGDNN5F.js +0 -46
  132. package/dist/chunk-PIGDNN5F.js.map +0 -1
  133. package/dist/chunk-Q2MJVSJT.js +0 -7
  134. package/dist/chunk-Q2MJVSJT.js.map +0 -1
  135. package/dist/chunk-Q3LT745N.js +0 -3710
  136. package/dist/chunk-Q3LT745N.js.map +0 -1
  137. package/dist/chunk-QAGQRNKI.js +0 -145
  138. package/dist/chunk-QAGQRNKI.js.map +0 -1
  139. package/dist/chunk-QRL64J5F.js +0 -503
  140. package/dist/chunk-QRL64J5F.js.map +0 -1
  141. package/dist/chunk-QSKCQUZE.js +0 -1103
  142. package/dist/chunk-QSKCQUZE.js.map +0 -1
  143. package/dist/chunk-R4OQIQYX.js +0 -153
  144. package/dist/chunk-R4OQIQYX.js.map +0 -1
  145. package/dist/chunk-RT6DSB5Y.js +0 -143
  146. package/dist/chunk-RT6DSB5Y.js.map +0 -1
  147. package/dist/chunk-SHQM5CK3.js +0 -549
  148. package/dist/chunk-SHQM5CK3.js.map +0 -1
  149. package/dist/chunk-T4VQHMG4.js +0 -822
  150. package/dist/chunk-T4VQHMG4.js.map +0 -1
  151. package/dist/chunk-TRCWINHF.js +0 -105
  152. package/dist/chunk-TRCWINHF.js.map +0 -1
  153. package/dist/chunk-TW7LPMVR.js +0 -16
  154. package/dist/chunk-TW7LPMVR.js.map +0 -1
  155. package/dist/chunk-W622KQTD.js +0 -465
  156. package/dist/chunk-W622KQTD.js.map +0 -1
  157. package/dist/chunk-X4Q6G253.js +0 -416
  158. package/dist/chunk-X4Q6G253.js.map +0 -1
  159. package/dist/chunk-YNKK7NE3.js +0 -171
  160. package/dist/chunk-YNKK7NE3.js.map +0 -1
  161. package/dist/chunk-YPO6RDMX.js +0 -20
  162. package/dist/chunk-YPO6RDMX.js.map +0 -1
  163. package/dist/file-intake/index.js.map +0 -1
  164. package/dist/index.js.map +0 -1
  165. package/dist/map/index.js.map +0 -1
  166. package/dist/markdown/index.js.map +0 -1
  167. package/dist/markup/index.js.map +0 -1
  168. package/dist/page-tabs/index.js.map +0 -1
  169. package/dist/sounds-NT4DEZGD.js +0 -3
  170. package/dist/sounds-NT4DEZGD.js.map +0 -1
  171. package/dist/ui/index.js.map +0 -1
@@ -1,192 +0,0 @@
1
- import { loadAppearance, WidgetSettingsModal } from './chunk-R4OQIQYX.js';
2
- import { useWidgetSettings } from './chunk-Q3LT745N.js';
3
- import './chunk-GA35NEND.js';
4
- import './chunk-2TPTHAKI.js';
5
- import './chunk-RT6DSB5Y.js';
6
- import './chunk-QRL64J5F.js';
7
- import './chunk-W622KQTD.js';
8
- import './chunk-D276EMXS.js';
9
- import './chunk-72CQWN7O.js';
10
- import './chunk-IRWSRJ4K.js';
11
- import './chunk-IPXN646P.js';
12
- import { useState, useCallback, useEffect } from 'react';
13
- import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
14
-
15
- var CALC_SETTINGS_KEY = "calc_appearance";
16
- function Calculator() {
17
- const [display, setDisplay] = useState("0");
18
- const [prev, setPrev] = useState(null);
19
- const [op, setOp] = useState(null);
20
- const [resetNext, setResetNext] = useState(false);
21
- const [lastExpr, setLastExpr] = useState("");
22
- const [history, setHistory] = useState([]);
23
- const [copied, setCopied] = useState(false);
24
- const [appearance, setAppearance] = useState(() => loadAppearance(CALC_SETTINGS_KEY));
25
- const [settingsOpen, setSettingsOpen] = useState(false);
26
- const [configAppearance, setConfigAppearance] = useState(appearance);
27
- useWidgetSettings(useCallback(() => {
28
- setConfigAppearance({ ...appearance });
29
- setSettingsOpen(true);
30
- }, [appearance]));
31
- const append = useCallback((ch) => {
32
- setLastExpr("");
33
- setDisplay((d) => {
34
- if (resetNext || d === "0") {
35
- setResetNext(false);
36
- return ch === "." ? "0." : ch;
37
- }
38
- if (ch === "." && d.includes(".")) return d;
39
- return d + ch;
40
- });
41
- }, [resetNext]);
42
- const clear = useCallback(() => {
43
- setDisplay("0");
44
- setPrev(null);
45
- setOp(null);
46
- setResetNext(false);
47
- }, []);
48
- const compute = useCallback((a, b, operator) => {
49
- switch (operator) {
50
- case "+":
51
- return a + b;
52
- case "-":
53
- return a - b;
54
- case "\xD7":
55
- return a * b;
56
- case "\xF7":
57
- return b === 0 ? 0 : a / b;
58
- default:
59
- return b;
60
- }
61
- }, []);
62
- const handleOp = useCallback((nextOp) => {
63
- const current = parseFloat(display);
64
- if (prev !== null && op && !resetNext) {
65
- const result = compute(prev, current, op);
66
- setDisplay(String(result));
67
- setPrev(result);
68
- setHistory((h) => [`${prev} ${op} ${current} = ${result}`, ...h].slice(0, 20));
69
- } else {
70
- setPrev(current);
71
- }
72
- setOp(nextOp);
73
- setResetNext(true);
74
- }, [display, prev, op, resetNext, compute]);
75
- const equals = useCallback(() => {
76
- if (prev === null || !op) return;
77
- const current = parseFloat(display);
78
- const result = compute(prev, current, op);
79
- const expr = `${prev} ${op} ${current} =`;
80
- setHistory((h) => [`${expr} ${result}`, ...h].slice(0, 20));
81
- setLastExpr(expr);
82
- setDisplay(String(result));
83
- setPrev(null);
84
- setOp(null);
85
- setResetNext(true);
86
- }, [display, prev, op, compute]);
87
- const percent = useCallback(() => {
88
- setDisplay((d) => String(parseFloat(d) / 100));
89
- }, []);
90
- const negate = useCallback(() => {
91
- setDisplay((d) => d.startsWith("-") ? d.slice(1) : d === "0" ? d : "-" + d);
92
- }, []);
93
- useEffect(() => {
94
- const handler = (e) => {
95
- const tag = e.target.tagName;
96
- if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return;
97
- if (e.key >= "0" && e.key <= "9") append(e.key);
98
- else if (e.key === ".") append(".");
99
- else if (e.key === "+") handleOp("+");
100
- else if (e.key === "-") handleOp("-");
101
- else if (e.key === "*") handleOp("\xD7");
102
- else if (e.key === "/") {
103
- e.preventDefault();
104
- handleOp("\xF7");
105
- } else if (e.key === "Enter" || e.key === "=") equals();
106
- else if (e.key === "Escape") clear();
107
- else if (e.key === "Backspace") setDisplay((d) => d.length > 1 ? d.slice(0, -1) : "0");
108
- else if (e.key === "%") percent();
109
- };
110
- window.addEventListener("keydown", handler);
111
- return () => window.removeEventListener("keydown", handler);
112
- }, [append, handleOp, equals, clear, percent]);
113
- const btn = "flex items-center justify-center rounded-lg text-sm font-medium transition-colors";
114
- const numBtn = `${btn} bg-white border border-gray-200 text-gray-900 hover:bg-gray-50 active:bg-gray-100`;
115
- const opBtn = `${btn} bg-blue-50 border border-blue-200 text-blue-700 hover:bg-blue-100 active:bg-blue-200`;
116
- const fnBtn = `${btn} bg-gray-100 border border-gray-200 text-gray-600 hover:bg-gray-200 active:bg-gray-300`;
117
- const eqBtn = `${btn} bg-blue-600 text-white hover:bg-blue-700 active:bg-blue-800`;
118
- const formatDisplay = (val) => {
119
- const num = parseFloat(val);
120
- if (isNaN(num)) return val;
121
- if (val.endsWith(".") || val.endsWith(".0")) return val;
122
- if (Math.abs(num) < 1e15 && val.length < 16) return val;
123
- return num.toExponential(6);
124
- };
125
- return /* @__PURE__ */ jsxs(Fragment, { children: [
126
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", style: {
127
- opacity: appearance.activeOpacity / 100,
128
- backdropFilter: appearance.activeBlur > 0 ? `blur(${appearance.activeBlur}px)` : void 0
129
- }, children: [
130
- /* @__PURE__ */ jsxs("div", { className: "bg-slate-200 rounded-t-lg px-4 py-2 group/display relative flex flex-col justify-end min-h-[120px] border-b border-slate-300", children: [
131
- /* @__PURE__ */ jsx("div", { className: "flex flex-col justify-end flex-1 overflow-hidden", children: history.slice(0, 3).reverse().map((h, i) => /* @__PURE__ */ jsx("div", { className: "text-[11px] text-slate-400 text-right font-mono truncate", children: h }, i)) }),
132
- (lastExpr || op && prev !== null) && /* @__PURE__ */ jsx("div", { className: "text-base text-slate-600 text-right font-mono", children: lastExpr || `${prev} ${op} ${!resetNext ? display : ""}` }),
133
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
134
- /* @__PURE__ */ jsx(
135
- "button",
136
- {
137
- onClick: () => {
138
- navigator.clipboard.writeText(display);
139
- setCopied(true);
140
- setTimeout(() => setCopied(false), 1200);
141
- },
142
- title: "Copy result",
143
- className: "shrink-0 text-slate-300 hover:text-slate-500 transition-colors opacity-0 group-hover/display:opacity-100",
144
- children: copied ? /* @__PURE__ */ jsx("svg", { className: "h-5 w-5 text-green-500", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) : /* @__PURE__ */ jsx("svg", { className: "h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) })
145
- }
146
- ),
147
- /* @__PURE__ */ jsx("div", { className: "text-right text-4xl font-mono font-bold text-slate-800 truncate flex-1", children: formatDisplay(display) })
148
- ] })
149
- ] }),
150
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-4 grid-rows-5 gap-1.5 flex-1 min-h-0 p-2", children: [
151
- /* @__PURE__ */ jsx("button", { onClick: clear, className: fnBtn, children: "AC" }),
152
- /* @__PURE__ */ jsx("button", { onClick: negate, className: fnBtn, children: "+/\u2212" }),
153
- /* @__PURE__ */ jsx("button", { onClick: percent, className: fnBtn, children: "%" }),
154
- /* @__PURE__ */ jsx("button", { onClick: () => handleOp("\xF7"), className: `${opBtn} ${op === "\xF7" ? "ring-2 ring-blue-400" : ""}`, children: "\xF7" }),
155
- /* @__PURE__ */ jsx("button", { onClick: () => append("7"), className: numBtn, children: "7" }),
156
- /* @__PURE__ */ jsx("button", { onClick: () => append("8"), className: numBtn, children: "8" }),
157
- /* @__PURE__ */ jsx("button", { onClick: () => append("9"), className: numBtn, children: "9" }),
158
- /* @__PURE__ */ jsx("button", { onClick: () => handleOp("\xD7"), className: `${opBtn} ${op === "\xD7" ? "ring-2 ring-blue-400" : ""}`, children: "\xD7" }),
159
- /* @__PURE__ */ jsx("button", { onClick: () => append("4"), className: numBtn, children: "4" }),
160
- /* @__PURE__ */ jsx("button", { onClick: () => append("5"), className: numBtn, children: "5" }),
161
- /* @__PURE__ */ jsx("button", { onClick: () => append("6"), className: numBtn, children: "6" }),
162
- /* @__PURE__ */ jsx("button", { onClick: () => handleOp("-"), className: `${opBtn} ${op === "-" ? "ring-2 ring-blue-400" : ""}`, children: "\u2212" }),
163
- /* @__PURE__ */ jsx("button", { onClick: () => append("1"), className: numBtn, children: "1" }),
164
- /* @__PURE__ */ jsx("button", { onClick: () => append("2"), className: numBtn, children: "2" }),
165
- /* @__PURE__ */ jsx("button", { onClick: () => append("3"), className: numBtn, children: "3" }),
166
- /* @__PURE__ */ jsx("button", { onClick: () => handleOp("+"), className: `${opBtn} ${op === "+" ? "ring-2 ring-blue-400" : ""}`, children: "+" }),
167
- /* @__PURE__ */ jsx("button", { onClick: () => append("0"), className: `${numBtn} col-span-2`, children: "0" }),
168
- /* @__PURE__ */ jsx("button", { onClick: () => append("."), className: numBtn, children: "." }),
169
- /* @__PURE__ */ jsx("button", { onClick: equals, className: eqBtn, children: "=" })
170
- ] })
171
- ] }),
172
- /* @__PURE__ */ jsx(
173
- WidgetSettingsModal,
174
- {
175
- open: settingsOpen,
176
- onClose: () => setSettingsOpen(false),
177
- title: "Calculator Settings",
178
- appearance: configAppearance,
179
- onAppearanceChange: setConfigAppearance,
180
- onSave: () => {
181
- setAppearance(configAppearance);
182
- localStorage.setItem(CALC_SETTINGS_KEY, JSON.stringify(configAppearance));
183
- setSettingsOpen(false);
184
- }
185
- }
186
- )
187
- ] });
188
- }
189
-
190
- export { Calculator as default };
191
- //# sourceMappingURL=Calculator-L6N5X3KU.js.map
192
- //# sourceMappingURL=Calculator-L6N5X3KU.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/apps/Calculator.tsx"],"names":[],"mappings":"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","file":"Calculator-L6N5X3KU.js","sourcesContent":["import { useState, useCallback, useEffect } from 'react';\nimport { useWidgetSettings } from '../shell/Modal';\nimport WidgetSettingsModal, { loadAppearance, type WidgetAppearance } from '../shell/WidgetSettingsModal';\n\ntype Op = '+' | '-' | '×' | '÷' | null;\nconst CALC_SETTINGS_KEY = 'calc_appearance';\n\nexport default function Calculator() {\n const [display, setDisplay] = useState('0');\n const [prev, setPrev] = useState<number | null>(null);\n const [op, setOp] = useState<Op>(null);\n const [resetNext, setResetNext] = useState(false);\n const [lastExpr, setLastExpr] = useState('');\n const [history, setHistory] = useState<string[]>([]);\n const [copied, setCopied] = useState(false);\n const [appearance, setAppearance] = useState(() => loadAppearance(CALC_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 append = useCallback((ch: string) => {\n setLastExpr('');\n setDisplay(d => {\n if (resetNext || d === '0') {\n setResetNext(false);\n return ch === '.' ? '0.' : ch;\n }\n if (ch === '.' && d.includes('.')) return d;\n return d + ch;\n });\n }, [resetNext]);\n\n const clear = useCallback(() => {\n setDisplay('0');\n setPrev(null);\n setOp(null);\n setResetNext(false);\n }, []);\n\n const compute = useCallback((a: number, b: number, operator: Op): number => {\n switch (operator) {\n case '+': return a + b;\n case '-': return a - b;\n case '×': return a * b;\n case '÷': return b === 0 ? 0 : a / b;\n default: return b;\n }\n }, []);\n\n const handleOp = useCallback((nextOp: Op) => {\n const current = parseFloat(display);\n if (prev !== null && op && !resetNext) {\n const result = compute(prev, current, op);\n setDisplay(String(result));\n setPrev(result);\n setHistory(h => [`${prev} ${op} ${current} = ${result}`, ...h].slice(0, 20));\n } else {\n setPrev(current);\n }\n setOp(nextOp);\n setResetNext(true);\n }, [display, prev, op, resetNext, compute]);\n\n const equals = useCallback(() => {\n if (prev === null || !op) return;\n const current = parseFloat(display);\n const result = compute(prev, current, op);\n const expr = `${prev} ${op} ${current} =`;\n setHistory(h => [`${expr} ${result}`, ...h].slice(0, 20));\n setLastExpr(expr);\n setDisplay(String(result));\n setPrev(null);\n setOp(null);\n setResetNext(true);\n }, [display, prev, op, compute]);\n\n const percent = useCallback(() => {\n setDisplay(d => String(parseFloat(d) / 100));\n }, []);\n\n const negate = useCallback(() => {\n setDisplay(d => d.startsWith('-') ? d.slice(1) : d === '0' ? d : '-' + d);\n }, []);\n\n // Keyboard support\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n const tag = (e.target as HTMLElement).tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return;\n if (e.key >= '0' && e.key <= '9') append(e.key);\n else if (e.key === '.') append('.');\n else if (e.key === '+') handleOp('+');\n else if (e.key === '-') handleOp('-');\n else if (e.key === '*') handleOp('×');\n else if (e.key === '/') { e.preventDefault(); handleOp('÷'); }\n else if (e.key === 'Enter' || e.key === '=') equals();\n else if (e.key === 'Escape') clear();\n else if (e.key === 'Backspace') setDisplay(d => d.length > 1 ? d.slice(0, -1) : '0');\n else if (e.key === '%') percent();\n };\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [append, handleOp, equals, clear, percent]);\n\n const btn = 'flex items-center justify-center rounded-lg text-sm font-medium transition-colors';\n const numBtn = `${btn} bg-white border border-gray-200 text-gray-900 hover:bg-gray-50 active:bg-gray-100`;\n const opBtn = `${btn} bg-blue-50 border border-blue-200 text-blue-700 hover:bg-blue-100 active:bg-blue-200`;\n const fnBtn = `${btn} bg-gray-100 border border-gray-200 text-gray-600 hover:bg-gray-200 active:bg-gray-300`;\n const eqBtn = `${btn} bg-blue-600 text-white hover:bg-blue-700 active:bg-blue-800`;\n\n // Format display for readability\n const formatDisplay = (val: string) => {\n const num = parseFloat(val);\n if (isNaN(num)) return val;\n if (val.endsWith('.') || val.endsWith('.0')) return val;\n if (Math.abs(num) < 1e15 && val.length < 16) return val;\n return num.toExponential(6);\n };\n\n return (\n <>\n <div className=\"flex flex-col h-full\" style={{\n opacity: appearance.activeOpacity / 100,\n backdropFilter: appearance.activeBlur > 0 ? `blur(${appearance.activeBlur}px)` : undefined,\n }}>\n {/* Display — 5-line area with history + current value */}\n <div className=\"bg-slate-200 rounded-t-lg px-4 py-2 group/display relative flex flex-col justify-end min-h-[120px] border-b border-slate-300\">\n {/* History lines (most recent at bottom, above current) */}\n <div className=\"flex flex-col justify-end flex-1 overflow-hidden\">\n {history.slice(0, 3).reverse().map((h, i) => (\n <div key={i} className=\"text-[11px] text-slate-400 text-right font-mono truncate\">{h}</div>\n ))}\n </div>\n {/* Current expression */}\n {(lastExpr || (op && prev !== null)) && (\n <div className=\"text-base text-slate-600 text-right font-mono\">\n {lastExpr || `${prev} ${op} ${!resetNext ? display : ''}`}\n </div>\n )}\n {/* Current value */}\n <div className=\"flex items-center gap-2\">\n <button onClick={() => { navigator.clipboard.writeText(display); setCopied(true); setTimeout(() => setCopied(false), 1200); }}\n title=\"Copy result\"\n className=\"shrink-0 text-slate-300 hover:text-slate-500 transition-colors opacity-0 group-hover/display:opacity-100\">\n {copied\n ? <svg className=\"h-5 w-5 text-green-500\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" /></svg>\n : <svg className=\"h-5 w-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" /></svg>\n }\n </button>\n <div className=\"text-right text-4xl font-mono font-bold text-slate-800 truncate flex-1\">\n {formatDisplay(display)}\n </div>\n </div>\n </div>\n\n {/* Buttons */}\n <div className=\"grid grid-cols-4 grid-rows-5 gap-1.5 flex-1 min-h-0 p-2\">\n <button onClick={clear} className={fnBtn}>AC</button>\n <button onClick={negate} className={fnBtn}>+/−</button>\n <button onClick={percent} className={fnBtn}>%</button>\n <button onClick={() => handleOp('÷')} className={`${opBtn} ${op === '÷' ? 'ring-2 ring-blue-400' : ''}`}>÷</button>\n\n <button onClick={() => append('7')} className={numBtn}>7</button>\n <button onClick={() => append('8')} className={numBtn}>8</button>\n <button onClick={() => append('9')} className={numBtn}>9</button>\n <button onClick={() => handleOp('×')} className={`${opBtn} ${op === '×' ? 'ring-2 ring-blue-400' : ''}`}>×</button>\n\n <button onClick={() => append('4')} className={numBtn}>4</button>\n <button onClick={() => append('5')} className={numBtn}>5</button>\n <button onClick={() => append('6')} className={numBtn}>6</button>\n <button onClick={() => handleOp('-')} className={`${opBtn} ${op === '-' ? 'ring-2 ring-blue-400' : ''}`}>−</button>\n\n <button onClick={() => append('1')} className={numBtn}>1</button>\n <button onClick={() => append('2')} className={numBtn}>2</button>\n <button onClick={() => append('3')} className={numBtn}>3</button>\n <button onClick={() => handleOp('+')} className={`${opBtn} ${op === '+' ? 'ring-2 ring-blue-400' : ''}`}>+</button>\n\n <button onClick={() => append('0')} className={`${numBtn} col-span-2`}>0</button>\n <button onClick={() => append('.')} className={numBtn}>.</button>\n <button onClick={equals} className={eqBtn}>=</button>\n </div>\n\n </div>\n <WidgetSettingsModal open={settingsOpen} onClose={() => setSettingsOpen(false)} title=\"Calculator Settings\"\n appearance={configAppearance} onAppearanceChange={setConfigAppearance}\n onSave={() => { setAppearance(configAppearance); localStorage.setItem(CALC_SETTINGS_KEY, JSON.stringify(configAppearance)); setSettingsOpen(false); }} />\n </>\n );\n}\n"]}
@@ -1,4 +0,0 @@
1
- export { ConfirmProvider, confirm, confirmDestructive, prompt, useConfirm } from './chunk-W622KQTD.js';
2
- import './chunk-72CQWN7O.js';
3
- //# sourceMappingURL=ConfirmDialog-LYSSZSUD.js.map
4
- //# sourceMappingURL=ConfirmDialog-LYSSZSUD.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"ConfirmDialog-LYSSZSUD.js"}
@@ -1,236 +0,0 @@
1
- import { loadAppearance, WidgetSettingsModal } from './chunk-R4OQIQYX.js';
2
- import { useWidgetSettings } from './chunk-Q3LT745N.js';
3
- import './chunk-GA35NEND.js';
4
- import './chunk-2TPTHAKI.js';
5
- import './chunk-RT6DSB5Y.js';
6
- import './chunk-QRL64J5F.js';
7
- import './chunk-W622KQTD.js';
8
- import './chunk-D276EMXS.js';
9
- import './chunk-72CQWN7O.js';
10
- import './chunk-IRWSRJ4K.js';
11
- import './chunk-IPXN646P.js';
12
- import { useState, useCallback, useEffect } from 'react';
13
- import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
14
-
15
- var ALL_CURRENCIES = ["USD", "CNY", "AUD", "GBP", "EUR", "JPY", "CAD", "THB", "NZD", "SGD", "HKD", "CHF", "KRW", "INR", "MXN", "BRL"];
16
- var MAX_PAIRS = 4;
17
- var DEFAULT_PAIRS = [
18
- ["USD", "CNY"],
19
- ["USD", "AUD"],
20
- ["GBP", "USD"],
21
- ["USD", "JPY"]
22
- ];
23
- var PAIRS_KEY = "currency_pairs";
24
- var SETTINGS_KEY = "currency_appearance";
25
- var CACHE_KEY = "currency_rates_cache";
26
- var CACHE_TTL = 36e5;
27
- function getCached(base) {
28
- try {
29
- const c = JSON.parse(localStorage.getItem(CACHE_KEY) || "{}");
30
- const e = c[base];
31
- if (e && Date.now() - e.timestamp < CACHE_TTL) return e.rates;
32
- } catch {
33
- }
34
- return null;
35
- }
36
- function setCache(base, rates) {
37
- try {
38
- const c = JSON.parse(localStorage.getItem(CACHE_KEY) || "{}");
39
- c[base] = { rates, timestamp: Date.now() };
40
- localStorage.setItem(CACHE_KEY, JSON.stringify(c));
41
- } catch {
42
- }
43
- }
44
- function loadPairs() {
45
- try {
46
- const s = JSON.parse(localStorage.getItem(PAIRS_KEY) || "");
47
- if (Array.isArray(s) && s.length) return s.slice(0, MAX_PAIRS);
48
- } catch {
49
- }
50
- return DEFAULT_PAIRS;
51
- }
52
- var FLAG = {
53
- USD: "\u{1F1FA}\u{1F1F8}",
54
- CNY: "\u{1F1E8}\u{1F1F3}",
55
- AUD: "\u{1F1E6}\u{1F1FA}",
56
- GBP: "\u{1F1EC}\u{1F1E7}",
57
- JPY: "\u{1F1EF}\u{1F1F5}",
58
- CAD: "\u{1F1E8}\u{1F1E6}",
59
- EUR: "\u{1F1EA}\u{1F1FA}",
60
- THB: "\u{1F1F9}\u{1F1ED}",
61
- NZD: "\u{1F1F3}\u{1F1FF}",
62
- SGD: "\u{1F1F8}\u{1F1EC}",
63
- HKD: "\u{1F1ED}\u{1F1F0}",
64
- CHF: "\u{1F1E8}\u{1F1ED}",
65
- KRW: "\u{1F1F0}\u{1F1F7}",
66
- INR: "\u{1F1EE}\u{1F1F3}",
67
- MXN: "\u{1F1F2}\u{1F1FD}",
68
- BRL: "\u{1F1E7}\u{1F1F7}"
69
- };
70
- function CurrencyConverter() {
71
- const [pairs, setPairs] = useState(loadPairs);
72
- const [appearance, setAppearance] = useState(() => loadAppearance(SETTINGS_KEY));
73
- const [allRates, setAllRates] = useState({});
74
- const [loading, setLoading] = useState(false);
75
- const [settingsOpen, setSettingsOpen] = useState(false);
76
- const [configPairs, setConfigPairs] = useState([]);
77
- const [configAppearance, setConfigAppearance] = useState(appearance);
78
- const [newFrom, setNewFrom] = useState("USD");
79
- const [newTo, setNewTo] = useState("CNY");
80
- useWidgetSettings(useCallback(() => {
81
- setConfigPairs([...pairs]);
82
- setConfigAppearance({ ...appearance });
83
- setSettingsOpen(true);
84
- }, [pairs, appearance]));
85
- useEffect(() => {
86
- const bases = [...new Set(pairs.map(([from]) => from))];
87
- let mounted = true;
88
- async function fetchAll() {
89
- setLoading(true);
90
- const result = {};
91
- for (const base of bases) {
92
- const cached = getCached(base);
93
- if (cached) {
94
- result[base] = cached;
95
- continue;
96
- }
97
- try {
98
- const res = await fetch(`https://open.er-api.com/v6/latest/${base}`);
99
- const data = await res.json();
100
- if (data.rates) {
101
- result[base] = data.rates;
102
- setCache(base, data.rates);
103
- }
104
- } catch {
105
- }
106
- }
107
- if (mounted) {
108
- setAllRates(result);
109
- setLoading(false);
110
- }
111
- }
112
- fetchAll();
113
- return () => {
114
- mounted = false;
115
- };
116
- }, [pairs]);
117
- const saveSettings = () => {
118
- if (configPairs.length === 0) return;
119
- const capped = configPairs.slice(0, MAX_PAIRS);
120
- setPairs(capped);
121
- setAppearance(configAppearance);
122
- localStorage.setItem(PAIRS_KEY, JSON.stringify(capped));
123
- localStorage.setItem(SETTINGS_KEY, JSON.stringify(configAppearance));
124
- setSettingsOpen(false);
125
- };
126
- return /* @__PURE__ */ jsxs(Fragment, { children: [
127
- /* @__PURE__ */ jsx(
128
- "div",
129
- {
130
- style: { backgroundColor: `rgb(var(--taskbar-bg-rgb, 243 244 246) / ${appearance.activeOpacity / 100})`, backdropFilter: appearance.activeBlur > 0 ? `blur(${appearance.activeBlur}px)` : void 0 },
131
- children: /* @__PURE__ */ jsxs("div", { className: "px-4 py-3 space-y-1", children: [
132
- loading && /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-400 text-center py-4", children: "Loading rates..." }),
133
- pairs.map(([from, to], idx) => {
134
- const rate = allRates[from]?.[to];
135
- return /* @__PURE__ */ jsxs(
136
- "button",
137
- {
138
- onClick: () => {
139
- const swapped = pairs.map((p, i) => i === idx ? [p[1], p[0]] : p);
140
- setPairs(swapped);
141
- localStorage.setItem(PAIRS_KEY, JSON.stringify(swapped));
142
- },
143
- className: "flex items-center justify-between px-2 py-2 border-b border-gray-200 last:border-0 w-full hover:bg-gray-100 rounded transition-colors cursor-pointer",
144
- children: [
145
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
146
- /* @__PURE__ */ jsx("span", { className: "text-base", children: FLAG[from] || "" }),
147
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-gray-700", children: from }),
148
- /* @__PURE__ */ jsx("svg", { className: "h-3 w-3 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4" }) }),
149
- /* @__PURE__ */ jsx("span", { className: "text-base", children: FLAG[to] || "" }),
150
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-gray-700", children: to })
151
- ] }),
152
- /* @__PURE__ */ jsx("div", { className: "text-base font-mono font-semibold text-gray-900 tabular-nums", children: rate != null ? rate.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 4 }) : "\u2014" })
153
- ]
154
- },
155
- `${from}-${to}-${idx}`
156
- );
157
- })
158
- ] })
159
- }
160
- ),
161
- /* @__PURE__ */ jsx(
162
- WidgetSettingsModal,
163
- {
164
- open: settingsOpen,
165
- onClose: () => setSettingsOpen(false),
166
- title: "Currency Settings",
167
- appearance: configAppearance,
168
- onAppearanceChange: setConfigAppearance,
169
- onSave: saveSettings,
170
- children: /* @__PURE__ */ jsxs("div", { children: [
171
- /* @__PURE__ */ jsxs("h3", { className: "text-sm font-semibold text-gray-700 mb-2", children: [
172
- "Currency Pairs ",
173
- /* @__PURE__ */ jsxs("span", { className: "text-[11px] font-normal text-gray-400", children: [
174
- "(",
175
- configPairs.length,
176
- "/",
177
- MAX_PAIRS,
178
- ")"
179
- ] })
180
- ] }),
181
- /* @__PURE__ */ jsx("div", { className: "space-y-1 mb-2", children: configPairs.map(([f, t], i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-1 px-2 bg-gray-50 rounded", children: [
182
- /* @__PURE__ */ jsxs("span", { className: "text-sm", children: [
183
- FLAG[f] || "",
184
- " ",
185
- f,
186
- " \u2192 ",
187
- FLAG[t] || "",
188
- " ",
189
- t
190
- ] }),
191
- /* @__PURE__ */ jsx("button", { onClick: () => setConfigPairs((p) => p.filter((_, idx) => idx !== i)), className: "text-red-400 hover:text-red-600", children: "\xD7" })
192
- ] }, i)) }),
193
- configPairs.length < MAX_PAIRS ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
194
- /* @__PURE__ */ jsx(
195
- "select",
196
- {
197
- value: newFrom,
198
- onChange: (e) => setNewFrom(e.target.value),
199
- 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",
200
- children: ALL_CURRENCIES.map((c) => /* @__PURE__ */ jsx("option", { children: c }, c))
201
- }
202
- ),
203
- /* @__PURE__ */ jsx("span", { className: "text-gray-400", children: "\u2192" }),
204
- /* @__PURE__ */ jsx(
205
- "select",
206
- {
207
- value: newTo,
208
- onChange: (e) => setNewTo(e.target.value),
209
- 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",
210
- children: ALL_CURRENCIES.map((c) => /* @__PURE__ */ jsx("option", { children: c }, c))
211
- }
212
- ),
213
- /* @__PURE__ */ jsx(
214
- "button",
215
- {
216
- onClick: () => {
217
- if (newFrom !== newTo && configPairs.length < MAX_PAIRS) setConfigPairs((p) => [...p, [newFrom, newTo]]);
218
- },
219
- className: "text-sm font-medium text-blue-600 hover:text-blue-800 px-2",
220
- children: "+ Add"
221
- }
222
- )
223
- ] }) : /* @__PURE__ */ jsxs("p", { className: "text-[11px] text-gray-400 italic", children: [
224
- "Max ",
225
- MAX_PAIRS,
226
- " pairs \u2014 remove one to add another."
227
- ] })
228
- ] })
229
- }
230
- )
231
- ] });
232
- }
233
-
234
- export { CurrencyConverter as default };
235
- //# sourceMappingURL=CurrencyConverter-64MKXB3D.js.map
236
- //# sourceMappingURL=CurrencyConverter-64MKXB3D.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/apps/CurrencyConverter.tsx"],"names":[],"mappings":"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","file":"CurrencyConverter-64MKXB3D.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\n/** Cap the rate list at 4 — keeps the widget compact and avoids\n * overwhelming the user with currencies they don't actually track. */\nconst MAX_PAIRS = 4;\n\nconst DEFAULT_PAIRS: [string, string][] = [\n ['USD', 'CNY'], ['USD', 'AUD'], ['GBP', 'USD'], ['USD', 'JPY'],\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 {\n const s = JSON.parse(localStorage.getItem(PAIRS_KEY) || '');\n if (Array.isArray(s) && s.length) return s.slice(0, MAX_PAIRS);\n } catch {}\n 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 [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); setLoading(false); }\n }\n fetchAll();\n return () => { mounted = false; };\n }, [pairs]);\n\n const saveSettings = () => {\n if (configPairs.length === 0) return;\n const capped = configPairs.slice(0, MAX_PAIRS);\n setPairs(capped); setAppearance(configAppearance);\n localStorage.setItem(PAIRS_KEY, JSON.stringify(capped));\n localStorage.setItem(SETTINGS_KEY, JSON.stringify(configAppearance));\n setSettingsOpen(false);\n };\n\n return (\n <>\n {/* Theme-aware panel — pulls the same `--taskbar-bg-rgb` colour the\n * taskbar uses so the widget matches it across all themes\n * (gray-100-ish on light, Catppuccin mantle in dark). Tailwind\n * gray-* text/border classes auto-invert in dark via the existing\n * `[data-theme=\"dark\"]` overrides in styles.css.\n *\n * A plain naturally-flowing div — deliberately no `h-full`/`flex-1`, so\n * the window's `autoHeight` measurement hugs these rows instead of\n * reading the root as fill-height and pinning the window to its full\n * `dimensions` height (320×480) with empty space below the rows. */}\n <div\n style={{ backgroundColor: `rgb(var(--taskbar-bg-rgb, 243 244 246) / ${appearance.activeOpacity / 100})`, backdropFilter: appearance.activeBlur > 0 ? `blur(${appearance.activeBlur}px)` : undefined }}>\n <div className=\"px-4 py-3 space-y-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 px-2 py-2 border-b border-gray-200 last:border-0 w-full hover:bg-gray-100 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-sm font-semibold text-gray-700\">{from}</span>\n <svg className=\"h-3 w-3 text-gray-400\" 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-sm font-semibold text-gray-700\">{to}</span>\n </div>\n <div className=\"text-base font-mono font-semibold text-gray-900 tabular-nums\">\n {rate != null ? rate.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 4 }) : '—'}\n </div>\n </button>\n );\n })}\n </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 <span className=\"text-[11px] font-normal text-gray-400\">({configPairs.length}/{MAX_PAIRS})</span></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 {configPairs.length < MAX_PAIRS ? (\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 && configPairs.length < MAX_PAIRS) 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 ) : (\n <p className=\"text-[11px] text-gray-400 italic\">Max {MAX_PAIRS} pairs — remove one to add another.</p>\n )}\n </div>\n </WidgetSettingsModal>\n </>\n );\n}\n"]}