From 7779dd9c897187d6e155687233dc2aab3bf77914 Mon Sep 17 00:00:00 2001
From: listlessbird <124798751+listlessbird@users.noreply.github.com>
Date: Wed, 30 Oct 2024 01:16:05 +0530
Subject: [PATCH 1/3] feat: add raw markdown view for text
---
src/components/artifacts/ArtifactRenderer.tsx | 15 +++
src/components/artifacts/TextRenderer.tsx | 95 +++++++++++--------
2 files changed, 71 insertions(+), 39 deletions(-)
diff --git a/src/components/artifacts/ArtifactRenderer.tsx b/src/components/artifacts/ArtifactRenderer.tsx
index a7ddd58d..e88990ee 100644
--- a/src/components/artifacts/ArtifactRenderer.tsx
+++ b/src/components/artifacts/ArtifactRenderer.tsx
@@ -18,6 +18,7 @@ import {
Copy,
LoaderCircle,
CircleCheck,
+ Eye,
} from "lucide-react";
import {
Dispatch,
@@ -86,6 +87,7 @@ export function ArtifactRenderer(props: ArtifactRendererProps) {
const [isInputVisible, setIsInputVisible] = useState(false);
const [isSelectionActive, setIsSelectionActive] = useState(false);
const [inputValue, setInputValue] = useState("");
+ const [isRawView, setIsRawView] = useState(false);
const handleMouseUp = useCallback(() => {
const selection = window.getSelection();
@@ -377,6 +379,18 @@ export function ArtifactRenderer(props: ArtifactRendererProps) {
/>
+
setIsRawView((p) => !p)}
+ className={cn(
+ "transition-colors w-fit h-fit p-2",
+ isRawView && "bg-gray-100 text-gray-900"
+ )}
+ >
+
+
) : null}
{currentArtifactContent.type === "code" ? (
diff --git a/src/components/artifacts/TextRenderer.tsx b/src/components/artifacts/TextRenderer.tsx
index 4135bad1..0fc4c5a5 100644
--- a/src/components/artifacts/TextRenderer.tsx
+++ b/src/components/artifacts/TextRenderer.tsx
@@ -24,11 +24,14 @@ export interface TextRendererProps {
updateRenderedArtifactRequired: boolean;
setUpdateRenderedArtifactRequired: Dispatch
>;
firstTokenReceived: boolean;
+ isRawView: boolean;
}
export function TextRenderer(props: TextRendererProps) {
const editor = useCreateBlockNote({});
+ const [rawMarkdown, setRawMarkdown] = useState("");
+
const [manuallyUpdatingArtifact, setManuallyUpdatingArtifact] =
useState(false);
@@ -110,6 +113,12 @@ export function TextRenderer(props: TextRendererProps) {
}
}, [props.artifact, props.updateRenderedArtifactRequired]);
+ useEffect(() => {
+ if (props.isRawView) {
+ editor.blocksToMarkdownLossy(editor.document).then(setRawMarkdown);
+ }
+ }, [props.isRawView, editor]);
+
const isComposition = useRef(false);
const onChange = async () => {
@@ -153,45 +162,53 @@ export function TextRenderer(props: TextRendererProps) {
return (
-
-
(isComposition.current = true)}
- onCompositionEndCapture={() => (isComposition.current = false)}
- onChange={onChange}
- editable={
- !props.isStreaming || props.isEditing || !manuallyUpdatingArtifact
- }
- editor={editor}
- className={
- props.isStreaming && !props.firstTokenReceived ? "pulse-text" : ""
- }
- >
-
- getDefaultReactSlashMenuItems(editor).filter(
- (z) => z.group !== "Media"
- )
- }
- triggerCharacter={"/"}
- />
-
+ {props.isRawView ? (
+
+ {rawMarkdown}
+
+ ) : (
+ <>
+
+
(isComposition.current = true)}
+ onCompositionEndCapture={() => (isComposition.current = false)}
+ onChange={onChange}
+ editable={
+ !props.isStreaming || props.isEditing || !manuallyUpdatingArtifact
+ }
+ editor={editor}
+ className={
+ props.isStreaming && !props.firstTokenReceived ? "pulse-text" : ""
+ }
+ >
+
+ getDefaultReactSlashMenuItems(editor).filter(
+ (z) => z.group !== "Media"
+ )
+ }
+ triggerCharacter={"/"}
+ />
+
+ >
+ )}
);
}
From 37732ebcc425e1afffa9288b80787a2caa03614b Mon Sep 17 00:00:00 2001
From: bracesproul
Date: Tue, 29 Oct 2024 16:43:53 -0700
Subject: [PATCH 2/3] format
---
src/components/artifacts/TextRenderer.tsx | 74 ++++++++++++-----------
1 file changed, 38 insertions(+), 36 deletions(-)
diff --git a/src/components/artifacts/TextRenderer.tsx b/src/components/artifacts/TextRenderer.tsx
index 0c78a284..2d324196 100644
--- a/src/components/artifacts/TextRenderer.tsx
+++ b/src/components/artifacts/TextRenderer.tsx
@@ -195,45 +195,47 @@ export function TextRendererComponent(props: TextRendererProps) {
) : (
<>
-
- (isComposition.current = true)}
- onCompositionEndCapture={() => (isComposition.current = false)}
- onChange={onChange}
- editable={!isStreaming || props.isEditing || !manuallyUpdatingArtifact}
- editor={editor}
- className={isStreaming && !firstTokenReceived ? "pulse-text" : ""}
- >
-
- getDefaultReactSlashMenuItems(editor).filter(
- (z) => z.group !== "Media"
- )
- }
- triggerCharacter={"/"}
- />
-
+
+ (isComposition.current = true)}
+ onCompositionEndCapture={() => (isComposition.current = false)}
+ onChange={onChange}
+ editable={
+ !isStreaming || props.isEditing || !manuallyUpdatingArtifact
+ }
+ editor={editor}
+ className={isStreaming && !firstTokenReceived ? "pulse-text" : ""}
+ >
+
+ getDefaultReactSlashMenuItems(editor).filter(
+ (z) => z.group !== "Media"
+ )
+ }
+ triggerCharacter={"/"}
+ />
+
>
)}
- )
+ );
}
export const TextRenderer = React.memo(TextRendererComponent);
From 9f5dc012b2709f9b65035fb470a1ec34cb82500b Mon Sep 17 00:00:00 2001
From: bracesproul
Date: Tue, 29 Oct 2024 17:17:39 -0700
Subject: [PATCH 3/3] make editable
---
src/components/artifacts/TextRenderer.tsx | 105 ++++++++++++++++++----
src/constants.ts | 2 +-
2 files changed, 87 insertions(+), 20 deletions(-)
diff --git a/src/components/artifacts/TextRenderer.tsx b/src/components/artifacts/TextRenderer.tsx
index 2d324196..1454783e 100644
--- a/src/components/artifacts/TextRenderer.tsx
+++ b/src/components/artifacts/TextRenderer.tsx
@@ -1,4 +1,4 @@
-import { useEffect, useRef, useState } from "react";
+import { Dispatch, SetStateAction, useEffect, useRef, useState } from "react";
import { ArtifactMarkdownV3 } from "@/types";
import "@blocknote/core/fonts/inter.css";
import {
@@ -14,13 +14,44 @@ import { getArtifactContent } from "@/contexts/utils";
import { useGraphContext } from "@/contexts/GraphContext";
import React from "react";
import { TooltipIconButton } from "../ui/assistant-ui/tooltip-icon-button";
-import { Eye } from "lucide-react";
-import { cn } from "@/lib/utils";
+import { Eye, EyeOff } from "lucide-react";
+import { motion } from "framer-motion";
+import { Textarea } from "../ui/textarea";
const cleanText = (text: string) => {
return text.replaceAll("\\\n", "\n");
};
+function ViewRawText({
+ isRawView,
+ setIsRawView,
+}: {
+ isRawView: boolean;
+ setIsRawView: Dispatch>;
+}) {
+ return (
+
+ setIsRawView((p) => !p)}
+ >
+ {isRawView ? (
+
+ ) : (
+
+ )}
+
+
+ );
+}
+
export interface TextRendererProps {
isEditing: boolean;
isHovering: boolean;
@@ -126,6 +157,18 @@ export function TextRendererComponent(props: TextRendererProps) {
useEffect(() => {
if (isRawView) {
editor.blocksToMarkdownLossy(editor.document).then(setRawMarkdown);
+ } else if (!isRawView && rawMarkdown) {
+ try {
+ (async () => {
+ setManuallyUpdatingArtifact(true);
+ const markdownAsBlocks =
+ await editor.tryParseMarkdownToBlocks(rawMarkdown);
+ editor.replaceBlocks(editor.document, markdownAsBlocks);
+ setManuallyUpdatingArtifact(false);
+ })();
+ } catch (_) {
+ setManuallyUpdatingArtifact(false);
+ }
}
}, [isRawView, editor]);
@@ -170,29 +213,53 @@ export function TextRendererComponent(props: TextRendererProps) {
});
};
+ const onChangeRawMarkdown = (e: React.ChangeEvent) => {
+ const newRawMarkdown = e.target.value;
+ setRawMarkdown(newRawMarkdown);
+ setArtifact((prev) => {
+ if (!prev) {
+ return {
+ currentIndex: 1,
+ contents: [
+ {
+ index: 1,
+ fullMarkdown: newRawMarkdown,
+ title: "Untitled",
+ type: "text",
+ },
+ ],
+ };
+ } else {
+ return {
+ ...prev,
+ contents: prev.contents.map((c) => {
+ if (c.index === prev.currentIndex) {
+ return {
+ ...c,
+ fullMarkdown: newRawMarkdown,
+ };
+ }
+ return c;
+ }),
+ };
+ }
+ });
+ };
+
return (
{props.isHovering && artifact && (
-
+
- setIsRawView((p) => !p)}
- className={cn(
- "transition-colors w-fit h-fit p-2",
- isRawView && "bg-gray-100 text-gray-900"
- )}
- >
-
-
+
)}
{isRawView ? (
-
- {rawMarkdown}
-
+
) : (
<>