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