efficient-shell 4.177.0 → 4.179.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +381 -6
  2. package/dist/{Browser-MFFTBGEB.js → Browser-LZMLL4CZ.js} +14 -14
  3. package/dist/Calculator-R5OEHQ67.js +29 -0
  4. package/dist/ConfirmDialog-CMNQZQA3.js +1 -0
  5. package/dist/{CurrencyConverter-KZPE7ZCC.js → CurrencyConverter-AMXUOQR2.js} +7 -7
  6. package/dist/{Documents-ZD227WZC.js → Documents-M4HKZAPJ.js} +7 -7
  7. package/dist/{Files-BLGT4RLF.js → Files-OY5GKCXA.js} +28 -28
  8. package/dist/{Notepad-LUK2IFHD.js → Notepad-JLDNTMVB.js} +10 -10
  9. package/dist/PdfViewer-3SC3LE4U.js +1 -0
  10. package/dist/{PomodoroTimer-LHPV6QXG.js → PomodoroTimer-LE6J2KUU.js} +26 -26
  11. package/dist/Preview-2KHLL6NP.js +188 -0
  12. package/dist/{Sidebar-4GIZSTD5.js → Sidebar-BQ4P5LBI.js} +21 -21
  13. package/dist/{Spreadsheet-F3VBCPHF.js → Spreadsheet-B5Z5MSX4.js} +14 -14
  14. package/dist/{Stock-XSDFN7U2.js → Stock-GWVG2INU.js} +4 -4
  15. package/dist/{Weather-7YDUDMCO.js → Weather-APBCG4TO.js} +14 -14
  16. package/dist/{WorldClock-Q2JHBKLS.js → WorldClock-2LMZYKWR.js} +7 -7
  17. package/dist/apps/index.d.ts +4 -2
  18. package/dist/apps/index.js +1 -1
  19. package/dist/bin/ui-check.js +1 -1
  20. package/dist/{chunk-L3U2R7DH.js → chunk-3DGTIWZP.js} +1 -1
  21. package/dist/{chunk-AZO5NPB4.js → chunk-47VJNVB6.js} +621 -621
  22. package/dist/{chunk-KS7OSQ3Y.js → chunk-5ZDM6WIC.js} +11 -11
  23. package/dist/{chunk-E2D54MVV.js → chunk-6CFBF543.js} +2 -2
  24. package/dist/{chunk-LCTSBQBJ.js → chunk-7WZEFHPS.js} +1 -1
  25. package/dist/chunk-AZURXTRB.js +1 -0
  26. package/dist/chunk-C3QOHMR6.js +1 -0
  27. package/dist/{chunk-YJRC6IKD.js → chunk-CIXQKCFA.js} +4 -4
  28. package/dist/chunk-CZK2VKIO.js +9 -0
  29. package/dist/{chunk-Q7UGGJ5X.js → chunk-FORN7LG7.js} +1 -1
  30. package/dist/chunk-J3LIIIHJ.js +1 -0
  31. package/dist/{chunk-7H6Q5TNN.js → chunk-KDRAU4XQ.js} +8 -8
  32. package/dist/{chunk-ZOPYAOUP.js → chunk-KVOFUFPP.js} +1 -1
  33. package/dist/{chunk-KDHXRJIX.js → chunk-LK7V32MR.js} +1 -1
  34. package/dist/{chunk-TZ2BPFCT.js → chunk-N6STBYXR.js} +111 -111
  35. package/dist/{chunk-54OP3M3K.js → chunk-NHIGOEZF.js} +1 -1
  36. package/dist/{chunk-PE6MTNFO.js → chunk-PE4F4MJE.js} +4 -4
  37. package/dist/chunk-R7EBJKN2.js +69 -0
  38. package/dist/{chunk-AI6HQ55O.js → chunk-SVO3ES2E.js} +1 -1
  39. package/dist/{chunk-RKR5V4QR.js → chunk-T4CFSGSL.js} +6 -6
  40. package/dist/{chunk-N6BJG6AL.js → chunk-UAIVAA5X.js} +11 -11
  41. package/dist/{chunk-REXHKIIJ.js → chunk-WNEO7TSP.js} +1 -1
  42. package/dist/{chunk-XJYXKO7K.js → chunk-ZAE6ROV7.js} +15 -15
  43. package/dist/file-intake/index.js +1 -1
  44. package/dist/i18n/index.d.ts +3 -2
  45. package/dist/i18n/index.js +1 -1
  46. package/dist/{index-BS_HzJCc.d.ts → index-DcUj0nXY.d.ts} +14 -2
  47. package/dist/index.d.ts +3 -3
  48. package/dist/index.js +656 -656
  49. package/dist/locales/zh-Hans.d.ts +59 -0
  50. package/dist/locales/zh-Hans.js +1 -0
  51. package/dist/map/index.js +3 -3
  52. package/dist/page-tabs/index.js +4 -4
  53. package/dist/pdf/index.js +1 -1
  54. package/dist/{strings-C3kt6WTH.d.ts → strings-ZbotP_I6.d.ts} +368 -0
  55. package/dist/ui/index.d.ts +2 -2
  56. package/dist/ui/index.js +1 -1
  57. package/package.json +6 -1
  58. package/dist/Calculator-AGQQYMMZ.js +0 -29
  59. package/dist/ConfirmDialog-6PVUVYXZ.js +0 -1
  60. package/dist/PdfViewer-RKRGO7Q2.js +0 -1
  61. package/dist/Preview-5CALO6PW.js +0 -187
  62. package/dist/chunk-3YTHR7IC.js +0 -1
  63. package/dist/chunk-4PCIZFDR.js +0 -9
  64. package/dist/chunk-MFXG5BWL.js +0 -1
  65. package/dist/chunk-VIIBZ6DE.js +0 -69
