Skip to content

Commit

Permalink
frat: add reload button
Browse files Browse the repository at this point in the history
  • Loading branch information
lloydzhou committed Aug 21, 2024
1 parent 8b67536 commit b0e9a54
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 16 deletions.
59 changes: 43 additions & 16 deletions app/components/artifacts.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { useEffect, useState, useRef, useMemo } from "react";
import {
useEffect,
useState,
useRef,
useMemo,
forwardRef,
useImperativeHandle,
} from "react";
import { useParams } from "react-router";
import { useWindowSize } from "@/app/utils";
import { IconButton } from "./button";
Expand All @@ -8,21 +15,27 @@ import CopyIcon from "../icons/copy.svg";
import DownloadIcon from "../icons/download.svg";
import GithubIcon from "../icons/github.svg";
import LoadingButtonIcon from "../icons/loading.svg";
import ReloadButtonIcon from "../icons/reload.svg";
import Locale from "../locales";
import { Modal, showToast } from "./ui-lib";
import { copyToClipboard, downloadAs } from "../utils";
import { Path, ApiPath, REPO_URL } from "@/app/constant";
import { Loading } from "./home";
import styles from "./artifacts.module.scss";

export function HTMLPreview(props: {
code: string;
autoHeight?: boolean;
height?: number | string;
onLoad?: (title?: string) => void;
}) {
const ref = useRef<HTMLIFrameElement>(null);
const frameId = useRef<string>(nanoid());
export const HTMLPreview = forwardRef<
{
reload: () => void;
},
{
code: string;
autoHeight?: boolean;
height?: number | string;
onLoad?: (title?: string) => void;
}
>(function HTMLPreview(props, ref) {
const iframeRef = useRef<HTMLIFrameElement>(null);
const [frameId, setFrameId] = useState<string>(nanoid());
const [iframeHeight, setIframeHeight] = useState(600);
const [title, setTitle] = useState("");
/*
Expand All @@ -37,15 +50,21 @@ export function HTMLPreview(props: {
const handleMessage = (e: any) => {
const { id, height, title } = e.data;
setTitle(title);
if (id == frameId.current) {
if (id == frameId) {
setIframeHeight(height);
}
};
window.addEventListener("message", handleMessage);
return () => {
window.removeEventListener("message", handleMessage);
};
}, []);
}, [frameId]);

useImperativeHandle(ref, () => ({
reload: () => {
setFrameId(nanoid());
},
}));

const height = useMemo(() => {
if (!props.autoHeight) return props.height || 600;
Expand All @@ -57,12 +76,12 @@ export function HTMLPreview(props: {
}, [props.autoHeight, props.height, iframeHeight]);

const srcDoc = useMemo(() => {
const script = `<script>new ResizeObserver((entries) => parent.postMessage({id: '${frameId.current}', height: entries[0].target.clientHeight}, '*')).observe(document.body)</script>`;
const script = `<script>new ResizeObserver((entries) => parent.postMessage({id: '${frameId}', height: entries[0].target.clientHeight}, '*')).observe(document.body)</script>`;
if (props.code.includes("</head>")) {
props.code.replace("</head>", "</head>" + script);
}
return props.code + script;
}, [props.code]);
}, [props.code, frameId]);

const handleOnLoad = () => {
if (props?.onLoad) {
Expand All @@ -73,15 +92,15 @@ export function HTMLPreview(props: {
return (
<iframe
className={styles["artifacts-iframe"]}
id={frameId.current}
ref={ref}
key={frameId}
ref={iframeRef}
sandbox="allow-forms allow-modals allow-scripts"
style={{ height }}
srcDoc={srcDoc}
onLoad={handleOnLoad}
/>
);
}
});

export function ArtifactsShareButton({
getCode,
Expand Down Expand Up @@ -184,6 +203,7 @@ export function Artifacts() {
const [code, setCode] = useState("");
const [loading, setLoading] = useState(true);
const [fileName, setFileName] = useState("");
const previewRef = useRef<typeof HTMLPreview>(null);

useEffect(() => {
if (id) {
Expand All @@ -208,6 +228,12 @@ export function Artifacts() {
<a href={REPO_URL} target="_blank" rel="noopener noreferrer">
<IconButton bordered icon={<GithubIcon />} shadow />
</a>
<IconButton
bordered
icon={<ReloadButtonIcon />}
shadow
onClick={() => previewRef.current?.reload()}
/>
<div className={styles["artifacts-title"]}>NextChat Artifacts</div>
<ArtifactsShareButton
id={id}
Expand All @@ -220,6 +246,7 @@ export function Artifacts() {
{code && (
<HTMLPreview
code={code}
ref={previewRef}
autoHeight={false}
height={"100%"}
onLoad={(title) => {
Expand Down
12 changes: 12 additions & 0 deletions app/components/markdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ import { copyToClipboard, useWindowSize } from "../utils";
import mermaid from "mermaid";

import LoadingIcon from "../icons/three-dots.svg";
import ReloadButtonIcon from "../icons/reload.svg";
import React from "react";
import { useDebouncedCallback } from "use-debounce";
import { showImageModal, FullScreen } from "./ui-lib";
import { ArtifactsShareButton, HTMLPreview } from "./artifacts";
import { Plugin } from "../constant";
import { useChatStore } from "../store";
import { IconButton } from "./button";

export function Mermaid(props: { code: string }) {
const ref = useRef<HTMLDivElement>(null);
const [hasError, setHasError] = useState(false);
Expand Down Expand Up @@ -64,6 +67,7 @@ export function Mermaid(props: { code: string }) {

export function PreCode(props: { children: any }) {
const ref = useRef<HTMLPreElement>(null);
const previewRef = useRef<typeof HTMLPreview>(null);
const [mermaidCode, setMermaidCode] = useState("");
const [htmlCode, setHtmlCode] = useState("");
const { height } = useWindowSize();
Expand Down Expand Up @@ -141,7 +145,15 @@ export function PreCode(props: { children: any }) {
style={{ position: "absolute", right: 20, top: 10 }}
getCode={() => htmlCode}
/>
<IconButton
style={{ position: "absolute", right: 120, top: 10 }}
bordered
icon={<ReloadButtonIcon />}
shadow
onClick={() => previewRef.current?.reload()}
/>
<HTMLPreview
ref={previewRef}
code={htmlCode}
autoHeight={!document.fullscreenElement}
height={!document.fullscreenElement ? 600 : height}
Expand Down

0 comments on commit b0e9a54

Please sign in to comment.