Spaces:
Running
Running
| <html lang="pt-BR"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Notas Editáveis</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> | |
| .note { | |
| transition: all 0.3s ease; | |
| box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); | |
| } | |
| .note:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); | |
| } | |
| .color-option { | |
| width: 24px; | |
| height: 24px; | |
| border-radius: 50%; | |
| cursor: pointer; | |
| transition: transform 0.2s; | |
| } | |
| .color-option:hover { | |
| transform: scale(1.2); | |
| } | |
| .fade-in { | |
| animation: fadeIn 0.3s ease-in-out; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-100 min-h-screen"> | |
| <div class="container mx-auto px-4 py-8"> | |
| <!-- Header --> | |
| <header class="flex justify-between items-center mb-8"> | |
| <h1 class="text-3xl font-bold text-indigo-700"> | |
| <i class="fas fa-edit mr-2"></i> Notas Editáveis | |
| </h1> | |
| <button id="newNoteBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg flex items-center transition-colors"> | |
| <i class="fas fa-plus mr-2"></i> Nova Nota | |
| </button> | |
| </header> | |
| <!-- Notes Grid --> | |
| <div id="notesContainer" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> | |
| <!-- Notes will be added here dynamically --> | |
| </div> | |
| <!-- Empty State --> | |
| <div id="emptyState" class="text-center py-20"> | |
| <i class="fas fa-sticky-note text-6xl text-gray-300 mb-4"></i> | |
| <h3 class="text-xl font-medium text-gray-500">Nenhuma nota criada ainda</h3> | |
| <p class="text-gray-400 mb-4">Clique no botão "Nova Nota" para começar</p> | |
| </div> | |
| </div> | |
| <!-- Color Picker Modal (hidden by default) --> | |
| <div id="colorPickerModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> | |
| <div class="bg-white rounded-lg p-6 w-64"> | |
| <h3 class="font-bold text-lg mb-4">Escolha uma cor</h3> | |
| <div class="grid grid-cols-5 gap-3 mb-4"> | |
| <div class="color-option bg-blue-200" data-color="blue-200"></div> | |
| <div class="color-option bg-green-200" data-color="green-200"></div> | |
| <div class="color-option bg-yellow-200" data-color="yellow-200"></div> | |
| <div class="color-option bg-red-200" data-color="red-200"></div> | |
| <div class="color-option bg-purple-200" data-color="purple-200"></div> | |
| <div class="color-option bg-pink-200" data-color="pink-200"></div> | |
| <div class="color-option bg-indigo-200" data-color="indigo-200"></div> | |
| <div class="color-option bg-gray-200" data-color="gray-200"></div> | |
| <div class="color-option bg-teal-200" data-color="teal-200"></div> | |
| <div class="color-option bg-orange-200" data-color="orange-200"></div> | |
| </div> | |
| <div class="flex justify-end space-x-2"> | |
| <button id="cancelColorBtn" class="px-4 py-2 text-gray-600 hover:text-gray-800">Cancelar</button> | |
| <button id="applyColorBtn" class="px-4 py-2 bg-indigo-600 text-white rounded hover:bg-indigo-700">Aplicar</button> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // DOM Elements | |
| const newNoteBtn = document.getElementById('newNoteBtn'); | |
| const notesContainer = document.getElementById('notesContainer'); | |
| const emptyState = document.getElementById('emptyState'); | |
| const colorPickerModal = document.getElementById('colorPickerModal'); | |
| const cancelColorBtn = document.getElementById('cancelColorBtn'); | |
| const applyColorBtn = document.getElementById('applyColorBtn'); | |
| const colorOptions = document.querySelectorAll('.color-option'); | |
| // State | |
| let notes = JSON.parse(localStorage.getItem('notes')) || []; | |
| let currentNoteId = null; | |
| let selectedColor = 'yellow-200'; | |
| // Initialize | |
| renderNotes(); | |
| updateEmptyState(); | |
| // Event Listeners | |
| newNoteBtn.addEventListener('click', createNewNote); | |
| cancelColorBtn.addEventListener('click', hideColorPicker); | |
| applyColorBtn.addEventListener('click', applySelectedColor); | |
| colorOptions.forEach(option => { | |
| option.addEventListener('click', function() { | |
| selectedColor = this.getAttribute('data-color'); | |
| // Highlight selected color | |
| colorOptions.forEach(opt => opt.classList.remove('ring-2', 'ring-offset-2', 'ring-indigo-500')); | |
| this.classList.add('ring-2', 'ring-offset-2', 'ring-indigo-500'); | |
| }); | |
| }); | |
| // Functions | |
| function createNewNote() { | |
| const newNote = { | |
| id: Date.now(), | |
| title: 'Nova Nota', | |
| content: 'Comece a digitar aqui...', | |
| color: 'yellow-200', | |
| createdAt: new Date().toISOString() | |
| }; | |
| notes.unshift(newNote); | |
| saveNotes(); | |
| renderNotes(); | |
| updateEmptyState(); | |
| // Focus on the title of the first note (the new one) | |
| setTimeout(() => { | |
| const firstNote = document.querySelector('.note'); | |
| if (firstNote) { | |
| const titleInput = firstNote.querySelector('.note-title'); | |
| titleInput.focus(); | |
| titleInput.select(); | |
| } | |
| }, 100); | |
| } | |
| function renderNotes() { | |
| notesContainer.innerHTML = ''; | |
| notes.forEach(note => { | |
| const noteElement = document.createElement('div'); | |
| noteElement.className = `note rounded-lg p-4 flex flex-col bg-${note.color} fade-in`; | |
| noteElement.dataset.id = note.id; | |
| noteElement.innerHTML = ` | |
| <div class="flex justify-between items-center mb-2"> | |
| <input type="text" class="note-title bg-transparent font-bold text-lg w-full focus:outline-none border-b border-transparent focus:border-gray-400" value="${note.title}"> | |
| <div class="flex space-x-2"> | |
| <button class="note-color-btn text-gray-600 hover:text-gray-800"> | |
| <i class="fas fa-palette"></i> | |
| </button> | |
| <button class="note-delete-btn text-gray-600 hover:text-red-500"> | |
| <i class="fas fa-trash"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <textarea class="note-content bg-transparent flex-grow resize-none focus:outline-none">${note.content}</textarea> | |
| <div class="text-xs text-gray-500 mt-2"> | |
| ${formatDate(note.createdAt)} | |
| </div> | |
| `; | |
| notesContainer.appendChild(noteElement); | |
| // Add event listeners to the new note | |
| const titleInput = noteElement.querySelector('.note-title'); | |
| const contentInput = noteElement.querySelector('.note-content'); | |
| const colorBtn = noteElement.querySelector('.note-color-btn'); | |
| const deleteBtn = noteElement.querySelector('.note-delete-btn'); | |
| titleInput.addEventListener('input', () => updateNote(note.id, 'title', titleInput.value)); | |
| contentInput.addEventListener('input', () => updateNote(note.id, 'content', contentInput.value)); | |
| colorBtn.addEventListener('click', () => showColorPicker(note.id)); | |
| deleteBtn.addEventListener('click', () => deleteNote(note.id)); | |
| }); | |
| } | |
| function updateNote(id, field, value) { | |
| const noteIndex = notes.findIndex(note => note.id === id); | |
| if (noteIndex !== -1) { | |
| notes[noteIndex][field] = value; | |
| saveNotes(); | |
| } | |
| } | |
| function deleteNote(id) { | |
| if (confirm('Tem certeza que deseja excluir esta nota?')) { | |
| notes = notes.filter(note => note.id !== id); | |
| saveNotes(); | |
| renderNotes(); | |
| updateEmptyState(); | |
| } | |
| } | |
| function showColorPicker(noteId) { | |
| currentNoteId = noteId; | |
| const note = notes.find(n => n.id === noteId); | |
| if (note) { | |
| // Reset selected color | |
| colorOptions.forEach(opt => { | |
| opt.classList.remove('ring-2', 'ring-offset-2', 'ring-indigo-500'); | |
| if (opt.getAttribute('data-color') === note.color) { | |
| opt.classList.add('ring-2', 'ring-offset-2', 'ring-indigo-500'); | |
| selectedColor = note.color; | |
| } | |
| }); | |
| colorPickerModal.classList.remove('hidden'); | |
| } | |
| } | |
| function hideColorPicker() { | |
| colorPickerModal.classList.add('hidden'); | |
| } | |
| function applySelectedColor() { | |
| if (currentNoteId) { | |
| const noteIndex = notes.findIndex(note => note.id === currentNoteId); | |
| if (noteIndex !== -1) { | |
| notes[noteIndex].color = selectedColor; | |
| saveNotes(); | |
| renderNotes(); | |
| hideColorPicker(); | |
| } | |
| } | |
| } | |
| function saveNotes() { | |
| localStorage.setItem('notes', JSON.stringify(notes)); | |
| } | |
| function updateEmptyState() { | |
| emptyState.style.display = notes.length === 0 ? 'block' : 'none'; | |
| } | |
| function formatDate(dateString) { | |
| const options = { | |
| year: 'numeric', | |
| month: 'short', | |
| day: 'numeric', | |
| hour: '2-digit', | |
| minute: '2-digit' | |
| }; | |
| return new Date(dateString).toLocaleDateString('pt-BR', options); | |
| } | |
| }); | |
| </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=Elleres/ellerestech" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |