react-os-shell 0.7.2 → 0.7.4

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.
@@ -0,0 +1,234 @@
1
+ import { loadAppearance, WidgetSettingsModal } from './chunk-LWVRQWGV.js';
2
+ import { useWidgetSettings } from './chunk-3T6SQ4UO.js';
3
+ import './chunk-UBN4IUDE.js';
4
+ import './chunk-ZF6AYO4G.js';
5
+ import { useState, useCallback, useEffect } from 'react';
6
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
7
+
8
+ var MAX_SYMBOLS = 8;
9
+ var DEFAULT_SYMBOLS = ["AAPL", "MSFT", "GOOGL", "TSLA"];
10
+ var SYMBOLS_KEY = "stock_symbols";
11
+ var APIKEY_KEY = "stock_api_key";
12
+ var SETTINGS_KEY = "stock_appearance";
13
+ var CACHE_KEY = "stock_quotes_cache";
14
+ var CACHE_TTL = 6e4;
15
+ var REFRESH_MS = 6e4;
16
+ function readCache() {
17
+ try {
18
+ return JSON.parse(localStorage.getItem(CACHE_KEY) || "{}");
19
+ } catch {
20
+ return {};
21
+ }
22
+ }
23
+ function writeCache(c) {
24
+ try {
25
+ localStorage.setItem(CACHE_KEY, JSON.stringify(c));
26
+ } catch {
27
+ }
28
+ }
29
+ function loadSymbols() {
30
+ try {
31
+ const s = JSON.parse(localStorage.getItem(SYMBOLS_KEY) || "");
32
+ if (Array.isArray(s) && s.length) return s.slice(0, MAX_SYMBOLS);
33
+ } catch {
34
+ }
35
+ return DEFAULT_SYMBOLS;
36
+ }
37
+ var fmtPrice = (n) => `$${n.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
38
+ var fmtSigned = (n) => `${n >= 0 ? "+" : ""}${n.toFixed(2)}`;
39
+ function Stock() {
40
+ const [symbols, setSymbols] = useState(loadSymbols);
41
+ const [apiKey, setApiKey] = useState(() => {
42
+ try {
43
+ return localStorage.getItem(APIKEY_KEY) || "";
44
+ } catch {
45
+ return "";
46
+ }
47
+ });
48
+ const [appearance, setAppearance] = useState(() => loadAppearance(SETTINGS_KEY));
49
+ const [quotes, setQuotes] = useState({});
50
+ const [loading, setLoading] = useState(false);
51
+ const [tick, setTick] = useState(0);
52
+ const [settingsOpen, setSettingsOpen] = useState(false);
53
+ const [configSymbols, setConfigSymbols] = useState([]);
54
+ const [configApiKey, setConfigApiKey] = useState("");
55
+ const [configAppearance, setConfigAppearance] = useState(appearance);
56
+ const [newSymbol, setNewSymbol] = useState("");
57
+ const openSettings = useCallback(() => {
58
+ setConfigSymbols([...symbols]);
59
+ setConfigApiKey(apiKey);
60
+ setConfigAppearance({ ...appearance });
61
+ setNewSymbol("");
62
+ setSettingsOpen(true);
63
+ }, [symbols, apiKey, appearance]);
64
+ useWidgetSettings(openSettings);
65
+ useEffect(() => {
66
+ const t = setInterval(() => setTick((n) => n + 1), REFRESH_MS);
67
+ return () => clearInterval(t);
68
+ }, []);
69
+ useEffect(() => {
70
+ if (!apiKey || symbols.length === 0) {
71
+ setQuotes({});
72
+ return;
73
+ }
74
+ let mounted = true;
75
+ (async () => {
76
+ setLoading(true);
77
+ const cache = readCache();
78
+ const next = {};
79
+ await Promise.all(symbols.map(async (sym) => {
80
+ const hit = cache[sym];
81
+ if (hit && Date.now() - hit.ts < CACHE_TTL) {
82
+ next[sym] = hit.q;
83
+ return;
84
+ }
85
+ try {
86
+ const res = await fetch(`https://finnhub.io/api/v1/quote?symbol=${encodeURIComponent(sym)}&token=${encodeURIComponent(apiKey)}`);
87
+ const d = await res.json();
88
+ if (typeof d.c === "number" && d.c > 0) {
89
+ const q = { price: d.c, change: d.d ?? 0, changePct: d.dp ?? 0 };
90
+ next[sym] = q;
91
+ cache[sym] = { q, ts: Date.now() };
92
+ } else if (hit) {
93
+ next[sym] = hit.q;
94
+ }
95
+ } catch {
96
+ if (hit) next[sym] = hit.q;
97
+ }
98
+ }));
99
+ writeCache(cache);
100
+ if (mounted) {
101
+ setQuotes(next);
102
+ setLoading(false);
103
+ }
104
+ })();
105
+ return () => {
106
+ mounted = false;
107
+ };
108
+ }, [symbols.join(","), apiKey, tick]);
109
+ const addSymbol = () => {
110
+ const s = newSymbol.trim().toUpperCase();
111
+ if (!s || configSymbols.includes(s) || configSymbols.length >= MAX_SYMBOLS) return;
112
+ setConfigSymbols((p) => [...p, s]);
113
+ setNewSymbol("");
114
+ };
115
+ const saveSettings = () => {
116
+ const cleaned = configSymbols.map((s) => s.toUpperCase()).slice(0, MAX_SYMBOLS);
117
+ const key = configApiKey.trim();
118
+ setSymbols(cleaned);
119
+ setApiKey(key);
120
+ setAppearance(configAppearance);
121
+ localStorage.setItem(SYMBOLS_KEY, JSON.stringify(cleaned));
122
+ localStorage.setItem(APIKEY_KEY, key);
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
+ className: "flex flex-col h-full",
131
+ style: { backgroundColor: `rgb(var(--taskbar-bg-rgb, 243 244 246) / ${appearance.activeOpacity / 100})`, backdropFilter: appearance.activeBlur > 0 ? `blur(${appearance.activeBlur}px)` : void 0 },
132
+ children: /* @__PURE__ */ jsx("div", { className: "px-4 py-3 flex-1", children: !apiKey ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center text-center gap-2 py-6", children: [
133
+ /* @__PURE__ */ jsx("svg", { className: "h-8 w-8 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M2.25 18L9 11.25l4.306 4.306a11.95 11.95 0 015.814-5.518l2.74-1.22m0 0l-5.94-2.281m5.94 2.28l-2.28 5.941" }) }),
134
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-gray-700", children: "Track live stock prices" }),
135
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 max-w-[15rem]", children: "Add a free API key to get started." }),
136
+ /* @__PURE__ */ jsx("button", { onClick: openSettings, className: "mt-1 text-xs font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-lg px-3 py-1.5 transition-colors", children: "Set up" })
137
+ ] }) : symbols.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500 text-center py-6", children: "No symbols yet \u2014 add some in settings." }) : /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
138
+ loading && Object.keys(quotes).length === 0 && /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-400 text-center py-4", children: "Loading quotes\u2026" }),
139
+ symbols.map((sym) => {
140
+ const q = quotes[sym];
141
+ const up = (q?.change ?? 0) >= 0;
142
+ const color = !q ? "text-gray-400" : q.change > 0 ? "text-green-600" : q.change < 0 ? "text-red-600" : "text-gray-500";
143
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-2 py-2 border-b border-gray-200 last:border-0", children: [
144
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-gray-800 tracking-tight", children: sym }),
145
+ q ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-end leading-tight", children: [
146
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-mono font-semibold text-gray-900 tabular-nums", children: fmtPrice(q.price) }),
147
+ /* @__PURE__ */ jsxs("span", { className: `text-[11px] font-medium tabular-nums ${color}`, children: [
148
+ up ? "\u25B2" : "\u25BC",
149
+ " ",
150
+ fmtSigned(q.change),
151
+ " (",
152
+ fmtSigned(q.changePct),
153
+ "%)"
154
+ ] })
155
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-sm font-mono text-gray-400 tabular-nums", children: "\u2014" })
156
+ ] }, sym);
157
+ })
158
+ ] }) })
159
+ }
160
+ ),
161
+ /* @__PURE__ */ jsxs(
162
+ WidgetSettingsModal,
163
+ {
164
+ open: settingsOpen,
165
+ onClose: () => setSettingsOpen(false),
166
+ title: "Stock Settings",
167
+ appearance: configAppearance,
168
+ onAppearanceChange: setConfigAppearance,
169
+ onSave: saveSettings,
170
+ children: [
171
+ /* @__PURE__ */ jsxs("div", { children: [
172
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-700 mb-2", children: "API Key" }),
173
+ /* @__PURE__ */ jsx(
174
+ "input",
175
+ {
176
+ value: configApiKey,
177
+ onChange: (e) => setConfigApiKey(e.target.value),
178
+ placeholder: "Finnhub API key",
179
+ className: "w-full bg-gray-50 border border-gray-200 rounded px-2 py-1.5 text-sm font-mono focus:outline-none focus:ring-1 focus:ring-blue-500"
180
+ }
181
+ ),
182
+ /* @__PURE__ */ jsxs("p", { className: "text-[11px] text-gray-400 mt-1", children: [
183
+ "Free key from ",
184
+ /* @__PURE__ */ jsx("a", { href: "https://finnhub.io/register", target: "_blank", rel: "noreferrer", className: "text-blue-600 hover:underline", children: "finnhub.io" }),
185
+ " \u2014 quotes update every minute."
186
+ ] })
187
+ ] }),
188
+ /* @__PURE__ */ jsxs("div", { children: [
189
+ /* @__PURE__ */ jsxs("h3", { className: "text-sm font-semibold text-gray-700 mb-2", children: [
190
+ "Symbols ",
191
+ /* @__PURE__ */ jsxs("span", { className: "text-[11px] font-normal text-gray-400", children: [
192
+ "(",
193
+ configSymbols.length,
194
+ "/",
195
+ MAX_SYMBOLS,
196
+ ")"
197
+ ] })
198
+ ] }),
199
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1 mb-2", children: [
200
+ configSymbols.map((s, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-1 px-2 bg-gray-50 rounded", children: [
201
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-gray-700", children: s }),
202
+ /* @__PURE__ */ jsx("button", { onClick: () => setConfigSymbols((p) => p.filter((_, idx) => idx !== i)), className: "text-red-400 hover:text-red-600", children: "\xD7" })
203
+ ] }, i)),
204
+ configSymbols.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-gray-400 italic", children: "No symbols \u2014 add a ticker below." })
205
+ ] }),
206
+ configSymbols.length < MAX_SYMBOLS ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
207
+ /* @__PURE__ */ jsx(
208
+ "input",
209
+ {
210
+ value: newSymbol,
211
+ onChange: (e) => setNewSymbol(e.target.value),
212
+ onKeyDown: (e) => {
213
+ if (e.key === "Enter") addSymbol();
214
+ },
215
+ placeholder: "e.g. NVDA",
216
+ className: "flex-1 bg-gray-50 border border-gray-200 rounded px-2 py-1 text-sm uppercase focus:outline-none focus:ring-1 focus:ring-blue-500"
217
+ }
218
+ ),
219
+ /* @__PURE__ */ jsx("button", { onClick: addSymbol, className: "text-sm font-medium text-blue-600 hover:text-blue-800 px-2", children: "+ Add" })
220
+ ] }) : /* @__PURE__ */ jsxs("p", { className: "text-[11px] text-gray-400 italic", children: [
221
+ "Max ",
222
+ MAX_SYMBOLS,
223
+ " symbols \u2014 remove one to add another."
224
+ ] })
225
+ ] })
226
+ ]
227
+ }
228
+ )
229
+ ] });
230
+ }
231
+
232
+ export { Stock as default };
233
+ //# sourceMappingURL=Stock-ZXZOCSJD.js.map
234
+ //# sourceMappingURL=Stock-ZXZOCSJD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/apps/Stock.tsx"],"names":[],"mappings":"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","file":"Stock-ZXZOCSJD.js","sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport { useWidgetSettings } from '../shell/Modal';\nimport WidgetSettingsModal, { loadAppearance, type WidgetAppearance } from '../shell/WidgetSettingsModal';\n\n/**\n * Stock ticker widget — track a watchlist of equities with live prices.\n *\n * Quotes come from Finnhub's keyless-from-the-browser /quote endpoint, which\n * needs a (free) API key the user pastes in settings — there's no reliable\n * keyless + CORS stock feed, so \"setup\" means entering a key + picking\n * symbols. Until a key is set the widget shows a friendly call-to-action.\n */\n\n/** Cap the watchlist — keeps the widget compact and stays well within\n * Finnhub's free tier (one /quote call per symbol, polled each minute). */\nconst MAX_SYMBOLS = 8;\nconst DEFAULT_SYMBOLS = ['AAPL', 'MSFT', 'GOOGL', 'TSLA'];\n\nconst SYMBOLS_KEY = 'stock_symbols';\nconst APIKEY_KEY = 'stock_api_key';\nconst SETTINGS_KEY = 'stock_appearance';\nconst CACHE_KEY = 'stock_quotes_cache';\nconst CACHE_TTL = 60_000; // 1 min — fresh enough for a desktop ticker\nconst REFRESH_MS = 60_000;\n\ninterface Quote { price: number; change: number; changePct: number }\ntype CacheEntry = { q: Quote; ts: number };\ntype Cache = Record<string, CacheEntry>;\n\nfunction readCache(): Cache { try { return JSON.parse(localStorage.getItem(CACHE_KEY) || '{}'); } catch { return {}; } }\nfunction writeCache(c: Cache) { try { localStorage.setItem(CACHE_KEY, JSON.stringify(c)); } catch {} }\n\nfunction loadSymbols(): string[] {\n try { const s = JSON.parse(localStorage.getItem(SYMBOLS_KEY) || ''); if (Array.isArray(s) && s.length) return s.slice(0, MAX_SYMBOLS); } catch {}\n return DEFAULT_SYMBOLS;\n}\n\nconst fmtPrice = (n: number) => `$${n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;\nconst fmtSigned = (n: number) => `${n >= 0 ? '+' : ''}${n.toFixed(2)}`;\n\nexport default function Stock() {\n const [symbols, setSymbols] = useState(loadSymbols);\n const [apiKey, setApiKey] = useState(() => { try { return localStorage.getItem(APIKEY_KEY) || ''; } catch { return ''; } });\n const [appearance, setAppearance] = useState(() => loadAppearance(SETTINGS_KEY));\n const [quotes, setQuotes] = useState<Record<string, Quote>>({});\n const [loading, setLoading] = useState(false);\n const [tick, setTick] = useState(0);\n\n const [settingsOpen, setSettingsOpen] = useState(false);\n const [configSymbols, setConfigSymbols] = useState<string[]>([]);\n const [configApiKey, setConfigApiKey] = useState('');\n const [configAppearance, setConfigAppearance] = useState<WidgetAppearance>(appearance);\n const [newSymbol, setNewSymbol] = useState('');\n\n const openSettings = useCallback(() => {\n setConfigSymbols([...symbols]);\n setConfigApiKey(apiKey);\n setConfigAppearance({ ...appearance });\n setNewSymbol('');\n setSettingsOpen(true);\n }, [symbols, apiKey, appearance]);\n\n useWidgetSettings(openSettings);\n\n // Poll on a timer so prices stay current while the widget sits on the desktop.\n useEffect(() => {\n const t = setInterval(() => setTick(n => n + 1), REFRESH_MS);\n return () => clearInterval(t);\n }, []);\n\n useEffect(() => {\n if (!apiKey || symbols.length === 0) { setQuotes({}); return; }\n let mounted = true;\n (async () => {\n setLoading(true);\n const cache = readCache();\n const next: Record<string, Quote> = {};\n await Promise.all(symbols.map(async sym => {\n const hit = cache[sym];\n if (hit && Date.now() - hit.ts < CACHE_TTL) { next[sym] = hit.q; return; }\n try {\n const res = await fetch(`https://finnhub.io/api/v1/quote?symbol=${encodeURIComponent(sym)}&token=${encodeURIComponent(apiKey)}`);\n const d = await res.json();\n if (typeof d.c === 'number' && d.c > 0) {\n const q: Quote = { price: d.c, change: d.d ?? 0, changePct: d.dp ?? 0 };\n next[sym] = q; cache[sym] = { q, ts: Date.now() };\n } else if (hit) { next[sym] = hit.q; } // unknown symbol / rate-limited → keep last good\n } catch { if (hit) next[sym] = hit.q; }\n }));\n writeCache(cache);\n if (mounted) { setQuotes(next); setLoading(false); }\n })();\n return () => { mounted = false; };\n }, [symbols.join(','), apiKey, tick]);\n\n const addSymbol = () => {\n const s = newSymbol.trim().toUpperCase();\n if (!s || configSymbols.includes(s) || configSymbols.length >= MAX_SYMBOLS) return;\n setConfigSymbols(p => [...p, s]);\n setNewSymbol('');\n };\n\n const saveSettings = () => {\n const cleaned = configSymbols.map(s => s.toUpperCase()).slice(0, MAX_SYMBOLS);\n const key = configApiKey.trim();\n setSymbols(cleaned); setApiKey(key); setAppearance(configAppearance);\n localStorage.setItem(SYMBOLS_KEY, JSON.stringify(cleaned));\n localStorage.setItem(APIKEY_KEY, key);\n localStorage.setItem(SETTINGS_KEY, JSON.stringify(configAppearance));\n setSettingsOpen(false);\n };\n\n return (\n <>\n {/* Theme-aware panel — mirrors the taskbar's `--taskbar-bg-rgb` so the\n * widget matches it across themes; gray-* classes auto-invert in dark. */}\n <div className=\"flex flex-col h-full\"\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 flex-1\">\n {!apiKey ? (\n <div className=\"flex flex-col items-center justify-center text-center gap-2 py-6\">\n <svg className=\"h-8 w-8 text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.25 18L9 11.25l4.306 4.306a11.95 11.95 0 015.814-5.518l2.74-1.22m0 0l-5.94-2.281m5.94 2.28l-2.28 5.941\" /></svg>\n <p className=\"text-sm font-semibold text-gray-700\">Track live stock prices</p>\n <p className=\"text-xs text-gray-500 max-w-[15rem]\">Add a free API key to get started.</p>\n <button onClick={openSettings} className=\"mt-1 text-xs font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-lg px-3 py-1.5 transition-colors\">Set up</button>\n </div>\n ) : symbols.length === 0 ? (\n <div className=\"text-xs text-gray-500 text-center py-6\">No symbols yet — add some in settings.</div>\n ) : (\n <div className=\"space-y-0.5\">\n {loading && Object.keys(quotes).length === 0 && <div className=\"text-xs text-gray-400 text-center py-4\">Loading quotes…</div>}\n {symbols.map(sym => {\n const q = quotes[sym];\n const up = (q?.change ?? 0) >= 0;\n const color = !q ? 'text-gray-400' : q.change > 0 ? 'text-green-600' : q.change < 0 ? 'text-red-600' : 'text-gray-500';\n return (\n <div key={sym} className=\"flex items-center justify-between px-2 py-2 border-b border-gray-200 last:border-0\">\n <span className=\"text-sm font-bold text-gray-800 tracking-tight\">{sym}</span>\n {q ? (\n <div className=\"flex flex-col items-end leading-tight\">\n <span className=\"text-sm font-mono font-semibold text-gray-900 tabular-nums\">{fmtPrice(q.price)}</span>\n <span className={`text-[11px] font-medium tabular-nums ${color}`}>{up ? '▲' : '▼'} {fmtSigned(q.change)} ({fmtSigned(q.changePct)}%)</span>\n </div>\n ) : (\n <span className=\"text-sm font-mono text-gray-400 tabular-nums\">—</span>\n )}\n </div>\n );\n })}\n </div>\n )}\n </div>\n </div>\n\n <WidgetSettingsModal open={settingsOpen} onClose={() => setSettingsOpen(false)} title=\"Stock Settings\"\n appearance={configAppearance} onAppearanceChange={setConfigAppearance} onSave={saveSettings}>\n <div>\n <h3 className=\"text-sm font-semibold text-gray-700 mb-2\">API Key</h3>\n <input value={configApiKey} onChange={e => setConfigApiKey(e.target.value)} placeholder=\"Finnhub API key\"\n className=\"w-full bg-gray-50 border border-gray-200 rounded px-2 py-1.5 text-sm font-mono focus:outline-none focus:ring-1 focus:ring-blue-500\" />\n <p className=\"text-[11px] text-gray-400 mt-1\">Free key from <a href=\"https://finnhub.io/register\" target=\"_blank\" rel=\"noreferrer\" className=\"text-blue-600 hover:underline\">finnhub.io</a> — quotes update every minute.</p>\n </div>\n <div>\n <h3 className=\"text-sm font-semibold text-gray-700 mb-2\">Symbols <span className=\"text-[11px] font-normal text-gray-400\">({configSymbols.length}/{MAX_SYMBOLS})</span></h3>\n <div className=\"space-y-1 mb-2\">\n {configSymbols.map((s, i) => (\n <div key={i} className=\"flex items-center justify-between py-1 px-2 bg-gray-50 rounded\">\n <span className=\"text-sm font-semibold text-gray-700\">{s}</span>\n <button onClick={() => setConfigSymbols(p => p.filter((_, idx) => idx !== i))} className=\"text-red-400 hover:text-red-600\">&times;</button>\n </div>\n ))}\n {configSymbols.length === 0 && <p className=\"text-[11px] text-gray-400 italic\">No symbols — add a ticker below.</p>}\n </div>\n {configSymbols.length < MAX_SYMBOLS ? (\n <div className=\"flex items-center gap-2\">\n <input value={newSymbol} onChange={e => setNewSymbol(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') addSymbol(); }}\n placeholder=\"e.g. NVDA\" className=\"flex-1 bg-gray-50 border border-gray-200 rounded px-2 py-1 text-sm uppercase focus:outline-none focus:ring-1 focus:ring-blue-500\" />\n <button onClick={addSymbol} 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_SYMBOLS} symbols — remove one to add another.</p>\n )}\n </div>\n </WidgetSettingsModal>\n </>\n );\n}\n"]}
@@ -63,6 +63,8 @@ declare function Chess$1(): react_jsx_runtime.JSX.Element;
63
63
 
