@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,215 @@
1
+ import { VscIcon_default } from './chunk-GRYCUBJZ.js';
2
+ import { ColorPicker_default } from './chunk-EX5V2ZTU.js';
3
+ import { useDesktopStore } from './chunk-NWMSWRUD.js';
4
+ import { useVscIconElement, useFcIconElement } from './chunk-YY6OUR2U.js';
5
+ import { SimpleGrid, Tooltip, UnstyledButton, Text, TextInput, ActionIcon, Collapse, Group, Button } from './chunk-BQL3YXMV.js';
6
+ import { useState, useRef, useEffect } from 'react';
7
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
8
+
9
+ // src/components/Shared/IconColorPicker/IconColorPicker.module.css
10
+ var IconColorPicker_default = {};
11
+
12
+ // src/constants/Icons.ts
13
+ var PRESET_ICONS = [
14
+ "VscFolder",
15
+ "VscFolderOpened",
16
+ "VscHome",
17
+ "VscServer",
18
+ "VscDatabase",
19
+ "VscBook",
20
+ "VscMail",
21
+ "VscGithub",
22
+ "VscCloud",
23
+ "VscLock",
24
+ "VscSettingsGear",
25
+ "VscStar",
26
+ "VscHeart",
27
+ "VscMusic",
28
+ "VscCamera",
29
+ "VscArchive"
30
+ ];
31
+ var IconColorPicker = ({
32
+ selectedIcon,
33
+ selectedColor,
34
+ onIconChange,
35
+ onColorChange,
36
+ colorError
37
+ }) => {
38
+ return /* @__PURE__ */ jsxs("div", { className: IconColorPicker_default.root, children: [
39
+ /* @__PURE__ */ jsx(SimpleGrid, { cols: 8, spacing: 4, className: IconColorPicker_default.iconGrid, children: PRESET_ICONS.map((name) => {
40
+ const isSelected = selectedIcon === name;
41
+ return /* @__PURE__ */ jsx(Tooltip, { label: name, openDelay: 500, children: /* @__PURE__ */ jsx(
42
+ UnstyledButton,
43
+ {
44
+ className: IconColorPicker_default.iconButton,
45
+ "data-selected": isSelected || void 0,
46
+ onClick: () => onIconChange(name),
47
+ "aria-label": name,
48
+ "aria-pressed": isSelected,
49
+ children: /* @__PURE__ */ jsx(VscIcon_default, { name, size: 20, color: selectedColor })
50
+ }
51
+ ) }, name);
52
+ }) }),
53
+ /* @__PURE__ */ jsx(ColorPicker_default, { value: selectedColor, onChange: onColorChange, error: colorError })
54
+ ] });
55
+ };
56
+ var IconColorPicker_default2 = IconColorPicker;
57
+
58
+ // src/components/Shared/CreateItemApp/CreateItemApp.module.css
59
+ var CreateItemApp_default = {};
60
+ var CSS_COLOR_RE = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
61
+ var isValidColor = (color) => CSS_COLOR_RE.test(color);
62
+ var ICON_PROPS = { size: 14, style: { display: "block" } };
63
+ var CollapseToggleIcon = ({ open }) => useFcIconElement(open ? "FcCollapse" : "FcExpand", ICON_PROPS);
64
+ var CancelIcon = () => useFcIconElement("FcCancel", ICON_PROPS);
65
+ var CheckIcon = () => useFcIconElement("FcCheckmark", ICON_PROPS);
66
+ var DEFAULT_ICON = "VscFolder";
67
+ var DEFAULT_COLOR = "#228be6";
68
+ var DEFAULT_FILE_NAME = "New File";
69
+ var DEFAULT_FOLDER_NAME = "New Folder";
70
+ var TITLE_BAR_HEIGHT = 36;
71
+ var CreateItemApp = ({ window }) => {
72
+ const win = window;
73
+ const mode = win?.contentData?.mode ?? "folder";
74
+ const parentId = win?.contentData?.parentId ?? null;
75
+ const currentPath = win?.contentData?.currentPath ?? "/home";
76
+ const [name, setName] = useState(mode === "folder" ? DEFAULT_FOLDER_NAME : DEFAULT_FILE_NAME);
77
+ const [iconName, setIconName] = useState(DEFAULT_ICON);
78
+ const [iconColor, setIconColor] = useState(DEFAULT_COLOR);
79
+ const [iconPickerOpen, setIconPickerOpen] = useState(
80
+ win?.contentData?.iconPickerOpen ?? false
81
+ );
82
+ const rootRef = useRef(null);
83
+ const closeWindow = useDesktopStore((state) => state.closeWindow);
84
+ const resizeWindow = useDesktopStore((state) => state.resizeWindow);
85
+ const createFile = useDesktopStore((state) => state.createFile);
86
+ const createFolder = useDesktopStore((state) => state.createFolder);
87
+ const addNotification = useDesktopStore((state) => state.addNotification);
88
+ const fsNodes = useDesktopStore((state) => state.fsNodes);
89
+ const windowWidth = useDesktopStore(
90
+ (state) => state.windows.find((w) => w.id === win?.id)?.width ?? 400
91
+ );
92
+ const duplicateName = fsNodes.some(
93
+ (n) => n.parentId === parentId && n.type === mode && n.name === name.trim()
94
+ );
95
+ const colorError = mode === "folder" && iconPickerOpen && !isValidColor(iconColor);
96
+ const canConfirm = name.trim().length > 0 && !duplicateName && !colorError;
97
+ useEffect(() => {
98
+ if (!win?.id || !rootRef.current) return;
99
+ const el = rootRef.current;
100
+ const observer = new ResizeObserver(() => {
101
+ resizeWindow(win.id, windowWidth, el.scrollHeight + TITLE_BAR_HEIGHT);
102
+ });
103
+ observer.observe(el);
104
+ return () => observer.disconnect();
105
+ }, [win, windowWidth, resizeWindow]);
106
+ const handleConfirm = () => {
107
+ if (!canConfirm) return;
108
+ const itemName = name.trim();
109
+ const itemParentId = parentId ?? null;
110
+ const itemIconName = iconName;
111
+ const itemIconColor = iconColor;
112
+ closeWindow(win.id);
113
+ if (mode === "folder") {
114
+ createFolder(itemName, itemParentId, itemIconName, itemIconColor).catch((error) => {
115
+ console.error("Failed to create folder:", error);
116
+ addNotification({
117
+ id: `create-folder-error-${Date.now()}`,
118
+ title: "Error",
119
+ message: `Failed to create folder: ${error instanceof Error ? error.message : "Unknown error"}`,
120
+ fcIcon: "FcHighPriority"
121
+ });
122
+ });
123
+ } else {
124
+ createFile(itemName, "", itemParentId).catch((error) => {
125
+ console.error("Failed to create file:", error);
126
+ addNotification({
127
+ id: `create-file-error-${Date.now()}`,
128
+ title: "Error",
129
+ message: `Failed to create file: ${error instanceof Error ? error.message : "Unknown error"}`,
130
+ fcIcon: "FcHighPriority"
131
+ });
132
+ });
133
+ }
134
+ };
135
+ const handleCancel = () => {
136
+ closeWindow(win.id);
137
+ };
138
+ const previewIconElement = useVscIconElement(iconName, { size: 40, color: iconColor });
139
+ return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: CreateItemApp_default.root, children: [
140
+ /* @__PURE__ */ jsx("div", { className: CreateItemApp_default.header, children: /* @__PURE__ */ jsxs(Text, { fw: 600, size: "sm", children: [
141
+ mode === "folder" ? "Create new folder" : "Create new file",
142
+ " in ",
143
+ currentPath,
144
+ ":"
145
+ ] }) }),
146
+ /* @__PURE__ */ jsxs("div", { className: CreateItemApp_default.content, children: [
147
+ /* @__PURE__ */ jsxs("div", { className: CreateItemApp_default.nameRow, children: [
148
+ mode === "folder" && previewIconElement && /* @__PURE__ */ jsx("div", { className: CreateItemApp_default.iconPreview, "aria-hidden": "true", children: previewIconElement }),
149
+ /* @__PURE__ */ jsx(
150
+ TextInput,
151
+ {
152
+ value: name,
153
+ onChange: (e) => setName(e.currentTarget.value),
154
+ onKeyDown: (e) => e.key === "Enter" && handleConfirm(),
155
+ error: duplicateName ? `There is already a ${mode} with that name` : void 0,
156
+ rightSection: name ? /* @__PURE__ */ jsx(
157
+ ActionIcon,
158
+ {
159
+ variant: "transparent",
160
+ size: "sm",
161
+ onClick: () => setName(""),
162
+ "aria-label": "Clear name",
163
+ children: /* @__PURE__ */ jsx(CancelIcon, {})
164
+ }
165
+ ) : null,
166
+ autoFocus: true,
167
+ className: CreateItemApp_default.nameInput,
168
+ "aria-label": "Item name"
169
+ }
170
+ )
171
+ ] }),
172
+ mode === "folder" && /* @__PURE__ */ jsxs(Fragment, { children: [
173
+ /* @__PURE__ */ jsxs(
174
+ UnstyledButton,
175
+ {
176
+ className: CreateItemApp_default.collapseToggle,
177
+ onClick: () => setIconPickerOpen((o) => !o),
178
+ "aria-expanded": iconPickerOpen,
179
+ children: [
180
+ /* @__PURE__ */ jsx(CollapseToggleIcon, { open: iconPickerOpen }),
181
+ /* @__PURE__ */ jsx(Text, { size: "sm", ml: 6, children: "Choose custom icon or color" })
182
+ ]
183
+ }
184
+ ),
185
+ /* @__PURE__ */ jsx(Collapse, { expanded: iconPickerOpen, children: /* @__PURE__ */ jsx("div", { className: CreateItemApp_default.pickerWrapper, children: /* @__PURE__ */ jsx(
186
+ IconColorPicker_default2,
187
+ {
188
+ selectedIcon: iconName,
189
+ selectedColor: iconColor,
190
+ onIconChange: setIconName,
191
+ onColorChange: setIconColor,
192
+ colorError: colorError ? "Enter a valid hex color (e.g. #ff0000)" : void 0
193
+ }
194
+ ) }) }),
195
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", mt: 4, children: "You can change the icon later in folder properties." })
196
+ ] }),
197
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", mt: "md", children: [
198
+ /* @__PURE__ */ jsx(Button, { variant: "default", size: "sm", onClick: handleCancel, leftSection: /* @__PURE__ */ jsx(CancelIcon, {}), children: "Cancel" }),
199
+ /* @__PURE__ */ jsx(
200
+ Button,
201
+ {
202
+ size: "sm",
203
+ onClick: handleConfirm,
204
+ leftSection: /* @__PURE__ */ jsx(CheckIcon, {}),
205
+ disabled: !canConfirm,
206
+ children: "OK"
207
+ }
208
+ )
209
+ ] })
210
+ ] })
211
+ ] });
212
+ };
213
+ var CreateItemApp_default2 = CreateItemApp;
214
+
215
+ export { CreateItemApp_default2 as CreateItemApp_default, IconColorPicker_default2 as IconColorPicker_default, PRESET_ICONS };
@@ -0,0 +1,53 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ // src/hooks/useDynamicIcon.ts
6
+ var useDynamicIcon = (name, library) => {
7
+ const [Icon, setIcon] = react.useState(null);
8
+ react.useEffect(() => {
9
+ if (!name || typeof window === "undefined") return;
10
+ let cancelled = false;
11
+ const loadIcon = async () => {
12
+ try {
13
+ let mod;
14
+ if (library === "fi") {
15
+ mod = await import('react-icons/fi');
16
+ } else if (library === "vsc") {
17
+ mod = await import('react-icons/vsc');
18
+ } else {
19
+ mod = await import('react-icons/fc');
20
+ }
21
+ if (!cancelled) {
22
+ setIcon(() => mod[name] ?? null);
23
+ }
24
+ } catch {
25
+ }
26
+ };
27
+ loadIcon();
28
+ return () => {
29
+ cancelled = true;
30
+ };
31
+ }, [name, library]);
32
+ return Icon;
33
+ };
34
+ var useDynamicIconElement = (name, library, props) => {
35
+ const Icon = useDynamicIcon(name, library);
36
+ if (!Icon) return null;
37
+ return react.createElement(Icon, props);
38
+ };
39
+ var useFiIcon = (name) => useDynamicIcon(name, "fi");
40
+ var useFcIcon = (name) => useDynamicIcon(name, "fc");
41
+ var useVscIcon = (name) => useDynamicIcon(name, "vsc");
42
+ var useFiIconElement = (name, props) => useDynamicIconElement(name, "fi", props);
43
+ var useFcIconElement = (name, props) => useDynamicIconElement(name, "fc", props);
44
+ var useVscIconElement = (name, props) => useDynamicIconElement(name, "vsc", props);
45
+
46
+ exports.useDynamicIcon = useDynamicIcon;
47
+ exports.useDynamicIconElement = useDynamicIconElement;
48
+ exports.useFcIcon = useFcIcon;
49
+ exports.useFcIconElement = useFcIconElement;
50
+ exports.useFiIcon = useFiIcon;
51
+ exports.useFiIconElement = useFiIconElement;
52
+ exports.useVscIcon = useVscIcon;
53
+ exports.useVscIconElement = useVscIconElement;
@@ -0,0 +1,45 @@
1
+ 'use strict';
2
+
3
+ var chunk7Y7HB7FB_cjs = require('./chunk-7Y7HB7FB.cjs');
4
+ var react = require('react');
5
+
6
+ // src/utils/getFileExtension.ts
7
+ var getFileExtension = (name) => name.split(".").pop()?.toLowerCase() ?? "";
8
+ var EXTENSION_ICONS = {
9
+ pdf: "VscFilePdf",
10
+ md: "VscMarkdown",
11
+ txt: "VscFile",
12
+ jpg: "VscFileMedia",
13
+ jpeg: "VscFileMedia",
14
+ png: "VscFileMedia",
15
+ gif: "VscFileMedia",
16
+ svg: "VscFileCode",
17
+ ts: "VscFileCode",
18
+ tsx: "VscFileCode",
19
+ js: "VscFileCode",
20
+ jsx: "VscFileCode",
21
+ json: "VscJson",
22
+ html: "VscFileCode",
23
+ css: "VscFileCode"
24
+ };
25
+ var FileIcon = ({ type, name = "", folderNode, fileNode, size = 20 }) => {
26
+ let iconName;
27
+ let iconColor;
28
+ if (type === "folder") {
29
+ iconName = folderNode?.iconName ?? "VscFolder";
30
+ iconColor = folderNode?.iconColor ?? void 0;
31
+ } else if (type === "file" && fileNode?.iconName) {
32
+ iconName = fileNode.iconName;
33
+ iconColor = fileNode.iconColor ?? void 0;
34
+ } else {
35
+ const ext = getFileExtension(name);
36
+ iconName = EXTENSION_ICONS[ext] ?? "VscFile";
37
+ }
38
+ const Icon = chunk7Y7HB7FB_cjs.useVscIcon(iconName);
39
+ if (!Icon) return null;
40
+ return react.createElement(Icon, { size, color: iconColor, "aria-hidden": "true" });
41
+ };
42
+ var FileIcon_default = FileIcon;
43
+
44
+ exports.FileIcon_default = FileIcon_default;
45
+ exports.getFileExtension = getFileExtension;
@@ -0,0 +1,219 @@
1
+ 'use strict';
2
+
3
+ var chunkYSOLW4FS_cjs = require('./chunk-YSOLW4FS.cjs');
4
+ var chunkLMJE6V4N_cjs = require('./chunk-LMJE6V4N.cjs');
5
+ var chunk6QOUYSEE_cjs = require('./chunk-6QOUYSEE.cjs');
6
+ var chunk7Y7HB7FB_cjs = require('./chunk-7Y7HB7FB.cjs');
7
+ var chunkE55VXNLK_cjs = require('./chunk-E55VXNLK.cjs');
8
+ var react = require('react');
9
+ var jsxRuntime = require('react/jsx-runtime');
10
+
11
+ // src/components/Shared/IconColorPicker/IconColorPicker.module.css
12
+ var IconColorPicker_default = {};
13
+
14
+ // src/constants/Icons.ts
15
+ var PRESET_ICONS = [
16
+ "VscFolder",
17
+ "VscFolderOpened",
18
+ "VscHome",
19
+ "VscServer",
20
+ "VscDatabase",
21
+ "VscBook",
22
+ "VscMail",
23
+ "VscGithub",
24
+ "VscCloud",
25
+ "VscLock",
26
+ "VscSettingsGear",
27
+ "VscStar",
28
+ "VscHeart",
29
+ "VscMusic",
30
+ "VscCamera",
31
+ "VscArchive"
32
+ ];
33
+ var IconColorPicker = ({
34
+ selectedIcon,
35
+ selectedColor,
36
+ onIconChange,
37
+ onColorChange,
38
+ colorError
39
+ }) => {
40
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: IconColorPicker_default.root, children: [
41
+ /* @__PURE__ */ jsxRuntime.jsx(chunkE55VXNLK_cjs.SimpleGrid, { cols: 8, spacing: 4, className: IconColorPicker_default.iconGrid, children: PRESET_ICONS.map((name) => {
42
+ const isSelected = selectedIcon === name;
43
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkE55VXNLK_cjs.Tooltip, { label: name, openDelay: 500, children: /* @__PURE__ */ jsxRuntime.jsx(
44
+ chunkE55VXNLK_cjs.UnstyledButton,
45
+ {
46
+ className: IconColorPicker_default.iconButton,
47
+ "data-selected": isSelected || void 0,
48
+ onClick: () => onIconChange(name),
49
+ "aria-label": name,
50
+ "aria-pressed": isSelected,
51
+ children: /* @__PURE__ */ jsxRuntime.jsx(chunkYSOLW4FS_cjs.VscIcon_default, { name, size: 20, color: selectedColor })
52
+ }
53
+ ) }, name);
54
+ }) }),
55
+ /* @__PURE__ */ jsxRuntime.jsx(chunkLMJE6V4N_cjs.ColorPicker_default, { value: selectedColor, onChange: onColorChange, error: colorError })
56
+ ] });
57
+ };
58
+ var IconColorPicker_default2 = IconColorPicker;
59
+
60
+ // src/components/Shared/CreateItemApp/CreateItemApp.module.css
61
+ var CreateItemApp_default = {};
62
+ var CSS_COLOR_RE = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
63
+ var isValidColor = (color) => CSS_COLOR_RE.test(color);
64
+ var ICON_PROPS = { size: 14, style: { display: "block" } };
65
+ var CollapseToggleIcon = ({ open }) => chunk7Y7HB7FB_cjs.useFcIconElement(open ? "FcCollapse" : "FcExpand", ICON_PROPS);
66
+ var CancelIcon = () => chunk7Y7HB7FB_cjs.useFcIconElement("FcCancel", ICON_PROPS);
67
+ var CheckIcon = () => chunk7Y7HB7FB_cjs.useFcIconElement("FcCheckmark", ICON_PROPS);
68
+ var DEFAULT_ICON = "VscFolder";
69
+ var DEFAULT_COLOR = "#228be6";
70
+ var DEFAULT_FILE_NAME = "New File";
71
+ var DEFAULT_FOLDER_NAME = "New Folder";
72
+ var TITLE_BAR_HEIGHT = 36;
73
+ var CreateItemApp = ({ window }) => {
74
+ const win = window;
75
+ const mode = win?.contentData?.mode ?? "folder";
76
+ const parentId = win?.contentData?.parentId ?? null;
77
+ const currentPath = win?.contentData?.currentPath ?? "/home";
78
+ const [name, setName] = react.useState(mode === "folder" ? DEFAULT_FOLDER_NAME : DEFAULT_FILE_NAME);
79
+ const [iconName, setIconName] = react.useState(DEFAULT_ICON);
80
+ const [iconColor, setIconColor] = react.useState(DEFAULT_COLOR);
81
+ const [iconPickerOpen, setIconPickerOpen] = react.useState(
82
+ win?.contentData?.iconPickerOpen ?? false
83
+ );
84
+ const rootRef = react.useRef(null);
85
+ const closeWindow = chunk6QOUYSEE_cjs.useDesktopStore((state) => state.closeWindow);
86
+ const resizeWindow = chunk6QOUYSEE_cjs.useDesktopStore((state) => state.resizeWindow);
87
+ const createFile = chunk6QOUYSEE_cjs.useDesktopStore((state) => state.createFile);
88
+ const createFolder = chunk6QOUYSEE_cjs.useDesktopStore((state) => state.createFolder);
89
+ const addNotification = chunk6QOUYSEE_cjs.useDesktopStore((state) => state.addNotification);
90
+ const fsNodes = chunk6QOUYSEE_cjs.useDesktopStore((state) => state.fsNodes);
91
+ const windowWidth = chunk6QOUYSEE_cjs.useDesktopStore(
92
+ (state) => state.windows.find((w) => w.id === win?.id)?.width ?? 400
93
+ );
94
+ const duplicateName = fsNodes.some(
95
+ (n) => n.parentId === parentId && n.type === mode && n.name === name.trim()
96
+ );
97
+ const colorError = mode === "folder" && iconPickerOpen && !isValidColor(iconColor);
98
+ const canConfirm = name.trim().length > 0 && !duplicateName && !colorError;
99
+ react.useEffect(() => {
100
+ if (!win?.id || !rootRef.current) return;
101
+ const el = rootRef.current;
102
+ const observer = new ResizeObserver(() => {
103
+ resizeWindow(win.id, windowWidth, el.scrollHeight + TITLE_BAR_HEIGHT);
104
+ });
105
+ observer.observe(el);
106
+ return () => observer.disconnect();
107
+ }, [win, windowWidth, resizeWindow]);
108
+ const handleConfirm = () => {
109
+ if (!canConfirm) return;
110
+ const itemName = name.trim();
111
+ const itemParentId = parentId ?? null;
112
+ const itemIconName = iconName;
113
+ const itemIconColor = iconColor;
114
+ closeWindow(win.id);
115
+ if (mode === "folder") {
116
+ createFolder(itemName, itemParentId, itemIconName, itemIconColor).catch((error) => {
117
+ console.error("Failed to create folder:", error);
118
+ addNotification({
119
+ id: `create-folder-error-${Date.now()}`,
120
+ title: "Error",
121
+ message: `Failed to create folder: ${error instanceof Error ? error.message : "Unknown error"}`,
122
+ fcIcon: "FcHighPriority"
123
+ });
124
+ });
125
+ } else {
126
+ createFile(itemName, "", itemParentId).catch((error) => {
127
+ console.error("Failed to create file:", error);
128
+ addNotification({
129
+ id: `create-file-error-${Date.now()}`,
130
+ title: "Error",
131
+ message: `Failed to create file: ${error instanceof Error ? error.message : "Unknown error"}`,
132
+ fcIcon: "FcHighPriority"
133
+ });
134
+ });
135
+ }
136
+ };
137
+ const handleCancel = () => {
138
+ closeWindow(win.id);
139
+ };
140
+ const previewIconElement = chunk7Y7HB7FB_cjs.useVscIconElement(iconName, { size: 40, color: iconColor });
141
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rootRef, className: CreateItemApp_default.root, children: [
142
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: CreateItemApp_default.header, children: /* @__PURE__ */ jsxRuntime.jsxs(chunkE55VXNLK_cjs.Text, { fw: 600, size: "sm", children: [
143
+ mode === "folder" ? "Create new folder" : "Create new file",
144
+ " in ",
145
+ currentPath,
146
+ ":"
147
+ ] }) }),
148
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: CreateItemApp_default.content, children: [
149
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: CreateItemApp_default.nameRow, children: [
150
+ mode === "folder" && previewIconElement && /* @__PURE__ */ jsxRuntime.jsx("div", { className: CreateItemApp_default.iconPreview, "aria-hidden": "true", children: previewIconElement }),
151
+ /* @__PURE__ */ jsxRuntime.jsx(
152
+ chunkE55VXNLK_cjs.TextInput,
153
+ {
154
+ value: name,
155
+ onChange: (e) => setName(e.currentTarget.value),
156
+ onKeyDown: (e) => e.key === "Enter" && handleConfirm(),
157
+ error: duplicateName ? `There is already a ${mode} with that name` : void 0,
158
+ rightSection: name ? /* @__PURE__ */ jsxRuntime.jsx(
159
+ chunkE55VXNLK_cjs.ActionIcon,
160
+ {
161
+ variant: "transparent",
162
+ size: "sm",
163
+ onClick: () => setName(""),
164
+ "aria-label": "Clear name",
165
+ children: /* @__PURE__ */ jsxRuntime.jsx(CancelIcon, {})
166
+ }
167
+ ) : null,
168
+ autoFocus: true,
169
+ className: CreateItemApp_default.nameInput,
170
+ "aria-label": "Item name"
171
+ }
172
+ )
173
+ ] }),
174
+ mode === "folder" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
175
+ /* @__PURE__ */ jsxRuntime.jsxs(
176
+ chunkE55VXNLK_cjs.UnstyledButton,
177
+ {
178
+ className: CreateItemApp_default.collapseToggle,
179
+ onClick: () => setIconPickerOpen((o) => !o),
180
+ "aria-expanded": iconPickerOpen,
181
+ children: [
182
+ /* @__PURE__ */ jsxRuntime.jsx(CollapseToggleIcon, { open: iconPickerOpen }),
183
+ /* @__PURE__ */ jsxRuntime.jsx(chunkE55VXNLK_cjs.Text, { size: "sm", ml: 6, children: "Choose custom icon or color" })
184
+ ]
185
+ }
186
+ ),
187
+ /* @__PURE__ */ jsxRuntime.jsx(chunkE55VXNLK_cjs.Collapse, { expanded: iconPickerOpen, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: CreateItemApp_default.pickerWrapper, children: /* @__PURE__ */ jsxRuntime.jsx(
188
+ IconColorPicker_default2,
189
+ {
190
+ selectedIcon: iconName,
191
+ selectedColor: iconColor,
192
+ onIconChange: setIconName,
193
+ onColorChange: setIconColor,
194
+ colorError: colorError ? "Enter a valid hex color (e.g. #ff0000)" : void 0
195
+ }
196
+ ) }) }),
197
+ /* @__PURE__ */ jsxRuntime.jsx(chunkE55VXNLK_cjs.Text, { size: "xs", c: "dimmed", mt: 4, children: "You can change the icon later in folder properties." })
198
+ ] }),
199
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkE55VXNLK_cjs.Group, { justify: "flex-end", mt: "md", children: [
200
+ /* @__PURE__ */ jsxRuntime.jsx(chunkE55VXNLK_cjs.Button, { variant: "default", size: "sm", onClick: handleCancel, leftSection: /* @__PURE__ */ jsxRuntime.jsx(CancelIcon, {}), children: "Cancel" }),
201
+ /* @__PURE__ */ jsxRuntime.jsx(
202
+ chunkE55VXNLK_cjs.Button,
203
+ {
204
+ size: "sm",
205
+ onClick: handleConfirm,
206
+ leftSection: /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, {}),
207
+ disabled: !canConfirm,
208
+ children: "OK"
209
+ }
210
+ )
211
+ ] })
212
+ ] })
213
+ ] });
214
+ };
215
+ var CreateItemApp_default2 = CreateItemApp;
216
+
217
+ exports.CreateItemApp_default = CreateItemApp_default2;
218
+ exports.IconColorPicker_default = IconColorPicker_default2;
219
+ exports.PRESET_ICONS = PRESET_ICONS;
@@ -0,0 +1,88 @@
1
+ 'use strict';
2
+
3
+ var chunkUIQCTAVM_cjs = require('./chunk-UIQCTAVM.cjs');
4
+ var chunkBQCD5RAF_cjs = require('./chunk-BQCD5RAF.cjs');
5
+ var chunkICUE6T7J_cjs = require('./chunk-ICUE6T7J.cjs');
6
+ var chunkBDO6B7MZ_cjs = require('./chunk-BDO6B7MZ.cjs');
7
+ var chunk6QOUYSEE_cjs = require('./chunk-6QOUYSEE.cjs');
8
+ var react = require('react');
9
+ var reactI18next = require('react-i18next');
10
+ var jsxRuntime = require('react/jsx-runtime');
11
+
12
+ // src/components/Apps/ImageViewerApp/ImageViewerApp.module.css
13
+ var ImageViewerApp_default = {};
14
+ var ACCEPTED_IMAGE_TYPES = [...chunk6QOUYSEE_cjs.IMAGE_MIME_TYPES, "image/*"];
15
+ var ImageViewerApp = ({ window, notifyReady }) => {
16
+ const { t } = reactI18next.useTranslation("apps");
17
+ const win = window;
18
+ const windowId = win?.id ?? "";
19
+ const initialSrc = win?.contentData?.src;
20
+ const [src, setSrc] = react.useState(initialSrc);
21
+ const [pickerOpen, setPickerOpen] = react.useState(false);
22
+ const [imageDimensions, setImageDimensions] = react.useState(null);
23
+ const containerRef = react.useRef(null);
24
+ const displayZoom = chunkUIQCTAVM_cjs.useImageViewerStore((s) => s.getDisplayZoom(windowId));
25
+ const fitToWindow = chunkUIQCTAVM_cjs.useImageViewerStore((s) => s.getFitToWindow(windowId));
26
+ const updateCalculatedZoom = chunkUIQCTAVM_cjs.useImageViewerStore((s) => s.updateCalculatedZoom);
27
+ const reset = chunkUIQCTAVM_cjs.useImageViewerStore((s) => s.reset);
28
+ const resolvedSrc = chunkICUE6T7J_cjs.useResolvedUrl(src);
29
+ react.useEffect(() => {
30
+ reset(windowId);
31
+ }, [windowId, reset]);
32
+ react.useEffect(() => {
33
+ if (!fitToWindow || !imageDimensions || !containerRef.current) return;
34
+ const observer = new ResizeObserver((entries) => {
35
+ for (const entry of entries) {
36
+ const { width, height } = entry.contentRect;
37
+ updateCalculatedZoom(windowId, imageDimensions, { width, height });
38
+ }
39
+ });
40
+ observer.observe(containerRef.current);
41
+ return () => observer.disconnect();
42
+ }, [fitToWindow, imageDimensions, windowId, updateCalculatedZoom]);
43
+ react.useEffect(() => {
44
+ notifyReady?.({
45
+ ...win?.contentData ?? {},
46
+ setPickerOpen: () => setPickerOpen(true)
47
+ });
48
+ }, [win, notifyReady]);
49
+ const handleFileSelected = react.useCallback(
50
+ (node) => {
51
+ setSrc(node.url ?? node.name);
52
+ setPickerOpen(false);
53
+ reset(windowId);
54
+ setImageDimensions(null);
55
+ },
56
+ [windowId, reset]
57
+ );
58
+ const handleImageLoad = react.useCallback((e) => {
59
+ const img = e.currentTarget;
60
+ setImageDimensions({ width: img.naturalWidth, height: img.naturalHeight });
61
+ }, []);
62
+ const imgStyle = fitToWindow ? void 0 : { transform: `scale(${displayZoom / 100})` };
63
+ const content = resolvedSrc ? /* @__PURE__ */ jsxRuntime.jsx(
64
+ "img",
65
+ {
66
+ src: resolvedSrc,
67
+ alt: resolvedSrc.split("/").pop() ?? "image",
68
+ className: ImageViewerApp_default.image,
69
+ style: imgStyle,
70
+ onLoad: handleImageLoad
71
+ }
72
+ ) : /* @__PURE__ */ jsxRuntime.jsx(chunkBQCD5RAF_cjs.AppEmptyState_default, { label: t("imageViewer.noImage") });
73
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: ImageViewerApp_default.container, "data-windowid": win?.id, children: [
74
+ content,
75
+ /* @__PURE__ */ jsxRuntime.jsx(
76
+ chunkBDO6B7MZ_cjs.FilePickerModal,
77
+ {
78
+ opened: pickerOpen,
79
+ acceptedMimeTypes: ACCEPTED_IMAGE_TYPES,
80
+ onConfirm: handleFileSelected,
81
+ onCancel: () => setPickerOpen(false)
82
+ }
83
+ )
84
+ ] });
85
+ };
86
+ var ImageViewerApp_default2 = ImageViewerApp;
87
+
88
+ exports.ImageViewerApp_default = ImageViewerApp_default2;