package/README.md CHANGED
@@ -951,7 +951,7 @@ All exports are named — `import { Modal, ... } from 'efficient-shell'`.
951
951
  | `DataTable` | Read-only table for server-driven lists: it renders and reports, and never sorts or pages its own `data`. Controlled sort and pager, row selection, column groups, pinned columns, windowed rendering. `onRow` gives a row `onClick`, a `className`, any `data-*` attributes for its `<tr>` — a test's or a stylesheet's hook (`data-testid`, `data-state`) — the pointer and the keyboard coming in and out (`onMouseEnter` … `onBlur`) and `current`. `rowHref` makes each row one real link (`onRowPress` a button) with its controls still pressable — see [DataTable rows that are links](#datatable-rows-that-are-links). `stackOnNarrow` turns each row into a labelled card on a narrow container — see [DataTable on a narrow screen](#datatable-on-a-narrow-screen). |
952
952
  | `Pagination` | Numbered page control (pairs with tables; complements `ListFooter`). |
953
953
  | `Sparkline`, `LineChart`, `BarChart`, `DonutChart`, `ScatterChart` | Dependency-free inline-SVG charts (`currentColor`-themed). `LineChart` is the multi-series trend with optional scale, legend, dots and area fill. `ScatterChart` takes `xDomain` / `yDomain` to override the derived axis, and `xScale` / `yScale` of `'log'` for a long tail; a point outside a supplied domain is dropped and counted in the accessible label. |
954
- | `BulkImportGrid` | Paste-or-upload bulk entry with column mapping, duplicate review and optional sum-merge. Hands resolved rows to `onImport`; owns no persistence. The whole panel takes a dropped CSV; the Upload CSV button opens the same dialog. |
954
+ | `BulkImportGrid` | Paste-or-upload bulk entry with column mapping, duplicate review and optional sum-merge. Hands resolved rows to `onImport`; owns no persistence. The whole panel takes a dropped CSV; the Upload CSV button opens the same dialog. Its words are the strings catalog's `bulkImport` section (a `description` prop wins), and its totals are written in the provider's `locale`. |
955
955
  | `UndoProvider`, `UndoControls` | One undo stack per form window, covering its fields, line items and bulk imports. Register state with `useUndoable` and the shell shows the Undo/Redo pair itself, leftmost in the window footer, as soon as the form has state and the window is editing (a draft, a duplicate, Edit mode) or the form has said `useUndoCanEdit(true)` — a view that merely holds state gets nothing — it joins a footer that is there for other reasons and never creates one, and the mobile chrome (footer hidden) gets nothing. A form mounts `UndoControls` by hand only for a place the footer is not (a plain overlay, a section header); a hand mount claims the stack and the shell then mounts nothing for it, so a form shows one pair wherever it chose to put it. Binds ⌘Z / ⇧⌘Z (and Ctrl+Y) except while the caret is in a field, where the browser's own undo wins. `WindowManager` already mounts one per window, scoped with `windowId` so a keypress reaches only the frontmost window; pass `windowId` yourself for any provider you mount outside a `<Modal>`, or two open windows will step back together. Offered to anyone who may edit the record — gate with `canEdit` and/or `perms`; a reader sees no controls and records no history. The shell-level provider cannot know the record's permissions, so a read-only form nests its own `<UndoProvider canEdit={false}>` to shadow it. A provider nested inside a window puts its own pair in the footer on the same footer terms — it joins a footer that is there for other reasons, never creates one or holds it open, and shows nothing on the mobile chrome — but its `canEdit` takes the place of the editing check: the form that nested it has already said whether the record may be edited, so pass `canEdit={isEditing}` (or the lock) rather than leaving the default. |
956
956
  | `Calendar` | Month grid with full keyboard navigation (arrows, Home/End, PageUp/Down) and `role="grid"` semantics. Single or range. Days of the months either side are quieter than the month's own but keep AA contrast: they are dates a person can press. The shared grid behind `DatePicker` and `DateRangePicker`. `weekStartsOn` defaults to the provider locale's first day of the week (`firstDayOfWeek`), Sunday without one. |
957
957
  | `DashboardTemplate`, `DataTablePage`, `FormLayoutPage`, `CheckoutTemplate`, `EmailTemplate`, `ChatTemplate`, `GalleryTemplate`, `AuthScreen`, `ErrorPage` | Zero-prop starter page templates composed from the primitives. |
@@ -1007,7 +1007,7 @@ All exports are named — `import { Modal, ... } from 'efficient-shell'`.
1007
1007
  | `utilityApps`, `documentApps`, `webApps` | Subsets of `bundledApps`. |
1008
1008
  | `Calculator`, `Spreadsheet`, `Weather`, `CurrencyConverter`, `PomodoroTimer`, `TodoList`, `Browser` | Lazy components — use directly in custom registry entries. |
1009
1009
  | `PdfViewer` | Lazy component — the PDF reader on its own, for embedding. See below. |
1010
- | `BUILTIN_APP_INFO` | Per-app metadata for the document/web apps (Spreadsheets, Notepad, Documents, Preview, Files, Browser): display name, independent app version and one-line description. Drives each app's "About" dialog (window title menu → About <App>), which also shows the shell version. |
1010
+ | `BUILTIN_APP_INFO` | Per-app metadata for the document/web apps (Spreadsheets, Notepad, Documents, Preview, Files, Browser): display name, independent app version and one-line description. Drives each app's "About" dialog (window title menu → About <App>), which also shows the shell version. The dialog's words, and each app's description, are the strings catalog's `aboutApp` section; `description` here is its English default. |
1011
1011
 
1012
1012
  #### An embedded PDF — `PdfViewer`
1013
1013
 
@@ -1695,6 +1695,43 @@ const { language, languages, setLanguage } = useShellLanguage();
1695
1695
  except after a language change, when the tab takes its route's title until
1696
1696
  its page mounts and titles it again.
1697
1697
 
1698
+ #### Shipped languages — `efficient-shell/locales/zh-Hans`
1699
+
1700
+ The shell ships its own catalogue for Simplified Chinese (mainland usage), so
1701
+ its window controls, pagers and dialogs read the same in every host:
1702
+
1703
+ ```tsx
1704
+ import { zhHansStrings } from 'efficient-shell/locales/zh-Hans';
1705
+
1706
+ <ShellLanguageProvider languages={LANGUAGES} language="zh-Hans" strings={zhHansStrings()}>
1707
+ <App />
1708
+ </ShellLanguageProvider>
1709
+
1710
+ // or, without the language provider:
1711
+ <ShellStringsProvider value={zhHansStrings()} locale="zh-Hans">…</ShellStringsProvider>
1712
+ ```
1713
+
1714
+ - **It is a draft.** No native speaker has reviewed it yet.
1715
+ `ZH_HANS_REVIEWED_SECTIONS` (same subpath) lists the catalogue sections one
1716
+ has signed off, and it is empty: the whole catalogue is draft. The shell only
1717
+ reports this; whether to offer the language meanwhile is the host's call.
1718
+ - **It is the whole catalogue.** `zhHansStrings(locale = 'zh-Hans')` returns a
1719
+ complete `ShellStrings`, the word-order entries included, so no key falls
1720
+ back to English. Its counts are written in `locale`. A key you want said
1721
+ differently is one spread away: `{ ...zh, dialog: { ...zh.dialog, ok: '好' } }`.
1722
+ - **A caller's words are spaced the Chinese way.** A label or a name you pass
1723
+ in is closed up against Chinese and set off by a space when it is Latin
1724
+ (`复制采购订单号`, `复制 SO-0041`), so a host part-way through its own
1725
+ translation reads correctly in both.
1726
+ - **What stays in Latin letters** is notation: file formats (`PDF`, `CSV`,
1727
+ `DXF`), key names (`Esc`, `Enter`), units, the drawing panel's commands and
1728
+ package names.
1729
+ - **Nothing loads it by accident.** The subpath is its own entry with no React
1730
+ and no peer, safe to call from server code, and neither `efficient-shell` nor
1731
+ `efficient-shell/ui` imports it: a host that offers one language downloads
1732
+ none of it. `createShellI18n` (below) fetches it with a dynamic import when
1733
+ `zh-Hans` is activated.
1734
+
1698
1735
  #### Your own copy — `efficient-shell/i18n`
1699
1736
 
1700
1737
  The catalog above is the shell's words. A host's own copy (its column
@@ -1712,7 +1749,7 @@ import orders from '../locales/en/orders.json';
1712
1749
  export const { i18n, t, activate } = createShellI18n({
1713
1750
  copy: { common, orders }, // English, bundled
1714
1751
  load: language => import(`../locales/${language}/index.ts`).then(m => m.default),
1715
- loadShellStrings: language => SHELL_CATALOGS[language]?.(), // the shell's own words
1752
+ // loadShellStrings: omitted, the shell loads the catalogue it ships for the language
1716
1753
  });
1717
1754
  ```
1718
1755
 
@@ -1731,6 +1768,12 @@ const { default: App } = await import('./App');
1731
1768
  together, then switches `t`. A key the language lacks falls back to the
1732
1769
  source language. If either load fails the page stays in the source language
1733
1770
  and the result says `failed: true`; it never rejects into a blank page.
1771
+ - **The shell's catalogue comes by default.** With no `loadShellStrings`,
1772
+ `activate` loads the catalogue the shell ships for the language
1773
+ (`efficient-shell/locales/zh-Hans`, lazily) and hands it back as
1774
+ `activation.strings`; a language the shell does not ship activates with
1775
+ `strings: undefined` and the shell's own words stay in English. Pass
1776
+ `loadShellStrings` to supply your own instead: it wins.
1734
1777
  - **Import the app after `activate`.** Module-level constants call `t` when
1735
1778
  they are imported and keep what it said, so copy read before `activate` stays
1736
1779
  in the source language for the life of the page. `activate` reports that on
@@ -1750,15 +1793,35 @@ and event names (`sounds`). Their own props — `submitLabel`, `doneLabel`, the
1750
1793
  PDF button's `label`, a list's `errorTitle` — still win, and the keys a sound
1751
1794
  scheme is stored under are identifiers, never translated.
1752
1795
 
1796
+ **The status and file surfaces are in the catalog too.**
1797
+ `ServerStatusIndicator`'s tooltip and card (`serverStatus`), `BulkImportGrid`
1798
+ with its column mapper and both duplicate reviews (`bulkImport`), the Preview
1799
+ window (`preview`) with its drawing panel and command bar (`drawing`) and its
1800
+ 3D panel (`model`), `ImageAnnotator` (`annotator`), what `openAttachment` says
1801
+ when a stored file cannot be shown in a window (`attachment`) and a bundled
1802
+ app's About dialog (`aboutApp`). The PDF panel was already `pdf`. A caller's own
1803
+ words still win: the bulk grid's `description`, a staged `convertingMessage`,
1804
+ `openAttachment`'s `loadingMessage`, a fetch error's own message. The times on
1805
+ the status card and the totals over the bulk grid are written in `locale`, and
1806
+ exactly as before without one.
1807
+
1753
1808
  **What is not in the catalog, on purpose:** month and weekday names (the
1754
1809
  `locale` supplies them); file-format names in `BrandAssetEditor`'s default
1755
1810
  `acceptHint` and the `20ft`/`40ft` container codes (notation, not language); the
1756
1811
  `Kbd` shortcut constants (key symbols); `STAGES` labels (data a consumer's own
1757
1812
  tables read); the sample content of the starter templates (`DashboardTemplate`,
1758
1813
  `AuthScreen` and the rest are demos to copy, not components to configure); and
1759
- console warnings, which are for developers.
1760
-
1761
- **The full catalog** — 56 sections, 525 keys. A function's default is shown
1814
+ console warnings, which are for developers. In the Preview window the same
1815
+ goes for file extensions and the two optional packages' names, the drawing
1816
+ panel's command names (`DI`, `DIM`, `H`, `V`, `Z`, `LA`: what is typed is the
1817
+ same in every language) and its `ΔX`/`ΔY`, the axis letters and `⊥` of the 3D
1818
+ panel, a measurement's unit (`18.56 mm`, `1.250 m`) and the status card's
1819
+ latency (`42 ms`), a colour swatch's hex code, and the names of the files a
1820
+ snapshot or an annotated image is saved under. A bundled app's NAME is its
1821
+ window-registry label and is not in the catalog either; its one-line
1822
+ description is.
1823
+
1824
+ **The full catalog** — 64 sections, 781 keys. A function's default is shown
1762
1825
  with sample arguments.
1763
1826
 
1764
1827
  <details><summary><code>window</code> — 17 keys</summary>
@@ -2678,6 +2741,318 @@ with sample arguments.
2678
2741
 
2679
2742
  </details>
2680
2743
 
2744
+ <details><summary><code>serverStatus</code> — 27 keys</summary>
2745
+
2746
+ | Key | Type | English default |
2747
+ |---|---|---|
2748
+ | `connected` | `string` | `Connected` |
2749
+ | `disconnected` | `string` | `Disconnected` |
2750
+ | `checking` | `string` | `Checking…` |
2751
+ | `lastOkTitle` | `(status: string, time: string) => string` | `{status} · last ok {time}` |
2752
+ | `details` | `string` | `Server connection details` |
2753
+ | `lastPoll` | `(ago: string) => string` | `Last poll {ago}.` |
2754
+ | `lastFailure` | `(ago: string) => string` | `Last failure {ago}.` |
2755
+ | `firstPoll` | `string` | `First poll in flight…` |
2756
+ | `server` | `string` | `Server` |
2757
+ | `protocol` | `string` | `Protocol` |
2758
+ | `browser` | `string` | `Browser` |
2759
+ | `online` | `string` | `Online` |
2760
+ | `offline` | `string` | `Offline` |
2761
+ | `lastOk` | `string` | `Last OK` |
2762
+ | `lastFail` | `string` | `Last fail` |
2763
+ | `latency` | `string` | `Latency` |
2764
+ | `poll` | `string` | `Poll` |
2765
+ | `pollEvery` | `(seconds: number) => string` | `every 3 s` |
2766
+ | `session` | `string` | `Session` |
2767
+ | `user` | `string` | `User` |
2768
+ | `notSignedIn` | `string` | `Not signed in` |
2769
+ | `role` | `string` | `Role` |
2770
+ | `build` | `string` | `Build` |
2771
+ | `app` | `string` | `App` |
2772
+ | `userAgent` | `string` | `UA` |
2773
+ | `pingHint` | `string` | `Click ↻ to ping now` |
2774
+ | `refresh` | `string` | `Refresh` |
2775
+
2776
+ </details>
2777
+
2778
+ <details><summary><code>bulkImport</code> — 29 keys</summary>
2779
+
2780
+ | Key | Type | English default |
2781
+ |---|---|---|
2782
+ | `description` | `string` | `Paste from spreadsheets, type directly, or upload a CSV. Rows don't need to be in order — they'll be matched. Values not in the list will be added to the end. Fields left blank will not be affected.` |
2783
+ | `lines` | `(count: number) => string` | `3 lines` |
2784
+ | `total` | `(label: string, value: string) => string` | `{label}: {value}` |
2785
+ | `clear` | `string` | `Clear` |
2786
+ | `upload` | `string` | `Upload CSV` |
2787
+ | `importLines` | `(count: number) => string` | `Import 3 Lines` |
2788
+ | `importing` | `string` | `Importing...` |
2789
+ | `importFailed` | `string` | `Import failed.` |
2790
+ | `enterAtLeastOne` | `(noun: string, title: string) => string` | `Enter at least one {noun}.` (`Enter at least one value.` with no title) |
2791
+ | `allSkipped` | `string` | `All rows skipped.` |
2792
+ | `cancel` | `string` | `Cancel` |
2793
+ | `mapTitle` | `string` | `Map CSV columns to fields` |
2794
+ | `skip` | `string` | `— Skip —` |
2795
+ | `columnOption` | `(column: number, sample: string) => string` | `Column 3 (e.g. {sample})` |
2796
+ | `rowsDetected` | `(count: number) => string` | `3 rows detected` |
2797
+ | `confirmMapping` | `string` | `Confirm Mapping` |
2798
+ | `duplicatesTitle` | `string` | `Duplicate entries detected` |
2799
+ | `duplicatesFound` | `(count: number) => string` | `3 values appear more than once in your import. Choose how to handle each before proceeding.` (`1 value appears…` for one) |
2800
+ | `occurrences` | `(count: number) => string` | `3 occurrences` |
2801
+ | `keepFirst` | `string` | `Keep first` |
2802
+ | `keepLast` | `string` | `Keep last` |
2803
+ | `keepAll` | `string` | `Keep all` |
2804
+ | `skipAll` | `string` | `Skip all` |
2805
+ | `keptDropped` | `(kept: number, dropped: number) => string` | `3 kept · 3 dropped` |
2806
+ | `proceed` | `string` | `Proceed` |
2807
+ | `duplicatesMerged` | `(count: number) => string` | `3 values appeared more than once. Each is merged into a single line with its quantity summed — review before proceeding.` (`1 value appeared…` for one) |
2808
+ | `mergedFrom` | `string` | `Merged from` |
2809
+ | `mergedRows` | `(count: number) => string` | `3 rows` |
2810
+ | `mergeSummary` | `(rows: number, lines: number) => string` | `3 duplicate rows → 3 merged lines` (`… → 1 merged line` for one) |
2811
+
2812
+ </details>
2813
+
2814
+ <details><summary><code>preview</code> — 29 keys</summary>
2815
+
2816
+ | Key | Type | English default |
2817
+ |---|---|---|
2818
+ | `windowTitle` | `(name: string) => string` | `{name} - Preview` |
2819
+ | `untitled` | `string` | `Untitled` |
2820
+ | `open` | `string` | `Open` |
2821
+ | `formats` | `string` | `PDF · DXF · 3D · Images` |
2822
+ | `dropHere` | `(open: string) => string` | `Drop a file here, or click {open}.` |
2823
+ | `supportedFormats` | `string` | `Supported formats` |
2824
+ | `formatPdf` | `string` | `multi-page document viewer` |
2825
+ | `formatDxf` | `(packageName: string) => string` | `vector CAD drawings (optional {packageName} peer dep)` |
2826
+ | `format3d` | `(packageName: string) => string` | `3D models (optional {packageName} peer dep)` |
2827
+ | `formatImage` | `string` | `raster images` |
2828
+ | `dwgNote` | `string` | `DWG files need to be converted to PDF or DXF first (server-side).` |
2829
+ | `dropToOpen` | `string` | `Drop to open` |
2830
+ | `dwgUnsupported` | `string` | `DWG files need server-side conversion. Convert to PDF or DXF first.` |
2831
+ | `unsupportedType` | `(extension: string) => string` | `Unsupported file type: .{extension}` (`.unknown` with none) |
2832
+ | `converting` | `string` | `Converting file` |
2833
+ | `download` | `string` | `Download` |
2834
+ | `email` | `string` | `Email` |
2835
+ | `howToNavigate` | `string` | `How to navigate` |
2836
+ | `stopMeasuring` | `string` | `Stop measuring (Esc)` |
2837
+ | `scrollToZoom` | `string` | `Scroll to zoom` |
2838
+ | `closePanel` | `string` | `Close` |
2839
+ | `annotate` | `string` | `Annotate` |
2840
+ | `annotateHint` | `string` | `Annotate this image` |
2841
+ | `view` | `string` | `View` |
2842
+ | `viewHint` | `string` | `Back to viewer` |
2843
+ | `copy` | `string` | `Copy` |
2844
+ | `save` | `string` | `Save` |
2845
+ | `imageFailed` | `string` | `Failed to load image.` |
2846
+ | `downloadFailed` | `string` | `Download failed — couldn't reach the file.` |
2847
+
2848
+ </details>
2849
+
2850
+ <details><summary><code>drawing</code> — 49 keys</summary>
2851
+
2852
+ | Key | Type | English default |
2853
+ |---|---|---|
2854
+ | `loading` | `string` | `Loading drawing…` |
2855
+ | `notInstalled` | `string` | `dxf-viewer is not installed in this app.` |
2856
+ | `renderFailed` | `string` | `Failed to render DXF.` |
2857
+ | `layers` | `string` | `Layers` |
2858
+ | `layersHint` | `string` | `Toggle layer visibility` |
2859
+ | `allLayers` | `string` | `All` |
2860
+ | `noLayers` | `string` | `None` |
2861
+ | `measure` | `string` | `Measure` |
2862
+ | `measureHint` | `string` | `Measure distance — click two points on the drawing, or type DI / DIM below` |
2863
+ | `auto` | `string` | `Auto` |
2864
+ | `autoHint` | `string` | `Auto — AutoCAD DIMLINEAR: measures ΔX or ΔY, whichever is larger between the two picks` |
2865
+ | `horizontalHint` | `string` | `Horizontal — distance along the X axis between two picks (AutoCAD DIMLINEAR horizontal)` |
2866
+ | `verticalHint` | `string` | `Vertical — distance along the Y axis between two picks (AutoCAD DIMLINEAR vertical)` |
2867
+ | `point` | `string` | `Point` |
2868
+ | `pointHint` | `string` | `Point — straight-line (Euclidean) distance between two picks (AutoCAD DIST)` |
2869
+ | `fixX` | `string` | `fix Δx` |
2870
+ | `fixY` | `string` | `fix Δy` |
2871
+ | `fixHint` | `string` | `Lock the second pick's axis coord to first pick + this value (mm). The reported measurement becomes the perpendicular distance.` |
2872
+ | `clearFixed` | `string` | `Clear fixed distance` |
2873
+ | `horizontalDistance` | `(auto: boolean) => string` | `Horizontal distance (Δx) between the two picked points` (plus ` — Auto resolved to the X axis` when `auto`) |
2874
+ | `verticalDistance` | `(auto: boolean) => string` | `Vertical distance (Δy) between the two picked points` (plus ` — Auto resolved to the Y axis` when `auto`) |
2875
+ | `straightDistance` | `string` | `Straight-line distance between the two picked points` |
2876
+ | `fit` | `string` | `Fit` |
2877
+ | `fitHint` | `string` | `Fit drawing to view` |
2878
+ | `dragToPan` | `string` | `Drag to pan` |
2879
+ | `fitToReset` | `string` | `Fit to reset` |
2880
+ | `typeToMeasure` | `(commands: string) => string` | `Type {commands} to measure` |
2881
+ | `commandPlaceholder` | `string` | `Type a command — DI, DIM, H, V, Z, LA (? for help)` |
2882
+ | `commandHelp` | `string` | `Commands: DI distance · DIM/DLI linear dim · H / V force axis · <number> lock Δ · U undo pick · Z fit · LA layers · Esc exit` |
2883
+ | `echoDistance` | `(distance: string, deltaX: string, deltaY: string) => string` | `Distance = {distance} ΔX = {deltaX} ΔY = {deltaY}` |
2884
+ | `echoLinear` | `(distance: string, axis: string) => string` | `Linear dimension = {distance} ({axis})` |
2885
+ | `echoLocked` | `(axis: string, distance: string, lockedAxis: string, locked: string) => string` | `{axis} = {distance} with {lockedAxis} locked to {locked}` |
2886
+ | `axisLocked` | `(axis: string, distance: string) => string` | `{axis} locked to {distance} — the label shows the perpendicular distance` |
2887
+ | `fixedCleared` | `string` | `Fixed distance cleared.` |
2888
+ | `fixedNeedsAxis` | `string` | `Fixed distances apply in H or V mode — type H or V first.` |
2889
+ | `echoDist` | `string` | `DIST — click two points; straight-line distance (Esc to exit)` |
2890
+ | `echoDimLinear` | `string` | `DIMLINEAR — click two points; measures ΔX or ΔY, whichever is larger (H / V to force)` |
2891
+ | `echoHorizontal` | `string` | `Horizontal — ΔX between the two picks` |
2892
+ | `echoVertical` | `string` | `Vertical — ΔY between the two picks` |
2893
+ | `echoAuto` | `string` | `Auto (DIMLINEAR) — measures along the dominant axis of the two picks` |
2894
+ | `measureOn` | `string` | `Measure on — click two points.` |
2895
+ | `measureOff` | `string` | `Measure off.` |
2896
+ | `pickRemoved` | `string` | `Last pick removed.` |
2897
+ | `zoomExtents` | `string` | `Zoom extents.` |
2898
+ | `layersToggled` | `string` | `Layer panel toggled.` |
2899
+ | `measurementCleared` | `string` | `Measurement cleared.` |
2900
+ | `readOnly` | `(command: string) => string` | `{command} is a drawing command — Preview is a read-only viewer. Measuring: DI, DIM, H, V (? for help)` |
2901
+ | `unknownCommand` | `(command: string) => string` | `Unknown command "{command}" — try DI, DIM, H, V, Z, LA (? for help)` |
2902
+ | `cancelled` | `string` | `*Cancel*` |
2903
+
2904
+ </details>
2905
+
2906
+ <details><summary><code>model</code> — 53 keys</summary>
2907
+
2908
+ | Key | Type | English default |
2909
+ |---|---|---|
2910
+ | `loading` | `string` | `Loading 3D model…` |
2911
+ | `stepNote` | `string` | `STEP files load OpenCascade WASM (~5 MB) on first use.` |
2912
+ | `notInstalled` | `string` | `online-3d-viewer is not installed in this app. Add it to enable 3D file viewing.` |
2913
+ | `loadFailed` | `string` | `Failed to load 3D model.` |
2914
+ | `rootNode` | `string` | `Root` |
2915
+ | `node` | `string` | `Node` |
2916
+ | `collapse` | `string` | `Collapse` |
2917
+ | `expand` | `string` | `Expand` |
2918
+ | `fitToView` | `string` | `Fit to view` |
2919
+ | `hide` | `string` | `Hide` |
2920
+ | `show` | `string` | `Show` |
2921
+ | `isometric` | `string` | `ISO` |
2922
+ | `isometricView` | `string` | `Isometric view` |
2923
+ | `top` | `string` | `TOP` |
2924
+ | `topView` | `string` | `Top view` |
2925
+ | `front` | `string` | `FRT` |
2926
+ | `frontView` | `string` | `Front view` |
2927
+ | `side` | `string` | `SDE` |
2928
+ | `sideView` | `string` | `Side view` |
2929
+ | `perspective` | `string` | `Perspective` |
2930
+ | `orthographic` | `string` | `Orthographic` |
2931
+ | `toPerspective` | `string` | `Switch to perspective view` |
2932
+ | `toOrthographic` | `string` | `Switch to orthographic view` |
2933
+ | `snapshot` | `string` | `Save snapshot as PNG` |
2934
+ | `measureHint` | `string` | `Measure distance — click two points on the model` |
2935
+ | `point` | `string` | `Point` |
2936
+ | `pointHint` | `string` | `Point — measure straight-line distance between two picked points` |
2937
+ | `perpendicularHint` | `string` | `Perpendicular — pick two surfaces and measure the perpendicular gap between them` |
2938
+ | `straightDistance` | `string` | `Straight-line distance between the two picked points` |
2939
+ | `perpendicularDistance` | `string` | `Perpendicular distance between the two picked surfaces` |
2940
+ | `meshesHint` | `string` | `Toggle meshes panel` |
2941
+ | `displayHint` | `string` | `Toggle display panel` |
2942
+ | `downloadOriginal` | `string` | `Download original file` |
2943
+ | `meshes` | `string` | `Meshes` |
2944
+ | `readingModel` | `string` | `Reading model…` |
2945
+ | `noStructure` | `string` | `No structure available` |
2946
+ | `allVisible` | `string` | `All visible` |
2947
+ | `hiddenCount` | `(count: number) => string` | `3 hidden` |
2948
+ | `dragToRotate` | `string` | `Drag to rotate` |
2949
+ | `rightDragToPan` | `string` | `Right-click drag to pan` |
2950
+ | `display` | `string` | `Model Display` |
2951
+ | `backgroundColor` | `string` | `Background Color` |
2952
+ | `showEdges` | `string` | `Show Edges` |
2953
+ | `edgeColor` | `string` | `Edge Color` |
2954
+ | `edgeThreshold` | `string` | `Edge Threshold` |
2955
+ | `sectionView` | `string` | `Section View` |
2956
+ | `angle` | `string` | `Angle` |
2957
+ | `axis` | `string` | `Axis` |
2958
+ | `flipHint` | `string` | `Flip section direction` |
2959
+ | `flip` | `string` | `flip →` |
2960
+ | `flipped` | `string` | `← flipped` |
2961
+ | `position` | `string` | `Position` |
2962
+ | `resetDisplay` | `string` | `Reset to Default` |
2963
+
2964
+ </details>
2965
+
2966
+ <details><summary><code>annotator</code> — 52 keys</summary>
2967
+
2968
+ | Key | Type | English default |
2969
+ |---|---|---|
2970
+ | `toolSelect` | `string` | `Select / Move` |
2971
+ | `toolDraw` | `string` | `Pen / Draw` |
2972
+ | `toolRect` | `string` | `Rectangle` |
2973
+ | `toolEllipse` | `string` | `Ellipse` |
2974
+ | `toolArrow` | `string` | `Arrow` |
2975
+ | `toolMosaic` | `string` | `Mosaic` |
2976
+ | `toolText` | `string` | `Text` |
2977
+ | `toolCrop` | `string` | `Crop` |
2978
+ | `weight` | `string` | `Weight` |
2979
+ | `radius` | `string` | `Radius` |
2980
+ | `size` | `string` | `Size` |
2981
+ | `padding` | `string` | `Pad` |
2982
+ | `fontSystem` | `string` | `System` |
2983
+ | `fontSerif` | `string` | `Serif` |
2984
+ | `fontMono` | `string` | `Mono` |
2985
+ | `fontCursive` | `string` | `Cursive` |
2986
+ | `bold` | `string` | `Bold` |
2987
+ | `boldLetter` | `string` | `B` |
2988
+ | `italic` | `string` | `Italic` |
2989
+ | `italicLetter` | `string` | `I` |
2990
+ | `underline` | `string` | `Underline` |
2991
+ | `underlineLetter` | `string` | `U` |
2992
+ | `border` | `string` | `Border` |
2993
+ | `borderColor` | `string` | `Text-box border color` |
2994
+ | `addBorder` | `string` | `Add a border` |
2995
+ | `removeBorder` | `string` | `Remove border` |
2996
+ | `fill` | `string` | `Fill` |
2997
+ | `fillColor` | `string` | `Text-box background color` |
2998
+ | `addFill` | `string` | `Add a background fill` |
2999
+ | `removeFill` | `string` | `Remove fill` |
3000
+ | `add` | `string` | `Add` |
3001
+ | `zoomOut` | `string` | `Zoom out` |
3002
+ | `zoomIn` | `string` | `Zoom in` |
3003
+ | `fit` | `string` | `Fit` |
3004
+ | `fitHint` | `string` | `Fit to area` |
3005
+ | `undo` | `string` | `Undo` |
3006
+ | `applyCrop` | `string` | `Apply Crop` |
3007
+ | `cancel` | `string` | `Cancel` |
3008
+ | `apply` | `string` | `Apply` |
3009
+ | `hintSelected` | `string` | `Drag to move. Drag a corner to resize. Delete / Backspace removes. Click outside to deselect.` |
3010
+ | `hintSelect` | `string` | `Tap a shape to select. Double-click text to edit.` |
3011
+ | `hintText` | `string` | `Click to drop a text label.` |
3012
+ | `hintCrop` | `string` | `Drag a rectangle to set the crop region.` |
3013
+ | `hintDraw` | `string` | `Drag to draw freehand.` |
3014
+ | `hintShape` | `string` | `Drag on the image to draw.` |
3015
+ | `textPlaceholder` | `string` | `Type then Enter…` |
3016
+ | `loadFailed` | `string` | `Failed to load image` |
3017
+ | `exportFailed` | `string` | `Failed to export` |
3018
+ | `clipboardUnsupported` | `string` | `Clipboard images not supported in this browser` |
3019
+ | `copyFailed` | `string` | `Failed to copy` |
3020
+ | `copied` | `string` | `Copied to clipboard` |
3021
+ | `copyRefused` | `string` | `Copy failed (clipboard permission?)` |
3022
+
3023
+ </details>
3024
+
3025
+ <details><summary><code>attachment</code> — 7 keys</summary>
3026
+
3027
+ | Key | Type | English default |
3028
+ |---|---|---|
3029
+ | `fallbackName` | `string` | `attachment` |
3030
+ | `noLink` | `string` | `This attachment has no download link.` |
3031
+ | `spreadsheetFailed` | `string` | `Could not open the spreadsheet — opening the file instead.` |
3032
+ | `workbookUnavailable` | `string` | `Spreadsheet preview is unavailable for this file type. Opening the file instead.` |
3033
+ | `noViewer` | `string` | `Opening this file outside the app — no viewer can show it here.` |
3034
+ | `loading` | `string` | `LOADING FILE` |
3035
+ | `loadFailed` | `string` | `Failed to load this file.` |
3036
+
3037
+ </details>
3038
+
3039
+ <details><summary><code>aboutApp</code> — 10 keys</summary>
3040
+
3041
+ | Key | Type | English default |
3042
+ |---|---|---|
3043
+ | `title` | `(name: string) => string` | `About {name}` |
3044
+ | `version` | `(version: string) => string` | `Version {version}` |
3045
+ | `partOf` | `(shell: string) => string` | `Part of the {shell} desktop environment` |
3046
+ | `shellVersion` | `(version: string) => string` | `shell v{version}` |
3047
+ | `spreadsheet` | `string` | `Multi-sheet spreadsheet editor with CSV / TSV import and export.` |
3048
+ | `notepad` | `string` | `Color-coded notes with checklists, desktop stickies and entity autolinking.` |
3049
+ | `documents` | `string` | `Letter-page editor for Word documents and plain-text files — images, lists, alignment.` |
3050
+ | `preview` | `string` | `Viewer for PDF documents, images, DXF drawings and 3D models — CAD-style measuring with object snap and an AutoCAD-like command bar.` |
3051
+ | `files` | `string` | `Personal file manager with folders, uploads, quota, trash and desktop shortcut folders.` |
3052
+ | `browser` | `string` | `Minimal web browser with bookmarks, history and navigation bar.` |
3053
+
3054
+ </details>
3055
+
2681
3056
  ### Brand surfaces — `efficient-shell/brand.css`
2682
3057
 
2683
3058
  For output that is not a portal window — a report, a published artifact, a
@@ -1,29 +1,29 @@
1
- import{peekBrowserStartUrl as e,claimBrowserStartUrl as t}from"./chunk-LWLCNQY7.js";import{AboutApp as o}from"./chunk-4PCIZFDR.js";import{WindowTitle as r}from"./chunk-TZ2BPFCT.js";import"./chunk-DSSLOQDW.js";import"./chunk-ZOPYAOUP.js";import"./chunk-MFXG5BWL.js";import"./chunk-YJRC6IKD.js";import"./chunk-5A7MWTXX.js";import"./chunk-OGXU7QFW.js";import{confirm as n}from"./chunk-XJYXKO7K.js";import"./chunk-AA4TMQOS.js";import"./chunk-AFYQTVZO.js";import"./chunk-HZZNJHRH.js";import"./chunk-X4FJ54PP.js";import"./chunk-D65T4H6J.js";import"./chunk-3YTHR7IC.js";import"./chunk-YKZHOXI4.js";import{useRef as a,useEffect as i,useState as s}from"react";import{jsxs as l,jsx as c,Fragment as m}from"react/jsx-runtime";var d="react-os-shell:browser-bookmarks",u="react-os-shell:browser-homepage",h="https://en.wikipedia.org/wiki/Main_Page",p=[{label:"Wikipedia",url:"https://en.wikipedia.org/wiki/Main_Page"},{label:"DevDocs",url:"https://devdocs.io"},{label:"Example",url:"https://example.com"}],g=new Set(["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","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","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","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","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","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","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","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","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","ua ug uk us uy uz va vc ve vg vi vn vu wf ws ye yt za zm zw","com net org edu gov mil int info biz name pro app dev xyz online site tech","store shop cloud design digital agency studio media news blog live life","world today email systems solutions services software page link space host","press wiki team group works careers finance capital energy academy"].join(" ").split(" "));function b(e){let t=e.trim();return t?/^[a-z][a-z0-9+.-]*:\/\//i.test(t)?t:function(e){const t=/^([\w-]+\.)+([a-z]{2,})(\/.*)?$/i.exec(e);return null!==t&&g.has(t[2].toLowerCase())}(t)?"https://"+t:"https://duckduckgo.com/?q="+encodeURIComponent(t):""}var k=["duckduckgo.com","developer.mozilla.org","google.com","gmail.com","youtube.com","facebook.com","instagram.com","whatsapp.com","twitter.com","x.com","github.com","gitlab.com","linkedin.com","reddit.com","pinterest.com","amazon.com","amazon.ca","amazon.co.uk","apple.com","icloud.com","microsoft.com","outlook.com","live.com","office.com","netflix.com","spotify.com","paypal.com","stripe.com","chat.openai.com","chatgpt.com","claude.ai"];function f(){if("undefined"==typeof window)return p;try{const e=localStorage.getItem(d);if(!e)return p;const t=JSON.parse(e);if(Array.isArray(t)&&t.every(e=>"string"==typeof e?.url))return t}catch{}return p}function x(){return"undefined"==typeof window?h:localStorage.getItem(u)||h}function w(){const m=a(void 0);void 0===m.current&&(m.current=e()),i(()=>{null!=m.current&&t(m.current)},[]);const h=m.current?b(m.current.url):"",[p,g]=s(x),[k,w]=s(h||p),[N,L]=s(k),[C,j]=s([k]),[z,M]=s(0),[W,H]=s(0),[R,S]=s(f),[A,B]=s(!1),[O,T]=s(null),D=a(null),P=a(null);i(()=>{try{localStorage.setItem(d,JSON.stringify(R))}catch{}},[R]);const E=e=>{const t=b(e);t&&(w(t),L(t),j(e=>{const o=e.slice(0,z+1);return o.push(t),o}),M(e=>e+1),B(!1))},F=()=>{"undefined"!=typeof window&&window.open(k,"_blank","noopener,noreferrer")},I=()=>{const e=O?.trim();e?(S(t=>[...t,{label:e,url:k}]),T(null)):T(null)};i(()=>{if(null===O)return;D.current?.focus(),D.current?.select();const e=e=>{const t=e.target;t?.closest("[data-bookmark-popover]")||T(null)},t=setTimeout(()=>document.addEventListener("mousedown",e),0);return()=>{clearTimeout(t),document.removeEventListener("mousedown",e)}},[null!==O]);const X=e=>{S(t=>t.filter((t,o)=>o!==e))},U=z>0,J=z<C.length-1,K=R.some(e=>e.url===k),Y="p-1.5 rounded hover:bg-gray-200 transition-colors text-gray-600 disabled:opacity-30";/* @__PURE__ */
1
+ import{peekBrowserStartUrl as e,claimBrowserStartUrl as t}from"./chunk-LWLCNQY7.js";import{AboutApp as o}from"./chunk-CZK2VKIO.js";import{WindowTitle as r}from"./chunk-N6STBYXR.js";import"./chunk-DSSLOQDW.js";import"./chunk-KVOFUFPP.js";import"./chunk-AZURXTRB.js";import"./chunk-CIXQKCFA.js";import"./chunk-5A7MWTXX.js";import"./chunk-OGXU7QFW.js";import{confirm as n}from"./chunk-ZAE6ROV7.js";import"./chunk-AA4TMQOS.js";import"./chunk-AFYQTVZO.js";import"./chunk-HZZNJHRH.js";import"./chunk-X4FJ54PP.js";import"./chunk-D65T4H6J.js";import"./chunk-J3LIIIHJ.js";import"./chunk-C3QOHMR6.js";import"./chunk-YKZHOXI4.js";import{useRef as a,useEffect as i,useState as s}from"react";import{jsxs as l,jsx as c,Fragment as m}from"react/jsx-runtime";var d="react-os-shell:browser-bookmarks",u="react-os-shell:browser-homepage",h="https://en.wikipedia.org/wiki/Main_Page",p=[{label:"Wikipedia",url:"https://en.wikipedia.org/wiki/Main_Page"},{label:"DevDocs",url:"https://devdocs.io"},{label:"Example",url:"https://example.com"}],g=new Set(["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","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","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","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","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","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","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","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","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","ua ug uk us uy uz va vc ve vg vi vn vu wf ws ye yt za zm zw","com net org edu gov mil int info biz name pro app dev xyz online site tech","store shop cloud design digital agency studio media news blog live life","world today email systems solutions services software page link space host","press wiki team group works careers finance capital energy academy"].join(" ").split(" "));function b(e){let t=e.trim();return t?/^[a-z][a-z0-9+.-]*:\/\//i.test(t)?t:function(e){const t=/^([\w-]+\.)+([a-z]{2,})(\/.*)?$/i.exec(e);return null!==t&&g.has(t[2].toLowerCase())}(t)?"https://"+t:"https://duckduckgo.com/?q="+encodeURIComponent(t):""}var k=["duckduckgo.com","developer.mozilla.org","google.com","gmail.com","youtube.com","facebook.com","instagram.com","whatsapp.com","twitter.com","x.com","github.com","gitlab.com","linkedin.com","reddit.com","pinterest.com","amazon.com","amazon.ca","amazon.co.uk","apple.com","icloud.com","microsoft.com","outlook.com","live.com","office.com","netflix.com","spotify.com","paypal.com","stripe.com","chat.openai.com","chatgpt.com","claude.ai"];function f(){if("undefined"==typeof window)return p;try{const e=localStorage.getItem(d);if(!e)return p;const t=JSON.parse(e);if(Array.isArray(t)&&t.every(e=>"string"==typeof e?.url))return t}catch{}return p}function x(){return"undefined"==typeof window?h:localStorage.getItem(u)||h}function w(){const m=a(void 0);void 0===m.current&&(m.current=e()),i(()=>{null!=m.current&&t(m.current)},[]);const h=m.current?b(m.current.url):"",[p,g]=s(x),[k,w]=s(h||p),[N,L]=s(k),[j,C]=s([k]),[z,M]=s(0),[R,H]=s(0),[S,W]=s(f),[A,O]=s(!1),[B,I]=s(null),T=a(null),E=a(null);i(()=>{try{localStorage.setItem(d,JSON.stringify(S))}catch{}},[S]);const D=e=>{const t=b(e);t&&(w(t),L(t),C(e=>{const o=e.slice(0,z+1);return o.push(t),o}),M(e=>e+1),O(!1))},F=()=>{"undefined"!=typeof window&&window.open(k,"_blank","noopener,noreferrer")},X=()=>{const e=B?.trim();e?(W(t=>[...t,{label:e,url:k}]),I(null)):I(null)};i(()=>{if(null===B)return;T.current?.focus(),T.current?.select();const e=e=>{const t=e.target;t?.closest("[data-bookmark-popover]")||I(null)},t=setTimeout(()=>document.addEventListener("mousedown",e),0);return()=>{clearTimeout(t),document.removeEventListener("mousedown",e)}},[null!==B]);const P=e=>{W(t=>t.filter((t,o)=>o!==e))},U=z>0,V=z<j.length-1,K=S.some(e=>e.url===k),J="p-1.5 rounded hover:bg-gray-200 transition-colors text-gray-600 disabled:opacity-30";/* @__PURE__ */
2
2
  return l("div",{className:"relative flex flex-col h-full bg-white",children:[
3
3
  /* @__PURE__ */c(r,{title:`Browser - ${v(k)}`}),
4
4
  /* @__PURE__ */c(o,{app:"browser"}),
5
5
  /* @__PURE__ */l("div",{className:"flex items-center gap-1 px-2 py-1.5 border-b border-gray-200 bg-gray-50 shrink-0",children:[
6
- /* @__PURE__ */c("button",{onClick:()=>{if(z>0){const e=z-1;M(e),w(C[e]),L(C[e]),B(!1)}},disabled:!U,className:Y,title:"Back",children:/* @__PURE__ */c("svg",{className:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:/* @__PURE__ */c("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.75 19.5L8.25 12l7.5-7.5"})})}),
7
- /* @__PURE__ */c("button",{onClick:()=>{if(z<C.length-1){const e=z+1;M(e),w(C[e]),L(C[e]),B(!1)}},disabled:!J,className:Y,title:"Forward",children:/* @__PURE__ */c("svg",{className:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:/* @__PURE__ */c("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M8.25 4.5l7.5 7.5-7.5 7.5"})})}),
8
- /* @__PURE__ */c("button",{onClick:()=>H(e=>e+1),className:Y,title:"Refresh",children:/* @__PURE__ */c("svg",{className:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:/* @__PURE__ */c("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"})})}),
9
- /* @__PURE__ */c("button",{onClick:()=>E(p),className:Y,title:"Home",children:/* @__PURE__ */c("svg",{className:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:/* @__PURE__ */c("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"})})}),
10
- /* @__PURE__ */c("form",{onSubmit:e=>{e.preventDefault(),E(N)},className:"flex-1 flex items-center mx-1",children:/* @__PURE__ */l("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",children:[
6
+ /* @__PURE__ */c("button",{onClick:()=>{if(z>0){const e=z-1;M(e),w(j[e]),L(j[e]),O(!1)}},disabled:!U,className:J,title:"Back",children:/* @__PURE__ */c("svg",{className:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:/* @__PURE__ */c("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.75 19.5L8.25 12l7.5-7.5"})})}),
7
+ /* @__PURE__ */c("button",{onClick:()=>{if(z<j.length-1){const e=z+1;M(e),w(j[e]),L(j[e]),O(!1)}},disabled:!V,className:J,title:"Forward",children:/* @__PURE__ */c("svg",{className:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:/* @__PURE__ */c("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M8.25 4.5l7.5 7.5-7.5 7.5"})})}),
8
+ /* @__PURE__ */c("button",{onClick:()=>H(e=>e+1),className:J,title:"Refresh",children:/* @__PURE__ */c("svg",{className:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:/* @__PURE__ */c("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"})})}),
9
+ /* @__PURE__ */c("button",{onClick:()=>D(p),className:J,title:"Home",children:/* @__PURE__ */c("svg",{className:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:/* @__PURE__ */c("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"})})}),
10
+ /* @__PURE__ */c("form",{onSubmit:e=>{e.preventDefault(),D(N)},className:"flex-1 flex items-center mx-1",children:/* @__PURE__ */l("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",children:[
11
11
  /* @__PURE__ */c("span",{className:"px-2 text-gray-400 text-xs",children:k.startsWith("https://")?"🔒":"⚠️"}),
12
12
  /* @__PURE__ */c("input",{type:"text",value:N,onChange:e=>L(e.target.value),onFocus:e=>e.target.select(),className:"flex-1 px-1 py-1 text-sm bg-transparent outline-none font-mono",spellCheck:!1,placeholder:"Enter URL or search…"}),k!==N&&/* @__PURE__ */c("button",{type:"button",onClick:()=>L(k),className:"px-1.5 text-[10px] text-gray-400 hover:text-gray-700",title:"Reset to current URL",children:"×"})]})}),
13
- /* @__PURE__ */c("button",{"data-bookmark-popover":!0,onClick:()=>K?X(R.findIndex(e=>e.url===k)):void T(v(k)),className:Y+" "+(K?"text-yellow-500":""),title:K?"Remove bookmark":"Add bookmark",children:/* @__PURE__ */c("svg",{className:"h-4 w-4",fill:K?"currentColor":"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:/* @__PURE__ */c("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"})})}),
14
- /* @__PURE__ */c("button",{onClick:F,className:Y,title:"Open in new tab",children:/* @__PURE__ */c("svg",{className:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:/* @__PURE__ */c("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"})})}),
15
- /* @__PURE__ */c("button",{onClick:()=>B(e=>!e),className:Y,title:"Embedding help",children:/* @__PURE__ */c("svg",{className:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:/* @__PURE__ */c("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"})})})]}),null!==O&&/* @__PURE__ */l("div",{"data-bookmark-popover":!0,className:"absolute right-3 top-12 z-30 w-72 bg-white border border-gray-200 rounded-md shadow-lg p-3",children:[
13
+ /* @__PURE__ */c("button",{"data-bookmark-popover":!0,onClick:()=>K?P(S.findIndex(e=>e.url===k)):void I(v(k)),className:J+" "+(K?"text-yellow-500":""),title:K?"Remove bookmark":"Add bookmark",children:/* @__PURE__ */c("svg",{className:"h-4 w-4",fill:K?"currentColor":"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:/* @__PURE__ */c("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"})})}),
14
+ /* @__PURE__ */c("button",{onClick:F,className:J,title:"Open in new tab",children:/* @__PURE__ */c("svg",{className:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:/* @__PURE__ */c("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"})})}),
15
+ /* @__PURE__ */c("button",{onClick:()=>O(e=>!e),className:J,title:"Embedding help",children:/* @__PURE__ */c("svg",{className:"h-4 w-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:/* @__PURE__ */c("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"})})})]}),null!==B&&/* @__PURE__ */l("div",{"data-bookmark-popover":!0,className:"absolute right-3 top-12 z-30 w-72 bg-white border border-gray-200 rounded-md shadow-lg p-3",children:[
16
16
  /* @__PURE__ */c("div",{className:"text-[11px] font-semibold uppercase tracking-wide text-gray-500 mb-1",children:"Bookmark this page"}),
17
17
  /* @__PURE__ */c("div",{className:"text-[11px] text-gray-400 truncate mb-2 font-mono",title:k,children:k}),
18
- /* @__PURE__ */c("input",{ref:D,type:"text",value:O,onChange:e=>T(e.target.value),onKeyDown:e=>{"Enter"===e.key?I():"Escape"===e.key&&T(null)},placeholder:"Name",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"}),
18
+ /* @__PURE__ */c("input",{ref:T,type:"text",value:B,onChange:e=>I(e.target.value),onKeyDown:e=>{"Enter"===e.key?X():"Escape"===e.key&&I(null)},placeholder:"Name",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"}),
19
19
  /* @__PURE__ */l("div",{className:"flex justify-end gap-1 mt-2",children:[
20
- /* @__PURE__ */c("button",{onClick:()=>T(null),className:"px-2 py-1 text-xs text-gray-600 hover:bg-gray-100 rounded",children:"Cancel"}),
21
- /* @__PURE__ */c("button",{onClick:I,disabled:!O.trim(),className:"px-2 py-1 text-xs bg-blue-500 text-white rounded hover:bg-blue-600 disabled:opacity-40",children:"Save"})]})]}),
22
- /* @__PURE__ */l("div",{className:"flex items-center gap-0.5 px-2 py-1 border-b border-gray-200 bg-white shrink-0 overflow-x-auto",children:[0===R.length&&/* @__PURE__ */c("span",{className:"text-[11px] text-gray-400 italic px-2",children:"No bookmarks yet — star the address bar to add one."}),R.map((e,t)=>/* @__PURE__ */l("button",{onClick:()=>E(e.url),onContextMenu:async o=>{o.preventDefault();await n({title:"Remove bookmark",message:`"${e.label}" will be removed from your bookmarks.`,confirmLabel:"Remove",variant:"danger"})&&X(t)},className:"flex items-center gap-1.5 px-2 py-0.5 rounded text-[12px] text-gray-700 hover:bg-gray-100 whitespace-nowrap",title:`${e.url}\n(right-click to remove)`,children:[
20
+ /* @__PURE__ */c("button",{onClick:()=>I(null),className:"px-2 py-1 text-xs text-gray-600 hover:bg-gray-100 rounded",children:"Cancel"}),
21
+ /* @__PURE__ */c("button",{onClick:X,disabled:!B.trim(),className:"px-2 py-1 text-xs bg-blue-500 text-white rounded hover:bg-blue-600 disabled:opacity-40",children:"Save"})]})]}),
22
+ /* @__PURE__ */l("div",{className:"flex items-center gap-0.5 px-2 py-1 border-b border-gray-200 bg-white shrink-0 overflow-x-auto",children:[0===S.length&&/* @__PURE__ */c("span",{className:"text-[11px] text-gray-400 italic px-2",children:"No bookmarks yet — star the address bar to add one."}),S.map((e,t)=>/* @__PURE__ */l("button",{onClick:()=>D(e.url),onContextMenu:async o=>{o.preventDefault();await n({title:"Remove bookmark",message:`"${e.label}" will be removed from your bookmarks.`,confirmLabel:"Remove",variant:"danger"})&&P(t)},className:"flex items-center gap-1.5 px-2 py-0.5 rounded text-[12px] text-gray-700 hover:bg-gray-100 whitespace-nowrap",title:`${e.url}\n(right-click to remove)`,children:[
23
23
  /* @__PURE__ */c("img",{src:`https://icons.duckduckgo.com/ip3/${new URL(e.url).hostname}.ico`,alt:"",className:"h-3.5 w-3.5",onError:e=>{e.target.style.visibility="hidden"}}),e.label]},t)),
24
24
  /* @__PURE__ */c("div",{className:"flex-1"}),
25
25
  /* @__PURE__ */c("button",{onClick:()=>{g(k);try{localStorage.setItem(u,k)}catch{}},className:"px-2 py-0.5 text-[11px] text-gray-500 hover:text-gray-800",title:"Set current page as homepage",children:"Set as home"})]}),
26
- /* @__PURE__ */c("div",{className:"flex-1 relative min-h-0 bg-gray-50",children:/* @__PURE__ */c(y,{url:k,iframeKey:W,iframeRef:P,openExternal:F,showHelp:A,dismissHelp:()=>B(!1)})})]})}function v(e){try{return new URL(e).hostname.replace(/^www\./,"")}catch{return e}}function y({url:e,iframeKey:t,iframeRef:o,openExternal:r,showHelp:n,dismissHelp:a}){const[d,u]=s(!1);i(()=>{u(!1)},[e]);return function(e){try{const t=new URL(e).hostname.toLowerCase();return k.some(e=>t===e||t.endsWith("."+e))}catch{return!1}}(e)&&!d?/* @__PURE__ */c("div",{className:"absolute inset-0 flex items-center justify-center bg-white p-8",children:/* @__PURE__ */l("div",{className:"max-w-md text-center",children:[
26
+ /* @__PURE__ */c("div",{className:"flex-1 relative min-h-0 bg-gray-50",children:/* @__PURE__ */c(y,{url:k,iframeKey:R,iframeRef:E,openExternal:F,showHelp:A,dismissHelp:()=>O(!1)})})]})}function v(e){try{return new URL(e).hostname.replace(/^www\./,"")}catch{return e}}function y({url:e,iframeKey:t,iframeRef:o,openExternal:r,showHelp:n,dismissHelp:a}){const[d,u]=s(!1);i(()=>{u(!1)},[e]);return function(e){try{const t=new URL(e).hostname.toLowerCase();return k.some(e=>t===e||t.endsWith("."+e))}catch{return!1}}(e)&&!d?/* @__PURE__ */c("div",{className:"absolute inset-0 flex items-center justify-center bg-white p-8",children:/* @__PURE__ */l("div",{className:"max-w-md text-center",children:[
27
27
  /* @__PURE__ */c("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,children:/* @__PURE__ */c("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"})}),
28
28
  /* @__PURE__ */l("h3",{className:"text-base font-semibold text-gray-800 mb-1",children:[v(e)," can't be embedded"]}),
29
29
  /* @__PURE__ */l("p",{className:"text-sm text-gray-500 mb-4",children:["This site sends an ",
@@ -0,0 +1,29 @@
1
+ import{loadAppearance as e,WidgetSettingsModal as t}from"./chunk-SVO3ES2E.js";import{useWidgetSettings as n}from"./chunk-N6STBYXR.js";import"./chunk-DSSLOQDW.js";import"./chunk-KVOFUFPP.js";import"./chunk-CIXQKCFA.js";import"./chunk-5A7MWTXX.js";import"./chunk-OGXU7QFW.js";import"./chunk-ZAE6ROV7.js";import"./chunk-AA4TMQOS.js";import"./chunk-AFYQTVZO.js";import"./chunk-HZZNJHRH.js";import"./chunk-X4FJ54PP.js";import"./chunk-D65T4H6J.js";import"./chunk-J3LIIIHJ.js";import"./chunk-C3QOHMR6.js";import"./chunk-YKZHOXI4.js";import{useState as r,useRef as l,useCallback as o,useEffect as i}from"react";import{jsxs as a,Fragment as c,jsx as s}from"react/jsx-runtime";var u="calc_appearance";function d(){const[d,h]=r("0"),[m,k]=r(null),[b,p]=r(null),[g,v]=r(!1),[x,y]=r(""),[N,f]=r([]),[C,$]=r(!1),[j,w]=r(()=>e(u)),[S,E]=r(!1),[F,O]=r(j),T=l(null);n(o(()=>{O({...j}),E(!0)},[j]));const A=o(e=>{y(""),h(t=>g||"0"===t?(v(!1),"."===e?"0.":e):"."===e&&t.includes(".")?t:t+e)},[g]),L=o(()=>{h("0"),k(null),p(null),v(!1)},[]),H=o((e,t,n)=>{switch(n){case"+":return e+t;case"-":return e-t;case"×":return e*t;case"÷":return 0===t?0:e/t;default:return t}},[]),W=o(e=>{const t=parseFloat(d);if(null!==m&&b&&!g){const e=H(m,t,b);h(String(e)),k(e),f(n=>[`${m} ${b} ${t} = ${e}`,...n].slice(0,20))}else k(t);p(e),v(!0)},[d,m,b,g,H]),X=o(()=>{if(null===m||!b)return;const e=parseFloat(d),t=H(m,e,b),n=`${m} ${b} ${e} =`;f(e=>[`${n} ${t}`,...e].slice(0,20)),y(n),h(String(t)),k(null),p(null),v(!0)},[d,m,b,H]),I=o(()=>{h(e=>String(parseFloat(e)/100))},[]),B=o(()=>{h(e=>e.startsWith("-")?e.slice(1):"0"===e?e:"-"+e)},[]);i(()=>{const e=e=>{const t=e.target.tagName;"INPUT"!==t&&"TEXTAREA"!==t&&"SELECT"!==t&&(e.key>="0"&&e.key<="9"?A(e.key):"."===e.key?A("."):"+"===e.key?W("+"):"-"===e.key?W("-"):"*"===e.key?W("×"):"/"===e.key?(e.preventDefault(),W("÷")):"Enter"===e.key||"="===e.key?("Enter"===e.key&&e.target instanceof Node&&T.current?.contains(e.target)&&e.preventDefault(),X()):"Escape"===e.key?L():"Backspace"===e.key?h(e=>e.length>1?e.slice(0,-1):"0"):"%"===e.key&&I())};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)},[A,W,X,L,I]);const J="flex items-center justify-center rounded-lg text-sm font-medium transition-colors",M=`${J} bg-white border border-gray-200 text-gray-900 hover:bg-gray-50 active:bg-gray-100`,Q=`${J} bg-blue-50 border border-blue-200 text-blue-700 hover:bg-blue-100 active:bg-blue-200`,D=`${J} bg-gray-100 border border-gray-200 text-gray-600 hover:bg-gray-200 active:bg-gray-300`,P=`${J} bg-blue-600 text-white hover:bg-blue-700 active:bg-blue-800`;/* @__PURE__ */
2
+ return a(c,{children:[
3
+ /* @__PURE__ */a("div",{ref:T,className:"flex flex-col h-full",style:{opacity:j.activeOpacity/100,backdropFilter:j.activeBlur>0?`blur(${j.activeBlur}px)`:void 0},children:[
4
+ /* @__PURE__ */a("div",{className:"bg-slate-200 rounded-t-lg px-4 py-2 group/display relative flex flex-col justify-end min-h-[120px] border-b border-slate-300",children:[
5
+ /* @__PURE__ */s("div",{className:"flex flex-col justify-end flex-1 overflow-hidden",children:N.slice(0,3).reverse().map((e,t)=>/* @__PURE__ */s("div",{className:"text-[11px] text-slate-400 text-right font-mono truncate",children:e},t))}),(x||b&&null!==m)&&/* @__PURE__ */s("div",{className:"text-base text-slate-600 text-right font-mono",children:x||`${m} ${b} ${g?"":d}`}),
6
+ /* @__PURE__ */a("div",{className:"flex items-center gap-2",children:[
7
+ /* @__PURE__ */s("button",{onClick:()=>{navigator.clipboard.writeText(d),$(!0),setTimeout(()=>$(!1),1200)},title:"Copy result",className:"shrink-0 text-slate-300 hover:text-slate-500 transition-colors opacity-0 group-hover/display:opacity-100",children:/* @__PURE__ */s("svg",C?{className:"h-5 w-5 text-green-500",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:/* @__PURE__ */s("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 13l4 4L19 7"})}:{className:"h-5 w-5",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:/* @__PURE__ */s("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"})})}),
8
+ /* @__PURE__ */s("div",{className:"text-right text-4xl font-mono font-bold text-slate-800 truncate flex-1",children:(e=>{const t=parseFloat(e);return isNaN(t)||e.endsWith(".")||e.endsWith(".0")||Math.abs(t)<1e15&&e.length<16?e:t.toExponential(6)})(d)})]})]}),
9
+ /* @__PURE__ */a("div",{className:"grid grid-cols-4 grid-rows-5 gap-1.5 flex-1 min-h-0 p-2",children:[
10
+ /* @__PURE__ */s("button",{onClick:L,className:D,children:"AC"}),
11
+ /* @__PURE__ */s("button",{onClick:B,className:D,children:"+/−"}),
12
+ /* @__PURE__ */s("button",{onClick:I,className:D,children:"%"}),
13
+ /* @__PURE__ */s("button",{onClick:()=>W("÷"),className:`${Q} ${"÷"===b?"ring-2 ring-blue-400":""}`,children:"÷"}),
14
+ /* @__PURE__ */s("button",{onClick:()=>A("7"),className:M,children:"7"}),
15
+ /* @__PURE__ */s("button",{onClick:()=>A("8"),className:M,children:"8"}),
16
+ /* @__PURE__ */s("button",{onClick:()=>A("9"),className:M,children:"9"}),
17
+ /* @__PURE__ */s("button",{onClick:()=>W("×"),className:`${Q} ${"×"===b?"ring-2 ring-blue-400":""}`,children:"×"}),
18
+ /* @__PURE__ */s("button",{onClick:()=>A("4"),className:M,children:"4"}),
19
+ /* @__PURE__ */s("button",{onClick:()=>A("5"),className:M,children:"5"}),
20
+ /* @__PURE__ */s("button",{onClick:()=>A("6"),className:M,children:"6"}),
21
+ /* @__PURE__ */s("button",{onClick:()=>W("-"),className:`${Q} ${"-"===b?"ring-2 ring-blue-400":""}`,children:"−"}),
22
+ /* @__PURE__ */s("button",{onClick:()=>A("1"),className:M,children:"1"}),
23
+ /* @__PURE__ */s("button",{onClick:()=>A("2"),className:M,children:"2"}),
24
+ /* @__PURE__ */s("button",{onClick:()=>A("3"),className:M,children:"3"}),
25
+ /* @__PURE__ */s("button",{onClick:()=>W("+"),className:`${Q} ${"+"===b?"ring-2 ring-blue-400":""}`,children:"+"}),
26
+ /* @__PURE__ */s("button",{onClick:()=>A("0"),className:`${M} col-span-2`,children:"0"}),
27
+ /* @__PURE__ */s("button",{onClick:()=>A("."),className:M,children:"."}),
28
+ /* @__PURE__ */s("button",{onClick:X,className:P,children:"="})]})]}),
29
+ /* @__PURE__ */s(t,{open:S,onClose:()=>E(!1),title:"Calculator Settings",appearance:F,onAppearanceChange:O,onSave:()=>{w(F),localStorage.setItem(u,JSON.stringify(F)),E(!1)}})]})}export{d as default};
@@ -0,0 +1 @@
1
+ export{ConfirmProvider,confirm,confirmDestructive,prompt,useConfirm}from"./chunk-ZAE6ROV7.js";import"./chunk-AFYQTVZO.js";import"./chunk-X4FJ54PP.js";import"./chunk-J3LIIIHJ.js";import"./chunk-C3QOHMR6.js";