@fde-desktop/fde-core 0.3.8 → 0.4.2

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 (148) hide show
  1. package/README.md +419 -68
  2. package/dist/CalendarApp-CHLUCAI7.css +744 -0
  3. package/dist/CalendarApp-K7ZOUZ6C.js +2 -0
  4. package/dist/CalendarApp-OTGEERSS.cjs +8 -0
  5. package/dist/CodeServerApp-5KZGO7HL.css +75 -0
  6. package/dist/CodeServerApp-LUZFCQBI.js +3 -0
  7. package/dist/CodeServerApp-P3TMJPLY.cjs +9 -0
  8. package/dist/CreateItemApp-NAZMXOPK.cjs +14 -0
  9. package/dist/CreateItemApp-PQB5GTFG.css +107 -0
  10. package/dist/CreateItemApp-ZHCTSPQE.js +8 -0
  11. package/dist/DeviceInfoApp-R6YNVIGX.cjs +11 -0
  12. package/dist/DeviceInfoApp-YHCYAO6N.js +5 -0
  13. package/dist/DeviceInfoApp-ZSMRSITP.css +7 -0
  14. package/dist/FilesApp-AKCVRTXR.js +8 -0
  15. package/dist/FilesApp-E6L5W3T2.css +1817 -0
  16. package/dist/FilesApp-RW3Y6ILO.cjs +14 -0
  17. package/dist/ImageViewerApp-5UXNSW2O.js +11 -0
  18. package/dist/ImageViewerApp-N2Q7E7WZ.css +215 -0
  19. package/dist/ImageViewerApp-RRRRKSFN.cjs +17 -0
  20. package/dist/ImageViewerMenuBar-I3TFKQPS.cjs +14 -0
  21. package/dist/ImageViewerMenuBar-TV5C6TM2.js +5 -0
  22. package/dist/ImageViewerMenuBar-XLK4LIHW.css +56 -0
  23. package/dist/MenuEditApp-HUZRFEHE.js +9 -0
  24. package/dist/MenuEditApp-MCUHGTKQ.cjs +15 -0
  25. package/dist/MenuEditApp-YA6HSAMJ.css +94 -0
  26. package/dist/MenuEditMenuBar-7VHMZNRM.css +56 -0
  27. package/dist/MenuEditMenuBar-GF6L4PGZ.cjs +15 -0
  28. package/dist/MenuEditMenuBar-IUXFPZE5.js +6 -0
  29. package/dist/NotesApp-37BV33C6.js +10 -0
  30. package/dist/NotesApp-4EVUQEFZ.cjs +16 -0
  31. package/dist/NotesApp-TQ6IHDNX.css +302 -0
  32. package/dist/NotesMenuBar-25LKN3SE.cjs +15 -0
  33. package/dist/NotesMenuBar-MXLOX7OT.css +56 -0
  34. package/dist/NotesMenuBar-SRV3AIAL.js +6 -0
  35. package/dist/PdfApp-5VBDNRMC.cjs +16 -0
  36. package/dist/PdfApp-BUIC5U5H.css +206 -0
  37. package/dist/PdfApp-RH6MZZX5.js +10 -0
  38. package/dist/PdfMenuBar-NLZC6JHS.js +4 -0
  39. package/dist/PdfMenuBar-QUM72EE4.css +56 -0
  40. package/dist/PdfMenuBar-WBRTKMLN.cjs +13 -0
  41. package/dist/SettingsApp-5LDHEHYV.cjs +20 -0
  42. package/dist/SettingsApp-JVOSEFH3.css +283 -0
  43. package/dist/SettingsApp-X6764D7T.js +14 -0
  44. package/dist/SettingsMenuBar-5CBSSMVM.css +56 -0
  45. package/dist/SettingsMenuBar-VLT6TTCM.js +6 -0
  46. package/dist/SettingsMenuBar-Y5QEXDEO.cjs +15 -0
  47. package/dist/StorybookApp-NQ244BER.css +7 -0
  48. package/dist/StorybookApp-NZDV4X3Y.js +1 -0
  49. package/dist/StorybookApp-VF3KIMU3.cjs +7 -0
  50. package/dist/TerminalApp-CDGWRBFJ.cjs +10 -0
  51. package/dist/TerminalApp-EAATMIMX.css +77 -0
  52. package/dist/TerminalApp-GCKJCM55.js +4 -0
  53. package/dist/TerminalMenuBar-3J26O26Q.css +56 -0
  54. package/dist/TerminalMenuBar-7BH7MGNJ.cjs +14 -0
  55. package/dist/TerminalMenuBar-7JAEQUZ4.js +5 -0
  56. package/dist/UploaderApp-2WYRCUQV.js +10 -0
  57. package/dist/UploaderApp-6KV3TGCT.css +1817 -0
  58. package/dist/UploaderApp-EYFC36PM.cjs +16 -0
  59. package/dist/chunk-2FO445RM.cjs +449 -0
  60. package/dist/chunk-2PSTHGTD.cjs +42 -0
  61. package/dist/chunk-2RQX7QBP.cjs +148 -0
  62. package/dist/chunk-3IICBLEA.js +442 -0
  63. package/dist/chunk-43W6UDUZ.cjs +19 -0
  64. package/dist/chunk-4E45FBAH.js +223 -0
  65. package/dist/chunk-4MCFQPKY.js +444 -0
  66. package/dist/chunk-4OH5RPSQ.cjs +38 -0
  67. package/dist/chunk-4XURSNM4.js +43 -0
  68. package/dist/chunk-4ZCRYHL6.js +407 -0
  69. package/dist/chunk-54PYEQLK.js +283 -0
  70. package/dist/chunk-5C6IQE42.cjs +35 -0
  71. package/dist/chunk-5NOHYJNH.js +84 -0
  72. package/dist/chunk-5PYK5ASL.js +162 -0
  73. package/dist/chunk-5YH6AKEO.js +146 -0
  74. package/dist/chunk-657BJOY5.cjs +324 -0
  75. package/dist/chunk-6QOUYSEE.cjs +2303 -0
  76. package/dist/chunk-7SAFECOJ.js +215 -0
  77. package/dist/chunk-7Y7HB7FB.cjs +53 -0
  78. package/dist/chunk-ABIAPZ6S.cjs +45 -0
  79. package/dist/chunk-AQL372JF.cjs +219 -0
  80. package/dist/chunk-AXDUVZVP.cjs +88 -0
  81. package/dist/chunk-AYFNYHMP.js +541 -0
  82. package/dist/chunk-BDO6B7MZ.cjs +451 -0
  83. package/dist/chunk-BKXEA2BK.cjs +286 -0
  84. package/dist/chunk-BLV47DX2.js +47 -0
  85. package/dist/chunk-BQCD5RAF.cjs +48 -0
  86. package/dist/chunk-BQL3YXMV.js +17429 -0
  87. package/dist/chunk-C6BEZNAM.cjs +45 -0
  88. package/dist/chunk-CFWV2JMR.js +234 -0
  89. package/dist/chunk-CV5PUHAE.cjs +86 -0
  90. package/dist/chunk-D5MVFFID.js +42 -0
  91. package/dist/chunk-D7R55WWT.js +1601 -0
  92. package/dist/chunk-DMNF4CNN.cjs +49 -0
  93. package/dist/chunk-DWP2SYF7.js +55 -0
  94. package/dist/chunk-E55VXNLK.cjs +17498 -0
  95. package/dist/chunk-EAELL43F.js +42 -0
  96. package/dist/chunk-EUQLZW6P.js +48 -0
  97. package/dist/chunk-EX5V2ZTU.js +40 -0
  98. package/dist/chunk-FH4ILMKF.js +38 -0
  99. package/dist/chunk-FRHBM2U7.js +33 -0
  100. package/dist/chunk-FX2TPX3L.cjs +45 -0
  101. package/dist/chunk-GCYD6T52.js +32 -0
  102. package/dist/chunk-GRYCUBJZ.js +9 -0
  103. package/dist/chunk-HWHBSAUC.js +40 -0
  104. package/dist/chunk-ICUE6T7J.cjs +50 -0
  105. package/dist/chunk-IDHP3R4I.js +31 -0
  106. package/dist/chunk-IUOQPOEN.js +2293 -0
  107. package/dist/chunk-J7L2S2GT.cjs +34 -0
  108. package/dist/chunk-JEBKLIMU.cjs +123 -0
  109. package/dist/chunk-KQHICFX3.js +121 -0
  110. package/dist/chunk-LMJE6V4N.cjs +42 -0
  111. package/dist/chunk-MVDGM5Y4.js +68 -0
  112. package/dist/chunk-NVEGEK3N.js +31 -0
  113. package/dist/chunk-NWMSWRUD.js +2236 -0
  114. package/dist/chunk-ODXL6BR3.js +77 -0
  115. package/dist/chunk-OJIDKDKF.js +68 -0
  116. package/dist/chunk-PKPQA5NR.js +15 -0
  117. package/dist/chunk-PNDBLFJW.cjs +50 -0
  118. package/dist/chunk-PYTKNRGM.js +280 -0
  119. package/dist/chunk-Q3WA72BF.cjs +70 -0
  120. package/dist/chunk-QB72BLCJ.cjs +237 -0
  121. package/dist/chunk-QHBBLML3.js +86 -0
  122. package/dist/chunk-RDIDAZ3S.cjs +9 -0
  123. package/dist/chunk-RGJPRXYY.js +48 -0
  124. package/dist/chunk-RQ6OZRUW.cjs +41 -0
  125. package/dist/chunk-SBE4SZAN.cjs +226 -0
  126. package/dist/chunk-SYGUWGWK.cjs +2329 -0
  127. package/dist/chunk-TDZ43MUX.cjs +165 -0
  128. package/dist/chunk-TGWMOHAO.js +17 -0
  129. package/dist/chunk-U4RYIS6Z.cjs +548 -0
  130. package/dist/chunk-UIQCTAVM.cjs +59 -0
  131. package/dist/chunk-XVASHRCE.cjs +70 -0
  132. package/dist/chunk-XYSMVQQD.cjs +1608 -0
  133. package/dist/chunk-YAIWI4Z5.js +7 -0
  134. package/dist/chunk-YP2PLNOF.cjs +34 -0
  135. package/dist/chunk-YSOLW4FS.cjs +11 -0
  136. package/dist/chunk-YY6OUR2U.js +44 -0
  137. package/dist/chunk-YZWS7FDT.cjs +409 -0
  138. package/dist/chunk-Z5YGWL65.cjs +39 -0
  139. package/dist/chunk-ZBGWYTCU.cjs +83 -0
  140. package/dist/chunk-ZHB5Q2M6.js +36 -0
  141. package/dist/chunk-ZHNDXNL4.js +45 -0
  142. package/dist/chunk-ZX3EDZ5C.cjs +17 -0
  143. package/dist/index.cjs +4405 -5156
  144. package/dist/index.css +9192 -0
  145. package/dist/index.d.cts +1324 -762
  146. package/dist/index.d.ts +1324 -762
  147. package/dist/index.js +3648 -5038
  148. package/package.json +14 -6
