diff --git a/icons/folder.png b/icons/folder.png new file mode 100644 index 0000000..6cd9908 Binary files /dev/null and b/icons/folder.png differ diff --git a/icons/notepad.png b/icons/notepad.png new file mode 100644 index 0000000..0426663 Binary files /dev/null and b/icons/notepad.png differ diff --git a/icons/trash.png b/icons/trash.png new file mode 100644 index 0000000..3cbf73d Binary files /dev/null and b/icons/trash.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..10ff36d --- /dev/null +++ b/index.html @@ -0,0 +1,15 @@ + + + + + + + My Desktop Page + + +
+
+ + + + diff --git a/script.js b/script.js new file mode 100644 index 0000000..b917427 --- /dev/null +++ b/script.js @@ -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", + ``, + true, + 500, + 400 + ) + }, + { + label: "Notes", + icon: "icons/notepad.png", + width: 400, + height: 300, + action: () => + openNewWindow( + "Notes", + ``, + true, + 400, + 300 + ) + }, + { + label: "Recycle Bin", + icon: "icons/trash.png", + width: 300, + height: 200, + action: () => + openNewWindow( + "Recycle Bin", + `

Your trash goes here.

`, + false, + 300, + 200 + ) + }, + { + label: "CSS Art", + icon: "icons/folder.png", + width: 600, + height: 500, + action: () => + openNewWindow( + "CSS Art", + ``, + true, + 600, + 600 + ) + } + ]; + + shortcutData.forEach(({ label, icon, action }) => { + const shortcut = document.createElement("div"); + shortcut.className = "shortcut"; + + shortcut.innerHTML = ` + ${label} + ${label} + `; + + 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 = ` +
+
${title}
+ +
+
${contentHTML}
+ `; + + 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; + } +} + diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..774ac19 --- /dev/null +++ b/styles.css @@ -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; } +