From 55e1616e1b7601d2ae6b2c72c6fa0055399fff73 Mon Sep 17 00:00:00 2001 From: usernames122 Date: Sat, 9 Aug 2025 05:25:35 +0200 Subject: [PATCH] first commit --- clickin.wav | Bin 0 -> 10318 bytes clickout.wav | Bin 0 -> 10318 bytes immersion.js | 49 +++++++++ index.html | 23 ++++ script.js | 303 +++++++++++++++++++++++++++++++++++++++++++++++++++ shell.js | 286 ++++++++++++++++++++++++++++++++++++++++++++++++ style.css | 85 +++++++++++++++ 7 files changed, 746 insertions(+) create mode 100644 clickin.wav create mode 100644 clickout.wav create mode 100644 immersion.js create mode 100644 index.html create mode 100644 script.js create mode 100644 shell.js create mode 100644 style.css diff --git a/clickin.wav b/clickin.wav new file mode 100644 index 0000000000000000000000000000000000000000..0204d5f2b99f2e9114c7b45e6c2f68540d766ab1 GIT binary patch literal 10318 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 WJxyr$TqBR(m(fTo4dQ+rEdB|p6+i?4 literal 0 HcmV?d00001 diff --git a/clickout.wav b/clickout.wav new file mode 100644 index 0000000000000000000000000000000000000000..23096ae001d50ec3d5078976c7d4bdcd2a2e627f GIT binary patch literal 10318 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 MD$n)g7|#R$4+2#6+5i9m literal 0 HcmV?d00001 diff --git a/immersion.js b/immersion.js new file mode 100644 index 0000000..a366381 --- /dev/null +++ b/immersion.js @@ -0,0 +1,49 @@ +// immersion.js +(function () { + // Preload audio + const clickIn = new Audio('clickin.wav'); + const clickOut = new Audio('clickout.wav'); + + // Optional: make sure they can play multiple times quickly + clickIn.preload = 'auto'; + clickOut.preload = 'auto'; + + document.addEventListener('mousedown', () => { + // Reset currentTime so rapid clicks restart the sound + clickIn.currentTime = 0; + clickIn.play().catch(err => { + // Ignore if browser blocks autoplay until user interaction + console.warn('Click-in sound not played:', err); + }); + }); + + document.addEventListener('mouseup', () => { + clickOut.currentTime = 0; + clickOut.play().catch(err => { + console.warn('Click-out sound not played:', err); + }); + }); + windowHooks.push(function (e) { + if (e.event === "windowCreate") { + const iframe = e.window.iframe; + iframe.onload = function () { + try { + // Access the iframe's global scope + iframe.contentWindow.clickIn = clickIn; + iframe.contentWindow.clickOut = clickOut; + + // Also attach event listeners inside iframe + const doc = iframe.contentDocument; + doc.addEventListener('mousedown', () => { + clickIn.currentTime = 0; + clickIn.play().catch(() => { }); + }); + doc.addEventListener('mouseup', () => { + clickOut.currentTime = 0; + clickOut.play().catch(() => { }); + }); + } catch { }; + }; + } + }); +})(); diff --git a/index.html b/index.html new file mode 100644 index 0000000..2b18dd6 --- /dev/null +++ b/index.html @@ -0,0 +1,23 @@ + + + + + + + LAMINAX Windower + + + + +
+
+ + + + + + + + diff --git a/script.js b/script.js new file mode 100644 index 0000000..fbd78dc --- /dev/null +++ b/script.js @@ -0,0 +1,303 @@ +// WINDOW MANAGER +const desktop = document.getElementById('desktop'); +const bglayer = document.getElementById('background-layer'); +const newWindowBtn = document.getElementById('new-window-btn'); +let zIndexCounter = 1; + +let focusedWindow = null; +let windows = {}; +let windowHooks = []; + +function uniqueid() { + // always start with a letter (for DOM friendlyness) + var idstr = String.fromCharCode(Math.floor((Math.random() * 25) + 65)); + do { + // between numbers and characters (48 is 0 and 90 is Z (42-48 = 90) + var ascicode = Math.floor((Math.random() * 42) + 48); + if (ascicode < 58 || ascicode > 64) { + // exclude all chars between : (58) and @ (64) + idstr += String.fromCharCode(ascicode); + } + } while (idstr.length < 32); + + return (idstr); +} + +function fadeOut(fadeTarget, speed, callback) { + let eee = 0; + var fadeEffect = setInterval(function () { + if (!fadeTarget.style.opacity) { + fadeTarget.style.opacity = 1; + } + fadeTarget.style.transform = `rotate3d(1, 0, 0, ${eee}deg)`; + if (fadeTarget.style.opacity > 0) { + fadeTarget.style.opacity -= 0.1; + eee += 10; + } else { + clearInterval(fadeEffect); + callback(); + } + }, speed); +} + +function killWind(id) { + const windowDiv = windows[id]?.windElems?.windowDiv; + if (typeof (windowDiv) == "undefined") { + console.warn("Attempted to close undefined window.."); + return; + }; + fadeOut(windowDiv, 20, function () { + windowDiv.remove(); + delete windows[id]; + windowHooks.forEach(element => { + element({ event: "windowDestroy", id: id }) + }); + }); +} + +function focusWindow(id) { + const windData = windows[id]; + const windowDiv = windData?.windElems?.windowDiv; + if (typeof (windData) == "undefined") { + console.warn("Attempted to focus undefined window.."); + return; + }; + windowDiv.style.zIndex = zIndexCounter++; + if (windData.layer == "background") windowDiv.style.zIndex = windowDiv.style.zIndex * -1; + windowHooks.forEach(element => { + element({ event: "windowFocused", id: id }) + }); + Object.keys(windows).forEach(key => { + const element = windows[key]; + if (element.alwaysOnTop) { + element.windElems.windowDiv.style.zIndex = zIndexCounter + 5; + } + }); + focusedWindow = id; +} + +function createWindow(url, settings) { + const windID = uniqueid(); + const name = settings.name; + const headerless = settings.headerless || false; + const resizable = settings.resizable !== undefined ? settings.resizable : true; + const shouldIndent = settings.indent !== undefined ? settings.indent : true; + const layer = settings.layer || "foreground"; + + const windowDiv = document.createElement('div'); + windowDiv.classList.add('window'); + windowDiv.style.top = '50px'; + if (shouldIndent) windowDiv.style.left = '50px'; + windowDiv.style.zIndex = zIndexCounter++; + windowDiv.id = windID; + + // Header + const header = document.createElement('div'); + header.classList.add('window-header'); + + if (headerless) header.classList.add("window-hidden"); + + const title = document.createElement('div'); + title.classList.add('window-title'); + title.textContent = name || url; + + const closeBtn = document.createElement('button'); + closeBtn.classList.add('window-close-btn'); + closeBtn.textContent = '×'; + + header.appendChild(title); + header.appendChild(closeBtn); + windowDiv.appendChild(header); + + // iframe + const iframe = document.createElement('iframe'); + iframe.classList.add('window-iframe'); + iframe.src = url; + windowDiv.appendChild(iframe); + iframe.onload = function () { + try { + iframe.contentDocument.oncontextmenu = function () { + return false; + }; + } catch { }; + }; + + // Add resize handle if resizable + let resizeHandle = null; + if (resizable) { + resizeHandle = document.createElement('div'); + resizeHandle.style.width = '16px'; + resizeHandle.style.height = '16px'; + resizeHandle.style.position = 'absolute'; + resizeHandle.style.right = '0'; + resizeHandle.style.bottom = '0'; + resizeHandle.style.cursor = 'se-resize'; + // Optional: make it visible if you want + // resizeHandle.style.background = 'rgba(0,0,0,0.2)'; + windowDiv.appendChild(resizeHandle); + } + + if (layer == "foreground") desktop.appendChild(windowDiv); + else bglayer.appendChild(windowDiv); + + // Dragging functionality + let isDragging = false; + let offsetX, offsetY; + + header.addEventListener('mousedown', (e) => { + isDragging = true; + offsetX = e.clientX - windowDiv.getBoundingClientRect().left; + offsetY = e.clientY - windowDiv.getBoundingClientRect().top; + focusWindow(windID); + }); + + // Resizing variables + let isResizing = false; + let startWidth, startHeight, startX, startY; + + window.addEventListener('mouseup', () => { + isDragging = false; + isResizing = false; + }); + + window.addEventListener('mousemove', (e) => { + if (isDragging) { + let newX = e.clientX - offsetX; + let newY = e.clientY - offsetY; + + transformWindow(windID, null, null, newX, newY); + + + } else if (isResizing) { + const dx = e.clientX - startX; + const dy = e.clientY - startY; + + const newWidth = startWidth + dx; + const newHeight = startHeight + dy; + + transformWindow(windID, newWidth, newHeight); + } + }); + + // Resize handle mousedown + if (resizeHandle) { + resizeHandle.addEventListener('mousedown', (e) => { + e.stopPropagation(); + isResizing = true; + startWidth = windowDiv.offsetWidth; + startHeight = windowDiv.offsetHeight; + startX = e.clientX; + startY = e.clientY; + focusWindow(windID); + }); + } + + // Focus window on click + windowDiv.addEventListener('mousedown', () => { + focusWindow(windID); + }); + + + + // Close window + closeBtn.addEventListener('click', () => { + killWind(windID); + }); + + const windObj = { + iframe: iframe, + windElems: { + closeBtn: closeBtn, + windowDiv: windowDiv, + header: header, + title: title, + resizeHandle: resizeHandle + }, + windID: windID, + minSizeX: 250, + minSizeY: 150, + alwaysOnTop: false, + layer: layer, + hideInTaskbar: layer == "background" + }; + + windows[windID] = windObj; + windowHooks.forEach(element => { + element({ event: "windowCreate", id: windID, window: windObj }) + }); + return windObj; +} + + +function transformWindow(id, sizex, sizey, posx, posy, ignoreRects) { + const windData = windows[id]; + const windowDiv = windData?.windElems?.windowDiv; + if (typeof (windData) == "undefined") { + console.warn("Attempted to transform undefined window.."); + return; + }; + if (sizex) windowDiv.style.width = Math.max(windData.minSizeX, sizex) + 'px'; + if (sizey) windowDiv.style.height = Math.max(windData.minSizeY, sizey) + 'px'; + const desktopRect = desktop.getBoundingClientRect(); + const winRect = windowDiv.getBoundingClientRect(); + if (posx) { + const newX = ignoreRects ? posx : Math.max(desktopRect.left, Math.min(posx, desktopRect.right - winRect.width)); + windowDiv.style.left = newX - desktopRect.left + 'px'; + } + if (posy) { + const newY = ignoreRects ? posy : Math.max(desktopRect.top, Math.min(posy, desktopRect.bottom - winRect.height)); + windowDiv.style.top = newY - desktopRect.top + 'px'; + } + +} + +function getTransform(id) { + const windData = windows[id]; + const windowDiv = windData?.windElems?.windowDiv; + if (typeof windData === "undefined" || !windowDiv) { + console.warn("Attempted to transform undefined window.."); + return; + } + + const desktopRect = desktop.getBoundingClientRect(); + + // Extract numeric values from style or fallback to computed styles + const style = windowDiv.style; + + // Helper to parse px values safely + function parsePx(val) { + if (!val) return 0; + return Math.floor(parseFloat(val)); + } + + // Use inline style if present, otherwise computed style + let topStr = style.top || window.getComputedStyle(windowDiv).top; + let leftStr = style.left || window.getComputedStyle(windowDiv).left; + let widthStr = style.width || window.getComputedStyle(windowDiv).width; + let heightStr = style.height || window.getComputedStyle(windowDiv).height; + + // Parse numbers from strings like "50px" + const posy = parsePx(topStr); + const posx = parsePx(leftStr); + const sizex = parsePx(widthStr); + const sizey = parsePx(heightStr); + + return { + x: posx, + y: posy, + sizex: sizex, + sizey: sizey + }; +} + + +function updateWindowMin(id) { + const windData = windows[id]; + if (typeof (windData) == "undefined") { + console.warn("Attempted to update undefined window.."); + return; + }; + const transform = getTransform(id); + transformWindow(id,transform.sizex,transform.sizey,transform.posx,transform.posy); + +} \ No newline at end of file diff --git a/shell.js b/shell.js new file mode 100644 index 0000000..872cdda --- /dev/null +++ b/shell.js @@ -0,0 +1,286 @@ +var embeddedApps = { + calc: `data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+PGh0bWwgbGFuZz0iZW4iPjxoZWFkPjxtZXRhIGNoYXJzZXQ9IlVURi04Ij48dGl0bGU+Q2FsY3VsYXRvcjwvdGl0bGU+PHN0eWxlPmJvZHl7bWFyZ2luOjA7Zm9udC1mYW1pbHk6bW9ub3NwYWNlLG1vbm9zcGFjZTtkaXNwbGF5OmZsZXg7anVzdGlmeS1jb250ZW50OmNlbnRlcjthbGlnbi1pdGVtczpjZW50ZXI7aGVpZ2h0OjEwMHZoO2JhY2tncm91bmQ6IzIyMjtjb2xvcjojZWVlfSNjYWxjdWxhdG9ye2JhY2tncm91bmQ6IzMzMztwYWRkaW5nOjFyZW07Ym9yZGVyLXJhZGl1czo4cHg7d2lkdGg6MjIwcHg7Ym94LXNoYWRvdzowIDAgMTBweCAjMDAwfSNkaXNwbGF5e3dpZHRoOjEwMCU7aGVpZ2h0OjQwcHg7Zm9udC1zaXplOjEuMnJlbTtiYWNrZ3JvdW5kOiMxMTE7Ym9yZGVyOm5vbmU7Y29sb3I6I2VlZTtwYWRkaW5nOjAgMDttYXJnaW4tYm90dG9tOjEwcHg7dGV4dC1hbGlnbjpyaWdodH1idXR0b257d2lkdGg6NDhweDtoZWlnaHQ6NDhweDttYXJnaW46MnB4O2ZvbnQtc2l6ZToxLjJyZW07Ym9yZGVyOm5vbmU7Ym9yZGVyLXJhZGl1czo0cHg7Y3Vyc29yOnBvaW50ZXI7YmFja2dyb3VuZDojNTU1O2NvbG9yOiNlZWU7dHJhbnNpdGlvbjpiYWNrZ3JvdW5kIC4ycyBlYXNlfWJ1dHRvbjpob3ZlcntiYWNrZ3JvdW5kOiM3Nzd9Lm9wZXJhdG9ye2JhY2tncm91bmQ6I2Y1N2MwMDtjb2xvcjojZmZmfS5vcGVyYXRvcjpob3ZlcntiYWNrZ3JvdW5kOiNmYjhjMDB9LmVxdWFsc3tiYWNrZ3JvdW5kOiMxOTc2ZDI7Y29sb3I6I2ZmZjt3aWR0aDoxMDAlO21hcmdpbi10b3A6NnB4fS5lcXVhbHM6aG92ZXJ7YmFja2dyb3VuZDojMjE5NmYzfTwvc3R5bGU+PC9oZWFkPjxib2R5PjxkaXYgaWQ9ImNhbGN1bGF0b3IiPjxpbnB1dCBpZD0iZGlzcGxheSIgdHlwZT0idGV4dCIgcmVhZG9ubHk9InJlYWRvbmx5Ij48ZGl2PjxidXR0b24gZGF0YS12YWw9IjciPjc8L2J1dHRvbj48YnV0dG9uIGRhdGEtdmFsPSI4Ij44PC9idXR0b24+PGJ1dHRvbiBkYXRhLXZhbD0iOSI+OTwvYnV0dG9uPjxidXR0b24gZGF0YS12YWw9Ii8iIGNsYXNzPSJvcGVyYXRvciI+w7c8L2J1dHRvbj48L2Rpdj48ZGl2PjxidXR0b24gZGF0YS12YWw9IjQiPjQ8L2J1dHRvbj48YnV0dG9uIGRhdGEtdmFsPSI1Ij41PC9idXR0b24+PGJ1dHRvbiBkYXRhLXZhbD0iNiI+NjwvYnV0dG9uPjxidXR0b24gZGF0YS12YWw9IioiIGNsYXNzPSJvcGVyYXRvciI+w5c8L2J1dHRvbj48L2Rpdj48ZGl2PjxidXR0b24gZGF0YS12YWw9IjEiPjE8L2J1dHRvbj48YnV0dG9uIGRhdGEtdmFsPSIyIj4yPC9idXR0b24+PGJ1dHRvbiBkYXRhLXZhbD0iMyI+MzwvYnV0dG9uPjxidXR0b24gZGF0YS12YWw9Ii0iIGNsYXNzPSJvcGVyYXRvciI+4oiSPC9idXR0b24+PC9kaXY+PGRpdj48YnV0dG9uIGRhdGEtdmFsPSIwIj4wPC9idXR0b24+PGJ1dHRvbiBkYXRhLXZhbD0iLiI+LjwvYnV0dG9uPjxidXR0b24gaWQ9ImNsZWFyIj5DPC9idXR0b24+PGJ1dHRvbiBkYXRhLXZhbD0iKyIgY2xhc3M9Im9wZXJhdG9yIj4rPC9idXR0b24+PC9kaXY+PGJ1dHRvbiBpZD0iZXF1YWxzIiBjbGFzcz0iZXF1YWxzIj49PC9idXR0b24+PC9kaXY+PHNjcmlwdD5jb25zdCBkaXNwbGF5ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2Rpc3BsYXknKTsNCiAgY29uc3QgYnV0dG9ucyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJyNjYWxjdWxhdG9yIGJ1dHRvbltkYXRhLXZhbF0nKTsNCiAgY29uc3QgY2xlYXJCdG4gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnY2xlYXInKTsNCiAgY29uc3QgZXF1YWxzQnRuID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2VxdWFscycpOw0KDQogIGJ1dHRvbnMuZm9yRWFjaChidG4gPT4gew0KICAgIGJ0bi5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsICgpID0+IHsNCiAgICAgIGRpc3BsYXkudmFsdWUgKz0gYnRuLmdldEF0dHJpYnV0ZSgnZGF0YS12YWwnKTsNCiAgICB9KTsNCiAgfSk7DQoNCiAgY2xlYXJCdG4uYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoKSA9PiB7DQogICAgZGlzcGxheS52YWx1ZSA9ICcnOw0KICB9KTsNCg0KICBlcXVhbHNCdG4uYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoKSA9PiB7DQogICAgdHJ5IHsNCiAgICAgIC8vIEV2YWx1YXRlIGV4cHJlc3Npb24gc2FmZWx5DQogICAgICAvLyBSZXBsYWNlIG11bHRpcGxpY2F0aW9uIGFuZCBkaXZpc2lvbiBzeW1ib2xzIGZpcnN0IChpbiBjYXNlIHlvdSB3YW50IHRvIHN1cHBvcnQgw7cgYW5kIMOXIGluIGRpc3BsYXkpDQogICAgICBjb25zdCBleHByID0gZGlzcGxheS52YWx1ZS5yZXBsYWNlKC/Dty9nLCAnLycpLnJlcGxhY2UoL8OXL2csICcqJyk7DQogICAgICBjb25zdCByZXN1bHQgPSBGdW5jdGlvbignInVzZSBzdHJpY3QiO3JldHVybiAoJyArIGV4cHIgKyAnKScpKCk7DQogICAgICBkaXNwbGF5LnZhbHVlID0gcmVzdWx0Ow0KICAgIH0gY2F0Y2ggew0KICAgICAgZGlzcGxheS52YWx1ZSA9ICdFcnJvcic7DQogICAgfQ0KICB9KTs8L3NjcmlwdD48L2JvZHk+PC9odG1sPg==`, + notepad: "data:text/html;charset=utf-8;base64,PGh0bWw+PGhlYWQ+PHRpdGxlPm5vdGVwYWQ8L3RpdGxlPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Ym9keXttYXJnaW46MH10ZXh0YXJlYXtyZXNpemU6bm9uZTt3aWR0aDo5OCU7aGVpZ2h0Ojk4JTtwb3NpdGlvbjphYnNvbHV0ZTt0b3A6MDtib3JkZXI6bm9uZTttYXJnaW46MSU7Zm9udC1mYW1pbHk6bW9ub3NwYWNlO2ZvbnQtc2l6ZToxZW07b3ZlcmZsb3c6aGlkZGVufXRleHRhcmVhOmZvY3Vze291dGxpbmU6MH08L3N0eWxlPjwvaGVhZD48Ym9keT48dGV4dGFyZWE+PC90ZXh0YXJlYT48L2JvZHk+PC9odG1sPg==" +} + +var shell = { + taskbar_wind: null, + taskbar_size: 25, + startmenuWidth: 400, + startmenuHeight: 300 +}; + +function doTheBullshitByShellBruh() { + const taskbarWind = shell.taskbar_wind; + const taskbarSize = shell.taskbar_size; + const desktopRect = desktop.getBoundingClientRect(); + transformWindow(taskbarWind.windID, + desktopRect.width, + taskbarSize, + 0, + desktopRect.height - taskbarSize + ) +} + +shell.launch = function(app) { + if (app === "Notepad") { + createWindow(embeddedApps.notepad, { + resizable: true, + name: "Notepad" + }); // Launch notepad + } else if (app === "Calculator") { + const calc = createWindow(embeddedApps.calc, { + resizable: true, + name: "Calculator" + }); // Launch ZE CALCULATOR + calc.minSizeX = 500; + calc.minSizeY = 444; + updateWindowMin(calc.windID); + } +}; + +shell.updateTaskbar = doTheBullshitByShellBruh; + +shell.init = function () { + // Create wind for shell using API + const taskbarWind = createWindow("about:blank", { + headerless: true, + resizable: false, + indent: false + }); + + shell.taskbar_wind = taskbarWind; + taskbarWind.minSizeX = 0; + taskbarWind.minSizeY = 0; + taskbarWind.alwaysOnTop = true; + taskbarWind.hideInTaskbar = true; + + // Inject base HTML for taskbar + const tbDoc = taskbarWind.iframe.contentDocument || taskbarWind.iframe.contentWindow.document; + tbDoc.open(); + tbDoc.write(` + + + + + + +
Start
+
+
+ + + + `); + tbDoc.close(); + + shell.updateTaskbar(); + shell.updateTaskbarContents(); + + window.addEventListener('resize', function () { + shell.updateTaskbar(); + }, true); + // Add hook + windowHooks.push(shell.updateTaskbarContents); + + + + // Create start menu window + const startMenu = createWindow("about:blank", { + headerless: true, + resizable: false, + indent: false, + layer: "foreground", + name: "Start Menu" + }); + shell.startMenu = startMenu; + startMenu.hideInTaskbar = true; + shell.updateTaskbarContents(); + + // Inject start menu HTML into its iframe + const smDoc = startMenu.iframe.contentDocument || startMenu.iframe.contentWindow.document; + smDoc.open(); + smDoc.write(` + + + + + + +

Start Menu

+
    +
  • Calculator
  • +
  • Notepad
  • +
  • Settings
  • +
+ + + `); + smDoc.close(); + + // Initially hide the start menu by sizing it to zero and positioning it off-screen + transformWindow(startMenu.windID, 0, 0, 0, window.innerHeight); + + // Helper function to show start menu + function showStartMenu() { + const desktopRect = desktop.getBoundingClientRect(); + const taskbarHeight = shell.taskbar_size || 40; + const width = shell.startmenuWidth; + const height = shell.startmenuHeight; + const x = 0; + const y = desktopRect.height - taskbarHeight - height; + transformWindow(startMenu.windID, width, height, x, y,true); + focusWindow(startMenu.windID); + } + + // Helper function to hide start menu + function hideStartMenu() { + transformWindow(startMenu.windID, 0, 0, 0, window.innerHeight + shell.startmenuHeight,true); + } + + let startMenuVisible = false; + + // Hook start button to toggle start menu + const startBtn = tbDoc.getElementById('startBtn'); + startBtn.addEventListener('click', () => { + if (startMenuVisible) { + hideStartMenu(); + startMenuVisible = false; + } else { + showStartMenu(); + startMenuVisible = true; + } + }); + + // Close start menu when clicking outside (optional) + window.addEventListener('mousedown', (e) => { + if (!startMenuVisible) return; + const smElem = startMenu.windElems.windowDiv; + if (!smElem.contains(e.target)) { + hideStartMenu(); + startMenuVisible = false; + } + }); + + // Optionally, listen for start menu item clicks + window.addEventListener('message', (event) => { + if (event.data?.type === 'startItem' && event.data.action === 'openApp') { + console.log('Open app:', event.data.app); + // Close start menu on selection + hideStartMenu(); + startMenuVisible = false; + shell.launch(event.data.app); + } + }); + + hideStartMenu(); + +}; + +shell.updateTaskbarContents = function () { + const taskbarWind = shell.taskbar_wind; + if (!taskbarWind) return; + + const tbDoc = taskbarWind.iframe.contentDocument || taskbarWind.iframe.contentWindow.document; + const taskList = tbDoc.getElementById('taskList'); + if (!taskList) return; + + // Clear old tasks + taskList.innerHTML = ''; + + // Add a button for each open window except the taskbar + for (const id in windows) { + const winObj = windows[id]; + if (!winObj || id === taskbarWind.windID) continue; + if (winObj.hideInTaskbar) continue; + + const btn = tbDoc.createElement('div'); + btn.className = 'task-item'; + btn.textContent = winObj.windElems.title.textContent || 'Window'; + + btn.addEventListener('click', () => { + // Focus the clicked window + winObj.windElems.windowDiv.style.zIndex = ++zIndexCounter; + }); + + taskList.appendChild(btn); + } +}; diff --git a/style.css b/style.css new file mode 100644 index 0000000..2398e23 --- /dev/null +++ b/style.css @@ -0,0 +1,85 @@ + +body { + margin: 0; + font-family: Arial, sans-serif; + background: #282c34; + height: 100vh; + overflow: hidden; + user-select: none; +} + +#new-window-btn { + position: fixed; + top: 10px; + left: 10px; + padding: 8px 16px; + z-index: 1000; + cursor: pointer; +} + +#desktop { + position: relative; + width: 100vw; + height: 100vh; + overflow: hidden; +} + +.window { + position: absolute; + width: 400px; + height: 300px; + border: 1px solid #888; + background: white; + box-shadow: 0 0 10px rgba(0,0,0,0.7); + display: flex; + flex-direction: column; + user-select: none; +} + +.window-header { + background: #444; + color: white; + padding: 6px 10px; + cursor: grab; + display: flex; + justify-content: space-between; + align-items: center; +} + +.window-header:active { + cursor: grabbing; +} + +.window-title { + font-weight: bold; + font-size: 14px; +} + +.window-close-btn { + background: #ff4d4d; + border: none; + color: white; + font-weight: bold; + cursor: pointer; + width: 22px; + height: 22px; + border-radius: 3px; + display: flex; + align-items: center; + justify-content: center; + line-height: 0; +} + +.window-iframe { + flex: 1; + border: none; + width: 100%; +} + +.window-hidden { + display: none !important; +} + +.background-layer-windower { + z-index: -4; +} \ No newline at end of file