feat(artifact):Artifact 预览 iframe 增加加载中转圈

This commit is contained in:
肖应宇 2026-04-03 11:26:17 +08:00
parent 54295642a2
commit 86722a09a7
1 changed files with 55 additions and 19 deletions

View File

@ -9,6 +9,7 @@ import {
useEffect,
useMemo,
useState,
type ComponentProps,
type HTMLAttributes,
} from "react";
import { toast } from "sonner";
@ -477,7 +478,7 @@ export function ArtifactFileDetail({
)}
{isCodeFile && viewMode === "code" && (
<div className="min-h-full mb-[180px] rounded-b-[10px] bg-white p-0 mb-0">
<div className="min-h-full mb-[207px] rounded-b-[10px] bg-white p-0 mb-0">
<CodeEditor
className="size-full resize-none rounded-none border-none py-[20px]"
value={displayContent ?? ""}
@ -487,14 +488,13 @@ export function ArtifactFileDetail({
</div>
)}
{!isCodeFile && (
<div className="h-full mb-[180px]">
<iframe
className="size-full border-0"
srcDoc={artifactViewerSrcDoc}
sandbox="allow-same-origin allow-scripts allow-downloads"
title={`Artifact preview: ${fileName}`}
/>
</div>
<PreviewIframe
className="size-full border-0"
containerClassName="h-full mb-[207px]"
srcDoc={artifactViewerSrcDoc}
sandbox="allow-same-origin allow-scripts allow-downloads"
title={`Artifact preview: ${fileName}`}
/>
)}
</ArtifactContent>
</Artifact>
@ -515,7 +515,7 @@ export function ArtifactFilePreview({
if (language === "markdown") {
return (
<div
className={cn("w-full bg-white mb-[207px] p-[20px]")}
className={cn("w-full bg-white mb-[207px] p-[20px]")}
style={{ "--zoom-scale": zoomScale } as React.CSSProperties}
>
<Streamdown
@ -531,21 +531,57 @@ export function ArtifactFilePreview({
}
if (language === "html") {
return (
<div className="h-full mb-[180px]">
<iframe
className="size-full"
title="Artifact preview"
srcDoc={content}
sandbox="allow-scripts allow-forms"
style={{ zoom: zoomScale }}
/>
</div>
<PreviewIframe
className="size-full"
containerClassName="h-full mb-[207px]"
title="Artifact preview"
srcDoc={content}
sandbox="allow-scripts allow-forms"
style={{ zoom: zoomScale }}
/>
);
}
return null;
}
function PreviewIframe({
className,
containerClassName,
onLoad,
src,
srcDoc,
...props
}: ComponentProps<"iframe"> & {
containerClassName?: string;
}) {
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
setIsLoading(true);
}, [src, srcDoc]);
return (
<div className={cn("relative", containerClassName)}>
<iframe
className={className}
src={src}
srcDoc={srcDoc}
onLoad={(event) => {
setIsLoading(false);
onLoad?.(event);
}}
{...props}
/>
{isLoading && (
<div className="absolute inset-0 z-10 flex items-center justify-center bg-white/85">
<LoaderIcon className="text-muted-foreground size-5 animate-spin" />
</div>
)}
</div>
);
}
type ArtifactPreviewKind =
| "html"
| "image"