react-os-shell 3.24.0 → 3.28.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.
- package/README.md +15 -1
- package/dist/{Browser-MU2LBUTA.js → Browser-AR4QP23G.js} +5 -6
- package/dist/Browser-AR4QP23G.js.map +1 -0
- package/dist/{Calculator-BFRUXV7E.js → Calculator-7MRLC77Q.js} +4 -5
- package/dist/Calculator-7MRLC77Q.js.map +1 -0
- package/dist/ConfirmDialog-2BV43KSW.js +4 -0
- package/dist/{ConfirmDialog-BEALMXZM.js.map → ConfirmDialog-2BV43KSW.js.map} +1 -1
- package/dist/{CurrencyConverter-543D5YHO.js → CurrencyConverter-6UTL2ZBY.js} +4 -5
- package/dist/CurrencyConverter-6UTL2ZBY.js.map +1 -0
- package/dist/{Documents-UGITESQI.js → Documents-FQKIQ4GH.js} +5 -6
- package/dist/Documents-FQKIQ4GH.js.map +1 -0
- package/dist/{Files-6E3RNGNQ.js → Files-NTUFLWY3.js} +5 -6
- package/dist/Files-NTUFLWY3.js.map +1 -0
- package/dist/{Notepad-LFLER4N2.js → Notepad-MQQSDSLT.js} +5 -6
- package/dist/Notepad-MQQSDSLT.js.map +1 -0
- package/dist/{PomodoroTimer-V4FCRP35.js → PomodoroTimer-YI4D7OLV.js} +5 -6
- package/dist/PomodoroTimer-YI4D7OLV.js.map +1 -0
- package/dist/{Preview-6SVV4EVG.js → Preview-2GUM6NO7.js} +5 -6
- package/dist/Preview-2GUM6NO7.js.map +1 -0
- package/dist/{Spreadsheet-OVFTWCJ6.js → Spreadsheet-6JWSE5NC.js} +5 -6
- package/dist/Spreadsheet-6JWSE5NC.js.map +1 -0
- package/dist/{Stock-UVBHR5NW.js → Stock-KQA6QWZ2.js} +4 -5
- package/dist/Stock-KQA6QWZ2.js.map +1 -0
- package/dist/{Weather-3GHOQR2B.js → Weather-45REOKUY.js} +4 -5
- package/dist/Weather-45REOKUY.js.map +1 -0
- package/dist/{WorldClock-B5ZW37KG.js → WorldClock-EJNEFDWZ.js} +4 -5
- package/dist/WorldClock-EJNEFDWZ.js.map +1 -0
- package/dist/apps/index.js +15 -16
- package/dist/apps/index.js.map +1 -1
- package/dist/chunk-CZW7CTI6.js +7 -0
- package/dist/{chunk-TGEZDU6N.js.map → chunk-CZW7CTI6.js.map} +1 -1
- package/dist/{chunk-JDGURXTZ.js → chunk-EWRKU7EF.js} +3 -3
- package/dist/{chunk-JDGURXTZ.js.map → chunk-EWRKU7EF.js.map} +1 -1
- package/dist/{chunk-L3RPWMS4.js → chunk-GHGD4GKR.js} +4 -4
- package/dist/{chunk-L3RPWMS4.js.map → chunk-GHGD4GKR.js.map} +1 -1
- package/dist/{chunk-2YTZ6COH.js → chunk-IU7MSBRI.js} +2964 -2589
- package/dist/chunk-IU7MSBRI.js.map +1 -0
- package/dist/{chunk-WNZH4GVY.js → chunk-WWT4XQJL.js} +3 -3
- package/dist/{chunk-WNZH4GVY.js.map → chunk-WWT4XQJL.js.map} +1 -1
- package/dist/index.d.ts +151 -5
- package/dist/index.js +711 -71
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
- package/dist/Browser-MU2LBUTA.js.map +0 -1
- package/dist/Calculator-BFRUXV7E.js.map +0 -1
- package/dist/ConfirmDialog-BEALMXZM.js +0 -3
- package/dist/CurrencyConverter-543D5YHO.js.map +0 -1
- package/dist/Documents-UGITESQI.js.map +0 -1
- package/dist/Files-6E3RNGNQ.js.map +0 -1
- package/dist/Notepad-LFLER4N2.js.map +0 -1
- package/dist/PomodoroTimer-V4FCRP35.js.map +0 -1
- package/dist/Preview-6SVV4EVG.js.map +0 -1
- package/dist/Spreadsheet-OVFTWCJ6.js.map +0 -1
- package/dist/Stock-UVBHR5NW.js.map +0 -1
- package/dist/Weather-3GHOQR2B.js.map +0 -1
- package/dist/WorldClock-B5ZW37KG.js.map +0 -1
- package/dist/chunk-2YTZ6COH.js.map +0 -1
- package/dist/chunk-TGEZDU6N.js +0 -7
- package/dist/chunk-UBN4IUDE.js +0 -229
- package/dist/chunk-UBN4IUDE.js.map +0 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ A backend-less playground hosted on GitHub Pages. Wallpapers, themes, sticky not
|
|
|
16
16
|
|
|
17
17
|
**Shell:** `<Layout>`, `<StartMenu>`, `<Desktop>` (with sticky notes + folders), `<WindowManager>`, `<Modal>` (standard / compact / widget styles), `<PopupMenu>`, `<ConfirmDialog>`, `<GlobalSearch>` (Cmd-K), `<ShortcutHelp>`, `<NotificationBell>`, `<StatusBadge>`, `<SearchableSelect>`, frosted-glass theming.
|
|
18
18
|
|
|
19
|
-
**UI primitives:** `<Button>`, `<Input>`, `<Textarea>`, `<Select>`, `<Checkbox>`, `<Radio>`, `<FormField>`, `<Label>`, `<Card>` / `<StatCard>`, `<Avatar>` / `<AvatarGroup>`, `<Banner>`, `<Tabs>`, `<Accordion>`, `<Tooltip>`, `<Pagination>`, and dependency-free `<Sparkline>` / `<BarChart>` / `<DonutChart>` charts.
|
|
19
|
+
**UI primitives:** `<Button>`, `<Input>`, `<Textarea>`, `<Select>`, `<Checkbox>`, `<Radio>`, `<FormField>`, `<Label>`, `<Card>` / `<StatCard>`, `<Avatar>` / `<AvatarGroup>`, `<Banner>`, `<Tabs>`, `<Accordion>`, `<Tooltip>`, `<Pagination>`, `<MetricBar>`, and dependency-free `<Sparkline>` / `<BarChart>` / `<DonutChart>` charts.
|
|
20
20
|
|
|
21
21
|
**Page templates:** ready-made screens composed from the primitives — `<DashboardTemplate>`, `<DataTablePage>`, `<FormLayoutPage>`, `<CheckoutTemplate>`, `<EmailTemplate>`, `<ChatTemplate>`, `<GalleryTemplate>`, `<AuthScreen>`, `<ErrorPage>`.
|
|
22
22
|
|
|
@@ -176,6 +176,8 @@ All exports are named — `import { Modal, ... } from 'react-os-shell'`.
|
|
|
176
176
|
| `BugReportDetail` | Used inside an entity-window registry entry; reads from `<BugReportConfigProvider>`. |
|
|
177
177
|
| `StatusBadge` | Coloured pill rendering a status string. Map status→semantic group via `<StatusBadgeProvider groups={{...}}>`. |
|
|
178
178
|
| `SidebarLayout` | Two-pane layout with a drag-to-resize sidebar (`storageKey` persists the width). Pair with a `flushBody` window so the sidebar runs edge-to-edge. |
|
|
179
|
+
| `SidebarNavItem`, `SidebarGroupLabel` | Filter-sidebar button (optional `count` badge and `severity` marker dot) plus its group heading. Roll the severity up in the app; omitting it renders exactly as before it existed. An unrecognised `severity` renders a visible "unknown" marker and logs — it never silently disappears. |
|
|
180
|
+
| `MetricBar` | Value + proportional bar with optional `warn` / `crit` threshold ticks — the CPU / memory / disk row. `value={null}` renders "no data" (dashed empty track), never a zero-width bar; with no thresholds the fill stays grey rather than claiming health. `max` must be a positive finite number — given `0`/`NaN` the row prints the value but draws no bar, rather than dividing by zero into a full one. |
|
|
179
181
|
| `Button`, `Input`, `Textarea`, `Select`, `Checkbox`, `Radio`, `FormField`, `Label` | Form controls — controlled (`value`/`onChange`); `Input`/`Textarea` forward native props for react-hook-form. |
|
|
180
182
|
| `Card`, `StatCard` | Surface panel (optional header/footer) + dashboard metric tile. |
|
|
181
183
|
| `Avatar`, `AvatarGroup` | User avatar with initials fallback + status dot; overlapping stack with +N overflow. |
|
|
@@ -232,6 +234,8 @@ All exports are named — `import { Modal, ... } from 'react-os-shell'`.
|
|
|
232
234
|
| `glassStyle()` | Returns the theme-aware frosted-glass `style` object. |
|
|
233
235
|
| `reportBug(submit)` | Captures a screenshot via `getDisplayMedia`, opens the dialog, hands the payload to your `submit`. |
|
|
234
236
|
| `formatDate(iso)` | Locale-aware date formatter. |
|
|
237
|
+
| `severityOf(value, warn?, crit?)` | The `SeverityTone` (`success` \| `warning` \| `danger`) a reading earns against **inclusive** bounds; `null` when there's no reading or no usable bounds — the shell hardcodes no threshold. Backs `MetricBar`; use it to roll a `SidebarNavItem severity` up. |
|
|
238
|
+
| `isSeverityTone(value)` | Type guard for the three tones. Validate a backend rollup with it at the fetch boundary, where a bad token can still be reported against its payload, rather than letting it surface as a wrong pixel. |
|
|
235
239
|
| `toast.success / .error / .info` | Toast notifications — auto-mounts container. |
|
|
236
240
|
| `Kbd` constants — `MOD`, `ALT`, `SHIFT`, `ENTER`, `ALT_SHIFT_E`, `CMD_K`, … | Symbol constants for rendering keyboard shortcuts. |
|
|
237
241
|
|
|
@@ -247,6 +251,16 @@ Most "desktop UI" demos on the web are toys with hardcoded windows and no escape
|
|
|
247
251
|
|
|
248
252
|
PRs welcome. Open an issue first for non-trivial changes so we can align on shape.
|
|
249
253
|
|
|
254
|
+
```bash
|
|
255
|
+
npm run typecheck # tsc --noEmit, then tsc -p tsconfig.test.json (src + tests)
|
|
256
|
+
npm test # specs in tests/, run by node's test runner
|
|
257
|
+
npm run build # tsup → dist/
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
`npm test` bundles `tests/*.test.tsx` with esbuild and runs them under `node --test`, rendering components with `react-dom/server`. No test framework is installed — the runner is `scripts/test.mjs`, ~60 lines. `esbuild` (the runner imports it) and `@types/node` (the specs import `node:test`) are declared devDependencies rather than borrowed from `tsup`'s transitive tree, so a change in its dependency layout cannot break the build job with a module-not-found.
|
|
261
|
+
|
|
262
|
+
Typecheck runs twice on purpose: `tsconfig.json` is the *build* config, so `rootDir: "./src"` fixes the shape of `dist/` and its `include` stops at `src/**`. `tsconfig.test.json` widens the scope to cover `tests/` as well — esbuild strips types without checking them, so without it a type error in a spec is invisible to CI.
|
|
263
|
+
|
|
250
264
|
## License
|
|
251
265
|
|
|
252
266
|
[MIT](./LICENSE)
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { peekBrowserStartUrl, claimBrowserStartUrl } from './chunk-BFBWLCO6.js';
|
|
2
|
-
import { AboutApp } from './chunk-
|
|
3
|
-
import './chunk-
|
|
4
|
-
import { WindowTitle } from './chunk-
|
|
5
|
-
import { confirm } from './chunk-UBN4IUDE.js';
|
|
2
|
+
import { AboutApp } from './chunk-GHGD4GKR.js';
|
|
3
|
+
import './chunk-CZW7CTI6.js';
|
|
4
|
+
import { WindowTitle, confirm } from './chunk-IU7MSBRI.js';
|
|
6
5
|
import './chunk-GW3RA6IS.js';
|
|
7
6
|
import { useRef, useEffect, useState } from 'react';
|
|
8
7
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
@@ -471,5 +470,5 @@ function BrowserBody({
|
|
|
471
470
|
}
|
|
472
471
|
|
|
473
472
|
export { Browser as default };
|
|
474
|
-
//# sourceMappingURL=Browser-
|
|
475
|
-
//# sourceMappingURL=Browser-
|
|
473
|
+
//# sourceMappingURL=Browser-AR4QP23G.js.map
|
|
474
|
+
//# sourceMappingURL=Browser-AR4QP23G.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/apps/Browser.tsx"],"names":[],"mappings":"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","file":"Browser-AR4QP23G.js","sourcesContent":["/**\n * Browser — minimal iframe-backed web browser app.\n *\n * URL bar with back / forward / refresh, navigable bookmark bar\n * (persisted to localStorage), and a graceful \"open in new tab\"\n * escape hatch since most major sites refuse iframe embedding via\n * X-Frame-Options or Content-Security-Policy.\n */\nimport { useEffect, useRef, useState } from 'react';\nimport { WindowTitle } from '../shell/Modal';\nimport { confirm } from '../shell/ConfirmDialog';\nimport AboutApp from './_about';\nimport { peekBrowserStartUrl, claimBrowserStartUrl, type PendingStartUrl } from './_browserStage';\n\ninterface Bookmark {\n label: string;\n url: string;\n}\n\nconst BOOKMARKS_KEY = 'react-os-shell:browser-bookmarks';\nconst HOMEPAGE_KEY = 'react-os-shell:browser-homepage';\nconst DEFAULT_HOMEPAGE = 'https://en.wikipedia.org/wiki/Main_Page';\n// Search provider (DuckDuckGo, no tracking). Hoisted to a constant so the\n// provider is stated in exactly one place — note it is deliberately NOT\n// framable, hence its presence in BLOCKED_HOSTS below.\nconst SEARCH_URL = 'https://duckduckgo.com/?q=';\nconst DEFAULT_BOOKMARKS: Bookmark[] = [\n { label: 'Wikipedia', url: 'https://en.wikipedia.org/wiki/Main_Page' },\n // DevDocs rather than MDN: MDN sends `x-frame-options: DENY`, so shipping it\n // as a default bookmark shipped a guaranteed-blank pane (BG#00374). DevDocs\n // carries the same API reference content and permits embedding.\n { label: 'DevDocs', url: 'https://devdocs.io' },\n { label: 'Example', url: 'https://example.com' },\n];\n\n// A dotted single token is ambiguous: `example.com` is a host, but `node.js`,\n// `web.config` and `array.map` are search queries the user expects to search.\n// The only offline signal is the last label, so we treat a bare token as a host\n// ONLY when it ends in a real TLD; everything else searches. A host on an\n// exotic TLD missing from this list is still reachable by typing the scheme\n// (`https://foo.zuerich`), which short-circuits before this check.\nconst KNOWN_TLDS = new Set([\n // ISO 3166-1 alpha-2 ccTLDs. Mind the lookalikes: `md`, `py`, `rs` and `sh`\n // ARE countries (`foo.sh` is a real host), while `js` and `ts` are not.\n 'ac ad ae af ag ai al am ao aq ar as at au aw ax az ba bb bd be bf bg bh bi',\n 'bj bm bn bo br bs bt bw by bz ca cc cd cf cg ch ci ck cl cm cn co cr cu cv',\n 'cw cx cy cz de dj dk dm do dz ec ee eg er es et eu fi fj fk fm fo fr ga gd',\n 'ge gf gg gh gi gl gm gn gp gq gr gs gt gu gw gy hk hm hn hr ht hu id ie il',\n 'im in io iq ir is it je jm jo jp ke kg kh ki km kn kp kr kw ky kz la lb lc',\n 'li lk lr ls lt lu lv ly ma mc md me mg mh mk ml mm mn mo mp mq mr ms mt mu',\n 'mv mw mx my mz na nc ne nf ng ni nl no np nr nu nz om pa pe pf pg ph pk pl',\n 'pm pn pr ps pt pw py qa re ro rs ru rw sa sb sc sd se sg sh si sk sl sm sn',\n 'so sr ss st su sv sx sy sz tc td tf tg th tj tk tl tm tn to tr tt tv tw tz',\n 'ua ug uk us uy uz va vc ve vg vi vn vu wf ws ye yt za zm zw',\n // Common gTLDs, plus the ones this business actually uses (`design`).\n 'com net org edu gov mil int info biz name pro app dev xyz online site tech',\n 'store shop cloud design digital agency studio media news blog live life',\n 'world today email systems solutions services software page link space host',\n 'press wiki team group works careers finance capital energy academy',\n].join(' ').split(' '));\n\n// `example.com`, `sub.example.co.uk`, `example.com/path` → host; `node.js` → search.\nfunction isProbableHost(s: string): boolean {\n const m = /^([\\w-]+\\.)+([a-z]{2,})(\\/.*)?$/i.exec(s);\n return m !== null && KNOWN_TLDS.has(m[2].toLowerCase());\n}\n\nfunction normalizeUrl(input: string): string {\n let s = input.trim();\n if (!s) return '';\n // Already a URL? Otherwise treat as a search query.\n if (/^[a-z][a-z0-9+.-]*:\\/\\//i.test(s)) return s;\n if (isProbableHost(s)) return 'https://' + s;\n return SEARCH_URL + encodeURIComponent(s);\n}\n\n// Sites known to refuse iframe embedding via X-Frame-Options or CSP. There's\n// no workaround inside an iframe — the browser blocks the load. We keep a\n// list so we can short-circuit to a friendly \"open in new tab\" panel\n// instead of letting the browser's blank \"refused to connect\" error\n// through. Subdomain match: `mail.google.com` matches `google.com`.\nconst BLOCKED_HOSTS = [\n // The two hosts this app itself routes to or ships as a default bookmark.\n // Their absence here was BG#00374: an address-bar search went to a blank\n // pane rather than the panel below, reading as \"search does nothing\".\n // Verified live 2026-07-16 — duckduckgo.com: `x-frame-options: SAMEORIGIN` +\n // `frame-ancestors 'self' https://html.duckduckgo.com` (the html/ and lite/\n // mirrors are no escape hatch: `frame-ancestors 'self'`);\n // developer.mozilla.org: `x-frame-options: DENY` (kept even though the\n // default bookmark moved to DevDocs — existing users have MDN persisted in\n // localStorage, and it stays a thing people type).\n 'duckduckgo.com', 'developer.mozilla.org',\n 'google.com', 'gmail.com', 'youtube.com',\n 'facebook.com', 'instagram.com', 'whatsapp.com',\n 'twitter.com', 'x.com',\n 'github.com', 'gitlab.com',\n 'linkedin.com', 'reddit.com', 'pinterest.com',\n 'amazon.com', 'amazon.ca', 'amazon.co.uk',\n 'apple.com', 'icloud.com',\n 'microsoft.com', 'outlook.com', 'live.com', 'office.com',\n 'netflix.com', 'spotify.com',\n 'paypal.com', 'stripe.com',\n 'chat.openai.com', 'chatgpt.com', 'claude.ai',\n];\n\nfunction hostIsBlocked(href: string): boolean {\n try {\n const host = new URL(href).hostname.toLowerCase();\n return BLOCKED_HOSTS.some(b => host === b || host.endsWith('.' + b));\n } catch { return false; }\n}\n\nfunction loadBookmarks(): Bookmark[] {\n if (typeof window === 'undefined') return DEFAULT_BOOKMARKS;\n try {\n const raw = localStorage.getItem(BOOKMARKS_KEY);\n if (!raw) return DEFAULT_BOOKMARKS;\n const parsed = JSON.parse(raw);\n if (Array.isArray(parsed) && parsed.every(b => typeof b?.url === 'string')) return parsed;\n } catch {}\n return DEFAULT_BOOKMARKS;\n}\n\n// The consumer-facing `setBrowserStartUrl` lives in ./_browserStage so that\n// hosts importing it don't pull this module into their startup bundle. This\n// component drains the stage via the @internal peek/claim pair.\n\nfunction loadHomepage(): string {\n if (typeof window === 'undefined') return DEFAULT_HOMEPAGE;\n return localStorage.getItem(HOMEPAGE_KEY) || DEFAULT_HOMEPAGE;\n}\n\nexport default function Browser() {\n // One-shot drain of a staged start URL. The render phase only PEEKS — under\n // React 18 concurrent rendering the first render pass of this lazy component\n // can be discarded and replayed, so a destructive read here would lose the\n // payload (see Spreadsheet/Preview). The stage is cleared in the mount\n // effect below.\n const consumedRef = useRef<PendingStartUrl | null | undefined>(undefined);\n if (consumedRef.current === undefined) {\n consumedRef.current = peekBrowserStartUrl();\n }\n useEffect(() => {\n if (consumedRef.current != null) {\n claimBrowserStartUrl(consumedRef.current);\n }\n }, []);\n const startUrl = consumedRef.current ? normalizeUrl(consumedRef.current.url) : '';\n\n const [homepage, setHomepage] = useState(loadHomepage);\n const [url, setUrl] = useState(startUrl || homepage);\n const [inputUrl, setInputUrl] = useState(url);\n const [history, setHistory] = useState<string[]>([url]);\n const [historyIdx, setHistoryIdx] = useState(0);\n const [iframeKey, setIframeKey] = useState(0);\n const [bookmarks, setBookmarks] = useState<Bookmark[]>(loadBookmarks);\n const [showHelp, setShowHelp] = useState(false);\n // Inline \"name this bookmark\" popover state. Populated when the user\n // clicks the star icon to add — replaces the native window.prompt().\n const [bookmarkDraft, setBookmarkDraft] = useState<string | null>(null);\n const bookmarkInputRef = useRef<HTMLInputElement>(null);\n const iframeRef = useRef<HTMLIFrameElement>(null);\n\n // Persist bookmarks.\n useEffect(() => {\n try { localStorage.setItem(BOOKMARKS_KEY, JSON.stringify(bookmarks)); } catch {}\n }, [bookmarks]);\n\n const navigate = (next: string) => {\n const n = normalizeUrl(next);\n if (!n) return;\n setUrl(n);\n setInputUrl(n);\n // Truncate forward history when navigating from a back state.\n setHistory(h => {\n const trimmed = h.slice(0, historyIdx + 1);\n trimmed.push(n);\n return trimmed;\n });\n setHistoryIdx(i => i + 1);\n setShowHelp(false);\n };\n\n const back = () => {\n if (historyIdx > 0) {\n const next = historyIdx - 1;\n setHistoryIdx(next);\n setUrl(history[next]);\n setInputUrl(history[next]);\n setShowHelp(false);\n }\n };\n\n const forward = () => {\n if (historyIdx < history.length - 1) {\n const next = historyIdx + 1;\n setHistoryIdx(next);\n setUrl(history[next]);\n setInputUrl(history[next]);\n setShowHelp(false);\n }\n };\n\n const refresh = () => setIframeKey(k => k + 1);\n\n const goHome = () => navigate(homepage);\n\n const openExternal = () => {\n if (typeof window !== 'undefined') window.open(url, '_blank', 'noopener,noreferrer');\n };\n\n const openBookmarkPopover = () => {\n setBookmarkDraft(titleFromUrl(url));\n // Focus + select happens in a useEffect once the input is mounted.\n };\n\n const commitBookmark = () => {\n const label = bookmarkDraft?.trim();\n if (!label) { setBookmarkDraft(null); return; }\n setBookmarks(b => [...b, { label, url }]);\n setBookmarkDraft(null);\n };\n\n // Auto-focus + select the popover input when it opens, and dismiss on\n // outside click.\n useEffect(() => {\n if (bookmarkDraft === null) return;\n bookmarkInputRef.current?.focus();\n bookmarkInputRef.current?.select();\n const onDocClick = (e: MouseEvent) => {\n const target = e.target as HTMLElement | null;\n if (!target?.closest('[data-bookmark-popover]')) setBookmarkDraft(null);\n };\n // Defer one tick so the click that opened the popover doesn't close it.\n const t = setTimeout(() => document.addEventListener('mousedown', onDocClick), 0);\n return () => {\n clearTimeout(t);\n document.removeEventListener('mousedown', onDocClick);\n };\n }, [bookmarkDraft !== null]);\n\n const removeBookmark = (i: number) => {\n setBookmarks(b => b.filter((_, idx) => idx !== i));\n };\n\n const setAsHomepage = () => {\n setHomepage(url);\n try { localStorage.setItem(HOMEPAGE_KEY, url); } catch {}\n };\n\n const onSubmitUrl = (e: React.FormEvent) => {\n e.preventDefault();\n navigate(inputUrl);\n };\n\n const canBack = historyIdx > 0;\n const canForward = historyIdx < history.length - 1;\n const isBookmarked = bookmarks.some(b => b.url === url);\n const btn = 'p-1.5 rounded hover:bg-gray-200 transition-colors text-gray-600 disabled:opacity-30';\n\n return (\n <div className=\"relative flex flex-col h-full bg-white\">\n <WindowTitle title={`Browser - ${titleFromUrl(url)}`} />\n <AboutApp app=\"browser\" />\n\n {/* Top toolbar */}\n <div className=\"flex items-center gap-1 px-2 py-1.5 border-b border-gray-200 bg-gray-50 shrink-0\">\n <button onClick={back} disabled={!canBack} className={btn} title=\"Back\">\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M15.75 19.5L8.25 12l7.5-7.5\" /></svg>\n </button>\n <button onClick={forward} disabled={!canForward} className={btn} title=\"Forward\">\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M8.25 4.5l7.5 7.5-7.5 7.5\" /></svg>\n </button>\n <button onClick={refresh} className={btn} title=\"Refresh\">\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.8}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M16.023 9.348h4.992V4.356M2.985 19.644v-4.992h4.992M3.05 9.348a9 9 0 0114.85-3.36L21.015 9.348m0 5.304a9 9 0 01-14.85 3.36l-3.115-3.36\" /></svg>\n </button>\n <button onClick={goHome} className={btn} title=\"Home\">\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.8}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.25 12l8.954-8.955a1.5 1.5 0 012.122 0l8.954 8.955M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25\" /></svg>\n </button>\n\n <form onSubmit={onSubmitUrl} className=\"flex-1 flex items-center mx-1\">\n <div className=\"flex items-center w-full bg-white border border-gray-300 rounded focus-within:border-blue-400 focus-within:ring-1 focus-within:ring-blue-200\">\n <span className=\"px-2 text-gray-400 text-xs\">{url.startsWith('https://') ? '🔒' : '⚠️'}</span>\n <input\n type=\"text\"\n value={inputUrl}\n onChange={(e) => setInputUrl(e.target.value)}\n onFocus={(e) => e.target.select()}\n className=\"flex-1 px-1 py-1 text-sm bg-transparent outline-none font-mono\"\n spellCheck={false}\n placeholder=\"Enter URL or search…\"\n />\n {url !== inputUrl && (\n <button\n type=\"button\"\n onClick={() => setInputUrl(url)}\n className=\"px-1.5 text-[10px] text-gray-400 hover:text-gray-700\"\n title=\"Reset to current URL\"\n >×</button>\n )}\n </div>\n </form>\n\n <button\n data-bookmark-popover\n onClick={() => isBookmarked\n ? removeBookmark(bookmarks.findIndex(b => b.url === url))\n : openBookmarkPopover()}\n className={btn + ' ' + (isBookmarked ? 'text-yellow-500' : '')}\n title={isBookmarked ? 'Remove bookmark' : 'Add bookmark'}\n >\n <svg className=\"h-4 w-4\" fill={isBookmarked ? 'currentColor' : 'none'} viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z\" />\n </svg>\n </button>\n <button onClick={openExternal} className={btn} title=\"Open in new tab\">\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-7.5-9L21 3m0 0v6m0-6L9.75 14.25\" /></svg>\n </button>\n <button onClick={() => setShowHelp(s => !s)} className={btn} title=\"Embedding help\">\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z\" /></svg>\n </button>\n </div>\n\n {/* Inline \"name this bookmark\" popover. Anchored to the right of the\n toolbar (where the star icon lives) so the visual flow matches\n how the user just clicked. Renders inside the panel so it\n inherits the window's z-stacking. */}\n {bookmarkDraft !== null && (\n <div\n data-bookmark-popover\n className=\"absolute right-3 top-12 z-30 w-72 bg-white border border-gray-200 rounded-md shadow-lg p-3\"\n >\n <div className=\"text-[11px] font-semibold uppercase tracking-wide text-gray-500 mb-1\">Bookmark this page</div>\n <div className=\"text-[11px] text-gray-400 truncate mb-2 font-mono\" title={url}>{url}</div>\n <input\n ref={bookmarkInputRef}\n type=\"text\"\n value={bookmarkDraft}\n onChange={(e) => setBookmarkDraft(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') commitBookmark();\n else if (e.key === 'Escape') setBookmarkDraft(null);\n }}\n placeholder=\"Name\"\n className=\"w-full text-sm px-2 py-1.5 border border-gray-300 rounded focus:outline-none focus:border-blue-400 focus:ring-1 focus:ring-blue-200\"\n />\n <div className=\"flex justify-end gap-1 mt-2\">\n <button\n onClick={() => setBookmarkDraft(null)}\n className=\"px-2 py-1 text-xs text-gray-600 hover:bg-gray-100 rounded\"\n >Cancel</button>\n <button\n onClick={commitBookmark}\n disabled={!bookmarkDraft.trim()}\n className=\"px-2 py-1 text-xs bg-blue-500 text-white rounded hover:bg-blue-600 disabled:opacity-40\"\n >Save</button>\n </div>\n </div>\n )}\n\n {/* Bookmarks bar */}\n <div className=\"flex items-center gap-0.5 px-2 py-1 border-b border-gray-200 bg-white shrink-0 overflow-x-auto\">\n {bookmarks.length === 0 && (\n <span className=\"text-[11px] text-gray-400 italic px-2\">No bookmarks yet — star the address bar to add one.</span>\n )}\n {bookmarks.map((b, i) => (\n <button\n key={i}\n onClick={() => navigate(b.url)}\n onContextMenu={async (e) => {\n e.preventDefault();\n const ok = await confirm({\n title: 'Remove bookmark',\n message: `\"${b.label}\" will be removed from your bookmarks.`,\n confirmLabel: 'Remove',\n variant: 'danger',\n });\n if (ok) removeBookmark(i);\n }}\n className=\"flex items-center gap-1.5 px-2 py-0.5 rounded text-[12px] text-gray-700 hover:bg-gray-100 whitespace-nowrap\"\n title={`${b.url}\\n(right-click to remove)`}\n >\n <img\n src={`https://icons.duckduckgo.com/ip3/${new URL(b.url).hostname}.ico`}\n alt=\"\"\n className=\"h-3.5 w-3.5\"\n onError={(e) => { (e.target as HTMLImageElement).style.visibility = 'hidden'; }}\n />\n {b.label}\n </button>\n ))}\n <div className=\"flex-1\" />\n <button\n onClick={setAsHomepage}\n className=\"px-2 py-0.5 text-[11px] text-gray-500 hover:text-gray-800\"\n title=\"Set current page as homepage\"\n >Set as home</button>\n </div>\n\n {/* Iframe area */}\n <div className=\"flex-1 relative min-h-0 bg-gray-50\">\n <BrowserBody\n url={url}\n iframeKey={iframeKey}\n iframeRef={iframeRef}\n openExternal={openExternal}\n showHelp={showHelp}\n dismissHelp={() => setShowHelp(false)}\n />\n </div>\n </div>\n );\n}\n\nfunction titleFromUrl(u: string): string {\n try {\n const url = new URL(u);\n return url.hostname.replace(/^www\\./, '');\n } catch {\n return u;\n }\n}\n\nfunction BrowserBody({\n url,\n iframeKey,\n iframeRef,\n openExternal,\n showHelp,\n dismissHelp,\n}: {\n url: string;\n iframeKey: number;\n iframeRef: React.RefObject<HTMLIFrameElement | null>;\n openExternal: () => void;\n showHelp: boolean;\n dismissHelp: () => void;\n}) {\n // If the user dismisses the blocked-site panel, allow them to attempt\n // the iframe load anyway. Reset the override whenever URL changes.\n const [forceTry, setForceTry] = useState(false);\n useEffect(() => { setForceTry(false); }, [url]);\n\n const blocked = hostIsBlocked(url) && !forceTry;\n\n if (blocked) {\n return (\n <div className=\"absolute inset-0 flex items-center justify-center bg-white p-8\">\n <div className=\"max-w-md text-center\">\n <svg className=\"h-14 w-14 mx-auto text-gray-300 mb-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728L5.636 5.636m12.728 12.728L21 21M5.636 5.636L3 3m9 9a9 9 0 110-18 9 9 0 010 18z\" />\n </svg>\n <h3 className=\"text-base font-semibold text-gray-800 mb-1\">\n {titleFromUrl(url)} can't be embedded\n </h3>\n <p className=\"text-sm text-gray-500 mb-4\">\n This site sends an <span className=\"font-mono text-xs\">X-Frame-Options</span>{' '}\n or <span className=\"font-mono text-xs\">Content-Security-Policy</span> header\n that refuses iframe embedding. The browser blocks the load before our app\n can do anything about it.\n </p>\n <div className=\"flex flex-col items-center gap-2\">\n <button\n onClick={openExternal}\n className=\"px-4 py-2 bg-blue-500 text-white text-sm rounded hover:bg-blue-600 inline-flex items-center gap-2\"\n >\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-7.5-9L21 3m0 0v6m0-6L9.75 14.25\" />\n </svg>\n Open in a new tab\n </button>\n <button\n onClick={() => setForceTry(true)}\n className=\"text-xs text-gray-500 hover:text-gray-800 underline\"\n >\n Try loading it here anyway\n </button>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <>\n <iframe\n key={iframeKey + url}\n ref={iframeRef as React.RefObject<HTMLIFrameElement>}\n src={url}\n className=\"absolute inset-0 w-full h-full bg-white\"\n // Sandboxing keeps embedded pages from messing with the parent\n // window state. allow-same-origin lets sites that *do* allow\n // embedding actually behave normally; allow-scripts is needed\n // for any modern site.\n sandbox=\"allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-modals\"\n referrerPolicy=\"no-referrer-when-downgrade\"\n />\n\n {showHelp && (\n <div className=\"absolute top-2 right-2 max-w-sm bg-white border border-gray-200 rounded-md shadow-lg p-3 text-xs text-gray-700 z-10\">\n <div className=\"font-medium text-gray-900 mb-1\">Why is this page blank?</div>\n <p className=\"mb-2\">\n Most major sites (Google, GitHub, banks, news) refuse to be embedded in\n an iframe via <span className=\"font-mono\">X-Frame-Options</span> or\n Content Security Policy. There's no workaround — the browser blocks the\n load before our app can do anything.\n </p>\n <p>\n Hit the <span className=\"font-medium\">↗</span> button to open the page in\n a real new tab. Sites that <em>do</em> allow embedding (Wikipedia, DevDocs,\n your own apps) work fine in here.\n </p>\n <button\n onClick={dismissHelp}\n className=\"mt-2 text-[11px] text-blue-600 hover:underline\"\n >Got it</button>\n </div>\n )}\n </>\n );\n}\n"]}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { loadAppearance, WidgetSettingsModal } from './chunk-
|
|
2
|
-
import { useWidgetSettings } from './chunk-
|
|
3
|
-
import './chunk-UBN4IUDE.js';
|
|
1
|
+
import { loadAppearance, WidgetSettingsModal } from './chunk-EWRKU7EF.js';
|
|
2
|
+
import { useWidgetSettings } from './chunk-IU7MSBRI.js';
|
|
4
3
|
import './chunk-GW3RA6IS.js';
|
|
5
4
|
import { useState, useCallback, useEffect } from 'react';
|
|
6
5
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
@@ -181,5 +180,5 @@ function Calculator() {
|
|
|
181
180
|
}
|
|
182
181
|
|
|
183
182
|
export { Calculator as default };
|
|
184
|
-
//# sourceMappingURL=Calculator-
|
|
185
|
-
//# sourceMappingURL=Calculator-
|
|
183
|
+
//# sourceMappingURL=Calculator-7MRLC77Q.js.map
|
|
184
|
+
//# sourceMappingURL=Calculator-7MRLC77Q.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/apps/Calculator.tsx"],"names":[],"mappings":"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","file":"Calculator-7MRLC77Q.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 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"ConfirmDialog-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"ConfirmDialog-2BV43KSW.js"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { loadAppearance, WidgetSettingsModal } from './chunk-
|
|
2
|
-
import { useWidgetSettings } from './chunk-
|
|
3
|
-
import './chunk-UBN4IUDE.js';
|
|
1
|
+
import { loadAppearance, WidgetSettingsModal } from './chunk-EWRKU7EF.js';
|
|
2
|
+
import { useWidgetSettings } from './chunk-IU7MSBRI.js';
|
|
4
3
|
import './chunk-GW3RA6IS.js';
|
|
5
4
|
import { useState, useCallback, useEffect } from 'react';
|
|
6
5
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
@@ -225,5 +224,5 @@ function CurrencyConverter() {
|
|
|
225
224
|
}
|
|
226
225
|
|
|
227
226
|
export { CurrencyConverter as default };
|
|
228
|
-
//# sourceMappingURL=CurrencyConverter-
|
|
229
|
-
//# sourceMappingURL=CurrencyConverter-
|
|
227
|
+
//# sourceMappingURL=CurrencyConverter-6UTL2ZBY.js.map
|
|
228
|
+
//# sourceMappingURL=CurrencyConverter-6UTL2ZBY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/apps/CurrencyConverter.tsx"],"names":[],"mappings":"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","file":"CurrencyConverter-6UTL2ZBY.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\">×</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"]}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { toast_default } from './chunk-VENYVK3L.js';
|
|
2
|
-
import { AboutApp } from './chunk-
|
|
3
|
-
import './chunk-
|
|
4
|
-
import { WindowTitle, PopupMenu, PopupMenuLabel, PopupMenuItem, PopupMenuDivider } from './chunk-
|
|
5
|
-
import './chunk-UBN4IUDE.js';
|
|
2
|
+
import { AboutApp } from './chunk-GHGD4GKR.js';
|
|
3
|
+
import './chunk-CZW7CTI6.js';
|
|
4
|
+
import { WindowTitle, PopupMenu, PopupMenuLabel, PopupMenuItem, PopupMenuDivider } from './chunk-IU7MSBRI.js';
|
|
6
5
|
import './chunk-GW3RA6IS.js';
|
|
7
6
|
import { useState, useRef } from 'react';
|
|
8
7
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
@@ -438,5 +437,5 @@ function Documents() {
|
|
|
438
437
|
}
|
|
439
438
|
|
|
440
439
|
export { Documents as default };
|
|
441
|
-
//# sourceMappingURL=Documents-
|
|
442
|
-
//# sourceMappingURL=Documents-
|
|
440
|
+
//# sourceMappingURL=Documents-FQKIQ4GH.js.map
|
|
441
|
+
//# sourceMappingURL=Documents-FQKIQ4GH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/apps/Documents.tsx"],"names":[],"mappings":"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","file":"Documents-FQKIQ4GH.js","sourcesContent":["/**\n * Documents — windowed viewer / editor for plain-text and Word documents.\n * TXT-family files (.txt, .md, .csv, .log, .json, .xml, .html, .css, .ts,\n * .tsx, .js, .jsx, .py, .yml, .yaml, .toml, .sh) open in a full-width\n * monospace editor. Word .docx files (and new blank documents) open on a\n * letter-size page (8.5 × 11 in) with rich formatting: bold/italic/…,\n * font size & color, bulleted / numbered lists, text alignment, and\n * images (toolbar button, paste, or drag-drop; click an image to resize\n * or remove it — images embed as data URLs so saved files stay\n * self-contained). .docx conversion uses mammoth (an optional peer dep).\n *\n * Open files via the toolbar's Open button or by dragging them onto\n * the window.\n */\nimport { useState, useRef, useEffect } from 'react';\nimport { WindowTitle } from '../shell/Modal';\nimport { PopupMenu, PopupMenuItem, PopupMenuDivider, PopupMenuLabel } from '../shell/PopupMenu';\nimport toast from '../shell/toast';\nimport AboutApp from './_about';\n\nconst TITLE_DISPLAY_MAX = 24;\nfunction truncateForTitle(s: string) {\n return s.length > TITLE_DISPLAY_MAX ? `${s.slice(0, TITLE_DISPLAY_MAX - 1)}…` : s;\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, c => ({\n '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''',\n }[c] || c));\n}\n\nconst TEXT_EXTS = new Set([\n 'txt', 'md', 'markdown', 'csv', 'tsv', 'log', 'json', 'xml',\n 'html', 'htm', 'css', 'js', 'jsx', 'ts', 'tsx', 'py', 'rb',\n 'go', 'rs', 'java', 'c', 'h', 'cpp', 'hpp', 'sh', 'bash',\n 'yml', 'yaml', 'toml', 'ini', 'conf', 'env', 'sql',\n]);\nconst DOCX_EXTS = new Set(['docx']);\n\ninterface DocData {\n filename: string;\n kind: 'text' | 'docx';\n content: string;\n /** Original mime / extension hint for the download button. */\n ext: string;\n}\n\nconst BLANK_DOC: DocData = { filename: 'Untitled', kind: 'docx', content: '', ext: 'docx' };\n\nexport default function Documents() {\n // Documents is for editing — open with a blank paper-style canvas so the\n // user can start typing immediately. Loading a file replaces this state.\n const [data, setData] = useState<DocData>(BLANK_DOC);\n const [busy, setBusy] = useState(false);\n const [isDragging, setIsDragging] = useState(false);\n const [edited, setEdited] = useState(false);\n // Floating menu shown when an image in the document is clicked.\n const [imgMenu, setImgMenu] = useState<{ x: number; y: number; el: HTMLImageElement } | null>(null);\n const fileRef = useRef<HTMLInputElement>(null);\n const imgInputRef = useRef<HTMLInputElement>(null);\n const editorRef = useRef<HTMLDivElement>(null);\n\n // Apply a formatting command to the current selection in the editor.\n const exec = (cmd: string, value?: string) => {\n editorRef.current?.focus();\n document.execCommand(cmd, false, value);\n setEdited(true);\n };\n\n // ── Images ──\n // Inserted at the caret as data URLs, so the document needs no server-side\n // storage and a saved .html round-trips with its images embedded.\n const insertImageFiles = (files: File[]) => {\n for (const file of files) {\n if (!file.type.startsWith('image/')) continue;\n const reader = new FileReader();\n reader.onload = () => {\n editorRef.current?.focus();\n document.execCommand('insertImage', false, String(reader.result));\n setEdited(true);\n };\n reader.readAsDataURL(file);\n }\n };\n\n const handlePaste = (e: React.ClipboardEvent) => {\n const images = Array.from(e.clipboardData?.items ?? [])\n .filter(i => i.kind === 'file' && i.type.startsWith('image/'))\n .map(i => i.getAsFile())\n .filter((f): f is File => !!f);\n if (images.length) {\n e.preventDefault();\n insertImageFiles(images);\n }\n };\n\n // Click an image → floating resize / remove menu.\n const handleEditorClick = (e: React.MouseEvent) => {\n const target = e.target as HTMLElement;\n if (target.tagName === 'IMG') {\n e.preventDefault();\n setImgMenu({ x: e.clientX, y: e.clientY, el: target as HTMLImageElement });\n }\n };\n\n const setImageWidth = (width: string | null) => {\n if (!imgMenu) return;\n // Pixel width/height attributes (e.g. from pasted HTML) would fight the\n // percentage style — drop them and let height follow the aspect ratio.\n imgMenu.el.removeAttribute('width');\n imgMenu.el.removeAttribute('height');\n imgMenu.el.style.width = width ?? '';\n imgMenu.el.style.height = width ? 'auto' : '';\n setEdited(true);\n setImgMenu(null);\n };\n\n const removeImage = () => {\n imgMenu?.el.remove();\n setEdited(true);\n setImgMenu(null);\n };\n\n // Pull current HTML out of the editor (for save).\n const getEditorHtml = () => editorRef.current?.innerHTML ?? '';\n const getEditorText = () => editorRef.current?.innerText ?? '';\n\n const ingestFile = async (file: File) => {\n const ext = (file.name.split('.').pop() || '').toLowerCase();\n setBusy(true);\n try {\n if (TEXT_EXTS.has(ext) || (!DOCX_EXTS.has(ext) && file.type.startsWith('text/'))) {\n const text = await file.text();\n // Convert plain text → HTML so the contenteditable shows\n // line breaks correctly. Escape HTML special chars first.\n const html = escapeHtml(text).replace(/\\n/g, '<br>');\n setData({ filename: file.name, kind: 'text', content: html, ext });\n setEdited(false);\n } else if (DOCX_EXTS.has(ext)) {\n try {\n // mammoth is an optional peer dep — convert .docx → HTML.\n const mammoth = await import(/* @vite-ignore */ 'mammoth' as any);\n const buf = await file.arrayBuffer();\n const result = await mammoth.convertToHtml({ arrayBuffer: buf });\n setData({ filename: file.name, kind: 'docx', content: result.value || '<p><em>(empty document)</em></p>', ext });\n setEdited(false);\n } catch (err) {\n toast.error('Install the optional \"mammoth\" peer dep to read .docx files.');\n }\n } else if (ext === 'doc') {\n toast.error('.doc is the legacy Word binary format — convert to .docx first.');\n } else {\n toast.error(`Unsupported file type: .${ext || 'unknown'}`);\n }\n } finally {\n setBusy(false);\n }\n };\n\n const handlePick = () => fileRef.current?.click();\n const handleFile = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (file) ingestFile(file);\n if (fileRef.current) fileRef.current.value = '';\n };\n const handleDrop = (e: React.DragEvent) => {\n e.preventDefault();\n setIsDragging(false);\n const files = Array.from(e.dataTransfer.files ?? []);\n if (files.length === 0) return;\n // Dropped images go INTO the document; anything else opens as a document.\n if (files.every(f => f.type.startsWith('image/'))) {\n insertImageFiles(files);\n return;\n }\n ingestFile(files[0]);\n };\n\n const downloadCurrent = () => {\n if (!data) return;\n const html = getEditorHtml();\n if (data.kind === 'text') {\n // If the user added formatting, save as .html alongside; otherwise\n // strip back to plain text so the original .txt round-trips cleanly.\n // (`style=\"…text-align` only matches a real attribute — literal text\n // mentioning text-align gets its quotes escaped to " on load.)\n const hasFormatting = /<(b|strong|i|em|u|font|span style|ul|ol|img)|style=\"[^\"]*text-align/i.test(html);\n if (hasFormatting) {\n const blob = new Blob([`<!doctype html><meta charset=\"utf-8\"><title>${escapeHtml(data.filename)}</title><body style=\"font-family:ui-monospace,monospace;white-space:pre-wrap\">${html}`], { type: 'text/html' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a'); a.href = url; a.download = `${data.filename.replace(/\\.[^.]+$/, '')}.html`; a.click();\n URL.revokeObjectURL(url);\n } else {\n const text = getEditorText();\n const blob = new Blob([text], { type: 'text/plain' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a'); a.href = url; a.download = data.filename; a.click();\n URL.revokeObjectURL(url);\n }\n } else {\n const blob = new Blob([`<!doctype html><meta charset=\"utf-8\"><title>${escapeHtml(data.filename)}</title>${html}`], { type: 'text/html' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url; a.download = `${data.filename.replace(/\\.docx$/i, '')}.html`; a.click();\n URL.revokeObjectURL(url);\n }\n };\n\n const titleName = data?.filename ? truncateForTitle(data.filename) : 'Untitled';\n\n return (\n <div\n className=\"relative flex flex-col h-full\"\n onDragOver={(e) => { e.preventDefault(); if (!isDragging) setIsDragging(true); }}\n onDragLeave={(e) => { if (e.currentTarget === e.target) setIsDragging(false); }}\n onDrop={handleDrop}\n >\n <WindowTitle title={`${titleName}${edited ? ' •' : ''} - Documents`} />\n <AboutApp app=\"documents\" />\n\n {/* Toolbar */}\n <div className=\"flex items-center flex-wrap gap-x-2 gap-y-1 px-3 py-2 border-b border-gray-200 bg-gray-50 shrink-0\">\n <input\n ref={fileRef}\n type=\"file\"\n accept=\".txt,.md,.csv,.tsv,.log,.json,.xml,.html,.htm,.css,.js,.jsx,.ts,.tsx,.py,.rb,.go,.rs,.java,.c,.h,.cpp,.hpp,.sh,.bash,.yml,.yaml,.toml,.ini,.conf,.env,.sql,.docx,text/*\"\n onChange={handleFile}\n className=\"hidden\"\n />\n <button onClick={handlePick} className=\"text-xs text-gray-700 hover:text-gray-900 px-2 py-1 rounded hover:bg-gray-200 transition-colors flex items-center gap-1\">\n <svg className=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3.75 9.776c.112-.017.227-.026.344-.026h15.812c.117 0 .232.009.344.026m-16.5 0a2.25 2.25 0 00-1.883 2.542l.857 6a2.25 2.25 0 002.227 1.932H19.05a2.25 2.25 0 002.227-1.932l.857-6a2.25 2.25 0 00-1.883-2.542m-16.5 0V6A2.25 2.25 0 016 3.75h3.879a1.5 1.5 0 011.06.44l2.122 2.12a1.5 1.5 0 001.06.44H18A2.25 2.25 0 0120.25 9v.776\" />\n </svg>\n Open\n </button>\n <button onClick={downloadCurrent} className=\"text-xs text-gray-700 hover:text-gray-900 px-2 py-1 rounded hover:bg-gray-200 transition-colors\">\n Save\n </button>\n <span className=\"text-[10px] text-gray-400 ml-1\">TXT · DOCX · Code</span>\n <div className=\"h-4 w-px bg-gray-300 mx-1\" />\n <span className=\"text-xs font-medium text-gray-700 truncate max-w-[200px]\" title={data.filename}>\n {data.filename}{edited ? ' •' : ''}\n </span>\n\n {/* Formatting toolbar */}\n <div className=\"h-4 w-px bg-gray-300 mx-1\" />\n <div className=\"flex items-center gap-0.5\">\n <button onMouseDown={e => e.preventDefault()} onClick={() => exec('bold')}\n className=\"px-2 py-1 text-xs rounded font-bold text-gray-700 hover:bg-gray-200 transition-colors\" title=\"Bold\">B</button>\n <button onMouseDown={e => e.preventDefault()} onClick={() => exec('italic')}\n className=\"px-2 py-1 text-xs rounded italic text-gray-700 hover:bg-gray-200 transition-colors\" title=\"Italic\">I</button>\n <button onMouseDown={e => e.preventDefault()} onClick={() => exec('underline')}\n className=\"px-2 py-1 text-xs rounded underline text-gray-700 hover:bg-gray-200 transition-colors\" title=\"Underline\">U</button>\n <button onMouseDown={e => e.preventDefault()} onClick={() => exec('strikeThrough')}\n className=\"px-2 py-1 text-xs rounded line-through text-gray-700 hover:bg-gray-200 transition-colors\" title=\"Strikethrough\">S</button>\n </div>\n <div className=\"h-4 w-px bg-gray-300 mx-1\" />\n <select onMouseDown={e => e.preventDefault()} onChange={e => { exec('fontSize', e.target.value); e.currentTarget.value = ''; }}\n defaultValue=\"\" className=\"text-xs border border-gray-300 rounded px-1 py-0.5 bg-white\">\n <option value=\"\" disabled>Size</option>\n <option value=\"1\">XS</option>\n <option value=\"2\">S</option>\n <option value=\"3\">M</option>\n <option value=\"4\">L</option>\n <option value=\"5\">XL</option>\n <option value=\"6\">2XL</option>\n </select>\n <input type=\"color\" defaultValue=\"#000000\" onChange={e => exec('foreColor', e.target.value)}\n className=\"w-7 h-6 border border-gray-300 rounded cursor-pointer\" title=\"Text color\" />\n <div className=\"h-4 w-px bg-gray-300 mx-1\" />\n <button onMouseDown={e => e.preventDefault()} onClick={() => exec('insertUnorderedList')}\n className=\"px-2 py-1 text-xs rounded text-gray-700 hover:bg-gray-200 transition-colors\" title=\"Bulleted list\">• List</button>\n <button onMouseDown={e => e.preventDefault()} onClick={() => exec('insertOrderedList')}\n className=\"px-2 py-1 text-xs rounded text-gray-700 hover:bg-gray-200 transition-colors\" title=\"Numbered list\">1.</button>\n\n {/* Alignment */}\n <div className=\"h-4 w-px bg-gray-300 mx-1\" />\n <div className=\"flex items-center gap-0.5\">\n <button onMouseDown={e => e.preventDefault()} onClick={() => exec('justifyLeft')}\n className=\"px-2 py-1 rounded text-gray-700 hover:bg-gray-200 transition-colors\" title=\"Align left\">\n <svg className=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.8}>\n <path strokeLinecap=\"round\" d=\"M3.75 6h16.5M3.75 12h9.75M3.75 18h14.25\" />\n </svg>\n </button>\n <button onMouseDown={e => e.preventDefault()} onClick={() => exec('justifyCenter')}\n className=\"px-2 py-1 rounded text-gray-700 hover:bg-gray-200 transition-colors\" title=\"Align center\">\n <svg className=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.8}>\n <path strokeLinecap=\"round\" d=\"M3.75 6h16.5M7.125 12h9.75M4.875 18h14.25\" />\n </svg>\n </button>\n <button onMouseDown={e => e.preventDefault()} onClick={() => exec('justifyRight')}\n className=\"px-2 py-1 rounded text-gray-700 hover:bg-gray-200 transition-colors\" title=\"Align right\">\n <svg className=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.8}>\n <path strokeLinecap=\"round\" d=\"M3.75 6h16.5M10.5 12h9.75M6 18h14.25\" />\n </svg>\n </button>\n <button onMouseDown={e => e.preventDefault()} onClick={() => exec('justifyFull')}\n className=\"px-2 py-1 rounded text-gray-700 hover:bg-gray-200 transition-colors\" title=\"Justify\">\n <svg className=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.8}>\n <path strokeLinecap=\"round\" d=\"M3.75 6h16.5M3.75 12h16.5M3.75 18h16.5\" />\n </svg>\n </button>\n </div>\n\n {/* Image insert */}\n <div className=\"h-4 w-px bg-gray-300 mx-1\" />\n <input\n ref={imgInputRef}\n type=\"file\"\n accept=\"image/*\"\n multiple\n className=\"hidden\"\n onChange={e => {\n if (e.target.files?.length) insertImageFiles(Array.from(e.target.files));\n if (imgInputRef.current) imgInputRef.current.value = '';\n }}\n />\n <button onClick={() => imgInputRef.current?.click()}\n className=\"px-2 py-1 text-xs rounded text-gray-700 hover:bg-gray-200 transition-colors flex items-center gap-1\" title=\"Insert image (or paste / drop one)\">\n <svg className=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z\" />\n </svg>\n Image\n </button>\n </div>\n\n {/* Body */}\n <div className=\"flex-1 min-h-0 overflow-hidden\">\n {busy ? (\n <div className=\"flex items-center justify-center h-full text-sm text-gray-400\">Loading…</div>\n ) : (\n <div className={`h-full overflow-auto ${data.kind === 'docx' ? 'bg-gray-100 px-6 py-8' : 'bg-white'}`}>\n {/* Word-style documents render on a US-letter page (8.5 × 11 in,\n 1 in margins) that grows past 11 in as content does; the gray\n \"desk\" scrolls when the window is narrower than the page. */}\n <div\n ref={editorRef}\n contentEditable\n suppressContentEditableWarning\n spellCheck={false}\n onInput={() => setEdited(true)}\n onPaste={handlePaste}\n onClick={handleEditorClick}\n dangerouslySetInnerHTML={{ __html: data.content }}\n className={\n data.kind === 'docx'\n ? 'docs-editor mx-auto w-[8.5in] min-h-[11in] bg-white p-[1in] shadow text-[14px] leading-relaxed text-gray-800 outline-none focus:ring-2 focus:ring-blue-400/40'\n : 'docs-editor block w-full min-h-full p-4 font-mono text-[13px] leading-relaxed text-gray-800 bg-white outline-none whitespace-pre-wrap'\n }\n />\n </div>\n )}\n </div>\n\n {isDragging && (\n <div className=\"absolute inset-0 bg-blue-500/15 border-4 border-dashed border-blue-500 pointer-events-none flex items-center justify-center z-20\">\n <div className=\"px-4 py-2 rounded-md bg-blue-600 text-white text-sm font-medium shadow-lg\">\n Drop a document to open · images insert into the page\n </div>\n </div>\n )}\n\n {/* Image menu — resize / remove the clicked image */}\n {imgMenu && (\n <PopupMenu\n minWidth={150}\n style={{ left: imgMenu.x, top: imgMenu.y }}\n onClose={() => setImgMenu(null)}\n >\n <PopupMenuLabel>Image width</PopupMenuLabel>\n <PopupMenuItem onClick={() => setImageWidth('25%')}>25%</PopupMenuItem>\n <PopupMenuItem onClick={() => setImageWidth('50%')}>50%</PopupMenuItem>\n <PopupMenuItem onClick={() => setImageWidth('75%')}>75%</PopupMenuItem>\n <PopupMenuItem onClick={() => setImageWidth('100%')}>100%</PopupMenuItem>\n <PopupMenuItem onClick={() => setImageWidth(null)}>Original size</PopupMenuItem>\n <PopupMenuDivider />\n <PopupMenuItem danger onClick={removeImage}>Remove image</PopupMenuItem>\n </PopupMenu>\n )}\n </div>\n );\n}\n\n"]}
|
|
@@ -4,11 +4,10 @@ import { toast_default } from './chunk-VENYVK3L.js';
|
|
|
4
4
|
import { getFilesDemoTree } from './chunk-AA24QYTD.js';
|
|
5
5
|
import { peekFilesViewRequest, consumeFilesViewRequest, FILES_SHOW_TRASH_EVENT, FILES_OPEN_DESKTOP_FOLDER_EVENT, subscribeDesktopFolders, getDesktopFoldersSnapshot, FolderGlyph, DesktopItemMiniIcon, desktopItemTypeLabel } from './chunk-LRVPNWRE.js';
|
|
6
6
|
import './chunk-BV6SQ46N.js';
|
|
7
|
-
import { AboutApp } from './chunk-
|
|
7
|
+
import { AboutApp } from './chunk-GHGD4GKR.js';
|
|
8
8
|
import './chunk-4SQU5YV6.js';
|
|
9
|
-
import './chunk-
|
|
10
|
-
import { useWindowManager, WindowTitle } from './chunk-
|
|
11
|
-
import { confirm, prompt } from './chunk-UBN4IUDE.js';
|
|
9
|
+
import './chunk-CZW7CTI6.js';
|
|
10
|
+
import { useWindowManager, WindowTitle, confirm, prompt } from './chunk-IU7MSBRI.js';
|
|
12
11
|
import './chunk-GW3RA6IS.js';
|
|
13
12
|
import { useState, useEffect, useSyncExternalStore, useRef, useCallback } from 'react';
|
|
14
13
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
@@ -793,5 +792,5 @@ function Files() {
|
|
|
793
792
|
}
|
|
794
793
|
|
|
795
794
|
export { Files as default };
|
|
796
|
-
//# sourceMappingURL=Files-
|
|
797
|
-
//# sourceMappingURL=Files-
|
|
795
|
+
//# sourceMappingURL=Files-NTUFLWY3.js.map
|
|
796
|
+
//# sourceMappingURL=Files-NTUFLWY3.js.map
|