feat: artifacts style

This commit is contained in:
Dogtiti 2024-07-25 23:29:29 +08:00
parent 51e8f0440d
commit c27ef6ffbf
4 changed files with 52 additions and 30 deletions

View File

@ -1,8 +1,26 @@
.artifact { .artifact {
display: block; display: flex;
width: 100%; width: 100%;
height: 100%; height: 100%;
position: relative; flex-direction: column;
&-header {
display: flex;
align-items: center;
height: 36px;
padding: 20px;
background: var(--second);
}
&-title {
flex: 1;
text-align: center;
font-weight: bold;
font-size: 24px;
}
&-content {
flex-grow: 1;
padding: 0 20px 20px 20px;
background-color: var(--second);
}
} }
.artifact-iframe { .artifact-iframe {

View File

@ -18,7 +18,7 @@ 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);
@ -185,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) {
@ -205,33 +204,28 @@ export function Artifact() {
}, [id]); }, [id]);
return ( return (
<div className={styles.artifact}> <div className={styles["artifact"]}>
<div <div className={styles["artifact-header"]}>
style={{
height: 36,
display: "flex",
alignItems: "center",
padding: 12,
}}
>
<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 />} <div className={styles["artifact-content"]}>
{code && ( {loading && <Loading />}
<HTMLPreview {code && (
code={code} <HTMLPreview
autoHeight={false} code={code}
height={height - 36} autoHeight={false}
onLoad={(title) => { height={"100%"}
setFileName(title as string); onLoad={(title) => {
setLoading(false); setFileName(title as string);
}} setLoading(false);
/> }}
)} />
)}
</div>
</div> </div>
); );
} }

View File

@ -641,12 +641,13 @@ export function ChatActions(props: {
]} ]}
onClose={() => setShowPluginSelector(false)} onClose={() => setShowPluginSelector(false)}
onSelection={(s) => { onSelection={(s) => {
if (s.length === 0) return;
const plugin = s[0]; const plugin = s[0];
chatStore.updateCurrentSession((session) => { chatStore.updateCurrentSession((session) => {
session.mask.plugin = s; session.mask.plugin = s;
}); });
showToast(plugin); if (plugin) {
showToast(plugin);
}
}} }}
/> />
)} )}

View File

@ -14,7 +14,8 @@ import React from "react";
import { useDebouncedCallback } from "use-debounce"; import { useDebouncedCallback } from "use-debounce";
import { showImageModal, FullScreen } from "./ui-lib"; import { showImageModal, FullScreen } from "./ui-lib";
import { ArtifactShareButton, HTMLPreview } from "./artifact"; import { ArtifactShareButton, HTMLPreview } from "./artifact";
import { Plugin } from "../constant";
import { useChatStore } from "../store";
export function Mermaid(props: { code: string }) { export function Mermaid(props: { code: string }) {
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
const [hasError, setHasError] = useState(false); const [hasError, setHasError] = useState(false);
@ -67,6 +68,9 @@ export function PreCode(props: { children: any }) {
const [mermaidCode, setMermaidCode] = useState(""); const [mermaidCode, setMermaidCode] = useState("");
const [htmlCode, setHtmlCode] = useState(""); const [htmlCode, setHtmlCode] = useState("");
const { height } = useWindowSize(); const { height } = useWindowSize();
const chatStore = useChatStore();
const session = chatStore.currentSession();
const plugins = session.mask?.plugin;
const renderArtifacts = useDebouncedCallback(() => { const renderArtifacts = useDebouncedCallback(() => {
if (!ref.current) return; if (!ref.current) return;
@ -87,6 +91,11 @@ export function PreCode(props: { children: any }) {
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [refText]); }, [refText]);
const enableArtifacts = useMemo(
() => plugins?.includes(Plugin.Artifact),
[plugins],
);
return ( return (
<> <>
<pre ref={ref}> <pre ref={ref}>
@ -104,7 +113,7 @@ export function PreCode(props: { children: any }) {
{mermaidCode.length > 0 && ( {mermaidCode.length > 0 && (
<Mermaid code={mermaidCode} key={mermaidCode} /> <Mermaid code={mermaidCode} key={mermaidCode} />
)} )}
{htmlCode.length > 0 && ( {htmlCode.length > 0 && enableArtifacts && (
<FullScreen className="no-dark html" right={70}> <FullScreen className="no-dark html" right={70}>
<ArtifactShareButton <ArtifactShareButton
style={{ position: "absolute", right: 20, top: 10 }} style={{ position: "absolute", right: 20, top: 10 }}