// Логика переключения темы function initThemeToggle() { const themeToggleBtn = document.getElementById("theme-toggle-btn"); if (!themeToggleBtn) return; // Загружаем сохраненную тему или используем системную const savedTheme = localStorage.getItem("theme"); const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; const currentTheme = savedTheme || systemTheme; // Применяем тему applyTheme(currentTheme); // Обработчик клика на переключатель themeToggleBtn.addEventListener("click", () => { const currentTheme = document.documentElement.getAttribute("data-theme"); const newTheme = currentTheme === "dark" ? "light" : "dark"; applyTheme(newTheme); localStorage.setItem("theme", newTheme); }); // Слушаем изменения системной темы window .matchMedia("(prefers-color-scheme: dark)") .addEventListener("change", (e) => { if (!localStorage.getItem("theme")) { applyTheme(e.matches ? "dark" : "light"); } }); } function applyTheme(theme) { document.documentElement.setAttribute("data-theme", theme); // Обновляем meta теги для PWA const themeColorMeta = document.querySelector('meta[name="theme-color"]'); if (themeColorMeta) { themeColorMeta.setAttribute( "content", theme === "dark" ? "#1a1a1a" : "#007bff" ); } // Обновляем иконку переключателя const themeToggleBtn = document.getElementById("theme-toggle-btn"); if (themeToggleBtn) { const icon = themeToggleBtn.querySelector(".iconify"); if (icon) { icon.setAttribute( "data-icon", theme === "dark" ? "mdi:weather-sunny" : "mdi:weather-night" ); } } } // Инициализируем переключатель темы при загрузке страницы document.addEventListener("DOMContentLoaded", initThemeToggle); // Переменные для пагинации логов let logsOffset = 0; const logsLimit = 50; let hasMoreLogs = true; // DOM элементы для внешнего вида const settingsAccentColorInput = document.getElementById( "settings-accentColor" ); const updateAppearanceBtn = document.getElementById("updateAppearanceBtn"); // Проверка аутентификации async function checkAuthentication() { try { const response = await fetch("/api/auth/status"); if (!response.ok) { localStorage.removeItem("isAuthenticated"); localStorage.removeItem("username"); window.location.href = "/"; return false; } const authData = await response.json(); if (!authData.authenticated) { localStorage.removeItem("isAuthenticated"); localStorage.removeItem("username"); window.location.href = "/"; return false; } return true; } catch (error) { console.error("Ошибка проверки аутентификации:", error); return false; } } // Загрузка информации о пользователе для применения accent color и заполнения формы async function loadUserInfo() { try { const response = await fetch("/api/user"); if (response.ok) { const user = await response.json(); const accentColor = user.accent_color || "#007bff"; // Применяем цветовой акцент if ( getComputedStyle(document.documentElement) .getPropertyValue("--accent-color") .trim() !== accentColor ) { document.documentElement.style.setProperty( "--accent-color", accentColor ); } // Заполняем поле цветового акцента в настройках if (settingsAccentColorInput) { settingsAccentColorInput.value = accentColor; updateColorPickerSelection(accentColor); } } } catch (error) { console.error("Ошибка загрузки информации о пользователе:", error); } } // Функция для обновления выбора цвета в цветовой палитре function updateColorPickerSelection(selectedColor) { const colorOptions = document.querySelectorAll( "#appearance-tab .color-option" ); colorOptions.forEach((option) => { option.classList.remove("selected"); if (option.dataset.color === selectedColor) { option.classList.add("selected"); } }); } // Функция для показа сообщений function showSettingsMessage(message, type = "success") { const container = document.getElementById("settings-message-container"); if (container) { container.textContent = message; container.className = `message-container ${type}`; container.style.display = "block"; setTimeout(() => { container.style.display = "none"; }, 5000); } } // Переключение табов function initTabs() { const tabs = document.querySelectorAll(".settings-tab"); const contents = document.querySelectorAll(".tab-content"); tabs.forEach((tab) => { tab.addEventListener("click", () => { const tabName = tab.dataset.tab; // Убираем активный класс со всех табов и контентов tabs.forEach((t) => t.classList.remove("active")); contents.forEach((c) => c.classList.remove("active")); // Добавляем активный класс к выбранному табу и контенту tab.classList.add("active"); document.getElementById(`${tabName}-tab`).classList.add("active"); // Загружаем данные для таба if (tabName === "archive") { loadArchivedNotes(); } else if (tabName === "logs") { loadLogs(true); } else if (tabName === "appearance") { // Данные внешнего вида уже загружены в loadUserInfo() } }); }); } // Загрузка архивных заметок async function loadArchivedNotes() { const container = document.getElementById("archived-notes-container"); container.innerHTML = '
Загрузка...
'; try { const response = await fetch("/api/notes/archived"); if (!response.ok) { throw new Error("Ошибка загрузки архивных заметок"); } const notes = await response.json(); if (notes.length === 0) { container.innerHTML = 'Архив пуст
'; return; } container.innerHTML = ""; notes.forEach((note) => { const noteDiv = document.createElement("div"); noteDiv.className = "archived-note-item"; noteDiv.dataset.noteId = note.id; // Форматируем дату const created = new Date(note.created_at.replace(" ", "T") + "Z"); const dateStr = new Intl.DateTimeFormat("ru-RU", { day: "2-digit", month: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit", }).format(created); // Преобразуем markdown в HTML для предпросмотра const htmlContent = marked.parse(note.content); const preview = htmlContent.substring(0, 200) + (htmlContent.length > 200 ? "..." : ""); // Изображения let imagesHtml = ""; if (note.images && note.images.length > 0) { imagesHtml = `Ошибка загрузки архивных заметок
'; } } // Добавление обработчиков для архивных заметок function addArchivedNotesEventListeners() { // Восстановление document.querySelectorAll(".btn-restore").forEach((btn) => { btn.addEventListener("click", async (e) => { const noteId = e.target.closest("button").dataset.id; if (confirm("Восстановить эту заметку из архива?")) { try { const response = await fetch(`/api/notes/${noteId}/unarchive`, { method: "PUT", }); if (!response.ok) { throw new Error("Ошибка восстановления заметки"); } // Удаляем элемент из списка document.querySelector(`[data-note-id="${noteId}"]`)?.remove(); // Проверяем, остались ли заметки const container = document.getElementById("archived-notes-container"); if (container.children.length === 0) { container.innerHTML = 'Архив пуст
'; } alert("Заметка восстановлена!"); } catch (error) { console.error("Ошибка:", error); alert("Ошибка восстановления заметки"); } } }); }); // Окончательное удаление document.querySelectorAll(".btn-delete-permanent").forEach((btn) => { btn.addEventListener("click", async (e) => { const noteId = e.target.closest("button").dataset.id; if ( confirm("Удалить эту заметку НАВСЕГДА? Это действие нельзя отменить!") ) { try { const response = await fetch(`/api/notes/archived/${noteId}`, { method: "DELETE", }); if (!response.ok) { throw new Error("Ошибка удаления заметки"); } // Удаляем элемент из списка document.querySelector(`[data-note-id="${noteId}"]`)?.remove(); // Проверяем, остались ли заметки const container = document.getElementById("archived-notes-container"); if (container.children.length === 0) { container.innerHTML = 'Архив пуст
'; } alert("Заметка удалена окончательно"); } catch (error) { console.error("Ошибка:", error); alert("Ошибка удаления заметки"); } } }); }); } // Загрузка логов async function loadLogs(reset = false) { if (reset) { logsOffset = 0; hasMoreLogs = true; } const tbody = document.getElementById("logsTableBody"); const loadMoreContainer = document.getElementById("logsLoadMore"); const filterValue = document.getElementById("logTypeFilter").value; if (reset) { tbody.innerHTML = '