nottri-os / index.html
Ramesh-vani's picture
Update index.html
9fc2761 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Custom OS with Fixed FileSystem CRUD</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body, html { width: 100%; height: 100%; overflow: hidden; font-family: Arial, sans-serif; }
#desktop {
position: absolute;
width: 100%;
height: 100%;
background: url('background.jpg') no-repeat center center fixed;
background-size: cover;
}
#desktop-icons {
position: absolute;
top: 10px;
left: 10px;
display: flex;
flex-wrap: wrap;
}
.icon {
width: 80px;
height: 80px;
margin: 10px;
background: rgba(0,0,0,0.5);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
cursor: pointer;
border-radius: 5px;
font-size: 14px;
}
#taskbar {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 40px;
background: rgba(0,0,0,0.8);
z-index: 1000;
}
#taskbar-left {
display: flex;
align-items: center;
height: 100%;
padding: 0 5px;
}
#start-button {
background: #0078d7;
color: white;
border: none;
padding: 5px 10px;
cursor: pointer;
margin-right: 10px;
}
#taskbar-pinned {
display: flex;
align-items: center;
}
#taskbar-pinned button {
background: transparent;
border: none;
color: white;
margin-right: 5px;
font-size: 18px;
cursor: pointer;
}
#taskbar-windows {
display: flex;
align-items: center;
margin-left: 10px;
}
#taskbar-windows button {
background: #555;
border: none;
color: white;
padding: 3px 8px;
margin: 0 2px;
cursor: pointer;
border-radius: 3px;
font-size: 13px;
}
.taskbar-icon {
font-size: 16px;
display: inline-block;
}
#start-menu {
position: absolute;
bottom: 45px;
left: 10px;
width: 200px;
background: #fff;
border: 1px solid #ccc;
display: none;
z-index: 1001;
}
#start-menu ul { list-style: none; }
#start-menu li {
padding: 10px;
cursor: pointer;
border-bottom: 1px solid #eee;
}
#start-menu li:hover { background: #f0f0f0; }
.window {
position: absolute;
width: 400px;
height: 300px;
min-height: 200px;
background: #fff;
border: 1px solid #333;
box-shadow: 2px 2px 10px rgba(0,0,0,0.5);
z-index: 200;
overflow: hidden;
}
.window-header {
background: #0078d7;
color: #fff;
padding: 5px;
cursor: move;
display: flex;
align-items: center;
justify-content: space-between;
}
.window-header .app-icon {
font-size: 16px;
margin-right: 5px;
}
.window-header .title {
font-weight: bold;
}
.window-header .controls button {
background: transparent;
border: none;
color: #fff;
cursor: pointer;
margin-left: 5px;
font-size: 14px;
}
.window-content {
padding: 10px;
overflow-y: auto;
max-height: calc(100% - 40px);
}
.resizer {
position: absolute;
background: transparent;
z-index: 10;
}
.resizer.top { top: -5px; left: 0; width: 100%; height: 10px; cursor: ns-resize; }
.resizer.right { right: -5px; top: 0; width: 10px; height: 100%; cursor: ew-resize; }
.resizer.bottom { bottom: -5px; left: 0; width: 100%; height: 10px; cursor: ns-resize; }
.resizer.left { left: -5px; top: 0; width: 10px; height: 100%; cursor: ew-resize; }
.resizer.top-left { top: -5px; left: -5px; width: 10px; height: 10px; cursor: nwse-resize; }
.resizer.top-right { top: -5px; right: -5px; width: 10px; height: 10px; cursor: nesw-resize; }
.resizer.bottom-left { bottom: -5px; left: -5px; width: 10px; height: 10px; cursor: nesw-resize; }
.resizer.bottom-right { bottom: -5px; right: -5px; width: 10px; height: 10px; cursor: nwse-resize; }
#custom-context-menu, #file-context-menu {
position: absolute;
display: none;
background: #fff;
border: 1px solid #ccc;
z-index: 5000;
box-shadow: 2px 2px 10px rgba(0,0,0,0.5);
}
#custom-context-menu ul, #file-context-menu ul { list-style: none; }
#custom-context-menu li, #file-context-menu li {
padding: 8px 12px;
cursor: pointer;
}
#custom-context-menu li:hover, #file-context-menu li:hover {
background: #f0f0f0;
}
</style>
</head>
<body>
<style id="custom-css"></style>
<div id="desktop">
<div id="desktop-icons"></div>
</div>
<div id="taskbar">
<div id="taskbar-left">
<button id="start-button">Start</button>
<div id="taskbar-pinned"></div>
<div id="taskbar-windows"></div>
</div>
</div>
<div id="start-menu">
<ul id="start-menu-list"></ul>
</div>
<div id="custom-context-menu">
<ul>
<li data-custom="openCustomizer">Open Customizer</li>
<li data-custom="reset">Reset Customizations</li>
</ul>
</div>
<div id="file-context-menu">
<ul>
<li data-action="open">Open</li>
<li data-action="rename">Rename</li>
<li data-action="delete">Delete</li>
</ul>
</div>
<script>
/***** Core OS Object *****/
const OS = {
windowCounter: 1,
runningWindows: {},
zIndexCounter: 300,
eventListeners: {},
// File System API
FileSystem: {
init: function() {
if (!localStorage.getItem('fs_root')) {
localStorage.setItem('fs_root', JSON.stringify({
name: "Root",
type: "directory",
contents: []
}));
}
},
getRoot: function() {
return JSON.parse(localStorage.getItem('fs_root'));
},
saveRoot: function(root) {
console.log("Saving root:", JSON.stringify(root));
localStorage.setItem('fs_root', JSON.stringify(root));
OS.triggerEvent('fileSystemChanged', root);
},
addItem: function(name, type, content = "", appId = null, parentPath = "/") {
console.log(`Adding ${type}: ${name} to ${parentPath}`);
const root = this.getRoot();
let parent = parentPath === "/" ? root : this.findItem(parentPath);
if (!parent || parent.type !== "directory") {
console.error(`Invalid parent directory: ${parentPath}`);
return false;
}
if (parent.contents.some(item => item.name === name)) {
console.error(`Item ${name} already exists in ${parentPath}`);
return false;
}
const newItem = {
name: name,
type: type,
created: new Date().toISOString()
};
if (type === "file") {
newItem.content = content;
newItem.fileType = "text";
newItem.associatedAppId = appId;
} else if (type === "directory") {
newItem.contents = [];
}
parent.contents.push(newItem);
this.saveRoot(root);
OS.triggerEvent('itemAdded', { path: `${parentPath}${name}${type === 'directory' ? '/' : ''}`, item: newItem });
return true;
},
findItem: function(path) {
console.log(`Finding item at: ${path}`);
if (path === "/") return this.getRoot();
const parts = path.split('/').filter(p => p);
let current = this.getRoot();
for (let part of parts) {
current = current.contents.find(item => item.name === part);
if (!current) {
console.error(`Item not found: ${path}`);
return null;
}
}
return current;
},
removeItem: function(path) {
console.log(`Removing item: ${path}`);
const parent = this.getParent(path);
if (!parent) {
console.error(`Parent not found for: ${path}`);
return false;
}
const itemName = path.split('/').filter(p => p).pop();
const index = parent.contents.findIndex(item => item.name === itemName);
if (index === -1) {
console.error(`Item ${itemName} not found in parent`);
return false;
}
parent.contents.splice(index, 1);
this.saveRoot(this.getRoot());
OS.triggerEvent('itemRemoved', { path });
return true;
},
renameItem: function(oldPath, newName) {
console.log(`Renaming ${oldPath} to ${newName}`);
const item = this.findItem(oldPath);
if (!item) {
console.error(`Item not found: ${oldPath}`);
return false;
}
const parent = this.getParent(oldPath);
if (!parent) {
console.error(`Parent not found for: ${oldPath}`);
return false;
}
if (parent.contents.some(i => i.name === newName && i !== item)) {
console.error(`Name ${newName} already exists in directory`);
return false;
}
item.name = newName;
this.saveRoot(this.getRoot());
const newPath = `${parentPath(oldPath)}${newName}${item.type === 'directory' ? '/' : ''}`;
OS.triggerEvent('itemRenamed', { oldPath, newPath });
return true;
},
getParent: function(path) {
console.log(`Getting parent of: ${path}`);
if (path === "/") return null;
const parts = path.split('/').filter(p => p);
parts.pop();
return parts.length === 0 ? this.getRoot() : this.findItem("/" + parts.join('/'));
},
readFile: function(path) {
console.log(`Reading file: ${path}`);
const file = this.findItem(path);
if (file && file.type === "file") {
return file.content;
}
console.error(`File not found or not a file: ${path}`);
return null;
},
writeFile: function(path, content) {
console.log(`Writing to file: ${path}`);
const file = this.findItem(path);
if (!file || file.type !== "file") {
console.error(`File not found or not a file: ${path}`);
return false;
}
file.content = content;
this.saveRoot(this.getRoot());
OS.triggerEvent('fileWritten', { path, content });
return true;
}
},
// Window Management API (unchanged for brevity, assumed working)
WindowManager: {
createWindow: function(title, contentHTML = "", options = {}) {
const win = document.createElement("div");
win.classList.add("window");
win.style.top = options.top || "100px";
win.style.left = options.left || "100px";
win.style.width = options.width || "400px";
win.style.height = options.height || "300px";
win.dataset.windowId = OS.windowCounter++;
win.dataset.maximized = "false";
win.dataset.appId = options.appId || '';
const header = document.createElement("div");
header.classList.add("window-header");
const controlsHTML = options.controls || "<button class='minimize-btn'>_</button><button class='maximize-btn'>[ ]</button><button class='close'>X</button>";
header.innerHTML = `<span class="app-icon">${options.icon || ''}</span><span class="title">${title}</span><span class="controls">${controlsHTML}</span>`;
win.appendChild(header);
const content = document.createElement("div");
content.classList.add("window-content");
content.innerHTML = contentHTML;
win.appendChild(content);
OS.makeResizable(win);
document.body.appendChild(win);
win.addEventListener("mousedown", () => OS.WindowManager.bringToFront(win));
OS.makeDraggable(win, header);
OS.WindowManager.bringToFront(win);
const minimizeBtn = header.querySelector(".minimize-btn");
if(minimizeBtn) minimizeBtn.addEventListener("click", () => OS.WindowManager.minimizeWindow(win));
const maximizeBtn = header.querySelector(".maximize-btn");
if(maximizeBtn) maximizeBtn.addEventListener("click", () => OS.WindowManager.toggleMaximizeWindow(win));
const closeBtn = header.querySelector(".close");
if(closeBtn) closeBtn.addEventListener("click", () => OS.WindowManager.closeWindow(win));
OS.runningWindows[win.dataset.windowId] = win;
OS.createTaskbarWindowButton(win);
OS.triggerEvent('windowCreated', { windowId: win.dataset.windowId });
return win;
},
minimizeWindow: function(win) { win.style.display = "none"; OS.triggerEvent('windowMinimized', { windowId: win.dataset.windowId }); },
maximizeWindow: function(win) {
if (win.dataset.maximized === "true") {
win.style.top = win.dataset.originalTop;
win.style.left = win.dataset.originalLeft;
win.style.width = win.dataset.originalWidth;
win.style.height = win.dataset.originalHeight;
win.dataset.maximized = "false";
} else {
win.dataset.originalTop = win.style.top;
win.dataset.originalLeft = win.style.left;
win.dataset.originalWidth = win.style.width;
win.dataset.originalHeight = win.style.height;
win.style.top = "0";
win.style.left = "0";
win.style.width = "100%";
win.style.height = "100%";
win.dataset.maximized = "true";
}
OS.triggerEvent('windowMaximized', { windowId: win.dataset.windowId, maximized: win.dataset.maximized === "true" });
},
toggleMaximizeWindow: function(win) { this.maximizeWindow(win); },
closeWindow: function(win) {
const winId = win.dataset.windowId;
const taskbarWindows = document.getElementById("taskbar-windows");
const btn = taskbarWindows.querySelector(`button[data-window-id="${winId}"]`);
if(btn) btn.remove();
delete OS.runningWindows[winId];
win.remove();
OS.triggerEvent('windowClosed', { windowId: winId });
},
bringToFront: function(win) {
OS.zIndexCounter++;
win.style.zIndex = OS.zIndexCounter;
OS.triggerEvent('windowFocused', { windowId: win.dataset.windowId });
},
getWindow: function(windowId) { return OS.runningWindows[windowId]; }
},
// App Management API (unchanged for brevity)
AppManager: {
apps: {},
registerApp: function(appId, appDef) {
this.apps[appId] = appDef;
localStorage.setItem(`app_${appId}`, JSON.stringify(appDef));
OS.triggerEvent('appRegistered', { appId });
OS.updateSystemAppsUI();
},
launchApp: function(appId, options = {}) {
const appDef = this.apps[appId] || JSON.parse(localStorage.getItem(`app_${appId}`));
if (!appDef) return null;
const win = OS.WindowManager.createWindow(appDef.name, appDef.ui || '', {
appId: appId,
icon: appDef.icon || 'πŸ”³',
controls: appDef.windowControls
});
if (appDef.init) appDef.init(win, options);
OS.triggerEvent('appLaunched', { appId, windowId: win.dataset.windowId });
return win;
}
},
// Event System
on: function(eventName, callback) {
if (!this.eventListeners[eventName]) this.eventListeners[eventName] = [];
this.eventListeners[eventName].push(callback);
},
triggerEvent: function(eventName, data) {
if (this.eventListeners[eventName]) {
this.eventListeners[eventName].forEach(callback => callback(data));
}
},
// Utility Functions (unchanged for brevity)
makeDraggable: function(win, handle) {
let offsetX = 0, offsetY = 0;
handle.addEventListener("mousedown", function(e) {
if (win.dataset.maximized === "true") return;
offsetX = e.clientX - win.offsetLeft;
offsetY = e.clientY - win.offsetTop;
document.addEventListener("mousemove", mouseMove);
document.addEventListener("mouseup", mouseUp);
});
function mouseMove(e) {
let newLeft = e.clientX - offsetX;
let newTop = e.clientY - offsetY;
const desktopRect = document.getElementById("desktop").getBoundingClientRect();
newLeft = Math.max(0, Math.min(newLeft, desktopRect.width - win.offsetWidth));
newTop = Math.max(0, Math.min(newTop, desktopRect.height - win.offsetHeight));
win.style.left = newLeft + "px";
win.style.top = newTop + "px";
}
function mouseUp() {
document.removeEventListener("mousemove", mouseMove);
document.removeEventListener("mouseup", mouseUp);
}
},
makeResizable: function(win) {
const directions = ["top", "right", "bottom", "left", "top-left", "top-right", "bottom-left", "bottom-right"];
directions.forEach(direction => {
const resizer = document.createElement("div");
resizer.classList.add("resizer", direction);
win.appendChild(resizer);
resizer.addEventListener("mousedown", initResize);
function initResize(e) {
e.preventDefault();
e.stopPropagation();
const startX = e.clientX;
const startY = e.clientY;
const startWidth = parseInt(document.defaultView.getComputedStyle(win).width, 10);
const startHeight = parseInt(document.defaultView.getComputedStyle(win).height, 10);
const startLeft = win.offsetLeft;
const startTop = win.offsetTop;
const desktopRect = document.getElementById("desktop").getBoundingClientRect();
function doResize(e) {
let dx = e.clientX - startX;
let dy = e.clientY - startY;
let newWidth = startWidth;
let newHeight = startHeight;
let newLeft = startLeft;
let newTop = startTop;
if(direction.includes("right")) newWidth = startWidth + dx;
if(direction.includes("left")) { newWidth = startWidth - dx; newLeft = startLeft + dx; }
if(direction.includes("bottom")) newHeight = startHeight + dy;
if(direction.includes("top")) { newHeight = startHeight - dy; newTop = startTop + dy; }
if(newLeft < 0) { newWidth += newLeft; newLeft = 0; }
if(newTop < 0) { newHeight += newTop; newTop = 0; }
if(newLeft + newWidth > desktopRect.width) newWidth = desktopRect.width - newLeft;
if(newTop + newHeight > desktopRect.height) newHeight = desktopRect.height - newTop;
const minWidth = 100, minHeight = 50;
newWidth = Math.max(minWidth, newWidth);
newHeight = Math.max(minHeight, newHeight);
win.style.width = newWidth + "px";
win.style.height = newHeight + "px";
win.style.left = newLeft + "px";
win.style.top = newTop + "px";
}
function stopResize() {
document.removeEventListener("mousemove", doResize);
document.removeEventListener("mouseup", stopResize);
}
document.addEventListener("mousemove", doResize);
document.addEventListener("mouseup", stopResize);
}
});
},
createTaskbarWindowButton: function(win) {
const taskbarWindows = document.getElementById("taskbar-windows");
let btn = document.createElement("button");
btn.classList.add("taskbar-window-btn");
btn.setAttribute("data-window-id", win.dataset.windowId);
let icon = win.querySelector('.app-icon')?.innerText || 'πŸ”³';
btn.innerHTML = `<span class="taskbar-icon">${icon}</span>`;
btn.onclick = () => {
if(win.style.display === "none") {
win.style.display = "block";
OS.WindowManager.bringToFront(win);
} else {
OS.WindowManager.bringToFront(win);
}
};
taskbarWindows.appendChild(btn);
},
updateSystemAppsUI: function() {
const desktopIcons = document.getElementById("desktop-icons");
const startMenuList = document.getElementById("start-menu-list");
const taskbarPinned = document.getElementById("taskbar-pinned");
desktopIcons.innerHTML = startMenuList.innerHTML = taskbarPinned.innerHTML = "";
const allApps = { ...builtInApps.reduce((acc, app) => ({ ...acc, [app.id]: app }), {}), ...OS.AppManager.apps };
Object.values(allApps).forEach(app => {
let icon = document.createElement("div");
icon.className = "icon";
icon.setAttribute("data-app", app.id);
icon.innerHTML = `${app.icon || 'πŸ”³'}<br>${app.name}`;
icon.onclick = () => OS.AppManager.launchApp(app.id);
desktopIcons.appendChild(icon);
let li = document.createElement("li");
li.setAttribute("data-app", app.id);
li.innerHTML = `${app.icon || 'πŸ”³'} ${app.name}`;
li.onclick = () => { OS.AppManager.launchApp(app.id); hideStartMenu(); };
startMenuList.appendChild(li);
let btn = document.createElement("button");
btn.setAttribute("data-app", app.id);
btn.title = app.name;
btn.innerHTML = `${app.icon || 'πŸ”³'}`;
btn.onclick = () => OS.AppManager.launchApp(app.id);
taskbarPinned.appendChild(btn);
});
}
};
/***** Built-in Apps *****/
const builtInApps = [
{
id: "appInstaller",
name: "App Installer",
icon: "πŸ› ",
init: function(win) {
win.querySelector(".window-content").innerHTML = `
<h3>Install App</h3>
<textarea id="app-json" placeholder="Paste App JSON here"></textarea><br>
<button id="install-app-btn">Install</button>
<hr>
<h3>Installed Apps</h3>
<div id="installed-apps-list"></div>
`;
win.querySelector("#install-app-btn").addEventListener("click", () => {
const jsonText = win.querySelector("#app-json").value;
try {
const appData = JSON.parse(jsonText);
if (!appData.id) throw new Error("App JSON must contain an 'id'");
OS.AppManager.registerApp(appData.id, appData);
win.querySelector("#app-json").value = "";
updateInstalledAppsList();
} catch (e) {
alert("Invalid JSON: " + e.message);
}
});
function updateInstalledAppsList() {
const list = win.querySelector("#installed-apps-list");
list.innerHTML = Object.values(OS.AppManager.apps).map(app => `<div>${app.icon || 'πŸ”³'} ${app.name}</div>`).join("");
}
updateInstalledAppsList();
}
},
{
id: "fileExplorer",
name: "File Explorer",
icon: "πŸ“",
init: function(win) {
win.dataset.currentPath = "/";
win.querySelector(".window-content").innerHTML = `
<div style="margin-bottom: 10px;">
<button id="new-file-btn">New File</button>
<button id="new-folder-btn">New Folder</button>
<button id="up-btn">Up</button>
<span id="current-path" style="margin-left: 10px;">/</span>
</div>
<div id="file-list"></div>
`;
win.querySelector("#new-file-btn").addEventListener("click", () => createNewFile());
win.querySelector("#new-folder-btn").addEventListener("click", () => createNewFolder());
win.querySelector("#up-btn").addEventListener("click", () => navigateUp());
win.querySelector("#file-list").addEventListener("contextmenu", showContextMenu);
updateFileList();
function updateFileList() {
const currentPath = win.dataset.currentPath;
console.log(`Updating file list for: ${currentPath}`);
const currentDir = OS.FileSystem.findItem(currentPath) || OS.FileSystem.getRoot();
win.querySelector("#current-path").textContent = currentPath;
const fileList = win.querySelector("#file-list");
fileList.innerHTML = currentDir.contents.map(item => `
<div style="padding: 5px; cursor: pointer;" data-path="${currentPath}${item.name}${item.type === 'directory' ? '/' : ''}">
${item.type === "file" ? "πŸ“„" : "πŸ“"} ${item.name}
${item.type === "file" ? `<button class="open-btn" data-path="${currentPath}${item.name}">Open</button>` :
`<button class="enter-btn" data-path="${currentPath}${item.name}/">Enter</button>`}
</div>
`).join("");
fileList.querySelectorAll(".open-btn").forEach(btn => btn.addEventListener("click", () => OS.AppManager.launchApp("textViewer", { filePath: btn.dataset.path })));
fileList.querySelectorAll(".enter-btn").forEach(btn => btn.addEventListener("click", () => { win.dataset.currentPath = btn.dataset.path; updateFileList(); }));
}
function createNewFile() {
const filename = prompt("Enter file name:");
if (filename && OS.FileSystem.addItem(filename, "file", "New file content", null, win.dataset.currentPath)) {
updateFileList();
} else {
alert("Failed to create file!");
}
}
function createNewFolder() {
const foldername = prompt("Enter folder name:");
if (foldername && OS.FileSystem.addItem(foldername, "directory", "", null, win.dataset.currentPath)) {
updateFileList();
} else {
alert("Failed to create folder!");
}
}
function navigateUp() {
if (win.dataset.currentPath === "/") return;
const parts = win.dataset.currentPath.split('/').filter(p => p);
parts.pop();
win.dataset.currentPath = parts.length ? `/${parts.join('/')}/` : "/";
updateFileList();
}
function showContextMenu(e) {
e.preventDefault();
const target = e.target.closest("[data-path]");
if (target) {
const path = target.dataset.path;
const contextMenu = document.getElementById("file-context-menu");
contextMenu.style.top = e.clientY + "px";
contextMenu.style.left = e.clientX + "px";
contextMenu.style.display = "block";
contextMenu.querySelector("ul").dataset.path = path;
contextMenu.querySelector("[data-action='open']").style.display = OS.FileSystem.findItem(path)?.type === "file" ? "block" : "none";
}
}
OS.on('fileSystemChanged', updateFileList);
OS.on('itemAdded', updateFileList);
OS.on('itemRemoved', updateFileList);
OS.on('itemRenamed', updateFileList);
OS.on('fileWritten', updateFileList);
}
},
{
id: "textViewer",
name: "Text Viewer",
icon: "πŸ“„",
init: function(win, options) {
const filePath = options.filePath;
const content = OS.FileSystem.readFile(filePath) || "";
win.querySelector(".window-content").innerHTML = `<textarea style="width: 100%; height: 100%;">${content}</textarea>`;
win.querySelector("textarea").addEventListener("change", () => {
const newContent = win.querySelector("textarea").value;
if (OS.FileSystem.writeFile(filePath, newContent)) {
console.log(`Content updated for ${filePath}`);
} else {
alert("Failed to save file content!");
}
});
}
}
];
/***** System Initialization *****/
builtInApps.forEach(app => OS.AppManager.registerApp(app.id, app));
document.getElementById("start-button").addEventListener("click", (e) => {
e.stopPropagation();
const startMenu = document.getElementById("start-menu");
startMenu.style.display = startMenu.style.display === "block" ? "none" : "block";
});
document.addEventListener("click", (e) => {
if (!document.getElementById("start-menu").contains(e.target) && e.target !== document.getElementById("start-button")) {
hideStartMenu();
}
if (!e.target.closest('#file-context-menu')) {
document.getElementById("file-context-menu").style.display = "none";
}
document.getElementById("custom-context-menu").style.display = "none";
});
document.getElementById("desktop").addEventListener("contextmenu", function(e) {
e.preventDefault();
const customContextMenu = document.getElementById("custom-context-menu");
customContextMenu.style.display = "block";
customContextMenu.style.top = e.clientY + "px";
customContextMenu.style.left = e.clientX + "px";
});
document.getElementById("custom-context-menu").addEventListener("click", function(e) {
const option = e.target.getAttribute("data-custom");
if (option === "openCustomizer") {
// Placeholder for customizer app
} else if (option === "reset") {
document.getElementById("desktop").style.background = "url('background.jpg') no-repeat center center fixed";
document.getElementById("desktop").style.backgroundSize = "cover";
document.getElementById("taskbar").style.background = "rgba(0,0,0,0.8)";
document.getElementById("taskbar").style.height = "40px";
document.getElementById("start-menu").style.background = "#fff";
document.getElementById("start-menu").style.color = "#000";
document.getElementById("custom-css").innerHTML = "";
alert("Customizations reset to default!");
}
document.getElementById("custom-context-menu").style.display = "none";
});
document.getElementById("file-context-menu").addEventListener("click", (e) => {
const action = e.target.dataset.action;
const path = e.target.closest("ul").dataset.path;
const fileExplorerWin = OS.WindowManager.getWindow(Object.keys(OS.runningWindows).find(id => OS.runningWindows[id].dataset.appId === "fileExplorer"));
if (action === "open") {
OS.AppManager.launchApp("textViewer", { filePath: path });
} else if (action === "rename") {
const newName = prompt("Enter new name:");
if (newName && OS.FileSystem.renameItem(path, newName)) {
if (fileExplorerWin) updateFileExplorer(fileExplorerWin);
} else {
alert("Failed to rename item!");
}
} else if (action === "delete") {
if (confirm("Are you sure you want to delete this item?") && OS.FileSystem.removeItem(path)) {
if (fileExplorerWin) updateFileExplorer(fileExplorerWin);
} else {
alert("Failed to delete item!");
}
}
document.getElementById("file-context-menu").style.display = "none";
});
function updateFileExplorer(win) {
const updateFileList = () => {
const currentPath = win.dataset.currentPath;
const currentDir = OS.FileSystem.findItem(currentPath) || OS.FileSystem.getRoot();
win.querySelector("#current-path").textContent = currentPath;
const fileList = win.querySelector("#file-list");
fileList.innerHTML = currentDir.contents.map(item => `
<div style="padding: 5px; cursor: pointer;" data-path="${currentPath}${item.name}${item.type === 'directory' ? '/' : ''}">
${item.type === "file" ? "πŸ“„" : "πŸ“"} ${item.name}
${item.type === "file" ? `<button class="open-btn" data-path="${currentPath}${item.name}">Open</button>` :
`<button class="enter-btn" data-path="${currentPath}${item.name}/">Enter</button>`}
</div>
`).join("");
fileList.querySelectorAll(".open-btn").forEach(btn => btn.addEventListener("click", () => OS.AppManager.launchApp("textViewer", { filePath: btn.dataset.path })));
fileList.querySelectorAll(".enter-btn").forEach(btn => btn.addEventListener("click", () => { win.dataset.currentPath = btn.dataset.path; updateFileList(); }));
};
updateFileList();
}
function hideStartMenu() {
document.getElementById("start-menu").style.display = "none";
}
document.addEventListener("DOMContentLoaded", () => {
OS.FileSystem.init();
OS.updateSystemAppsUI();
});
</script>
</body>
</html>