/** * 社区引导浮窗 — 适时提醒用户加群 & Star * * 触发条件(全部满足才弹出): * 1. 累计打开 ≥ 2 次 * 2. 首次打开距今 ≥ 1 天 * 3. 今天未关闭过(每天最多弹一次) * 4. 未被永久关闭 * 5. 由外部在"正向时机"主动调用 tryShow()(如保存配置成功、Gateway 启动成功) * 6. 不在聊天/助手页面时触发(避免打断对话) */ const KEYS = { firstOpen: 'clawpanel_first_open', openCount: 'clawpanel_open_count', lastShown: 'clawpanel_engage_shown', never: 'clawpanel_engage_never', todayDismiss: 'clawpanel_engage_today', } const DAY = 86400000 const MIN_OPENS = 2 const MIN_DAYS = 1 const COOLDOWN_DAYS = 1 const AUTO_DISMISS_MS = 25000 // 启动时记录打开次数 function _track() { const now = Date.now() if (!localStorage.getItem(KEYS.firstOpen)) { localStorage.setItem(KEYS.firstOpen, String(now)) } const count = parseInt(localStorage.getItem(KEYS.openCount) || '0') + 1 localStorage.setItem(KEYS.openCount, String(count)) } _track() function _todayKey() { const d = new Date() return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}` } function _canShow() { if (localStorage.getItem(KEYS.never) === '1') return false const count = parseInt(localStorage.getItem(KEYS.openCount) || '0') if (count < MIN_OPENS) return false const first = parseInt(localStorage.getItem(KEYS.firstOpen) || '0') if (Date.now() - first < MIN_DAYS * DAY) return false // 今天已经弹过/关闭过 → 不再弹 if (localStorage.getItem(KEYS.todayDismiss) === _todayKey()) return false // 避免在聊天/助手页面打断对话 const hash = location.hash || '' if (hash.includes('/chat') || hash.includes('/assistant')) return false return true } let _showing = false /** * 在正向时机调用(如 Gateway 启动成功、配置保存成功) * 满足条件才弹出,否则静默返回 */ export function tryShowEngagement() { if (_showing || !_canShow()) return if (document.querySelector('.engage-overlay')) return _showing = true localStorage.setItem(KEYS.lastShown, String(Date.now())) const shareText = '推荐一个开源的 OpenClaw 管理面板 — ClawPanel,一键搭建、便捷管理模型和 Agent,还内置 AI 助手帮你排查问题,小白也能轻松上手:https://claw.qt.cool' const overlay = document.createElement('div') overlay.className = 'engage-overlay' overlay.innerHTML = `
` document.body.appendChild(overlay) requestAnimationFrame(() => overlay.classList.add('engage-visible')) function dismiss(markToday = true) { if (markToday) localStorage.setItem(KEYS.todayDismiss, _todayKey()) overlay.classList.remove('engage-visible') setTimeout(() => { overlay.remove(); _showing = false }, 250) } overlay.addEventListener('click', (e) => { if (e.target === overlay) dismiss() }) overlay.querySelector('.engage-close').onclick = () => dismiss() overlay.querySelector('.engage-today-dismiss').onclick = () => dismiss(true) overlay.querySelector('[data-action="copy-share"]').onclick = () => { navigator.clipboard.writeText(shareText).then(() => { const desc = overlay.querySelector('[data-action="copy-share"] .engage-action-desc') if (desc) { desc.textContent = '✅ 已复制,去分享吧!'; setTimeout(() => { desc.textContent = '复制推荐文案,让更多人知道' }, 2000) } }) } } // 测试用:绕过条件直接弹出(浏览器控制台输入 __testEngagement()) window.__testEngagement = function() { _showing = false document.querySelector('.engage-overlay')?.remove() localStorage.removeItem(KEYS.never) localStorage.setItem(KEYS.openCount, '99') localStorage.setItem(KEYS.firstOpen, '0') localStorage.removeItem(KEYS.lastShown) tryShowEngagement() }