project-standalo-note-to-app/app/components/AppIframeViewer.tsx

53 lines
1.5 KiB
TypeScript

'use client';
import { useState, useRef, useEffect } from 'react';
import type { AppIframeViewerProps } from '@/types/component-props';
export default function AppIframeViewer({
htmlContent,
title,
onLoadComplete,
}: AppIframeViewerProps) {
const [isLoading, setIsLoading] = useState(true);
const iframeRef = useRef<HTMLIFrameElement>(null);
useEffect(() => {
if (iframeRef.current) {
const iframe = iframeRef.current;
const handleLoad = () => {
setIsLoading(false);
onLoadComplete?.();
};
iframe.addEventListener('load', handleLoad);
return () => iframe.removeEventListener('load', handleLoad);
}
}, [onLoadComplete]);
return (
<div className="bg-white border rounded-lg overflow-hidden">
<div className="bg-gray-100 border-b px-4 py-2 flex items-center justify-between">
<h3 className="font-semibold text-gray-900">{title}</h3>
{isLoading && (
<span className="text-sm text-gray-600">Loading...</span>
)}
</div>
<div className="relative w-full h-[600px]">
{isLoading && (
<div className="absolute inset-0 flex items-center justify-center bg-gray-50">
<div className="w-8 h-8 border-4 border-blue-500 border-t-transparent rounded-full animate-spin" />
</div>
)}
<iframe
ref={iframeRef}
srcDoc={htmlContent}
title={title}
sandbox="allow-scripts allow-same-origin"
className="w-full h-full border-0"
/>
</div>
</div>
);
}