wergrom's picture
внеси сюда пользователя admin чтобы не выкидывало
cf5bb85 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WinDeskOS - Virtual Desktop</title>
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Segoe+UI:wght@300;400;500;600&display=swap');
* {
font-family: 'Segoe UI', sans-serif;
}
.window {
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
}
.desktop-icon {
transition: all 0.2s ease;
position: absolute;
}
.desktop-icon:hover {
background-color: rgba(255, 255, 255, 0.1);
transform: scale(1.05);
}
.desktop-icon.dragging {
opacity: 0.8;
z-index: 9999;
}
.taskbar-item {
transition: all 0.2s ease;
}
.taskbar-item:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.start-menu {
transition: all 0.3s ease;
transform-origin: bottom left;
}
.context-menu {
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3);
}
.desktop-bg {
background: linear-gradient(135deg, #0078d4 0%, #106ebe 100%);
}
</style>
</head>
<body class="bg-gray-900 text-white overflow-hidden h-screen flex flex-col">
<!-- Desktop Area -->
<div class="desktop-bg flex-1 relative p-4" id="desktop">
<!-- Desktop Icons -->
<div id="desktop-icon-1" class="desktop-icon cursor-pointer p-2 rounded text-center" style="top: 16px; left: 16px;" data-app="recycle-bin">
<i data-feather="trash-2" class="w-8 h-8 mx-auto text-blue-300"></i>
<p class="text-xs mt-1 text-white">Recycle Bin</p>
</div>
<div id="desktop-icon-2" class="desktop-icon cursor-pointer p-2 rounded text-center" style="top: 16px; left: 96px;" data-app="documents">
<i data-feather="folder" class="w-8 h-8 mx-auto text-yellow-300"></i>
<p class="text-xs mt-1 text-white">Documents</p>
</div>
<div id="desktop-icon-3" class="desktop-icon cursor-pointer p-2 rounded text-center" style="top: 80px; left: 16px;" data-app="pictures">
<i data-feather="image" class="w-8 h-8 mx-auto text-green-300"></i>
<p class="text-xs mt-1 text-white">Pictures</p>
</div>
<div id="desktop-icon-4" class="desktop-icon cursor-pointer p-2 rounded text-center" style="top: 80px; left: 96px;" data-app="browser">
<i data-feather="globe" class="w-8 h-8 mx-auto text-purple-300"></i>
<p class="text-xs mt-1 text-white">Browser</p>
</div>
<!-- Windows -->
<div id="windows-container" class="absolute inset-0 pointer-events-none">
<!-- Windows will be dynamically added here -->
</div>
</div>
<!-- Taskbar -->
<div class="bg-gray-800 bg-opacity-90 border-t border-gray-700 h-10 flex items-center px-2">
<!-- Start Button -->
<button id="start-button" class="taskbar-item h-8 w-8 bg-blue-600 hover:bg-blue-500 rounded flex items-center justify-center mr-2">
<i data-feather="grid" class="w-4 h-4"></i>
</button>
<!-- User Profile Button -->
<div class="taskbar-item h-8 px-3 bg-gray-700 hover:bg-gray-600 rounded flex items-center justify-center cursor-pointer mr-2" onclick="showUserMenu()">
<i data-feather="user" class="w-4 h-4 mr-2"></i>
<span id="username-display" class="text-xs">User</span>
</div>
<!-- Taskbar Apps -->
<div class="flex space-x-1">
<div class="taskbar-item h-8 w-8 bg-gray-700 hover:bg-gray-600 rounded flex items-center justify-center cursor-pointer" onclick="openWindow('browser')">
<i data-feather="globe" class="w-4 h-4"></i>
</div>
<div class="taskbar-item h-8 w-8 bg-gray-700 hover:bg-gray-600 rounded flex items-center justify-center cursor-pointer" onclick="openWindow('explorer')">
<i data-feather="folder" class="w-4 h-4"></i>
</div>
<div class="taskbar-item h-8 w-8 bg-gray-700 hover:bg-gray-600 rounded flex items-center justify-center cursor-pointer" onclick="openWindow('settings')">
<i data-feather="settings" class="w-4 h-4"></i>
</div>
</div>
<!-- System Tray -->
<div class="ml-auto flex items-center space-x-3">
<div class="text-xs cursor-pointer hover:text-blue-300" onclick="toggleVolume()">
<i data-feather="volume-2" id="volume-icon" class="w-4 h-4"></i>
</div>
<div class="text-xs cursor-pointer hover:text-blue-300" onclick="toggleWiFiMenu()">
<i data-feather="wifi" id="wifi-icon" class="w-4 h-4"></i>
</div>
<div class="text-xs cursor-pointer hover:text-blue-300" onclick="toggleBatteryInfo()">
<i data-feather="battery" id="battery-icon" class="w-4 h-4"></i>
</div>
<div class="text-xs">
<span id="time">15:30</span>
</div>
<div class="w-4 h-4 bg-green-500 rounded-full cursor-pointer" onclick="showNotificationCenter()"></div>
</div>
</div>
<!-- User Menu -->
<div id="user-menu" class="fixed bottom-12 left-14 w-48 bg-gray-800 bg-opacity-95 rounded-lg window hidden transform scale-95 opacity-0 pointer-events-none z-50">
<div class="p-3 border-b border-gray-700">
<div class="text-sm font-semibold" id="user-menu-name">User</div>
<div class="text-xs text-gray-400" id="user-menu-email">user@example.com</div>
</div>
<div class="p-1">
<div class="px-3 py-2 hover:bg-gray-700 cursor-pointer rounded text-sm flex items-center space-x-2" onclick="showUserSettings()">
<i data-feather="settings" class="w-4 h-4"></i>
<span>Account Settings</span>
</div>
<div class="px-3 py-2 hover:bg-gray-700 cursor-pointer rounded text-sm flex items-center space-x-2" onclick="lockSession()">
<i data-feather="lock" class="w-4 h-4"></i>
<span>Lock Session</span>
</div>
<div class="border-t border-gray-700 my-1"></div>
<div class="px-3 py-2 hover:bg-gray-700 cursor-pointer rounded text-sm flex items-center space-x-2" onclick="logout()">
<i data-feather="log-out" class="w-4 h-4"></i>
<span>Sign Out</span>
</div>
</div>
</div>
<!-- Start Menu -->
<div id="start-menu" class="start-menu fixed bottom-10 left-2 w-80 h-96 bg-gray-800 bg-opacity-95 rounded-lg window hidden transform scale-95 opacity-0 pointer-events-none">
<div class="p-4">
<div class="text-xl font-semibold mb-4">Applications</div>
<div class="grid grid-cols-2 gap-2">
<div class="p-3 rounded hover:bg-gray-700 cursor-pointer flex items-center space-x-2" onclick="openWindow('browser')">
<i data-feather="globe" class="w-6 h-6 text-blue-400"></i>
<span>Browser</span>
</div>
<div class="p-3 rounded hover:bg-gray-700 cursor-pointer flex items-center space-x-2" onclick="openWindow('explorer')">
<i data-feather="folder" class="w-6 h-6 text-yellow-400"></i>
<span>File Explorer</span>
</div>
<div class="p-3 rounded hover:bg-gray-700 cursor-pointer flex items-center space-x-2" onclick="openWindow('settings')">
<i data-feather="settings" class="w-6 h-6 text-gray-400"></i>
<span>Settings</span>
</div>
<div class="p-3 rounded hover:bg-gray-700 cursor-pointer flex items-center space-x-2" onclick="openWindow('notepad')">
<i data-feather="edit" class="w-6 h-6 text-green-400"></i>
<span>Notepad</span>
</div>
<div class="p-3 rounded hover:bg-gray-700 cursor-pointer flex items-center space-x-2" onclick="openWindow('calculator')">
<i data-feather="calculator" class="w-6 h-6 text-purple-400"></i>
<span>Calculator</span>
</div>
<div class="p-3 rounded hover:bg-gray-700 cursor-pointer flex items-center space-x-2" onclick="openWindow('weather')">
<i data-feather="cloud" class="w-6 h-6 text-blue-400"></i>
<span>Weather</span>
</div>
<div class="p-3 rounded hover:bg-gray-700 cursor-pointer flex items-center space-x-2" onclick="openWindow('calendar')">
<i data-feather="calendar" class="w-6 h-6 text-red-400"></i>
<span>Calendar</span>
</div>
</div>
</div>
</div>
<!-- Context Menu -->
<div id="context-menu" class="context-menu fixed bg-gray-800 bg-opacity-95 rounded-lg py-2 hidden z-50">
<div class="px-4 py-2 hover:bg-gray-700 cursor-pointer flex items-center space-x-2">
<i data-feather="folder-plus" class="w-4 h-4"></i>
<span>New Folder</span>
</div>
<div class="px-4 py-2 hover:bg-gray-700 cursor-pointer flex items-center space-x-2">
<i data-feather="file-text" class="w-4 h-4"></i>
<span>New Text Document</span>
</div>
<div class="border-t border-gray-700 my-1"></div>
<div class="px-4 py-2 hover:bg-gray-700 cursor-pointer flex items-center space-x-2">
<i data-feather="settings" class="w-4 h-4"></i>
<span>Personalize</span>
</div>
<div class="px-4 py-2 hover:bg-gray-700 cursor-pointer flex items-center space-x-2">
<i data-feather="info" class="w-4 h-4"></i>
<span>Properties</span>
</div>
<div class="border-t border-gray-700 my-1"></div>
<div class="px-4 py-2 hover:bg-gray-700 cursor-pointer flex items-center space-x-2">
<i data-feather="refresh-cw" class="w-4 h-4"></i>
<span>Refresh</span>
</div>
</div>
<!-- Notification Center -->
<div id="notification-center" class="fixed right-2 bottom-12 w-80 h-96 bg-gray-800 bg-opacity-95 rounded-lg window hidden transform scale-95 opacity-0 pointer-events-none z-50">
<div class="p-4">
<div class="flex items-center justify-between mb-4">
<div class="text-lg font-semibold">Notifications</div>
<button onclick="hideNotificationCenter()" class="w-6 h-6 rounded hover:bg-gray-700 flex items-center justify-center">
<i data-feather="x" class="w-4 h-4"></i>
</button>
</div>
<div class="space-y-2 max-h-64 overflow-y-auto">
<div class="p-3 bg-gray-700 rounded">
<div class="text-sm font-medium">System</div>
<div class="text-xs text-gray-300">Welcome to WinDeskOS!</div>
<div class="text-xs text-gray-400 mt-1">Just now</div>
</div>
</div>
<div class="border-t border-gray-700 mt-4 pt-4">
<div class="text-sm font-semibold mb-2">Quick Settings</div>
<div class="grid grid-cols-3 gap-2">
<div class="p-2 bg-gray-700 rounded text-center cursor-pointer hover:bg-gray-600" onclick="toggleDarkMode()">
<i data-feather="moon" class="w-5 h-5 mx-auto"></i>
<div class="text-xs mt-1">Dark Mode</div>
</div>
<div class="p-2 bg-gray-700 rounded text-center cursor-pointer hover:bg-gray-600" onclick="toggleVolume()">
<i data-feather="volume-2" class="w-5 h-5 mx-auto"></i>
<div class="text-xs mt-1">Volume</div>
</div>
<div class="p-2 bg-gray-700 rounded text-center cursor-pointer hover:bg-gray-600" onclick="toggleWiFi()">
<i data-feather="wifi" class="w-5 h-5 mx-auto"></i>
<div class="text-xs mt-1">Wi-Fi</div>
</div>
</div>
</div>
</div>
</div>
<!-- Calculator App Content -->
<script id="calculator-template" type="text/template">
<div class="h-full flex flex-col">
<div class="bg-gray-900 p-2 text-right text-2xl font-mono mb-2 rounded" id="calc-display">0</div>
<div class="grid grid-cols-4 gap-2 flex-1">
<button class="bg-gray-700 hover:bg-gray-600 rounded p-2" onclick="calcClear()">C</button>
<button class="bg-gray-700 hover:bg-gray-600 rounded p-2" onclick="calcBackspace()"></button>
<button class="bg-gray-700 hover:bg-gray-600 rounded p-2" onclick="calcOperation('%')">%</button>
<button class="bg-blue-600 hover:bg-blue-500 rounded p-2" onclick="calcOperation('/')">/</button>
<button class="bg-gray-600 hover:bg-gray-500 rounded p-2" onclick="calcInput('7')">7</button>
<button class="bg-gray-600 hover:bg-gray-500 rounded p-2" onclick="calcInput('8')">8</button>
<button class="bg-gray-600 hover:bg-gray-500 rounded p-2" onclick="calcInput('9')">9</button>
<button class="bg-blue-600 hover:bg-blue-500 rounded p-2" onclick="calcOperation('*')">×</button>
<button class="bg-gray-600 hover:bg-gray-500 rounded p-2" onclick="calcInput('4')">4</button>
<button class="bg-gray-600 hover:bg-gray-500 rounded p-2" onclick="calcInput('5')">5</button>
<button class="bg-gray-600 hover:bg-gray-500 rounded p-2" onclick="calcInput('6')">6</button>
<button class="bg-blue-600 hover:bg-blue-500 rounded p-2" onclick="calcOperation('-')">-</button>
<button class="bg-gray-600 hover:bg-gray-500 rounded p-2" onclick="calcInput('1')">1</button>
<button class="bg-gray-600 hover:bg-gray-500 rounded p-2" onclick="calcInput('2')">2</button>
<button class="bg-gray-600 hover:bg-gray-500 rounded p-2" onclick="calcInput('3')">3</button>
<button class="bg-blue-600 hover:bg-blue-500 rounded p-2" onclick="calcOperation('+')">+</button>
<button class="bg-gray-600 hover:bg-gray-500 rounded p-2 col-span-2" onclick="calcInput('0')">0</button>
<button class="bg-gray-600 hover:bg-gray-500 rounded p-2" onclick="calcInput('.')">.</button>
<button class="bg-green-600 hover:bg-green-500 rounded p-2" onclick="calcCalculate()">=</button>
</div>
</div>
</script>
<!-- Weather App Content -->
<script id="weather-template" type="text/template">
<div class="h-full flex flex-col items-center justify-center p-4">
<i data-feather="cloud" class="w-16 h-16 text-blue-400 mb-4"></i>
<div class="text-3xl font-bold" id="weather-temp">--°C</div>
<div class="text-lg text-gray-300 mb-2" id="weather-location">Loading...</div>
<div class="text-sm text-gray-400" id="weather-desc">Fetching weather data</div>
<button onclick="fetchWeather()" class="mt-4 px-4 py-2 bg-blue-600 hover:bg-blue-500 rounded text-sm">
<i data-feather="refresh-cw" class="w-4 h-4 inline mr-1"></i>
Refresh
</button>
</div>
</script>
<script>
let windows = [];
let zIndexCounter = 1000;
let currentUser = null;
// Check authentication on page load
function checkAuthentication() {
const userData = localStorage.getItem('currentUser');
// Allow admin user to bypass login for demo purposes
if (!userData) {
// Create demo admin user if none exists
const demoUser = {
username: 'admin',
rememberMe: true,
loginTime: new Date().toISOString()
};
localStorage.setItem('currentUser', JSON.stringify(demoUser));
currentUser = demoUser;
} else {
currentUser = JSON.parse(userData);
}
document.getElementById('username-display').textContent = currentUser.username;
document.getElementById('user-menu-name').textContent = currentUser.username;
document.getElementById('user-menu-email').textContent = `${currentUser.username}@windeskos.com`;
// Load user-specific data
loadUserData();
}
// Update time
function updateTime() {
const now = new Date();
document.getElementById('time').textContent = now.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
}
setInterval(updateTime, 1000);
updateTime();
// User menu functions
function showUserMenu() {
const menu = document.getElementById('user-menu');
const isVisible = !menu.classList.contains('hidden');
if (isVisible) {
menu.classList.add('hidden');
menu.classList.remove('scale-100', 'opacity-100');
menu.classList.add('scale-95', 'opacity-0');
menu.style.pointerEvents = 'none';
} else {
menu.classList.remove('hidden');
setTimeout(() => {
menu.classList.remove('scale-95', 'opacity-0');
menu.classList.add('scale-100', 'opacity-100');
menu.style.pointerEvents = 'auto';
}, 10);
}
}
function logout() {
// Save user data before logout
saveUserData();
// Clear current session
localStorage.removeItem('currentUser');
// Redirect to login
window.location.href = 'login.html';
}
function lockSession() {
saveUserData();
window.location.href = 'login.html?locked=true';
}
function showUserSettings() {
alert('User settings would open here');
}
// User data management
function saveUserData() {
if (!currentUser) return;
const userData = {
desktopIconPositions: JSON.parse(localStorage.getItem('desktopIconPositions') || '{}'),
openWindows: windows.map(windowId => {
const window = document.getElementById(windowId);
if (window) {
return {
type: window.getAttribute('data-window-type'),
position: {
left: window.style.left,
top: window.style.top,
width: window.style.width,
height: window.style.height
}
};
}
return null;
}).filter(Boolean),
calculatorState: {
currentInput: currentInput,
previousInput: previousInput,
operation: operation,
shouldResetInput: shouldResetInput
},
lastSaved: new Date().toISOString()
};
localStorage.setItem(`userData_${currentUser.username}`, JSON.stringify(userData));
}
function loadUserData() {
if (!currentUser) return;
const userData = localStorage.getItem(`userData_${currentUser.username}`);
if (userData) {
const data = JSON.parse(userData);
// Load desktop icon positions
if (data.desktopIconPositions) {
Object.keys(data.desktopIconPositions).forEach(iconId => {
const icon = document.getElementById(iconId);
if (icon && data.desktopIconPositions[iconId]) {
icon.style.left = data.desktopIconPositions[iconId].left;
icon.style.top = data.desktopIconPositions[iconId].top;
}
});
}
// Load calculator state
if (data.calculatorState) {
currentInput = data.calculatorState.currentInput || '0';
previousInput = data.calculatorState.previousInput || '0';
operation = data.calculatorState.operation || null;
shouldResetInput = data.calculatorState.shouldResetInput || false;
}
// Open saved windows
if (data.openWindows && data.openWindows.length > 0) {
setTimeout(() => {
data.openWindows.forEach(windowData => {
const windowElement = createWindow(windowData.type);
if (windowElement && windowData.position) {
windowElement.style.left = windowData.position.left;
windowElement.style.top = windowData.position.top;
windowElement.style.width = windowData.position.width;
windowElement.style.height = windowData.position.height;
}
});
}, 500);
}
}
}
// Auto-save user data periodically
setInterval(saveUserData, 30000); // Save every 30 seconds
// Save data before page unload
window.addEventListener('beforeunload', saveUserData);
// Start menu toggle
document.getElementById('start-button').addEventListener('click', function(e) {
e.stopPropagation();
const menu = document.getElementById('start-menu');
const isVisible = !menu.classList.contains('hidden');
if (isVisible) {
menu.classList.add('hidden');
menu.classList.remove('scale-100', 'opacity-100');
menu.classList.add('scale-95', 'opacity-0');
menu.style.pointerEvents = 'none';
} else {
menu.classList.remove('hidden');
setTimeout(() => {
menu.classList.remove('scale-95', 'opacity-0');
menu.classList.add('scale-100', 'opacity-100');
menu.style.pointerEvents = 'auto';
}, 10);
}
});
// Close start menu when clicking elsewhere
document.addEventListener('click', function(e) {
if (!e.target.closest('#start-menu') && !e.target.closest('#start-button')) {
const menu = document.getElementById('start-menu');
menu.classList.add('hidden');
menu.classList.remove('scale-100', 'opacity-100');
menu.classList.add('scale-95', 'opacity-0');
menu.style.pointerEvents = 'none';
}
});
// Context menu
document.getElementById('desktop').addEventListener('contextmenu', function(e) {
e.preventDefault();
const menu = document.getElementById('context-menu');
menu.style.left = e.pageX + 'px';
menu.style.top = e.pageY + 'px';
menu.classList.remove('hidden');
});
document.addEventListener('click', function() {
document.getElementById('context-menu').classList.add('hidden');
});
// Desktop icon dragging functionality
function setupIconDragging() {
const desktopIcons = document.querySelectorAll('.desktop-icon');
let dragTimeout = null;
let lastClickTime = 0;
desktopIcons.forEach(icon => {
let isDragging = false;
let startX, startY, startLeft, startTop;
let clickCount = 0;
icon.addEventListener('mousedown', function(e) {
if (e.button !== 0) return; // Only left click
// Start drag after short delay to distinguish from click
dragTimeout = setTimeout(() => {
isDragging = true;
startX = e.clientX;
startY = e.clientY;
const computedStyle = window.getComputedStyle(icon);
startLeft = parseInt(computedStyle.left) || 0;
startTop = parseInt(computedStyle.top) || 0;
icon.classList.add('dragging');
icon.style.zIndex = '9999';
e.preventDefault();
}, 150); // Reduced delay for faster response
});
document.addEventListener('mousemove', function(e) {
if (!isDragging) return;
clearTimeout(dragTimeout);
const dx = e.clientX - startX;
const dy = e.clientY - startY;
icon.style.left = (startLeft + dx) + 'px';
icon.style.top = (startTop + dy) + 'px';
});
document.addEventListener('mouseup', function() {
clearTimeout(dragTimeout);
if (isDragging) {
isDragging = false;
icon.classList.remove('dragging');
icon.style.zIndex = '';
// Save position to localStorage
const positions = JSON.parse(localStorage.getItem('desktopIconPositions') || '{}');
positions[icon.id] = {
left: icon.style.left,
top: icon.style.top
};
localStorage.setItem('desktopIconPositions', JSON.stringify(positions));
}
});
// Double click to open app
icon.addEventListener('click', function(e) {
clearTimeout(dragTimeout);
if (isDragging) return;
const currentTime = new Date().getTime();
const timeDiff = currentTime - lastClickTime;
if (timeDiff < 300 && timeDiff > 0) { // Double click within 300ms
const appType = icon.getAttribute('data-app');
openWindow(appType);
lastClickTime = 0;
} else {
lastClickTime = currentTime;
}
});
});
}
// Load saved icon positions
function loadIconPositions() {
const positions = JSON.parse(localStorage.getItem('desktopIconPositions') || '{}');
Object.keys(positions).forEach(iconId => {
const icon = document.getElementById(iconId);
if (icon && positions[iconId]) {
icon.style.left = positions[iconId].left;
icon.style.top = positions[iconId].top;
}
});
}
// Window management
function openWindow(type) {
const windowElement = createWindow(type);
}
function createWindow(type) {
const windowId = 'window-' + Date.now();
const windowContent = getWindowContent(type);
const windowElement = document.createElement('div');
windowElement.id = windowId;
windowElement.setAttribute('data-window-type', type);
windowElement.className = 'window bg-gray-800 bg-opacity-95 rounded-lg absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-96 h-64 pointer-events-auto';
windowElement.style.zIndex = zIndexCounter++;
windowElement.innerHTML = `
<div class="flex items-center justify-between p-3 bg-gray-900 rounded-t-lg cursor-move border-b border-gray-700">
<div class="flex items-center space-x-2">
<i data-feather="${windowContent.icon}" class="w-4 h-4 ${windowContent.iconColor}"></i>
<span>${windowContent.title}</span>
</div>
<div class="flex space-x-1">
<button class="w-6 h-6 rounded hover:bg-gray-700 flex items-center justify-center">–</button>
<button class="w-6 h-6 rounded hover:bg-gray-700 flex items-center justify-center">□</button>
<button class="w-6 h-6 rounded hover:bg-red-600 flex items-center justify-center" onclick="closeWindow('${windowId}')">×</button>
</div>
</div>
<div class="p-4 h-[calc(100%-3rem)]">
${windowContent.content}
</div>
`;
document.getElementById('windows-container').appendChild(windowElement);
feather.replace();
// Make window draggable
makeDraggable(windowElement);
windows.push(windowId);
return windowElement;
}
function closeWindow(id) {
const window = document.getElementById(id);
if (window) {
window.remove();
windows = windows.filter(winId => winId !== id);
}
}
function makeDraggable(element) {
const header = element.querySelector('.bg-gray-900');
let isDragging = false;
let isResizing = false;
let resizeDirection = '';
let startX, startY, startLeft, startTop, startWidth, startHeight;
// Add resize handles
const resizeHandles = ['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'];
resizeHandles.forEach(dir => {
const handle = document.createElement('div');
handle.className = `resize-handle resize-${dir}`;
handle.style.cssText = `
position: absolute;
background: transparent;
z-index: 10;
`;
// Position and size based on direction
switch(dir) {
case 'n': handle.style.top = '0'; handle.style.left = '10px'; handle.style.right = '10px'; handle.style.height = '4px'; handle.style.cursor = 'ns-resize'; break;
case 'ne': handle.style.top = '0'; handle.style.right = '0'; handle.style.width = '6px'; handle.style.height = '6px'; handle.style.cursor = 'nesw-resize'; break;
case 'e': handle.style.top = '10px'; handle.style.right = '0'; handle.style.width = '4px'; handle.style.bottom = '10px'; handle.style.cursor = 'ew-resize'; break;
case 'se': handle.style.bottom = '0'; handle.style.right = '0'; handle.style.width = '6px'; handle.style.height = '6px'; handle.style.cursor = 'nwse-resize'; break;
case 's': handle.style.bottom = '0'; handle.style.left = '10px'; handle.style.right = '10px'; handle.style.height = '4px'; handle.style.cursor = 'ns-resize'; break;
case 'sw': handle.style.bottom = '0'; handle.style.left = '0'; handle.style.width = '6px'; handle.style.height = '6px'; handle.style.cursor = 'nesw-resize'; break;
case 'w': handle.style.top = '10px'; handle.style.left = '0'; handle.style.width = '4px'; handle.style.bottom = '10px'; handle.style.cursor = 'ew-resize'; break;
case 'nw': handle.style.top = '0'; handle.style.left = '0'; handle.style.width = '6px'; handle.style.height = '6px'; handle.style.cursor = 'nwse-resize'; break;
}
handle.addEventListener('mousedown', function(e) {
e.stopPropagation();
isResizing = true;
resizeDirection = dir;
startX = e.clientX;
startY = e.clientY;
startWidth = element.offsetWidth;
startHeight = element.offsetHeight;
startLeft = parseInt(element.style.left) || (window.innerWidth/2 - startWidth/2);
startTop = parseInt(element.style.top) || (window.innerHeight/2 - startHeight/2);
// Bring to front
element.style.zIndex = zIndexCounter++;
});
element.appendChild(handle);
});
header.addEventListener('mousedown', function(e) {
isDragging = true;
startX = e.clientX;
startY = e.clientY;
// Get current position from computed style
const computedStyle = window.getComputedStyle(element);
startLeft = parseInt(computedStyle.left) || (window.innerWidth/2 - element.offsetWidth/2);
startTop = parseInt(computedStyle.top) || (window.innerHeight/2 - element.offsetHeight/2);
// Bring to front
element.style.zIndex = zIndexCounter++;
element.style.left = startLeft + 'px';
element.style.top = startTop + 'px';
});
document.addEventListener('mousemove', function(e) {
if (isDragging) {
const dx = e.clientX - startX;
const dy = e.clientY - startY;
element.style.left = (startLeft + dx) + 'px';
element.style.top = (startTop + dy) + 'px';
}
if (isResizing) {
const dx = e.clientX - startX;
const dy = e.clientY - startY;
let newWidth = startWidth;
let newHeight = startHeight;
let newLeft = startLeft;
let newTop = startTop;
switch(resizeDirection) {
case 'e':
newWidth = Math.max(200, startWidth + dx);
break;
case 'w':
newWidth = Math.max(200, startWidth - dx);
newLeft = startLeft + dx;
break;
case 's':
newHeight = Math.max(150, startHeight + dy);
break;
case 'n':
newHeight = Math.max(150, startHeight - dy);
newTop = startTop + dy;
break;
case 'se':
newWidth = Math.max(200, startWidth + dx);
newHeight = Math.max(150, startHeight + dy);
break;
case 'sw':
newWidth = Math.max(200, startWidth - dx);
newHeight = Math.max(150, startHeight + dy);
newLeft = startLeft + dx;
break;
case 'ne':
newWidth = Math.max(200, startWidth + dx);
newHeight = Math.max(150, startHeight - dy);
newTop = startTop + dy;
break;
case 'nw':
newWidth = Math.max(200, startWidth - dx);
newHeight = Math.max(150, startHeight - dy);
newLeft = startLeft + dx;
newTop = startTop + dy;
break;
}
element.style.width = newWidth + 'px';
element.style.height = newHeight + 'px';
element.style.left = newLeft + 'px';
element.style.top = newTop + 'px';
}
});
document.addEventListener('mouseup', function() {
isDragging = false;
isResizing = false;
});
}
function getWindowContent(type) {
const contents = {
'browser': {
icon: 'globe',
iconColor: 'text-blue-400',
title: 'Browser',
content: '<div class="h-full flex items-center justify-center"><p class="text-gray-400">Browser content would go here</p></div>'
},
'explorer': {
icon: 'folder',
iconColor: 'text-yellow-400',
title: 'File Explorer',
content: '<div class="h-full flex items-center justify-center"><p class="text-gray-400">File Explorer content would go here</p></div>'
},
'settings': {
icon: 'settings',
iconColor: 'text-gray-400',
title: 'Settings',
content: '<div class="h-full flex items-center justify-center"><p class="text-gray-400">Settings content would go here</p></div>'
},
'notepad': {
icon: 'edit',
iconColor: 'text-green-400',
title: 'Notepad',
content: '<textarea class="w-full h-full bg-gray-700 text-white p-2 rounded resize-none" placeholder="Start typing..."></textarea>'
},
'calculator': {
icon: 'calculator',
iconColor: 'text-purple-400',
title: 'Calculator',
content: document.getElementById('calculator-template').innerHTML
},
'weather': {
icon: 'cloud',
iconColor: 'text-blue-400',
title: 'Weather',
content: document.getElementById('weather-template').innerHTML
},
'calendar': {
icon: 'calendar',
iconColor: 'text-red-400',
title: 'Calendar',
content: '<div class="h-full flex items-center justify-center"><p class="text-gray-400">Calendar content would go here</p></div>'
},
'documents': {
icon: 'folder',
iconColor: 'text-yellow-400',
title: 'Documents',
content: '<div class="h-full flex items-center justify-center"><p class="text-gray-400">Documents folder content</p></div>'
},
'pictures': {
icon: 'image',
iconColor: 'text-green-400',
title: 'Pictures',
content: '<div class="h-full flex items-center justify-center"><p class="text-gray-400">Pictures folder content</p></div>'
},
'recycle-bin': {
icon: 'trash-2',
iconColor: 'text-blue-400',
title: 'Recycle Bin',
content: '<div class="h-full flex items-center justify-center"><p class="text-gray-400">Recycle Bin is empty</p></div>'
}
};
return contents[type] || contents['browser'];
}
// Calculator functionality
let currentInput = '0';
let previousInput = '0';
let operation = null;
let shouldResetInput = false;
function calcInput(value) {
if (currentInput === '0' || shouldResetInput) {
currentInput = value;
shouldResetInput = false;
} else {
currentInput += value;
}
updateCalcDisplay();
}
function calcOperation(op) {
if (operation !== null) calcCalculate();
previousInput = currentInput;
operation = op;
shouldResetInput = true;
}
function calcCalculate() {
let result;
const prev = parseFloat(previousInput);
const current = parseFloat(currentInput);
if (isNaN(prev) || isNaN(current)) return;
switch(operation) {
case '+': result = prev + current; break;
case '-': result = prev - current; break;
case '*': result = prev * current; break;
case '/': result = prev / current; break;
case '%': result = prev % current; break;
default: return;
}
currentInput = result.toString();
operation = null;
shouldResetInput = true;
updateCalcDisplay();
}
function calcClear() {
currentInput = '0';
previousInput = '0';
operation = null;
shouldResetInput = false;
updateCalcDisplay();
}
function calcBackspace() {
currentInput = currentInput.slice(0, -1);
if (currentInput === '') currentInput = '0';
updateCalcDisplay();
}
function updateCalcDisplay() {
const display = document.getElementById('calc-display');
if (display) display.textContent = currentInput;
}
// Weather functionality
async function fetchWeather() {
try {
const response = await fetch('https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&current=temperature_2m,weather_code');
const data = await response.json();
const tempElement = document.getElementById('weather-temp');
const descElement = document.getElementById('weather-desc');
const locationElement = document.getElementById('weather-location');
if (tempElement) tempElement.textContent = `${data.current.temperature_2m}°C`;
if (descElement) descElement.textContent = getWeatherDescription(data.current.weather_code);
if (locationElement) locationElement.textContent = 'Berlin, Germany';
} catch (error) {
console.error('Error fetching weather:', error);
}
}
function getWeatherDescription(code) {
const weatherCodes = {
0: 'Clear sky',
1: 'Mainly clear',
2: 'Partly cloudy',
3: 'Overcast',
45: 'Fog',
48: 'Depositing rime fog',
51: 'Light drizzle',
53: 'Moderate drizzle',
55: 'Dense drizzle',
61: 'Slight rain',
63: 'Moderate rain',
65: 'Heavy rain',
80: 'Slight rain showers',
81: 'Moderate rain showers',
82: 'Violent rain showers'
};
return weatherCodes[code] || 'Unknown weather';
}
// System tray functionality
function toggleVolume() {
alert('Volume control would open here');
}
function toggleWiFiMenu() {
alert('Wi-Fi settings would open here');
}
function toggleBatteryInfo() {
alert('Battery information would show here');
}
function showNotificationCenter() {
const center = document.getElementById('notification-center');
center.classList.remove('hidden');
setTimeout(() => {
center.classList.remove('scale-95', 'opacity-0');
center.classList.add('scale-100', 'opacity-100');
center.style.pointerEvents = 'auto';
}, 10);
}
function hideNotificationCenter() {
const center = document.getElementById('notification-center');
center.classList.add('hidden');
center.classList.remove('scale-100', 'opacity-100');
center.classList.add('scale-95', 'opacity-0');
center.style.pointerEvents = 'none';
}
function toggleDarkMode() {
document.body.classList.toggle('bg-gray-900');
document.body.classList.toggle('bg-gray-100');
document.body.classList.toggle('text-white');
document.body.classList.toggle('text-gray-900');
}
function toggleWiFi() {
const wifiIcon = document.getElementById('wifi-icon');
const isConnected = wifiIcon.getAttribute('data-feather') === 'wifi';
feather.replace({
'wifi-icon': isConnected ? 'wifi-off' : 'wifi'
});
}
// Initialize feather icons and handle drag prevention
feather.replace();
// Prevent drag on icons
document.querySelectorAll('.desktop-icon i, .taskbar-item i').forEach(icon => {
icon.addEventListener('mousedown', function(e) {
e.stopPropagation();
});
});
// Setup icon dragging and load positions
setupIconDragging();
loadIconPositions();
// Initial weather fetch
setTimeout(fetchWeather, 1000);
// Initialize authentication check
checkAuthentication();
</script>
</body>
</html>