|
@@ -13,11 +13,12 @@ import { Modal, showToast } from "./ui-lib";
|
|
|
import { copyToClipboard, downloadAs } from "../utils";
|
|
import { copyToClipboard, downloadAs } from "../utils";
|
|
|
import { Path, ApiPath, REPO_URL } from "@/app/constant";
|
|
import { Path, ApiPath, REPO_URL } from "@/app/constant";
|
|
|
import { Loading } from "./home";
|
|
import { Loading } from "./home";
|
|
|
|
|
+import styles from "./artifact.module.scss";
|
|
|
|
|
|
|
|
export function HTMLPreview(props: {
|
|
export function HTMLPreview(props: {
|
|
|
code: string;
|
|
code: string;
|
|
|
autoHeight?: boolean;
|
|
autoHeight?: boolean;
|
|
|
- height?: number;
|
|
|
|
|
|
|
+ height?: number | string;
|
|
|
onLoad?: (title?: string) => void;
|
|
onLoad?: (title?: string) => void;
|
|
|
}) {
|
|
}) {
|
|
|
const ref = useRef<HTMLIFrameElement>(null);
|
|
const ref = useRef<HTMLIFrameElement>(null);
|
|
@@ -65,17 +66,22 @@ export function HTMLPreview(props: {
|
|
|
return props.code + script;
|
|
return props.code + script;
|
|
|
}, [props.code]);
|
|
}, [props.code]);
|
|
|
|
|
|
|
|
|
|
+ const handleOnLoad = () => {
|
|
|
|
|
+ if (props?.onLoad) {
|
|
|
|
|
+ props.onLoad(title);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
return (
|
|
return (
|
|
|
<iframe
|
|
<iframe
|
|
|
|
|
+ className={styles["artifact-iframe"]}
|
|
|
id={frameId.current}
|
|
id={frameId.current}
|
|
|
ref={ref}
|
|
ref={ref}
|
|
|
- frameBorder={0}
|
|
|
|
|
sandbox="allow-forms allow-modals allow-scripts"
|
|
sandbox="allow-forms allow-modals allow-scripts"
|
|
|
- style={{ width: "100%", height }}
|
|
|
|
|
- // src={`data:text/html,${encodeURIComponent(srcDoc)}`}
|
|
|
|
|
|
|
+ style={{ height }}
|
|
|
srcDoc={srcDoc}
|
|
srcDoc={srcDoc}
|
|
|
- onLoad={(e) => props?.onLoad && props?.onLoad(title)}
|
|
|
|
|
- ></iframe>
|
|
|
|
|
|
|
+ onLoad={handleOnLoad}
|
|
|
|
|
+ />
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -179,7 +185,6 @@ export function Artifact() {
|
|
|
const [code, setCode] = useState("");
|
|
const [code, setCode] = useState("");
|
|
|
const [loading, setLoading] = useState(true);
|
|
const [loading, setLoading] = useState(true);
|
|
|
const [fileName, setFileName] = useState("");
|
|
const [fileName, setFileName] = useState("");
|
|
|
- const { height } = useWindowSize();
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
if (id) {
|
|
if (id) {
|
|
@@ -199,40 +204,28 @@ export function Artifact() {
|
|
|
}, [id]);
|
|
}, [id]);
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
- <div
|
|
|
|
|
- style={{
|
|
|
|
|
- display: "block",
|
|
|
|
|
- width: "100%",
|
|
|
|
|
- height: "100%",
|
|
|
|
|
- position: "relative",
|
|
|
|
|
- }}
|
|
|
|
|
- >
|
|
|
|
|
- <div
|
|
|
|
|
- style={{
|
|
|
|
|
- height: 36,
|
|
|
|
|
- display: "flex",
|
|
|
|
|
- alignItems: "center",
|
|
|
|
|
- padding: 12,
|
|
|
|
|
- }}
|
|
|
|
|
- >
|
|
|
|
|
|
|
+ <div className={styles["artifact"]}>
|
|
|
|
|
+ <div className={styles["artifact-header"]}>
|
|
|
<a href={REPO_URL} target="_blank" rel="noopener noreferrer">
|
|
<a href={REPO_URL} target="_blank" rel="noopener noreferrer">
|
|
|
<IconButton bordered icon={<GithubIcon />} shadow />
|
|
<IconButton bordered icon={<GithubIcon />} shadow />
|
|
|
</a>
|
|
</a>
|
|
|
- <div style={{ flex: 1, textAlign: "center" }}>NextChat Artifact</div>
|
|
|
|
|
|
|
+ <div className={styles["artifact-title"]}>NextChat Artifact</div>
|
|
|
<ArtifactShareButton id={id} getCode={() => code} fileName={fileName} />
|
|
<ArtifactShareButton id={id} getCode={() => code} fileName={fileName} />
|
|
|
</div>
|
|
</div>
|
|
|
- {loading && <Loading />}
|
|
|
|
|
- {code && (
|
|
|
|
|
- <HTMLPreview
|
|
|
|
|
- code={code}
|
|
|
|
|
- autoHeight={false}
|
|
|
|
|
- height={height - 36}
|
|
|
|
|
- onLoad={(title) => {
|
|
|
|
|
- setFileName(title as string);
|
|
|
|
|
- setLoading(false);
|
|
|
|
|
- }}
|
|
|
|
|
- />
|
|
|
|
|
- )}
|
|
|
|
|
|
|
+ <div className={styles["artifact-content"]}>
|
|
|
|
|
+ {loading && <Loading />}
|
|
|
|
|
+ {code && (
|
|
|
|
|
+ <HTMLPreview
|
|
|
|
|
+ code={code}
|
|
|
|
|
+ autoHeight={false}
|
|
|
|
|
+ height={"100%"}
|
|
|
|
|
+ onLoad={(title) => {
|
|
|
|
|
+ setFileName(title as string);
|
|
|
|
|
+ setLoading(false);
|
|
|
|
|
+ }}
|
|
|
|
|
+ />
|
|
|
|
|
+ )}
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|