(function() { 'use strict'; /* --- Header scroll effect --- */ var header = document.getElementById('siteHeader'); var backTop = document.querySelector('.back-top'); var scrollThreshold = 40; function onScroll() { if (window.scrollY > scrollThreshold) { header.classList.add('scrolled'); } else { header.classList.remove('scrolled'); } if (backTop) { backTop.classList.toggle('visible', window.scrollY > 480); } } window.addEventListener('scroll', onScroll, { passive: true }); onScroll(); if (backTop) { backTop.addEventListener('click', function() { window.scrollTo({ top: 0, behavior: 'smooth' }); }); } /* --- Mobile menu --- */ var menuBtn = document.querySelector('.menu-btn'); var mobileMenu = document.getElementById('mobileMenu'); if (menuBtn && mobileMenu) { menuBtn.addEventListener('click', function() { var isOpen = mobileMenu.classList.toggle('open'); menuBtn.setAttribute('aria-expanded', String(isOpen)); var spans = menuBtn.querySelectorAll('span'); if (isOpen) { spans[0].style.transform = 'translateY(4px) rotate(45deg)'; spans[1].style.transform = 'translateY(-4px) rotate(-45deg)'; } else { spans[0].style.transform = ''; spans[1].style.transform = ''; } }); mobileMenu.querySelectorAll('a').forEach(function(link) { link.addEventListener('click', function() { mobileMenu.classList.remove('open'); menuBtn.setAttribute('aria-expanded', 'false'); var spans = menuBtn.querySelectorAll('span'); spans[0].style.transform = ''; spans[1].style.transform = ''; }); }); } /* --- Downloads use the same release feed as desktop updates. --- */ var updateFeedURL = 'https://api.gitcode.com/api/v5/repos/wendao-ai/wendao-ai-updates/raw/updates/stable.json'; var releasePageURL = 'https://gitcode.com/wendao-ai/wendao-ai-updates/releases'; function formatSize(bytes) { if (!Number.isFinite(bytes) || bytes <= 0) return ''; return Math.round(bytes / 1024 / 1024) + ' MB'; } function detectedPlatform() { var agent = navigator.userAgent || ''; if (/Windows/i.test(agent)) return { platform: 'windows', fallbackArch: 'amd64' }; if (/Macintosh|Mac OS X/i.test(agent)) return { platform: 'macos', fallbackArch: 'arm64' }; return null; } async function detectedPackageKey(packages) { var detected = detectedPlatform(); if (!detected) return ''; var arch = detected.fallbackArch; if (navigator.userAgentData && navigator.userAgentData.getHighEntropyValues) { try { var values = await navigator.userAgentData.getHighEntropyValues(['architecture']); if (/arm/i.test(values.architecture || '')) arch = 'arm64'; if (/x86|x64|amd64/i.test(values.architecture || '')) arch = 'amd64'; } catch (error) { // The platform fallback remains usable when the browser hides architecture. } } var key = detected.platform + '/' + arch; return packages[key] ? key : ''; } function setDownloadFailure() { var selectedLink = document.getElementById('downloadSelected'); if (selectedLink) selectedLink.setAttribute('href', releasePageURL); document.querySelectorAll('.js-download').forEach(function(link) { link.setAttribute('href', releasePageURL); }); var note = document.getElementById('downloadVersion'); if (note) note.textContent = '暂时无法获取最新版本,请前往发布页下载'; var extensionVersion = document.querySelector('[data-extension-version]'); if (extensionVersion) extensionVersion.textContent = '系统更新源暂时不可用,无法获取插件下载地址'; } async function loadDownloads() { try { var response = await fetch(updateFeedURL, { headers: { Accept: 'application/json' } }); if (!response.ok) throw new Error('HTTP ' + response.status); var feed = await response.json(); if (feed.product !== 'wendao-ai' || !feed.version || !feed.packages) throw new Error('Invalid update feed'); var browserExtensions = feed.browserExtensions; var extensionPackages = browserExtensions && browserExtensions.packages; ['chrome', 'edge', 'safari', 'firefox'].forEach(function(browser) { var link = document.querySelector('[data-extension-browser="' + browser + '"]'); var item = extensionPackages && extensionPackages[browser]; if (!link || !item || !/^https:\/\//.test(item.url || '')) return; link.setAttribute('href', item.url); link.removeAttribute('aria-disabled'); link.classList.remove('is-disabled'); var browserNames = { chrome: 'Chrome', edge: 'Edge', safari: 'Safari', firefox: 'Firefox' }; link.innerHTML = '下载 ' + browserNames[browser] + ' 版 ↓'; }); var extensionVersion = document.querySelector('[data-extension-version]'); if (extensionVersion) { extensionVersion.textContent = browserExtensions && browserExtensions.version ? '当前插件版本 v' + browserExtensions.version + ' \u00b7 支持 Chrome / Edge / Safari / Firefox' : '系统更新源暂未提供浏览器插件下载'; } var note = document.getElementById('downloadVersion'); var packageKey = await detectedPackageKey(feed.packages); var picker = document.getElementById('downloadPackage'); var selectedLink = document.getElementById('downloadSelected'); if (picker && packageKey) picker.value = packageKey; function applySelectedPackage() { var key = picker ? picker.value : packageKey; var selected = key && feed.packages[key]; var url = selected && /^https:\/\//.test(selected.url || '') ? selected.url : releasePageURL; var size = selected ? formatSize(Number(selected.size)) : ''; if (selectedLink) selectedLink.setAttribute('href', url); document.querySelectorAll('.js-download').forEach(function(link) { link.setAttribute('href', url); link.removeAttribute('download'); }); if (note) note.textContent = '当前版本 v' + feed.version + (size ? ' \u00b7 安装包 ' + size : '') + ' \u00b7 已选择 ' + picker.options[picker.selectedIndex].text; } if (picker) picker.addEventListener('change', applySelectedPackage); applySelectedPackage(); } catch (error) { setDownloadFailure(); } } loadDownloads(); /* Stable deep-link positioning for campaign previews and screenshot QA. */ if (new URLSearchParams(window.location.search).get('view') === 'workflow') { var workflowSection = document.getElementById('workflow'); if (workflowSection) { workflowSection.querySelectorAll('.reveal').forEach(function(item) { item.classList.add('visible'); }); var main = document.querySelector('main'); if (main) main.prepend(workflowSection); } } /* --- Product screenshot preview --- */ var screenDialog = document.getElementById('screenDialog'); if (screenDialog && typeof screenDialog.showModal === 'function') { var dialogImage = screenDialog.querySelector('img'); var dialogCaption = screenDialog.querySelector('figcaption'); var dialogClose = screenDialog.querySelector('.screen-dialog-close'); document.querySelectorAll('.js-screen-open').forEach(function(button) { button.addEventListener('click', function() { var source = button.getAttribute('data-screen') || ''; var caption = button.getAttribute('data-caption') || '文到AI真实产品界面'; if (dialogImage) { dialogImage.setAttribute('src', source); dialogImage.setAttribute('alt', caption); } if (dialogCaption) dialogCaption.textContent = caption; screenDialog.showModal(); }); }); if (dialogClose) dialogClose.addEventListener('click', function() { screenDialog.close(); }); screenDialog.addEventListener('click', function(event) { if (event.target === screenDialog) screenDialog.close(); }); } /* --- Scroll reveal --- */ if ('IntersectionObserver' in window && !window.matchMedia('(prefers-reduced-motion: reduce)').matches) { var revealItems = document.querySelectorAll('.reveal'); var observer = new IntersectionObserver(function(entries) { entries.forEach(function(entry) { if (entry.isIntersecting) { entry.target.classList.add('visible'); observer.unobserve(entry.target); } }); }, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' }); revealItems.forEach(function(item) { observer.observe(item); }); } else { document.querySelectorAll('.reveal').forEach(function(item) { item.classList.add('visible'); }); } /* --- Smooth scroll for anchor links --- */ document.querySelectorAll('a[href^="#"]').forEach(function(anchor) { anchor.addEventListener('click', function(e) { var targetId = this.getAttribute('href'); if (!targetId || targetId.charAt(0) !== '#' || targetId === '#') return; var target = document.querySelector(targetId); if (target) { e.preventDefault(); var headerHeight = header ? header.offsetHeight : 0; var targetPos = target.getBoundingClientRect().top + window.scrollY - headerHeight - 20; window.scrollTo({ top: targetPos, behavior: 'smooth' }); } }); }); })();