Spaces:
Running
Running
| ```html | |
| <html lang="it"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Applicazione Argomenti - Built with anycoder</title> | |
| <style> | |
| /* Modern CSS Reset and Variables */ | |
| :root { | |
| --primary-color: #4f46e5; | |
| --primary-dark: #4338ca; | |
| --secondary-color: #10b981; | |
| --danger-color: #ef4444; | |
| --warning-color: #f59e0b; | |
| --text-dark: #1f2937; | |
| --text-light: #6b7280; | |
| --bg-light: #f9fafb; | |
| --bg-white: #ffffff; | |
| --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); | |
| --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); | |
| --radius: 8px; | |
| --transition: all 0.3s ease; | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; | |
| line-height: 1.6; | |
| color: var(--text-dark); | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| min-height: 100vh; | |
| padding: 20px; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| } | |
| /* Header Styles */ | |
| .header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| background: var(--bg-white); | |
| padding: 1rem 2rem; | |
| border-radius: var(--radius); | |
| box-shadow: var(--shadow); | |
| margin-bottom: 2rem; | |
| } | |
| .header h1 { | |
| font-size: 1.8rem; | |
| font-weight: 700; | |
| color: var(--primary-color); | |
| } | |
| .built-with { | |
| color: var(--text-light); | |
| font-size: 0.9rem; | |
| text-decoration: none; | |
| transition: var(--transition); | |
| } | |
| .built-with:hover { | |
| color: var(--primary-color); | |
| text-decoration: underline; | |
| } | |
| /* Main Content */ | |
| .main-content { | |
| display: grid; | |
| grid-template-columns: 1fr 2fr; | |
| gap: 2rem; | |
| margin-bottom: 2rem; | |
| } | |
| @media (max-width: 768px) { | |
| .main-content { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| /* Sidebar */ | |
| .sidebar { | |
| background: var(--bg-white); | |
| border-radius: var(--radius); | |
| padding: 1.5rem; | |
| box-shadow: var(--shadow); | |
| } | |
| .sidebar h2 { | |
| font-size: 1.4rem; | |
| margin-bottom: 1rem; | |
| color: var(--text-dark); | |
| border-bottom: 2px solid var(--primary-color); | |
| padding-bottom: 0.5rem; | |
| } | |
| .category-list { | |
| list-style: none; | |
| } | |
| .category-item { | |
| padding: 0.75rem 1rem; | |
| margin-bottom: 0.5rem; | |
| background: var(--bg-light); | |
| border-radius: var(--radius); | |
| cursor: pointer; | |
| transition: var(--transition); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .category-item:hover { | |
| background: #e0e7ff; | |
| transform: translateX(5px); | |
| } | |
| .category-item.active { | |
| background: var(--primary-color); | |
| color: white; | |
| } | |
| .category-count { | |
| background: var(--text-light); | |
| color: white; | |
| padding: 0.25rem 0.5rem; | |
| border-radius: 20px; | |
| font-size: 0.8rem; | |
| } | |
| .category-item.active .category-count { | |
| background: rgba(255, 255, 255, 0.3); | |
| } | |
| /* Content Area */ | |
| .content-area { | |
| background: var(--bg-white); | |
| border-radius: var(--radius); | |
| padding: 2rem; | |
| box-shadow: var(--shadow); | |
| } | |
| .content-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 1.5rem; | |
| padding-bottom: 1rem; | |
| border-bottom: 1px solid #e5e7eb; | |
| } | |
| .content-header h2 { | |
| font-size: 1.5rem; | |
| color: var(--text-dark); | |
| } | |
| .add-btn { | |
| background: var(--primary-color); | |
| color: white; | |
| border: none; | |
| padding: 0.6rem 1.2rem; | |
| border-radius: var(--radius); | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: var(--transition); | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .add-btn:hover { | |
| background: var(--primary-dark); | |
| transform: translateY(-2px); | |
| } | |
| .topic-list { | |
| list-style: none; | |
| } | |
| .topic-item { | |
| padding: 1.5rem; | |
| margin-bottom: 1rem; | |
| background: var(--bg-light); | |
| border-radius: var(--radius); | |
| border-left: 4px solid var(--primary-color); | |
| transition: var(--transition); | |
| } | |
| .topic-item:hover { | |
| box-shadow: var(--shadow); | |
| transform: translateY(-2px); | |
| } | |
| .topic-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 0.75rem; | |
| } | |
| .topic-title { | |
| font-size: 1.2rem; | |
| font-weight: 600; | |
| color: var(--text-dark); | |
| } | |
| .topic-status { | |
| padding: 0.3rem 0.8rem; | |
| border-radius: 20px; | |
| font-size: 0.8rem; | |
| font-weight: 600; | |
| } | |
| .status-completed { | |
| background: #dcfce7; | |
| color: #166534; | |
| } | |
| .status-incomplete { | |
| background: #fef3c7; | |
| color: #92400e; | |
| } | |
| .status-problematic { | |
| background: #fee2e2; | |
| color: #991b1b; | |
| } | |
| .topic-description { | |
| color: var(--text-light); | |
| margin-bottom: 1rem; | |
| } | |
| .topic-progress { | |
| margin-bottom: 1rem; | |
| } | |
| .progress-bar { | |
| height: 8px; | |
| background: #e5e7eb; | |
| border-radius: 4px; | |
| overflow: hidden; | |
| } | |
| .progress-fill { | |
| height: 100%; | |
| background: var(--primary-color); | |
| border-radius: 4px; | |
| transition: width 0.5s ease; | |
| } | |
| .topic-actions { | |
| display: flex; | |
| gap: 0.5rem; | |
| } | |
| .action-btn { | |
| padding: 0.4rem 0.8rem; | |
| border: none; | |
| border-radius: var(--radius); | |
| cursor: pointer; | |
| font-size: 0.8rem; | |
| font-weight: 500; | |
| transition: var(--transition); | |
| } | |
| .edit-btn { | |
| background: #dbeafe; | |
| color: var(--primary-color); | |
| } | |
| .edit-btn:hover { | |
| background: #bfdbfe; | |
| } | |
| .complete-btn { | |
| background: #dcfce7; | |
| color: var(--secondary-color); | |
| } | |
| .complete-btn:hover { | |
| background: #bbf7d0; | |
| } | |
| .delete-btn { | |
| background: #fee2e2; | |
| color: var(--danger-color); | |
| } | |
| .delete-btn:hover { | |
| background: #fecaca; | |
| } | |
| /* Modal */ | |
| .modal { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0, 0, 0, 0.5); | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| z-index: 1000; | |
| opacity: 0; | |
| visibility: hidden; | |
| transition: var(--transition); | |
| } | |
| .modal.active { | |
| opacity: 1; | |
| visibility: visible; | |
| } | |
| .modal-content { | |
| background: var(--bg-white); | |
| width: 90%; | |
| max-width: 500px; | |
| border-radius: var(--radius); | |
| padding: 2rem; | |
| box-shadow: var(--shadow-lg); | |
| transform: translateY(-20px); | |
| transition: var(--transition); | |
| } | |
| .modal.active .modal-content { | |
| transform: translateY(0); | |
| } | |
| .modal-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 1.5rem; | |
| padding-bottom: 1rem; | |
| border-bottom: 1px solid #e5e7eb; | |
| } | |
| .modal-header h3 { | |
| font-size: 1.3rem; | |
| color: var(--text-dark); | |
| } | |
| .close-btn { | |
| background: none; | |
| border: none; | |
| font-size: 1.5rem; | |
| cursor: pointer; | |
| color: var(--text-light); | |
| transition: var(--transition); | |
| } | |
| .close-btn:hover { | |
| color: var(--danger-color); | |
| } | |
| .form-group { | |
| margin-bottom: 1.5rem; | |
| } | |
| .form-label { | |
| display: block; | |
| margin-bottom: 0.5rem; | |
| font-weight: 500; | |
| color: var(--text-dark); | |
| } | |
| .form-input, | |
| .form-select, | |
| .form-textarea { | |
| width: 100%; | |
| padding: 0.75rem; | |
| border: 1px solid #d1d5db; | |
| border-radius: var(--radius); | |
| font-family: inherit; | |
| font-size: 1rem; | |
| transition: var(--transition); | |
| } | |
| .form-input:focus, | |
| .form-select:focus, | |
| .form-textarea:focus { | |
| outline: none; | |
| border-color: var(--primary-color); | |
| box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1); | |
| } | |
| .form-textarea { | |
| resize: vertical; | |
| min-height: 100px; | |
| } | |
| .form-actions { | |
| display: flex; | |
| justify-content: flex-end; | |
| gap: 0.75rem; | |
| margin-top: 1.5rem; | |
| } | |
| .cancel-btn { | |
| background: var(--bg-light); | |
| color: var(--text-dark); | |
| border: none; | |
| padding: 0.75rem 1.5rem; | |
| border-radius: var(--radius); | |
| cursor: pointer; | |
| font-weight: 500; | |
| transition: var(--transition); | |
| } | |
| .cancel-btn:hover { | |
| background: #e5e7eb; | |
| } | |
| .save-btn { | |
| background: var(--primary-color); | |
| color: white; | |
| border: none; | |
| padding: 0.75rem 1.5rem; | |
| border-radius: var(--radius); | |
| cursor: pointer; | |
| font-weight: 500; | |
| transition: var(--transition); | |
| } | |
| .save-btn:hover { | |
| background: var(--primary-dark); | |
| } | |
| /* Empty State */ | |
| .empty-state { | |
| text-align: center; | |
| padding: 3rem 1rem; | |
| color: var(--text-light); | |
| } | |
| .empty-state-icon { | |
| font-size: 3rem; | |
| margin-bottom: 1rem; | |
| color: #d1d5db; | |
| } | |
| .empty-state h3 { | |
| font-size: 1.3rem; | |
| margin-bottom: 0.5rem; | |
| color: var(--text-dark); | |
| } | |
| /* Stats */ | |
| .stats { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
| gap: 1rem; | |
| margin-bottom: 2rem; | |
| } | |
| .stat-card { | |
| background: var(--bg-white); | |
| border-radius: var(--radius); | |
| padding: 1.5rem; | |
| box-shadow: var(--shadow); | |
| text-align: center; | |
| } | |
| .stat-value { | |
| font-size: 2rem; | |
| font-weight: 700; | |
| margin-bottom: 0.5rem; | |
| } | |
| .stat-label { | |
| color: var(--text-light); | |
| font-size: 0.9rem; | |
| } | |
| .stat-total { | |
| color: var(--primary-color); | |
| } | |
| .stat-completed { | |
| color: var(--secondary-color); | |
| } | |
| .stat-incomplete { | |
| color: var(--warning-color); | |
| } | |
| .stat-problematic { | |
| color: var(--danger-color); | |
| } | |
| /* Footer */ | |
| .footer { | |
| text-align: center; | |
| padding: 1.5rem; | |
| color: rgba(255, 255, 255, 0.8); | |
| font-size: 0.9rem; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <header class="header"> | |
| <h1>Gestione Argomenti</h1> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" class="built-with" target="_blank">Built with | |
| anycoder</a> | |
| </header> | |
| <div class="stats"> | |
| <div class="stat-card"> | |
| <div class="stat-value stat-total">0</div> | |
| <div class="stat-label">Argomenti Totali</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-value stat-completed">0</div> | |
| <div class="stat-label">Completati</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-value stat-incomplete">0</div> | |
| <div class="stat-label">Incompleti</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-value stat-problematic">0</div> | |
| <div class="stat-label">Problematici</div> | |
| </div> | |
| </div> | |
| <div class="main-content"> | |
| <aside class="sidebar"> | |
| <h2>Categorie</h2> | |
| <ul class="category-list"> | |
| <li class="category-item active" data-category="all"> | |
| <span>Tutti gli argomenti</span> | |
| <span class="category-count">0</span> | |
| </li> | |
| <li class="category-item" data-category="development"> | |
| <span>Sviluppo</span> | |
| <span class="category-count">0</span> | |
| </li> | |
| <li class="category-item" data-category="design"> | |
| <span>Design</span> | |
| <span class="category-count">0</span> | |
| </li> | |
| <li class="category-item" data-category="marketing"> | |
| <span>Marketing</span> | |
| <span class="category-count">0</span> | |
| </li> | |
| <li class="category-item" data-category="research"> | |
| <span>Ricerca</span> | |
| <span class="category-count">0</span> | |
| </li> | |
| <li class="category-item" data-category="other"> | |
| <span>Altro</span> | |
| <span class="category-count">0</span> | |
| </li> | |
| </ul> | |
| </aside> | |
| <main class="content-area"> | |
| <div class="content-header"> | |
| <h2>Argomenti da Completare</h2> | |
| <button class="add-btn" id="addTopicBtn"> | |
| <span>+</span> Nuovo Argomento | |
| </button> | |
| </div> | |
| <ul class="topic-list" id="topicList"> | |
| <!-- Topics will be dynamically added here --> | |
| <div class="empty-state"> | |
| <div class="empty-state-icon">📝</div> | |
| <h3>Nessun argomento trovato</h3> | |
| <p>Aggiungi il tuo primo argomento per iniziare</p> | |
| </div> | |
| </ul> | |
| </main> | |
| </div> | |
| <!-- Modal for adding/editing topics --> | |
| <div class="modal" id="topicModal"> | |
| <div class="modal-content"> | |
| <div class="modal-header"> | |
| <h3 id="modalTitle">Aggiungi Nuovo Argomento</h3> | |
| <button class="close-btn" id="closeModalBtn">×</button> | |
| </div> | |
| <form id="topicForm"> | |
| <div class="form-group"> | |
| <label for="topicTitle" class="form-label">Titolo Argomento</label> | |
| <input type="text" id="topicTitle" class="form-input" placeholder="Inserisci il titolo dell'argomento" required> | |
| </div> | |
| <div class="form-group"> | |
| <label for="topicCategory" class="form-label">Categoria</label> | |
| <select id="topicCategory" class="form-select"> | |
| <option value="development">Sviluppo</option> | |
| <option value="design">Design</option> | |
| <option value="marketing">Marketing</option> | |
| <option value="research">Ricerca</option> | |
| <option value="other">Altro</option> | |
| </select> | |
| </div> | |
| <div class="form-group"> | |
| <label for="topicDescription" class="form-label">Descrizione</label> | |
| <textarea id="topicDescription" class="form-textarea" placeholder="Descrivi l'argomento in dettaglio"></textarea> | |
| </div> | |
| <div class="form-group"> | |
| <label for="topicProgress" class="form-label">Progresso (%)</label> | |
| <input type="number" id="topicProgress" class="form-input" min="0" max="100" value="0"> | |
| </div> | |
| <div class="form-actions"> | |
| <button type="button" class="cancel-btn" id="cancelBtn">Annulla</button> | |
| <button type="submit" class="save-btn" id="saveBtn">Salva Argomento</button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| <footer class="footer"> | |
| <p>Applicazione per la gestione degli argomenti - Organizza e completa i tuoi progetti</p> | |
| </footer> | |
| </div> | |
| <script> | |
| // Application state | |
| let topics = []; | |
| let currentCategory = 'all'; | |
| let editingTopicId = null; | |
| // DOM Elements | |
| const topicList = document.getElementById('topicList'); | |
| const addTopicBtn = document.getElementById('addTopicBtn'); | |
| const topicModal = document.getElementById('topicModal'); | |
| const closeModalBtn = document.getElementById('closeModalBtn'); | |
| const cancelBtn = document.getElementById('cancelBtn'); | |
| const topicForm = document.getElementById('topicForm'); | |
| const modalTitle = document.getElementById('modalTitle'); | |
| const categoryItems = document.querySelectorAll('.category-item'); | |
| const statTotal = document.querySelector('.stat-total'); | |
| const statCompleted = document.querySelector('.stat-completed'); | |
| const statIncomplete = document.querySelector('.stat-incomplete'); | |
| const statProblematic = document.querySelector('.stat-problematic'); | |
| // Initialize the application | |
| function init() { | |
| // Load topics from localStorage if available | |
| const savedTopics = localStorage.getItem('topics'); | |
| if (savedTopics) { | |
| topics = JSON.parse(savedTopics); | |
| } | |
| // Add event listeners | |
| addTopicBtn.addEventListener('click', openAddModal); | |
| closeModalBtn.addEventListener('click', closeModal); | |
| cancelBtn.addEventListener('click', closeModal); | |
| topicForm.addEventListener('submit', saveTopic); | |
| // Add category selection listeners | |
| categoryItems.forEach(item => { | |
| item.addEventListener('click', () => { | |
| categoryItems.forEach(i => i.classList.remove('active')); | |
| item.classList.add('active'); | |
| currentCategory = item.dataset.category; | |
| renderTopics(); | |
| }); | |
| }); | |
| // Render initial state | |
| renderTopics(); | |
| updateStats(); | |
| } | |
| // Render topics based on current category | |
| function renderTopics() { | |
| const filteredTopics = currentCategory === 'all' | |
| ? topics | |
| : topics.filter(topic => topic.category === currentCategory); | |
| // Update category counts | |
| updateCategoryCounts(); | |
| if (filteredTopics.length === 0) { | |
| topicList.innerHTML = ` | |
| <div class="empty-state"> | |
| <div class="empty-state-icon">📝</div> | |
| <h3>Nessun argomento trovato</h3> | |
| <p>Aggiungi il tuo primo argomento per iniziare</p> | |
| </div> | |
| `; | |
| return; | |
| } | |
| topicList.innerHTML = filteredTopics.map(topic => { | |
| const status = getTopicStatus(topic); | |
| const statusText = getStatusText(status); | |
| const statusClass = `status-${status}`; | |
| return ` | |
| <li class="topic-item" data-id="${topic.id}"> | |
| <div class="topic-header"> | |
| <h3 class="topic-title">${topic.title}</h3> | |
| <span class="topic-status ${statusClass}">${statusText}</span> | |
| </div> | |
| <p class="topic-description">${topic.description || 'Nessuna descrizione fornita'}</p> | |
| <div class="topic-progress"> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" style="width: ${topic.progress}%"></div> | |
| </div> | |
| <div class="progress-text">Progresso: ${topic.progress}%</div> | |
| </div> | |
| <div class="topic-actions"> | |
| <button class="action-btn edit-btn" onclick="editTopic('${topic.id}')">Modifica</button> | |
| <button class="action-btn complete-btn" onclick="toggleComplete('${topic.id}')">${topic.progress === 100 ? 'Riapri' : 'Completa'}</button> | |
| <button class="action-btn delete-btn" onclick="deleteTopic('${topic.id}')">Elimina</button> | |
| </div> | |
| </li> | |
| `; | |
| }).join(''); | |
| } | |
| // Update category counts | |
| function updateCategoryCounts() { | |
| const counts = { | |
| all: topics.length, | |
| development: topics.filter(t => t.category === 'development').length, | |
| design: topics.filter(t => t.category === 'design').length, | |
| marketing: topics.filter(t => t.category === 'marketing').length, | |
| research: topics.filter(t => t.category === 'research').length, | |
| other: topics.filter(t => t.category === 'other').length | |
| }; | |
| categoryItems.forEach(item => { | |
| const category = item.dataset.category; | |
| const countElement = item.querySelector('.category-count'); | |
| countElement.textContent = counts[category]; | |
| }); | |
| } | |
| // Update statistics | |
| function updateStats() { | |
| const total = topics.length; | |
| const completed = topics.filter(t => t.progress === 100).length; | |
| const incomplete = topics.filter(t => t.progress < 100 && t.progress > 0).length; | |
| const problematic = topics.filter(t => t.progress === 0).length; | |
| statTotal.textContent = total; | |
| statCompleted.textContent = completed; | |
| statIncomplete.textContent = incomplete; | |
| statProblematic.textContent = problematic; | |
| } | |
| // Get topic status | |
| function getTopicStatus(topic) { | |
| if (topic.progress === 100) return 'completed'; | |
| if (topic.progress === 0) return 'problematic'; | |
| return 'incomplete'; | |
| } | |
| // Get status text | |
| function getStatusText(status) { | |
| const statusMap = { | |
| 'completed': 'Completato', | |
| 'incomplete': 'In Corso', | |
| 'problematic': 'Non Funziona' | |
| }; | |
| return statusMap[status]; | |
| } | |
| // Open modal for adding new topic | |
| function openAddModal() { | |
| editingTopicId = null; | |
| modalTitle.textContent = 'Aggiungi Nuovo Argomento'; | |
| topicForm.reset(); | |
| document.getElementById('topicProgress').value = 0; | |
| topicModal.classList.add('active'); | |
| } | |
| // Edit topic | |
| function editTopic(id) { | |
| const topic = topics.find(t => t.id === id); | |
| if (!topic) return; | |
| editingTopicId = id; | |
| modalTitle.textContent = 'Modifica Argomento'; | |
| document.getElementById('topicTitle').value = topic.title; | |
| document.getElementById('topicCategory').value = topic.category; | |
| document.getElementById('topicDescription').value = topic.description || ''; | |
| document.getElementById('topicProgress').value = topic.progress; | |
| topicModal.classList.add('active'); | |
| } | |
| // Save topic (add or edit) | |
| function saveTopic(e) { | |
| e.preventDefault(); | |
| const title = document.getElementById('topicTitle').value.trim(); | |
| const category = document.getElementById('topicCategory').value; | |
| const description = document.getElementById('topicDescription').value.trim(); | |
| const progress = parseInt(document.getElementById('topicProgress').value); | |
| if (!title) { | |
| alert('Il titolo è obbligatorio'); | |
| return; | |
| } | |
| if (editingTopicId) { | |
| // Update existing topic | |
| const topicIndex = topics.findIndex(t => t.id === editingTopicId); | |
| if (topicIndex !== -1) { | |
| topics[topicIndex] = { | |
| ...topics[topicIndex], | |
| title, | |
| category, | |
| description, | |
| progress | |
| }; | |
| } | |
| } else { | |
| // Add new topic | |
| const newTopic = { | |
| id: generateId(), | |
| title, | |
| category, | |
| description, | |
| progress, | |
| createdAt: new Date().toISOString() | |
| }; | |
| topics.push(newTopic); | |
| } | |
| // Save to localStorage | |
| localStorage.setItem('topics', JSON.stringify(topics)); | |
| // Update UI | |
| renderTopics(); | |
| updateStats(); | |
| closeModal(); | |
| } | |
| // Toggle complete status | |
| function toggleComplete(id) { | |
| const topicIndex = topics.findIndex(t => t.id === id); | |
| if (topicIndex === -1) return; | |
| topics[topicIndex].progress = topics[topicIndex].progress === 100 ? 0 : 100; | |
| // Save to localStorage | |
| localStorage.setItem('topics', JSON.stringify(topics)); | |
| // Update UI | |
| renderTopics(); | |
| updateStats(); | |
| } | |
| // Delete topic | |
| function deleteTopic(id) { | |
| if (!confirm('Sei sicuro di voler eliminare questo argomento?')) return; | |
| topics = topics.filter(t => t.id !== id); | |
| // Save to localStorage | |
| localStorage.setItem('topics', JSON.stringify(topics)); | |
| // Update UI | |
| renderTopics(); | |
| updateStats(); | |
| } | |
| // Close modal | |
| function closeModal() { | |
| topicModal.classList.remove('active'); | |
| editingTopicId = null; | |
| } | |
| // Generate unique ID | |
| function generateId() { | |
| return Date.now().toString(36) + Math.random().toString(36).substr(2); | |
| } | |
| // Initialize the application when DOM is loaded | |
| document.addEventListener('DOMContentLoaded', init); | |
| </script> | |
| </body> | |
| </html> | |
| ``` |