| <!DOCTYPE html> |
| <html lang="fr"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>ÆOS - Système d'exploitation minimaliste</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <style> |
| @keyframes boot-animation { |
| 0% { opacity: 0; } |
| 100% { opacity: 1; } |
| } |
| .boot-screen { |
| animation: boot-animation 1.5s ease-out; |
| } |
| .window { |
| box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); |
| } |
| .title-bar { |
| user-select: none; |
| } |
| .cursor-blink { |
| animation: cursor-blink 1s infinite; |
| } |
| @keyframes cursor-blink { |
| 0%, 100% { opacity: 1; } |
| 50% { opacity: 0; } |
| } |
| </style> |
| </head> |
| <body class="bg-gray-100 h-screen overflow-hidden font-mono"> |
| |
| <div id="boot-screen" class="boot-screen fixed inset-0 bg-black text-white flex flex-col items-center justify-center z-50"> |
| <div class="text-4xl mb-8">ÆOS</div> |
| <div class="text-sm text-gray-400">© Æ Corporation - Développé par Abiye Enzo</div> |
| <div class="w-64 h-1 bg-gray-700 rounded-full overflow-hidden"> |
| <div id="boot-progress" class="h-full bg-blue-500 rounded-full" style="width: 0%"></div> |
| </div> |
| <div class="mt-4 text-gray-400">Chargement du système...</div> |
| </div> |
|
|
| |
| <div id="desktop" class="hidden h-full flex flex-col"> |
| |
| <div class="bg-gray-800 text-white p-2 flex justify-between items-center"> |
| <div class="flex items-center"> |
| <button id="menu-btn" class="px-3 py-1 bg-gray-700 hover:bg-gray-600 rounded mr-2"> |
| ☰ Menu |
| </button> |
| <button id="new-file-btn" class="px-3 py-1 bg-blue-600 hover:bg-blue-700 rounded mr-2"> |
| Éditeur |
| </button> |
| <button id="terminal-btn" class="px-3 py-1 bg-purple-600 hover:bg-purple-700 rounded mr-2"> |
| Terminal |
| </button> |
| <button id="calculator-btn" class="px-3 py-1 bg-green-600 hover:bg-green-700 rounded mr-2"> |
| Calculatrice |
| </button> |
| <button id="game-btn" class="px-3 py-1 bg-red-600 hover:bg-red-700 rounded mr-2"> |
| Snake Game |
| </button> |
| <div id="clock" class="px-3 py-1 bg-gray-700 rounded">00:00:00</div> |
| </div> |
| <div class="text-sm">ÆOS v1.0</div> |
| </div> |
|
|
| |
| <div id="editor-window" class="window hidden absolute top-10 left-10 w-3/4 h-3/4 flex flex-col bg-white rounded-lg overflow-hidden border border-gray-300"> |
| <div class="title-bar bg-gray-800 text-white p-2 flex justify-between items-center cursor-move"> |
| <div class="flex items-center"> |
| <span class="ml-2">Éditeur de texte</span> |
| </div> |
| <div> |
| <button class="window-control px-3 py-1 hover:bg-gray-700">_</button> |
| <button class="window-control px-3 py-1 hover:bg-gray-700">□</button> |
| <button id="close-editor" class="window-control px-3 py-1 hover:bg-red-600">×</button> |
| </div> |
| </div> |
| <div class="flex-1 flex flex-col"> |
| <div class="toolbar bg-gray-100 p-2 flex space-x-2 border-b"> |
| <button id="save-btn" class="px-3 py-1 bg-green-600 text-white rounded hover:bg-green-700">Enregistrer</button> |
| <button id="open-btn" class="px-3 py-1 bg-blue-600 text-white rounded hover:bg-blue-700">Ouvrir</button> |
| <input type="file" id="file-input" class="hidden" accept=".txt"> |
| </div> |
| <div class="flex-1 relative"> |
| <textarea id="text-editor" class="w-full h-full p-4 outline-none resize-none" spellcheck="false"></textarea> |
| <div id="status-bar" class="absolute bottom-0 left-0 right-0 bg-gray-100 p-1 text-sm text-gray-600 border-t"> |
| Ligne 1, Colonne 1 | UTF-8 |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="calculator-window" class="window hidden absolute top-30 left-30 w-64 h-auto flex flex-col bg-gray-100 rounded-lg overflow-hidden border border-gray-300"> |
| <div class="title-bar bg-gray-800 text-white p-2 flex justify-between items-center cursor-move"> |
| <div class="flex items-center"> |
| <span class="ml-2">Calculatrice</span> |
| </div> |
| <div> |
| <button class="window-control px-3 py-1 hover:bg-gray-700">_</button> |
| <button class="window-control px-3 py-1 hover:bg-gray-700">□</button> |
| <button id="close-calculator" class="window-control px-3 py-1 hover:bg-red-600">×</button> |
| </div> |
| </div> |
| <div class="p-4"> |
| <input type="text" id="calc-display" class="w-full p-2 mb-2 text-right bg-white border border-gray-300 rounded" readonly> |
| <div class="grid grid-cols-4 gap-2"> |
| <button class="calc-btn p-2 bg-gray-200 hover:bg-gray-300 rounded">7</button> |
| <button class="calc-btn p-2 bg-gray-200 hover:bg-gray-300 rounded">8</button> |
| <button class="calc-btn p-2 bg-gray-200 hover:bg-gray-300 rounded">9</button> |
| <button class="calc-btn p-2 bg-blue-200 hover:bg-blue-300 rounded">/</button> |
| <button class="calc-btn p-2 bg-gray-200 hover:bg-gray-300 rounded">4</button> |
| <button class="calc-btn p-2 bg-gray-200 hover:bg-gray-300 rounded">5</button> |
| <button class="calc-btn p-2 bg-gray-200 hover:bg-gray-300 rounded">6</button> |
| <button class="calc-btn p-2 bg-blue-200 hover:bg-blue-300 rounded">*</button> |
| <button class="calc-btn p-2 bg-gray-200 hover:bg-gray-300 rounded">1</button> |
| <button class="calc-btn p-2 bg-gray-200 hover:bg-gray-300 rounded">2</button> |
| <button class="calc-btn p-2 bg-gray-200 hover:bg-gray-300 rounded">3</button> |
| <button class="calc-btn p-2 bg-blue-200 hover:bg-blue-300 rounded">-</button> |
| <button class="calc-btn p-2 bg-gray-200 hover:bg-gray-300 rounded">0</button> |
| <button class="calc-btn p-2 bg-gray-200 hover:bg-gray-300 rounded">.</button> |
| <button class="calc-btn p-2 bg-green-200 hover:bg-green-300 rounded">=</button> |
| <button class="calc-btn p-2 bg-blue-200 hover:bg-blue-300 rounded">+</button> |
| <button class="calc-btn p-2 bg-red-200 hover:bg-red-300 rounded col-span-2">C</button> |
| <button class="calc-btn p-2 bg-red-200 hover:bg-red-300 rounded col-span-2">CE</button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="menu-window" class="window hidden absolute top-20 left-20 w-64 h-auto flex flex-col bg-white rounded-lg overflow-hidden border border-gray-300"> |
| <div class="title-bar bg-gray-800 text-white p-2 flex justify-between items-center cursor-move"> |
| <div class="flex items-center"> |
| <span class="ml-2">Menu</span> |
| </div> |
| <div> |
| <button class="window-control px-3 py-1 hover:bg-gray-700">_</button> |
| <button class="window-control px-3 py-1 hover:bg-gray-700">□</button> |
| <button id="close-menu" class="window-control px-3 py-1 hover:bg-red-600">×</button> |
| </div> |
| </div> |
| <div class="p-2"> |
| <button class="menu-item w-full p-2 text-left hover:bg-gray-100 rounded flex items-center" onclick="openEditor()"> |
| <span class="mr-2">📝</span> Éditeur de texte |
| </button> |
| <button class="menu-item w-full p-2 text-left hover:bg-gray-100 rounded flex items-center" onclick="openTerminal()"> |
| <span class="mr-2">💻</span> Terminal |
| </button> |
| <button class="menu-item w-full p-2 text-left hover:bg-gray-100 rounded flex items-center" onclick="openCalculator()"> |
| <span class="mr-2">🧮</span> Calculatrice |
| </button> |
| <button class="menu-item w-full p-2 text-left hover:bg-gray-100 rounded flex items-center" onclick="openGame()"> |
| <span class="mr-2">🐍</span> Snake Game |
| </button> |
| <div class="border-t my-1"></div> |
| <button id="settings-btn" class="menu-item w-full p-2 text-left hover:bg-gray-100 rounded flex items-center"> |
| <span class="mr-2">⚙️</span> Paramètres |
| </button> |
| <button class="menu-item w-full p-2 text-left hover:bg-gray-100 rounded flex items-center" onclick="addTerminalLine('ÆOS v1.0 - Développé par Abiye Enzo')"> |
| <span class="mr-2">ℹ️</span> À propos |
| </button> |
| <div class="border-t my-1"></div> |
| <button class="menu-item w-full p-2 text-left hover:bg-gray-100 rounded flex items-center" onclick="document.getElementById('menu-window').classList.add('hidden')"> |
| <span class="mr-2">🚪</span> Fermer |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div id="settings-window" class="window hidden absolute top-30 left-30 w-96 h-64 flex flex-col bg-white rounded-lg overflow-hidden border border-gray-300"> |
| <div class="title-bar bg-gray-800 text-white p-2 flex justify-between items-center cursor-move"> |
| <div class="flex items-center"> |
| <span class="ml-2">Paramètres</span> |
| </div> |
| <div> |
| <button class="window-control px-3 py-1 hover:bg-gray-700">_</button> |
| <button class="window-control px-3 py-1 hover:bg-gray-700">□</button> |
| <button id="close-settings" class="window-control px-3 py-1 hover:bg-red-600">×</button> |
| </div> |
| </div> |
| <div class="p-4"> |
| <div class="mb-4"> |
| <label class="block text-sm font-medium mb-1">Thème</label> |
| <select class="w-full p-2 border rounded"> |
| <option>Clair</option> |
| <option>Sombre</option> |
| </select> |
| </div> |
| <div class="mb-4"> |
| <label class="block text-sm font-medium mb-1">Langue</label> |
| <select class="w-full p-2 border rounded"> |
| <option>Français</option> |
| <option>English</option> |
| </select> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="game-window" class="window hidden absolute top-30 left-30 w-96 h-96 flex flex-col bg-gray-900 rounded-lg overflow-hidden border border-gray-700"> |
| <div class="title-bar bg-gray-800 text-white p-2 flex justify-between items-center cursor-move"> |
| <div class="flex items-center"> |
| <span class="ml-2">Snake Game</span> |
| </div> |
| <div> |
| <button class="window-control px-3 py-1 hover:bg-gray-700">_</button> |
| <button class="window-control px-3 py-1 hover:bg-gray-700">□</button> |
| <button id="close-game" class="window-control px-3 py-1 hover:bg-red-600">×</button> |
| </div> |
| </div> |
| <div class="flex-1 flex flex-col items-center justify-center p-4"> |
| <canvas id="game-canvas" width="300" height="300" class="bg-black"></canvas> |
| <div class="mt-4 text-white"> |
| Score: <span id="game-score">0</span> |
| </div> |
| <button id="restart-game" class="mt-4 px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700"> |
| Nouvelle partie |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div id="terminal-window" class="window hidden absolute top-20 left-20 w-3/4 h-3/4 flex flex-col bg-black text-green-400 rounded-lg overflow-hidden border border-gray-700"> |
| <div class="title-bar bg-gray-800 text-white p-2 flex justify-between items-center cursor-move"> |
| <div class="flex items-center"> |
| <span class="ml-2">Terminal</span> |
| </div> |
| <div> |
| <button class="window-control px-3 py-1 hover:bg-gray-700">_</button> |
| <button class="window-control px-3 py-1 hover:bg-gray-700">□</button> |
| <button id="close-terminal" class="window-control px-3 py-1 hover:bg-red-600">×</button> |
| </div> |
| </div> |
| <div class="flex-1 p-4 overflow-auto font-mono" id="terminal-output"> |
| <div class="text-center mb-2"> |
| <div class="text-2xl text-green-400">Bienvenue sur ÆOS Terminal</div> |
| <div class="text-sm text-gray-500">v1.0 - Tapez 'help' pour la liste des commandes</div> |
| </div> |
| <div class="border-t border-gray-700 my-2"></div> |
| <div class="mt-2"> |
| <span class="text-green-500">┌──(</span> |
| <span class="text-yellow-400">user@ÆOS</span> |
| <span class="text-green-500">)-[</span> |
| <span class="text-blue-400">~</span> |
| <span class="text-green-500">]</span> |
| <br> |
| <span class="text-green-500">└─$</span> |
| <span id="command-line" class="inline-flex items-center"> |
| <span id="command-input" contenteditable="true"></span> |
| <span class="cursor-blink">|</span> |
| </span> |
| </div> |
| </div> |
| </div> |
|
|
| </div> |
|
|
| <script> |
| |
| document.addEventListener('DOMContentLoaded', () => { |
| const bootScreen = document.getElementById('boot-screen'); |
| const bootProgress = document.getElementById('boot-progress'); |
| const desktop = document.getElementById('desktop'); |
| |
| let progress = 0; |
| const bootInterval = setInterval(() => { |
| progress += Math.random() * 10; |
| if (progress > 100) progress = 100; |
| bootProgress.style.width = `${progress}%`; |
| |
| if (progress >= 100) { |
| clearInterval(bootInterval); |
| setTimeout(() => { |
| bootScreen.classList.add('hidden'); |
| desktop.classList.remove('hidden'); |
| updateClock(); |
| setInterval(updateClock, 1000); |
| setupTerminal(); |
| }, 500); |
| } |
| }, 150); |
| }); |
| |
| |
| function updateClock() { |
| const now = new Date(); |
| const timeString = now.toLocaleTimeString(); |
| document.getElementById('clock').textContent = timeString; |
| } |
| |
| |
| const terminalCommands = { |
| help: () => ` |
| Commandes disponibles: |
| |
| help - Affiche cette aide |
| clear - Efface l'écran du terminal |
| about - Affiche les informations sur ÆOS |
| echo [text] - Affiche le texte spécifié |
| ls - Liste les commandes disponibles |
| date - Affiche la date et l'heure actuelles |
| calc [expr] - Évalue une expression mathématique |
| shutdown - Ferme la fenêtre du terminal |
| sysinfo - Affiche les informations système |
| neofetch - Affiche le logo et informations système |
| whoami - Affiche le nom d'utilisateur actuel |
| pwd - Affiche le répertoire courant |
| history - Affiche les 10 dernières commandes |
| color [c] - Change la couleur du texte (rouge, vert, bleu, jaune, violet) |
| theme [t] - Change le thème du terminal (dark/light) |
| |
| Pour plus d'informations sur une commande, essayez 'help [commande]' |
| `, |
| clear: () => { terminalOutput.innerHTML = ''; return ""; }, |
| about: () => "ÆOS v1.0\nSystème d'exploitation minimaliste\n© Æ Corporation", |
| echo: (args) => args.join(" "), |
| date: () => new Date().toLocaleString('fr-FR'), |
| ls: () => Object.keys(terminalCommands).join(" "), |
| calc: (args) => { |
| try { |
| return eval(args.join(" ")); |
| } catch { |
| return "Erreur: Expression invalide"; |
| } |
| }, |
| shutdown: () => { |
| document.getElementById('terminal-window').classList.add('hidden'); |
| return "Terminal fermé"; |
| }, |
| sysinfo: () => `Système: ÆOS v1.0\nCPU: Virtual CPU @ 2.4GHz\nMémoire: 1024MB\nDisque: 10GB\nRéseau: eth0 (192.168.1.100)`, |
| neofetch: () => { |
| const art = ` |
| _____ ______ |
| / _ \\ / __ \\ |
| / /_\\ \\| | | | |
| / | \\ | | | |
| \\____|__ /__|__|__| |
| \\/ |
| `; |
| return art + "\nÆOS v1.0\nDéveloppé par Abiye Enzo"; |
| }, |
| whoami: () => "user", |
| pwd: () => "/home/user", |
| history: () => commandHistory.slice(0, 10).join("\n"), |
| color: (args) => { |
| const colors = { |
| 'rouge': 'text-red-400', |
| 'vert': 'text-green-400', |
| 'bleu': 'text-blue-400', |
| 'jaune': 'text-yellow-400', |
| 'violet': 'text-purple-400' |
| }; |
| const color = args[0]; |
| if (color in colors) { |
| document.getElementById('terminal-output').className = `flex-1 p-4 overflow-auto font-mono ${colors[color]}`; |
| return `Couleur changée en ${color}`; |
| } |
| return "Couleurs disponibles: rouge, vert, bleu, jaune, violet"; |
| }, |
| theme: (args) => { |
| const theme = args[0]; |
| if (theme === 'dark') { |
| document.getElementById('terminal-window').className = 'window hidden absolute top-20 left-20 w-3/4 h-3/4 flex flex-col bg-black text-green-400 rounded-lg overflow-hidden border border-gray-700'; |
| return "Thème changé en sombre"; |
| } else if (theme === 'light') { |
| document.getElementById('terminal-window').className = 'window hidden absolute top-20 left-20 w-3/4 h-3/4 flex flex-col bg-gray-100 text-gray-800 rounded-lg overflow-hidden border border-gray-300'; |
| return "Thème changé en clair"; |
| } |
| return "Utilisation: theme [dark/light]"; |
| } |
| }; |
| |
| function processCommand(command) { |
| const parts = command.trim().split(/\s+/); |
| const cmd = parts[0].toLowerCase(); |
| const args = parts.slice(1); |
| |
| if (cmd === '') return ""; |
| |
| if (cmd in terminalCommands) { |
| const result = terminalCommands[cmd](args); |
| if (result === undefined) return ""; |
| if (typeof result === 'string') { |
| return result.split('\n').map(line => line.trim()).join('\n'); |
| } |
| return String(result); |
| } |
| return `Commande inconnue: ${cmd}\nTapez 'help' pour la liste des commandes`; |
| } |
| |
| const terminalOutput = document.getElementById('terminal-output'); |
| |
| function addTerminalLine(text) { |
| const line = document.createElement('div'); |
| line.textContent = text; |
| terminalOutput.appendChild(line); |
| terminalOutput.scrollTop = terminalOutput.scrollHeight; |
| } |
| |
| function setupTerminal() { |
| let currentCommand = ''; |
| let commandHistory = []; |
| let historyIndex = -1; |
| |
| function addPrompt() { |
| const prompt = document.createElement('div'); |
| prompt.innerHTML = ` |
| <span class="text-green-500">┌──(</span> |
| <span class="text-yellow-400">user@ÆOS</span> |
| <span class="text-green-500">)-[</span> |
| <span class="text-blue-400">~</span> |
| <span class="text-green-500">]</span> |
| <br> |
| <span class="text-green-500">└─$</span> |
| <span id="command-input" contenteditable="true" class="inline-block min-w-[1px]"></span> |
| <span class="cursor-blink">|</span> |
| `; |
| terminalOutput.appendChild(prompt); |
| return prompt.querySelector('#command-input'); |
| } |
| |
| function processCommand(cmd) { |
| if (!cmd) return; |
| |
| |
| commandHistory.unshift(cmd); |
| if (commandHistory.length > 20) commandHistory.pop(); |
| |
| |
| const result = terminalCommands[cmd] ? terminalCommands[cmd]() : `Commande inconnue: ${cmd}`; |
| |
| |
| if (result) { |
| const resultDiv = document.createElement('div'); |
| resultDiv.textContent = result; |
| terminalOutput.appendChild(resultDiv); |
| } |
| } |
| |
| let currentInput = addPrompt(); |
| currentInput.focus(); |
| |
| terminalOutput.addEventListener('keydown', (e) => { |
| if (e.target.id !== 'command-input') return; |
| |
| if (e.key === 'Enter') { |
| e.preventDefault(); |
| const cmd = currentInput.textContent.trim(); |
| |
| |
| const cmdDisplay = document.createElement('div'); |
| cmdDisplay.innerHTML = ` |
| <span class="text-green-500">┌──(</span> |
| <span class="text-yellow-400">user@ÆOS</span> |
| <span class="text-green-500">)-[</span> |
| <span class="text-blue-400">~</span> |
| <span class="text-green-500">]</span> |
| <br> |
| <span class="text-green-500">└─$</span> ${cmd} |
| `; |
| terminalOutput.appendChild(cmdDisplay); |
| |
| processCommand(cmd); |
| |
| |
| currentInput = addPrompt(); |
| currentInput.focus(); |
| historyIndex = -1; |
| |
| |
| terminalOutput.scrollTop = terminalOutput.scrollHeight; |
| } |
| else if (e.key === 'ArrowUp') { |
| e.preventDefault(); |
| if (historyIndex < commandHistory.length - 1) { |
| historyIndex++; |
| currentInput.textContent = commandHistory[historyIndex]; |
| placeCaretAtEnd(currentInput); |
| } |
| } |
| else if (e.key === 'ArrowDown') { |
| e.preventDefault(); |
| if (historyIndex > 0) { |
| historyIndex--; |
| currentInput.textContent = commandHistory[historyIndex]; |
| placeCaretAtEnd(currentInput); |
| } else if (historyIndex === 0) { |
| historyIndex = -1; |
| currentInput.textContent = ''; |
| } |
| } |
| }); |
| } |
| |
| function placeCaretAtEnd(el) { |
| el.focus(); |
| const range = document.createRange(); |
| range.selectNodeContents(el); |
| range.collapse(false); |
| const sel = window.getSelection(); |
| sel.removeAllRanges(); |
| sel.addRange(range); |
| } |
| |
| |
| document.getElementById('terminal-btn').addEventListener('click', () => { |
| openTerminal(); |
| }); |
| |
| document.getElementById('close-terminal').addEventListener('click', () => { |
| document.getElementById('terminal-window').classList.add('hidden'); |
| }); |
| |
| function openTerminal() { |
| const terminalWindow = document.getElementById('terminal-window'); |
| terminalWindow.classList.remove('hidden'); |
| commandInput.focus(); |
| |
| |
| const maxX = window.innerWidth - terminalWindow.offsetWidth; |
| const maxY = window.innerHeight - terminalWindow.offsetHeight; |
| const randomX = Math.floor(Math.random() * maxX * 0.5); |
| const randomY = Math.floor(Math.random() * maxY * 0.5); |
| |
| terminalWindow.style.left = `${randomX}px`; |
| terminalWindow.style.top = `${randomY}px`; |
| |
| makeDraggable(terminalWindow); |
| } |
| |
| document.getElementById('new-file-btn').addEventListener('click', openEditor); |
| |
| document.getElementById('close-editor').addEventListener('click', () => { |
| document.getElementById('editor-window').classList.add('hidden'); |
| }); |
| |
| function openEditor() { |
| const editorWindow = document.getElementById('editor-window'); |
| editorWindow.classList.remove('hidden'); |
| document.getElementById('home-screen').classList.add('hidden'); |
| document.getElementById('text-editor').focus(); |
| |
| |
| const maxX = window.innerWidth - editorWindow.offsetWidth; |
| const maxY = window.innerHeight - editorWindow.offsetHeight; |
| const randomX = Math.floor(Math.random() * maxX * 0.5); |
| const randomY = Math.floor(Math.random() * maxY * 0.5); |
| |
| editorWindow.style.left = `${randomX}px`; |
| editorWindow.style.top = `${randomY}px`; |
| |
| makeDraggable(editorWindow); |
| } |
| |
| |
| function makeDraggable(element) { |
| const titleBar = element.querySelector('.title-bar'); |
| let isDragging = false; |
| let offsetX, offsetY; |
| |
| titleBar.addEventListener('mousedown', (e) => { |
| isDragging = true; |
| offsetX = e.clientX - element.getBoundingClientRect().left; |
| offsetY = e.clientY - element.getBoundingClientRect().top; |
| element.style.cursor = 'grabbing'; |
| }); |
| |
| document.addEventListener('mousemove', (e) => { |
| if (!isDragging) return; |
| |
| const x = e.clientX - offsetX; |
| const y = e.clientY - offsetY; |
| |
| |
| const maxX = window.innerWidth - element.offsetWidth; |
| const maxY = window.innerHeight - element.offsetHeight; |
| |
| element.style.left = `${Math.max(0, Math.min(x, maxX))}px`; |
| element.style.top = `${Math.max(0, Math.min(y, maxY))}px`; |
| }); |
| |
| document.addEventListener('mouseup', () => { |
| isDragging = false; |
| element.style.cursor = ''; |
| }); |
| } |
| |
| |
| document.querySelectorAll('.window-control').forEach(btn => { |
| btn.addEventListener('click', function() { |
| const editorWindow = document.getElementById('editor-window'); |
| if (this.textContent === '_') { |
| |
| editorWindow.classList.add('hidden'); |
| } else if (this.textContent === '×') { |
| |
| editorWindow.classList.add('hidden'); |
| document.getElementById('home-screen').classList.remove('hidden'); |
| } else if (this.textContent === '□') { |
| |
| if (editorWindow.classList.contains('maximized')) { |
| editorWindow.classList.remove('maximized'); |
| editorWindow.style.width = '75%'; |
| editorWindow.style.height = '75%'; |
| editorWindow.style.left = '10%'; |
| editorWindow.style.top = '10%'; |
| } else { |
| editorWindow.classList.add('maximized'); |
| editorWindow.style.width = '100%'; |
| editorWindow.style.height = 'calc(100% - 40px)'; |
| editorWindow.style.left = '0'; |
| editorWindow.style.top = '0'; |
| } |
| } |
| }); |
| }); |
| |
| |
| const textEditor = document.getElementById('text-editor'); |
| const statusBar = document.getElementById('status-bar'); |
| |
| textEditor.addEventListener('input', updateCursorPosition); |
| textEditor.addEventListener('click', updateCursorPosition); |
| textEditor.addEventListener('keyup', updateCursorPosition); |
| |
| function updateCursorPosition() { |
| const text = textEditor.value; |
| const cursorPos = textEditor.selectionStart; |
| |
| let line = 1; |
| let column = 1; |
| |
| for (let i = 0; i < cursorPos; i++) { |
| if (text[i] === '\n') { |
| line++; |
| column = 1; |
| } else { |
| column++; |
| } |
| } |
| |
| statusBar.textContent = `Ligne ${line}, Colonne ${column} | UTF-8`; |
| } |
| |
| |
| document.getElementById('menu-btn').addEventListener('click', openMenu); |
| document.getElementById('close-menu').addEventListener('click', () => { |
| document.getElementById('menu-window').classList.add('hidden'); |
| }); |
| |
| document.getElementById('settings-btn').addEventListener('click', () => { |
| document.getElementById('menu-window').classList.add('hidden'); |
| openSettings(); |
| }); |
| |
| document.getElementById('close-settings').addEventListener('click', () => { |
| document.getElementById('settings-window').classList.add('hidden'); |
| }); |
| |
| function openMenu() { |
| const menuWindow = document.getElementById('menu-window'); |
| menuWindow.classList.remove('hidden'); |
| document.getElementById('home-screen').classList.add('hidden'); |
| |
| |
| const maxX = window.innerWidth - menuWindow.offsetWidth; |
| const maxY = window.innerHeight - menuWindow.offsetHeight; |
| const randomX = Math.floor(Math.random() * maxX * 0.5); |
| const randomY = Math.floor(Math.random() * maxY * 0.5); |
| |
| menuWindow.style.left = `${randomX}px`; |
| menuWindow.style.top = `${randomY}px`; |
| |
| makeDraggable(menuWindow); |
| } |
| |
| function openSettings() { |
| const settingsWindow = document.getElementById('settings-window'); |
| settingsWindow.classList.remove('hidden'); |
| |
| |
| const maxX = window.innerWidth - settingsWindow.offsetWidth; |
| const maxY = window.innerHeight - settingsWindow.offsetHeight; |
| const randomX = Math.floor(Math.random() * maxX * 0.5); |
| const randomY = Math.floor(Math.random() * maxY * 0.5); |
| |
| settingsWindow.style.left = `${randomX}px`; |
| settingsWindow.style.top = `${randomY}px`; |
| |
| makeDraggable(settingsWindow); |
| } |
| |
| |
| document.getElementById('calculator-btn').addEventListener('click', openCalculator); |
| document.getElementById('close-calculator').addEventListener('click', () => { |
| document.getElementById('calculator-window').classList.add('hidden'); |
| }); |
| |
| function openCalculator() { |
| const calculatorWindow = document.getElementById('calculator-window'); |
| calculatorWindow.classList.remove('hidden'); |
| document.getElementById('home-screen').classList.add('hidden'); |
| |
| |
| const maxX = window.innerWidth - calculatorWindow.offsetWidth; |
| const maxY = window.innerHeight - calculatorWindow.offsetHeight; |
| const randomX = Math.floor(Math.random() * maxX * 0.5); |
| const randomY = Math.floor(Math.random() * maxY * 0.5); |
| |
| calculatorWindow.style.left = `${randomX}px`; |
| calculatorWindow.style.top = `${randomY}px`; |
| |
| makeDraggable(calculatorWindow); |
| } |
| |
| |
| let currentInput = '0'; |
| let previousInput = ''; |
| let operation = null; |
| const display = document.getElementById('calc-display'); |
| |
| document.querySelectorAll('.calc-btn').forEach(button => { |
| button.addEventListener('click', () => { |
| const value = button.textContent; |
| |
| if (value >= '0' && value <= '9') { |
| if (currentInput === '0') { |
| currentInput = value; |
| } else { |
| currentInput += value; |
| } |
| } else if (value === '.') { |
| if (!currentInput.includes('.')) { |
| currentInput += value; |
| } |
| } else if (value === 'C') { |
| currentInput = '0'; |
| previousInput = ''; |
| operation = null; |
| } else if (value === 'CE') { |
| currentInput = '0'; |
| } else if (value === '+' || value === '-' || value === '*' || value === '/') { |
| if (operation !== null) calculate(); |
| previousInput = currentInput; |
| currentInput = '0'; |
| operation = value; |
| } else if (value === '=') { |
| if (operation !== null) calculate(); |
| } |
| |
| display.value = currentInput; |
| }); |
| }); |
| |
| function calculate() { |
| 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; |
| default: |
| return; |
| } |
| |
| currentInput = result.toString(); |
| operation = null; |
| previousInput = ''; |
| } |
| |
| |
| document.getElementById('game-btn').addEventListener('click', openGame); |
| document.getElementById('close-game').addEventListener('click', () => { |
| document.getElementById('game-window').classList.add('hidden'); |
| clearInterval(gameLoop); |
| }); |
| |
| function openGame() { |
| const gameWindow = document.getElementById('game-window'); |
| gameWindow.classList.remove('hidden'); |
| |
| |
| const maxX = window.innerWidth - gameWindow.offsetWidth; |
| const maxY = window.innerHeight - gameWindow.offsetHeight; |
| const randomX = Math.floor(Math.random() * maxX * 0.5); |
| const randomY = Math.floor(Math.random() * maxY * 0.5); |
| |
| gameWindow.style.left = `${randomX}px`; |
| gameWindow.style.top = `${randomY}px`; |
| |
| makeDraggable(gameWindow); |
| initGame(); |
| } |
| |
| let gameLoop; |
| function initGame() { |
| const canvas = document.getElementById('game-canvas'); |
| const ctx = canvas.getContext('2d'); |
| const scoreElement = document.getElementById('game-score'); |
| |
| const gridSize = 20; |
| const tileCount = canvas.width / gridSize; |
| |
| let snake = [{x: 10, y: 10}]; |
| let velocityX = 0; |
| let velocityY = 0; |
| let foodX = 5; |
| let foodY = 5; |
| let score = 0; |
| let gameSpeed = 100; |
| |
| function gameUpdate() { |
| |
| const head = {x: snake[0].x + velocityX, y: snake[0].y + velocityY}; |
| |
| |
| if (head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount) { |
| gameOver(); |
| return; |
| } |
| |
| |
| for (let i = 0; i < snake.length; i++) { |
| if (head.x === snake[i].x && head.y === snake[i].y) { |
| gameOver(); |
| return; |
| } |
| } |
| |
| snake.unshift(head); |
| |
| |
| if (head.x === foodX && head.y === foodY) { |
| score++; |
| scoreElement.textContent = score; |
| placeFood(); |
| |
| |
| if (score % 5 === 0) { |
| gameSpeed = Math.max(50, gameSpeed - 10); |
| clearInterval(gameLoop); |
| gameLoop = setInterval(gameUpdate, gameSpeed); |
| } |
| } else { |
| snake.pop(); |
| } |
| |
| |
| ctx.fillStyle = 'black'; |
| ctx.fillRect(0, 0, canvas.width, canvas.height); |
| |
| |
| ctx.fillStyle = 'lime'; |
| snake.forEach(segment => { |
| ctx.fillRect(segment.x * gridSize, segment.y * gridSize, gridSize-2, gridSize-2); |
| }); |
| |
| |
| ctx.fillStyle = 'red'; |
| ctx.fillRect(foodX * gridSize, foodY * gridSize, gridSize-2, gridSize-2); |
| } |
| |
| function placeFood() { |
| foodX = Math.floor(Math.random() * tileCount); |
| foodY = Math.floor(Math.random() * tileCount); |
| |
| |
| for (let i = 0; i < snake.length; i++) { |
| if (foodX === snake[i].x && foodY === snake[i].y) { |
| placeFood(); |
| return; |
| } |
| } |
| } |
| |
| function gameOver() { |
| clearInterval(gameLoop); |
| alert(`Game Over! Score: ${score}`); |
| initGame(); |
| } |
| |
| function handleKeyDown(e) { |
| switch(e.key) { |
| case 'ArrowUp': |
| if (velocityY !== 1) { |
| velocityX = 0; |
| velocityY = -1; |
| } |
| break; |
| case 'ArrowDown': |
| if (velocityY !== -1) { |
| velocityX = 0; |
| velocityY = 1; |
| } |
| break; |
| case 'ArrowLeft': |
| if (velocityX !== 1) { |
| velocityX = -1; |
| velocityY = 0; |
| } |
| break; |
| case 'ArrowRight': |
| if (velocityX !== -1) { |
| velocityX = 1; |
| velocityY = 0; |
| } |
| break; |
| } |
| } |
| |
| |
| snake = [{x: 10, y: 10}]; |
| velocityX = 0; |
| velocityY = 0; |
| score = 0; |
| scoreElement.textContent = score; |
| gameSpeed = 100; |
| |
| |
| document.removeEventListener('keydown', handleKeyDown); |
| document.addEventListener('keydown', handleKeyDown); |
| |
| |
| placeFood(); |
| |
| |
| clearInterval(gameLoop); |
| gameLoop = setInterval(gameUpdate, gameSpeed); |
| |
| |
| document.getElementById('restart-game').addEventListener('click', initGame); |
| } |
| |
| |
| document.getElementById('save-btn').addEventListener('click', () => { |
| const text = textEditor.value; |
| const blob = new Blob([text], { type: 'text/plain' }); |
| const url = URL.createObjectURL(blob); |
| |
| const a = document.createElement('a'); |
| a.href = url; |
| a.download = 'document.txt'; |
| a.click(); |
| |
| URL.revokeObjectURL(url); |
| }); |
| |
| document.getElementById('open-btn').addEventListener('click', () => { |
| document.getElementById('file-input').click(); |
| }); |
| |
| document.getElementById('file-input').addEventListener('change', (e) => { |
| const file = e.target.files[0]; |
| if (!file) return; |
| |
| const reader = new FileReader(); |
| reader.onload = (event) => { |
| textEditor.value = event.target.result; |
| updateCursorPosition(); |
| }; |
| reader.readAsText(file); |
| }); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=abiyeenzo/os" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |