// API 配置(从 config.js 读取,部署 Pages 时请设置后端 Worker 地址) const API_BASE = typeof window !== 'undefined' && window.API_BASE !== undefined ? window.API_BASE : ''; // 初始数据(示例) let sites = [ { id: '1', name: '百度', url: 'https://www.baidu.com', description: '全球最大的中文搜索引擎', category: '常用', tags: ['搜索', '中文'] }, { id: '2', name: '知乎', url: 'https://www.zhihu.com', description: '中文互联网高质量的问答社区', category: '社交', tags: ['问答', '知识'] }, { id: '3', name: 'GitHub', url: 'https://github.com', description: '全球最大的代码托管平台', category: '工作', tags: ['代码', '开发'] }, { id: '4', name: 'Bilibili', url: 'https://www.bilibili.com', description: '中国年轻世代高度聚集的文化社区', category: '娱乐', tags: ['视频', '弹幕'] }, { id: '5', name: '淘宝', url: 'https://www.taobao.com', description: '亚洲最大的购物网站', category: '购物', tags: ['电商', '购物'] } ]; let deferredInstallPrompt = null; let installBtn = null; let hasRefreshing = false; function isStandaloneMode() { return window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone === true; } function createInstallButton() { if (installBtn) { return installBtn; } installBtn = document.createElement('button'); installBtn.className = 'install-btn'; installBtn.type = 'button'; installBtn.textContent = '📲 安装应用'; installBtn.style.cssText = ` position: fixed; bottom: 20px; right: 20px; background: linear-gradient(135deg, #10b981, #059669); color: #fff; border: none; padding: 12px 24px; border-radius: 50px; cursor: pointer; font-weight: 600; font-size: 0.95rem; box-shadow: 0 4px 15px rgba(16, 185, 129, 0.3); display: none; z-index: 1000; transition: all 0.2s ease; `; installBtn.addEventListener('mouseenter', () => { installBtn.style.transform = 'translateY(-2px)'; installBtn.style.boxShadow = '0 6px 20px rgba(16, 185, 129, 0.4)'; }); installBtn.addEventListener('mouseleave', () => { installBtn.style.transform = 'translateY(0)'; installBtn.style.boxShadow = '0 4px 15px rgba(16, 185, 129, 0.3)'; }); installBtn.addEventListener('click', async () => { if (!deferredInstallPrompt) { return; } deferredInstallPrompt.prompt(); const choice = await deferredInstallPrompt.userChoice; if (choice.outcome === 'accepted') { showToast('已触发安装流程'); } deferredInstallPrompt = null; installBtn.style.display = 'none'; }); document.body.appendChild(installBtn); return installBtn; } function initInstallPrompt() { const button = createInstallButton(); if (isStandaloneMode()) { button.style.display = 'none'; return; } window.addEventListener('beforeinstallprompt', (event) => { event.preventDefault(); deferredInstallPrompt = event; button.style.display = 'block'; }); window.addEventListener('appinstalled', () => { deferredInstallPrompt = null; button.style.display = 'none'; showToast('应用安装成功'); }); } async function registerServiceWorker() { if (!('serviceWorker' in navigator)) { return; } try { const registration = await navigator.serviceWorker.register('/sw.js', { scope: '/' }); if (registration.waiting) { promptRefresh(registration.waiting); } registration.addEventListener('updatefound', () => { const newWorker = registration.installing; if (!newWorker) { return; } newWorker.addEventListener('statechange', () => { if (newWorker.state === 'installed' && navigator.serviceWorker.controller) { promptRefresh(newWorker); } }); }); navigator.serviceWorker.addEventListener('controllerchange', () => { if (hasRefreshing) { return; } hasRefreshing = true; window.location.reload(); }); } catch (error) { console.error('Service Worker 注册失败:', error); } } function promptRefresh(worker) { const shouldRefresh = window.confirm('发现新版本,是否立即刷新?'); if (shouldRefresh) { worker.postMessage('SKIP_WAITING'); } } // 加载网站数据 async function loadSites() { try { const response = await fetch(`${API_BASE}/api/sites`); if (response.ok) { sites = await response.json(); updateStats(); renderSites(); } } catch (error) { console.error('加载网站数据失败:', error); // 使用默认数据 updateStats(); renderSites(); } } // 更新统计信息 function updateStats() { const totalSites = sites.length; const categories = [...new Set(sites.map(site => site.category))]; const allTags = sites.flatMap(site => site.tags || []); const uniqueTags = [...new Set(allTags)]; document.getElementById('total-sites').textContent = totalSites; document.getElementById('total-categories').textContent = categories.length; document.getElementById('total-tags').textContent = uniqueTags.length; // 更新分类过滤器 updateCategoryFilters(); } // 更新分类过滤器 function updateCategoryFilters() { const categoryFilters = document.getElementById('category-filters'); const categories = ['all', ...new Set(sites.map(site => site.category))]; categoryFilters.innerHTML = ''; categories.forEach(category => { const filterBtn = document.createElement('div'); filterBtn.className = 'category-filter'; filterBtn.textContent = category === 'all' ? '全部' : category; filterBtn.dataset.category = category; if (category === 'all') { filterBtn.classList.add('active'); } filterBtn.addEventListener('click', () => { document.querySelectorAll('.category-filter').forEach(btn => { btn.classList.remove('active'); }); filterBtn.classList.add('active'); filterSites(); closeCategorySidebar(); }); categoryFilters.appendChild(filterBtn); }); } // 渲染网站 function renderSites(filteredSites = null) { const container = document.getElementById('categories-container'); const searchInput = document.getElementById('search-input').value.toLowerCase(); const activeCategory = document.querySelector('.category-filter.active').dataset.category; // 如果没有传入过滤后的网站,则使用全部网站 const sitesToRender = filteredSites || sites; // 如果有搜索关键词,进一步过滤 let finalSites = sitesToRender; if (searchInput) { finalSites = sitesToRender.filter(site => site.name.toLowerCase().includes(searchInput) || (site.description && site.description.toLowerCase().includes(searchInput)) || (site.tags && site.tags.some(tag => tag.toLowerCase().includes(searchInput))) ); } // 如果有分类过滤 if (activeCategory !== 'all') { finalSites = finalSites.filter(site => site.category === activeCategory); } // 按分类分组 const sitesByCategory = {}; finalSites.forEach(site => { if (!sitesByCategory[site.category]) { sitesByCategory[site.category] = []; } sitesByCategory[site.category].push(site); }); // 如果没有网站匹配 if (Object.keys(sitesByCategory).length === 0) { container.innerHTML = `
尝试调整搜索关键词或分类筛选条件