feat: TTD dialog tweaks (#7346)
* tweaks to TTD dialog ~ prepping for settings dialog * tweaks to ttd parsing & error logging
This commit is contained in:
parent
fe75f29c15
commit
dd220bcaea
@ -363,8 +363,9 @@ export const ShapesSwitcher = ({
|
|||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
trackEvent("ai", "open-settings", "d2c");
|
trackEvent("ai", "open-settings", "d2c");
|
||||||
app.setOpenDialog({
|
app.setOpenDialog({
|
||||||
name: "magicSettings",
|
name: "settings",
|
||||||
source: "settings",
|
source: "settings",
|
||||||
|
tab: "diagram-to-code",
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
icon={OpenAIIcon}
|
icon={OpenAIIcon}
|
||||||
|
@ -1700,7 +1700,11 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
) {
|
) {
|
||||||
if (!this.OPENAI_KEY) {
|
if (!this.OPENAI_KEY) {
|
||||||
this.setState({
|
this.setState({
|
||||||
openDialog: { name: "magicSettings", source: "generation" },
|
openDialog: {
|
||||||
|
name: "settings",
|
||||||
|
tab: "diagram-to-code",
|
||||||
|
source: "generation",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
trackEvent("ai", "generate (missing key)", "d2c");
|
trackEvent("ai", "generate (missing key)", "d2c");
|
||||||
return;
|
return;
|
||||||
@ -1871,7 +1875,11 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
public onMagicframeToolSelect = () => {
|
public onMagicframeToolSelect = () => {
|
||||||
if (!this.OPENAI_KEY) {
|
if (!this.OPENAI_KEY) {
|
||||||
this.setState({
|
this.setState({
|
||||||
openDialog: { name: "magicSettings", source: "tool" },
|
openDialog: {
|
||||||
|
name: "settings",
|
||||||
|
tab: "diagram-to-code",
|
||||||
|
source: "tool",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
trackEvent("ai", "tool-select (missing key)", "d2c");
|
trackEvent("ai", "tool-select (missing key)", "d2c");
|
||||||
return;
|
return;
|
||||||
|
@ -461,14 +461,14 @@ const LayerUI = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{appState.openDialog?.name === "magicSettings" && (
|
{appState.openDialog?.name === "settings" && (
|
||||||
<MagicSettings
|
<MagicSettings
|
||||||
openAIKey={openAIKey}
|
openAIKey={openAIKey}
|
||||||
isPersisted={isOpenAIKeyPersisted}
|
isPersisted={isOpenAIKeyPersisted}
|
||||||
onChange={onOpenAIAPIKeyChange}
|
onChange={onOpenAIAPIKeyChange}
|
||||||
onConfirm={(apiKey, shouldPersist) => {
|
onConfirm={(apiKey, shouldPersist) => {
|
||||||
const source =
|
const source =
|
||||||
appState.openDialog?.name === "magicSettings"
|
appState.openDialog?.name === "settings"
|
||||||
? appState.openDialog?.source
|
? appState.openDialog?.source
|
||||||
: "settings";
|
: "settings";
|
||||||
setAppState({ openDialog: null }, () => {
|
setAppState({ openDialog: null }, () => {
|
||||||
|
@ -1,9 +1,18 @@
|
|||||||
.excalidraw {
|
.excalidraw {
|
||||||
|
.MagicSettings {
|
||||||
|
.Island {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.MagicSettings-confirm {
|
.MagicSettings-confirm {
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.MagicSettings__confirm {
|
.MagicSettings__confirm {
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import { InlineIcon } from "./InlineIcon";
|
|||||||
import { Paragraph } from "./Paragraph";
|
import { Paragraph } from "./Paragraph";
|
||||||
|
|
||||||
import "./MagicSettings.scss";
|
import "./MagicSettings.scss";
|
||||||
|
import TTDDialogTabs from "./TTDDialog/TTDDialogTabs";
|
||||||
|
import { TTDDialogTab } from "./TTDDialog/TTDDialogTab";
|
||||||
|
|
||||||
export const MagicSettings = (props: {
|
export const MagicSettings = (props: {
|
||||||
openAIKey: string | null;
|
openAIKey: string | null;
|
||||||
@ -18,16 +20,21 @@ export const MagicSettings = (props: {
|
|||||||
onConfirm: (key: string, shouldPersist: boolean) => void;
|
onConfirm: (key: string, shouldPersist: boolean) => void;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
const { theme } = useUIAppState();
|
|
||||||
const [keyInputValue, setKeyInputValue] = useState(props.openAIKey || "");
|
const [keyInputValue, setKeyInputValue] = useState(props.openAIKey || "");
|
||||||
const [shouldPersist, setShouldPersist] = useState<boolean>(
|
const [shouldPersist, setShouldPersist] = useState<boolean>(
|
||||||
props.isPersisted,
|
props.isPersisted,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const appState = useUIAppState();
|
||||||
|
|
||||||
const onConfirm = () => {
|
const onConfirm = () => {
|
||||||
props.onConfirm(keyInputValue.trim(), shouldPersist);
|
props.onConfirm(keyInputValue.trim(), shouldPersist);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (appState.openDialog?.name !== "settings") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
onCloseRequest={() => {
|
onCloseRequest={() => {
|
||||||
@ -36,7 +43,7 @@ export const MagicSettings = (props: {
|
|||||||
}}
|
}}
|
||||||
title={
|
title={
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
Diagram to Code (AI){" "}
|
Wireframe to Code (AI){" "}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@ -46,7 +53,8 @@ export const MagicSettings = (props: {
|
|||||||
marginLeft: "1rem",
|
marginLeft: "1rem",
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
borderRadius: "12px",
|
borderRadius: "12px",
|
||||||
background: theme === "light" ? "#FFCCCC" : "#703333",
|
color: "#000",
|
||||||
|
background: "pink",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Experimental
|
Experimental
|
||||||
@ -56,75 +64,97 @@ export const MagicSettings = (props: {
|
|||||||
className="MagicSettings"
|
className="MagicSettings"
|
||||||
autofocus={false}
|
autofocus={false}
|
||||||
>
|
>
|
||||||
<Paragraph
|
{/* <h2
|
||||||
style={{
|
style={{
|
||||||
display: "inline-flex",
|
margin: 0,
|
||||||
alignItems: "center",
|
fontSize: "1.25rem",
|
||||||
marginBottom: 0,
|
paddingLeft: "2.5rem",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
For the diagram-to-code feature we use <InlineIcon icon={OpenAIIcon} />
|
AI Settings
|
||||||
OpenAI.
|
</h2> */}
|
||||||
</Paragraph>
|
<TTDDialogTabs dialog="settings" tab={appState.openDialog.tab}>
|
||||||
<Paragraph>
|
{/* <TTDDialogTabTriggers>
|
||||||
While the OpenAI API is in beta, its use is strictly limited — as such
|
<TTDDialogTabTrigger tab="text-to-diagram">
|
||||||
we require you use your own API key. You can create an{" "}
|
<InlineIcon icon={brainIcon} /> Text to diagram
|
||||||
<a
|
</TTDDialogTabTrigger>
|
||||||
href="https://platform.openai.com/login?launch"
|
<TTDDialogTabTrigger tab="diagram-to-code">
|
||||||
rel="noopener noreferrer"
|
<InlineIcon icon={MagicIcon} /> Wireframe to code
|
||||||
target="_blank"
|
</TTDDialogTabTrigger>
|
||||||
|
</TTDDialogTabTriggers> */}
|
||||||
|
{/* <TTDDialogTab className="ttd-dialog-content" tab="text-to-diagram">
|
||||||
|
TODO
|
||||||
|
</TTDDialogTab> */}
|
||||||
|
<TTDDialogTab
|
||||||
|
// className="ttd-dialog-content"
|
||||||
|
tab="diagram-to-code"
|
||||||
>
|
>
|
||||||
OpenAI account
|
<Paragraph>
|
||||||
</a>
|
For the diagram-to-code feature we use{" "}
|
||||||
, add a small credit (5 USD minimum), and{" "}
|
<InlineIcon icon={OpenAIIcon} />
|
||||||
<a
|
OpenAI.
|
||||||
href="https://platform.openai.com/api-keys"
|
</Paragraph>
|
||||||
rel="noopener noreferrer"
|
<Paragraph>
|
||||||
target="_blank"
|
While the OpenAI API is in beta, its use is strictly limited — as
|
||||||
>
|
such we require you use your own API key. You can create an{" "}
|
||||||
generate your own API key
|
<a
|
||||||
</a>
|
href="https://platform.openai.com/login?launch"
|
||||||
.
|
rel="noopener noreferrer"
|
||||||
</Paragraph>
|
target="_blank"
|
||||||
<Paragraph>
|
>
|
||||||
Your OpenAI key does not leave the browser, and you can also set your
|
OpenAI account
|
||||||
own limit in your OpenAI account dashboard if needed.
|
</a>
|
||||||
</Paragraph>
|
, add a small credit (5 USD minimum), and{" "}
|
||||||
<TextField
|
<a
|
||||||
isRedacted
|
href="https://platform.openai.com/api-keys"
|
||||||
value={keyInputValue}
|
rel="noopener noreferrer"
|
||||||
placeholder="Paste your API key here"
|
target="_blank"
|
||||||
label="OpenAI API key"
|
>
|
||||||
onChange={(value) => {
|
generate your own API key
|
||||||
setKeyInputValue(value);
|
</a>
|
||||||
props.onChange(value.trim(), shouldPersist);
|
.
|
||||||
}}
|
</Paragraph>
|
||||||
selectOnRender
|
<Paragraph>
|
||||||
onKeyDown={(event) => event.key === KEYS.ENTER && onConfirm()}
|
Your OpenAI key does not leave the browser, and you can also set
|
||||||
/>
|
your own limit in your OpenAI account dashboard if needed.
|
||||||
<Paragraph>
|
</Paragraph>
|
||||||
By default, your API token is not persisted anywhere so you'll need to
|
<TextField
|
||||||
insert it again after reload. But, you can persist locally in your
|
isRedacted
|
||||||
browser below.
|
value={keyInputValue}
|
||||||
</Paragraph>
|
placeholder="Paste your API key here"
|
||||||
|
label="OpenAI API key"
|
||||||
|
onChange={(value) => {
|
||||||
|
setKeyInputValue(value);
|
||||||
|
props.onChange(value.trim(), shouldPersist);
|
||||||
|
}}
|
||||||
|
selectOnRender
|
||||||
|
onKeyDown={(event) => event.key === KEYS.ENTER && onConfirm()}
|
||||||
|
/>
|
||||||
|
<Paragraph>
|
||||||
|
By default, your API token is not persisted anywhere so you'll need
|
||||||
|
to insert it again after reload. But, you can persist locally in
|
||||||
|
your browser below.
|
||||||
|
</Paragraph>
|
||||||
|
|
||||||
<CheckboxItem checked={shouldPersist} onChange={setShouldPersist}>
|
<CheckboxItem checked={shouldPersist} onChange={setShouldPersist}>
|
||||||
Persist API key in browser storage
|
Persist API key in browser storage
|
||||||
</CheckboxItem>
|
</CheckboxItem>
|
||||||
|
|
||||||
<Paragraph>
|
<Paragraph>
|
||||||
Once API key is set, you can use the <InlineIcon icon={MagicIcon} />{" "}
|
Once API key is set, you can use the <InlineIcon icon={MagicIcon} />{" "}
|
||||||
tool to wrap your elements in a frame that will then allow you to turn
|
tool to wrap your elements in a frame that will then allow you to
|
||||||
it into code. This dialog can be accessed using the <b>AI Settings</b>{" "}
|
turn it into code. This dialog can be accessed using the{" "}
|
||||||
<InlineIcon icon={OpenAIIcon} />.
|
<b>AI Settings</b> <InlineIcon icon={OpenAIIcon} />.
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
|
|
||||||
<FilledButton
|
<FilledButton
|
||||||
className="MagicSettings__confirm"
|
className="MagicSettings__confirm"
|
||||||
size="large"
|
size="large"
|
||||||
label="Confirm"
|
label="Confirm"
|
||||||
onClick={onConfirm}
|
onClick={onConfirm}
|
||||||
/>
|
/>
|
||||||
|
</TTDDialogTab>
|
||||||
|
</TTDDialogTabs>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -18,8 +18,11 @@
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: calc(var(--space-factor) * 10);
|
padding: calc(var(--space-factor) * 10);
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
.Island {
|
.Island {
|
||||||
padding: 2.5rem !important;
|
padding: 2.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ const MermaidToExcalidraw = ({
|
|||||||
data,
|
data,
|
||||||
mermaidToExcalidrawLib,
|
mermaidToExcalidrawLib,
|
||||||
setError,
|
setError,
|
||||||
text: deferredText,
|
mermaidDefinition: deferredText,
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
}, [deferredText, mermaidToExcalidrawLib]);
|
}, [deferredText, mermaidToExcalidrawLib]);
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ export const TTDDialogBase = withInternalFallback(
|
|||||||
tab,
|
tab,
|
||||||
...rest
|
...rest
|
||||||
}: {
|
}: {
|
||||||
tab: string;
|
tab: "text-to-diagram" | "mermaid";
|
||||||
} & (
|
} & (
|
||||||
| {
|
| {
|
||||||
onTextSubmit(value: string): Promise<OnTestSubmitRetValue>;
|
onTextSubmit(value: string): Promise<OnTestSubmitRetValue>;
|
||||||
@ -150,11 +150,19 @@ export const TTDDialogBase = withInternalFallback(
|
|||||||
data,
|
data,
|
||||||
mermaidToExcalidrawLib,
|
mermaidToExcalidrawLib,
|
||||||
setError,
|
setError,
|
||||||
text: generatedResponse,
|
mermaidDefinition: generatedResponse,
|
||||||
});
|
});
|
||||||
trackEvent("ai", "mermaid parse success", "ttd");
|
trackEvent("ai", "mermaid parse success", "ttd");
|
||||||
saveMermaidDataToStorage(generatedResponse);
|
saveMermaidDataToStorage(generatedResponse);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
console.info(
|
||||||
|
`%cTTD mermaid render errror: ${error.message}`,
|
||||||
|
"color: red",
|
||||||
|
);
|
||||||
|
console.info(
|
||||||
|
`>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\nTTD mermaid definition render errror: ${error.message}`,
|
||||||
|
"color: yellow",
|
||||||
|
);
|
||||||
trackEvent("ai", "mermaid parse failed", "ttd");
|
trackEvent("ai", "mermaid parse failed", "ttd");
|
||||||
setError(
|
setError(
|
||||||
new Error(
|
new Error(
|
||||||
@ -206,17 +214,34 @@ export const TTDDialogBase = withInternalFallback(
|
|||||||
app.setOpenDialog(null);
|
app.setOpenDialog(null);
|
||||||
}}
|
}}
|
||||||
size={1200}
|
size={1200}
|
||||||
title=""
|
title={false}
|
||||||
{...rest}
|
{...rest}
|
||||||
autofocus={false}
|
autofocus={false}
|
||||||
>
|
>
|
||||||
<TTDDialogTabs tab={tab}>
|
<TTDDialogTabs dialog="ttd" tab={tab}>
|
||||||
{"__fallback" in rest && rest.__fallback ? (
|
{"__fallback" in rest && rest.__fallback ? (
|
||||||
<p className="dialog-mermaid-title">{t("mermaid.title")}</p>
|
<p className="dialog-mermaid-title">{t("mermaid.title")}</p>
|
||||||
) : (
|
) : (
|
||||||
<TTDDialogTabTriggers>
|
<TTDDialogTabTriggers>
|
||||||
<TTDDialogTabTrigger tab="text-to-diagram">
|
<TTDDialogTabTrigger tab="text-to-diagram">
|
||||||
{t("labels.textToDiagram")}
|
<div style={{ display: "flex", alignItems: "center" }}>
|
||||||
|
{t("labels.textToDiagram")}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
padding: "1px 6px",
|
||||||
|
marginLeft: "10px",
|
||||||
|
fontSize: 10,
|
||||||
|
borderRadius: "12px",
|
||||||
|
background: "pink",
|
||||||
|
color: "#000",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
AI Beta
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</TTDDialogTabTrigger>
|
</TTDDialogTabTrigger>
|
||||||
<TTDDialogTabTrigger tab="mermaid">Mermaid</TTDDialogTabTrigger>
|
<TTDDialogTabTrigger tab="mermaid">Mermaid</TTDDialogTabTrigger>
|
||||||
</TTDDialogTabTriggers>
|
</TTDDialogTabTriggers>
|
||||||
|
@ -1,34 +1,60 @@
|
|||||||
import * as RadixTabs from "@radix-ui/react-tabs";
|
import * as RadixTabs from "@radix-ui/react-tabs";
|
||||||
import { ReactNode } from "react";
|
import { ReactNode, useRef } from "react";
|
||||||
import { useExcalidrawSetAppState } from "../App";
|
import { useExcalidrawSetAppState } from "../App";
|
||||||
|
import { isMemberOf } from "../../utils";
|
||||||
|
|
||||||
const TTDDialogTabs = ({
|
const TTDDialogTabs = (
|
||||||
children,
|
props: {
|
||||||
tab,
|
children: ReactNode;
|
||||||
...rest
|
} & (
|
||||||
}: {
|
| { dialog: "ttd"; tab: "text-to-diagram" | "mermaid" }
|
||||||
children: ReactNode;
|
| { dialog: "settings"; tab: "text-to-diagram" | "diagram-to-code" }
|
||||||
tab: string;
|
),
|
||||||
}) => {
|
) => {
|
||||||
const setAppState = useExcalidrawSetAppState();
|
const setAppState = useExcalidrawSetAppState();
|
||||||
|
|
||||||
|
const rootRef = useRef<HTMLDivElement>(null);
|
||||||
|
const minHeightRef = useRef<number>(0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RadixTabs.Root
|
<RadixTabs.Root
|
||||||
|
ref={rootRef}
|
||||||
className="ttd-dialog-tabs-root"
|
className="ttd-dialog-tabs-root"
|
||||||
value={tab}
|
value={props.tab}
|
||||||
onValueChange={(
|
onValueChange={(
|
||||||
// at least in test enviros, `tab` can be `undefined`
|
// at least in test enviros, `tab` can be `undefined`
|
||||||
tab: string | undefined,
|
tab: string | undefined,
|
||||||
) => {
|
) => {
|
||||||
if (tab) {
|
if (!tab) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const modalContentNode =
|
||||||
|
rootRef.current?.closest<HTMLElement>(".Modal__content");
|
||||||
|
if (modalContentNode) {
|
||||||
|
const currHeight = modalContentNode.offsetHeight || 0;
|
||||||
|
if (currHeight > minHeightRef.current) {
|
||||||
|
minHeightRef.current = currHeight;
|
||||||
|
modalContentNode.style.minHeight = `min(${minHeightRef.current}px, 100%)`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
props.dialog === "settings" &&
|
||||||
|
isMemberOf(["text-to-diagram", "diagram-to-code"], tab)
|
||||||
|
) {
|
||||||
setAppState({
|
setAppState({
|
||||||
openDialog: { name: "ttd", tab },
|
openDialog: { name: props.dialog, tab, source: "settings" },
|
||||||
|
});
|
||||||
|
} else if (
|
||||||
|
props.dialog === "ttd" &&
|
||||||
|
isMemberOf(["text-to-diagram", "mermaid"], tab)
|
||||||
|
) {
|
||||||
|
setAppState({
|
||||||
|
openDialog: { name: props.dialog, tab },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
{...rest}
|
|
||||||
>
|
>
|
||||||
{children}
|
{props.children}
|
||||||
</RadixTabs.Root>
|
</RadixTabs.Root>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -43,7 +43,7 @@ export interface MermaidToExcalidrawLibProps {
|
|||||||
interface ConvertMermaidToExcalidrawFormatProps {
|
interface ConvertMermaidToExcalidrawFormatProps {
|
||||||
canvasRef: React.RefObject<HTMLDivElement>;
|
canvasRef: React.RefObject<HTMLDivElement>;
|
||||||
mermaidToExcalidrawLib: MermaidToExcalidrawLibProps;
|
mermaidToExcalidrawLib: MermaidToExcalidrawLibProps;
|
||||||
text: string;
|
mermaidDefinition: string;
|
||||||
setError: (error: Error | null) => void;
|
setError: (error: Error | null) => void;
|
||||||
data: React.MutableRefObject<{
|
data: React.MutableRefObject<{
|
||||||
elements: readonly NonDeletedExcalidrawElement[];
|
elements: readonly NonDeletedExcalidrawElement[];
|
||||||
@ -54,7 +54,7 @@ interface ConvertMermaidToExcalidrawFormatProps {
|
|||||||
export const convertMermaidToExcalidraw = async ({
|
export const convertMermaidToExcalidraw = async ({
|
||||||
canvasRef,
|
canvasRef,
|
||||||
mermaidToExcalidrawLib,
|
mermaidToExcalidrawLib,
|
||||||
text,
|
mermaidDefinition,
|
||||||
setError,
|
setError,
|
||||||
data,
|
data,
|
||||||
}: ConvertMermaidToExcalidrawFormatProps) => {
|
}: ConvertMermaidToExcalidrawFormatProps) => {
|
||||||
@ -65,7 +65,7 @@ export const convertMermaidToExcalidraw = async ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!text) {
|
if (!mermaidDefinition) {
|
||||||
resetPreview({ canvasRef, setError });
|
resetPreview({ canvasRef, setError });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -73,9 +73,20 @@ export const convertMermaidToExcalidraw = async ({
|
|||||||
try {
|
try {
|
||||||
const api = await mermaidToExcalidrawLib.api;
|
const api = await mermaidToExcalidrawLib.api;
|
||||||
|
|
||||||
const { elements, files } = await api.parseMermaidToExcalidraw(text, {
|
let ret;
|
||||||
fontSize: DEFAULT_FONT_SIZE,
|
try {
|
||||||
});
|
ret = await api.parseMermaidToExcalidraw(mermaidDefinition, {
|
||||||
|
fontSize: DEFAULT_FONT_SIZE,
|
||||||
|
});
|
||||||
|
} catch (err: any) {
|
||||||
|
ret = await api.parseMermaidToExcalidraw(
|
||||||
|
mermaidDefinition.replace(/"/g, "'"),
|
||||||
|
{
|
||||||
|
fontSize: DEFAULT_FONT_SIZE,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const { elements, files } = ret;
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
data.current = {
|
data.current = {
|
||||||
@ -101,7 +112,7 @@ export const convertMermaidToExcalidraw = async ({
|
|||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
parent.style.background = "var(--default-bg-color)";
|
parent.style.background = "var(--default-bg-color)";
|
||||||
if (text) {
|
if (mermaidDefinition) {
|
||||||
setError(err);
|
setError(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,6 +652,19 @@
|
|||||||
--button-bg: var(--color-surface-high);
|
--button-bg: var(--color-surface-high);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.excalidraw__paragraph {
|
||||||
|
margin: 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Modal__content {
|
||||||
|
.excalidraw__paragraph:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
.excalidraw__paragraph + .excalidraw__paragraph {
|
||||||
|
margin-top: 0rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ErrorSplash.excalidraw {
|
.ErrorSplash.excalidraw {
|
||||||
@ -735,8 +748,4 @@
|
|||||||
letter-spacing: 0.6px;
|
letter-spacing: 0.6px;
|
||||||
font-family: "Assistant";
|
font-family: "Assistant";
|
||||||
}
|
}
|
||||||
|
|
||||||
.excalidraw__paragraph {
|
|
||||||
margin: 1rem 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -248,13 +248,14 @@ export interface AppState {
|
|||||||
| null
|
| null
|
||||||
| { name: "imageExport" | "help" | "jsonExport" }
|
| { name: "imageExport" | "help" | "jsonExport" }
|
||||||
| {
|
| {
|
||||||
name: "magicSettings";
|
name: "settings";
|
||||||
source:
|
source:
|
||||||
| "tool" // when magicframe tool is selected
|
| "tool" // when magicframe tool is selected
|
||||||
| "generation" // when magicframe generate button is clicked
|
| "generation" // when magicframe generate button is clicked
|
||||||
| "settings"; // when AI settings dialog is explicitly invoked
|
| "settings"; // when AI settings dialog is explicitly invoked
|
||||||
|
tab: "text-to-diagram" | "diagram-to-code";
|
||||||
}
|
}
|
||||||
| { name: "ttd"; tab: string };
|
| { name: "ttd"; tab: "text-to-diagram" | "mermaid" };
|
||||||
/**
|
/**
|
||||||
* Reflects user preference for whether the default sidebar should be docked.
|
* Reflects user preference for whether the default sidebar should be docked.
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user