feat: TTD dialog UI tweaks (#7384)
This commit is contained in:
parent
42d8c5a040
commit
4bdeaf999b
@ -7,7 +7,6 @@ import "./MermaidToExcalidraw.scss";
|
|||||||
import { t } from "../../i18n";
|
import { t } from "../../i18n";
|
||||||
import Trans from "../Trans";
|
import Trans from "../Trans";
|
||||||
import {
|
import {
|
||||||
LOCAL_STORAGE_KEY_MERMAID_TO_EXCALIDRAW,
|
|
||||||
MermaidToExcalidrawLibProps,
|
MermaidToExcalidrawLibProps,
|
||||||
convertMermaidToExcalidraw,
|
convertMermaidToExcalidraw,
|
||||||
insertToEditor,
|
insertToEditor,
|
||||||
@ -17,30 +16,26 @@ import { TTDDialogPanels } from "./TTDDialogPanels";
|
|||||||
import { TTDDialogPanel } from "./TTDDialogPanel";
|
import { TTDDialogPanel } from "./TTDDialogPanel";
|
||||||
import { TTDDialogInput } from "./TTDDialogInput";
|
import { TTDDialogInput } from "./TTDDialogInput";
|
||||||
import { TTDDialogOutput } from "./TTDDialogOutput";
|
import { TTDDialogOutput } from "./TTDDialogOutput";
|
||||||
|
import { EditorLocalStorage } from "../../data/EditorLocalStorage";
|
||||||
|
import { EDITOR_LS_KEYS } from "../../constants";
|
||||||
|
import { debounce } from "../../utils";
|
||||||
|
import { TTDDialogSubmitShortcut } from "./TTDDialogSubmitShortcut";
|
||||||
|
|
||||||
const MERMAID_EXAMPLE =
|
const MERMAID_EXAMPLE =
|
||||||
"flowchart TD\n A[Christmas] -->|Get money| B(Go shopping)\n B --> C{Let me think}\n C -->|One| D[Laptop]\n C -->|Two| E[iPhone]\n C -->|Three| F[Car]";
|
"flowchart TD\n A[Christmas] -->|Get money| B(Go shopping)\n B --> C{Let me think}\n C -->|One| D[Laptop]\n C -->|Two| E[iPhone]\n C -->|Three| F[Car]";
|
||||||
|
|
||||||
const importMermaidDataFromStorage = () => {
|
const debouncedSaveMermaidDefinition = debounce(saveMermaidDataToStorage, 300);
|
||||||
try {
|
|
||||||
const data = localStorage.getItem(LOCAL_STORAGE_KEY_MERMAID_TO_EXCALIDRAW);
|
|
||||||
if (data) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
// Unable to access localStorage
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const MermaidToExcalidraw = ({
|
const MermaidToExcalidraw = ({
|
||||||
mermaidToExcalidrawLib,
|
mermaidToExcalidrawLib,
|
||||||
}: {
|
}: {
|
||||||
mermaidToExcalidrawLib: MermaidToExcalidrawLibProps;
|
mermaidToExcalidrawLib: MermaidToExcalidrawLibProps;
|
||||||
}) => {
|
}) => {
|
||||||
const [text, setText] = useState("");
|
const [text, setText] = useState(
|
||||||
|
() =>
|
||||||
|
EditorLocalStorage.get<string>(EDITOR_LS_KEYS.MERMAID_TO_EXCALIDRAW) ||
|
||||||
|
MERMAID_EXAMPLE,
|
||||||
|
);
|
||||||
const deferredText = useDeferredValue(text.trim());
|
const deferredText = useDeferredValue(text.trim());
|
||||||
const [error, setError] = useState<Error | null>(null);
|
const [error, setError] = useState<Error | null>(null);
|
||||||
|
|
||||||
@ -52,11 +47,6 @@ const MermaidToExcalidraw = ({
|
|||||||
|
|
||||||
const app = useApp();
|
const app = useApp();
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const data = importMermaidDataFromStorage() || MERMAID_EXAMPLE;
|
|
||||||
setText(data);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
convertMermaidToExcalidraw({
|
convertMermaidToExcalidraw({
|
||||||
canvasRef,
|
canvasRef,
|
||||||
@ -65,22 +55,25 @@ const MermaidToExcalidraw = ({
|
|||||||
setError,
|
setError,
|
||||||
mermaidDefinition: deferredText,
|
mermaidDefinition: deferredText,
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
|
|
||||||
|
debouncedSaveMermaidDefinition(deferredText);
|
||||||
}, [deferredText, mermaidToExcalidrawLib]);
|
}, [deferredText, mermaidToExcalidrawLib]);
|
||||||
|
|
||||||
const textRef = useRef(text);
|
useEffect(
|
||||||
|
() => () => {
|
||||||
|
debouncedSaveMermaidDefinition.flush();
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
// slightly hacky but really quite simple
|
const onInsertToEditor = () => {
|
||||||
// essentially, we want to save the text to LS when the component unmounts
|
insertToEditor({
|
||||||
useEffect(() => {
|
app,
|
||||||
textRef.current = text;
|
data,
|
||||||
}, [text]);
|
text,
|
||||||
useEffect(() => {
|
shouldSaveMermaidDataToStorage: true,
|
||||||
return () => {
|
});
|
||||||
if (textRef.current) {
|
|
||||||
saveMermaidDataToStorage(textRef.current);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -103,22 +96,21 @@ const MermaidToExcalidraw = ({
|
|||||||
input={text}
|
input={text}
|
||||||
placeholder={"Write Mermaid diagram defintion here..."}
|
placeholder={"Write Mermaid diagram defintion here..."}
|
||||||
onChange={(event) => setText(event.target.value)}
|
onChange={(event) => setText(event.target.value)}
|
||||||
|
onKeyboardSubmit={() => {
|
||||||
|
onInsertToEditor();
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</TTDDialogPanel>
|
</TTDDialogPanel>
|
||||||
<TTDDialogPanel
|
<TTDDialogPanel
|
||||||
label={t("mermaid.preview")}
|
label={t("mermaid.preview")}
|
||||||
panelAction={{
|
panelAction={{
|
||||||
action: () => {
|
action: () => {
|
||||||
insertToEditor({
|
onInsertToEditor();
|
||||||
app,
|
|
||||||
data,
|
|
||||||
text,
|
|
||||||
shouldSaveMermaidDataToStorage: true,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
label: t("mermaid.button"),
|
label: t("mermaid.button"),
|
||||||
icon: ArrowRightIcon,
|
icon: ArrowRightIcon,
|
||||||
}}
|
}}
|
||||||
|
renderSubmitShortcut={() => <TTDDialogSubmitShortcut />}
|
||||||
>
|
>
|
||||||
<TTDDialogOutput
|
<TTDDialogOutput
|
||||||
canvasRef={canvasRef}
|
canvasRef={canvasRef}
|
||||||
|
@ -298,4 +298,18 @@ $verticalBreakpoint: 861px;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ttd-dialog-submit-shortcut {
|
||||||
|
margin-inline-start: 0.5rem;
|
||||||
|
font-size: 0.625rem;
|
||||||
|
opacity: 0.6;
|
||||||
|
display: flex;
|
||||||
|
gap: 0.125rem;
|
||||||
|
|
||||||
|
&__key {
|
||||||
|
border: 1px solid gray;
|
||||||
|
padding: 2px 3px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Dialog } from "../Dialog";
|
import { Dialog } from "../Dialog";
|
||||||
import { useApp } from "../App";
|
import { useApp, useExcalidrawSetAppState } from "../App";
|
||||||
import MermaidToExcalidraw from "./MermaidToExcalidraw";
|
import MermaidToExcalidraw from "./MermaidToExcalidraw";
|
||||||
import TTDDialogTabs from "./TTDDialogTabs";
|
import TTDDialogTabs from "./TTDDialogTabs";
|
||||||
import { ChangeEventHandler, useEffect, useRef, useState } from "react";
|
import { ChangeEventHandler, useEffect, useRef, useState } from "react";
|
||||||
@ -27,6 +27,8 @@ import "./TTDDialog.scss";
|
|||||||
import { isFiniteNumber } from "../../utils";
|
import { isFiniteNumber } from "../../utils";
|
||||||
import { atom, useAtom } from "jotai";
|
import { atom, useAtom } from "jotai";
|
||||||
import { trackEvent } from "../../analytics";
|
import { trackEvent } from "../../analytics";
|
||||||
|
import { InlineIcon } from "../InlineIcon";
|
||||||
|
import { TTDDialogSubmitShortcut } from "./TTDDialogSubmitShortcut";
|
||||||
|
|
||||||
const MIN_PROMPT_LENGTH = 3;
|
const MIN_PROMPT_LENGTH = 3;
|
||||||
const MAX_PROMPT_LENGTH = 1000;
|
const MAX_PROMPT_LENGTH = 1000;
|
||||||
@ -36,6 +38,11 @@ const rateLimitsAtom = atom<{
|
|||||||
rateLimitRemaining: number;
|
rateLimitRemaining: number;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
||||||
|
const ttdGenerationAtom = atom<{
|
||||||
|
generatedResponse: string | null;
|
||||||
|
prompt: string | null;
|
||||||
|
} | null>(null);
|
||||||
|
|
||||||
type OnTestSubmitRetValue = {
|
type OnTestSubmitRetValue = {
|
||||||
rateLimit?: number | null;
|
rateLimit?: number | null;
|
||||||
rateLimitRemaining?: number | null;
|
rateLimitRemaining?: number | null;
|
||||||
@ -80,10 +87,13 @@ export const TTDDialogBase = withInternalFallback(
|
|||||||
| { __fallback: true }
|
| { __fallback: true }
|
||||||
)) => {
|
)) => {
|
||||||
const app = useApp();
|
const app = useApp();
|
||||||
|
const setAppState = useExcalidrawSetAppState();
|
||||||
|
|
||||||
const someRandomDivRef = useRef<HTMLDivElement>(null);
|
const someRandomDivRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const [text, setText] = useState("");
|
const [ttdGeneration, setTtdGeneration] = useAtom(ttdGenerationAtom);
|
||||||
|
|
||||||
|
const [text, setText] = useState(ttdGeneration?.prompt ?? "");
|
||||||
|
|
||||||
const prompt = text.trim();
|
const prompt = text.trim();
|
||||||
|
|
||||||
@ -91,6 +101,10 @@ export const TTDDialogBase = withInternalFallback(
|
|||||||
event,
|
event,
|
||||||
) => {
|
) => {
|
||||||
setText(event.target.value);
|
setText(event.target.value);
|
||||||
|
setTtdGeneration((s) => ({
|
||||||
|
generatedResponse: s?.generatedResponse ?? null,
|
||||||
|
prompt: event.target.value,
|
||||||
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const [onTextSubmitInProgess, setOnTextSubmitInProgess] = useState(false);
|
const [onTextSubmitInProgess, setOnTextSubmitInProgess] = useState(false);
|
||||||
@ -131,6 +145,13 @@ export const TTDDialogBase = withInternalFallback(
|
|||||||
const { generatedResponse, error, rateLimit, rateLimitRemaining } =
|
const { generatedResponse, error, rateLimit, rateLimitRemaining } =
|
||||||
await rest.onTextSubmit(prompt);
|
await rest.onTextSubmit(prompt);
|
||||||
|
|
||||||
|
if (typeof generatedResponse === "string") {
|
||||||
|
setTtdGeneration((s) => ({
|
||||||
|
generatedResponse,
|
||||||
|
prompt: s?.prompt ?? null,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
if (isFiniteNumber(rateLimit) && isFiniteNumber(rateLimitRemaining)) {
|
if (isFiniteNumber(rateLimit) && isFiniteNumber(rateLimitRemaining)) {
|
||||||
setRateLimits({ rateLimit, rateLimitRemaining });
|
setRateLimits({ rateLimit, rateLimitRemaining });
|
||||||
}
|
}
|
||||||
@ -153,7 +174,6 @@ export const TTDDialogBase = withInternalFallback(
|
|||||||
mermaidDefinition: generatedResponse,
|
mermaidDefinition: generatedResponse,
|
||||||
});
|
});
|
||||||
trackEvent("ai", "mermaid parse success", "ttd");
|
trackEvent("ai", "mermaid parse success", "ttd");
|
||||||
saveMermaidDataToStorage(generatedResponse);
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.info(
|
console.info(
|
||||||
`%cTTD mermaid render errror: ${error.message}`,
|
`%cTTD mermaid render errror: ${error.message}`,
|
||||||
@ -293,7 +313,32 @@ export const TTDDialogBase = withInternalFallback(
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
renderSubmitShortcut={() => <TTDDialogSubmitShortcut />}
|
||||||
renderBottomRight={() => {
|
renderBottomRight={() => {
|
||||||
|
if (typeof ttdGeneration?.generatedResponse === "string") {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="excalidraw-link"
|
||||||
|
style={{ marginLeft: "auto", fontSize: 14 }}
|
||||||
|
onClick={() => {
|
||||||
|
if (
|
||||||
|
typeof ttdGeneration?.generatedResponse ===
|
||||||
|
"string"
|
||||||
|
) {
|
||||||
|
saveMermaidDataToStorage(
|
||||||
|
ttdGeneration.generatedResponse,
|
||||||
|
);
|
||||||
|
setAppState({
|
||||||
|
openDialog: { name: "ttd", tab: "mermaid" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
View as Mermaid
|
||||||
|
<InlineIcon icon={ArrowRightIcon} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
const ratio = prompt.length / MAX_PROMPT_LENGTH;
|
const ratio = prompt.length / MAX_PROMPT_LENGTH;
|
||||||
if (ratio > 0.8) {
|
if (ratio > 0.8) {
|
||||||
return (
|
return (
|
||||||
|
@ -14,6 +14,7 @@ interface TTDDialogPanelProps {
|
|||||||
panelActionDisabled?: boolean;
|
panelActionDisabled?: boolean;
|
||||||
onTextSubmitInProgess?: boolean;
|
onTextSubmitInProgess?: boolean;
|
||||||
renderTopRight?: () => ReactNode;
|
renderTopRight?: () => ReactNode;
|
||||||
|
renderSubmitShortcut?: () => ReactNode;
|
||||||
renderBottomRight?: () => ReactNode;
|
renderBottomRight?: () => ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,6 +25,7 @@ export const TTDDialogPanel = ({
|
|||||||
panelActionDisabled = false,
|
panelActionDisabled = false,
|
||||||
onTextSubmitInProgess,
|
onTextSubmitInProgess,
|
||||||
renderTopRight,
|
renderTopRight,
|
||||||
|
renderSubmitShortcut,
|
||||||
renderBottomRight,
|
renderBottomRight,
|
||||||
}: TTDDialogPanelProps) => {
|
}: TTDDialogPanelProps) => {
|
||||||
return (
|
return (
|
||||||
@ -51,6 +53,9 @@ export const TTDDialogPanel = ({
|
|||||||
</div>
|
</div>
|
||||||
{onTextSubmitInProgess && <Spinner />}
|
{onTextSubmitInProgess && <Spinner />}
|
||||||
</Button>
|
</Button>
|
||||||
|
{!panelActionDisabled &&
|
||||||
|
!onTextSubmitInProgess &&
|
||||||
|
renderSubmitShortcut?.()}
|
||||||
{renderBottomRight?.()}
|
{renderBottomRight?.()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
14
src/components/TTDDialog/TTDDialogSubmitShortcut.tsx
Normal file
14
src/components/TTDDialog/TTDDialogSubmitShortcut.tsx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { getShortcutKey } from "../../utils";
|
||||||
|
|
||||||
|
export const TTDDialogSubmitShortcut = () => {
|
||||||
|
return (
|
||||||
|
<div className="ttd-dialog-submit-shortcut">
|
||||||
|
<div className="ttd-dialog-submit-shortcut__key">
|
||||||
|
{getShortcutKey("CtrlOrCmd")}
|
||||||
|
</div>
|
||||||
|
<div className="ttd-dialog-submit-shortcut__key">
|
||||||
|
{getShortcutKey("Enter")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -1,6 +1,10 @@
|
|||||||
import { MermaidOptions } from "@excalidraw/mermaid-to-excalidraw";
|
import { MermaidOptions } from "@excalidraw/mermaid-to-excalidraw";
|
||||||
import { MermaidToExcalidrawResult } from "@excalidraw/mermaid-to-excalidraw/dist/interfaces";
|
import { MermaidToExcalidrawResult } from "@excalidraw/mermaid-to-excalidraw/dist/interfaces";
|
||||||
import { DEFAULT_EXPORT_PADDING, DEFAULT_FONT_SIZE } from "../../constants";
|
import {
|
||||||
|
DEFAULT_EXPORT_PADDING,
|
||||||
|
DEFAULT_FONT_SIZE,
|
||||||
|
EDITOR_LS_KEYS,
|
||||||
|
} from "../../constants";
|
||||||
import {
|
import {
|
||||||
convertToExcalidrawElements,
|
convertToExcalidrawElements,
|
||||||
exportToCanvas,
|
exportToCanvas,
|
||||||
@ -8,6 +12,7 @@ import {
|
|||||||
import { NonDeletedExcalidrawElement } from "../../element/types";
|
import { NonDeletedExcalidrawElement } from "../../element/types";
|
||||||
import { AppClassProperties, BinaryFiles } from "../../types";
|
import { AppClassProperties, BinaryFiles } from "../../types";
|
||||||
import { canvasToBlob } from "../../data/blob";
|
import { canvasToBlob } from "../../data/blob";
|
||||||
|
import { EditorLocalStorage } from "../../data/EditorLocalStorage";
|
||||||
|
|
||||||
const resetPreview = ({
|
const resetPreview = ({
|
||||||
canvasRef,
|
canvasRef,
|
||||||
@ -110,7 +115,6 @@ export const convertMermaidToExcalidraw = async ({
|
|||||||
parent.style.background = "var(--default-bg-color)";
|
parent.style.background = "var(--default-bg-color)";
|
||||||
canvasNode.replaceChildren(canvas);
|
canvasNode.replaceChildren(canvas);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error(err);
|
|
||||||
parent.style.background = "var(--default-bg-color)";
|
parent.style.background = "var(--default-bg-color)";
|
||||||
if (mermaidDefinition) {
|
if (mermaidDefinition) {
|
||||||
setError(err);
|
setError(err);
|
||||||
@ -120,14 +124,11 @@ export const convertMermaidToExcalidraw = async ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LOCAL_STORAGE_KEY_MERMAID_TO_EXCALIDRAW = "mermaid-to-excalidraw";
|
export const saveMermaidDataToStorage = (mermaidDefinition: string) => {
|
||||||
export const saveMermaidDataToStorage = (data: string) => {
|
EditorLocalStorage.set(
|
||||||
try {
|
EDITOR_LS_KEYS.MERMAID_TO_EXCALIDRAW,
|
||||||
localStorage.setItem(LOCAL_STORAGE_KEY_MERMAID_TO_EXCALIDRAW, data);
|
mermaidDefinition,
|
||||||
} catch (error: any) {
|
);
|
||||||
// Unable to access window.localStorage
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const insertToEditor = ({
|
export const insertToEditor = ({
|
||||||
|
@ -49,12 +49,12 @@ export const DropDownMenuItemBadge = ({
|
|||||||
style={{
|
style={{
|
||||||
display: "inline-flex",
|
display: "inline-flex",
|
||||||
marginLeft: "auto",
|
marginLeft: "auto",
|
||||||
padding: "1px 4px",
|
padding: "2px 4px",
|
||||||
background: "pink",
|
background: "pink",
|
||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
fontSize: 11,
|
fontSize: 9,
|
||||||
color: "black",
|
color: "black",
|
||||||
fontFamily: "monospace",
|
fontFamily: "Cascadia, monospace",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
@ -373,5 +373,6 @@ export const TOOL_TYPE = {
|
|||||||
export const EDITOR_LS_KEYS = {
|
export const EDITOR_LS_KEYS = {
|
||||||
OAI_API_KEY: "excalidraw-oai-api-key",
|
OAI_API_KEY: "excalidraw-oai-api-key",
|
||||||
// legacy naming (non)scheme
|
// legacy naming (non)scheme
|
||||||
|
MERMAID_TO_EXCALIDRAW: "mermaid-to-excalidraw",
|
||||||
PUBLISH_LIBRARY: "publish-library-data",
|
PUBLISH_LIBRARY: "publish-library-data",
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -53,14 +53,20 @@
|
|||||||
// component (e.g. if you select text in a sidebar)
|
// component (e.g. if you select text in a sidebar)
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
|
.excalidraw-link,
|
||||||
a {
|
a {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: var(--link-color);
|
color: var(--link-color);
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
&:active {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas {
|
canvas {
|
||||||
|
@ -6,5 +6,5 @@ exports[`Test <MermaidToExcalidraw/> > should open mermaid popup when active too
|
|||||||
B --> C{Let me think}
|
B --> C{Let me think}
|
||||||
C -->|One| D[Laptop]
|
C -->|One| D[Laptop]
|
||||||
C -->|Two| E[iPhone]
|
C -->|Two| E[iPhone]
|
||||||
C -->|Three| F[Car]</textarea><div class=\\"ttd-dialog-panel-button-container invisible\\" style=\\"display: flex; align-items: center;\\"><button type=\\"button\\" class=\\"excalidraw-button ttd-dialog-panel-button\\"><div class=\\"\\"></div></button></div></div><div class=\\"ttd-dialog-panel\\"><div class=\\"ttd-dialog-panel__header\\"><label>Preview</label></div><div class=\\"ttd-dialog-output-wrapper\\"><div style=\\"opacity: 1;\\" class=\\"ttd-dialog-output-canvas-container\\"><canvas width=\\"89\\" height=\\"158\\" dir=\\"ltr\\"></canvas></div></div><div class=\\"ttd-dialog-panel-button-container\\" style=\\"display: flex; align-items: center;\\"><button type=\\"button\\" class=\\"excalidraw-button ttd-dialog-panel-button\\"><div class=\\"\\">Insert<span><svg aria-hidden=\\"true\\" focusable=\\"false\\" role=\\"img\\" viewBox=\\"0 0 20 20\\" class=\\"\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\"><g stroke-width=\\"1.25\\"><path d=\\"M4.16602 10H15.8327\\"></path><path d=\\"M12.5 13.3333L15.8333 10\\"></path><path d=\\"M12.5 6.66666L15.8333 9.99999\\"></path></g></svg></span></div></button></div></div></div></div></div></div></div></div></div>"
|
C -->|Three| F[Car]</textarea><div class=\\"ttd-dialog-panel-button-container invisible\\" style=\\"display: flex; align-items: center;\\"><button type=\\"button\\" class=\\"excalidraw-button ttd-dialog-panel-button\\"><div class=\\"\\"></div></button></div></div><div class=\\"ttd-dialog-panel\\"><div class=\\"ttd-dialog-panel__header\\"><label>Preview</label></div><div class=\\"ttd-dialog-output-wrapper\\"><div style=\\"opacity: 1;\\" class=\\"ttd-dialog-output-canvas-container\\"><canvas width=\\"89\\" height=\\"158\\" dir=\\"ltr\\"></canvas></div></div><div class=\\"ttd-dialog-panel-button-container\\" style=\\"display: flex; align-items: center;\\"><button type=\\"button\\" class=\\"excalidraw-button ttd-dialog-panel-button\\"><div class=\\"\\">Insert<span><svg aria-hidden=\\"true\\" focusable=\\"false\\" role=\\"img\\" viewBox=\\"0 0 20 20\\" class=\\"\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\"><g stroke-width=\\"1.25\\"><path d=\\"M4.16602 10H15.8327\\"></path><path d=\\"M12.5 13.3333L15.8333 10\\"></path><path d=\\"M12.5 6.66666L15.8333 9.99999\\"></path></g></svg></span></div></button><div class=\\"ttd-dialog-submit-shortcut\\"><div class=\\"ttd-dialog-submit-shortcut__key\\">Ctrl</div><div class=\\"ttd-dialog-submit-shortcut__key\\">Enter</div></div></div></div></div></div></div></div></div></div></div>"
|
||||||
`;
|
`;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user