Spaces:
Running
Running
| class DesktopIcon extends HTMLElement { | |
| connectedCallback() { | |
| this.attachShadow({ mode: 'open' }); | |
| const name = this.getAttribute('name') || 'Icon'; | |
| const icon = this.getAttribute('icon') || 'file'; | |
| const color = this.getAttribute('color') || 'text-zinc-300'; | |
| this.shadowRoot.innerHTML = ` | |
| <style> | |
| :host { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| gap: 4px; | |
| padding: 8px 12px; | |
| cursor: pointer; | |
| border-radius: 4px; | |
| transition: all 0.2s; | |
| user-select: none; | |
| } | |
| :host:hover { | |
| background: rgba(255, 255, 255, 0.1); | |
| transform: scale(1.05); | |
| } | |
| :host(.selected) { | |
| background: rgba(239, 68, 68, 0.3); | |
| border: 1px solid rgba(239, 68, 68, 0.5); | |
| } | |
| .icon-container { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| width: 48px; | |
| height: 48px; | |
| background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.05)); | |
| border-radius: 8px; | |
| backdrop-filter: blur(10px); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| } | |
| .icon-label { | |
| color: #e4e4e7; | |
| font-size: 11px; | |
| text-align: center; | |
| max-width: 80px; | |
| text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8); | |
| word-wrap: break-word; | |
| line-height: 1.2; | |
| } | |
| </style> | |
| <div class="icon-container"> | |
| <i data-feather="${icon}" class="${color}" style="width: 24px; height: 24px;"></i> | |
| </div> | |
| <div class="icon-label">${name}</div> | |
| `; | |
| this.initializeEventListeners(); | |
| // Re-render feather icon | |
| setTimeout(() => feather.replace(), 0); | |
| } | |
| initializeEventListeners() { | |
| this.addEventListener('dblclick', () => { | |
| this.openApplication(); | |
| }); | |
| this.addEventListener('click', (e) => { | |
| // Clear other selections | |
| document.querySelectorAll('desktop-icon').forEach(icon => { | |
| icon.classList.remove('selected'); | |
| }); | |
| // Select this icon | |
| this.classList.add('selected'); | |
| }); | |
| this.addEventListener('contextmenu', (e) => { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| this.showContextMenu(e); | |
| }); | |
| } | |
| openApplication() { | |
| const name = this.getAttribute('name'); | |
| const icon = this.getAttribute('icon'); | |
| switch(icon) { | |
| case 'terminal': | |
| this.openTerminal(); | |
| break; | |
| case 'globe': | |
| this.openBrowser(); | |
| break; | |
| case 'edit-3': | |
| this.openTextEditor(); | |
| break; | |
| case 'folder': | |
| this.openFileBrowser(name); | |
| break; | |
| case 'image': | |
| this.openImageViewer(); | |
| break; | |
| case 'music': | |
| this.openMusicPlayer(); | |
| break; | |
| case 'film': | |
| this.openVideoPlayer(); | |
| break; | |
| case 'file-text': | |
| this.openDocumentViewer(); | |
| break; | |
| case 'home': | |
| this.openHomeFolder(); | |
| break; | |
| case 'trash-2': | |
| this.openTrash(); | |
| break; | |
| default: | |
| this.showMessage(`Abrindo ${name}...`); | |
| } | |
| } | |
| openTerminal() { | |
| const content = `<div class="bg-black h-full p-4 font-mono text-sm text-green-400 overflow-auto"> | |
| <div>mate@mate-desktop:~$ echo "Bem-vindo ao terminal MATE!"</div> | |
| <div>Bem-vindo ao terminal MATE!</div> | |
| <div>mate@mate-desktop:~$ _</div> | |
| </div>`; | |
| createNewWindow('Terminal', 'terminal', 650, 450, content, 100, 150); | |
| } | |
| openBrowser() { | |
| const content = `<div class="bg-zinc-800 h-full flex flex-col"> | |
| <div class="bg-zinc-700 p-2 flex items-center gap-2"> | |
| <i data-feather="globe" class="text-blue-400" style="width: 16px; height: 16px;"></i> | |
| <span class="text-zinc-200 text-sm">Navegador Web MATE</span> | |
| </div> | |
| <div class="flex-1 flex items-center justify-center text-zinc-400"> | |
| <div class="text-center"> | |
| <i data-feather="globe" style="width: 48px; height: 48px; margin: 0 auto 16px;"></i> | |
| <p>Digite um endereço na barra de endereços</p> | |
| <input type="text" placeholder="https://..." class="mt-4 px-3 py-2 bg-zinc-700 rounded text-zinc-200 w-64 outline-none"> | |
| </div> | |
| </div> | |
| </div>`; | |
| createNewWindow('Navegador Web', 'globe', 800, 600, content, 200, 100); | |
| } | |
| openTextEditor() { | |
| const content = `<div class="bg-zinc-800 h-full p-4"> | |
| <textarea class="w-full h-full bg-zinc-900 text-zinc-200 p-3 rounded resize-none outline-none" placeholder="Comece a digitar...">Documento de Texto - MATE Desktop | |
| Este é um documento de exemplo criado com o editor de texto MATE. | |
| O ambiente MATE oferece uma experiência de desktop familiar e produtiva, | |
| com todas as ferramentas necessárias para o seu trabalho diário.</textarea> | |
| </div>`; | |
| createNewWindow('Editor de Texto', 'edit-3', 600, 450, content, 250, 120); | |
| } | |
| openFileBrowser(folderName) { | |
| const content = `<div class="bg-zinc-800 h-full flex flex-col"> | |
| <div class="bg-zinc-700 p-2 flex items-center gap-2 border-b border-zinc-600"> | |
| <i data-feather="folder" class="text-zinc-300" style="width: 16px; height: 16px;"></i> | |
| <span class="text-zinc-200 text-sm">${folderName}</span> | |
| </div> | |
| <div class="flex-1 p-6 flex items-center justify-center text-zinc-400"> | |
| <div class="text-center"> | |
| <i data-feather="folder" style="width: 64px; height: 64px; margin: 0 auto 16px;"></i> | |
| <p class="text-lg">Pasta vazia</p> | |
| <p class="text-sm mt-2">Esta pasta não contém arquivos</p> | |
| </div> | |
| </div> | |
| </div>`; | |
| createNewWindow(folderName, 'folder', 700, 500, content, 150, 120); | |
| } | |
| openImageViewer() { | |
| const content = `<div class="bg-zinc-800 h-full p-4 flex items-center justify-center"> | |
| <div class="text-center"> | |
| <img src="http://static.photos/nature/500x400/42" alt="Imagem" class="rounded shadow-lg mb-4"> | |
| <div class="flex justify-center gap-2"> | |
| <button class="px-3 py-1 bg-zinc-700 text-zinc-200 rounded hover:bg-zinc-600"> | |
| <i data-feather="chevron-left" style="width: 16px; height: 16px;"></i> | |
| </button> | |
| <button class="px-3 py-1 bg-zinc-700 text-zinc-200 rounded hover:bg-zinc-600"> | |
| <i data-feather="chevron-right" style="width: 16px; height: 16px;"></i> | |
| </button> | |
| <button class="px-3 py-1 bg-zinc-700 text-zinc-200 rounded hover:bg-zinc-600"> | |
| <i data-feather="maximize-2" style="width: 16px; height: 16px;"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div>`; | |
| createNewWindow('Visualizador de Imagens', 'image', 600, 500, content, 300, 150); | |
| } | |
| openMusicPlayer() { | |
| const content = `<div class="bg-zinc-800 h-full flex flex-col"> | |
| <div class="p-6"> | |
| <div class="w-48 h-48 mx-auto bg-gradient-to-br from-purple-500 to-pink-500 rounded-lg shadow-xl flex items-center justify-center"> | |
| <i data-feather="music" style="width: 64px; height: 64px; color: white;"></i> | |
| </div> | |
| <div class="text-center mt-6"> | |
| <h3 class="text-zinc-200 text-lg font-medium">Artista - Música</h3> | |
| <p class="text-zinc-400 text-sm mt-1">Álbum Exemplo</p> | |
| </div> | |
| </div> | |
| <div class="p-4 border-t border-zinc-700"> | |
| <div class="bg-zinc-700 h-2 rounded-full overflow-hidden mb-4"> | |
| <div class="bg-red-500 h-full rounded-full" style="width: 30%;"></div> | |
| </div> | |
| <div class="flex justify-center gap-4"> | |
| <button class="text-zinc-400 hover:text-zinc-200"> | |
| <i data-feather="skip-back" style="width: 24px; height: 24px;"></i> | |
| </button> | |
| <button class="text-zinc-400 hover:text-zinc-200"> | |
| <i data-feather="play" style="width: 32px; height: 32px;"></i> | |
| </button> | |
| <button class="text-zinc-400 hover:text-zinc-200"> | |
| <i data-feather="skip-forward" style="width: 24px; height: 24px;"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div>`; | |
| createNewWindow('Reprodutor de Música', 'music', 400, 500, content, 400, 100); | |
| } | |
| openVideoPlayer() { | |
| const content = `<div class="bg-black h-full flex items-center justify-center"> | |
| <div class="text-center text-white"> | |
| <i data-feather="film" style="width: 64px; height: 64px; margin: 0 auto 16px;"></i> | |
| <p>Reprodutor de Vídeo MATE</p> | |
| <p class="text-sm text-zinc-400 mt-2">Selecione um arquivo de vídeo para reproduzir</p> | |
| </div> | |
| </div>`; | |
| createNewWindow('Reprodutor de Vídeo', 'film', 700, 500, content, 350, 100); | |
| } | |
| openDocumentViewer() { | |
| const content = `<div class="bg-zinc-800 h-full p-8"> | |
| <div class="bg-white h-full rounded shadow-lg p-6"> | |
| <h1 class="text-2xl font-bold mb-4">Documento de Exemplo</h1> | |
| <p class="text-gray-700 mb-4">Este é um documento exemplo no visualizador de documentos MATE.</p> | |
| <p class="text-gray-700 mb-4">O MATE Desktop oferece ferramentas completas para produtividade, incluindo visualização de documentos, planilhas e apresentações.</p> | |
| <ul class="list-disc list-inside text-gray-700"> | |
| <li> Suporte para múltiplos formatos </li> | |
| <li> Interface intuitiva </li> | |
| <li> Integração com o sistema </li> | |
| <li> Ferramentas de edição básicas </li> | |
| </ul> | |
| </div> | |
| </div>`; | |
| createNewWindow('Visualizador de Documentos', 'file-text', 650, 500, content, 200, 150); | |
| } | |
| openHomeFolder() { | |
| this.openFileBrowser('Página Inicial'); | |
| } | |
| openTrash() { | |
| const content = `<div class="bg-zinc-800 h-full flex flex-col"> | |
| <div class="bg-zinc-700 p-2 flex items-center gap-2 border-b border-zinc-600"> | |
| <i data-feather="trash-2" class="text-red-400" style="width: 16px; height: 16px;"></i> | |
| <span class="text-zinc-200 text-sm">Lixeira</span> | |
| </div> | |
| <div class="flex-1 p-6 flex items-center justify-center text-zinc-400"> | |
| <div class="text-center"> | |
| <i data-feather="trash-2" style="width: 64px; height: 64px; margin: 0 auto 16px;"></i> | |
| <p class="text-lg">Lixeira vazia</p> | |
| <p class="text-sm mt-2">Nenhum item na lixeira</p> | |
| <button class="mt-4 px-4 py-2 bg-zinc-700 text-zinc-200 rounded hover:bg-zinc-600"> | |
| <i data-feather="refresh-cw" style="width: 16px; height: 16px; display: inline; vertical-align: middle;"></i> | |
| Restaurar itens | |
| </button> | |
| </div> | |
| </div> | |
| </div>`; | |
| createNewWindow('Lixeira', 'trash-2', 600, 450, content, 250, 150); | |
| } | |
| showMessage(text) { | |
| // Create a temporary notification | |
| const notification = document.createElement('div'); | |
| notification.className = 'fixed top-40 left-1/2 transform -translate-x-1/2 bg-zinc-800 text-zinc-200 px-4 py-2 rounded shadow-lg z-50'; | |
| notification.textContent = text; | |
| document.body.appendChild(notification); | |
| setTimeout(() => { | |
| notification.remove(); | |
| }, 2000); | |
| } | |
| showContextMenu(e) { | |
| const contextMenu = document.getElementById('context-menu'); | |
| contextMenu.style.left = `${e.clientX}px`; | |
| contextMenu.style.top = `${e.clientY}px`; | |
| contextMenu.classList.remove('hidden'); | |
| contextMenu.classList.add('menu-enter'); | |
| } | |
| } | |
| customElements.define('desktop-icon', DesktopIcon); |