mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-02-23 17:59:49 +08:00
feat: artifacts style
This commit is contained in:
parent
7c1bc1f1a1
commit
21ef9a4567
2
.gitignore
vendored
2
.gitignore
vendored
@ -44,3 +44,5 @@ dev
|
||||
|
||||
*.key
|
||||
*.key.pub
|
||||
|
||||
masks.json
|
||||
|
12
app/components/artifact.module.scss
Normal file
12
app/components/artifact.module.scss
Normal file
@ -0,0 +1,12 @@
|
||||
.artifact {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.artifact-iframe {
|
||||
width: 100%;
|
||||
border: var(--border-in-light);
|
||||
border-radius: 6px;
|
||||
}
|
@ -13,6 +13,7 @@ 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 "./artifact.module.scss";
|
||||
|
||||
export function HTMLPreview(props: {
|
||||
code: string;
|
||||
@ -61,17 +62,22 @@ export function HTMLPreview(props: {
|
||||
return props.code + script;
|
||||
}, [props.code]);
|
||||
|
||||
const handleOnLoad = () => {
|
||||
if (props?.onLoad) {
|
||||
props.onLoad(title);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<iframe
|
||||
className={styles["artifact-iframe"]}
|
||||
id={frameId.current}
|
||||
ref={ref}
|
||||
frameBorder={0}
|
||||
sandbox="allow-forms allow-modals allow-scripts"
|
||||
style={{ width: "100%", height }}
|
||||
// src={`data:text/html,${encodeURIComponent(srcDoc)}`}
|
||||
style={{ height }}
|
||||
srcDoc={srcDoc}
|
||||
onLoad={(e) => props?.onLoad && props?.onLoad(title)}
|
||||
></iframe>
|
||||
onLoad={handleOnLoad}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -186,14 +192,7 @@ export function Artifact() {
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "block",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<div className={styles.artifact}>
|
||||
<div
|
||||
style={{
|
||||
height: 36,
|
||||
|
@ -105,9 +105,9 @@ export function PreCode(props: { children: any }) {
|
||||
<Mermaid code={mermaidCode} key={mermaidCode} />
|
||||
)}
|
||||
{htmlCode.length > 0 && (
|
||||
<FullScreen className="no-dark html" right={60}>
|
||||
<FullScreen className="no-dark html" right={70}>
|
||||
<ArtifactShareButton
|
||||
style={{ position: "absolute", right: 10, top: 10 }}
|
||||
style={{ position: "absolute", right: 20, top: 10 }}
|
||||
getCode={() => htmlCode}
|
||||
/>
|
||||
<HTMLPreview
|
||||
|
@ -292,6 +292,7 @@
|
||||
z-index: 999;
|
||||
|
||||
&-content {
|
||||
min-width: 300px;
|
||||
.list {
|
||||
max-height: 90vh;
|
||||
overflow-x: hidden;
|
||||
|
@ -53,7 +53,7 @@ export function ListItem(props: {
|
||||
children?: JSX.Element | JSX.Element[];
|
||||
icon?: JSX.Element;
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
onClick?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
@ -454,25 +454,45 @@ export function Selector<T>(props: {
|
||||
onClose?: () => void;
|
||||
multiple?: boolean;
|
||||
}) {
|
||||
const [selectedValues, setSelectedValues] = useState<T[]>(
|
||||
Array.isArray(props.defaultSelectedValue)
|
||||
? props.defaultSelectedValue
|
||||
: props.defaultSelectedValue !== undefined
|
||||
? [props.defaultSelectedValue]
|
||||
: [],
|
||||
);
|
||||
|
||||
const handleSelection = (
|
||||
e: React.MouseEvent<HTMLDivElement, MouseEvent>,
|
||||
value: T,
|
||||
) => {
|
||||
if (props.multiple) {
|
||||
e.stopPropagation();
|
||||
const newSelectedValues = selectedValues.includes(value)
|
||||
? selectedValues.filter((v) => v !== value)
|
||||
: [...selectedValues, value];
|
||||
setSelectedValues(newSelectedValues);
|
||||
props.onSelection?.(newSelectedValues);
|
||||
} else {
|
||||
setSelectedValues([value]);
|
||||
props.onSelection?.([value]);
|
||||
props.onClose?.();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles["selector"]} onClick={() => props.onClose?.()}>
|
||||
<div className={styles["selector-content"]}>
|
||||
<List>
|
||||
{props.items.map((item, i) => {
|
||||
const selected = props.multiple
|
||||
? // @ts-ignore
|
||||
props.defaultSelectedValue?.includes(item.value)
|
||||
: props.defaultSelectedValue === item.value;
|
||||
const selected = selectedValues.includes(item.value);
|
||||
return (
|
||||
<ListItem
|
||||
className={styles["selector-item"]}
|
||||
key={i}
|
||||
title={item.title}
|
||||
subTitle={item.subTitle}
|
||||
onClick={() => {
|
||||
props.onSelection?.([item.value]);
|
||||
props.onClose?.();
|
||||
}}
|
||||
onClick={(e) => handleSelection(e, item.value)}
|
||||
>
|
||||
{selected ? (
|
||||
<div
|
||||
@ -494,7 +514,6 @@ export function Selector<T>(props: {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function FullScreen(props: any) {
|
||||
const { children, right = 10, top = 10, ...rest } = props;
|
||||
const ref = useRef<HTMLDivElement>();
|
||||
|
Loading…
Reference in New Issue
Block a user