@@ -0,0 +1,42 @@
1
+ import { useVscIcon } from './chunk-YY6OUR2U.js';
2
+ import { createElement } from 'react';
3
+
4
+ // src/utils/getFileExtension.ts
5
+ var getFileExtension = (name) => name.split(".").pop()?.toLowerCase() ?? "";
6
+ var EXTENSION_ICONS = {
7
+ pdf: "VscFilePdf",
8
+ md: "VscMarkdown",
9
+ txt: "VscFile",
10
+ jpg: "VscFileMedia",
11
+ jpeg: "VscFileMedia",
12
+ png: "VscFileMedia",
13
+ gif: "VscFileMedia",
14
+ svg: "VscFileCode",
15
+ ts: "VscFileCode",
16
+ tsx: "VscFileCode",
17
+ js: "VscFileCode",
18
+ jsx: "VscFileCode",
19
+ json: "VscJson",
20
+ html: "VscFileCode",
21
+ css: "VscFileCode"
22
+ };
23
+ var FileIcon = ({ type, name = "", folderNode, fileNode, size = 20 }) => {
24
+ let iconName;
25
+ let iconColor;
26
+ if (type === "folder") {
27
+ iconName = folderNode?.iconName ?? "VscFolder";
28
+ iconColor = folderNode?.iconColor ?? void 0;
29
+ } else if (type === "file" && fileNode?.iconName) {
30
+ iconName = fileNode.iconName;
31
+ iconColor = fileNode.iconColor ?? void 0;
32
+ } else {
33
+ const ext = getFileExtension(name);
34
+ iconName = EXTENSION_ICONS[ext] ?? "VscFile";
35
+ }
36
+ const Icon = useVscIcon(iconName);
37
+ if (!Icon) return null;
38
+ return createElement(Icon, { size, color: iconColor, "aria-hidden": "true" });
39
+ };
40
+ var FileIcon_default = FileIcon;
41
+
42
+ export { FileIcon_default, getFileExtension };
@@ -0,0 +1,48 @@
1
+ import { fileSystem, getBaseUrl } from './chunk-NWMSWRUD.js';
2
+ import { isDocker } from './chunk-FRHBM2U7.js';
3
+ import { useMemo, useState, useRef, useEffect } from 'react';
4
+
5
+ function useResolvedUrl(url) {
6
+ const needsBlobResolution = useMemo(
7
+ () => (url?.startsWith("idb://") || isDocker() && url?.startsWith("/api/fs")) ?? false,
8
+ [url]
9
+ );
10
+ const isApiFsUrl = useMemo(() => url?.startsWith("/api/fs") ?? false, [url]);
11
+ const [blobUrl, setBlobUrl] = useState(void 0);
12
+ const revokeRef = useRef(void 0);
13
+ useEffect(() => {
14
+ if (!url || !needsBlobResolution) return;
15
+ let cancelled = false;
16
+ fileSystem.toBlobUrl(url).then((result) => {
17
+ if (cancelled) {
18
+ if (result) URL.revokeObjectURL(result);
19
+ return;
20
+ }
21
+ revokeRef.current = result ?? void 0;
22
+ setBlobUrl(result ?? void 0);
23
+ });
24
+ return () => {
25
+ cancelled = true;
26
+ if (revokeRef.current) {
27
+ URL.revokeObjectURL(revokeRef.current);
28
+ revokeRef.current = void 0;
29
+ }
30
+ setBlobUrl(void 0);
31
+ };
32
+ }, [url, needsBlobResolution]);
33
+ if (!url) return void 0;
34
+ if (isApiFsUrl && needsBlobResolution) {
35
+ return blobUrl;
36
+ }
37
+ if (!needsBlobResolution) {
38
+ if (url.startsWith("/") || url.startsWith("http://") || url.startsWith("https://")) {
39
+ return url;
40
+ }
41
+ const base = getBaseUrl();
42
+ const normalizedBase = base.endsWith("/") ? base : `${base}/`;
43
+ return `${normalizedBase}${url}`;
44
+ }
45
+ return blobUrl;
46
+ }
47
+
48
+ export { useResolvedUrl };
@@ -0,0 +1,40 @@
1
+ import { PRESET_COLORS } from './chunk-PKPQA5NR.js';
2
+ import { UnstyledButton, ColorInput } from './chunk-BQL3YXMV.js';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+
5
+ // src/components/Shared/ColorPicker/ColorPicker.module.css
6
+ var ColorPicker_default = {};
7
+ var ColorPicker = ({ value, onChange, error, disabled = false }) => {
8
+ return /* @__PURE__ */ jsxs("div", { className: ColorPicker_default.root, children: [
9
+ /* @__PURE__ */ jsx("div", { className: ColorPicker_default.colorRow, children: PRESET_COLORS.map((color) => /* @__PURE__ */ jsx(
10
+ UnstyledButton,
11
+ {
12
+ className: ColorPicker_default.colorSwatch,
13
+ "data-selected": value === color || void 0,
14
+ "data-disabled": disabled || void 0,
15
+ style: { background: color },
16
+ onClick: () => !disabled && onChange(color),
17
+ "aria-label": `Color ${color}`,
18
+ "aria-pressed": value === color,
19
+ disabled
20
+ },
21
+ color
22
+ )) }),
23
+ /* @__PURE__ */ jsx(
24
+ ColorInput,
25
+ {
26
+ value,
27
+ onChange,
28
+ placeholder: "Custom color",
29
+ size: "xs",
30
+ className: ColorPicker_default.colorInput,
31
+ "aria-label": "Custom color picker",
32
+ error,
33
+ disabled
34
+ }
35
+ )
36
+ ] });
37
+ };
38
+ var ColorPicker_default2 = ColorPicker;
39
+
40
+ export { ColorPicker_default2 as ColorPicker_default };
@@ -0,0 +1,38 @@
1
+ import { create } from 'zustand';
2
+
3
+ // src/components/Apps/NotesApp/notesStore.ts
4
+ var DEFAULT_STATE = {
5
+ isDirty: false,
6
+ contentLoaded: false
7
+ };
8
+ var useNotesStore = create((set, get) => ({
9
+ states: {},
10
+ getIsDirty: (windowId) => get().states[windowId]?.isDirty ?? false,
11
+ setIsDirty: (windowId, isDirty) => {
12
+ const currentIsDirty = get().states[windowId]?.isDirty ?? false;
13
+ if (currentIsDirty === isDirty) return;
14
+ set((s) => ({
15
+ states: {
16
+ ...s.states,
17
+ [windowId]: { ...s.states[windowId] ?? DEFAULT_STATE, isDirty }
18
+ }
19
+ }));
20
+ },
21
+ getContentLoaded: (windowId) => get().states[windowId]?.contentLoaded ?? false,
22
+ setContentLoaded: (windowId, loaded) => {
23
+ set((s) => ({
24
+ states: {
25
+ ...s.states,
26
+ [windowId]: { ...s.states[windowId] ?? DEFAULT_STATE, contentLoaded: loaded }
27
+ }
28
+ }));
29
+ },
30
+ reset: (windowId) => {
31
+ set((s) => ({
32
+ states: { ...s.states, [windowId]: DEFAULT_STATE }
33
+ }));
34
+ }
35
+ }));
36
+ var useIsDirty = (windowId) => useNotesStore((s) => s.states[windowId]?.isDirty ?? false);
37
+
38
+ export { useIsDirty, useNotesStore };
@@ -0,0 +1,33 @@
1
+ // src/utils/getRuntime.ts
2
+ function getRuntime() {
3
+ if (typeof window === "undefined") {
4
+ return "browser";
5
+ }
6
+ if (window.__FDE_IN_DOCKER__ === true) {
7
+ return "docker";
8
+ }
9
+ if (typeof navigator !== "undefined" && /Electron/i.test(navigator.userAgent)) {
10
+ return "electron";
11
+ }
12
+ return "browser";
13
+ }
14
+ function isDocker() {
15
+ return getRuntime() === "docker";
16
+ }
17
+ function isElectron() {
18
+ return getRuntime() === "electron";
19
+ }
20
+ function isBrowser() {
21
+ return getRuntime() === "browser";
22
+ }
23
+ function isDev() {
24
+ if (typeof window === "undefined") {
25
+ return false;
26
+ }
27
+ if (window.__IS_DEV__ === true) {
28
+ return true;
29
+ }
30
+ return window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1";
31
+ }
32
+
33
+ export { getRuntime, isBrowser, isDev, isDocker, isElectron };
@@ -0,0 +1,45 @@
1
+ 'use strict';
2
+
3
+ var zustand = require('zustand');
4
+
5
+ // src/components/Apps/MenuEditApp/menuEditStore.ts
6
+ var useMenuEditStore = zustand.create((set, get) => ({
7
+ windows: {},
8
+ reset: (windowId) => {
9
+ set((state) => ({
10
+ windows: {
11
+ ...state.windows,
12
+ [windowId]: { isDirty: false, snapshot: null }
13
+ }
14
+ }));
15
+ },
16
+ setIsDirty: (windowId, isDirty) => {
17
+ set((state) => {
18
+ const windowState = state.windows[windowId];
19
+ if (windowState?.isDirty === isDirty) return state;
20
+ return {
21
+ windows: {
22
+ ...state.windows,
23
+ [windowId]: { ...windowState, isDirty }
24
+ }
25
+ };
26
+ });
27
+ },
28
+ takeSnapshot: (windowId, folders) => {
29
+ set((state) => ({
30
+ windows: {
31
+ ...state.windows,
32
+ [windowId]: { isDirty: false, snapshot: folders }
33
+ }
34
+ }));
35
+ },
36
+ getSnapshot: (windowId) => {
37
+ return get().windows[windowId]?.snapshot ?? null;
38
+ }
39
+ }));
40
+ var useIsDirty = (windowId) => {
41
+ return useMenuEditStore((state) => state.windows[windowId]?.isDirty ?? false);
42
+ };
43
+
44
+ exports.useIsDirty = useIsDirty;
45
+ exports.useMenuEditStore = useMenuEditStore;
@@ -0,0 +1,32 @@
1
+ import { resolveUrl } from './chunk-NWMSWRUD.js';
2
+ import { useFcIconElement, useFiIconElement, useVscIconElement } from './chunk-YY6OUR2U.js';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ var AppIcon = ({ fcIcon, fallback, iconUrl, size = 20, color }) => {
6
+ const isFiIcon = fcIcon?.startsWith("Fi");
7
+ const isVscIcon = fcIcon?.startsWith("Vsc");
8
+ const fcElement = useFcIconElement(!isFiIcon && !isVscIcon ? fcIcon ?? "" : "", { size });
9
+ const fiElement = useFiIconElement(isFiIcon ? fcIcon ?? "" : "", { size, color });
10
+ const vscElement = useVscIconElement(isVscIcon ? fcIcon ?? "" : "", { size });
11
+ if (iconUrl) {
12
+ const resolvedIconUrl = resolveUrl(iconUrl);
13
+ return /* @__PURE__ */ jsx(
14
+ "img",
15
+ {
16
+ src: resolvedIconUrl,
17
+ alt: "",
18
+ width: size,
19
+ height: size,
20
+ style: { objectFit: "contain" }
21
+ }
22
+ );
23
+ }
24
+ if (isFiIcon && fiElement) return fiElement;
25
+ if (isVscIcon && vscElement) return vscElement;
26
+ if (fcElement) return fcElement;
27
+ if (fallback) return /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: fallback });
28
+ return null;
29
+ };
30
+ var AppIcon_default = AppIcon;
31
+
32
+ export { AppIcon_default };
@@ -0,0 +1,9 @@
1
+ import { useVscIconElement } from './chunk-YY6OUR2U.js';
2
+
3
+ // src/components/Shared/VscIcon.tsx
4
+ var VscIcon = ({ name, size = 20, color }) => {
5
+ return useVscIconElement(name, { size, color }) ?? null;
6
+ };
7
+ var VscIcon_default = VscIcon;
8
+
9
+ export { VscIcon_default };
@@ -0,0 +1,40 @@
1
+ import { useFcIconElement } from './chunk-YY6OUR2U.js';
2
+ import { Group, Box, Text, Progress } from './chunk-BQL3YXMV.js';
3
+ import { useState, useEffect } from 'react';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
5
+
6
+ // src/components/Shared/DownloadProgress/DownloadProgress.module.css
7
+ var DownloadProgress_default = {};
8
+ var formatKb = (bytes) => (bytes / 1024).toFixed(1);
9
+ var DownloadProgress = ({
10
+ state,
11
+ ariaLabel = "Download progress",
12
+ minDisplayTime = 1e3
13
+ }) => {
14
+ const { status, loaded, total } = state;
15
+ const processIcon = useFcIconElement("FcProcess", { size: 24 });
16
+ const [doneTimestamp, setDoneTimestamp] = useState(null);
17
+ useEffect(() => {
18
+ if (status !== "done" && status !== "error") return;
19
+ const ts = Date.now();
20
+ const timer = setTimeout(() => {
21
+ setDoneTimestamp(ts);
22
+ }, minDisplayTime);
23
+ return () => clearTimeout(timer);
24
+ }, [status, minDisplayTime]);
25
+ if (status === "idle") return null;
26
+ const label = total !== null ? `${formatKb(loaded)} / ${formatKb(total)} KB` : `${formatKb(loaded)} KB`;
27
+ if (!doneTimestamp) {
28
+ return /* @__PURE__ */ jsxs(Group, { gap: "sm", align: "center", justify: "center", style: { minHeight: 40 }, children: [
29
+ /* @__PURE__ */ jsx(Box, { className: DownloadProgress_default.spinner, "data-testid": "process-icon", children: processIcon }),
30
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: label })
31
+ ] });
32
+ }
33
+ return /* @__PURE__ */ jsx(Progress, { value: 100, size: "sm", "aria-label": ariaLabel, children: /* @__PURE__ */ jsxs(Progress.Label, { children: [
34
+ formatKb(loaded),
35
+ " KB"
36
+ ] }) });
37
+ };
38
+ var DownloadProgress_default2 = DownloadProgress;
39
+
40
+ export { DownloadProgress_default2 as DownloadProgress_default };
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ var chunk6QOUYSEE_cjs = require('./chunk-6QOUYSEE.cjs');
4
+ var chunkZ5YGWL65_cjs = require('./chunk-Z5YGWL65.cjs');
5
+ var react = require('react');
6
+
7
+ function useResolvedUrl(url) {
8
+ const needsBlobResolution = react.useMemo(
9
+ () => (url?.startsWith("idb://") || chunkZ5YGWL65_cjs.isDocker() && url?.startsWith("/api/fs")) ?? false,
10
+ [url]
11
+ );
12
+ const isApiFsUrl = react.useMemo(() => url?.startsWith("/api/fs") ?? false, [url]);
13
+ const [blobUrl, setBlobUrl] = react.useState(void 0);
14
+ const revokeRef = react.useRef(void 0);
15
+ react.useEffect(() => {
16
+ if (!url || !needsBlobResolution) return;
17
+ let cancelled = false;
18
+ chunk6QOUYSEE_cjs.fileSystem.toBlobUrl(url).then((result) => {
19
+ if (cancelled) {
20
+ if (result) URL.revokeObjectURL(result);
21
+ return;
22
+ }
23
+ revokeRef.current = result ?? void 0;
24
+ setBlobUrl(result ?? void 0);
25
+ });
26
+ return () => {
27
+ cancelled = true;
28
+ if (revokeRef.current) {
29
+ URL.revokeObjectURL(revokeRef.current);
30
+ revokeRef.current = void 0;
31
+ }
32
+ setBlobUrl(void 0);
33
+ };
34
+ }, [url, needsBlobResolution]);
35
+ if (!url) return void 0;
36
+ if (isApiFsUrl && needsBlobResolution) {
37
+ return blobUrl;
38
+ }
39
+ if (!needsBlobResolution) {
40
+ if (url.startsWith("/") || url.startsWith("http://") || url.startsWith("https://")) {
41
+ return url;
42
+ }
43
+ const base = chunk6QOUYSEE_cjs.getBaseUrl();
44
+ const normalizedBase = base.endsWith("/") ? base : `${base}/`;
45
+ return `${normalizedBase}${url}`;
46
+ }
47
+ return blobUrl;
48
+ }
49
+
50
+ exports.useResolvedUrl = useResolvedUrl;
@@ -0,0 +1,31 @@
1
+ import { create } from 'zustand';
2
+
3
+ // src/stores/factories/createWindowStateStore.ts
4
+ function createDirtyStateStore() {
5
+ const DEFAULT_STATE = { isDirty: false };
6
+ return create((set, get) => ({
7
+ states: {},
8
+ getIsDirty: (windowId) => get().states[windowId]?.isDirty ?? false,
9
+ setIsDirty: (windowId, isDirty) => {
10
+ const currentIsDirty = get().states[windowId]?.isDirty ?? false;
11
+ if (currentIsDirty === isDirty) return;
12
+ set((s) => ({
13
+ states: {
14
+ ...s.states,
15
+ [windowId]: { ...s.states[windowId] ?? DEFAULT_STATE, isDirty }
16
+ }
17
+ }));
18
+ },
19
+ reset: (windowId) => {
20
+ set((s) => ({
21
+ states: { ...s.states, [windowId]: DEFAULT_STATE }
22
+ }));
23
+ }
24
+ }));
25
+ }
26
+
27
+ // src/components/Apps/SettingsApp/settingsAppStore.ts
28
+ var useSettingsAppStore = createDirtyStateStore();
29
+ var useIsDirty = (windowId) => useSettingsAppStore((s) => s.states[windowId]?.isDirty ?? false);
30
+
31
+ export { useIsDirty, useSettingsAppStore };