| import { useEffect, useRef, useState } from 'react' |
| import useAppStore from '../store/appStore' |
|
|
| export default function PreviewFrame({ url }) { |
| |
| |
| const storeKey = useAppStore((s) => s.runtime.iframeKey) |
| const [iframeKey, setIframeKey] = useState(0) |
| const [loaded, setLoaded] = useState(false) |
| const urlRef = useRef(url) |
|
|
| |
| useEffect(() => { |
| setLoaded(false) |
| setIframeKey((k) => k + 1) |
| urlRef.current = url |
| }, [url, storeKey]) |
|
|
| if (!url) { |
| return ( |
| <div |
| style={{ |
| height: '100%', |
| display: 'flex', |
| flexDirection: 'column', |
| alignItems: 'center', |
| justifyContent: 'center', |
| gap: 8, |
| color: 'var(--text-faint)', |
| fontFamily: 'system-ui, sans-serif', |
| fontSize: 13, |
| background: 'var(--bg)', |
| }} |
| > |
| <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1" strokeLinecap="round" strokeLinejoin="round" style={{ opacity: 0.4 }}> |
| <polygon points="5 3 19 12 5 21 5 3" /> |
| </svg> |
| <span style={{ opacity: 0.6 }}>Click Run to start the dev servers</span> |
| </div> |
| ) |
| } |
|
|
| return ( |
| <div style={{ position: 'relative', height: '100%', background: '#fff' }}> |
| <iframe |
| key={iframeKey} |
| src={url} |
| title="App preview" |
| style={{ width: '100%', height: '100%', border: 'none', display: 'block' }} |
| sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-modals allow-pointer-lock" |
| onLoad={() => setLoaded(true)} |
| /> |
| {!loaded && ( |
| <div |
| style={{ |
| position: 'absolute', |
| inset: 0, |
| background: '#fff', |
| display: 'flex', |
| alignItems: 'center', |
| justifyContent: 'center', |
| color: '#9ca3af', |
| fontSize: 13, |
| fontFamily: 'system-ui, sans-serif', |
| }} |
| > |
| Connecting to dev server… |
| </div> |
| )} |
| </div> |
| ) |
| } |
|
|