tildewin/script.js
2025-08-26 23:19:24 +02:00

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">&times;</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;
}
}