260 lines
5.8 KiB
JavaScript
260 lines
5.8 KiB
JavaScript
let highestZIndex = 100;
|
|
|
|
function init() {
|
|
const desktop = document.querySelector(".desktop");
|
|
|
|
const shortcutData = [
|
|
{
|
|
label: "My Files",
|
|
icon: "icons/folder.png",
|
|
width: 500,
|
|
height: 400,
|
|
action: () =>
|
|
openNewWindow(
|
|
"My Files",
|
|
`<iframe src="https://98.js.org"></iframe>`,
|
|
true,
|
|
500,
|
|
400
|
|
)
|
|
},
|
|
{
|
|
label: "Notes",
|
|
icon: "icons/notepad.png",
|
|
width: 400,
|
|
height: 300,
|
|
action: () =>
|
|
openNewWindow(
|
|
"Notes",
|
|
`<textarea>hello...</textarea>`,
|
|
true,
|
|
400,
|
|
300
|
|
)
|
|
},
|
|
{
|
|
label: "Recycle Bin",
|
|
icon: "icons/trash.png",
|
|
width: 300,
|
|
height: 200,
|
|
action: () =>
|
|
openNewWindow(
|
|
"Recycle Bin",
|
|
`<p>Your trash goes here.</p>`,
|
|
false,
|
|
300,
|
|
200
|
|
)
|
|
},
|
|
{
|
|
label: "CSS Art",
|
|
icon: "icons/folder.png",
|
|
width: 600,
|
|
height: 500,
|
|
action: () =>
|
|
openNewWindow(
|
|
"CSS Art",
|
|
`<iframe src="https://tilde.town/~dozens/cssart/quarters.html"></iframe>`,
|
|
true,
|
|
600,
|
|
600
|
|
)
|
|
}
|
|
];
|
|
|
|
shortcutData.forEach(({ label, icon, action }) => {
|
|
const shortcut = document.createElement("div");
|
|
shortcut.className = "shortcut";
|
|
|
|
shortcut.innerHTML = `
|
|
<img src="${icon}" alt="${label}" />
|
|
<span>${label}</span>
|
|
`;
|
|
|
|
shortcut.addEventListener("dblclick", action);
|
|
document.querySelector(".desktop").appendChild(shortcut);
|
|
});
|
|
}
|
|
|
|
init();
|
|
|
|
function openNewWindow(title, contentHTML, fullSizeContent = false, width = 300, height = 200) {
|
|
const newWin = document.createElement("div");
|
|
newWin.className = "window";
|
|
|
|
const viewportWidth = window.innerWidth;
|
|
const viewportHeight = window.innerHeight;
|
|
const randomLeft = Math.floor(Math.random() * (viewportWidth - 320));
|
|
const randomTop = Math.floor(Math.random() * (viewportHeight - 200));
|
|
newWin.style.left = `${randomLeft}px`;
|
|
newWin.style.top = `${randomTop}px`;
|
|
|
|
newWin.innerHTML = `
|
|
<div class="titlebar">
|
|
<div class="title">${title}</div>
|
|
<button class="close-btn" aria-label="Close window">×</button>
|
|
</div>
|
|
<div class="content">${contentHTML}</div>
|
|
`;
|
|
|
|
const resizers = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];
|
|
resizers.forEach(pos => {
|
|
const resizer = document.createElement("div");
|
|
resizer.className = `resizer ${pos}`;
|
|
newWin.appendChild(resizer);
|
|
});
|
|
|
|
document.body.appendChild(newWin);
|
|
|
|
bringToFront(newWin);
|
|
|
|
const content = newWin.querySelector(".content");
|
|
content.style.width = `${width}px`;
|
|
content.style.height = `${height}px`;
|
|
|
|
if (fullSizeContent) {
|
|
content.style.padding = "0";
|
|
}
|
|
|
|
// Bring window to front when clicked
|
|
newWin.addEventListener("mousedown", () => {
|
|
bringToFront(newWin);
|
|
});
|
|
|
|
// Dragging logic
|
|
const titlebar = newWin.querySelector(".titlebar");
|
|
let isDragging = false;
|
|
let offsetX = 0;
|
|
let offsetY = 0;
|
|
|
|
titlebar.addEventListener("mousedown", (e) => {
|
|
if (e.target.classList.contains("close-btn")) return;
|
|
isDragging = true;
|
|
const rect = newWin.getBoundingClientRect();
|
|
offsetX = e.clientX - rect.left;
|
|
offsetY = e.clientY - rect.top;
|
|
document.body.style.userSelect = 'none';
|
|
});
|
|
|
|
document.addEventListener("mousemove", (e) => {
|
|
if (!isDragging) return;
|
|
newWin.style.left = `${e.clientX - offsetX}px`;
|
|
newWin.style.top = `${e.clientY - offsetY}px`;
|
|
});
|
|
|
|
document.addEventListener("mouseup", () => {
|
|
if (isDragging) {
|
|
isDragging = false;
|
|
document.body.style.userSelect = '';
|
|
}
|
|
});
|
|
|
|
// Close button logic
|
|
const closeBtn = newWin.querySelector(".close-btn");
|
|
closeBtn.addEventListener("click", () => {
|
|
newWin.remove();
|
|
});
|
|
|
|
let isResizing = false;
|
|
let currentResizer = null;
|
|
|
|
const minWidth = 200;
|
|
const minHeight = 150;
|
|
|
|
const startResize = (e, resizer) => {
|
|
e.preventDefault();
|
|
isResizing = true;
|
|
currentResizer = resizer;
|
|
|
|
const rect = newWin.getBoundingClientRect();
|
|
newWin.dataset.startX = e.clientX;
|
|
newWin.dataset.startY = e.clientY;
|
|
newWin.dataset.startWidth = rect.width;
|
|
newWin.dataset.startHeight = rect.height;
|
|
newWin.dataset.startLeft = rect.left;
|
|
newWin.dataset.startTop = rect.top;
|
|
|
|
document.body.style.userSelect = "none";
|
|
};
|
|
|
|
const onMouseMove = (e) => {
|
|
if (!isResizing || !currentResizer) return;
|
|
|
|
const dx = e.clientX - newWin.dataset.startX;
|
|
const dy = e.clientY - newWin.dataset.startY;
|
|
|
|
let newWidth = parseFloat(newWin.dataset.startWidth);
|
|
let newHeight = parseFloat(newWin.dataset.startHeight);
|
|
let newLeft = parseFloat(newWin.dataset.startLeft);
|
|
let newTop = parseFloat(newWin.dataset.startTop);
|
|
|
|
switch (currentResizer) {
|
|
case 'e':
|
|
newWidth += dx;
|
|
break;
|
|
case 's':
|
|
newHeight += dy;
|
|
break;
|
|
case 'se':
|
|
newWidth += dx;
|
|
newHeight += dy;
|
|
break;
|
|
case 'w':
|
|
newWidth -= dx;
|
|
newLeft += dx;
|
|
break;
|
|
case 'n':
|
|
newHeight -= dy;
|
|
newTop += dy;
|
|
break;
|
|
case 'nw':
|
|
newWidth -= dx;
|
|
newLeft += dx;
|
|
newHeight -= dy;
|
|
newTop += dy;
|
|
break;
|
|
case 'ne':
|
|
newWidth += dx;
|
|
newHeight -= dy;
|
|
newTop += dy;
|
|
break;
|
|
case 'sw':
|
|
newWidth -= dx;
|
|
newLeft += dx;
|
|
newHeight += dy;
|
|
break;
|
|
}
|
|
|
|
if (newWidth >= minWidth) {
|
|
newWin.style.width = `${newWidth}px`;
|
|
newWin.style.left = `${newLeft}px`;
|
|
content.style.width = `${newWidth}px`;
|
|
}
|
|
if (newHeight >= minHeight) {
|
|
newWin.style.height = `${newHeight}px`;
|
|
newWin.style.top = `${newTop}px`;
|
|
content.style.height = `${newHeight - titlebar.offsetHeight}px`;
|
|
}
|
|
};
|
|
|
|
const stopResize = () => {
|
|
isResizing = false;
|
|
currentResizer = null;
|
|
document.body.style.userSelect = "";
|
|
};
|
|
|
|
resizers.forEach(pos => {
|
|
const el = newWin.querySelector(`.resizer.${pos}`);
|
|
el.addEventListener("mousedown", (e) => startResize(e, pos));
|
|
});
|
|
|
|
document.addEventListener("mousemove", onMouseMove);
|
|
document.addEventListener("mouseup", stopResize);
|
|
|
|
function bringToFront(win) {
|
|
highestZIndex++;
|
|
win.style.zIndex = highestZIndex;
|
|
}
|
|
}
|
|
|