Skip to content

Commit

Permalink
Add Nomnoml Renderer (#526)
Browse files Browse the repository at this point in the history
* added nomnoml

* began drafting NomnomlPreview.tsx

* began adding handleCopy and useEffect based on MermaidPreview component

* mirrored imports based on MermaidPreview component

* drafted fetchNomnoml() and modeled Card component off of MermaidPreview.tsx

* added error handling to catch block

* added elif block for handling nomnoml codeblocks

* added width autofitting to nomnoml svg

* removed nanoid, commented code, console.log statements

* added nomnoml to pnpm lock file

* updated Instructions blurb

* moved try/catch syntax inside fetchNomnoml to properly catch any errors from renderSvg()

* updated comments

* updated comments

* updated default system prompt to include nomnoml responses

* added error message to UI for when nomnoml rendering fails

* updated error message

* updated visual topics rule typo
  • Loading branch information
rjwignar committed Mar 28, 2024
1 parent 337f0f5 commit 947ff75
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 2 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"lodash-es": "^4.17.21",
"mermaid": "^10.8.0",
"nanoid": "^5.0.5",
"nomnoml": "^1.6.2",
"openai": "^4.26.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand Down
15 changes: 15 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/components/Markdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import oneLight from "react-syntax-highlighter/dist/esm/styles/hljs/atom-one-lig
import CodeHeader from "./CodeHeader";
import HtmlPreview from "./HtmlPreview";
import MermaidPreview from "./MermaidPreview";
import NomnomlPreview from "./NomnomlPreview";

const fixLanguageName = (language: string | null) => {
if (!language) {
Expand Down Expand Up @@ -108,6 +109,10 @@ function Markdown({
preview = (
<MermaidPreview children={Array.isArray(children) ? children : [children]} />
);
} else if (language === "nomnoml") {
preview = (
<NomnomlPreview children={Array.isArray(children) ? children : [children]} />
);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/Message/AppMessage/Instructions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ We think ChatCraft is the best platform for learning, experimenting, and getting
| ------------------------------------- |:---------:|:-------:|:-------:|
| Optimized for conversations about code | ✅ | ❌ | ❌ |
| Work with models from multiple AI vendors | ✅ |❌ | ❌ |
| Previews for Mermaid Diagrams, HTML | ✅ | ❌ | ❌ |
| Previews for Mermaid/Nomnoml Diagrams, HTML | ✅ | ❌ | ❌ |
| Edit Generated AI Replies | ✅ | ❌ | ✅ |
| Use Custom System Prompts | ✅ | ✅ | ❌ |
| Easy to retry with different AI models| ✅ | ❌ | ❌ |
Expand Down
85 changes: 85 additions & 0 deletions src/components/NomnomlPreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { memo, useCallback, useEffect, useRef, type ReactNode } from "react";
import { Card, CardBody, IconButton, useClipboard } from "@chakra-ui/react";
import { TbCopy } from "react-icons/tb";
import { useAlert } from "../hooks/use-alert";

type NomnomlPreviewProps = {
children: ReactNode & ReactNode[];
};

const NomnomlPreview = ({ children }: NomnomlPreviewProps) => {
const { onCopy, value, setValue } = useClipboard("");
const { info } = useAlert();
const diagramRef = useRef<HTMLDivElement | null>(null);
const code = String(children);

const handleCopy = useCallback(() => {
onCopy();
info({
title: "Copied to Clipboard",
message: "Nomnoml SVG diagram was copied to your clipboard.",
});
}, [onCopy, info]);

// Render the diagram as an SVG into our card's body
useEffect(() => {
const diagramDiv = diagramRef.current;
if (!diagramDiv) {
return;
}

const fetchNomnoml = async () => {
try {
// Load nomnoml dynamically at runtime if needed
const nomnoml = await import("nomnoml");
const svg = await nomnoml.renderSvg(code);

setValue(svg);

// Render nomnoml svg if successful
diagramDiv.innerHTML = svg;

// Adjust the width of the SVG to fit the content inside the CardBody
const svgElement = diagramDiv.querySelector("svg");
if (svgElement) {
svgElement.style.width = "100%";
}
} catch (err: any) {
// When the diagram fails, use the error vs. diagram for copying (to debug)
setValue(err);

// Render custom error message instead of error or blank content
const errMessage = `Error rendering Nomnoml diagram`;
diagramDiv.innerHTML = errMessage;
console.warn(`Error rendering nomnoml diagram`, err);
}
};
fetchNomnoml();
}, [diagramRef, code, setValue]);

return (
<Card variant="outline" position="relative" mt={2} minHeight="12em" resize="vertical">
<IconButton
position="absolute"
right={1}
top={1}
zIndex={50}
aria-label="Copy Diagram to Clipboard"
title="Copy Diagram to Clipboard"
icon={<TbCopy />}
color="gray.600"
_dark={{ color: "gray.300" }}
variant="ghost"
onClick={() => handleCopy()}
isDisabled={!value}
/>

<CardBody p={2}>
<div ref={diagramRef} />
</CardBody>
</Card>
);
};

// Memoize to reduce re-renders/flickering when content hasn't changed
export default memo(NomnomlPreview);
2 changes: 1 addition & 1 deletion src/lib/system-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ I follow these rules when responding:
- Use GitHub flavored Markdown
- ALWAYS include the programming language name (js) or type of data (csv) at the start of Markdown code blocks
- Format ALL lines of code to 80 characters or fewer
- Use Mermaid diagrams when discussing visual topics
- Use Nomnoml or Mermaid diagrams when discussing visual topics
- If using functions, only use the specific functions I have been provided with
- If responding with math markdown, inline or otherwise, I use KaTeX syntax in math Markdown by enclosing EVERY mathematical expression, equation, variable, and formula with double-dollar signs \`($$)\`, for example: $$O(n\\log n)$$, $$1024 * 1024 = 1048576$$, $$1024^2$$, $$X$$
`;
Expand Down

0 comments on commit 947ff75

Please sign in to comment.