diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/JS_Template.iml b/.idea/JS_Template.iml
new file mode 100644
index 0000000..3ad4ebd
--- /dev/null
+++ b/.idea/JS_Template.iml
@@ -0,0 +1,11 @@
+
+
No tasks to display
+ ${isCustomFilterActive ? '' : ''} + `; + tasksContainer.appendChild(noTasksMessage); + } +} + +/** + * Ініціалізація додатку після повного завантаження DOM + * + * DOMContentLoaded гарантує що всі HTML елементи доступні для маніпуляцій + */ +document.addEventListener('DOMContentLoaded', () => { + // Завантажуємо завдання та відображаємо їх + loadTasks(); + + // Відновлюємо збережені налаштування сортування + const sortBy = localStorage.getItem('sortBy') || 'date'; + sortTasks(sortBy); + + // Оновлюємо текст кнопки фільтру відповідно до збережених налаштувань + updateFilterButtonText(); + + // Реєструємо event listeners для різних елементів інтерфейсу + + // Обробка форми додавання/редагування завдань + document.getElementById('task-form').addEventListener('submit', saveTask); + + // Швидке додавання завдання через Enter у полі швидкого введення + document.getElementById('quick-task-input').addEventListener('keypress', (e) => { + if (e.key === 'Enter' && e.target.value.trim()) { + openPopup(); // Відкриваємо попап з попередньо заповненою назвою + } + }); + + // Зміна критерію сортування + document.getElementById('sort-select').addEventListener('change', (e) => { + sortTasks(e.target.value); + }); + + // Обробка форми кастомного фільтру + document.getElementById('custom-filter-form').addEventListener('submit', handleCustomFilterForm); + + // Оновлення інтерфейсу при зміні типу фільтру + document.getElementById('filter-date-type').addEventListener('change', updateFilter); + + // Обробник для кнопки очищення фільтру (якщо вона існує) + const clearFilterBtn = document.querySelector('.clear-filter-btn'); + if (clearFilterBtn) { + clearFilterBtn.addEventListener('click', clearFilter); + } +}); \ No newline at end of file diff --git a/src/style.css b/src/style.css new file mode 100644 index 0000000..57053de --- /dev/null +++ b/src/style.css @@ -0,0 +1,675 @@ +/* ГЛОБАЛЬНІ СТИЛІ */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + background-color: #f5f5f7; + color: #1d1d1f; + line-height: 1.4; +} + +/* ОСНОВНИЙ КОНТЕЙНЕР */ +.container { + max-width: 800px; + margin: 0 auto; + padding: 15px 12px; + display: flex; + flex-direction: column; + height: 100vh; +} + +/* ===== ФІКСОВАНИЙ ЗАГОЛОВОК ===== */ +.fixed-header { + flex-shrink: 0; +} + +h1 { + text-align: center; + font-size: 2.2rem; + font-weight: 700; + margin-bottom: 20px; + color: #1d1d1f; +} + +.add-task-section { + display: flex; + gap: 12px; + margin-bottom: 15px; +} + +.task-input { + flex: 1; + padding: 12px 16px; + border: 2px solid #e5e5e7; + border-radius: 12px; + font-size: 16px; + background: white; + outline: none; + transition: border-color 0.2s ease; +} + +.task-input:focus { + border-color: #007aff; +} + +.task-input::placeholder { + color: #86868b; +} + +.add-btn { + padding: 12px 20px; + background: white; + color: #1d1d1f; + border: 2px solid #e5e5e7; + border-radius: 12px; + font-size: 16px; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; + white-space: nowrap; +} + +.add-btn:hover { + border-color: #007aff; + background: #f9f9fb; +} + +/* Кнопка Analytics */ +.analytics-btn { + padding: 12px 20px; + background: white; + color: #1d1d1f; + border: 2px solid #e5e5e7; + border-radius: 12px; + font-size: 16px; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; + text-decoration: none; + display: inline-flex; + align-items: center; + gap: 8px; +} + +.analytics-btn:hover { + border-color: #007aff; + background: #f9f9fb; +} + +.controls { + display: flex; + justify-content: space-between; + margin-bottom: 15px; + gap: 20px; +} + +.control-group { + display: flex; + align-items: center; +} + +.control-group label { + display: none; +} + +.select { + padding: 10px 14px; + border: 2px solid #e5e5e7; + border-radius: 8px; + background: white; + font-size: 14px; + cursor: pointer; + min-width: 150px; + appearance: none; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e"); + background-position: right 12px center; + background-repeat: no-repeat; + background-size: 16px; + padding-right: 40px; +} + +.select:focus { + outline: none; + border-color: #007aff; +} + +.filter-btn { + padding: 10px 14px; + background: white; + color: #1d1d1f; + border: 2px solid #e5e5e7; + border-radius: 8px; + font-size: 14px; + cursor: pointer; + transition: all 0.2s ease; +} + +.filter-btn:hover { + border-color: #007aff; + background: #f9f9fb; +} + +.tasks-container { + background: white; + border-radius: 16px; + overflow-y: auto; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); + flex-grow: 1; + max-height: calc(100vh - 200px); + -webkit-overflow-scrolling: touch; +} + +.tasks-container::-webkit-scrollbar { + width: 8px; + background: transparent; +} + +.tasks-container::-webkit-scrollbar-track { + background: transparent; + margin: 16px 0; +} + +.tasks-container::-webkit-scrollbar-thumb { + background: #86868b; + border-radius: 4px; + border: 2px solid white; +} + +.tasks-container::-webkit-scrollbar-thumb:hover { + background: #6b7280; +} + +.task-item { + display: flex; + align-items: center; + padding: 12px 16px; + border-bottom: 1px solid #f2f2f7; + transition: background-color 0.2s ease; + min-height: 60px; +} + +.task-item:last-child { + border-bottom: none; +} + +.task-item:hover { + background-color: #f9f9fb; +} + +.task-checkbox { + width: 20px; + height: 20px; + border: 2px solid #d1d1d6; + border-radius: 50%; + margin-right: 12px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; +} + +.task-checkbox.completed { + background: white; + border-color: #34c759; +} + +.task-checkbox.completed::after { + content: '✓'; + color: #34c759; + font-size: 12px; + font-weight: bold; +} + +.task-content { + flex: 1; + display: flex; + flex-direction: column; + gap: 6px; + align-items: flex-start; +} + +.task-title { + font-size: 16px; + font-weight: 500; + color: #1d1d1f; + line-height: 1.3; +} + +.task-title.completed { + text-decoration: line-through; + color: #86868b; +} + +.task-priority { + display: inline-block; + padding: 2px 8px; + border-radius: 10px; + font-size: 10px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.3px; +} + +.priority-high { + background: #ff3b30; + color: white; +} + +.priority-medium { + background: #ff9500; + color: white; +} + +.priority-low { + background: #e5e5e7; + color: #86868b; +} + +.task-meta { + display: flex; + align-items: center; + gap: 12px; +} + +.task-date { + color: #86868b; + font-size: 12px; +} + +.task-actions { + display: flex; + gap: 6px; +} + +.action-btn { + width: 28px; + height: 28px; + border: none; + background: transparent; + cursor: pointer; + border-radius: 6px; + display: flex; + align-items: center; + justify-content: center; + transition: background-color 0.2s ease; +} + +.action-btn:hover { + background: #f2f2f7; +} + +.edit-btn::after { + content: '✏️'; + font-size: 12px; +} + +.delete-btn::after { + content: '🗑️'; + font-size: 12px; +} + +/* ===== POPUP ===== */ +.popup-overlay { + background: none; + border: none; + padding: 0; + max-width: none; + width: 100%; + height: 100%; +} + +.popup { + background: white; + border-radius: 20px; + padding: 32px; + width: 90%; + max-width: 500px; + margin: auto; + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15); +} + +.popup-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 24px; +} + +.popup-title { + font-size: 24px; + font-weight: 700; + color: #1d1d1f; +} + +.close-btn { + width: 32px; + height: 32px; + border: none; + background: transparent; + cursor: pointer; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 20px; + color: #86868b; + transition: background-color 0.2s ease; +} + +.close-btn:hover { + background: #f2f2f7; +} + +.form-group { + margin-bottom: 24px; +} + +.form-label { + display: block; + margin-bottom: 8px; + font-weight: 600; + color: #1d1d1f; + font-size: 16px; +} + +.form-input { + width: 100%; + padding: 16px; + border: 2px solid #e5e5e7; + border-radius: 12px; + font-size: 16px; + background: white; + outline: none; + transition: border-color 0.2s ease; +} + +.form-input:focus { + border-color: #007aff; +} + +.form-input::placeholder { + color: #86868b; +} + +.priority-options { + display: inline-flex; + gap: 16px; + margin-top: 8px; +} + +.priority-option { + display: flex; + align-items: center; + gap: 8px; + cursor: pointer; +} + +.priority-radio { + width: 20px; + height: 20px; + border: 2px solid #d1d1d6; + border-radius: 50%; + position: relative; + transition: all 0.2s ease; +} + +.priority-radio.selected { + border-color: #007aff; + background: #007aff; +} + +.priority-radio.selected::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 8px; + height: 8px; + background: white; + border-radius: 50%; +} + +.priority-label { + font-size: 16px; + color: #1d1d1f; +} + +.popup-actions { + display: flex; + gap: 12px; + justify-content: flex-end; +} + +.btn { + padding: 12px 24px; + border: none; + border-radius: 12px; + font-size: 16px; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; +} + +.btn-primary { + background: #007aff; + color: white; +} + +.btn-primary:hover { + background: #0056b3; +} + +.btn-secondary { + background: #f2f2f7; + color: #1d1d1f; +} + +.btn-secondary:hover { + background: #e5e5e7; +} + +.navigation { + display: flex; + justify-content: flex-start; + align-items: center; + margin-bottom: 20px; + gap: 12px; +} + +.stats-back-btn { + padding: 12px 20px; + background: white; + color: #1d1d1f; + border: 2px solid #e5e5e7; + border-radius: 12px; + font-size: 16px; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; + text-decoration: none; + display: inline-flex; + align-items: center; + gap: 8px; +} + +.stats-back-btn:hover { + border-color: #007aff; + background: #f9f9fb; +} + +.stats-bar { + background: white; + border-radius: 16px; + padding: 20px; + margin-bottom: 20px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); + display: grid; + grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); + gap: 16px; +} + +.stat-card { + text-align: center; + padding: 12px; + border-radius: 12px; + background: #f9f9fb; +} + +.stat-number { + font-size: 1.8rem; + font-weight: 700; + color: #007aff; +} + +.stat-label { + font-size: 12px; + color: #86868b; + margin-top: 4px; +} + +.view-controls { + background: white; + border-radius: 16px; + padding: 20px; + margin-bottom: 20px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); +} + +.view-controls h3 { + font-size: 18px; + font-weight: 600; + color: #1d1d1f; + margin-bottom: 16px; + text-align: center; +} + +.view-buttons { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); + gap: 12px; +} + +.stats-view-btn { + padding: 12px 16px; + background: white; + color: #1d1d1f; + border: 2px solid #e5e5e7; + border-radius: 12px; + font-size: 14px; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; + text-align: center; + position: relative; +} + +.stats-view-btn:hover { + border-color: #007aff; + background: #f9f9fb; +} + +.stats-view-btn.active { + background: #007aff; + color: white; + border-color: #007aff; +} + +.view-description { + font-size: 10px; + color: #86868b; + margin-top: 4px; + line-height: 1.2; +} + +.stats-view-btn.active .view-description { + color: rgba(255, 255, 255, 0.8); +} + +.pivot-wrapper { + background: white; + border-radius: 16px; + overflow: hidden; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); + flex-grow: 1; + min-height: 500px; +} + +#pivot-container { + width: 100%; + height: 100%; + min-height: 500px; + +} + +.wdr-toolbar-wrapper { + background: #f9f9fb !important; + border-bottom: 1px solid #e5e5e7 !important; + border-radius: 16px 16px 0 0 !important; +} + +.wdr-grid-container { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important; +} + +.wdr-grid-header { + background: #f9f9fb !important; + border-color: #e5e5e7 !important; +} + +.wdr-grid-cell { + border-color: #f2f2f7 !important; +} + +.wdr-grid-total { + background: #f2f2f7 !important; + font-weight: 600 !important; +} + +/* ===== АДАПТИВНІ СТИЛІ ===== */ +@media (max-width: 768px) { + h1 { + font-size: 2rem; + margin-bottom: 15px; + } + + .controls { + gap: 12px; + } + + .popup { + margin: 20px; + padding: 24px; + } + + .priority-options { + flex-direction: column; + gap: 12px; + } + + .navigation { + flex-direction: column; + align-items: stretch; + } + + .view-buttons { + grid-template-columns: 1fr; + } + + .view-controls { + padding: 16px; + } + + .container { + padding: 15px 8px; + } + + .stats-bar { + grid-template-columns: repeat(2, 1fr); + } +} \ No newline at end of file diff --git a/style/style.css b/style/style.css deleted file mode 100644 index e69de29..0000000