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/README.md +16 -16
- package/dist/index.cjs +749 -243
- package/dist/index.d.cts +77 -6
- package/dist/index.d.mts +77 -6
- package/dist/index.mjs +748 -246
- package/dist/internet-explorer-CAgm9-7A.mjs +35 -0
- package/dist/internet-explorer-CajUFG-6.cjs +37 -0
- package/dist/notepad-Cwg2fv8c.mjs +20 -0
- package/dist/notepad-D2pcJRhu.cjs +22 -0
- package/dist/scss/_apps.scss +75 -0
- package/dist/scss/_desktop-icons.scss +89 -0
- package/dist/scss/_taskbar.scss +32 -4
- package/dist/scss/_window.scss +75 -2
- package/dist/scss/index.scss +2 -0
- package/package.json +10 -9
package/dist/index.mjs
CHANGED
|
@@ -1,26 +1,263 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { $ as $$1, createRef, dequery, CallChainImpl } from 'defuss';
|
|
2
2
|
import { debounce, throttle } from 'defuss-runtime';
|
|
3
|
-
import { jsx,
|
|
3
|
+
import { jsxs, jsx, Fragment } from 'defuss/jsx-runtime';
|
|
4
4
|
import { access, transval, rule } from 'defuss-transval';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
{
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
220
|
-
|
|
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
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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
|
-
|
|
232
|
-
|
|
233
|
-
left: isMinimized ? "-10000px" : `${win.x}px`,
|
|
234
|
-
top: isMinimized ? "-10000px" : `${win.y}px`
|
|
488
|
+
left: "-10000px",
|
|
489
|
+
top: "-10000px"
|
|
235
490
|
});
|
|
236
|
-
|
|
237
|
-
|
|
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)
|
|
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
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
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__ */
|
|
977
|
+
/* @__PURE__ */ jsx(
|
|
467
978
|
Window,
|
|
468
979
|
{
|
|
469
|
-
width:
|
|
470
|
-
height:
|
|
471
|
-
title:
|
|
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(
|
|
475
|
-
},
|
|
476
|
-
onMaximize: () => {
|
|
477
|
-
console.log("I WAS MAXIMIZED!");
|
|
986
|
+
console.log(`${bundle.executable} was closed`);
|
|
478
987
|
},
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
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
|
-
|
|
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__ */
|
|
726
|
-
/* @__PURE__ */
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
/* @__PURE__ */
|
|
739
|
-
|
|
740
|
-
|
|
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: "/
|
|
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: "/
|
|
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: "/
|
|
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: "/
|
|
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: "/
|
|
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: "/
|
|
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: "/
|
|
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: "/
|
|
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
|
-
|
|
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", {
|
|
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
|
-
|
|
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
|
-
|
|
859
|
-
|
|
860
|
-
});
|
|
1376
|
+
new DefussApp(options);
|
|
1377
|
+
return this;
|
|
861
1378
|
}
|
|
862
1379
|
// create a desktop app icon
|
|
863
1380
|
createDesktopAppIcon(options) {
|
|
864
|
-
return
|
|
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
|
-
|
|
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 };
|