diff --git a/public/test-host.html b/public/test-host.html index e8a9e9a..6dc8759 100644 --- a/public/test-host.html +++ b/public/test-host.html @@ -23,19 +23,32 @@ .layout { display: grid; grid-template-columns: 360px minmax(0, 1fr); - min-height: 100vh; + height: 100vh; } .panel { padding: 24px; background: #ffffff; border-right: 1px solid #e5e7eb; + overflow: auto; } .preview { - padding: 24px; + width: 500px; + height: 800px; + overflow: auto; } + .preview-frame { + width: 800px; + height: 300px; + overflow: hidden; + border: 1px solid #d1d5db; + border-radius: 16px; + background: #ffffff; + } + + h1 { margin: 0 0 8px; font-size: 20px; @@ -98,14 +111,15 @@ font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace; white-space: pre-wrap; min-height: 160px; + max-height: min(360px, calc(100vh - 260px)); + overflow: auto; } iframe { + display: block; width: 100%; - height: calc(100vh - 48px); - border: 1px solid #d1d5db; - border-radius: 16px; - background: #ffffff; + height: 100%; + border: 0; } @media (max-width: 960px) { @@ -118,7 +132,8 @@ border-bottom: 1px solid #e5e7eb; } - iframe { + .preview-frame { + width: 100%; height: 70vh; } } @@ -149,23 +164,46 @@
- +
diff --git a/src/features/authGuide.tsx b/src/features/authGuide.tsx index 4da46c4..4d9e308 100644 --- a/src/features/authGuide.tsx +++ b/src/features/authGuide.tsx @@ -10,8 +10,10 @@ import {useUserStore} from '@/store/user.ts' import type {HostContextMessage} from '@/types' const HOST_READY_MESSAGE = 'PLAYX_READY' +const HOST_HEIGHT_MESSAGE = 'PLAYX_HEIGHT' const HOST_READY_INTERVAL = 500 const HOST_READY_RETRY_LIMIT = 20 +const HOST_HEIGHT_REPORT_INTERVAL = 250 const TEST_BOOTSTRAP_ENABLED = import.meta.env.VITE_BYPASS_IFRAME_CONTEXT === 'true' const TEST_BOOTSTRAP_USERNAME = '+60777777777' const TEST_BOOTSTRAP_LANGUAGE = 'zh' @@ -142,6 +144,97 @@ export function AuthGuide({children}: PropsWithChildren) { clearUserInfo() }, [authBootstrapQuery.isError, clearUserInfo]) + useEffect(() => { + if (window.parent === window) { + return + } + + let frameId = 0 + let timeoutId: number | null = null + let lastReportedHeight = 0 + let lastReportedAt = 0 + + const measureHeight = () => + Math.max( + document.body.scrollHeight, + document.documentElement.scrollHeight, + document.body.offsetHeight, + document.documentElement.offsetHeight, + ) + + const postHeight = (height: number) => { + lastReportedHeight = height + lastReportedAt = Date.now() + window.parent.postMessage( + { + type: HOST_HEIGHT_MESSAGE, + payload: { + height, + }, + }, + '*', + ) + } + + const flushPostHeight = () => { + frameId = 0 + + const nextHeight = measureHeight() + if (nextHeight === lastReportedHeight) { + return + } + + const elapsed = Date.now() - lastReportedAt + if (elapsed >= HOST_HEIGHT_REPORT_INTERVAL) { + postHeight(nextHeight) + return + } + + if (timeoutId != null) { + return + } + + timeoutId = window.setTimeout(() => { + timeoutId = null + postHeight(measureHeight()) + }, HOST_HEIGHT_REPORT_INTERVAL - elapsed) + } + + const schedulePostHeight = () => { + if (frameId) { + window.cancelAnimationFrame(frameId) + } + + frameId = window.requestAnimationFrame(() => { + flushPostHeight() + }) + } + + schedulePostHeight() + + const resizeObserver = new ResizeObserver(() => { + schedulePostHeight() + }) + + resizeObserver.observe(document.body) + resizeObserver.observe(document.documentElement) + + window.addEventListener('load', schedulePostHeight) + window.addEventListener('resize', schedulePostHeight) + + return () => { + resizeObserver.disconnect() + window.removeEventListener('load', schedulePostHeight) + window.removeEventListener('resize', schedulePostHeight) + if (frameId) { + window.cancelAnimationFrame(frameId) + } + if (timeoutId != null) { + window.clearTimeout(timeoutId) + } + } + }, []) + if (!username || authBootstrapQuery.isPending) { return (