64
64
  declare function TodoList$1(): react_jsx_runtime.JSX.Element;
65
65
 
66
+ declare function Stock$1(): react_jsx_runtime.JSX.Element;
67
+
66
68
  /**
67
69
  * World Clock widget — multi-city list. Each row pairs a tiny analogue
68
70
  * clock (minimal-style: ring, four cardinal dots, two hands) with the
@@ -109,6 +111,7 @@ declare const CurrencyConverter: react.LazyExoticComponent<typeof CurrencyConver
109
111
  declare const PomodoroTimer: react.LazyExoticComponent<typeof PomodoroTimer$1>;
110
112
  declare const Notepad: react.LazyExoticComponent<typeof Notepad$1>;
111
113
  declare const WorldClock: react.LazyExoticComponent<typeof WorldClock$1>;
114
+ declare const Stock: react.LazyExoticComponent<typeof Stock$1>;
112
115
  declare const TodoList: react.LazyExoticComponent<typeof TodoList$1>;
113
116
  declare const Chess: react.LazyExoticComponent<typeof Chess$1>;
114
117
  declare const Checkers: react.LazyExoticComponent<typeof Checkers$1>;
@@ -129,4 +132,4 @@ declare const documentApps: WindowRegistry;
129
132
  declare const webApps: WindowRegistry;
130
133
  declare const bundledApps: WindowRegistry;
131
134
 
132
- export { Browser, Calculator, Calendar, Checkers, Chess, CurrencyConverter, Documents, Email, Files, Game2048, Minesweeper, Notepad, type PdfPreviewData, type PdfPreviewHandle, PomodoroTimer, Preview, Spreadsheet, type SpreadsheetPreviewData, type SpreadsheetPreviewHandle, Sudoku, Tetris, TodoList, Weather, WorldClock, bundledApps, documentApps, gameApps, mailApps, openFilesInTrashMode, setPdfPreview, setSpreadsheetPreview, utilityApps, webApps };
135
+ export { Browser, Calculator, Calendar, Checkers, Chess, CurrencyConverter, Documents, Email, Files, Game2048, Minesweeper, Notepad, type PdfPreviewData, type PdfPreviewHandle, PomodoroTimer, Preview, Spreadsheet, type SpreadsheetPreviewData, type SpreadsheetPreviewHandle, Stock, Sudoku, Tetris, TodoList, Weather, WorldClock, bundledApps, documentApps, gameApps, mailApps, openFilesInTrashMode, setPdfPreview, setSpreadsheetPreview, utilityApps, webApps };
@@ -13,9 +13,10 @@ var Calculator = lazy(() => import('../Calculator-37EIFRDU.js'));
13
13
  var Spreadsheet = lazy(() => import('../Spreadsheet-UZMNMLZH.js'));
14
14
  var Weather = lazy(() => import('../Weather-R6ULA547.js'));
15
15
  var CurrencyConverter = lazy(() => import('../CurrencyConverter-PWX3FKRK.js'));
16
- var PomodoroTimer = lazy(() => import('../PomodoroTimer-VEYXRZWZ.js'));
16
+ var PomodoroTimer = lazy(() => import('../PomodoroTimer-YTV5Z6AC.js'));
17
17
  var Notepad = lazy(() => import('../Notepad-MXEQCIC7.js'));
18
18
  var WorldClock = lazy(() => import('../WorldClock-HHIBQXUR.js'));
19
+ var Stock = lazy(() => import('../Stock-ZXZOCSJD.js'));
19
20
  var TodoList = lazy(() => import('../TodoList-PI4SGVGI.js'));
20
21
  var Chess = lazy(() => import('../Chess-C5BY45NA.js'));
21
22
  var Checkers = lazy(() => import('../Checkers-MIAHIKJH.js'));
@@ -23,7 +24,7 @@ var Sudoku = lazy(() => import('../Sudoku-XHLYCEVT.js'));
23
24
  var Tetris = lazy(() => import('../Tetris-ZHCZYL24.js'));
24
25
  var Game2048 = lazy(() => import('../Game2048-3RH3ELRD.js'));
25
26
  var Minesweeper = lazy(() => import('../Minesweeper-N73MSPJV.js'));
26
- var Email = lazy(() => import('../Email-GTGL7CW5.js'));
27
+ var Email = lazy(() => import('../Email-ZUDCRZKB.js'));
27
28
  var Calendar = lazy(() => import('../Calendar-KCZQJ5CY.js'));
28
29
  var Preview = lazy(() => import('../Preview-VMKMY6SY.js'));
29
30
  var Documents = lazy(() => import('../Documents-W2DABIOW.js'));
@@ -37,6 +38,7 @@ var utilityApps = {
37
38
  "/currency": { component: CurrencyConverter, label: "Currency Converter", size: "sm", utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },
38
39
  "/pomodoro": { component: PomodoroTimer, label: "Pomodoro Timer", size: "sm", utility: true, widget: true, dimensions: [320, 600] },
39
40
  "/world-clock": { component: WorldClock, label: "World Clock", size: "sm", utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },
41
+ "/stock": { component: Stock, label: "Stocks", size: "sm", utility: true, widget: true, autoHeight: true, dimensions: [320, 360] },
40
42
  "/todo": { component: TodoList, label: "Todo List", size: "md", dimensions: [560, 640] }
41
43
  };
42
44
  var gameApps = {
@@ -67,6 +69,6 @@ var bundledApps = {
67
69
  ...webApps
68
70
  };
69
71
 
70
- export { Browser, Calculator, Calendar, Checkers, Chess, CurrencyConverter, Documents, Email, Files, Game2048, Minesweeper, Notepad, PomodoroTimer, Preview, Spreadsheet, Sudoku, Tetris, TodoList, Weather, WorldClock, bundledApps, documentApps, gameApps, mailApps, utilityApps, webApps };
72
+ export { Browser, Calculator, Calendar, Checkers, Chess, CurrencyConverter, Documents, Email, Files, Game2048, Minesweeper, Notepad, PomodoroTimer, Preview, Spreadsheet, Stock, Sudoku, Tetris, TodoList, Weather, WorldClock, bundledApps, documentApps, gameApps, mailApps, utilityApps, webApps };
71
73
  //# sourceMappingURL=index.js.map
72
74
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/apps/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Bundled apps — pre-built window registry entries for the 16 apps that ship\n * with `react-os-shell`. Consumers compose them into their own registry via\n * `createWindowRegistry`:\n *\n * import { createWindowRegistry } from 'react-os-shell';\n * import { bundledApps } from 'react-os-shell/apps';\n * import { erpEntities } from './shell-config';\n *\n * const windows = createWindowRegistry(bundledApps, erpEntities);\n *\n * Subsets are also exported (`utilityApps`, `gameApps`, `mailApps`) so a\n * consumer can pick-and-choose without importing every component.\n *\n * NOTE: 3 apps require consumer-supplied persistence (Calendar / Notepad for\n * stored content, Minesweeper for leaderboard). They're exported individually\n * but absent from `bundledApps` — wire the prefs provider to opt them in.\n * WorldClock uses `useShellPrefs()` so it lives in `bundledApps`; without a\n * consumer-supplied prefs adapter the city list won't survive a reload.\n */\nimport { lazy } from 'react';\nimport type { WindowRegistry } from '../windowRegistry/types';\n\n// ── Utility apps ──\nconst Calculator = lazy(() => import('./Calculator'));\nconst Spreadsheet = lazy(() => import('./Spreadsheet'));\nconst Weather = lazy(() => import('./Weather'));\nconst CurrencyConverter = lazy(() => import('./CurrencyConverter'));\nconst PomodoroTimer = lazy(() => import('./PomodoroTimer'));\nconst Notepad = lazy(() => import('./Notepad'));\nconst WorldClock = lazy(() => import('./WorldClock'));\nconst TodoList = lazy(() => import('./TodoList'));\n\n// ── Games ──\nconst Chess = lazy(() => import('./Chess'));\nconst Checkers = lazy(() => import('./Checkers'));\nconst Sudoku = lazy(() => import('./Sudoku'));\nconst Tetris = lazy(() => import('./Tetris'));\nconst Game2048 = lazy(() => import('./Game2048'));\nconst Minesweeper = lazy(() => import('./Minesweeper'));\n\n// ── Mail / Calendar (talk to the IMAP/SMTP/CalDAV bridge server) ──\nconst Email = lazy(() => import('./Email'));\nconst Calendar = lazy(() => import('./Calendar'));\n\n// ── Document apps ──\nconst Preview = lazy(() => import('./Preview'));\nconst Documents = lazy(() => import('./Documents'));\nconst Files = lazy(() => import('./Files'));\n\n// ── Web ──\nconst Browser = lazy(() => import('./Browser'));\n\nexport const utilityApps: WindowRegistry = {\n '/calculator': { component: Calculator, label: 'Calculator', size: 'sm', allowPinOnTop: true, utility: true, widget: true, dimensions: [280, 420] },\n '/spreadsheet': { component: Spreadsheet, label: 'Spreadsheets', size: '2xl', appStyle: true, multiInstance: true },\n '/notepad': { component: Notepad, label: 'Notepad', size: 'lg', allowPinOnTop: true },\n '/weather': { component: Weather, label: 'Weather', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 400] },\n '/currency': { component: CurrencyConverter, label: 'Currency Converter', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },\n '/pomodoro': { component: PomodoroTimer, label: 'Pomodoro Timer', size: 'sm', utility: true, widget: true, dimensions: [320, 600] },\n '/world-clock': { component: WorldClock, label: 'World Clock', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },\n '/todo': { component: TodoList, label: 'Todo List', size: 'md', dimensions: [560, 640] },\n};\n\nexport const gameApps: WindowRegistry = {\n '/chess': { component: Chess, label: 'Chess', size: 'lg', compact: true },\n '/checkers': { component: Checkers, label: 'Checkers', size: 'lg', compact: true },\n '/sudoku': { component: Sudoku, label: 'Sudoku', size: 'sm', compact: true, dimensions: [360, 535] },\n '/tetris': { component: Tetris, label: 'Tetris', size: 'md', compact: true, dimensions: [452, 618] },\n '/2048': { component: Game2048, label: '2048', size: 'sm', compact: true },\n '/minesweeper': { component: Minesweeper, label: 'Minesweeper', size: 'sm', compact: true },\n};\n\nexport const mailApps: WindowRegistry = {\n '/email': { component: Email, label: 'Email', size: '2xl', appStyle: true },\n '/calendar': { component: Calendar, label: 'Calendar', size: 'xl' },\n};\n\nexport const documentApps: WindowRegistry = {\n '/preview': { component: Preview, label: 'Preview', size: '2xl', appStyle: true, multiInstance: true },\n '/documents': { component: Documents, label: 'Documents', size: 'xl', appStyle: true, multiInstance: true },\n '/files': { component: Files, label: 'Files', size: 'xl', appStyle: true },\n};\n\nexport const webApps: WindowRegistry = {\n '/browser': { component: Browser, label: 'Browser', size: '2xl', appStyle: true, multiInstance: true },\n};\n\nexport const bundledApps: WindowRegistry = {\n ...utilityApps,\n ...gameApps,\n ...mailApps,\n ...documentApps,\n ...webApps,\n};\n\nexport {\n Calculator,\n Spreadsheet,\n Notepad,\n Weather,\n CurrencyConverter,\n PomodoroTimer,\n WorldClock,\n TodoList,\n Chess,\n Checkers,\n Sudoku,\n Tetris,\n Game2048,\n Minesweeper,\n Email,\n Calendar,\n Preview,\n Documents,\n Files,\n Browser,\n};\n\nexport { setPdfPreview } from './Preview';\nexport { setSpreadsheetPreview } from './Spreadsheet';\nexport { openFilesInTrashMode } from './Files';\nexport type { PdfPreviewData, PdfPreviewHandle } from './Preview';\nexport type { SpreadsheetPreviewData, SpreadsheetPreviewHandle } from './Spreadsheet';\n"]}
1
+ {"version":3,"sources":["../../src/apps/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Bundled apps — pre-built window registry entries for the 16 apps that ship\n * with `react-os-shell`. Consumers compose them into their own registry via\n * `createWindowRegistry`:\n *\n * import { createWindowRegistry } from 'react-os-shell';\n * import { bundledApps } from 'react-os-shell/apps';\n * import { erpEntities } from './shell-config';\n *\n * const windows = createWindowRegistry(bundledApps, erpEntities);\n *\n * Subsets are also exported (`utilityApps`, `gameApps`, `mailApps`) so a\n * consumer can pick-and-choose without importing every component.\n *\n * NOTE: 3 apps require consumer-supplied persistence (Calendar / Notepad for\n * stored content, Minesweeper for leaderboard). They're exported individually\n * but absent from `bundledApps` — wire the prefs provider to opt them in.\n * WorldClock uses `useShellPrefs()` so it lives in `bundledApps`; without a\n * consumer-supplied prefs adapter the city list won't survive a reload.\n */\nimport { lazy } from 'react';\nimport type { WindowRegistry } from '../windowRegistry/types';\n\n// ── Utility apps ──\nconst Calculator = lazy(() => import('./Calculator'));\nconst Spreadsheet = lazy(() => import('./Spreadsheet'));\nconst Weather = lazy(() => import('./Weather'));\nconst CurrencyConverter = lazy(() => import('./CurrencyConverter'));\nconst PomodoroTimer = lazy(() => import('./PomodoroTimer'));\nconst Notepad = lazy(() => import('./Notepad'));\nconst WorldClock = lazy(() => import('./WorldClock'));\nconst Stock = lazy(() => import('./Stock'));\nconst TodoList = lazy(() => import('./TodoList'));\n\n// ── Games ──\nconst Chess = lazy(() => import('./Chess'));\nconst Checkers = lazy(() => import('./Checkers'));\nconst Sudoku = lazy(() => import('./Sudoku'));\nconst Tetris = lazy(() => import('./Tetris'));\nconst Game2048 = lazy(() => import('./Game2048'));\nconst Minesweeper = lazy(() => import('./Minesweeper'));\n\n// ── Mail / Calendar (talk to the IMAP/SMTP/CalDAV bridge server) ──\nconst Email = lazy(() => import('./Email'));\nconst Calendar = lazy(() => import('./Calendar'));\n\n// ── Document apps ──\nconst Preview = lazy(() => import('./Preview'));\nconst Documents = lazy(() => import('./Documents'));\nconst Files = lazy(() => import('./Files'));\n\n// ── Web ──\nconst Browser = lazy(() => import('./Browser'));\n\nexport const utilityApps: WindowRegistry = {\n '/calculator': { component: Calculator, label: 'Calculator', size: 'sm', allowPinOnTop: true, utility: true, widget: true, dimensions: [280, 420] },\n '/spreadsheet': { component: Spreadsheet, label: 'Spreadsheets', size: '2xl', appStyle: true, multiInstance: true },\n '/notepad': { component: Notepad, label: 'Notepad', size: 'lg', allowPinOnTop: true },\n '/weather': { component: Weather, label: 'Weather', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 400] },\n '/currency': { component: CurrencyConverter, label: 'Currency Converter', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },\n '/pomodoro': { component: PomodoroTimer, label: 'Pomodoro Timer', size: 'sm', utility: true, widget: true, dimensions: [320, 600] },\n '/world-clock': { component: WorldClock, label: 'World Clock', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },\n '/stock': { component: Stock, label: 'Stocks', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 360] },\n '/todo': { component: TodoList, label: 'Todo List', size: 'md', dimensions: [560, 640] },\n};\n\nexport const gameApps: WindowRegistry = {\n '/chess': { component: Chess, label: 'Chess', size: 'lg', compact: true },\n '/checkers': { component: Checkers, label: 'Checkers', size: 'lg', compact: true },\n '/sudoku': { component: Sudoku, label: 'Sudoku', size: 'sm', compact: true, dimensions: [360, 535] },\n '/tetris': { component: Tetris, label: 'Tetris', size: 'md', compact: true, dimensions: [452, 618] },\n '/2048': { component: Game2048, label: '2048', size: 'sm', compact: true },\n '/minesweeper': { component: Minesweeper, label: 'Minesweeper', size: 'sm', compact: true },\n};\n\nexport const mailApps: WindowRegistry = {\n '/email': { component: Email, label: 'Email', size: '2xl', appStyle: true },\n '/calendar': { component: Calendar, label: 'Calendar', size: 'xl' },\n};\n\nexport const documentApps: WindowRegistry = {\n '/preview': { component: Preview, label: 'Preview', size: '2xl', appStyle: true, multiInstance: true },\n '/documents': { component: Documents, label: 'Documents', size: 'xl', appStyle: true, multiInstance: true },\n '/files': { component: Files, label: 'Files', size: 'xl', appStyle: true },\n};\n\nexport const webApps: WindowRegistry = {\n '/browser': { component: Browser, label: 'Browser', size: '2xl', appStyle: true, multiInstance: true },\n};\n\nexport const bundledApps: WindowRegistry = {\n ...utilityApps,\n ...gameApps,\n ...mailApps,\n ...documentApps,\n ...webApps,\n};\n\nexport {\n Calculator,\n Spreadsheet,\n Notepad,\n Weather,\n CurrencyConverter,\n PomodoroTimer,\n WorldClock,\n Stock,\n TodoList,\n Chess,\n Checkers,\n Sudoku,\n Tetris,\n Game2048,\n Minesweeper,\n Email,\n Calendar,\n Preview,\n Documents,\n Files,\n Browser,\n};\n\nexport { setPdfPreview } from './Preview';\nexport { setSpreadsheetPreview } from './Spreadsheet';\nexport { openFilesInTrashMode } from './Files';\nexport type { PdfPreviewData, PdfPreviewHandle } from './Preview';\nexport type { SpreadsheetPreviewData, SpreadsheetPreviewHandle } from './Spreadsheet';\n"]}
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { useEmailUnreadCount } from './chunk-PDFQNHW7.js';
2
- import { formatDate } from './chunk-NSU7OHPC.js';
3
- export { formatDate } from './chunk-NSU7OHPC.js';
4
2
  import { useMailAuth } from './chunk-VBFB3ZIN.js';
