feat: Add initial mess

This commit is contained in:
cymen 2025-08-26 21:00:00 +02:00
parent 1988edaafe
commit 59fa42e6c0
6 changed files with 430 additions and 0 deletions

BIN
icons/folder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
icons/notepad.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 843 B

BIN
icons/trash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 B

15
index.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="styles.css" />
<title>My Desktop Page</title>
</head>
<body>
<div class="desktop">
</div>
<script src="script.js"></script>
</body>
</html>

259
script.js Normal file
View File

@ -0,0 +1,259 @@
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;
}
}

156
styles.css Normal file
View File

@ -0,0 +1,156 @@
body {
font-family: Tahoma, sans-serif;
margin: 2rem;
background-color: #e0b0ff;
}
.window {
position: absolute;
border: 1px solid #555;
border-radius: 10px;
box-shadow:
0 4px 8px rgba(0, 0, 0, 0.3), /* Soft outer shadow */
inset 0 0 5px rgba(255, 255, 255, 0.1); /* Inner highlight for 3D */
overflow: hidden;
background-color: #f0f0f0;
font-family: sans-serif;
cursor: default;
display: flex;
flex-direction: column;
height: auto; /* allow flexible height */
box-sizing: border-box;
}
.titlebar .title {
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.titlebar {
width: 100%;
height: 30px;
background: linear-gradient(to bottom, #8a2be2, #6a1dbf);
color: white;
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 10px;
box-sizing: border-box;
cursor: move;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
box-shadow: inset 0 -1px 1px rgba(255, 255, 255, 0.3);
}
.content {
padding: 10px;
background: #C0C0C0;
overflow: auto;
box-sizing: border-box;
}
.close-btn {
background: transparent;
border: none;
color: white;
font-size: 20px;
margin-right: 8px;
cursor: pointer;
transition: color 0.2s ease;
}
.close-btn:hover {
color: #ffaaaa;
}
.desktop {
display: grid;
grid-template-columns: repeat(auto-fill, 80px);
grid-auto-rows: 100px;
gap: 20px;
padding: 20px;
position: absolute;
top: 0;
left: 0;
z-index: 0;
}
.shortcut {
width: 80px;
text-align: center;
color: black;
font-size: 12px;
font-family: sans-serif;
margin: 10px;
cursor: pointer;
user-select: none;
}
.shortcut img {
width: 32px;
height: 32px;
display: block;
margin: 0 auto 5px;
}
.shortcut span {
display: block;
text-shadow: 1px 1px 2px white;
}
.content textarea {
font-family: monospace;
padding: 8px;
resize: none;
outline: none;
}
.content iframe,
.content textarea {
width: 100%;
height: 100%;
border-radius: 6px;
border: none;
}
.window .resizer {
position: absolute;
background: transparent;
z-index: 10;
}
/* Corners */
.window .resizer.nw, .window .resizer.ne,
.window .resizer.sw, .window .resizer.se {
width: 10px;
height: 10px;
}
.window .resizer.nw { top: 0; left: 0; cursor: nw-resize; }
.window .resizer.ne { top: 0; right: 0; cursor: ne-resize; }
.window .resizer.sw { bottom: 0; left: 0; cursor: sw-resize; }
.window .resizer.se { bottom: 0; right: 0; cursor: se-resize; }
/* Sides */
.window .resizer.n, .window .resizer.s {
height: 6px;
left: 0;
right: 0;
cursor: ns-resize;
}
.window .resizer.n { top: 0; }
.window .resizer.s { bottom: 0; }
.window .resizer.e, .window .resizer.w {
width: 6px;
top: 0;
bottom: 0;
cursor: ew-resize;
}
.window .resizer.e { right: 0; }
.window .resizer.w { left: 0; }