/* WA Dev Tools — Shared JS (sidebar, theme, tailwind config, categories) */ /* Tailwind config */ if (typeof tailwind !== 'undefined') { tailwind.config = { darkMode: 'class', theme: { extend: { fontFamily: { mono: ['JetBrains Mono', 'monospace'], sans: ['Manrope', 'sans-serif'], }, colors: { surface: { 900: '#060c18', 800: '#091020', 700: '#0d1828', 600: '#162040' }, accent: { DEFAULT: '#0054e6', dim: '#0043b8', bright: '#6b9fff' }, warn: '#ffd600', danger: '#ff5252', } } } }; } /* Categories */ const WA_CATEGORIES = [ { id: 'images', title: 'Изображения', description: 'Сжатие, редактирование и генерация', icon: '', tools: ['compress', 'placeholder', 'svgeditor', 'editor', 'video'] }, { id: 'code', title: 'Код', description: 'Форматирование, очистка и конвертация', icon: '', tools: ['formatter', 'sanitizer', 'converter'] }, { id: 'web', title: 'Веб', description: 'HTTP-клиент, парсер и анализ', icon: '', tools: ['parser', 'httpclient', 'redirects'] }, { id: 'utils', title: 'Утилиты', description: 'Пароли, Markdown и другие', icon: '', tools: ['password', 'md'] }, ]; /* Sidebar tools definition */ const WA_TOOLS = [ { id: 'home', path: '/dashboard', title: 'Главная', category: null, icon: '' }, // Изображения { id: 'compress', path: '/compress', title: 'Сжатие', category: 'images', icon: '' }, { id: 'placeholder', path: '/placeholder', title: 'Placeholder', category: 'images', icon: '' }, { id: 'svgeditor', path: '/svgeditor', title: 'SVG', category: 'images', icon: '' }, { id: 'editor', path: '/editor', title: 'Фото', category: 'images', icon: '' }, { id: 'video', path: '/video', title: 'Видео', category: 'images', icon: '' }, // Код { id: 'formatter', path: '/formatter', title: 'Formatter', category: 'code', icon: '' }, { id: 'sanitizer', path: '/sanitizer', title: 'Sanitizer', category: 'code', icon: '' }, { id: 'converter', path: '/converter', title: 'Converter', category: 'code', icon: '' }, // Веб { id: 'parser', path: '/parser', title: 'Parser', category: 'web', icon: '' }, { id: 'httpclient', path: '/httpclient', title: 'HTTP', category: 'web', icon: '' }, { id: 'redirects', path: '/redirects', title: 'Redirects', category: 'web', icon: '' }, // Утилиты { id: 'password', path: '/password', title: 'Пароли', category: 'utils', icon: '' }, { id: 'md', path: '/md', title: 'Markdown', category: 'utils', icon: '' }, // Admin { id: 'logs', path: '/logs', title: 'Логи', category: null, icon: '' }, ]; /* Build sidebar SVG icon */ function _svgIcon(innerPath) { return `${innerPath}`; } /* Inject sidebar into the page */ function initSidebar(activeId) { if (!activeId) { const path = window.location.pathname; const match = WA_TOOLS.find(t => t.path !== '/dashboard' && path.startsWith(t.path)); activeId = match ? match.id : 'home'; } // Build links grouped by category let linksHtml = ''; let lastCategory = '__none__'; for (const t of WA_TOOLS) { // Add category divider if (t.category !== lastCategory && t.category !== null && lastCategory !== '__none__') { linksHtml += ''; } lastCategory = t.category; const isActive = t.id === activeId ? ' active' : ''; linksHtml += `${_svgIcon(t.icon)}\n`; } const nav = document.createElement('nav'); nav.className = 'sidebar'; nav.innerHTML = ` `; document.body.prepend(nav); _updateThemeIcons(); _loadUser(); } /* Load user info for sidebar avatar */ async function _loadUser() { try { const res = await fetch('/auth/me'); if (!res.ok) return; const user = await res.json(); const avatar = document.getElementById('sidebarAvatar'); const container = document.getElementById('sidebarUser'); if (!avatar || !container) return; const initials = (user.name || user.email || '?').charAt(0).toUpperCase(); avatar.textContent = initials; avatar.title = user.name || user.email; container.style.display = 'block'; avatar.addEventListener('click', () => { if (confirm('Выйти из аккаунта?')) { window.location.href = '/auth/logout'; } }); } catch {} } /* Theme management */ function initTheme() { const html = document.documentElement; const saved = localStorage.getItem('theme'); if (saved === 'dark' || (!saved && window.matchMedia('(prefers-color-scheme: dark)').matches)) { html.classList.add('dark'); } else if (saved === '') { html.classList.remove('dark'); } document.addEventListener('click', (e) => { const toggle = e.target.closest('#themeToggle'); if (!toggle) return; const isDark = html.classList.toggle('dark'); localStorage.setItem('theme', isDark ? 'dark' : ''); _updateThemeIcons(); }); } function _updateThemeIcons() { const isDark = document.documentElement.classList.contains('dark'); document.querySelectorAll('.wa-sun-icon').forEach(el => el.style.display = isDark ? 'none' : 'block'); document.querySelectorAll('.wa-moon-icon').forEach(el => el.style.display = isDark ? 'block' : 'none'); } /* Auto-init on DOM ready */ document.addEventListener('DOMContentLoaded', () => { initSidebar(window.WA_TOOL_ID); }); /* Init theme immediately (before DOM ready to prevent flash) */ initTheme();