5
3
  export { setShellMailServer, useMailAuth } from './chunk-VBFB3ZIN.js';
4
+ import { formatDate } from './chunk-NSU7OHPC.js';
5
+ export { formatDate } from './chunk-NSU7OHPC.js';
6
6
  import { subscribePomo, getPomoSnapshot } from './chunk-MK3HLUO4.js';
7
7
  import { useShellPrefs } from './chunk-36VM54SC.js';
8
8
  export { ShellPrefsProvider, useLocalStoragePrefs, useShellPrefs } from './chunk-36VM54SC.js';
@@ -1402,7 +1402,7 @@ function WidgetManager({ open, onClose }) {
1402
1402
  }
1403
1403
 
1404
1404
  // src/version.ts
1405
- var VERSION = "0.7.2" ;
1405
+ var VERSION = "0.7.4" ;
1406
1406
  var APP_VERSION = VERSION;
1407
1407
 
1408
1408
  // src/changelog.ts
@@ -3523,6 +3523,7 @@ function StartMenu({
3523
3523
  const erpSections = navSections2.filter((item) => isSection(item) && erpLabels.has(item.label));
3524
3524
  const systemSections = navSections2.filter((item) => isSection(item) && systemLabels.has(item.label));
3525
3525
  const footerSections = navSections2.filter((item) => isSection(item) && footerLabels.has(item.label));
3526
+ const hasAppsGroup = topItems.length > 0 || systemSections.length > 0 || virtualSections.length > 0;
3526
3527
  const getVisibleItems = (section) => section.items.filter((item) => !item.perms || hasAnyPerm(item.perms));
3527
3528
  const matchTree = (it, sectionLabel) => {
3528
3529
  if (it.perms && !hasAnyPerm(it.perms)) return [];
@@ -3688,7 +3689,7 @@ function StartMenu({
3688
3689
  footerSections.map((s) => renderSection(s, false)),
3689
3690
  (footerSections.length > 0 || footerItems.length > 0) && /* @__PURE__ */ jsx("div", { className: "border-t border-white/20 my-1.5 mx-2" }),
3690
3691
  erpSections.map((s) => renderSection(s, true)),
3691
- /* @__PURE__ */ jsx("div", { className: "border-t border-white/20 my-1.5 mx-2" }),
3692
+ erpSections.length > 0 && hasAppsGroup && /* @__PURE__ */ jsx("div", { className: "border-t border-white/20 my-1.5 mx-2" }),
3692
3693
  topItems.map((item) => /* @__PURE__ */ jsxs("div", { children: [
3693
3694
  /* @__PURE__ */ jsxs(
3694
3695
  "button",
@@ -3723,7 +3724,7 @@ function StartMenu({
3723
3724
  ] }, item.to)),
3724
3725
  systemSections.map((s) => renderSection(s, false)),
3725
3726
  virtualSections.map((v) => renderVirtualSection(v)),
3726
- /* @__PURE__ */ jsx("div", { className: "border-t border-white/20 my-1.5 mx-2" }),
3727
+ hasAppsGroup && erpSections.length > 0 && /* @__PURE__ */ jsx("div", { className: "border-t border-white/20 my-1.5 mx-2" }),
3727
3728
  erpSections.map((s) => renderSection(s, true)),
3728
3729
  (footerSections.length > 0 || footerItems.length > 0) && /* @__PURE__ */ jsx("div", { className: "border-t border-white/20 my-1.5 mx-2" }),
3729
3730
  footerSections.map((s) => renderSection(s, false)),