内容分四块: 1、产品规划产出 —— MCN 短视频整合营销工作台的①段五份(1a 需求/1b 竞品/1c 画像/1d 策略/1e 场景)、②段两份(2a 功能/2b 布局)、③段界面(DESIGN.md 契约与令牌表 + mcn-workbench.html 原型 + 实测/会诊/审查三份 + 23 张闸门截图)。 2、开源竞品调研 —— 5 个内容工作台项目的取证原始件与 1b 系列分析文档。 3、参考资料 —— 竞品视频抽帧 1145 张 + 2 个源视频 + 功能点截图。 4、机制侧 —— 协作脚本与状态台账、工作区记忆日志、抽帧/OCR 脚本。 .gitignore 只排运行时日志、脚本备份副本与一次性探针输出,其余按原样入库。
219 lines
9.3 KiB
JavaScript
219 lines
9.3 KiB
JavaScript
(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] + ' 版 <span class="arrow">↓</span>';
|
|
});
|
|
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' });
|
|
}
|
|
});
|
|
});
|
|
})();
|