Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Personal Information Organizer</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| } | |
| :root { | |
| --primary: #4361ee; | |
| --secondary: #3a0ca3; | |
| --success: #4cc9f0; | |
| --danger: #f72585; | |
| --warning: #f8961e; | |
| --light: #f8f9fa; | |
| --dark: #212529; | |
| --gray: #6c757d; | |
| --transition: all 0.3s ease; | |
| } | |
| body { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| min-height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 1rem; | |
| color: var(--light); | |
| } | |
| .header { | |
| position: absolute; | |
| top: 1rem; | |
| right: 1rem; | |
| display: flex; | |
| gap: 1rem; | |
| align-items: center; | |
| } | |
| .header a { | |
| color: var(--light); | |
| text-decoration: none; | |
| font-size: 0.9rem; | |
| opacity: 0.8; | |
| transition: var(--transition); | |
| } | |
| .header a:hover { | |
| opacity: 1; | |
| text-decoration: underline; | |
| } | |
| .container { | |
| background: rgba(255, 255, 255, 0.1); | |
| backdrop-filter: blur(10px); | |
| border-radius: 20px; | |
| padding: 2rem; | |
| width: 100%; | |
| max-width: 1000px; | |
| box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| } | |
| h1 { | |
| text-align: center; | |
| margin-bottom: 1.5rem; | |
| font-weight: 700; | |
| font-size: 2.5rem; | |
| text-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); | |
| } | |
| .description { | |
| text-align: center; | |
| margin-bottom: 2rem; | |
| font-size: 1.1rem; | |
| opacity: 0.9; | |
| line-height: 1.6; | |
| } | |
| .app-container { | |
| display: grid; | |
| grid-template-columns: 1fr 2fr; | |
| gap: 2rem; | |
| } | |
| .input-section { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 1.5rem; | |
| } | |
| .input-group { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.8rem; | |
| } | |
| .input-group label { | |
| font-weight: 600; | |
| font-size: 1.1rem; | |
| } | |
| .input-group input, | |
| .input-group textarea, | |
| .input-group select { | |
| padding: 0.8rem 1rem; | |
| border-radius: 10px; | |
| border: 1px solid rgba(255, 255, 255, 0.3); | |
| background: rgba(255, 255, 255, 0.15); | |
| color: var(--light); | |
| font-size: 1rem; | |
| transition: var(--transition); | |
| } | |
| .input-group input:focus, | |
| .input-group textarea:focus, | |
| .input-group select:focus { | |
| outline: none; | |
| border-color: var(--primary); | |
| background: rgba(255, 255, 255, 0.2); | |
| } | |
| .input-group textarea { | |
| min-height: 120px; | |
| resize: vertical; | |
| } | |
| .input-group input::placeholder, | |
| .input-group textarea::placeholder { | |
| color: rgba(255, 255, 255, 0.6); | |
| } | |
| .categories { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 0.5rem; | |
| } | |
| .category-tag { | |
| background: rgba(255, 255, 255, 0.2); | |
| padding: 0.3rem 0.8rem; | |
| border-radius: 20px; | |
| font-size: 0.9rem; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| } | |
| .category-tag:hover { | |
| background: rgba(255, 255, 255, 0.3); | |
| } | |
| .category-tag.active { | |
| background: var(--primary); | |
| } | |
| .btn { | |
| padding: 0.8rem 1.5rem; | |
| border: none; | |
| border-radius: 10px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 0.5rem; | |
| font-size: 1rem; | |
| } | |
| .btn-primary { | |
| background: var(--primary); | |
| color: white; | |
| } | |
| .btn-primary:hover { | |
| background: var(--secondary); | |
| transform: scale(1.05); | |
| } | |
| .btn-outline { | |
| background: transparent; | |
| color: var(--light); | |
| border: 1px solid rgba(255, 255, 255, 0.3); | |
| } | |
| .btn-outline:hover { | |
| background: rgba(255, 255, 255, 0.1); | |
| } | |
| .view-section { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 1.5rem; | |
| } | |
| .search-bar { | |
| display: flex; | |
| gap: 0.5rem; | |
| } | |
| .search-bar input { | |
| flex: 1; | |
| padding: 0.8rem 1rem; | |
| border-radius: 10px; | |
| border: 1px solid rgba(255, 255, 255, 0.3); | |
| background: rgba(255, 255, 255, 0.15); | |
| color: var(--light); | |
| font-size: 1rem; | |
| } | |
| .search-bar input:focus { | |
| outline: none; | |
| border-color: var(--primary); | |
| } | |
| .notes-container { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 1rem; | |
| max-height: 500px; | |
| overflow-y: auto; | |
| padding-right: 0.5rem; | |
| } | |
| .notes-container::-webkit-scrollbar { | |
| width: 8px; | |
| } | |
| .notes-container::-webkit-scrollbar-track { | |
| background: rgba(255, 255, 255, 0.1); | |
| border-radius: 10px; | |
| } | |
| .notes-container::-webkit-scrollbar-thumb { | |
| background: rgba(255, 255, 255, 0.3); | |
| border-radius: 10px; | |
| } | |
| .notes-container::-webkit-scrollbar-thumb:hover { | |
| background: rgba(255, 255, 255, 0.5); | |
| } | |
| .note-card { | |
| background: rgba(255, 255, 255, 0.15); | |
| border-radius: 15px; | |
| padding: 1.5rem; | |
| transition: var(--transition); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| } | |
| .note-card:hover { | |
| background: rgba(255, 255, 255, 0.2); | |
| transform: translateY(-3px); | |
| } | |
| .note-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 1rem; | |
| } | |
| .note-title { | |
| font-size: 1.3rem; | |
| font-weight: 600; | |
| } | |
| .note-category { | |
| padding: 0.3rem 0.8rem; | |
| border-radius: 20px; | |
| font-size: 0.8rem; | |
| font-weight: 600; | |
| background: var(--primary); | |
| } | |
| .note-content { | |
| margin-bottom: 1rem; | |
| line-height: 1.5; | |
| } | |
| .note-meta { | |
| display: flex; | |
| justify-content: space-between; | |
| font-size: 0.8rem; | |
| opacity: 0.8; | |
| } | |
| .note-actions { | |
| display: flex; | |
| gap: 0.5rem; | |
| margin-top: 1rem; | |
| } | |
| .action-btn { | |
| background: transparent; | |
| border: none; | |
| color: var(--light); | |
| cursor: pointer; | |
| opacity: 0.7; | |
| transition: var(--transition); | |
| padding: 0.3rem 0.5rem; | |
| border-radius: 5px; | |
| } | |
| .action-btn:hover { | |
| opacity: 1; | |
| background: rgba(255, 255, 255, 0.1); | |
| } | |
| .empty-state { | |
| text-align: center; | |
| padding: 2rem; | |
| opacity: 0.7; | |
| } | |
| .empty-state i { | |
| font-size: 3rem; | |
| margin-bottom: 1rem; | |
| } | |
| .stats-container { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); | |
| gap: 1rem; | |
| margin-top: 2rem; | |
| } | |
| .stat-card { | |
| background: rgba(255, 255, 255, 0.1); | |
| border-radius: 12px; | |
| padding: 1rem; | |
| text-align: center; | |
| transition: var(--transition); | |
| } | |
| .stat-card:hover { | |
| background: rgba(255, 255, 255, 0.15); | |
| transform: translateY(-3px); | |
| } | |
| .stat-value { | |
| font-size: 2rem; | |
| font-weight: 700; | |
| margin-bottom: 0.5rem; | |
| } | |
| .stat-label { | |
| font-size: 0.9rem; | |
| opacity: 0.8; | |
| } | |
| .notification { | |
| position: fixed; | |
| bottom: 2rem; | |
| right: 2rem; | |
| background: var(--success); | |
| color: var(--dark); | |
| padding: 1rem 1.5rem; | |
| border-radius: 10px; | |
| box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); | |
| display: flex; | |
| align-items: center; | |
| gap: 0.8rem; | |
| transform: translateY(150%); | |
| transition: transform 0.4s ease; | |
| z-index: 1000; | |
| } | |
| .notification.show { | |
| transform: translateY(0); | |
| } | |
| @media (max-width: 900px) { | |
| .app-container { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| @media (max-width: 768px) { | |
| .container { | |
| padding: 1.5rem; | |
| } | |
| h1 { | |
| font-size: 2rem; | |
| } | |
| .note-header { | |
| flex-direction: column; | |
| align-items: flex-start; | |
| gap: 0.5rem; | |
| margin-bottom: 1rem; | |
| } | |
| } | |
| @media (max-width: 480px) { | |
| .container { | |
| padding: 1rem; | |
| } | |
| h1 { | |
| font-size: 1.8rem; | |
| } | |
| .header { | |
| position: relative; | |
| top: 0; | |
| right: 0; | |
| margin-bottom: 1rem; | |
| justify-content: flex-end; | |
| } | |
| .stats-container { | |
| grid-template-columns: repeat(2, 1fr); | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="header"> | |
| <button class="btn btn-outline" id="exportBtn"><i class="fas fa-download"></i> Export</button> | |
| <button class="btn btn-outline" id="importBtn"><i class="fas fa-upload"></i> Import</button> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">Built with anycoder</a> | |
| </div> | |
| <div class="container"> | |
| <h1><i class="fas fa-brain"></i> Information Organizer</h1> | |
| <p class="description">Capture and organize your thoughts, ideas, and information. Everything saves automatically!</p> | |
| <div class="app-container"> | |
| <div class="input-section"> | |
| <div class="input-group"> | |
| <label for="noteTitle">Title</label> | |
| <input type="text" id="noteTitle" placeholder="Give your note a title"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="noteContent">Content</label> | |
| <textarea id="noteContent" placeholder="Write your thoughts, ideas, or information here..."></textarea> | |
| </div> | |
| <div class="input-group"> | |
| <label for="noteCategory">Category</label> | |
| <div class="categories"> | |
| <div class="category-tag active" data-category="general">General</div> | |
| <div class="category-tag" data-category="ideas">Ideas</div> | |
| <div class="category-tag" data-category="tasks">Tasks</div> | |
| <div class="category-tag" data-category="personal">Personal</div> | |
| <div class="category-tag" data-category="work">Work</div> | |
| </div> | |
| </div> | |
| <div class="input-group"> | |
| <label for="notePriority">Priority</label> | |
| <select id="notePriority"> | |
| <option value="low">Low</option> | |
| <option value="medium" selected>Medium</option> | |
| <option value="high">High</option> | |
| </select> | |
| </div> | |
| <button class="btn btn-primary" id="addNoteBtn"><i class="fas fa-plus"></i> Add Note</button> | |
| </div> | |
| <div class="view-section"> | |
| <div class="search-bar"> | |
| <input type="text" id="searchInput" placeholder="Search your notes..."> | |
| <button class="btn btn-outline" id="clearSearchBtn"><i class="fas fa-times"></i></button> | |
| </div> | |
| <div class="notes-container" id="notesContainer"> | |
| <!-- Notes will be dynamically added here --> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="stats-container"> | |
| <div class="stat-card"> | |
| <div class="stat-value" id="totalNotes">0</div> | |
| <div class="stat-label">Total Notes</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-value" id="generalNotes">0</div> | |
| <div class="stat-label">General</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-value" id="ideasNotes">0</div> | |
| <div class="stat-label">Ideas</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-value" id="tasksNotes">0</div> | |
| <div class="stat-label">Tasks</div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="notification" id="notification"> | |
| <i class="fas fa-check-circle"></i> | |
| <div>Note added successfully!</div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // DOM Elements | |
| const noteTitle = document.getElementById('noteTitle'); | |
| const noteContent = document.getElementById('noteContent'); | |
| const notePriority = document.getElementById('notePriority'); | |
| const addNoteBtn = document.getElementById('addNoteBtn'); | |
| const notesContainer = document.getElementById('notesContainer'); | |
| const searchInput = document.getElementById('searchInput'); | |
| const clearSearchBtn = document.getElementById('clearSearchBtn'); | |
| const categoryTags = document.querySelectorAll('.category-tag'); | |
| const notification = document.getElementById('notification'); | |
| const exportBtn = document.getElementById('exportBtn'); | |
| const importBtn = document.getElementById('importBtn'); | |
| const statElements = { | |
| total: document.getElementById('totalNotes'), | |
| general: document.getElementById('generalNotes'), | |
| ideas: document.getElementById('ideasNotes'), | |
| tasks: document.getElementById('tasksNotes') | |
| }; | |
| // Current category | |
| let currentCategory = 'general'; | |
| // Load notes from localStorage | |
| let notes = JSON.parse(localStorage.getItem('personalOrganizerNotes')) || []; | |
| // Initialize app | |
| function init() { | |
| renderNotes(); | |
| updateStats(); | |
| // Set up auto-save | |
| setupAutoSave(); | |
| // Set up category selection | |
| setupCategorySelection(); | |
| } | |
| // Set up auto-save for input fields | |
| function setupAutoSave() { | |
| const inputs = [noteTitle, noteContent, notePriority]; | |
| inputs.forEach(input => { | |
| // Load saved draft from localStorage | |
| const savedDraft = JSON.parse(localStorage.getItem('organizerDraft')) || {}; | |
| if (savedDraft[input.id]) { | |
| if (input.type === 'select-one') { | |
| input.value = savedDraft[input.id]; | |
| } else { | |
| input.value = savedDraft[input.id]; | |
| } | |
| } | |
| // Save on input change | |
| input.addEventListener('input', function() { | |
| saveDraft(); | |
| }); | |
| }); | |
| } | |
| // Save draft to localStorage | |
| function saveDraft() { | |
| const draft = { | |
| noteTitle: noteTitle.value, | |
| noteContent: noteContent.value, | |
| notePriority: notePriority.value | |
| }; | |
| localStorage.setItem('organizerDraft', JSON.stringify(draft)); | |
| } | |
| // Set up category selection | |
| function setupCategorySelection() { | |
| categoryTags.forEach(tag => { | |
| tag.addEventListener('click', function() { | |
| // Remove active class from all tags | |
| categoryTags.forEach(t => t.classList.remove('active')); | |
| // Add active class to clicked tag | |
| this.classList.add('active'); | |
| // Update current category | |
| currentCategory = this.getAttribute('data-category'); | |
| }); | |
| }); | |
| } | |
| // Add a new note | |
| function addNote() { | |
| const title = noteTitle.value.trim(); | |
| const content = noteContent.value.trim(); | |
| if (!title || !content) { | |
| showNotification('Please fill in both title and content', 'warning'); | |
| return; | |
| } | |
| const newNote = { | |
| id: Date.now(), | |
| title: title, | |
| content: content, | |
| category: currentCategory, | |
| priority: notePriority.value, | |
| createdAt: new Date().toISOString() | |
| }; | |
| notes.unshift(newNote); | |
| saveNotes(); | |
| renderNotes(); | |
| updateStats(); | |
| // Clear inputs | |
| noteTitle.value = ''; | |
| noteContent.value = ''; | |
| notePriority.value = 'medium'; | |
| // Update draft | |
| saveDraft(); | |
| showNotification('Note added successfully!', 'success'); | |
| } | |
| // Delete a note | |
| function deleteNote(id) { | |
| notes = notes.filter(note => note.id !== id); | |
| saveNotes(); | |
| renderNotes(); | |
| updateStats(); | |
| showNotification('Note deleted', 'danger'); | |
| } | |
| // Edit a note | |
| function editNote(id) { | |
| const note = notes.find(note => note.id === id); | |
| if (note) { | |
| noteTitle.value = note.title; | |
| noteContent.value = note.content; | |
| notePriority.value = note.priority; | |
| // Set category | |
| categoryTags.forEach(tag => { | |
| tag.classList.remove('active'); | |
| if (tag.getAttribute('data-category') === note.category) { | |
| tag.classList.add('active'); | |
| currentCategory = note.category; | |
| } | |
| }); | |
| showNotification('Note loaded for editing', 'success'); | |
| } | |
| // Save notes to localStorage | |
| function saveNotes() { | |
| localStorage.setItem('personalOrganizerNotes', JSON.stringify(notes)); | |
| } | |
| // Render notes to the DOM | |
| function renderNotes() { | |
| const searchTerm = searchInput.value.toLowerCase(); | |
| let filteredNotes = notes; | |
| if (searchTerm) { | |
| filteredNotes = notes.filter(note => | |
| note.title.toLowerCase().includes(searchTerm) || | |
| note.content.toLowerCase().includes(searchTerm) | |
| ); | |
| } | |
| if (filteredNotes.length === 0) { | |
| notesContainer.innerHTML = ` | |
| <div class="empty-state"> | |
| <i class="fas fa-sticky-note"></i> | |
| <p>No notes found. Add your first note to get started!</p> | |
| </div> | |
| `; | |
| return; | |
| } | |
| notesContainer.innerHTML = ''; | |
| filteredNotes.forEach(note => { | |
| const noteElement = document.createElement('div'); | |
| noteElement.className = 'note-card'; | |
| noteElement.innerHTML = ` | |
| <div class="note-header"> | |
| <div class="note-title">${note.title}</div> | |
| <div class="note-category">${note.category}</div> | |
| </div> | |
| <div class="note-content">${note.content}</div> | |
| <div class="note-meta"> | |
| <div>Priority: <span style="color: ${getPriorityColor(note.priority)}">${note.priority}</span></div> | |
| <div>${formatDate(note.createdAt)}</div> | |
| </div> | |
| <div class="note-actions"> | |
| <button class="action-btn edit-btn" data-id="${note.id}"><i class="fas fa-edit"></i> Edit</button> | |
| <button class="action-btn delete-btn" data-id="${note.id}"><i class="fas fa-trash"></i> Delete</button> | |
| </div> | |
| `; | |
| notesContainer.appendChild(noteElement); | |
| }); | |
| // Add event listeners to action buttons | |
| document.querySelectorAll('.edit-btn').forEach(btn => { | |
| btn.addEventListener('click', function() { | |
| const id = parseInt(this.getAttribute('data-id')); | |
| editNote(id); | |
| }); | |
| }); | |
| document.querySelectorAll('.delete-btn').forEach(btn => { | |
| btn.addEventListener('click', function() { | |
| const id = parseInt(this.getAttribute('data-id')); | |
| deleteNote(id); | |
| }); | |
| }); | |
| } | |
| // Update statistics | |
| function updateStats() { | |
| const total = notes.length; | |
| const general = notes.filter(note => note.category === 'general').length; | |
| const ideas = notes.filter(note => note.category === 'ideas').length; | |
| const tasks = notes.filter(note => note.category === 'tasks').length; | |
| statElements.total.textContent = total; | |
| statElements.general.textContent = general; | |
| statElements.ideas.textContent = ideas; | |
| statElements.tasks.textContent = tasks; | |
| } | |
| // Show notification | |
| function showNotification(message, type) { | |
| const icon = type === 'success' ? 'fa-check-circle' : | |
| type === 'warning' ? 'fa-exclamation-triangle' : 'fa-info-circle'; | |
| notification.innerHTML = ` | |
| <i class="fas ${icon}"></i> | |
| <div>${message}</div> | |
| `; | |
| notification.style.background = type === 'success' ? 'var(--success)' : | |
| type === 'warning' ? 'var(--warning)' : 'var(--danger)'; | |
| notification.style.color = type === 'warning' ? 'var(--dark)' : 'var(--light)'; | |
| notification.classList.add('show'); | |
| setTimeout(() => { | |
| notification.classList.remove('show'); | |
| }, 3000); | |
| } | |
| // Format date for display | |
| function formatDate(dateString) { | |
| const date = new Date(dateString); | |
| return date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}); | |
| } | |
| // Get color for priority | |
| function getPriorityColor(priority) { | |
| switch(priority) { | |
| case 'high': return '#f72585'; | |
| case 'medium': return '#f8961e'; | |
| case 'low': return '#4cc9f0'; | |
| default: return '#ffffff'; | |
| } | |
| } | |
| // Export notes as JSON file | |
| function exportNotes() { | |
| const dataStr = JSON.stringify(notes, null, 2); | |
| const dataBlob = new Blob([dataStr], {type: 'application/json'}); | |
| const url = URL.createObjectURL(dataBlob); | |
| const link = document.createElement('a'); | |
| link.href = url; | |
| link.download = 'personal-organizer-notes.json'; | |
| document.body.appendChild(link); | |
| link.click(); | |
| document.body.removeChild(link); | |
| URL.revokeObjectURL(url); | |
| showNotification('Notes exported successfully!', 'success'); | |
| } | |
| // Import notes from JSON file | |
| function importNotes() { | |
| const input = document.createElement('input'); | |
| input.type = 'file'; | |
| input.accept = '.json'; | |
| input.addEventListener('change', function() { | |
| const file = this.files[0]; | |
| if (!file) return; | |
| const reader = new FileReader(); | |
| reader.onload = function(e) { | |
| try { | |
| const importedNotes = JSON.parse(e.target.result); | |
| if (Array.isArray(importedNotes)) { | |
| notes = importedNotes; | |
| saveNotes(); | |
| renderNotes(); | |
| updateStats(); | |
| showNotification('Notes imported successfully!', 'success'); | |
| } else { | |
| showNotification('Invalid file format', 'danger'); | |
| } | |
| }; | |
| reader.readAsText(file); | |
| }); | |
| input.click(); | |
| } | |
| // Event Listeners | |
| addNoteBtn.addEventListener('click', addNote); | |
| searchInput.addEventListener('input', renderNotes); | |
| clearSearchBtn.addEventListener('click', function() { | |
| searchInput.value = ''; | |
| renderNotes(); | |
| }); | |
| exportBtn.addEventListener('click', exportNotes); | |
| importBtn.addEventListener('click', importNotes); | |
| // Initialize the application | |
| init(); | |
| }); | |
| </script> | |
| </body> | |
| </html> |