defuss-desktop 0.0.3 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,26 +1,263 @@
1
- import { createRef, $ as $$1, dequery, CallChainImpl, createCall } from 'defuss';
1
+ import { $ as $$1, createRef, dequery, CallChainImpl } from 'defuss';
2
2
  import { debounce, throttle } from 'defuss-runtime';
3
- import { jsx, jsxs } from 'defuss/jsx-runtime';
3
+ import { jsxs, jsx, Fragment } from 'defuss/jsx-runtime';
4
4
  import { access, transval, rule } from 'defuss-transval';
5
5
 
6
- function Button({
7
- onClick = () => {
8
- },
9
- disabled = false,
10
- children,
11
- ref = createRef()
12
- }) {
13
- return /* @__PURE__ */ jsx(
14
- "button",
15
- {
16
- ref,
17
- type: "button",
18
- onClick: disabled ? void 0 : onClick,
19
- disabled,
20
- children
6
+ class DesktopShellManager {
7
+ constructor(apps = []) {
8
+ this.apps = apps;
9
+ }
10
+ addApp(app) {
11
+ this.apps.push(app);
12
+ console.log(`App added: ${app.config.name}`);
13
+ }
14
+ async registerAppBundle(bundle) {
15
+ const { DefussApp } = await Promise.resolve().then(function () { return app; });
16
+ return DefussApp.fromBundle(bundle);
17
+ }
18
+ /** Find a registered app by executable name (e.g. "notepad.exe") */
19
+ findApp(executable) {
20
+ return this.apps.find((app) => app.bundle?.executable === executable);
21
+ }
22
+ /** Run an app by executable name */
23
+ runApp(executable) {
24
+ const app = this.findApp(executable);
25
+ if (!app) {
26
+ console.error(`App not found: ${executable}`);
27
+ return;
21
28
  }
22
- );
29
+ app.run();
30
+ }
31
+ /** Launch a bundled app by creating a window and passing the container */
32
+ launchApp(app) {
33
+ if (!app.bundle) return;
34
+ const event = new CustomEvent("defuss:launch-app", { detail: { app } });
35
+ document.dispatchEvent(event);
36
+ }
37
+ }
38
+ globalThis.__defussDesktopShellManager = globalThis.__defussDesktopShellManager || new DesktopShellManager();
39
+ const desktopShell = globalThis.__defussDesktopShellManager;
40
+
41
+ class SelectionModel {
42
+ constructor(options) {
43
+ this.options = options;
44
+ }
45
+ selectionDiv = null;
46
+ startX = 0;
47
+ startY = 0;
48
+ debounceTimer = null;
49
+ isSelecting = false;
50
+ debounceDelay = 1;
51
+ init() {
52
+ this.options.desktopElement.addEventListener("mousedown", this.onMouseDown);
53
+ }
54
+ destroy() {
55
+ this.options.desktopElement.removeEventListener("mousedown", this.onMouseDown);
56
+ this.removeSelectionDiv();
57
+ this.clearDebounce();
58
+ document.removeEventListener("mousemove", this.onMouseMove);
59
+ document.removeEventListener("mouseup", this.onMouseUp);
60
+ document.documentElement.removeEventListener("mouseleave", this.onMouseLeave);
61
+ }
62
+ onMouseDown = (e) => {
63
+ if (e.target.closest(".desktop-icon")) return;
64
+ this.startX = e.clientX;
65
+ this.startY = e.clientY;
66
+ this.isSelecting = true;
67
+ this.createSelectionDiv();
68
+ document.addEventListener("mousemove", this.onMouseMove);
69
+ document.addEventListener("mouseup", this.onMouseUp);
70
+ document.documentElement.addEventListener("mouseleave", this.onMouseLeave);
71
+ };
72
+ onMouseMove = (e) => {
73
+ if (!this.isSelecting) return;
74
+ this.clearDebounce();
75
+ this.debounceTimer = window.setTimeout(() => {
76
+ this.updateSelectionDiv(e.clientX, e.clientY);
77
+ this.selectIcons();
78
+ }, this.debounceDelay);
79
+ };
80
+ onMouseUp = () => {
81
+ this.endSelection();
82
+ };
83
+ onMouseLeave = () => {
84
+ this.endSelection();
85
+ };
86
+ endSelection = () => {
87
+ if (!this.isSelecting) return;
88
+ this.isSelecting = false;
89
+ this.clearDebounce();
90
+ this.selectIcons();
91
+ this.removeSelectionDiv();
92
+ document.removeEventListener("mousemove", this.onMouseMove);
93
+ document.removeEventListener("mouseup", this.onMouseUp);
94
+ document.documentElement.removeEventListener("mouseleave", this.onMouseLeave);
95
+ };
96
+ createSelectionDiv() {
97
+ this.selectionDiv = document.createElement("div");
98
+ this.selectionDiv.className = "selection-model";
99
+ this.selectionDiv.style.left = `${this.startX}px`;
100
+ this.selectionDiv.style.top = `${this.startY}px`;
101
+ this.selectionDiv.style.width = "0px";
102
+ this.selectionDiv.style.height = "0px";
103
+ document.body.appendChild(this.selectionDiv);
104
+ }
105
+ updateSelectionDiv(endX, endY) {
106
+ if (!this.selectionDiv) return;
107
+ const left = Math.min(this.startX, endX);
108
+ const top = Math.min(this.startY, endY);
109
+ const width = Math.abs(endX - this.startX);
110
+ const height = Math.abs(endY - this.startY);
111
+ this.selectionDiv.style.left = `${left}px`;
112
+ this.selectionDiv.style.top = `${top}px`;
113
+ this.selectionDiv.style.width = `${width}px`;
114
+ this.selectionDiv.style.height = `${height}px`;
115
+ }
116
+ selectIcons() {
117
+ const icons = this.options.iconsContainer.querySelectorAll(".desktop-icon");
118
+ if (!this.selectionDiv) return;
119
+ const selRect = this.selectionDiv.getBoundingClientRect();
120
+ icons.forEach((icon) => {
121
+ const iconRect = icon.getBoundingClientRect();
122
+ const intersects = !(iconRect.right < selRect.left || iconRect.left > selRect.right || iconRect.bottom < selRect.top || iconRect.top > selRect.bottom);
123
+ if (intersects) {
124
+ icon.classList.add("icon-selected");
125
+ } else {
126
+ icon.classList.remove("icon-selected");
127
+ }
128
+ });
129
+ }
130
+ removeSelectionDiv() {
131
+ if (this.selectionDiv) {
132
+ this.selectionDiv.remove();
133
+ this.selectionDiv = null;
134
+ }
135
+ }
136
+ clearDebounce() {
137
+ if (this.debounceTimer !== null) {
138
+ clearTimeout(this.debounceTimer);
139
+ this.debounceTimer = null;
140
+ }
141
+ }
142
+ }
143
+
144
+ const defaultTaskbarOptions = {
145
+ position: "bottom",
146
+ stateful: false,
147
+ theme: "default",
148
+ size: "medium"
149
+ };
150
+ class TaskbarManager {
151
+ position;
152
+ theme;
153
+ // e.g., 'windows-xp', 'macos', etc.
154
+ size;
155
+ constructor(options = defaultTaskbarOptions) {
156
+ this.position = options.position || "bottom";
157
+ this.theme = options.theme || "default";
158
+ this.size = options.size || "medium";
159
+ if (options.stateful) ;
160
+ }
161
+ getDimensions() {
162
+ const el = document.querySelector(".taskbar");
163
+ if (!el) {
164
+ return { width: 0, height: 0 };
165
+ }
166
+ return {
167
+ width: el.clientWidth,
168
+ height: el.clientHeight
169
+ };
170
+ }
171
+ }
172
+ globalThis.__defussTaskbarManager = globalThis.__defussTaskbarManager || new TaskbarManager();
173
+ const taskbarManager = globalThis.__defussTaskbarManager;
174
+
175
+ class DefussDesktopAppIcon {
176
+ constructor(config) {
177
+ this.config = config;
178
+ }
179
+ }
180
+ const defaultDesktopOptions = {
181
+ icons: [],
182
+ backgroundColor: "#000"
183
+ };
184
+ class DesktopManager {
185
+ constructor(options = defaultDesktopOptions) {
186
+ this.options = options;
187
+ }
188
+ el;
189
+ state;
190
+ resizeObserver;
191
+ resizeCallbacks = /* @__PURE__ */ new Set();
192
+ init(el, options = this.options) {
193
+ this.options = options;
194
+ this.el = el;
195
+ this.state = this.state || {
196
+ icons: this.options.icons.map((icon) => icon.config)
197
+ };
198
+ this.setupResizeObserver();
199
+ this.render(el);
200
+ }
201
+ render(el) {
202
+ el.style.backgroundColor = this.options.backgroundColor;
203
+ if (this.options.backgroundImage) {
204
+ el.style.backgroundImage = `url(${this.options.backgroundImage})`;
205
+ }
206
+ if (this.options.backgroundImageSize) {
207
+ el.style.backgroundSize = this.options.backgroundImageSize || "cover";
208
+ }
209
+ if (this.options.backgroundRepeat) {
210
+ el.style.backgroundRepeat = this.options.backgroundRepeat || "no-repeat";
211
+ }
212
+ if (this.options.backgroundPosition) {
213
+ el.style.backgroundPosition = this.options.backgroundPosition || "center";
214
+ }
215
+ }
216
+ addIcon(icon) {
217
+ this.options.icons.push(icon);
218
+ console.log(`Icon added: ${icon.config.name}`);
219
+ }
220
+ getDimensions() {
221
+ if (!this.el) {
222
+ throw new Error("Desktop not initialized. Call init() first.");
223
+ }
224
+ return {
225
+ width: this.el.offsetWidth,
226
+ height: this.el.offsetHeight - taskbarManager.getDimensions().height
227
+ // destop is root element minus taskbar height
228
+ };
229
+ }
230
+ setupResizeObserver() {
231
+ if (!this.el) return;
232
+ if (this.resizeObserver) {
233
+ this.resizeObserver.disconnect();
234
+ }
235
+ this.resizeObserver = new ResizeObserver(() => {
236
+ const dimensions = this.getDimensions();
237
+ this.resizeCallbacks.forEach((callback) => {
238
+ try {
239
+ callback(dimensions);
240
+ } catch (error) {
241
+ console.error("Error in desktop resize callback:", error);
242
+ }
243
+ });
244
+ });
245
+ this.resizeObserver.observe(this.el);
246
+ }
247
+ /**
248
+ * Register a callback for desktop resize events
249
+ * @param callback Function to call when desktop is resized
250
+ * @returns Unregister function to remove the callback
251
+ */
252
+ onResize(callback) {
253
+ this.resizeCallbacks.add(callback);
254
+ return () => {
255
+ this.resizeCallbacks.delete(callback);
256
+ };
257
+ }
23
258
  }
259
+ globalThis.__defussDesktopManager = globalThis.__defussDesktopManager || new DesktopManager();
260
+ const desktopManager = globalThis.__defussDesktopManager;
24
261
 
25
262
  const defaultWindowOptions = {
26
263
  title: "Untitled",
@@ -42,6 +279,18 @@ const defaultWindowOptions = {
42
279
  };
43
280
  class WindowManager {
44
281
  windows = [];
282
+ listeners = /* @__PURE__ */ new Set();
283
+ subscribe(listener) {
284
+ this.listeners.add(listener);
285
+ return () => {
286
+ this.listeners.delete(listener);
287
+ };
288
+ }
289
+ emitChanged() {
290
+ for (const listener of this.listeners) {
291
+ listener();
292
+ }
293
+ }
45
294
  constructor() {
46
295
  $$1(() => {
47
296
  if (desktopManager?.onResize) {
@@ -88,6 +337,7 @@ class WindowManager {
88
337
  });
89
338
  this.windows.push(window);
90
339
  this.renderWindowsActivationState();
340
+ this.emitChanged();
91
341
  }
92
342
  }
93
343
  renderWindowsActivationState() {
@@ -137,6 +387,7 @@ class WindowManager {
137
387
  state.y = activeWindow.y + 20;
138
388
  }
139
389
  this.windows.push(state);
390
+ this.emitChanged();
140
391
  return state;
141
392
  }
142
393
  updateWindow(id, options) {
@@ -160,6 +411,7 @@ class WindowManager {
160
411
  ...updatedWindow
161
412
  } : win2
162
413
  );
414
+ this.emitChanged();
163
415
  return updatedWindow;
164
416
  }
165
417
  closeWindow(id) {
@@ -168,6 +420,7 @@ class WindowManager {
168
420
  $$1(win.el).remove();
169
421
  this.windows = this.windows.filter((win2) => win2.id !== id);
170
422
  this.renderWindowsActivationState();
423
+ this.emitChanged();
171
424
  win.ref.state?.onClose?.();
172
425
  }
173
426
  maximizeWindow(id) {
@@ -209,6 +462,7 @@ class WindowManager {
209
462
  top: isMaximized ? "-3px" : `${win.y}px`
210
463
  });
211
464
  this.toggleTitleBarMaximizedButtonState(id);
465
+ this.emitChanged();
212
466
  if (isMaximized) {
213
467
  win.ref.state?.onMaximize?.();
214
468
  }
@@ -216,31 +470,33 @@ class WindowManager {
216
470
  minimizeWindow(id) {
217
471
  let win = this.getWindow(id);
218
472
  if (!win) return;
219
- win = this.updateWindow(id, { prevX: win.x, prevY: win.y });
220
- const isMinimized = !win.minimized;
473
+ if (win.minimized) {
474
+ this.restoreWindow(id);
475
+ return;
476
+ }
477
+ const actualWidth = win.el.offsetWidth || win.width;
478
+ const actualHeight = win.el.offsetHeight || win.height;
221
479
  win = this.updateWindow(id, {
222
- minimized: isMinimized,
223
- width: isMinimized ? 0 : win.width,
224
- height: isMinimized ? 0 : win.height,
225
- x: isMinimized ? -1e4 : win.x,
226
- // Move off-screen when minimized
227
- y: isMinimized ? -1e4 : win.y
480
+ prevX: win.x,
481
+ prevY: win.y,
482
+ prevWidth: actualWidth,
483
+ prevHeight: actualHeight,
484
+ minimized: true
228
485
  });
229
486
  const $win = $$1(win.el);
230
487
  $win.css({
231
- width: isMinimized ? "0px" : `${win.width}px`,
232
- height: isMinimized ? "0px" : `${win.height}px`,
233
- left: isMinimized ? "-10000px" : `${win.x}px`,
234
- top: isMinimized ? "-10000px" : `${win.y}px`
488
+ left: "-10000px",
489
+ top: "-10000px"
235
490
  });
236
- if (isMinimized) {
237
- win.ref.state?.onMinimize?.();
238
- }
491
+ this.renderWindowsActivationState();
492
+ this.emitChanged();
493
+ win.ref.state?.onMinimize?.();
239
494
  }
240
495
  restoreWindow(id) {
241
496
  let win = this.getWindow(id);
242
497
  if (!win) return;
243
498
  win = this.updateWindow(id, {
499
+ minimized: false,
244
500
  maximized: false,
245
501
  width: win.prevWidth || 800,
246
502
  // Use stored previous width
@@ -257,6 +513,8 @@ class WindowManager {
257
513
  top: `${win.y}px`
258
514
  });
259
515
  this.toggleTitleBarMaximizedButtonState(id);
516
+ this.setActiveWindow(id);
517
+ this.emitChanged();
260
518
  }
261
519
  toggleTitleBarMaximizedButtonState(id) {
262
520
  const win = this.getWindow(id);
@@ -289,12 +547,20 @@ function Window({
289
547
  onMaximize = () => {
290
548
  }
291
549
  }) {
550
+ const MIN_WINDOW_WIDTH = 240;
551
+ const MIN_WINDOW_HEIGHT = 160;
292
552
  let isDragging = false;
293
553
  let dragPointerId = null;
294
554
  let dragStartMouse = { x: 0, y: 0 };
295
555
  let dragStartWin = { x: 0, y: 0 };
296
556
  let lastWin = { x, y };
297
557
  let capturedTitleBar = null;
558
+ let isResizing = false;
559
+ let resizePointerId = null;
560
+ let resizeDirection = null;
561
+ let capturedResizeHandle = null;
562
+ let resizeStartMouse = { x: 0, y: 0 };
563
+ let resizeStartWin = { x, y, width, height };
298
564
  const initialWindowState = windowManager.addWindow({
299
565
  id,
300
566
  title,
@@ -358,7 +624,33 @@ function Window({
358
624
  capturedTitleBar = null;
359
625
  windowManager.updateWindow(initialWindowState.id, { x: lastWin.x, y: lastWin.y });
360
626
  };
627
+ const stopResizing = (event) => {
628
+ if (!isResizing) return;
629
+ if (event && capturedResizeHandle && typeof capturedResizeHandle.releasePointerCapture === "function" && resizePointerId === event.pointerId) {
630
+ try {
631
+ capturedResizeHandle.releasePointerCapture(event.pointerId);
632
+ } catch {
633
+ }
634
+ }
635
+ isResizing = false;
636
+ resizePointerId = null;
637
+ resizeDirection = null;
638
+ capturedResizeHandle = null;
639
+ const el = ref.current;
640
+ if (!el) return;
641
+ const left = Number.parseFloat(el.style.left);
642
+ const top = Number.parseFloat(el.style.top);
643
+ const width2 = Number.parseFloat(el.style.width);
644
+ const height2 = Number.parseFloat(el.style.height);
645
+ windowManager.updateWindow(initialWindowState.id, {
646
+ x: Number.isFinite(left) ? left : lastWin.x,
647
+ y: Number.isFinite(top) ? top : lastWin.y,
648
+ width: Number.isFinite(width2) ? width2 : el.offsetWidth,
649
+ height: Number.isFinite(height2) ? height2 : el.offsetHeight
650
+ });
651
+ };
361
652
  const onTitlePointerDown = (event) => {
653
+ if (isResizing) return;
362
654
  if (event.pointerType === "mouse" && event.button !== 0) return;
363
655
  const target = event.target;
364
656
  if (target?.tagName === "BUTTON") return;
@@ -375,6 +667,85 @@ function Window({
375
667
  }
376
668
  event.preventDefault();
377
669
  };
670
+ const onResizePointerDown = (event) => {
671
+ if (!resizable) return;
672
+ if (isDragging) return;
673
+ if (event.pointerType === "mouse" && event.button !== 0) return;
674
+ const currentState = windowManager.getWindow(initialWindowState.id);
675
+ if (currentState?.maximized) return;
676
+ const target = event.target;
677
+ const handle = target?.closest?.(".window-resize-handle");
678
+ const direction = handle?.getAttribute("data-dir");
679
+ if (!handle || !direction) return;
680
+ const currentPos = getCurrentWinPos();
681
+ const el = ref.current;
682
+ if (!el) return;
683
+ isResizing = true;
684
+ resizePointerId = event.pointerId;
685
+ resizeDirection = direction;
686
+ capturedResizeHandle = handle;
687
+ resizeStartMouse = { x: event.clientX, y: event.clientY };
688
+ resizeStartWin = {
689
+ x: currentPos.x,
690
+ y: currentPos.y,
691
+ width: el.offsetWidth,
692
+ height: el.offsetHeight
693
+ };
694
+ if (typeof handle.setPointerCapture === "function") {
695
+ handle.setPointerCapture(event.pointerId);
696
+ }
697
+ windowManager.setActiveWindow(initialWindowState.id);
698
+ event.preventDefault();
699
+ event.stopPropagation();
700
+ };
701
+ const onResizePointerMove = (event) => {
702
+ if (!isResizing) return;
703
+ if (resizePointerId !== null && event.pointerId !== resizePointerId) return;
704
+ if (!resizeDirection) return;
705
+ const el = ref.current;
706
+ if (!el) return;
707
+ const deltaX = event.clientX - resizeStartMouse.x;
708
+ const deltaY = event.clientY - resizeStartMouse.y;
709
+ let newX = resizeStartWin.x;
710
+ let newY = resizeStartWin.y;
711
+ let newWidth = resizeStartWin.width;
712
+ let newHeight = resizeStartWin.height;
713
+ if (resizeDirection.includes("e")) {
714
+ newWidth = Math.max(MIN_WINDOW_WIDTH, resizeStartWin.width + deltaX);
715
+ }
716
+ if (resizeDirection.includes("s")) {
717
+ newHeight = Math.max(MIN_WINDOW_HEIGHT, resizeStartWin.height + deltaY);
718
+ }
719
+ if (resizeDirection.includes("w")) {
720
+ const tentativeWidth = resizeStartWin.width - deltaX;
721
+ newWidth = Math.max(MIN_WINDOW_WIDTH, tentativeWidth);
722
+ newX = resizeStartWin.x + (resizeStartWin.width - newWidth);
723
+ }
724
+ if (resizeDirection.includes("n")) {
725
+ const tentativeHeight = resizeStartWin.height - deltaY;
726
+ newHeight = Math.max(MIN_WINDOW_HEIGHT, tentativeHeight);
727
+ newY = resizeStartWin.y + (resizeStartWin.height - newHeight);
728
+ }
729
+ lastWin = { x: newX, y: newY };
730
+ el.style.left = `${newX}px`;
731
+ el.style.top = `${newY}px`;
732
+ el.style.width = `${newWidth}px`;
733
+ el.style.height = `${newHeight}px`;
734
+ updateWindowState({
735
+ x: newX,
736
+ y: newY,
737
+ width: newWidth,
738
+ height: newHeight
739
+ });
740
+ event.preventDefault();
741
+ event.stopPropagation();
742
+ };
743
+ const onResizePointerUp = (event) => {
744
+ stopResizing(event);
745
+ };
746
+ const onResizePointerCancel = (event) => {
747
+ stopResizing(event);
748
+ };
378
749
  const onTitlePointerMove = (event) => {
379
750
  if (!isDragging) return;
380
751
  if (dragPointerId !== null && event.pointerId !== dragPointerId) return;
@@ -403,7 +774,10 @@ function Window({
403
774
  windowManager.setActiveWindow(initialWindowState.id);
404
775
  $$1(document).on("blur", () => stopDragging());
405
776
  $$1(document).on("visibilitychange", () => {
406
- if (document.hidden) stopDragging();
777
+ if (document.hidden) {
778
+ stopDragging();
779
+ stopResizing();
780
+ }
407
781
  });
408
782
  };
409
783
  const onCloseClick = () => windowManager.closeWindow(initialWindowState.id);
@@ -420,6 +794,7 @@ function Window({
420
794
  {
421
795
  class: "window crt",
422
796
  ref,
797
+ "data-resizable": String(resizable),
423
798
  onMouseDown: onWindowMouseDown,
424
799
  style: {
425
800
  width,
@@ -450,68 +825,230 @@ function Window({
450
825
  ]
451
826
  }
452
827
  ),
453
- /* @__PURE__ */ jsx("div", { class: "window-body", children })
828
+ /* @__PURE__ */ jsx("div", { class: "window-body", children }),
829
+ resizable && /* @__PURE__ */ jsxs(Fragment, { children: [
830
+ /* @__PURE__ */ jsx(
831
+ "div",
832
+ {
833
+ class: "window-resize-handle window-resize-handle--n",
834
+ "data-dir": "n",
835
+ onPointerDown: onResizePointerDown,
836
+ onPointerMove: onResizePointerMove,
837
+ onPointerUp: onResizePointerUp,
838
+ onPointerCancel: onResizePointerCancel
839
+ }
840
+ ),
841
+ /* @__PURE__ */ jsx(
842
+ "div",
843
+ {
844
+ class: "window-resize-handle window-resize-handle--e",
845
+ "data-dir": "e",
846
+ onPointerDown: onResizePointerDown,
847
+ onPointerMove: onResizePointerMove,
848
+ onPointerUp: onResizePointerUp,
849
+ onPointerCancel: onResizePointerCancel
850
+ }
851
+ ),
852
+ /* @__PURE__ */ jsx(
853
+ "div",
854
+ {
855
+ class: "window-resize-handle window-resize-handle--s",
856
+ "data-dir": "s",
857
+ onPointerDown: onResizePointerDown,
858
+ onPointerMove: onResizePointerMove,
859
+ onPointerUp: onResizePointerUp,
860
+ onPointerCancel: onResizePointerCancel
861
+ }
862
+ ),
863
+ /* @__PURE__ */ jsx(
864
+ "div",
865
+ {
866
+ class: "window-resize-handle window-resize-handle--w",
867
+ "data-dir": "w",
868
+ onPointerDown: onResizePointerDown,
869
+ onPointerMove: onResizePointerMove,
870
+ onPointerUp: onResizePointerUp,
871
+ onPointerCancel: onResizePointerCancel
872
+ }
873
+ ),
874
+ /* @__PURE__ */ jsx(
875
+ "div",
876
+ {
877
+ class: "window-resize-handle window-resize-handle--ne",
878
+ "data-dir": "ne",
879
+ onPointerDown: onResizePointerDown,
880
+ onPointerMove: onResizePointerMove,
881
+ onPointerUp: onResizePointerUp,
882
+ onPointerCancel: onResizePointerCancel
883
+ }
884
+ ),
885
+ /* @__PURE__ */ jsx(
886
+ "div",
887
+ {
888
+ class: "window-resize-handle window-resize-handle--se",
889
+ "data-dir": "se",
890
+ onPointerDown: onResizePointerDown,
891
+ onPointerMove: onResizePointerMove,
892
+ onPointerUp: onResizePointerUp,
893
+ onPointerCancel: onResizePointerCancel
894
+ }
895
+ ),
896
+ /* @__PURE__ */ jsx(
897
+ "div",
898
+ {
899
+ class: "window-resize-handle window-resize-handle--sw",
900
+ "data-dir": "sw",
901
+ onPointerDown: onResizePointerDown,
902
+ onPointerMove: onResizePointerMove,
903
+ onPointerUp: onResizePointerUp,
904
+ onPointerCancel: onResizePointerCancel
905
+ }
906
+ ),
907
+ /* @__PURE__ */ jsx(
908
+ "div",
909
+ {
910
+ class: "window-resize-handle window-resize-handle--nw",
911
+ "data-dir": "nw",
912
+ onPointerDown: onResizePointerDown,
913
+ onPointerMove: onResizePointerMove,
914
+ onPointerUp: onResizePointerUp,
915
+ onPointerCancel: onResizePointerCancel
916
+ }
917
+ )
918
+ ] })
454
919
  ]
455
920
  }
456
921
  );
457
922
  }
458
923
 
924
+ function DesktopIcon({ app }) {
925
+ const bundle = app.bundle;
926
+ const iconSrc = bundle?.icon ?? app.config.icon;
927
+ const label = bundle?.displayName ?? app.config.name;
928
+ const onClick = (e) => {
929
+ if (e.detail > 1) return;
930
+ const allIcons = document.querySelectorAll(".desktop-icon");
931
+ allIcons.forEach((icon) => icon.classList.remove("icon-selected"));
932
+ const target = e.target.closest(".desktop-icon");
933
+ if (target) {
934
+ target.classList.add("icon-selected");
935
+ }
936
+ };
937
+ const onDblClick = () => {
938
+ app.run();
939
+ };
940
+ return /* @__PURE__ */ jsxs("div", { class: "desktop-icon", onClick, onDblClick, children: [
941
+ /* @__PURE__ */ jsx("div", { class: "desktop-icon__image", style: { "--icon-src": `url(${iconSrc})` }, children: /* @__PURE__ */ jsx("img", { src: iconSrc, alt: label, draggable: false }) }),
942
+ /* @__PURE__ */ jsx("span", { class: "desktop-icon__label", children: label })
943
+ ] }, bundle?.executable ?? label);
944
+ }
945
+
459
946
  function Desktop({ ref }) {
460
- $$1(() => {
461
- console.log("Desktop mounted");
462
- });
463
- const onOpenWindow = async () => {
947
+ const appIconsRef = createRef();
948
+ const onLaunchApp = (event) => {
949
+ const customEvent = event;
950
+ const app = customEvent.detail?.app;
951
+ if (!app?.bundle) return;
952
+ void runBundledApp(app);
953
+ };
954
+ const resolveAppMain = async (app) => {
955
+ const bundle = app.bundle;
956
+ if (!bundle) return void 0;
957
+ if (bundle.main) {
958
+ return bundle.main;
959
+ }
960
+ if (bundle.load) {
961
+ const loaded = await bundle.load();
962
+ return loaded.main;
963
+ }
964
+ return void 0;
965
+ };
966
+ const runBundledApp = async (app) => {
967
+ const bundle = app.bundle;
968
+ if (!bundle) return;
969
+ const main = await resolveAppMain(app);
970
+ if (!main) {
971
+ console.error(`No app main() available for ${bundle.executable}`);
972
+ return;
973
+ }
974
+ const appRootRef = createRef();
464
975
  const winRef = createRef();
465
976
  await $$1(ref).append(
466
- /* @__PURE__ */ jsxs(
977
+ /* @__PURE__ */ jsx(
467
978
  Window,
468
979
  {
469
- width: 300,
470
- height: 200,
471
- title: "Test Window",
980
+ width: bundle.width ?? 720,
981
+ height: bundle.height ?? 480,
982
+ title: bundle.displayName,
983
+ id: bundle.executable,
472
984
  ref: winRef,
473
985
  onClose: () => {
474
- console.log("I WAS CLOSED!");
475
- },
476
- onMaximize: () => {
477
- console.log("I WAS MAXIMIZED!");
986
+ console.log(`${bundle.executable} was closed`);
478
987
  },
479
- onMinimize: () => {
480
- console.log("I WAS MINIMIZED!");
481
- },
482
- children: [
483
- /* @__PURE__ */ jsx("p", { children: "Hello, world!" }),
484
- /* @__PURE__ */ jsxs("section", { class: "field-row", style: "justify-content: space-between;", children: [
485
- /* @__PURE__ */ jsx(
486
- "button",
487
- {
488
- type: "button",
489
- onClick: () => {
490
- console.log("Cancel clicked");
491
- winRef.state?.close();
492
- },
493
- children: "Cancel"
494
- }
495
- ),
496
- /* @__PURE__ */ jsx(Button, { onClick: onOpenWindow, children: "Open Window" }),
497
- /* @__PURE__ */ jsx(
498
- "button",
499
- {
500
- type: "button",
501
- onClick: () => {
502
- console.log("OK clicked");
503
- winRef.state?.close();
504
- },
505
- children: "OK"
506
- }
507
- )
508
- ] })
509
- ]
988
+ children: /* @__PURE__ */ jsx(
989
+ "div",
990
+ {
991
+ class: "defuss-app-root",
992
+ ref: appRootRef,
993
+ onMount: () => {
994
+ void main({ app, container: appRootRef.current });
995
+ }
996
+ }
997
+ )
510
998
  }
511
999
  )
512
1000
  );
513
1001
  };
514
- return /* @__PURE__ */ jsx("div", { class: "defuss-desktop-panel crt", ref, children: /* @__PURE__ */ jsx(Button, { onClick: onOpenWindow, children: "Open Window" }) });
1002
+ const renderDesktopIcons = async () => {
1003
+ const appIcons = desktopShell.apps.filter((app) => app.bundle);
1004
+ await $$1(appIconsRef).update(
1005
+ /* @__PURE__ */ jsx(Fragment, { children: appIcons.map((app) => /* @__PURE__ */ jsx(DesktopIcon, { app }, app.bundle.executable)) })
1006
+ );
1007
+ };
1008
+ let selectionModel = null;
1009
+ const onMountDesktop = () => {
1010
+ void renderDesktopIcons();
1011
+ document.addEventListener("defuss:launch-app", onLaunchApp);
1012
+ selectionModel = new SelectionModel({
1013
+ desktopElement: ref.current,
1014
+ iconsContainer: appIconsRef.current
1015
+ });
1016
+ selectionModel.init();
1017
+ };
1018
+ const onUnmountDesktop = () => {
1019
+ document.removeEventListener("defuss:launch-app", onLaunchApp);
1020
+ selectionModel?.destroy();
1021
+ selectionModel = null;
1022
+ };
1023
+ return /* @__PURE__ */ jsx(
1024
+ "div",
1025
+ {
1026
+ class: "defuss-desktop-panel crt",
1027
+ ref,
1028
+ onMount: onMountDesktop,
1029
+ onUnmount: onUnmountDesktop,
1030
+ children: /* @__PURE__ */ jsx("div", { class: "desktop-icons-grid", ref: appIconsRef })
1031
+ }
1032
+ );
1033
+ }
1034
+
1035
+ function Button({
1036
+ onClick = () => {
1037
+ },
1038
+ disabled = false,
1039
+ children,
1040
+ ref = createRef()
1041
+ }) {
1042
+ return /* @__PURE__ */ jsx(
1043
+ "button",
1044
+ {
1045
+ ref,
1046
+ type: "button",
1047
+ onClick: disabled ? void 0 : onClick,
1048
+ disabled,
1049
+ children
1050
+ }
1051
+ );
515
1052
  }
516
1053
 
517
1054
  const LogonScreen = ({
@@ -631,146 +1168,67 @@ const LogonScreen = ({
631
1168
  ] });
632
1169
  };
633
1170
 
634
- class DefussDesktopAppIcon {
635
- constructor(config) {
636
- this.config = config;
637
- }
638
- }
639
- const defaultDesktopOptions = {
640
- icons: [],
641
- backgroundColor: "#000"
642
- };
643
- class DesktopManager {
644
- constructor(options = defaultDesktopOptions) {
645
- this.options = options;
646
- }
647
- el;
648
- state;
649
- resizeObserver;
650
- resizeCallbacks = /* @__PURE__ */ new Set();
651
- init(el, options = this.options) {
652
- this.options = options;
653
- this.el = el;
654
- this.state = this.state || {
655
- icons: this.options.icons.map((icon) => icon.config)
656
- };
657
- this.setupResizeObserver();
658
- this.render(el);
659
- }
660
- render(el) {
661
- el.style.backgroundColor = this.options.backgroundColor;
662
- if (this.options.backgroundImage) {
663
- el.style.backgroundImage = `url(${this.options.backgroundImage})`;
664
- }
665
- if (this.options.backgroundImageSize) {
666
- el.style.backgroundSize = this.options.backgroundImageSize || "cover";
667
- }
668
- if (this.options.backgroundRepeat) {
669
- el.style.backgroundRepeat = this.options.backgroundRepeat || "no-repeat";
670
- }
671
- if (this.options.backgroundPosition) {
672
- el.style.backgroundPosition = this.options.backgroundPosition || "center";
673
- }
674
- }
675
- addIcon(icon) {
676
- this.options.icons.push(icon);
677
- console.log(`Icon added: ${icon.config.name}`);
678
- }
679
- getDimensions() {
680
- if (!this.el) {
681
- throw new Error("Desktop not initialized. Call init() first.");
682
- }
683
- return {
684
- width: this.el.offsetWidth,
685
- height: this.el.offsetHeight - taskbarManager.getDimensions().height
686
- // destop is root element minus taskbar height
687
- };
688
- }
689
- setupResizeObserver() {
690
- if (!this.el) return;
691
- if (this.resizeObserver) {
692
- this.resizeObserver.disconnect();
693
- }
694
- this.resizeObserver = new ResizeObserver(() => {
695
- const dimensions = this.getDimensions();
696
- this.resizeCallbacks.forEach((callback) => {
697
- try {
698
- callback(dimensions);
699
- } catch (error) {
700
- console.error("Error in desktop resize callback:", error);
701
- }
702
- });
703
- });
704
- this.resizeObserver.observe(this.el);
705
- }
706
- /**
707
- * Register a callback for desktop resize events
708
- * @param callback Function to call when desktop is resized
709
- * @returns Unregister function to remove the callback
710
- */
711
- onResize(callback) {
712
- this.resizeCallbacks.add(callback);
713
- return () => {
714
- this.resizeCallbacks.delete(callback);
715
- };
716
- }
717
- }
718
- globalThis.__defussDesktopManager = globalThis.__defussDesktopManager || new DesktopManager();
719
- const desktopManager = globalThis.__defussDesktopManager;
720
-
721
1171
  const StartMenu = () => {
1172
+ const bundledApps = desktopShell.apps.filter((app) => app.bundle);
722
1173
  return /* @__PURE__ */ jsxs("div", { class: "slide-open crt", children: [
723
1174
  /* @__PURE__ */ jsx("div", { class: "top", children: /* @__PURE__ */ jsx("h1", { children: "Aron Homberg" }) }),
724
1175
  /* @__PURE__ */ jsxs("div", { class: "menu", children: [
725
- /* @__PURE__ */ jsx("div", { class: "programs", children: /* @__PURE__ */ jsxs("ul", { children: [
726
- /* @__PURE__ */ jsxs("li", { tabindex: "-1", children: [
727
- /* @__PURE__ */ jsx("a", { class: "program-image", href: "#", children: /* @__PURE__ */ jsx("img", { src: "/icons/ie.png", alt: "" }) }),
728
- /* @__PURE__ */ jsx("a", { href: "#", children: "Internet Explorer" })
729
- ] }),
730
- /* @__PURE__ */ jsxs("li", { tabindex: "-1", children: [
731
- /* @__PURE__ */ jsx("a", { class: "program-image", href: "#", children: /* @__PURE__ */ jsx("img", { src: "/icons/paint.png", alt: "" }) }),
732
- /* @__PURE__ */ jsx("a", { href: "#", children: "Paint" })
733
- ] }),
734
- /* @__PURE__ */ jsxs("li", { tabindex: "-1", children: [
735
- /* @__PURE__ */ jsx("a", { class: "program-image", href: "#", children: /* @__PURE__ */ jsx("img", { src: "/icons/media-player.png", alt: "" }) }),
736
- /* @__PURE__ */ jsx("a", { href: "#", children: "Windows Media Player" })
737
- ] }),
738
- /* @__PURE__ */ jsxs("li", { tabindex: "-1", children: [
739
- /* @__PURE__ */ jsx("a", { class: "program-image", href: "#", children: /* @__PURE__ */ jsx("img", { src: "/icons/outlook-express.jpg", alt: "" }) }),
740
- /* @__PURE__ */ jsx("a", { href: "#", children: "E-mail" })
741
- ] })
742
- ] }) }),
1176
+ /* @__PURE__ */ jsx("div", { class: "programs", children: /* @__PURE__ */ jsx("ul", { children: bundledApps.map((app) => /* @__PURE__ */ jsxs("li", { tabindex: "-1", children: [
1177
+ /* @__PURE__ */ jsx(
1178
+ "a",
1179
+ {
1180
+ class: "program-image",
1181
+ href: "#",
1182
+ onClick: (event) => {
1183
+ event.preventDefault();
1184
+ desktopShell.runApp(app.bundle.executable);
1185
+ },
1186
+ children: /* @__PURE__ */ jsx("img", { src: app.bundle.icon, alt: "" })
1187
+ }
1188
+ ),
1189
+ /* @__PURE__ */ jsx(
1190
+ "a",
1191
+ {
1192
+ href: "#",
1193
+ onClick: (event) => {
1194
+ event.preventDefault();
1195
+ desktopShell.runApp(app.bundle.executable);
1196
+ },
1197
+ children: app.bundle.displayName
1198
+ }
1199
+ )
1200
+ ] }, app.bundle.executable)) }) }),
743
1201
  /* @__PURE__ */ jsx("div", { class: "system", children: /* @__PURE__ */ jsxs("ul", { children: [
744
1202
  /* @__PURE__ */ jsxs("li", { tabindex: "-1", children: [
745
- /* @__PURE__ */ jsx("a", { href: "#", class: "program-image", children: /* @__PURE__ */ jsx("img", { src: "/icons/documents.png", alt: "" }) }),
1203
+ /* @__PURE__ */ jsx("a", { href: "#", class: "program-image", children: /* @__PURE__ */ jsx("img", { src: "/desktop/documents.png", alt: "" }) }),
746
1204
  /* @__PURE__ */ jsx("a", { href: "#", children: "My Documents" })
747
1205
  ] }),
748
1206
  /* @__PURE__ */ jsxs("li", { tabindex: "-1", children: [
749
- /* @__PURE__ */ jsx("a", { href: "#", class: "program-image", children: /* @__PURE__ */ jsx("img", { src: "/icons/pictures.png", alt: "" }) }),
1207
+ /* @__PURE__ */ jsx("a", { href: "#", class: "program-image", children: /* @__PURE__ */ jsx("img", { src: "/desktop/pictures.png", alt: "" }) }),
750
1208
  /* @__PURE__ */ jsx("a", { href: "#", children: "My Pictures" })
751
1209
  ] }),
752
1210
  /* @__PURE__ */ jsxs("li", { tabindex: "-1", children: [
753
- /* @__PURE__ */ jsx("a", { href: "#", class: "program-image", children: /* @__PURE__ */ jsx("img", { src: "/icons/music.png", alt: "" }) }),
1211
+ /* @__PURE__ */ jsx("a", { href: "#", class: "program-image", children: /* @__PURE__ */ jsx("img", { src: "/desktop/music.png", alt: "" }) }),
754
1212
  /* @__PURE__ */ jsx("a", { href: "#", children: "My Music" })
755
1213
  ] }),
756
1214
  /* @__PURE__ */ jsxs("li", { tabindex: "-1", children: [
757
- /* @__PURE__ */ jsx("a", { href: "#", class: "program-image", children: /* @__PURE__ */ jsx("img", { src: "/icons/computer.png", alt: "" }) }),
1215
+ /* @__PURE__ */ jsx("a", { href: "#", class: "program-image", children: /* @__PURE__ */ jsx("img", { src: "/desktop/computer.png", alt: "" }) }),
758
1216
  /* @__PURE__ */ jsx("a", { href: "#", children: "My Computer" })
759
1217
  ] }),
760
1218
  /* @__PURE__ */ jsxs("li", { tabindex: "-1", children: [
761
- /* @__PURE__ */ jsx("a", { href: "#", class: "program-image", children: /* @__PURE__ */ jsx("img", { src: "/icons/control-panel.png", alt: "" }) }),
1219
+ /* @__PURE__ */ jsx("a", { href: "#", class: "program-image", children: /* @__PURE__ */ jsx("img", { src: "/desktop/control-panel.png", alt: "" }) }),
762
1220
  /* @__PURE__ */ jsx("a", { href: "#", children: "Control Panel" })
763
1221
  ] }),
764
1222
  /* @__PURE__ */ jsxs("li", { tabindex: "-1", children: [
765
- /* @__PURE__ */ jsx("a", { href: "#", class: "program-image", children: /* @__PURE__ */ jsx("img", { src: "/icons/support-help.png", alt: "" }) }),
1223
+ /* @__PURE__ */ jsx("a", { href: "#", class: "program-image", children: /* @__PURE__ */ jsx("img", { src: "/desktop/support-help.png", alt: "" }) }),
766
1224
  /* @__PURE__ */ jsx("a", { href: "#", children: "Help and Support" })
767
1225
  ] }),
768
1226
  /* @__PURE__ */ jsxs("li", { tabindex: "-1", children: [
769
- /* @__PURE__ */ jsx("a", { href: "#", class: "program-image", children: /* @__PURE__ */ jsx("img", { src: "/icons/search.png", alt: "" }) }),
1227
+ /* @__PURE__ */ jsx("a", { href: "#", class: "program-image", children: /* @__PURE__ */ jsx("img", { src: "/desktop/search.png", alt: "" }) }),
770
1228
  /* @__PURE__ */ jsx("a", { href: "#", children: "Search" })
771
1229
  ] }),
772
1230
  /* @__PURE__ */ jsxs("li", { tabindex: "-1", children: [
773
- /* @__PURE__ */ jsx("a", { href: "#", class: "program-image", children: /* @__PURE__ */ jsx("img", { src: "/icons/run.png", alt: "" }) }),
1231
+ /* @__PURE__ */ jsx("a", { href: "#", class: "program-image", children: /* @__PURE__ */ jsx("img", { src: "/desktop/run.png", alt: "" }) }),
774
1232
  /* @__PURE__ */ jsx("a", { href: "#", children: "Run..." })
775
1233
  ] })
776
1234
  ] }) })
@@ -795,11 +1253,63 @@ const StartButton = () => {
795
1253
  };
796
1254
 
797
1255
  const Taskbar = () => {
798
- return /* @__PURE__ */ jsxs("div", { class: "bar crt", children: [
1256
+ const taskbarListRef = createRef();
1257
+ const clockRef = createRef();
1258
+ const renderTasks = async () => {
1259
+ const windows = [...windowManager.windows];
1260
+ const activeWindow = windowManager.getActiveWindow();
1261
+ await $$1(taskbarListRef).update(
1262
+ /* @__PURE__ */ jsx(Fragment, { children: windows.map((win) => /* @__PURE__ */ jsx("li", { class: activeWindow?.id === win.id && !win.minimized ? "active" : "", children: /* @__PURE__ */ jsx(
1263
+ "button",
1264
+ {
1265
+ type: "button",
1266
+ class: "taskbar__task-btn",
1267
+ onClick: () => {
1268
+ const current = windowManager.getWindow(win.id);
1269
+ if (!current) return;
1270
+ if (current.minimized) {
1271
+ windowManager.restoreWindow(current.id);
1272
+ return;
1273
+ }
1274
+ const active = windowManager.getActiveWindow();
1275
+ if (active?.id === current.id) {
1276
+ windowManager.minimizeWindow(current.id);
1277
+ return;
1278
+ }
1279
+ windowManager.setActiveWindow(current.id);
1280
+ },
1281
+ children: /* @__PURE__ */ jsxs("div", { class: "cell", children: [
1282
+ win.icon ? /* @__PURE__ */ jsx("img", { src: win.icon, alt: "" }) : null,
1283
+ /* @__PURE__ */ jsx("span", { class: "cell-name", children: win.title })
1284
+ ] })
1285
+ }
1286
+ ) }, win.id)) })
1287
+ );
1288
+ };
1289
+ const renderClock = () => {
1290
+ const now = /* @__PURE__ */ new Date();
1291
+ const value = now.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" });
1292
+ $$1(clockRef).text(value);
1293
+ };
1294
+ const onMount = () => {
1295
+ void renderTasks();
1296
+ renderClock();
1297
+ const unsubscribe = windowManager.subscribe(() => {
1298
+ void renderTasks();
1299
+ });
1300
+ const interval = setInterval(renderClock, 3e4);
1301
+ clockRef.state = { unsubscribe, interval };
1302
+ };
1303
+ const onUnmount = () => {
1304
+ const state = clockRef.state;
1305
+ state?.unsubscribe?.();
1306
+ if (state?.interval) clearInterval(state.interval);
1307
+ };
1308
+ return /* @__PURE__ */ jsxs("div", { class: "bar crt", onMount, onUnmount, children: [
799
1309
  /* @__PURE__ */ jsx(StartButton, {}),
800
- /* @__PURE__ */ jsx("ul", { class: "taskbar" }),
1310
+ /* @__PURE__ */ jsx("ul", { class: "taskbar", ref: taskbarListRef }),
801
1311
  /* @__PURE__ */ jsx("div", { class: "tray-toggle", children: /* @__PURE__ */ jsx("div", { class: "arrow" }) }),
802
- /* @__PURE__ */ jsx("div", { class: "taskbar__clock", children: /* @__PURE__ */ jsx("span", { children: "7:02 AM" }) })
1312
+ /* @__PURE__ */ jsx("div", { class: "taskbar__clock", children: /* @__PURE__ */ jsx("span", { ref: clockRef, children: "--:--" }) })
803
1313
  ] });
804
1314
  };
805
1315
 
@@ -821,29 +1331,37 @@ function Shell({
821
1331
  ] });
822
1332
  }
823
1333
 
824
- class DesktopShellManager {
825
- constructor(apps = []) {
826
- this.apps = apps;
827
- }
828
- addApp(app) {
829
- this.apps.push(app);
830
- console.log(`App added: ${app.config.name}`);
831
- }
832
- }
833
- globalThis.__defussDesktopShellManager = globalThis.__defussDesktopShellManager || new DesktopShellManager();
834
- const desktopShell = globalThis.__defussDesktopShellManager;
835
-
836
1334
  class DefussApp {
837
1335
  constructor(config) {
838
1336
  this.config = config;
839
1337
  desktopShell.addApp(this);
840
1338
  }
1339
+ bundle;
1340
+ static fromBundle(bundle) {
1341
+ const app = new DefussApp({
1342
+ name: bundle.displayName,
1343
+ icon: bundle.icon,
1344
+ main: () => {
1345
+ }
1346
+ });
1347
+ app.bundle = bundle;
1348
+ return app;
1349
+ }
841
1350
  run() {
842
1351
  console.log(`Running app: ${this.config.name}`);
843
- this.config.main(this, ...this.config.argv || []);
1352
+ if (this.bundle) {
1353
+ desktopShell.launchApp(this);
1354
+ } else {
1355
+ this.config.main(this, ...this.config.argv || []);
1356
+ }
844
1357
  }
845
1358
  }
846
1359
 
1360
+ var app = /*#__PURE__*/Object.freeze({
1361
+ __proto__: null,
1362
+ DefussApp: DefussApp
1363
+ });
1364
+
847
1365
  class DequeryWithWindowManager extends CallChainImpl {
848
1366
  /*
849
1367
  // create a window from any element (not necessarily identifier as an App)
@@ -855,15 +1373,12 @@ class DequeryWithWindowManager extends CallChainImpl {
855
1373
  */
856
1374
  // register an app to the desktop shell
857
1375
  createDesktopApp(options) {
858
- return createCall(this, "createDesktopApp", async () => {
859
- return new DefussApp(options);
860
- });
1376
+ new DefussApp(options);
1377
+ return this;
861
1378
  }
862
1379
  // create a desktop app icon
863
1380
  createDesktopAppIcon(options) {
864
- return createCall(this, "createDesktopAppIcon", async () => {
865
- return new DefussDesktopAppIcon(options);
866
- });
1381
+ return this;
867
1382
  }
868
1383
  }
869
1384
  const $ = dequery.extend(DequeryWithWindowManager, [
@@ -872,37 +1387,6 @@ const $ = dequery.extend(DequeryWithWindowManager, [
872
1387
  "createDesktopAppIcon"
873
1388
  ]);
874
1389
 
875
- const defaultTaskbarOptions = {
876
- position: "bottom",
877
- stateful: false,
878
- theme: "default",
879
- size: "medium"
880
- };
881
- class TaskbarManager {
882
- position;
883
- theme;
884
- // e.g., 'windows-xp', 'macos', etc.
885
- size;
886
- constructor(options = defaultTaskbarOptions) {
887
- this.position = options.position || "bottom";
888
- this.theme = options.theme || "default";
889
- this.size = options.size || "medium";
890
- if (options.stateful) ;
891
- }
892
- getDimensions() {
893
- const el = document.querySelector(".taskbar");
894
- if (!el) {
895
- return { width: 0, height: 0 };
896
- }
897
- return {
898
- width: el.clientWidth,
899
- height: el.clientHeight
900
- };
901
- }
902
- }
903
- globalThis.__defussTaskbarManager = globalThis.__defussTaskbarManager || new TaskbarManager();
904
- const taskbarManager = globalThis.__defussTaskbarManager;
905
-
906
1390
  const defaultSystemSoundFilePaths = [
907
1391
  "/sounds/balloon.ogg",
908
1392
  "/sounds/batterycritical.ogg",
@@ -1031,4 +1515,22 @@ class SoundManager {
1031
1515
  globalThis.__defussSoundManager = globalThis.__defussSoundManager || new SoundManager();
1032
1516
  const soundManager = globalThis.__defussSoundManager;
1033
1517
 
1034
- export { $, Button, DefussApp, DefussDesktopAppIcon, DequeryWithWindowManager, Desktop, DesktopManager, DesktopShellManager, LogonScreen, Shell, SoundManager, StartButton, StartMenu, Taskbar, TaskbarManager, WindowManager, defaultDesktopOptions, defaultSystemSoundFilePaths, defaultTaskbarOptions, defaultWindowOptions, desktopManager, desktopShell, soundManager, taskbarManager, windowManager };
1518
+ const notepadAppBundle = {
1519
+ executable: "notepad.exe",
1520
+ displayName: "Notepad",
1521
+ icon: "/desktop/documents.png",
1522
+ width: 760,
1523
+ height: 520,
1524
+ load: () => import('./notepad-Cwg2fv8c.mjs')
1525
+ };
1526
+
1527
+ const internetExplorerAppBundle = {
1528
+ executable: "explorer.exe",
1529
+ displayName: "Internet Explorer",
1530
+ icon: "/desktop/internet-explorer.png",
1531
+ width: 980,
1532
+ height: 680,
1533
+ load: () => import('./internet-explorer-CAgm9-7A.mjs')
1534
+ };
1535
+
1536
+ export { $, Button, DefussApp, DefussDesktopAppIcon, DequeryWithWindowManager, Desktop, DesktopIcon, DesktopManager, DesktopShellManager, LogonScreen, SelectionModel, Shell, SoundManager, StartButton, StartMenu, Taskbar, TaskbarManager, WindowManager, defaultDesktopOptions, defaultSystemSoundFilePaths, defaultTaskbarOptions, defaultWindowOptions, desktopManager, desktopShell, internetExplorerAppBundle, notepadAppBundle, soundManager, taskbarManager, windowManager };