// ==UserScript== // @name 0.7.9珠宝AI 移动端适配 // @namespace https://zbai.art/ // @version 0.7.11 // @description 修复高阶模型生成误跳升级页与首页退出无效问题 // @author Codex // @match https://zbai.art/* // @match https://www.zbai.art/* // @match https://jew.haistudio.ai/* // @run-at document-start // @grant none // ==/UserScript== (function () { 'use strict'; const STYLE_ID = 'zbai-mobile-adapter-style'; const ROOT_ID = 'zbai-mobile-root'; const CLASS_READY = 'zbai-mobile-adapted'; const HOME_SHELL_ID = 'zbai-mobile-home-shell'; const WORK_DETAIL_FALLBACK_ID = 'zbai-mobile-work-detail-fallback'; const MOBILE_QUERY = '(max-width: 768px), (pointer: coarse), (max-device-width: 820px)'; const ASSETS_URL = '/index/mine-homepage'; const VERSION = '0.7.9'; const CLASS = { enabled: 'zbai-mobile-enabled', compose: 'zbai-mobile-compose-source', composeOpen: 'zbai-mobile-compose-open', formatChoice: 'zbai-mobile-format-choice', formatLabel: 'zbai-mobile-format-label', formatRow: 'zbai-mobile-format-row', duplicateTitle: 'zbai-mobile-duplicate-title', templateTextMode: 'zbai-mobile-template-text-mode', history: 'zbai-mobile-history-source', historyOpen: 'zbai-mobile-history-open', lock: 'zbai-mobile-lock', }; const EDITOR_ROOT_SELECTOR = '#pictureEditor'; const HOME_TOOL_ACTIONS = [ { key: 'image', label: '图片创作', eyebrow: 'Image', href: '/create/module/image', desc: '生成首饰海报、商品图和创意画面' }, { key: 'video', label: '视频创作', eyebrow: 'Video', href: '/create/module/video', desc: '制作运镜展示、旋转视频和短片素材' }, ]; const TEMPLATE_ACTIONS = [ { label: '珠宝海报', href: '/create/ai-effects/jewelry-poster', tag: '海报', desc: '快速生成东方美学商品海报' }, { label: '道具展示', href: '/create/ai-effects/jewelry-display', tag: '展示', desc: '为首饰匹配托盘、布景与道具' }, { label: '社交媒体图', href: '/create/ai-effects/social-media', tag: '种草', desc: '小红书、朋友圈风格内容图' }, { label: '大片模特', href: '/create/ai-effects/jewelry-models-display', tag: '模特', desc: '真人佩戴与商业大片画面' }, { label: '珠宝纯净图', href: '/create/ai-effects/jewelry-background', tag: '底图', desc: '白底、黑底和纯净背景图' }, { label: '精致摄影', href: '/create/ai-effects/finephotograph', tag: '摄影', desc: '高级光影、倒影和质感摄影' }, { label: '布料与珠宝', href: '/create/ai-effects/jewelry-cloth', tag: '布料', desc: '丝绸、天鹅绒等材质布景' }, { label: '珠宝多视角', href: '/create/ai-effects/jewelry-multiview', tag: '视角', desc: '多角度展示结构与细节' }, { label: '珠宝详情页', href: '/create/ai-effects/product-details-page', tag: '详情', desc: '电商详情页视觉图' }, { label: '珠宝视频', href: '/create/ai-effects/jewelry-360-display', tag: '视频', desc: '旋转展示与火彩展示视频' }, ]; window.__ZBAI_DEBUG__ = window.__ZBAI_DEBUG__ === true; window.__ZBAI_MOBILE_ADAPTER_VERSION__ = VERSION; window.__ZBAI_MOBILE_ADAPTER_MERGE__ = '0.7.5-ui+0.2.3-actions'; window.__ZBAI_MOBILE_ADAPTER_DIAGNOSE__ = collectDiagnostics; window.ZBAI_MOBILE_ADAPTER_DIAGNOSE = collectDiagnostics; const media = window.matchMedia(MOBILE_QUERY); let activeSurface = ''; let toastTimer = 0; let authRefreshScheduled = false; injectStyles(); waitForBody(boot); function boot() { if (document.getElementById(ROOT_ID)) return; const root = buildRoot(); document.body.append(root); syncMode(); installListeners(root); scheduleAuthRefreshes(); const observer = new MutationObserver(throttle(() => { syncMode(); }, 180)); observer.observe(document.body, { attributes: true, childList: true, subtree: true }); } function installListeners(root) { root.addEventListener('click', onRootClick); listenForModeChange(media); window.addEventListener('resize', throttle(syncMode, 180), { passive: true }); document.addEventListener('click', delayPromoteFloatingMenus, true); document.addEventListener('touchend', delayPromoteFloatingMenus, { capture: true, passive: true }); } function buildRoot() { const root = document.createElement('div'); root.id = ROOT_ID; root.innerHTML = `
移动适配已启用
`; return root; } function onRootClick(event) { const button = event.target.closest('[data-zbai-action]'); if (!button || !isMobile()) return; event.preventDefault(); event.stopPropagation(); const action = button.dataset.zbaiAction; if (action === 'close') closeSurface(); if (action === 'back') goBack(); if (action === 'compose') runGenerate(); if (action === 'upload') openUpload(); if (action === 'history') toggleHistory(); if (action === 'download') openDownload(); if (action === 'auth') toggleAuth(); } async function toggleCompose() { const panel = await waitForComposePanel(); if (!panel) { toast('还没找到生成面板,页面加载完再点一次'); return; } if (activeSurface === 'compose') { closeSurface(); return; } openSurface('compose', panel); focusPrompt(panel); } async function runGenerate() { const panel = await waitForComposePanel(); if (!panel) { toast('没找到立即创作按钮,请确认已进入创作页'); return; } // 先找按钮,再 openSurface(避免 openSurface 后 DOM 变化导致找错按钮) const generate = findGenerateButton(findComposePanel() || panel); if (!generate) { toast('没找到立即创作按钮,请确认已进入创作页'); return; } openSurface('compose', panel); // 点击前二次确认:防止 openSurface 后按钮失效或变化 const generate2 = findGenerateButton(findComposePanel() || panel) || generate; debugLog('runGenerate', { beforeCount: findResultImages().length, button: describeElement(generate2) }); if (!isRealGenerateButton(generate2) || isPaymentOrMembershipNode(generate2) || hasPaymentOrMembershipAncestor(generate2)) { debugLog('runGenerate:blockedPayment', describeElement(generate2)); toast('识别到会员升级区,已阻止误点'); return; } const beforeCount = findResultImages().length; activate(generate2); await waitForNewResultAfterGenerate(beforeCount); } async function openUpload() { const panel = await waitForComposePanel(); if (!panel) { toast('还没找到上传区,先进入图片创作页'); return; } openSurface('compose', panel); const imageMode = findModeToggle(panel, '图生'); if (imageMode) { activate(imageMode); await delay(360); await waitForImageUploadControl(panel); } const upload = findUploadControl(findComposePanel() || panel); if (!upload) { toast('没找到上传参考图按钮'); return; } upload.scrollIntoView({ block: 'center', behavior: 'smooth' }); activateUpload(upload); } async function toggleHistory() { const rail = await waitForHistoryRail(); if (!rail) { toast('当前创作页没有找到历史缩略图,可点右上角资产查看全部'); return; } if (activeSurface === 'history') { closeSurface(); return; } rail.classList.add(CLASS.history); openSurface('history', rail); rail.scrollIntoView({ block: 'nearest', inline: 'nearest' }); } async function openDownload() { closeSurface(); const detailDownload = document.querySelector(`#${WORK_DETAIL_FALLBACK_ID} [data-zbai-work-download]`); if (detailDownload) { activate(detailDownload); return; } const download = findDownloadControl(); if (download) { activate(download); return; } const result = findResultImages()[0] || findPrimaryResult(); if (!result) { toast('先打开或生成一张图片,再点下载'); return; } const hadPreview = hasVisiblePreviewModal(); const beforeUrl = location.href; activate(result); await delay(500); const previewDownload = findDownloadControl(); if (previewDownload) { activate(previewDownload); return; } if (!hadPreview && !hasVisiblePreviewModal() && location.href === beforeUrl) { toast('未能打开预览图'); return; } toast('预览已打开,请点预览里的下载图标'); } function openSurface(surface, node) { closeSurface(); activeSurface = surface; node.classList.add(surface === 'compose' ? CLASS.composeOpen : CLASS.historyOpen); if (surface === 'compose') node.scrollTop = 0; document.body.classList.add(CLASS.lock); document.getElementById(ROOT_ID)?.setAttribute('data-zbai-surface', surface); } function closeSurface() { activeSurface = ''; document.querySelector(`.${CLASS.composeOpen}`)?.classList.remove(CLASS.composeOpen); document.querySelector(`.${CLASS.historyOpen}`)?.classList.remove(CLASS.historyOpen); document.body?.classList.remove(CLASS.lock); document.getElementById(ROOT_ID)?.removeAttribute('data-zbai-surface'); } function goBack() { closeSurface(); let sameOriginReferrer = false; try { sameOriginReferrer = Boolean(document.referrer) && new URL(document.referrer).origin === window.location.origin; } catch (_) { sameOriginReferrer = false; } if (sameOriginReferrer && window.history.length > 1) { window.history.back(); return; } navigateTo('/'); } function refreshTargets() { if (!document.body) return; ensureViewport(); updatePageType(); syncLoginModalState(); refreshRoute(); refreshAuthControl(); if (!isMobile()) { closeSurface(); cleanupMobileHomeShell(); cleanupWorkDetailFallback(); return; } if (document.documentElement.dataset.zbaiPage === 'home') ensureMobileHomeShell(); else cleanupMobileHomeShell(); ensureWorkDetailFallback(); document.querySelector(EDITOR_ROOT_SELECTOR)?.classList.add(CLASS_READY); const compose = findComposePanel(); compose?.classList.add(CLASS.compose); markFormatControls(compose); markTemplateTextMode(compose); markDuplicateTitles(compose); findHistoryRail()?.classList.add(CLASS.history); promoteFloatingMenus(); if (window.__ZBAI_DEBUG__ === true) debugLog('refreshTargets', collectDiagnostics()); } function refreshRoute() { const root = document.getElementById(ROOT_ID); if (!root) return; root.dataset.zbaiRoute = findComposePanel() || isCreateRoute() ? 'compose' : 'page'; } function refreshAuthControl() { const button = document.querySelector(`#${ROOT_ID} .zbai-mobile-auth`); if (!button) return; const loggedIn = isLoggedIn(); button.textContent = loggedIn ? '退出' : '登录'; button.setAttribute('aria-label', loggedIn ? '退出登录' : '登录'); } function scheduleAuthRefreshes() { if (authRefreshScheduled) return; authRefreshScheduled = true; [300, 900, 1800, 3200, 5200, 8000].forEach((ms) => { window.setTimeout(() => { refreshAuthControl(); const shell = document.getElementById(HOME_SHELL_ID); if (shell) updateMobileHomeAuth(shell); if (ms === 8000) authRefreshScheduled = false; }, ms); }); } function syncMode() { const enabled = isMobile(); document.documentElement.dataset.zbaiMobile = enabled ? '1' : '0'; document.body?.classList.toggle(CLASS.enabled, enabled); if (!enabled) closeSurface(); refreshTargets(); } function listenForModeChange(query) { const onChange = () => syncMode(); if (typeof query.addEventListener === 'function') query.addEventListener('change', onChange); else query.addListener?.(onChange); } function delayPromoteFloatingMenus() { window.setTimeout(promoteFloatingMenus, 60); } function promoteFloatingMenus() { if (!isMobile() || !activeSurface) return; const menus = document.querySelectorAll([ '.ant-select-dropdown', '.ant-dropdown', '.arco-select-popup', '.el-select-dropdown', '[role="listbox"]', '[data-radix-popper-content-wrapper]', ].join(',')); [...menus].filter(isFloatingMenu).forEach((node) => { if (node.style.getPropertyValue('z-index') !== '2147483605') { node.style.setProperty('z-index', '2147483605', 'important'); } }); } function isFloatingMenu(node) { if (!node || node.closest?.(`#${ROOT_ID}`)) return false; const style = getComputedStyle(node); const rect = node.getBoundingClientRect(); const position = style.position === 'absolute' || style.position === 'fixed'; return position && rect.width > 0 && rect.height > 0 && style.display !== 'none' && style.visibility !== 'hidden'; } async function toggleAuth() { closeSurface(); if (isLoggedIn()) { await openLogout(); return; } openLogin(); } function openLogin() { document.documentElement.dataset.zbaiLoginOpen = '1'; document.documentElement.dataset.zbaiLoginRequestedAt = String(Date.now()); cleanupMobileHomeShell(); const login = findLoginButton(); if (!login) { delete document.documentElement.dataset.zbaiLoginOpen; delete document.documentElement.dataset.zbaiLoginRequestedAt; if (getPageType() === 'home') ensureMobileHomeShell(); toast('还没找到原站登录入口,刷新首页后再点'); debugLog('openLogin:missing', collectDiagnostics()); return; } debugLog('openLogin', describeElement(login)); activate(login); scheduleLoginStateCleanup(); scheduleAuthRefreshes(); } async function openLogout() { if (getPageType() === 'home') { // 首页展示原站 #root 以便找到菜单和退出按钮 document.documentElement.dataset.zbaiNativeMenuOpen = '1'; cleanupMobileHomeShell(); scheduleNativeMenuCleanup(); } let logout = findLogoutButton(); if (logout) { debugLog('openLogout:direct', describeElement(logout)); activate(logout); return; } const menu = findMobileMenuButton(); if (!menu) { toast('还没找到原站菜单入口,刷新首页后再点'); return; } debugLog('openLogout:menuButton', describeElement(menu)); activate(menu); await delay(520); const drawer = findOpenMobileDrawer(); logout = findLogoutButton(drawer || document); if (logout) { debugLog('openLogout:drawer', describeElement(logout)); activate(logout); return; } toast('账号菜单已打开,请点 Log Out'); } function scheduleLoginStateCleanup() { [1800, 2600, 4200, 7000].forEach((ms) => { window.setTimeout(() => { if (hasLoginModalDom()) { document.documentElement.dataset.zbaiLoginOpen = '1'; if (getPageType() === 'home') cleanupMobileHomeShell(); return; } if (!hasVisibleLoginModal()) { delete document.documentElement.dataset.zbaiLoginOpen; delete document.documentElement.dataset.zbaiLoginRequestedAt; if (isMobile() && getPageType() === 'home') ensureMobileHomeShell(); } }, ms); }); } function scheduleNativeMenuCleanup() { const cleanup = () => { if (!document.documentElement.dataset.zbaiNativeMenuOpen) return; const drawer = findOpenMobileDrawer(); if (drawer) { window.setTimeout(cleanup, 800); return; } delete document.documentElement.dataset.zbaiNativeMenuOpen; if (isMobile() && getPageType() === 'home') ensureMobileHomeShell(); }; [1200, 2200, 4500, 8000].forEach((ms) => window.setTimeout(cleanup, ms)); } function syncLoginModalState() { if (hasLoginModalDom()) { document.documentElement.dataset.zbaiLoginOpen = '1'; if (getPageType() === 'home') cleanupMobileHomeShell(); return; } cleanupStaleLoginState(); } function cleanupStaleLoginState() { if (document.documentElement.dataset.zbaiLoginOpen !== '1') return; if (hasVisibleLoginModal()) return; if (hasLoginModalDom()) return; const requestedAt = Number(document.documentElement.dataset.zbaiLoginRequestedAt || '0'); if (requestedAt && Date.now() - requestedAt < 2200) return; delete document.documentElement.dataset.zbaiLoginOpen; delete document.documentElement.dataset.zbaiLoginRequestedAt; } function hasVisibleLoginModal() { const modal = [ ...document.querySelectorAll([ '.LoginModal_LoginModal__O59AS', '[class*="LoginModal"]', '[class*="OverseasLogin_overseasLogin"]', '[class*="overseasLoginModal"]', '.fixed.top-0.left-0.w-screen.h-screen', ].join(',')), ].some((node) => node instanceof HTMLElement && isUsable(node)); if (modal) return true; const phone = document.querySelector('input#first-phone, input[placeholder*="请输入手机号码"]'); if (phone instanceof HTMLElement && isUsable(phone)) return true; return [...document.querySelectorAll('div, section, main')] .some((node) => { if (!(node instanceof HTMLElement) || !isUsable(node)) return false; const text = normalizedText(node); return text.includes('欢迎来到') && text.includes('珠宝AI') && (text.includes('手机号登录') || text.includes('邮箱登录') || text.includes('下一步')); }); } function hasLoginModalDom() { const modalSelectors = [ '.LoginModal_LoginModal__O59AS', '[class*="LoginModal"]', '[class*="OverseasLogin_overseasLogin"]', '[class*="overseasLoginModal"]', '.fixed.top-0.left-0.w-screen.h-screen', ].join(','); const phone = document.querySelector('input#first-phone, input[placeholder*="请输入手机号码"]'); if (phone instanceof HTMLElement) { const style = getComputedStyle(phone); if (style.display !== 'none' && style.visibility !== 'hidden') return true; } return [...document.querySelectorAll(modalSelectors)] .some((node) => { if (!(node instanceof HTMLElement)) return false; const style = getComputedStyle(node); if (style.display === 'none' || style.visibility === 'hidden') return false; const text = normalizedText(node); return text.includes('欢迎来到') && text.includes('珠宝AI') && (text.includes('手机号登录') || text.includes('邮箱登录') || text.includes('下一步')); }); } function isLoggedIn() { return Boolean(findProfileAvatar() || findLoggedInIndicator()); } function findProfileAvatar() { const candidates = document.querySelectorAll('img[src*="avatar" i], img[src*="profile" i], img[src*="head" i]'); return [...candidates].find((image) => { if (!isUsable(image)) return false; const rect = image.getBoundingClientRect(); const src = image.currentSrc || image.src || ''; const style = getComputedStyle(image); const avatarSource = /avatar|profile|head|default_profile_picture/i.test(src); const headerAvatarShape = rect.top < 120 && rect.right > window.innerWidth * 0.66 && rect.width >= 24 && rect.width <= 72 && rect.height >= 24 && rect.height <= 72 && style.cursor === 'pointer'; return avatarSource && headerAvatarShape; }); } function findLoggedInIndicator() { const candidates = document.querySelectorAll([ '[class*="VipCenterButton"]', '[class*="VipLevelButton"]', '[class*="UserInfo"]', '[class*="Avatar"]', '[class*="Profile"]', 'button', 'a', '[role="button"]', 'div', 'span', ].join(',')); return [...candidates] .filter((node) => node instanceof HTMLElement && !node.closest(`#${ROOT_ID}, #${HOME_SHELL_ID}`)) .find((node) => { const text = normalizedText(node); const className = String(node.className || ''); const looksLikeVip = /VipCenterButton|VipLevelButton|UserInfo|Avatar|Profile/i.test(className) && /升级|会员|旗舰版|专业版|标准版|基础版|高级版|企业版|个人|账户|我的|VIP/i.test(text || className); const visibleHeaderVip = isUsable(node) && node.getBoundingClientRect().top < 120 && /^(升级|会员中心|旗舰版|专业版|标准版|基础版|高级版|企业版|个人中心|我的|VIP)$/i.test(text); return looksLikeVip || visibleHeaderVip; }) || null; } function findAuthTextControl(pattern, scope, ancestorSelector) { return [...scope.querySelectorAll('button, a, [role="button"], [role="menuitem"], li, div, span')] .filter((node) => !node.closest(`#${ROOT_ID}, #${HOME_SHELL_ID}`)) .map((node) => { const text = normalizedText(node); if (text.length > 20 || !pattern.test(text) || !isUsable(node)) return null; return node.closest(ancestorSelector) || findClickableAncestor(node); }) .find(Boolean); } function findLoginButton() { return findAuthTextControl(/^(Log In|Login|Sign In|登录|登录\/注册|注册\/登录)$/i, document) || findAuthTextControl(/Log In|Login|Sign In|登录/i, document); } function findLogoutButton(scope) { const resolved = findAuthTextControl( /^(退出登录|退出账号|退出|Log Out|Logout|Sign Out)$/i, scope || document, '[class*="MobileActionBar_LoginButton"], button, a, [role="button"], div, span' ) || findAuthTextControl( /退出登录|退出账号|退出|Log Out|Logout|Sign Out/i, scope || document, '[class*="MobileActionBar_LoginButton"], button, a, [role="button"], div, span' ); if (resolved) return resolved; // span 标签需要向上找可点击父级 const span = [...(scope || document).querySelectorAll('span')] .filter((node) => node instanceof HTMLElement && !node.closest(`#${ROOT_ID}, #${HOME_SHELL_ID}`)) .find((node) => { const text = normalizedText(node); return text.length <= 20 && /^(退出登录|退出账号|退出|Log Out|Logout|Sign Out)$/i.test(text) && isUsable(node); }); return span instanceof HTMLElement ? (span.closest('button, a, [role="button"], div, [class*="MobileActionBar_LoginButton"]') || span) : null; } function findClickableAncestor(node) { return node?.closest?.('button, a, [role="button"], div') || node; } function findComposePanel() { const anchors = [ ...document.querySelectorAll('textarea'), ...document.querySelectorAll('input[type="file"]'), ...[...document.querySelectorAll('button, label, [role="button"], div, span')] .filter((node) => /上传|立即创作|开始创作/.test(normalizedText(node))), ]; for (const anchor of anchors) { const panel = walkParents(anchor, isComposePanel); if (panel) return panel; } const editorControl = document.querySelector('.picture-editor-content-control'); if (editorControl instanceof HTMLElement && isUsable(editorControl)) return editorControl; return null; } function isComposePanel(node) { if (!(node instanceof HTMLElement)) return false; const text = normalizedText(node); const hasGeneratorConfig = text.includes('选择模型') || text.includes('选择模板') || text.includes('选个风格'); const hasCreate = text.includes('立即创作') || text.includes('开始创作'); const hasPrompt = Boolean(findPromptInput(node)); const hasUpload = text.includes('上传') || Boolean(node.querySelector?.('input[type="file"]')); return hasGeneratorConfig && hasCreate && (hasUpload || hasPrompt); } function markFormatControls(panel) { if (!panel) return; const labels = [...panel.querySelectorAll('div, span, p, label')].filter((node) => normalizedText(node) === '多格式'); labels.forEach((label) => { label.classList.add(CLASS.formatLabel); const row = walkParents(label, (node) => isFormatRow(node, panel)); if (!row) return; row.classList.add(CLASS.formatRow); markFormatChoices(row); }); } function markTemplateTextMode(panel) { document.querySelectorAll(`.${CLASS.templateTextMode}`).forEach((node) => node.classList.remove(CLASS.templateTextMode)); if (!panel || !isTemplateRoute()) return; [...panel.querySelectorAll('button, a, label, [role="button"], div, span')] .filter((node) => node instanceof HTMLElement && normalizedText(node) === '文生' && isUsable(node)) .map((node) => node.closest('button, a, label, [role="button"]') || node) .filter((node) => node instanceof HTMLElement && !node.querySelector('textarea, input, .ant-upload, .ant-upload-btn')) .forEach((node) => node.classList.add(CLASS.templateTextMode)); } function isFormatRow(node, panel) { if (!node || node === panel) return false; const text = normalizedText(node); return text.includes('多格式') && text.includes('JPEG') && text.includes('PNG') && text.length <= 80; } function markFormatChoices(row) { [...row.querySelectorAll('button, label, div, span, p')] .filter((node) => /^(JPEG|PNG)$/.test(normalizedText(node))) .forEach((node) => { node.classList.add(CLASS.formatChoice); const parent = node.parentElement; if (parent && parent !== row && normalizedText(parent).length <= 20) { parent.classList.add(CLASS.formatChoice); } }); } function markDuplicateTitles(panel) { if (!panel) return; panel.querySelectorAll(`.${CLASS.duplicateTitle}`).forEach((node) => node.classList.remove(CLASS.duplicateTitle)); const titles = [...panel.querySelectorAll('.control-config-title, [class*="title" i], h1, h2, h3')] .filter((node) => node instanceof HTMLElement && isUsable(node)) .filter(isIndependentTitleNode) .filter((node) => { const text = normalizedText(node); return !/选择模型|选择模板|上传参考图|立即创作|开始创作/.test(text); }); titles.forEach((node) => { const text = normalizedText(node); if (/^(请上传图片|请上传首饰图|上传首饰图)$/.test(text) || /^请上传前/.test(text)) { node.classList.add(CLASS.duplicateTitle); } }); for (let i = 0; i < titles.length; i += 1) { for (let j = i + 1; j < titles.length; j += 1) { if (!rectsOverlap(titles[i].getBoundingClientRect(), titles[j].getBoundingClientRect())) continue; const firstText = normalizedText(titles[i]); const secondText = normalizedText(titles[j]); const firstUploadTitle = /^(请上传图片|请上传首饰图|上传首饰图)$/.test(firstText) || /^请上传前/.test(firstText); const secondUploadTitle = /^(请上传图片|请上传首饰图|上传首饰图)$/.test(secondText) || /^请上传前/.test(secondText); if (firstUploadTitle || secondUploadTitle) { (firstUploadTitle ? titles[i] : titles[j]).classList.add(CLASS.duplicateTitle); continue; } if (/Hi|你想创作|创作什么/.test(firstText) && /上传|图片/.test(secondText)) { titles[j].classList.add(CLASS.duplicateTitle); continue; } titles[j].classList.add(CLASS.duplicateTitle); } } } function markOverlappingTitles(panel) { markDuplicateTitles(panel); } function isIndependentTitleNode(node) { if (!(node instanceof HTMLElement)) return false; if (node.matches('button, a, label, textarea, input, [role="button"], [role="textbox"]')) return false; if (node.closest('button, a, label, [role="button"], .ant-upload, .ant-upload-btn')) return false; if (node.querySelector('textarea, input, button, a, label, [role="button"], .ant-upload, .ant-upload-btn')) return false; return true; } function rectsOverlap(a, b) { return a.width > 0 && a.height > 0 && b.width > 0 && b.height > 0 && a.left < b.right && a.right > b.left && a.top < b.bottom && a.bottom > b.top; } function findPromptInput(scope) { return scope?.querySelector('textarea[placeholder*="描述"], textarea[placeholder*="重绘"], textarea'); } function findUploadControl(scope) { if (!scope) return null; return [...scope.querySelectorAll('input[type="file"]')].find(isImageUploadInput) || findUploadTrigger(scope) || [...scope.querySelectorAll('[class*="upload" i]')].find((node) => isUsable(node) && /上传参考图|上传图片|添加图片/.test(normalizedText(node))); } async function waitForComposePanel() { const waits = [0, 180, 420, 800, 1300, 2100]; let fallback = null; for (const wait of waits) { if (wait) await delay(wait); const panel = findComposePanel(); if (!panel) continue; if (isReadyComposePanel(panel)) return panel; if (!fallback) fallback = panel; } return fallback; } function isReadyComposePanel(panel) { return Boolean(findPromptInput(panel) || findGenerateButton(panel) || findModeToggle(panel, '图生') || findUploadTrigger(panel) || [...panel.querySelectorAll('input[type="file"]')].some(isImageUploadInput)); } async function waitForImageUploadControl(panel) { const waits = [160, 300, 520, 820, 1200, 1800]; for (const wait of waits) { await delay(wait); if (findUploadControl(findComposePanel() || panel)) return true; } return false; } function findModeToggle(scope, text) { if (!scope) return null; return [...scope.querySelectorAll('button, a, label, [role="button"], div, span')] .filter((node) => normalizedText(node) === text && isUsable(node)) .map((node) => node.closest('button, a, label, [role="button"]') || node) .sort((a, b) => elementArea(a) - elementArea(b))[0] || null; } function findUploadTrigger(scope) { const input = [...scope.querySelectorAll('input[type="file"]')].find(isImageUploadInput); if (input) { const uploadParent = findUploadParent(input); if (uploadParent) return uploadParent; } return [...scope.querySelectorAll(['button','a','label','[role="button"]','.ant-upload','.ant-upload-btn','.upload-custom-button','[class*="CoverUpload" i]','div','span'].join(','))] .filter((node) => { const text = normalizedText(node); return isUsable(node) && /上传参考图|上传图片|添加图片/.test(text); }) .map((node) => node.closest('button, a, label, [role="button"], .ant-upload, .ant-upload-btn') || node) .sort((a, b) => elementArea(a) - elementArea(b))[0] || null; } function findUploadParent(input) { return input.closest?.('label, .ant-upload, .ant-upload-btn, button, [role="button"], [class*="CoverUpload" i]') || walkParents(input.parentElement, (node) => { if (!(node instanceof HTMLElement)) return false; if (node.matches?.('label, .ant-upload, .ant-upload-btn, button, [role="button"], [class*="CoverUpload" i]')) return true; const text = normalizedText(node); return text.includes('上传参考图') && elementArea(node) > 1; }); } function activateUpload(node) { if (!node) return false; let target = node; if (node instanceof HTMLInputElement && node.type === 'file') { target = findUploadParent(node) || node; } debugLog('activateUpload', describeElement(target)); try { target.scrollIntoView?.({ block: 'center', inline: 'center', behavior: 'auto' }); } catch (_) {} target.focus?.({ preventScroll: true }); target.click?.(); return true; } function isImageUploadInput(node) { if (!(node instanceof HTMLInputElement) || node.type !== 'file') return false; const accept = node.accept || ''; if (!accept) return true; return /image\/(jpeg|jpg|png|bmp|webp|heic)|\.(jpe?g|png|bmp|webp|heic)/i.test(accept); } function elementArea(node) { const rect = node.getBoundingClientRect(); return Math.max(1, Math.round(rect.width * rect.height)); } function findGenerateButton(scope) { const root = scope || document; const selectors = ['button','[role="button"]','.generate-button-container','.generate-button-container button', '.ControlBottom_controlBottom__gooOU','.ControlBottom_controlBottom__gooOU button','div','span'].join(','); const seen = new Set(); return [...root.querySelectorAll(selectors)] .filter((node) => /立即创作|开始创作|创作|生成/.test(normalizedText(node))) .map((node) => getGenerateClickTarget(node)) .filter((node) => { if (!(node instanceof HTMLElement) || seen.has(node)) return false; seen.add(node); return isRealGenerateButton(node); }) .map((node) => ({ node, score: scoreGenerateButton(node) })) .sort((a, b) => b.score - a.score)[0]?.node || null; } function isRealGenerateButton(node) { if (!(node instanceof HTMLElement) || node.closest(`#${ROOT_ID}, #${HOME_SHELL_ID}`)) return false; const text = normalizedText(node); if (!/立即创作|开始创作|创作|生成/.test(text)) return false; if (!isGenerateClickable(node)) return false; if (!hasComposeConfigContext(node)) return false; if (isPaymentOrMembershipNode(node)) return false; if (hasPaymentOrMembershipAncestor(node)) return false; if (isInsidePaymentOrMembershipArea(node)) return false; return isUsable(node); } function isPaymentOrMembershipNode(node) { const text = normalizedText(node); const className = String(node?.className || ''); if (!text && !className) return false; const compact = text.slice(0, 900); const hasPriceOrPlan = /开通|升级|续费|套餐|购买|支付|会员|¥|\/年|\/月|入门版|个人版|专业版|旗舰版|商业授权/.test(compact); const classLooksPaid = /vip|member|pay|payment|subscribe|subscription|price|pricing|plan|package/i.test(className); return hasPriceOrPlan || (classLooksPaid && /开通|升级|套餐|会员|¥|\/年|\/月/.test(compact)); } function hasPaymentOrMembershipAncestor(node) { let parent = node.parentElement; while (parent && parent !== document.body && parent.id !== 'root' && parent.id !== 'haimeta') { if (isGenerateScopeBoundary(parent)) return false; if (isPaymentOrMembershipNode(parent)) return true; parent = parent.parentElement; } return false; } function isGenerateScopeBoundary(node) { if (!(node instanceof HTMLElement)) return false; const className = String(node.className || ''); return /picture-editor-content-control|ControlBottom_controlBottom|control-config/.test(className); } function isInsidePaymentOrMembershipArea(node) { if (!(node instanceof HTMLElement)) return false; let parent = node.parentElement; while (parent && parent !== document.body && parent.id !== 'root' && parent.id !== 'haimeta') { if (isPaymentOrMembershipNode(parent)) return true; parent = parent.parentElement; } return false; } function getGenerateClickTarget(node) { if (!(node instanceof HTMLElement)) return null; if (node.matches('.generate-button-container, .ControlBottom_controlBottom__gooOU')) { return node.querySelector('button, [role="button"]') || node; } return node.closest('button, [role="button"]') || node.closest('.generate-button-container, .ControlBottom_controlBottom__gooOU') || node; } function isGenerateClickable(node) { if (!(node instanceof HTMLElement)) return false; if (node.matches('button, [role="button"]')) return true; if (node.closest('button, [role="button"]')) return true; if (node.matches('.generate-button-container, .ControlBottom_controlBottom__gooOU')) return true; const style = getComputedStyle(node); return style.cursor === 'pointer' && elementArea(node) >= 900; } function hasComposeConfigContext(node) { const context = walkParents(node, (parent) => { if (!(parent instanceof HTMLElement)) return false; if (isPaymentOrMembershipNode(parent) && !isGenerateScopeBoundary(parent)) return false; return hasComposeConfigSignal(parent) || isComposePanel(parent); }); return Boolean(context); } function hasComposeConfigSignal(node) { if (!(node instanceof HTMLElement)) return false; const text = normalizedText(node); return Boolean(node.querySelector?.('textarea, input[type="file"], .ant-upload, .ant-upload-btn')) || /选择模板|选择模型|选择尺寸|尺寸|张数|上传参考图|上传图片|添加图片|提示词|描述|参考图|多格式/.test(text); } function scoreGenerateButton(node) { const text = normalizedText(node); const rect = node.getBoundingClientRect(); let score = 0; if (/^(立即创作|开始创作)(\s*\d+)?$/.test(text)) score += 120; else if (/立即创作|开始创作/.test(text)) score += 90; else if (/^(创作|生成)(\s*\d+)?$/.test(text)) score += 48; else score += 24; if (/generate|ControlBottom|controlBottom/i.test(String(node.className || ''))) score += 28; if (rect.width >= 120 && rect.height >= 40) score += 16; score += Math.min(18, Math.round(elementArea(node) / 1800)); score += Math.round(rect.top / Math.max(1, window.innerHeight)) * 4; return score; } function findResultImages() { return [...document.images] .map((image) => ({ image, rect: image.getBoundingClientRect(), src: image.currentSrc || image.src || '' })) .filter(({ image, rect, src }) => { if (!isUsable(image)) return false; if (rect.width < 120 || rect.height < 120) return false; if (/logo|avatar|profile|placeholder|icon|ic_|input-bg|bg-/i.test(src)) return false; if (image.closest(`#${ROOT_ID}, #${HOME_SHELL_ID}, .picture-editor-header`)) return false; return true; }) .sort((a, b) => b.rect.width * b.rect.height - a.rect.width * a.rect.height) .map(({ image }) => image); } async function waitForNewResultAfterGenerate(beforeCount) { const waits = Array.from({ length: 40 }, (_, index) => index < 6 ? 800 : 1000); for (const wait of waits) { await delay(wait); const images = findResultImages(); if (images.length > beforeCount) { closeSurface(); revealResult(images[0]); return true; } const text = normalizedText(document.body); if (!/创作中|生成中|processing|creating/i.test(text) && images.length > 0) { closeSurface(); revealResult(images[0]); return true; } } return false; } function revealResult(node) { try { node?.scrollIntoView?.({ block: 'center', inline: 'center', behavior: 'smooth' }); } catch (_) { node?.scrollIntoView?.(); } } function focusPrompt(panel) { const prompt = findPromptInput(panel); if (!prompt) return; prompt.scrollIntoView({ block: 'center' }); prompt.focus({ preventScroll: true }); } function findHistoryRail() { const knownRails = [...document.querySelectorAll([ '.picture-editor-content-left-drawer', '.PictureEditorHistoryDrawer_container__fn3Ud', '.TaskSide_record__JuEDU', '[class*="History" i]', '[class*="record" i]', '[class*="Record" i]', '[class*="task" i]', '[class*="Task" i]', '[class*="drawer" i]', '[class*="Drawer" i]', ].join(','))] .filter((node) => node instanceof HTMLElement) .filter((node) => !node.closest(`#${ROOT_ID}, #${HOME_SHELL_ID}, .ant-drawer-body, [class*="MobileDrawer"]`)); for (const rail of knownRails) { if (hasHistoryItems(rail) && looksLikeHistoryRail(rail)) return rail; } const images = [...document.images].filter((image) => { const rect = image.getBoundingClientRect(); return rect.left < 160 && rect.width > 24 && rect.width < 130 && rect.height > 24; }); for (const image of images) { const rail = walkParents(image, (node) => { const rect = node.getBoundingClientRect(); const imageCount = node.querySelectorAll?.('img').length || 0; return imageCount >= 2 && rect.height > 220 && rect.width > 44 && rect.width < 190; }); if (rail && hasHistoryItems(rail)) return rail; } return null; } function hasHistoryItems(rail) { if (!rail) return false; const mediaItems = [...rail.querySelectorAll?.('img, canvas, video') || []] .filter((node) => { if (!(node instanceof HTMLElement)) return false; if (node instanceof HTMLCanvasElement) return node.width > 20 && node.height > 20; if (node instanceof HTMLVideoElement) return Boolean(node.currentSrc || node.src || node.poster); const src = node.currentSrc || node.src || ''; return Boolean(src) && !/logo|avatar|profile|placeholder|icon|ic_|input-bg|bg-/i.test(src); }); if (mediaItems.length > 0) return true; const linkItems = [...rail.querySelectorAll?.('a[href], [data-href], [data-url], [style*="background"]') || []] .filter((node) => { const signature = [node.getAttribute?.('href'), node.getAttribute?.('data-href'), node.getAttribute?.('data-url'), node.getAttribute?.('style')].join(' '); return /work-detail|image|img|oss|cos|cdn|\.jpe?g|\.png|\.webp|\.heic/i.test(signature); }); if (linkItems.length > 0) return true; const nodes = [...rail.querySelectorAll?.('div, button, a, li') || []]; return nodes.some((node) => { if (!(node instanceof HTMLElement)) return false; const style = getComputedStyle(node); const className = String(node.className || ''); const text = normalizedText(node); const hasBg = Boolean(style.backgroundImage && style.backgroundImage !== 'none'); const taskLike = /history|record|task|item|card|work/i.test(className) && (node.onclick || node.getAttribute('role') === 'button' || node.querySelector('img, canvas, video, a[href]')); return hasBg || taskLike || /已完成|生成|创作/.test(text) && elementArea(node) > 1200; }); } async function waitForHistoryRail() { let rail = findHistoryRail(); if (rail) return rail; const trigger = findHistoryTrigger(); if (trigger) { debugLog('history:wakeTrigger', describeElement(trigger)); activate(trigger); await delay(620); rail = findHistoryRail(); if (rail) return rail; } await delay(320); return findHistoryRail(); } function findHistoryTrigger() { const pattern = /^(历史|记录|任务|生成记录|创作记录|History|Record|Tasks?)$/i; return [...document.querySelectorAll('button, a, [role="button"], div, span, i')] .filter((node) => !node.closest(`#${ROOT_ID}, #${HOME_SHELL_ID}, .ant-drawer-body, [class*="MobileDrawer"]`)) .map((node) => findClickableAncestor(node)) .filter((node, index, list) => node instanceof HTMLElement && list.indexOf(node) === index) .find((node) => { if (!isUsable(node)) return false; const text = normalizedText(node); const label = [node.getAttribute('aria-label'), node.getAttribute('title'), String(node.className || '')].join(' '); return pattern.test(text) || /history|record|task/i.test(label); }) || null; } function looksLikeHistoryRail(rail) { if (!(rail instanceof HTMLElement)) return false; const className = String(rail.className || ''); if (/picture-editor-content-left-drawer|PictureEditorHistoryDrawer|TaskSide_record/i.test(className)) return true; const rect = rail.getBoundingClientRect(); const leftLike = rect.left <= Math.max(180, window.innerWidth * 0.48) || rect.width === 0; return leftLike && /History|history|record|Record|task|Task|drawer|Drawer/i.test(className); } function findDownloadControl() { const labeled = ['[title*="下载"]', '[aria-label*="下载"]', '[download]', '[class*="download" i]'].flatMap((selector) => [...document.querySelectorAll(selector)]); const byText = [...document.querySelectorAll('button, a, [role="button"], div, span')].filter((node) => normalizedText(node).includes('下载')); const byRightPreviewIcon = [...document.querySelectorAll('button, a, [role="button"], i, span')].filter(isLikelyPreviewDownload); return [...labeled, ...byText, ...byRightPreviewIcon].map((node) => findClickableAncestor(node)).find((node) => node instanceof HTMLElement && isUsable(node) && !node.closest(`#${ROOT_ID}, #${HOME_SHELL_ID}`) && !/上传|上传参考图|上传图片/.test(normalizedText(node))); } function findPrimaryResult() { return [...document.images].map((image) => ({ image, rect: image.getBoundingClientRect() })).filter(({ image, rect }) => { const src = image.currentSrc || image.src || ''; return isUsable(image) && rect.width > 150 && rect.height > 150 && !src.includes('logo') && !src.includes('bg-') && !image.closest(`#${ROOT_ID}, #${HOME_SHELL_ID}, .picture-editor-header`); }).sort((a, b) => b.rect.width * b.rect.height - a.rect.width * a.rect.height).map(({ image }) => image)[0]; } function isLikelyPreviewDownload(node) { const rect = node.getBoundingClientRect(); if (!isUsable(node) || rect.left < window.innerWidth * 0.62 || rect.top > window.innerHeight * 0.66) return false; const signature = [node.className, node.getAttribute('title'), node.getAttribute('aria-label'), node.innerHTML].join(' '); return /download|xiazai|icon-download||/i.test(signature) && !normalizedText(node).includes('上传'); } function hasVisiblePreviewModal() { return [...document.querySelectorAll(['.ant-modal','[class*="Preview"]','[class*="preview"]','[class*="Viewer"]','[class*="viewer"]','[class*="Modal"]','[class*="modal"]'].join(','))] .some((node) => { if (!(node instanceof HTMLElement) || node.closest(`#${ROOT_ID}, #${HOME_SHELL_ID}`)) return false; if (!isUsable(node)) return false; const text = normalizedText(node); if (/欢迎来到|手机号登录|邮箱登录|请输入手机号码/.test(text)) return false; const rect = node.getBoundingClientRect(); const hasLargeImage = [...node.querySelectorAll('img, canvas, video')].some((item) => { const itemRect = item.getBoundingClientRect(); return itemRect.width > 120 && itemRect.height > 120; }); return hasLargeImage && (rect.width > window.innerWidth * 0.45 || rect.height > window.innerHeight * 0.45); }); } function findClickableByText(scope, text) { if (!scope) return null; return [...scope.querySelectorAll('button, a, [role="button"]')].find((node) => normalizedText(node).includes(text) && isUsable(node)); } function walkParents(start, predicate) { let node = start; for (let depth = 0; node && depth < 18; depth += 1, node = node.parentElement) { if (predicate(node)) return node; } return null; } function normalizedText(node) { return (node?.innerText || node?.textContent || '').replace(/\s+/g, ' ').trim(); } function isUsable(node) { if (!node || node.closest?.(`#${ROOT_ID}`)) return false; const rect = node.getBoundingClientRect(); const style = getComputedStyle(node); return rect.width > 0 && rect.height > 0 && style.visibility !== 'hidden' && style.display !== 'none'; } function activate(node) { if (!node) return false; const target = node.closest?.('button, a, label, [role="button"], [role="menuitem"]') || node; debugLog('activate', describeElement(target)); try { target.scrollIntoView?.({ block: 'center', inline: 'center', behavior: 'auto' }); } catch (_) {} target.focus?.({ preventScroll: true }); target.click?.(); return true; } function debugLog(label, data) { if (window.__ZBAI_DEBUG__ !== true) return; console.debug('[ZBAI mobile]', label, data); } function collectDiagnostics() { const composePanel = findComposePanel(); const uploadControl = composePanel ? findUploadControl(composePanel) : null; const generateButton = findGenerateButton(composePanel || document); const historyRail = findHistoryRail(); const downloadButton = findDownloadControl(); const loginButton = findLoginButton(); const logoutButton = findLogoutButton(); const profileAvatar = findProfileAvatar(); const mobileMenuButton = findMobileMenuButton(); return { version: VERSION, href: window.location.href, pageType: document.documentElement.dataset.zbaiPage || getPageType(), mobile: isMobile(), activeSurface, found: { composePanel: !!composePanel, uploadControl: !!uploadControl, generateButton: !!generateButton, historyRail: !!historyRail, downloadButton: !!downloadButton, loginButton: !!loginButton, logoutButton: !!logoutButton, mobileMenuButton: !!mobileMenuButton, profileAvatar: !!profileAvatar, loggedIn: isLoggedIn() }, elements: { composePanel: describeElement(composePanel), uploadControl: describeElement(uploadControl), generateButton: describeElement(generateButton), historyRail: describeElement(historyRail), downloadButton: describeElement(downloadButton), loginButton: describeElement(loginButton), logoutButton: describeElement(logoutButton), mobileMenuButton: describeElement(mobileMenuButton), profileAvatar: describeElement(profileAvatar) }, }; } function describeElement(node) { if (!(node instanceof HTMLElement)) return null; const rect = node.getBoundingClientRect(); return { tag: node.tagName.toLowerCase(), id: node.id || '', className: String(node.className || '').slice(0, 120), text: normalizedText(node).slice(0, 80), ariaLabel: node.getAttribute('aria-label') || '', title: node.getAttribute('title') || '', rect: { x: Math.round(rect.x), y: Math.round(rect.y), width: Math.round(rect.width), height: Math.round(rect.height) } }; } function ensureMobileHomeShell() { let shell = document.getElementById(HOME_SHELL_ID); if (!shell) { shell = document.createElement('main'); shell.id = HOME_SHELL_ID; shell.innerHTML = `
珠宝AI
开始创作选择一个入口
模板功能点击即用
`; shell.addEventListener('click', handleHomeShellClick); document.body.appendChild(shell); } updateMobileHomeAuth(shell); renderMobileHomeActions(shell); } function cleanupMobileHomeShell() { document.getElementById(HOME_SHELL_ID)?.remove(); } function ensureWorkDetailFallback() { if (!isWorkDetailRoute()) { cleanupWorkDetailFallback(); return; } const imageUrl = getWorkDetailImageUrl(); if (!imageUrl) { cleanupWorkDetailFallback(); return; } let fallback = document.getElementById(WORK_DETAIL_FALLBACK_ID); if (!fallback) { fallback = document.createElement('section'); fallback.id = WORK_DETAIL_FALLBACK_ID; fallback.innerHTML = `
珠宝AI作品预览
`; fallback.querySelector('[data-zbai-work-back]')?.addEventListener('click', () => { if (window.history.length > 1) window.history.back(); else navigateTo(ASSETS_URL); }); fallback.querySelector('[data-zbai-work-download]')?.addEventListener('click', async () => { await downloadPreparedWorkDetail(fallback); }); document.body.appendChild(fallback); } const image = fallback.querySelector('img'); if (image && image.src !== imageUrl) image.src = imageUrl; if (fallback.dataset.sourceUrl !== imageUrl) { if (fallback.dataset.downloadUrl) URL.revokeObjectURL(fallback.dataset.downloadUrl); fallback.dataset.sourceUrl = imageUrl; delete fallback.dataset.downloadUrl; delete fallback.dataset.downloadName; prepareWorkDetailDownload(fallback, imageUrl); } } function cleanupWorkDetailFallback() { const fallback = document.getElementById(WORK_DETAIL_FALLBACK_ID); if (fallback?.dataset.downloadUrl) URL.revokeObjectURL(fallback.dataset.downloadUrl); fallback?.remove(); } function getWorkDetailImageUrl() { try { const url = new URL(location.href); return url.searchParams.get('url') || url.searchParams.get('imageUrl') || ''; } catch (_) { return ''; } } async function downloadImageUrl(url) { if (!url) { toast('没找到可下载的图片'); return; } try { const response = await fetch(url, { mode: 'cors', credentials: 'omit' }); if (!response.ok) throw new Error(`download ${response.status}`); const blob = await response.blob(); const objectUrl = URL.createObjectURL(blob); triggerDownload(objectUrl, `zbai-${Date.now()}.${guessImageExtension(blob.type, url)}`); window.setTimeout(() => URL.revokeObjectURL(objectUrl), 4000); return; } catch (_) { triggerDownload(url, `zbai-${Date.now()}.jpg`); window.open(url, '_blank', 'noopener'); } } async function prepareWorkDetailDownload(fallback, url) { try { const response = await fetch(url, { mode: 'cors', credentials: 'omit' }); if (!response.ok) throw new Error(`download ${response.status}`); const blob = await response.blob(); if (fallback.dataset.sourceUrl !== url) return; const objectUrl = URL.createObjectURL(blob); if (fallback.dataset.downloadUrl) URL.revokeObjectURL(fallback.dataset.downloadUrl); fallback.dataset.downloadUrl = objectUrl; fallback.dataset.downloadName = `zbai-${Date.now()}.${guessImageExtension(blob.type, url)}`; } catch (_) {} } async function downloadPreparedWorkDetail(fallback) { const preparedUrl = fallback?.dataset.downloadUrl; if (preparedUrl) { triggerDownload(preparedUrl, fallback.dataset.downloadName || `zbai-${Date.now()}.jpg`); return; } await downloadImageUrl(getWorkDetailImageUrl()); } function triggerDownload(url, filename) { const link = document.createElement('a'); link.href = url; link.download = filename; link.rel = 'noopener'; document.body.appendChild(link); link.click(); link.remove(); } function guessImageExtension(mimeType, url) { if (/png/i.test(mimeType)) return 'png'; if (/webp/i.test(mimeType)) return 'webp'; if (/gif/i.test(mimeType)) return 'gif'; const match = String(url || '').split('?')[0].match(/\.([a-z0-9]{3,5})$/i); return match?.[1] || 'jpg'; } function handleHomeShellClick(event) { const actionButton = event.target.closest('[data-home-action]'); if (actionButton) { event.preventDefault(); event.stopPropagation(); runHomeAction(actionButton.getAttribute('data-home-action')); return; } const toolButton = event.target.closest('[data-tool-key]'); if (toolButton) { event.preventDefault(); event.stopPropagation(); openHomeTool(toolButton.getAttribute('data-tool-key')); return; } const navButton = event.target.closest('[data-href]'); if (!navButton) return; event.preventDefault(); event.stopPropagation(); navigateTo(navButton.getAttribute('data-href')); } function updateMobileHomeAuth(shell) { const loggedIn = isLoggedIn(); const loginButton = shell.querySelector('[data-home-action="login"]'); const logoutButton = shell.querySelector('[data-home-action="logout"]'); if (loginButton) loginButton.hidden = loggedIn; if (logoutButton) logoutButton.hidden = !loggedIn; } function renderMobileHomeActions(shell) { const toolGrid = shell.querySelector('.zbai-mobile-tool-grid'); const templateGrid = shell.querySelector('.zbai-mobile-template-grid'); if (toolGrid && toolGrid.dataset.ready !== '1') { toolGrid.innerHTML = HOME_TOOL_ACTIONS.map((item) => ``).join(''); toolGrid.dataset.ready = '1'; } if (templateGrid && templateGrid.dataset.ready !== '1') { templateGrid.innerHTML = TEMPLATE_ACTIONS.map((item) => ``).join(''); templateGrid.dataset.ready = '1'; } } function runHomeAction(action) { if (action === 'login') { openLogin(); return; } if (action === 'logout') { openLogout(); return; } if (action === 'assets' || action === 'history') { navigateTo(ASSETS_URL); return; } if (action === 'menu') { activate(findMobileMenuButton()); } } function openHomeTool(key) { const action = HOME_TOOL_ACTIONS.find((item) => item.key === key); if (action) navigateTo(action.href); } function findOriginalMenuButton() { return findMobileMenuButton(); } function findMobileMenuButton() { const candidates = [...document.querySelectorAll('button, a, [role="button"], [aria-label], [title], i, span, div')] .filter((node) => node instanceof HTMLElement && !node.closest(`#${ROOT_ID}, #${HOME_SHELL_ID}`)) .map((node) => findClickableAncestor(node)) .filter((node, index, list) => node instanceof HTMLElement && list.indexOf(node) === index && isUsable(node)); const scored = candidates.map((node) => { const rect = node.getBoundingClientRect(); const text = normalizedText(node); const label = [node.getAttribute('aria-label'), node.getAttribute('title'), String(node.className || '')].join(' '); let score = 0; if (/^(☰|三|菜单|Menu)$/i.test(text) || /菜单|menu|hamburger|ic_menu|icon-menu/i.test(label)) score += 90; if (/iconfont/i.test(label) && /menu|caidan|drawer|nav/i.test(label)) score += 40; if (rect.left >= 0 && rect.left < 92 && rect.top >= 0 && rect.top < 96) score += 36; if (rect.width >= 20 && rect.width <= 64 && rect.height >= 20 && rect.height <= 64) score += 18; if (/Log In|Log Out|登录|退出|升级|资产|历史/.test(text)) score -= 80; return { node, score }; }).filter((item) => item.score > 45).sort((a, b) => b.score - a.score); return scored[0]?.node || null; } function findOpenMobileDrawer() { return [...document.querySelectorAll('.ant-drawer-body, [class*="MobileDrawer"]')] .find((node) => node instanceof HTMLElement && isUsable(node) && /Log Out|Logout|退出|升级|从这开始|图片创作|资产/.test(normalizedText(node))) || null; } function navigateTo(path) { if (!path) return; const target = new URL(path, window.location.origin).href; if (window.location.href === target) return; window.location.assign(target); } function escapeHtml(value) { return String(value).replace(/[&<>"']/g, (char) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[char])); } function toast(message) { const box = document.querySelector(`#${ROOT_ID} .zbai-mobile-toast`); if (!box) return; box.textContent = message; box.classList.add('is-visible'); window.clearTimeout(toastTimer); toastTimer = window.setTimeout(() => box.classList.remove('is-visible'), 2600); } function ensureViewport() { if (!isMobile()) return; let viewport = document.querySelector('meta[name="viewport"]'); if (!viewport) { viewport = document.createElement('meta'); viewport.name = 'viewport'; (document.head || document.documentElement).appendChild(viewport); } viewport.setAttribute('content', 'width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover'); } function getPageType() { if (location.pathname === ASSETS_URL) return 'assets'; if (isWorkDetailRoute()) return 'assets'; if (document.querySelector(EDITOR_ROOT_SELECTOR)) return 'editor'; if (isCreateRoute()) return 'editor'; return 'home'; } function updatePageType() { document.documentElement.dataset.zbaiPage = getPageType(); } function isCreateRoute() { return location.pathname.startsWith('/create/') || location.pathname.startsWith('/effects/'); } function isTemplateRoute() { return location.pathname.startsWith('/create/ai-effects/') || location.pathname.startsWith('/effects/'); } function isWorkDetailRoute() { return /\/(?:mobile\/)?work-detail/.test(location.pathname); } function isMobile() { const physicalWidth = Math.min(window.screen.width || window.innerWidth, window.screen.height || window.innerHeight); const hasTouch = navigator.maxTouchPoints > 0 || 'ontouchstart' in window; return media.matches || window.innerWidth <= 768 || (hasTouch && physicalWidth <= 820); } function delay(ms) { return new Promise((resolve) => window.setTimeout(resolve, ms)); } function throttle(callback, wait) { let timer = 0; return () => { if (timer) return; timer = window.setTimeout(() => { timer = 0; callback(); }, wait); }; } function waitForBody(callback) { if (document.body) { callback(); return; } let done = false; const run = () => { if (done || !document.body) return; done = true; window.clearInterval(timer); callback(); }; const timer = window.setInterval(run, 50); window.setTimeout(() => window.clearInterval(timer), 8000); document.addEventListener('DOMContentLoaded', run, { once: true }); window.addEventListener('load', run, { once: true }); } function injectStyles() { let style = document.getElementById(STYLE_ID); const shouldAppend = !style; if (!style) style = document.createElement('style'); style.id = STYLE_ID; style.textContent = ` @media (max-width: 768px), (pointer: coarse), (max-device-width: 820px) { html[data-zbai-mobile="1"], html[data-zbai-mobile="1"] body#haimeta { width:100vw !important; min-width:0 !important; min-height:100dvh !important; overflow-x:hidden !important; -webkit-text-size-adjust:100% !important; } html[data-zbai-mobile="1"][data-zbai-page="editor"], html[data-zbai-mobile="1"][data-zbai-page="editor"] body#haimeta { height:100dvh !important; overflow:hidden !important; overscroll-behavior:none !important; } html[data-zbai-mobile="1"] #haimeta *, html[data-zbai-mobile="1"] #haimeta *::before, html[data-zbai-mobile="1"] #haimeta *::after { box-sizing:border-box !important; } html[data-zbai-mobile="1"] img, html[data-zbai-mobile="1"] video, html[data-zbai-mobile="1"] canvas { opacity:1 !important; filter:none !important; -webkit-filter:none !important; mix-blend-mode:normal !important; background-blend-mode:normal !important; image-rendering:auto !important; } body.${CLASS.enabled}.${CLASS.lock} { overflow:hidden !important; } html[data-zbai-mobile="1"][data-zbai-page="editor"] #root, html[data-zbai-mobile="1"][data-zbai-page="editor"] .PageContainer_haimetaApp__qfjGd, html[data-zbai-mobile="1"][data-zbai-page="editor"] .PageContainer_indexContent__5aBHJ, html[data-zbai-mobile="1"][data-zbai-page="editor"] #pictureEditor { width:100vw !important; min-width:0 !important; max-width:100vw !important; height:100dvh !important; min-height:100dvh !important; overflow:hidden !important; } html[data-zbai-mobile="1"][data-zbai-page="editor"] #pictureEditor { display:flex !important; flex-direction:column !important; transform:none !important; margin:0 !important; left:0 !important; right:auto !important; } html[data-zbai-mobile="1"] .picture-editor-header { height:calc(52px + env(safe-area-inset-top, 0px)) !important; min-height:calc(52px + env(safe-area-inset-top, 0px)) !important; padding-top:env(safe-area-inset-top, 0px) !important; position:sticky !important; top:0 !important; z-index:80 !important; background:var(--Background-1-Normal, #f4f5fb) !important; } html[data-zbai-mobile="1"] #picture-editor-header { height:52px !important; min-height:52px !important; padding:0 10px !important; display:grid !important; grid-template-columns:minmax(0, 1fr) auto !important; align-items:center !important; gap:8px !important; } html[data-zbai-mobile="1"] .picture-editor-header .center { display:none !important; } html[data-zbai-mobile="1"] .picture-editor-header .left { width:auto !important; min-width:0 !important; max-width:100% !important; position:static !important; transform:none !important; overflow:hidden !important; } html[data-zbai-mobile="1"] .picture-editor-header .left img { max-height:30px !important; width:auto !important; } html[data-zbai-mobile="1"] .picture-editor-header .right { width:auto !important; min-width:0 !important; max-width:46vw !important; position:static !important; display:flex !important; align-items:center !important; justify-content:flex-end !important; gap:8px !important; overflow:hidden !important; } html[data-zbai-mobile="1"] .picture-editor-header .right .login-btn { white-space:nowrap !important; } html[data-zbai-mobile="1"] .picture-editor-header .right button { min-width:0 !important; height:32px !important; padding:0 10px !important; white-space:nowrap !important; } html[data-zbai-mobile="1"] .picture-editor-content { height:calc(100dvh - 52px - env(safe-area-inset-top, 0px)) !important; width:100vw !important; min-width:0 !important; display:flex !important; flex-direction:column !important; overflow:hidden !important; position:relative !important; transform:none !important; margin:0 !important; padding:0 !important; left:0 !important; right:auto !important; } html[data-zbai-mobile="1"] .picture-editor-content-left-drawer, html[data-zbai-mobile="1"] .PictureEditorHistoryDrawer_container__fn3Ud, html[data-zbai-mobile="1"] .TaskSide_record__JuEDU { display:none !important; } html[data-zbai-mobile="1"] .picture-editor-content-box { width:100vw !important; min-width:0 !important; height:100% !important; margin:0 !important; left:auto !important; right:auto !important; transform:none !important; display:flex !important; flex-direction:column !important; overflow:hidden !important; position:relative !important; } html[data-zbai-mobile="1"] .picture-editor-content-render { width:100vw !important; min-width:0 !important; flex:0 0 auto !important; height:38dvh !important; min-height:180px !important; max-height:42dvh !important; padding:6px 10px !important; margin:0 !important; left:0 !important; right:auto !important; transform:none !important; display:flex !important; align-items:center !important; justify-content:center !important; overflow:auto !important; -webkit-overflow-scrolling:touch !important; } html[data-zbai-mobile="1"] .picture-editor-content-render > * { max-width:100% !important; max-height:100% !important; } html[data-zbai-mobile="1"] .picture-editor-content-control { width:100vw !important; min-width:0 !important; max-width:100vw !important; flex:1 1 auto !important; height:auto !important; min-height:0 !important; margin:0 !important; left:0 !important; right:auto !important; transform:none !important; padding:12px 12px calc(92px + env(safe-area-inset-bottom, 0px)) !important; overflow-y:auto !important; -webkit-overflow-scrolling:touch !important; border-radius:18px 18px 0 0 !important; background:var(--Background-2-Normal, #f1f2f8) !important; box-shadow:0 -10px 30px rgba(20,24,38,0.08) !important; } html[data-zbai-mobile="1"] .PictureEditorControl_PictureEditorControl__T6FHN { width:100% !important; min-width:0 !important; height:auto !important; padding:0 !important; } html[data-zbai-mobile="1"] .control-config { width:100% !important; height:auto !important; display:flex !important; flex-direction:column !important; gap:12px !important; } html[data-zbai-mobile="1"] .control-config > div, html[data-zbai-mobile="1"] .option-need-margin { width:100% !important; margin:0 !important; } html[data-zbai-mobile="1"] .control-config-title { width:100% !important; height:auto !important; min-height:24px !important; margin:0 0 8px !important; line-height:24px !important; position:relative !important; z-index:1 !important; white-space:normal !important; word-break:keep-all !important; transform:none !important; translate:none !important; } html[data-zbai-mobile="1"] #multifunctional-input, html[data-zbai-mobile="1"] .MultifunctionalInput_multifunctionalInput__NHcuq, html[data-zbai-mobile="1"] .Input_input__A9sVA, html[data-zbai-mobile="1"] .input-box, html[data-zbai-mobile="1"] textarea.textarea-buttons, html[data-zbai-mobile="1"] textarea.ant-input { width:100% !important; min-width:0 !important; } html[data-zbai-mobile="1"] textarea.textarea-buttons, html[data-zbai-mobile="1"] textarea.ant-input { min-height:92px !important; max-height:160px !important; font-size:16px !important; line-height:1.45 !important; } html[data-zbai-mobile="1"] .MultifunctionalInput_multifunctionalInput__NHcuq .bg-1, html[data-zbai-mobile="1"] .MultifunctionalInput_multifunctionalInput__NHcuq .bg-2 { display:none !important; } html[data-zbai-mobile="1"] .ChooseModelWithDetails_ChooseModelWithDetails__m_Cbs, html[data-zbai-mobile="1"] .ChooseModelWithDetails_selectBox__HoIuc, html[data-zbai-mobile="1"] .ChooseModelWithDetails_selectItem__7NA37 { width:100% !important; min-height:56px !important; height:auto !important; } html[data-zbai-mobile="1"] .ChooseSizeBase_chooseSizeBase__KgHNI, html[data-zbai-mobile="1"] .choose-size-base-shape { width:100% !important; overflow-x:auto !important; overflow-y:hidden !important; display:flex !important; gap:8px !important; -webkit-overflow-scrolling:touch !important; scroll-snap-type:x proximity !important; } html[data-zbai-mobile="1"] .choose-size-base-shape > div, html[data-zbai-mobile="1"] .shape-item, html[data-zbai-mobile="1"] .shape-item .item { flex:0 0 64px !important; width:64px !important; height:60px !important; scroll-snap-align:start !important; } html[data-zbai-mobile="1"] .ControlBottom_controlBottom__gooOU, html[data-zbai-mobile="1"] .generate-button-container { width:100% !important; height:auto !important; margin-top:10px !important; position:relative !important; bottom:auto !important; z-index:2 !important; transform:none !important; box-shadow:none !important; background:var(--Background-2-Normal, #f1f2f8) !important; pointer-events:auto !important; touch-action:manipulation !important; } html[data-zbai-mobile="1"] .ChooseNumber_ChooseNumber__J1uo_, html[data-zbai-mobile="1"] .choose-number-content { width:100% !important; } html[data-zbai-mobile="1"] .choose-number-content { display:grid !important; grid-template-columns:auto minmax(120px, 1fr) !important; align-items:center !important; gap:12px !important; } html[data-zbai-mobile="1"] .choose-number-options { justify-self:end !important; width:min(160px, 48vw) !important; } html[data-zbai-mobile="1"] .generate-button-container, html[data-zbai-mobile="1"] .control-buttons { width:100% !important; min-height:50px !important; pointer-events:auto !important; touch-action:manipulation !important; } html[data-zbai-mobile="1"] .generate-button-container button { width:100% !important; min-height:52px !important; border-radius:16px !important; background:#11120d !important; color:#fff !important; box-shadow:0 14px 34px rgba(17,18,13,0.18) !important; font-size:15px !important; pointer-events:auto !important; touch-action:manipulation !important; } html[data-zbai-mobile="1"] .fixed.top-0.left-0.w-screen.h-screen { padding:env(safe-area-inset-top, 0px) 12px env(safe-area-inset-bottom, 0px) !important; align-items:center !important; } html[data-zbai-mobile="1"] .LoginModal_LoginModal__O59AS, html[data-zbai-mobile="1"] [class*="LoginModal"], html[data-zbai-mobile="1"] [class*="OverseasLogin_overseasLogin"], html[data-zbai-mobile="1"] [class*="overseasLoginModal"] { width:calc(100vw - 24px) !important; max-width:420px !important; min-width:0 !important; max-height:calc(100dvh - 48px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)) !important; overflow-y:auto !important; border-radius:18px !important; } html[data-zbai-mobile="1"][data-zbai-login-open="1"] .fixed.top-0.left-0.w-screen.h-screen, html[data-zbai-mobile="1"][data-zbai-login-open="1"] .LoginModal_LoginModal__O59AS, html[data-zbai-mobile="1"][data-zbai-login-open="1"] [class*="LoginModal"], html[data-zbai-mobile="1"][data-zbai-login-open="1"] [class*="OverseasLogin_overseasLogin"], html[data-zbai-mobile="1"][data-zbai-login-open="1"] [class*="overseasLoginModal"] { display:flex !important; visibility:visible !important; opacity:1 !important; pointer-events:auto !important; } html[data-zbai-mobile="1"][data-zbai-page="home"] #root { display:none !important; } html[data-zbai-mobile="1"][data-zbai-page="home"][data-zbai-login-open="1"] #root { display:block !important; } html[data-zbai-mobile="1"][data-zbai-page="home"][data-zbai-login-open="1"] #${HOME_SHELL_ID} { display:none !important; } html[data-zbai-mobile="1"][data-zbai-page="home"][data-zbai-native-menu-open="1"] #root { display:block !important; } html[data-zbai-mobile="1"][data-zbai-page="home"][data-zbai-native-menu-open="1"] #${HOME_SHELL_ID} { display:none !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} { display:block !important; position:fixed !important; inset:0 !important; z-index:10025 !important; width:100vw !important; height:100dvh !important; min-height:100dvh !important; padding:calc(12px + env(safe-area-inset-top, 0px)) 10px calc(86px + env(safe-area-inset-bottom, 0px)) !important; background:linear-gradient(180deg, #fbfaf8 0%, #eef2f6 100%) !important; color:#111318 !important; overflow-x:hidden !important; overflow-y:auto !important; scroll-padding-bottom:calc(86px + env(safe-area-inset-bottom, 0px)) !important; overscroll-behavior-y:contain !important; box-sizing:border-box !important; font-family:-apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif !important; -webkit-overflow-scrolling:touch !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} * { box-sizing:border-box !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-topbar { display:grid !important; grid-template-columns:34px minmax(0, 1fr) auto !important; align-items:center !important; gap:8px !important; min-height:38px !important; margin-bottom:16px !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-menu-button { width:32px !important; height:32px !important; border:0 !important; border-radius:16px !important; display:grid !important; place-items:center !important; padding:0 !important; background:rgba(255,255,255,0.94) !important; color:#17191f !important; box-shadow:0 8px 22px rgba(21,24,33,0.08) !important; font:900 18px/32px -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif !important; touch-action:manipulation !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-brand { min-width:0 !important; overflow:hidden !important; text-overflow:ellipsis !important; white-space:nowrap !important; color:#111318 !important; font:900 13px/18px -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif !important; letter-spacing:0 !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-auth-pills { display:inline-flex !important; align-items:center !important; gap:5px !important; min-height:34px !important; padding:3px !important; border-radius:18px !important; background:rgba(255,255,255,0.82) !important; box-shadow:0 10px 28px rgba(19,24,33,0.12) !important; backdrop-filter:blur(14px) !important; -webkit-backdrop-filter:blur(14px) !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-pill-button { min-width:46px !important; height:28px !important; border:0 !important; border-radius:14px !important; padding:0 11px !important; background:#eef0f5 !important; color:#202333 !important; font:800 12px/28px -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif !important; white-space:nowrap !important; touch-action:manipulation !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-pill-button[data-home-action="login"], html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-pill-button[data-home-action="logout"] { background:#050605 !important; color:#fff !important; box-shadow:0 8px 18px rgba(5,6,5,0.18) !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-section-title { margin:12px 0 10px !important; display:flex !important; align-items:baseline !important; justify-content:space-between !important; gap:8px !important; width:100% !important; min-height:30px !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-section-title strong { color:#141722 !important; font:900 20px/30px -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif !important; letter-spacing:0 !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-section-title small { color:#7a808e !important; font:700 11px/18px -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-tool-grid, html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-template-grid { display:grid !important; grid-template-columns:repeat(2, minmax(0, 1fr)) !important; gap:10px !important; width:100% !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-tool-card, html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-template-card { position:relative !important; display:block !important; width:100% !important; height:auto !important; border:0 !important; border-radius:12px !important; background:rgba(255,255,255,0.94) !important; color:#141722 !important; box-shadow:0 12px 30px rgba(38,45,65,0.08) !important; overflow:hidden !important; text-align:left !important; touch-action:manipulation !important; cursor:pointer !important; pointer-events:auto !important; -webkit-tap-highlight-color:transparent !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-tool-card { min-height:98px !important; padding:14px !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-template-card { min-height:92px !important; padding:12px !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-tool-card small, html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-template-card small { display:block !important; color:#6f7584 !important; font:700 11px/16px -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-tool-card strong { display:block !important; margin-top:7px !important; color:#171a22 !important; font:900 18px/23px -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-tool-card span { display:block !important; margin-top:5px !important; color:#5b6070 !important; font:600 11px/16px -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-template-tag { display:inline-flex !important; align-items:center !important; height:22px !important; padding:0 8px !important; border-radius:11px !important; background:#f0f2f6 !important; color:#6d7481 !important; font:800 10px/22px -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-template-card strong { display:block !important; margin-top:8px !important; color:#171a22 !important; font:900 15px/20px -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif !important; } html[data-zbai-mobile="1"] #${HOME_SHELL_ID} .zbai-mobile-template-card small { margin-top:4px !important; display:-webkit-box !important; -webkit-line-clamp:2 !important; -webkit-box-orient:vertical !important; overflow:hidden !important; } html[data-zbai-mobile="1"][data-zbai-page="home"] #root, html[data-zbai-mobile="1"][data-zbai-page="home"] .PageContainer_haimetaApp__qfjGd, html[data-zbai-mobile="1"][data-zbai-page="home"] .PageContainer_indexContent__5aBHJ, html[data-zbai-mobile="1"][data-zbai-page="home"] main, html[data-zbai-mobile="1"][data-zbai-page="home"] section { width:100vw !important; min-width:0 !important; max-width:100vw !important; height:auto !important; overflow-x:hidden !important; transform:none !important; margin-left:0 !important; margin-right:0 !important; } html[data-zbai-mobile="1"][data-zbai-page="home"] #picture-editor-header.PictureEditorHeader_homepageHeader__j_gnO, html[data-zbai-mobile="1"][data-zbai-page="home"] .picture-editor-header, html[data-zbai-mobile="1"][data-zbai-page="home"] #picture-editor-header, html[data-zbai-mobile="1"][data-zbai-page="home"] header { width:100vw !important; min-width:0 !important; height:calc(52px + env(safe-area-inset-top, 0px)) !important; min-height:calc(52px + env(safe-area-inset-top, 0px)) !important; padding:env(safe-area-inset-top, 0px) 10px 0 !important; position:sticky !important; top:0 !important; z-index:80 !important; display:flex !important; align-items:center !important; justify-content:space-between !important; background:var(--Background-1-Normal, #f4f5fb) !important; } html[data-zbai-mobile="1"][data-zbai-page="home"] .SidebarNavigation_sidebarNavigation__KTG_b { display:none !important; } html[data-zbai-mobile="1"][data-zbai-page="home"] main.index-main, html[data-zbai-mobile="1"][data-zbai-page="home"] .index-main-content, html[data-zbai-mobile="1"][data-zbai-page="home"] #index-main-content--right { width:100vw !important; min-width:0 !important; max-width:100vw !important; height:auto !important; min-height:calc(100dvh - 52px) !important; margin:0 !important; padding-left:0 !important; padding-right:0 !important; transform:none !important; left:0 !important; right:auto !important; overflow-x:hidden !important; overflow-y:visible !important; } html[data-zbai-mobile="1"][data-zbai-page="home"] [class*="waterfall"], html[data-zbai-mobile="1"][data-zbai-page="home"] [class*="Waterfall"], html[data-zbai-mobile="1"][data-zbai-page="home"] [class*="card-list"], html[data-zbai-mobile="1"][data-zbai-page="home"] [class*="CardList"], html[data-zbai-mobile="1"][data-zbai-page="home"] [class*="template-list"], html[data-zbai-mobile="1"][data-zbai-page="home"] [class*="TemplateList"] { width:100% !important; max-width:100% !important; min-width:0 !important; } body.${CLASS.enabled} #${ROOT_ID} { display:block !important; position:fixed !important; inset:0 !important; z-index:2147483600 !important; pointer-events:none !important; font-family:-apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif !important; } body.${CLASS.enabled} #${ROOT_ID} .zbai-mobile-auth { position:fixed !important; z-index:2147483603 !important; top:max(12px, env(safe-area-inset-top)) !important; right:max(12px, env(safe-area-inset-right)) !important; min-width:64px !important; min-height:38px !important; padding:0 14px !important; border:1px solid rgba(255,255,255,0.56) !important; border-radius:19px !important; color:#fff !important; background:rgba(17,18,13,0.9) !important; box-shadow:0 8px 22px rgba(20,24,38,0.16) !important; backdrop-filter:blur(12px) !important; -webkit-backdrop-filter:blur(12px) !important; font:800 13px/38px -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif !important; letter-spacing:0 !important; pointer-events:auto !important; touch-action:manipulation !important; } body.${CLASS.enabled} #${ROOT_ID} .zbai-mobile-close { display:none !important; position:fixed !important; z-index:2147483606 !important; top:max(10px, env(safe-area-inset-top)) !important; left:max(10px, env(safe-area-inset-left)) !important; min-height:40px !important; padding:0 14px !important; border:1px solid rgba(31,35,40,0.14) !important; border-radius:20px !important; color:#17191f !important; background:rgba(255,255,255,0.96) !important; box-shadow:0 10px 28px rgba(19,24,33,0.18) !important; font:800 14px/40px -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif !important; letter-spacing:0 !important; pointer-events:auto !important; } body.${CLASS.enabled} #${ROOT_ID} .zbai-mobile-back { display:none !important; position:fixed !important; z-index:2147483603 !important; top:max(10px, env(safe-area-inset-top)) !important; left:max(10px, env(safe-area-inset-left)) !important; min-height:40px !important; padding:0 14px !important; border:1px solid rgba(31,35,40,0.14) !important; border-radius:20px !important; color:#17191f !important; background:rgba(255,255,255,0.96) !important; box-shadow:0 10px 28px rgba(19,24,33,0.18) !important; font:800 14px/40px -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif !important; letter-spacing:0 !important; pointer-events:auto !important; touch-action:manipulation !important; } html[data-zbai-mobile="1"]:not([data-zbai-page="home"]) body.${CLASS.enabled} #${ROOT_ID}:not([data-zbai-surface]) .zbai-mobile-back { display:block !important; } body.${CLASS.enabled} #${ROOT_ID}:not([data-zbai-route="compose"]) .zbai-mobile-dock { display:none !important; } body.${CLASS.enabled} #${ROOT_ID} .zbai-mobile-dock { position:fixed !important; z-index:2147483602 !important; right:max(12px, env(safe-area-inset-right)) !important; bottom:calc(12px + env(safe-area-inset-bottom)) !important; left:max(12px, env(safe-area-inset-left)) !important; display:grid !important; grid-template-columns:repeat(4, minmax(0, 1fr)) !important; gap:8px !important; padding:8px !important; border:1px solid rgba(255,255,255,0.66) !important; border-radius:18px !important; background:rgba(255,255,255,0.9) !important; box-shadow:0 12px 36px rgba(19,24,33,0.18) !important; backdrop-filter:blur(14px) !important; -webkit-backdrop-filter:blur(14px) !important; pointer-events:auto !important; } body.${CLASS.enabled} #${ROOT_ID} .zbai-mobile-dock button { min-width:0 !important; min-height:44px !important; border:0 !important; border-radius:13px !important; color:#17191f !important; background:#eef0f7 !important; font:800 14px/20px -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif !important; letter-spacing:0 !important; touch-action:manipulation !important; } body.${CLASS.enabled} #${ROOT_ID} .zbai-mobile-dock button:first-child { color:#fff !important; background:#11120d !important; box-shadow:0 8px 20px rgba(17,18,13,0.16) !important; } body.${CLASS.enabled} #${ROOT_ID} .zbai-mobile-ready { position:fixed !important; z-index:2147483603 !important; right:max(12px, env(safe-area-inset-right)) !important; bottom:calc(78px + env(safe-area-inset-bottom)) !important; padding:5px 9px !important; border:1px solid rgba(31,35,40,0.12) !important; border-radius:999px !important; color:#17191f !important; background:rgba(255,255,255,0.88) !important; box-shadow:0 8px 22px rgba(19,24,33,0.16) !important; font-size:12px !important; font-weight:700 !important; line-height:1.35 !important; pointer-events:none !important; } html[data-zbai-mobile="1"][data-zbai-page="home"] body.${CLASS.enabled} #${ROOT_ID} .zbai-mobile-ready { left:10px !important; right:auto !important; bottom:calc(8px + env(safe-area-inset-bottom)) !important; } body.${CLASS.enabled} #${ROOT_ID} .zbai-mobile-backdrop { position:fixed !important; inset:0 !important; border:0 !important; opacity:0 !important; background:rgba(10,12,18,0.34) !important; pointer-events:none !important; transition:opacity .18s ease !important; } body.${CLASS.enabled} #${ROOT_ID}[data-zbai-surface] .zbai-mobile-backdrop { opacity:1 !important; pointer-events:auto !important; } body.${CLASS.enabled} #${ROOT_ID} .zbai-mobile-toast { position:fixed !important; z-index:2147483607 !important; right:18px !important; bottom:calc(82px + env(safe-area-inset-bottom)) !important; left:18px !important; padding:11px 13px !important; border-radius:14px !important; color:#fff !important; background:rgba(23,25,31,0.94) !important; box-shadow:0 12px 30px rgba(19,24,33,0.24) !important; font-size:13px !important; line-height:1.4 !important; opacity:0 !important; transform:translateY(8px) !important; transition:opacity .16s ease, transform .16s ease !important; pointer-events:none !important; } body.${CLASS.enabled} #${ROOT_ID} .zbai-mobile-toast.is-visible { opacity:1 !important; transform:translateY(0) !important; } body.${CLASS.enabled} .${CLASS.compose}.${CLASS.composeOpen} { position:fixed !important; z-index:2147483601 !important; inset:auto 0 0 0 !important; width:auto !important; min-width:0 !important; max-width:none !important; height:min(88dvh, 860px) !important; max-height:calc(100dvh - 12px) !important; margin:0 !important; padding-bottom:calc(88px + env(safe-area-inset-bottom)) !important; border-radius:18px 18px 0 0 !important; overflow:auto !important; overscroll-behavior:contain !important; background:#fff !important; box-shadow:0 -16px 42px rgba(19,24,33,0.24) !important; transform:none !important; -webkit-overflow-scrolling:touch !important; } body.${CLASS.enabled} .${CLASS.compose}.${CLASS.composeOpen} textarea { min-height:108px !important; } body.${CLASS.enabled} .${CLASS.compose}.${CLASS.composeOpen} button { min-height:40px !important; } body.${CLASS.enabled} .${CLASS.compose}.${CLASS.composeOpen} .${CLASS.formatLabel} { flex:0 0 auto !important; min-width:48px !important; white-space:nowrap !important; word-break:keep-all !important; writing-mode:horizontal-tb !important; } body.${CLASS.enabled} .${CLASS.compose}.${CLASS.composeOpen} .${CLASS.formatRow} { width:100% !important; min-width:0 !important; display:flex !important; flex-wrap:wrap !important; align-items:center !important; gap:8px !important; pointer-events:auto !important; } body.${CLASS.enabled} .${CLASS.compose}.${CLASS.composeOpen} .${CLASS.formatRow} .${CLASS.formatChoice} { flex:0 0 auto !important; min-width:72px !important; min-height:40px !important; display:inline-flex !important; align-items:center !important; justify-content:center !important; touch-action:manipulation !important; pointer-events:auto !important; } body.${CLASS.enabled} .${CLASS.duplicateTitle} { display:none !important; } body.${CLASS.enabled} .${CLASS.templateTextMode} { display:none !important; } body.${CLASS.enabled} .ant-select-dropdown, body.${CLASS.enabled} .ant-dropdown, body.${CLASS.enabled} .arco-select-popup, body.${CLASS.enabled} .el-select-dropdown, body.${CLASS.enabled} [role="listbox"], body.${CLASS.enabled} [data-radix-popper-content-wrapper] { z-index:2147483605 !important; } body.${CLASS.enabled} .${CLASS.history}.${CLASS.historyOpen} { display:block !important; visibility:visible !important; position:fixed !important; z-index:2147483601 !important; inset:0 auto 0 0 !important; width:min(40vw, 148px) !important; min-width:92px !important; height:100dvh !important; margin:0 !important; padding:12px 8px calc(92px + env(safe-area-inset-bottom)) !important; border-radius:0 18px 18px 0 !important; overflow:auto !important; overscroll-behavior:contain !important; pointer-events:auto !important; background:#f8f8fb !important; box-shadow:10px 0 34px rgba(19,24,33,0.22) !important; transform:none !important; -webkit-overflow-scrolling:touch !important; } body.${CLASS.enabled} .${CLASS.history}.${CLASS.historyOpen} img { max-width:100% !important; height:auto !important; } html[data-zbai-mobile="1"] #${WORK_DETAIL_FALLBACK_ID} { position:fixed !important; inset:0 !important; z-index:2147483650 !important; display:flex !important; flex-direction:column !important; width:100vw !important; height:100dvh !important; padding:calc(10px + env(safe-area-inset-top, 0px)) 10px calc(12px + env(safe-area-inset-bottom, 0px)) !important; box-sizing:border-box !important; background:#0d0f12 !important; color:#fff !important; pointer-events:auto !important; } html[data-zbai-mobile="1"] #${WORK_DETAIL_FALLBACK_ID} .zbai-work-detail-bar { flex:0 0 44px !important; display:flex !important; align-items:center !important; justify-content:space-between !important; gap:10px !important; } html[data-zbai-mobile="1"] #${WORK_DETAIL_FALLBACK_ID} button { min-width:72px !important; height:38px !important; border:0 !important; border-radius:999px !important; background:rgba(255,255,255,0.92) !important; color:#101217 !important; font-size:14px !important; font-weight:700 !important; pointer-events:auto !important; } html[data-zbai-mobile="1"] #${WORK_DETAIL_FALLBACK_ID} .zbai-work-detail-stage { flex:1 1 auto !important; min-height:0 !important; display:flex !important; align-items:center !important; justify-content:center !important; overflow:auto !important; -webkit-overflow-scrolling:touch !important; } html[data-zbai-mobile="1"] #${WORK_DETAIL_FALLBACK_ID} img { max-width:100% !important; max-height:100% !important; object-fit:contain !important; border-radius:0 !important; } } #${ROOT_ID} { display:none; } `; if (shouldAppend) { const target = document.head || document.documentElement; if (!target) { window.setTimeout(injectStyles, 0); return; } target.appendChild(style); } } })();