Mios-OS / index.html
SiddhJagani's picture
Update index.html
29aa132 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Mios - Ultimate Web OS</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
:root {
--glass-border: rgba(255, 255, 255, 0.2);
--glass-bg: rgba(255, 255, 255, 0.75);
--glass-dark: rgba(28, 28, 30, 0.75);
--accent: #007AFF;
}
body {
font-family: 'Inter', sans-serif;
overflow: hidden;
user-select: none;
background: #000;
}
/* Wallpaper */
#wallpaper {
position: absolute;
inset: 0;
background-size: cover;
background-position: center;
background-image: url('https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?q=80&w=2564&auto=format&fit=crop');
transition: transform 0.3s;
z-index: 0;
}
/* Glassmorphism */
.glass {
background: var(--glass-bg);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid var(--glass-border);
box-shadow: 0 15px 35px rgba(0,0,0,0.2);
}
.glass-dark {
background: var(--glass-dark);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255,255,255,0.1);
color: white;
}
/* Icons */
.app-icon {
transition: all 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.app-icon:hover { transform: scale(1.15) translateY(-8px); }
.app-icon:active { transform: scale(0.95); filter: brightness(0.8); }
/* Window Animations */
.window {
transition: transform 0.2s, opacity 0.2s, width 0.05s, height 0.05s; /* Faster width/height for resizing */
opacity: 0;
transform: scale(0.95);
display: flex;
flex-direction: column;
overflow: hidden;
}
.window.active { opacity: 1; transform: scale(1); }
.window.minimized {
opacity: 0;
transform: scale(0.5) translate(0, 500px);
pointer-events: none;
}
/* Context Menu & Dropdowns */
.context-menu {
animation: fadeScale 0.1s ease-out;
transform-origin: top left;
}
@keyframes fadeScale {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
/* Utilities */
.resize-handle {
position: absolute;
bottom: 0;
right: 0;
width: 15px;
height: 15px;
cursor: nwse-resize;
z-index: 50;
}
/* Flash Animation for Camera */
@keyframes flash {
0% { opacity: 0; }
10% { opacity: 1; background: white; }
100% { opacity: 0; }
}
.flash-overlay {
animation: flash 0.5s ease-out;
pointer-events: none;
}
/* Scrollbars */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(128,128,128,0.4); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: rgba(128,128,128,0.6); }
</style>
</head>
<body class="h-screen w-screen overflow-hidden text-gray-900" oncontextmenu="return false;">
<!-- Desktop Wallpaper -->
<div id="wallpaper" onclick="handleDesktopClick(event)" oncontextmenu="handleRightClick(event)"></div>
<!-- Boot Screen -->
<div id="boot-screen" class="absolute inset-0 bg-black flex flex-col items-center justify-center text-white z-[9999]">
<i class="fab fa-apple text-7xl mb-10"></i>
<div class="w-56 h-1.5 bg-gray-800 rounded-full overflow-hidden">
<div class="h-full bg-white w-0 transition-all duration-[2500ms] ease-out" id="boot-bar"></div>
</div>
</div>
<!-- Top Bar -->
<div class="absolute top-0 left-0 right-0 h-8 glass-dark z-50 flex justify-between items-center px-4 text-xs font-medium select-none">
<div class="flex items-center space-x-4 relative">
<div class="hover:text-gray-300 cursor-pointer px-1 relative group" onclick="toggleMenu('apple-menu')">
<i class="fab fa-apple text-base"></i>
<!-- Apple Menu Dropdown -->
<div id="apple-menu" class="hidden absolute top-6 left-0 w-48 bg-gray-800/90 backdrop-blur-xl border border-gray-600 rounded-lg shadow-xl py-1 text-white flex-col">
<div class="px-4 py-1 hover:bg-blue-600 cursor-pointer" onclick="openApp('settings')">System Preferences...</div>
<div class="h-[1px] bg-gray-600 my-1"></div>
<div class="px-4 py-1 hover:bg-blue-600 cursor-pointer" onclick="location.reload()">Restart...</div>
<div class="px-4 py-1 hover:bg-blue-600 cursor-pointer" onclick="shutdown()">Shut Down...</div>
</div>
</div>
<span class="font-bold" id="active-app-name">Finder</span>
<!-- Top Menu Items -->
<div class="relative group cursor-pointer hover:text-gray-300" onclick="toggleMenu('file-menu')">
File
<div id="file-menu" class="hidden absolute top-6 left-0 w-40 bg-gray-800/90 backdrop-blur-xl border border-gray-600 rounded-lg shadow-xl py-1 text-white flex-col font-normal">
<div class="px-4 py-1 hover:bg-blue-600" onclick="alertMsg('New Window')">New Window</div>
<div class="px-4 py-1 hover:bg-blue-600" onclick="alertMsg('New Folder')">New Folder</div>
</div>
</div>
<span class="hidden md:inline hover:text-gray-300 cursor-pointer" onclick="alertMsg('Edit Menu')">Edit</span>
<span class="hidden md:inline hover:text-gray-300 cursor-pointer" onclick="alertMsg('View Menu')">View</span>
<span class="hidden md:inline hover:text-gray-300 cursor-pointer" onclick="alertMsg('Go Menu')">Go</span>
<span class="hidden md:inline hover:text-gray-300 cursor-pointer" onclick="alertMsg('Help Menu')">Help</span>
</div>
<!-- Right Status Icons -->
<div class="flex items-center space-x-3">
<div class="flex items-center space-x-3 px-2 py-1 rounded hover:bg-white/10 cursor-pointer transition" onclick="toggleControlCenter()">
<i id="status-wifi" class="fas fa-wifi text-sm"></i>
<i class="fas fa-battery-full text-sm text-green-400"></i>
<span id="clock" class="text-sm font-medium ml-2">12:00</span>
</div>
</div>
</div>
<!-- Control Center -->
<div id="control-center" class="absolute top-10 right-2 w-80 glass-dark rounded-2xl p-4 translate-y-[-150%] transition-transform duration-300 z-50 shadow-2xl text-white">
<div class="grid grid-cols-2 gap-3 mb-3">
<div class="bg-white/10 rounded-xl p-3 flex flex-col gap-2">
<div class="flex items-center gap-3 cursor-pointer group" onclick="toggleSystemState('wifi')">
<div id="cc-wifi-icon" class="w-8 h-8 rounded-full bg-blue-500 flex items-center justify-center transition"><i class="fas fa-wifi"></i></div>
<div class="flex flex-col">
<span class="text-xs font-bold">Wi-Fi</span>
<span id="cc-wifi-text" class="text-[10px] text-gray-300">Home_5G</span>
</div>
</div>
<div class="flex items-center gap-3 cursor-pointer group" onclick="toggleSystemState('bluetooth')">
<div id="cc-bt-icon" class="w-8 h-8 rounded-full bg-blue-500 flex items-center justify-center transition"><i class="fab fa-bluetooth-b"></i></div>
<div class="flex flex-col">
<span class="text-xs font-bold">Bluetooth</span>
<span id="cc-bt-text" class="text-[10px] text-gray-300">On</span>
</div>
</div>
</div>
<div class="bg-white/10 rounded-xl p-3 flex flex-col justify-between">
<div class="flex items-center space-x-2">
<div class="w-8 h-8 rounded-full bg-orange-500 flex items-center justify-center"><i class="fas fa-music"></i></div>
<span class="text-xs font-bold">Music</span>
</div>
<div class="text-xs text-gray-400 text-center mt-2">Not Playing</div>
<div class="flex justify-center text-lg space-x-4 mt-1">
<i class="fas fa-backward hover:text-white cursor-pointer"></i>
<i class="fas fa-play hover:text-white cursor-pointer"></i>
<i class="fas fa-forward hover:text-white cursor-pointer"></i>
</div>
</div>
</div>
<!-- Sliders -->
<div class="bg-white/10 rounded-xl p-3 mb-3">
<div class="text-[10px] font-bold mb-1 uppercase text-gray-400">Display</div>
<input type="range" min="0" max="100" value="80" class="w-full h-6 rounded-full overflow-hidden appearance-none bg-gray-700 cursor-pointer accent-white" oninput="document.getElementById('wallpaper').style.filter = `brightness(${this.value}%)`">
</div>
<div class="bg-white/10 rounded-xl p-3">
<div class="text-[10px] font-bold mb-1 uppercase text-gray-400">Sound</div>
<input type="range" min="0" max="100" value="60" class="w-full h-6 rounded-full overflow-hidden appearance-none bg-gray-700 cursor-pointer accent-white">
</div>
</div>
<!-- Desktop Context Menu -->
<div id="context-menu" class="hidden absolute w-48 bg-white/90 backdrop-blur-md rounded-lg shadow-xl py-1 z-[100] text-sm border border-gray-200 context-menu">
<div class="px-4 py-1.5 hover:bg-blue-500 hover:text-white cursor-pointer" onclick="openApp('settings'); switchSettingsTab('wallpaper')">Change Wallpaper...</div>
<div class="px-4 py-1.5 hover:bg-blue-500 hover:text-white cursor-pointer" onclick="createNewFolder()">New Folder</div>
<div class="h-[1px] bg-gray-300 my-1"></div>
<div class="px-4 py-1.5 hover:bg-blue-500 hover:text-white cursor-pointer" onclick="alertMsg('Sorted by Name')">Sort By</div>
<div class="px-4 py-1.5 hover:bg-blue-500 hover:text-white cursor-pointer" onclick="location.reload()">Refresh Simulation</div>
</div>
<!-- Window Area -->
<div id="window-container" class="absolute inset-0 z-10 pointer-events-none overflow-hidden pb-20 pt-8">
<!-- Dynamic Windows -->
</div>
<!-- Dock -->
<div class="absolute bottom-4 left-1/2 transform -translate-x-1/2 h-20 glass rounded-3xl flex items-center px-4 space-x-3 z-40 transition-all duration-300 hover:scale-105">
<div class="dock-item group relative" onclick="openApp('finder')">
<div class="w-14 h-14 bg-gradient-to-b from-blue-400 to-blue-600 rounded-xl flex items-center justify-center text-3xl text-white shadow-lg app-icon"><i class="far fa-face-smile"></i></div>
<div class="absolute -bottom-12 left-1/2 transform -translate-x-1/2 bg-gray-800 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 pointer-events-none transition">Finder</div>
</div>
<div class="dock-item group relative" onclick="openApp('browser')">
<div class="w-14 h-14 bg-white rounded-xl flex items-center justify-center text-3xl shadow-lg overflow-hidden app-icon">
<i class="fab fa-safari text-blue-500 text-5xl"></i>
</div>
<div class="absolute -bottom-12 left-1/2 transform -translate-x-1/2 bg-gray-800 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 pointer-events-none transition">Safari</div>
</div>
<div class="dock-item group relative" onclick="openApp('ai')">
<div class="w-14 h-14 bg-gradient-to-tr from-purple-600 to-pink-500 rounded-xl flex items-center justify-center text-2xl text-white shadow-lg app-icon"><i class="fas fa-sparkles"></i></div>
<div class="absolute -bottom-12 left-1/2 transform -translate-x-1/2 bg-gray-800 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 pointer-events-none transition">Qwen AI</div>
</div>
<div class="dock-item group relative" onclick="openApp('notes')">
<div class="w-14 h-14 bg-yellow-400 rounded-xl flex items-center justify-center text-2xl text-white shadow-lg overflow-hidden app-icon relative">
<div class="absolute top-0 left-0 w-full h-4 bg-yellow-300"></div>
<i class="fas fa-sticky-note mt-2 text-yellow-100"></i>
</div>
<div class="absolute -bottom-12 left-1/2 transform -translate-x-1/2 bg-gray-800 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 pointer-events-none transition">Notes</div>
</div>
<div class="w-[1px] h-10 bg-gray-400/50 mx-2"></div>
<div class="dock-item group relative" onclick="openApp('camera')">
<div class="w-14 h-14 bg-gray-200 rounded-xl flex items-center justify-center shadow-lg app-icon relative">
<div class="w-8 h-8 bg-black rounded-full border-2 border-gray-600"></div>
<div class="absolute top-2 right-2 w-2 h-2 bg-red-500 rounded-full animate-pulse"></div>
</div>
<div class="absolute -bottom-12 left-1/2 transform -translate-x-1/2 bg-gray-800 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 pointer-events-none transition">Camera</div>
</div>
<div class="dock-item group relative" onclick="openApp('settings')">
<div class="w-14 h-14 bg-gray-300 rounded-xl flex items-center justify-center text-3xl text-gray-700 shadow-lg app-icon"><i class="fas fa-cog"></i></div>
<div class="absolute -bottom-12 left-1/2 transform -translate-x-1/2 bg-gray-800 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 pointer-events-none transition">Settings</div>
</div>
<div class="dock-item group relative" onclick="openApp('bin')">
<div class="w-14 h-14 bg-white/20 rounded-xl flex items-center justify-center text-2xl text-gray-200 shadow-lg app-icon"><i class="fas fa-trash"></i></div>
<div class="absolute -bottom-12 left-1/2 transform -translate-x-1/2 bg-gray-800 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 pointer-events-none transition">Bin</div>
</div>
</div>
<!-- JAVASCRIPT LOGIC -->
<script>
// --- GLOBAL STATE ---
const system = {
wifi: true,
bluetooth: true,
volume: 60,
brightness: 100,
wallpaper: 'https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?q=80&w=2564&auto=format&fit=crop',
files: {
'Desktop': [
{ name: 'Welcome.txt', type: 'text', content: 'Welcome to Mios!\n\nThis is a fully functional simulation. Try opening apps, changing settings, or taking a photo!' },
{ name: 'Project_Specs.pdf', type: 'file' }
],
'Documents': [
{ name: 'Resume.docx', type: 'file' },
{ name: 'Budget.xlsx', type: 'file' },
{ name: 'Notes_Idea.txt', type: 'text', content: 'Idea for app: A hybrid OS that runs in the browser.' }
],
'Pictures': [
{ name: 'Vacation.jpg', type: 'image', src: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=400' },
{ name: 'Cat.png', type: 'image', src: 'https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?w=400' }
],
'Downloads': []
}
};
// --- BOOT & INIT ---
window.onload = () => {
// Boot Animation
setTimeout(() => document.getElementById('boot-bar').style.width = '100%', 100);
setTimeout(() => {
const screen = document.getElementById('boot-screen');
screen.style.opacity = '0';
setTimeout(() => screen.remove(), 1000);
}, 2800);
startClock();
};
// --- UTILS ---
function startClock() {
setInterval(() => {
const now = new Date();
document.getElementById('clock').innerText = now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
}, 1000);
}
function alertMsg(msg) {
// Use a custom toast instead of alert()
const toast = document.createElement('div');
toast.className = 'fixed top-12 left-1/2 transform -translate-x-1/2 bg-gray-800 text-white px-4 py-2 rounded-full text-sm shadow-lg z-[9999] animate-fade-in-down';
toast.innerHTML = `<i class="fas fa-info-circle mr-2"></i> ${msg}`;
document.body.appendChild(toast);
setTimeout(() => {
toast.style.opacity = '0';
setTimeout(() => toast.remove(), 500);
}, 2000);
}
function shutdown() {
document.body.innerHTML = '<div class="h-screen w-screen bg-black flex items-center justify-center text-white"><i class="fas fa-power-off text-4xl animate-pulse"></i></div>';
}
// --- SYSTEM UI INTERACTIONS ---
// Context Menu
function handleRightClick(e) {
e.preventDefault();
const menu = document.getElementById('context-menu');
menu.style.left = e.clientX + 'px';
menu.style.top = e.clientY + 'px';
menu.classList.remove('hidden');
closeAllDropdowns();
}
function handleDesktopClick(e) {
document.getElementById('context-menu').classList.add('hidden');
closeAllDropdowns();
}
function toggleMenu(id) {
const menu = document.getElementById(id);
const isHidden = menu.classList.contains('hidden');
closeAllDropdowns();
if (isHidden) menu.classList.remove('hidden');
}
function closeAllDropdowns() {
document.querySelectorAll('[id$="-menu"]').forEach(el => {
if(el.id !== 'context-menu') el.classList.add('hidden');
});
document.getElementById('context-menu').classList.add('hidden');
}
// Control Center
function toggleControlCenter() {
const cc = document.getElementById('control-center');
const current = cc.style.transform;
cc.style.transform = current === 'translateY(0px)' ? 'translateY(-150%)' : 'translateY(0px)';
}
function toggleSystemState(type) {
if (type === 'wifi') {
system.wifi = !system.wifi;
const icon = document.getElementById('cc-wifi-icon');
const text = document.getElementById('cc-wifi-text');
const status = document.getElementById('status-wifi');
icon.className = `w-8 h-8 rounded-full flex items-center justify-center transition ${system.wifi ? 'bg-blue-500 text-white' : 'bg-gray-600 text-gray-400'}`;
text.innerText = system.wifi ? 'Home_5G' : 'Off';
status.className = system.wifi ? 'fas fa-wifi text-sm' : 'fas fa-slash text-sm text-gray-500';
} else if (type === 'bluetooth') {
system.bluetooth = !system.bluetooth;
const icon = document.getElementById('cc-bt-icon');
const text = document.getElementById('cc-bt-text');
icon.className = `w-8 h-8 rounded-full flex items-center justify-center transition ${system.bluetooth ? 'bg-blue-500 text-white' : 'bg-gray-600 text-gray-400'}`;
text.innerText = system.bluetooth ? 'On' : 'Off';
}
}
// --- WINDOW MANAGER ---
let zIndex = 100;
const activeWindows = {};
function openApp(appId, extraData = null) {
if (activeWindows[appId]) {
bringToFront(appId);
if (extraData && appId === 'notes') loadNote(extraData);
return;
}
const appConfig = getAppConfig(appId);
const win = document.createElement('div');
win.id = `win-${appId}`;
win.className = 'window glass rounded-xl absolute shadow-2xl pointer-events-auto resize-y';
win.style.width = appConfig.width + 'px';
win.style.height = appConfig.height + 'px';
win.style.left = (50 + Math.random() * 50) + 'px';
win.style.top = (50 + Math.random() * 50) + 'px';
win.style.zIndex = ++zIndex;
win.innerHTML = `
<!-- Header -->
<div class="h-9 bg-gray-200/80 border-b border-gray-300 flex items-center px-3 justify-between cursor-move select-none" onmousedown="startDrag(event, '${appId}')" ondblclick="maximizeApp('${appId}')">
<div class="flex space-x-2">
<div onclick="closeApp('${appId}')" class="w-3 h-3 rounded-full bg-red-500 hover:brightness-90 cursor-pointer flex items-center justify-center group"><i class="fas fa-times text-[6px] opacity-0 group-hover:opacity-100 text-black"></i></div>
<div onclick="minimizeApp('${appId}')" class="w-3 h-3 rounded-full bg-yellow-500 hover:brightness-90 cursor-pointer flex items-center justify-center group"><i class="fas fa-minus text-[6px] opacity-0 group-hover:opacity-100 text-black"></i></div>
<div onclick="maximizeApp('${appId}')" class="w-3 h-3 rounded-full bg-green-500 hover:brightness-90 cursor-pointer flex items-center justify-center group"><i class="fas fa-expand text-[6px] opacity-0 group-hover:opacity-100 text-black"></i></div>
</div>
<div class="font-semibold text-sm text-gray-600">${appConfig.title}</div>
<div class="w-12"></div>
</div>
<!-- Content -->
<div class="flex-1 bg-white relative overflow-hidden flex flex-col window-content">
${appConfig.content}
</div>
<!-- Resize Handle -->
<div class="resize-handle" onmousedown="startResize(event, '${appId}')"></div>
`;
document.getElementById('window-container').appendChild(win);
activeWindows[appId] = win;
requestAnimationFrame(() => win.classList.add('active'));
updateMenuBar(appConfig.title);
// Post-render initialization
if (appId === 'camera') initCamera();
if (appId === 'finder') navigateFinder('Desktop');
if (appId === 'notes' && extraData) loadNote(extraData);
if (appId === 'ai') setTimeout(() => addAIMessage("Hello! I am Qwen (Simulated). How can I help?", false), 500);
}
function closeApp(id) {
const win = activeWindows[id];
if(win) {
win.classList.remove('active');
setTimeout(() => win.remove(), 200);
delete activeWindows[id];
if (id === 'camera') stopCamera();
}
}
function minimizeApp(id) {
const win = activeWindows[id];
win.classList.add('minimized');
}
function bringToFront(id) {
const win = activeWindows[id];
if(win) {
win.style.zIndex = ++zIndex;
win.classList.remove('minimized');
updateMenuBar(getAppConfig(id).title);
}
}
function maximizeApp(id) {
const win = activeWindows[id];
if (win.dataset.maximized) {
win.style.width = win.dataset.origW;
win.style.height = win.dataset.origH;
win.style.top = win.dataset.origT;
win.style.left = win.dataset.origL;
delete win.dataset.maximized;
win.style.borderRadius = '0.75rem';
} else {
win.dataset.origW = win.style.width;
win.dataset.origH = win.style.height;
win.dataset.origT = win.style.top;
win.dataset.origL = win.style.left;
win.style.width = '100%';
win.style.height = 'calc(100% - 32px)'; // Minus top bar
win.style.top = '32px';
win.style.left = '0';
win.style.borderRadius = '0';
win.dataset.maximized = true;
}
}
function updateMenuBar(name) {
document.getElementById('active-app-name').innerText = name;
}
// --- DRAG & RESIZE LOGIC ---
let dragObj = null, resizeObj = null;
let initialX, initialY, initialW, initialH;
function startDrag(e, id) {
bringToFront(id);
if(e.target.closest('.resize-handle')) return; // Avoid drag if resizing
dragObj = activeWindows[id];
initialX = e.clientX - dragObj.getBoundingClientRect().left;
initialY = e.clientY - dragObj.getBoundingClientRect().top;
// Prevent dragging maximized windows
if(dragObj.dataset.maximized) dragObj = null;
}
function startResize(e, id) {
e.stopPropagation();
bringToFront(id);
resizeObj = activeWindows[id];
initialX = e.clientX;
initialY = e.clientY;
initialW = parseInt(document.defaultView.getComputedStyle(resizeObj).width, 10);
initialH = parseInt(document.defaultView.getComputedStyle(resizeObj).height, 10);
}
window.addEventListener('mousemove', (e) => {
if (dragObj) {
e.preventDefault();
dragObj.style.left = (e.clientX - initialX) + 'px';
dragObj.style.top = (e.clientY - initialY) + 'px';
}
if (resizeObj) {
e.preventDefault();
resizeObj.style.width = (initialW + (e.clientX - initialX)) + 'px';
resizeObj.style.height = (initialH + (e.clientY - initialY)) + 'px';
}
});
window.addEventListener('mouseup', () => {
dragObj = null;
resizeObj = null;
});
// --- APP CONTENT GENERATORS ---
function getAppConfig(id) {
const configs = {
'finder': { title: 'Finder', width: 800, height: 500, content: `
<div class="flex h-full">
<div class="w-48 bg-gray-50 border-r border-gray-200 p-4 space-y-2">
<div class="text-xs font-bold text-gray-400 mb-2 px-2">Favorites</div>
${['Desktop', 'Documents', 'Pictures', 'Downloads'].map(f =>
`<div onclick="navigateFinder('${f}')" class="flex items-center space-x-2 px-2 py-1.5 rounded cursor-pointer hover:bg-gray-200 text-sm text-gray-700">
<i class="fas fa-${f === 'Pictures' ? 'image' : f === 'Downloads' ? 'download' : 'folder'} text-blue-500 w-4"></i>
<span>${f}</span>
</div>`
).join('')}
</div>
<div class="flex-1 flex flex-col">
<div class="h-10 border-b flex items-center px-4 space-x-4 bg-white">
<div class="flex space-x-2">
<i class="fas fa-chevron-left text-gray-400 cursor-pointer hover:text-gray-600"></i>
<i class="fas fa-chevron-right text-gray-400 cursor-pointer hover:text-gray-600"></i>
</div>
<div class="font-semibold text-sm" id="finder-path">Desktop</div>
</div>
<div class="flex-1 p-4 overflow-auto grid grid-cols-4 gap-4 content-start" id="finder-content">
<!-- Files injected here -->
</div>
</div>
</div>
`},
'settings': { title: 'System Settings', width: 700, height: 450, content: `
<div class="flex h-full bg-gray-100">
<div class="w-1/3 bg-white border-r p-3 space-y-1 overflow-y-auto">
<div class="flex items-center p-2 rounded-lg bg-gray-100 mb-4">
<div class="w-10 h-10 bg-gray-300 rounded-full flex items-center justify-center text-white"><i class="fas fa-user"></i></div>
<div class="ml-3">
<div class="text-sm font-bold">User</div>
<div class="text-xs text-gray-500">Apple ID</div>
</div>
</div>
<div onclick="switchSettingsTab('wifi')" class="p-2 hover:bg-blue-50 rounded cursor-pointer flex items-center text-sm"><i class="fas fa-wifi w-6 text-blue-500"></i> Wi-Fi</div>
<div onclick="switchSettingsTab('bluetooth')" class="p-2 hover:bg-blue-50 rounded cursor-pointer flex items-center text-sm"><i class="fab fa-bluetooth w-6 text-blue-500"></i> Bluetooth</div>
<div onclick="switchSettingsTab('wallpaper')" class="p-2 hover:bg-blue-50 rounded cursor-pointer flex items-center text-sm"><i class="fas fa-image w-6 text-purple-500"></i> Wallpaper</div>
<div onclick="switchSettingsTab('ai')" class="p-2 hover:bg-blue-50 rounded cursor-pointer flex items-center text-sm"><i class="fas fa-microchip w-6 text-green-500"></i> Artificial Intelligence</div>
</div>
<div class="flex-1 p-6 overflow-y-auto" id="settings-content">
<!-- Dynamic Settings Content -->
</div>
</div>
`},
'browser': { title: 'Safari', width: 900, height: 600, content: `
<div class="flex flex-col h-full bg-white">
<div class="h-12 bg-gray-100 border-b flex items-center px-3 space-x-3">
<i class="fas fa-chevron-left text-gray-400 cursor-pointer"></i>
<i class="fas fa-chevron-right text-gray-400 cursor-pointer"></i>
<i class="fas fa-newspaper text-gray-600"></i>
<form onsubmit="handleBrowserSearch(event)" class="flex-1 relative">
<input id="browser-url" type="text" class="w-full h-8 bg-gray-200 rounded-md pl-8 pr-3 text-sm focus:bg-white focus:ring-2 ring-blue-500 outline-none transition" placeholder="Search or enter website name">
<i class="fas fa-search absolute left-2.5 top-2.5 text-gray-400 text-xs"></i>
</form>
<i class="fas fa-plus text-gray-500 cursor-pointer"></i>
</div>
<div class="h-1 bg-blue-500 w-0 transition-all duration-1000" id="browser-load-bar"></div>
<div class="flex-1 overflow-auto p-8 flex flex-col items-center justify-center" id="browser-view">
<div class="text-center">
<i class="fab fa-safari text-6xl text-gray-300 mb-4"></i>
<h1 class="text-2xl font-bold text-gray-700">Start Page</h1>
<div class="grid grid-cols-4 gap-6 mt-8">
${['Apple', 'Google', 'Bing', 'Wiki'].map(n => `
<div onclick="loadUrl('${n.toLowerCase()}.com')" class="flex flex-col items-center cursor-pointer group">
<div class="w-12 h-12 bg-gray-100 rounded-xl flex items-center justify-center text-xl group-hover:bg-gray-200 transition">${n[0]}</div>
<span class="text-xs mt-2 text-gray-500">${n}</span>
</div>
`).join('')}
</div>
</div>
</div>
</div>
`},
'camera': { title: 'Camera', width: 600, height: 500, content: `
<div class="h-full bg-black flex flex-col relative overflow-hidden">
<video id="camera-feed" autoplay playsinline class="flex-1 object-cover transform scale-x-[-1]"></video>
<div id="flash-overlay" class="absolute inset-0 bg-white opacity-0 pointer-events-none"></div>
<div class="h-20 bg-black/40 absolute bottom-0 w-full flex items-center justify-center space-x-12 backdrop-blur-sm">
<div class="text-yellow-400 text-xs font-bold">PHOTO</div>
<div onclick="takePhoto()" class="w-16 h-16 rounded-full border-4 border-white flex items-center justify-center cursor-pointer active:scale-90 transition">
<div class="w-14 h-14 bg-white rounded-full"></div>
</div>
<div class="text-white text-xs font-bold opacity-50">VIDEO</div>
</div>
</div>
`},
'notes': { title: 'Notes', width: 500, height: 400, content: `
<div class="h-full flex flex-col bg-yellow-50">
<div class="h-10 border-b border-yellow-200 flex items-center justify-between px-4">
<span class="text-xs text-gray-500" id="note-timestamp">Today</span>
<i class="far fa-edit text-yellow-600 cursor-pointer"></i>
</div>
<textarea id="note-area" class="flex-1 bg-transparent p-4 outline-none resize-none text-gray-800 font-serif text-lg" placeholder="Type your notes here..."></textarea>
</div>
`},
'ai': { title: 'Qwen AI', width: 700, height: 550, content: `
<div class="flex flex-col h-full bg-white">
<div class="flex-1 overflow-y-auto p-4 space-y-4" id="ai-chat-container"></div>
<div class="p-4 bg-gray-50 border-t flex">
<input id="ai-input" type="text" class="flex-1 bg-white border rounded-full px-4 py-2 text-sm outline-none focus:ring-2 ring-purple-500" placeholder="Message Qwen..." onkeypress="if(event.key==='Enter') sendAIMessage()">
<button onclick="sendAIMessage()" class="ml-2 w-9 h-9 bg-purple-600 text-white rounded-full flex items-center justify-center hover:bg-purple-700"><i class="fas fa-arrow-up"></i></button>
</div>
</div>
`},
'bin': { title: 'Bin', width: 600, height: 400, content: `
<div class="flex-1 bg-white flex items-center justify-center flex-col text-gray-400">
<i class="fas fa-trash-alt text-5xl mb-4"></i>
<span>Bin is empty</span>
</div>
`}
};
return configs[id] || configs['finder'];
}
// --- FEATURE: FINDER ---
let currentPath = 'Desktop';
function navigateFinder(path) {
currentPath = path;
document.getElementById('finder-path').innerText = path;
const container = document.getElementById('finder-content');
if(!container) return;
const files = system.files[path] || [];
container.innerHTML = files.map(file => `
<div ondblclick="openFile('${file.name}')" class="flex flex-col items-center justify-center p-2 hover:bg-blue-100 rounded cursor-pointer group w-24">
${getFileIcon(file)}
<span class="text-xs text-center mt-2 text-gray-700 truncate w-full px-1 group-hover:text-blue-800">${file.name}</span>
</div>
`).join('');
}
function getFileIcon(file) {
if(file.type === 'image') return `<img src="${file.src}" class="w-14 h-14 object-cover rounded shadow-sm">`;
if(file.type === 'text') return `<i class="fas fa-file-alt text-4xl text-gray-400"></i>`;
return `<i class="fas fa-file text-4xl text-gray-400"></i>`;
}
function openFile(filename) {
const file = system.files[currentPath].find(f => f.name === filename);
if (!file) return;
if (file.type === 'text') {
openApp('notes', file.content);
} else if (file.type === 'image') {
// Create a preview window for image
const id = 'img-' + Math.random().toString(36).substr(2, 9);
const win = document.createElement('div');
// Simplified: just alert for now or update wallpaper
if(confirm("Set as wallpaper?")) {
system.wallpaper = `url('${file.src}')`;
document.getElementById('wallpaper').style.backgroundImage = `url('${file.src}')`;
}
} else {
alertMsg("Cannot open file type");
}
}
function createNewFolder() {
const name = prompt("Folder Name:", "New Folder");
if(name) {
if(!system.files['Desktop']) system.files['Desktop'] = [];
system.files['Desktop'].push({ name: name, type: 'folder' });
if(activeWindows['finder']) navigateFinder(currentPath); // Refresh if open
alertMsg("Folder created on Desktop");
}
}
// --- FEATURE: NOTES ---
function loadNote(content) {
const area = document.getElementById('note-area');
if(area) area.value = content;
}
// --- FEATURE: SETTINGS ---
function switchSettingsTab(tab) {
const container = document.getElementById('settings-content');
if (!container) return;
// Highlight active sidebar item (simplified)
let html = '';
if (tab === 'wifi') {
html = `
<h2 class="text-xl font-bold mb-4">Wi-Fi</h2>
<div class="flex items-center justify-between bg-white p-4 rounded-lg border">
<span>Wi-Fi</span>
<div onclick="toggleSystemState('wifi'); switchSettingsTab('wifi')" class="w-12 h-6 ${system.wifi ? 'bg-blue-500' : 'bg-gray-300'} rounded-full relative cursor-pointer transition">
<div class="w-5 h-5 bg-white rounded-full absolute top-0.5 ${system.wifi ? 'left-6.5' : 'left-0.5'} shadow transition-all" style="left: ${system.wifi ? '26px' : '2px'}"></div>
</div>
</div>
<p class="text-sm text-gray-500 mt-2">Known Networks: Home_5G, Office_Guest</p>
`;
} else if (tab === 'wallpaper') {
const walls = [
'https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?q=80&w=2564&auto=format&fit=crop',
'https://images.unsplash.com/photo-1477346611705-65d1883cee1e?auto=format&fit=crop&w=1000&q=80',
'https://images.unsplash.com/photo-1451187580459-43490279c0fa?auto=format&fit=crop&w=1000&q=80',
'https://images.unsplash.com/photo-1506744038136-46273834b3fb?auto=format&fit=crop&w=1000&q=80'
];
html = `
<h2 class="text-xl font-bold mb-4">Wallpaper</h2>
<div class="grid grid-cols-2 gap-4">
${walls.map(url => `
<div onclick="changeWallpaper('${url}')" class="h-24 rounded-lg bg-cover bg-center cursor-pointer border-2 border-transparent hover:border-blue-500" style="background-image: url('${url}')"></div>
`).join('')}
</div>
`;
} else if (tab === 'bluetooth') {
html = `
<h2 class="text-xl font-bold mb-4">Bluetooth</h2>
<div class="flex items-center justify-between bg-white p-4 rounded-lg border">
<span>Bluetooth</span>
<div onclick="toggleSystemState('bluetooth'); switchSettingsTab('bluetooth')" class="w-12 h-6 ${system.bluetooth ? 'bg-blue-500' : 'bg-gray-300'} rounded-full relative cursor-pointer transition">
<div class="w-5 h-5 bg-white rounded-full absolute top-0.5 shadow transition-all" style="left: ${system.bluetooth ? '26px' : '2px'}"></div>
</div>
</div>
<div class="mt-4 text-sm text-gray-500">
<div class="p-2 border-b">AirPods Pro <span class="float-right text-gray-400">Not Connected</span></div>
<div class="p-2 border-b">Magic Keyboard <span class="float-right text-gray-400">Connected</span></div>
</div>
`;
} else {
html = `<div class="flex items-center justify-center h-full text-gray-400">Select a setting</div>`;
}
container.innerHTML = html;
}
function changeWallpaper(url) {
document.getElementById('wallpaper').style.backgroundImage = `url('${url}')`;
system.wallpaper = url;
}
// --- FEATURE: CAMERA ---
function initCamera() {
navigator.mediaDevices.getUserMedia({ video: true })
.then(stream => {
const vid = document.getElementById('camera-feed');
if(vid) vid.srcObject = stream;
})
.catch(() => {
const vid = document.getElementById('camera-feed');
if(vid) {
vid.parentElement.innerHTML = '<div class="flex items-center justify-center h-full text-white bg-gray-900">Camera not available</div>';
}
});
}
function stopCamera() {
// Browser handles cleanup mostly, but good practice
}
function takePhoto() {
const video = document.getElementById('camera-feed');
if (!video) return;
// Flash effect
const flash = document.getElementById('flash-overlay');
flash.style.animation = 'none';
flash.offsetHeight; /* trigger reflow */
flash.style.animation = 'flash 0.3s ease-out';
// Capture logic
const canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0);
const imgUrl = canvas.toDataURL('image/jpeg');
// Save to system files
const filename = `Photo_${Date.now()}.jpg`;
system.files['Pictures'].push({ name: filename, type: 'image', src: imgUrl });
system.files['Downloads'].push({ name: filename, type: 'image', src: imgUrl }); // Add to downloads too
alertMsg('Photo saved to Pictures');
}
// --- FEATURE: BROWSER ---
function handleBrowserSearch(e) {
e.preventDefault();
const val = document.getElementById('browser-url').value;
if(val) loadUrl(val);
}
function loadUrl(url) {
const view = document.getElementById('browser-view');
const bar = document.getElementById('browser-load-bar');
const input = document.getElementById('browser-url');
input.value = url;
bar.style.width = '80%';
view.innerHTML = '<div class="flex h-full items-center justify-center"><i class="fas fa-spinner fa-spin text-4xl text-gray-300"></i></div>';
setTimeout(() => {
bar.style.width = '100%';
setTimeout(() => bar.style.width = '0', 200);
// Mock Content
let content = '';
if(url.includes('google')) content = `<div class="flex flex-col items-center mt-20"><h1 class="text-5xl font-bold text-gray-700 mb-4">Google</h1><input class="border rounded-full px-4 py-2 w-96 shadow-sm" placeholder="Search Google"></div>`;
else if(url.includes('bing')) content = `<div class="flex flex-col items-center mt-20"><h1 class="text-5xl font-bold text-blue-700 mb-4">Bing</h1><input class="border rounded-full px-4 py-2 w-96 shadow-sm" placeholder="Search Bing"></div>`;
else content = `<div class="p-10"><h1 class="text-3xl font-bold">${url}</h1><p class="mt-4 text-gray-600">This is a simulated webpage for ${url}. The sandbox prevents loading real external iframes properly.</p><div class="mt-8 h-4 bg-gray-200 rounded w-3/4"></div><div class="mt-2 h-4 bg-gray-200 rounded w-1/2"></div></div>`;
view.innerHTML = content;
}, 1000);
}
// --- FEATURE: AI ---
function sendAIMessage() {
const input = document.getElementById('ai-input');
const text = input.value;
if(!text) return;
const container = document.getElementById('ai-chat-container');
container.innerHTML += `<div class="flex justify-end mb-2"><div class="bg-blue-500 text-white px-4 py-2 rounded-2xl rounded-tr-none max-w-[80%]">${text}</div></div>`;
input.value = '';
container.scrollTop = container.scrollHeight;
setTimeout(() => {
const reply = getAIResponse(text);
container.innerHTML += `<div class="flex justify-start mb-2"><div class="bg-gray-100 text-gray-800 px-4 py-2 rounded-2xl rounded-tl-none max-w-[80%] shadow-sm">${reply}</div></div>`;
container.scrollTop = container.scrollHeight;
}, 800);
}
function getAIResponse(msg) {
msg = msg.toLowerCase();
if(msg.includes('hello')) return "Hi there! I'm running locally in Mios.";
if(msg.includes('time')) return "It's currently " + new Date().toLocaleTimeString();
if(msg.includes('joke')) return "Why did the developer go broke? Because he used up all his cache.";
return "I'm a simulated AI model. I can answer basic questions or help you navigate this OS!";
}
</script>
</body>
</html>