feat: use ReportEditor after research report completed

This commit is contained in:
Jiang Feng
2025-04-27 00:19:13 +08:00
parent 66794a4b73
commit d77d3484c4
4 changed files with 28 additions and 95 deletions

View File

@@ -37,6 +37,7 @@
"@radix-ui/react-tooltip": "^1.2.0",
"@t3-oss/env-nextjs": "^0.11.0",
"@tailwindcss/typography": "^0.5.16",
"@tiptap/react": "^2.11.7",
"best-effort-json-parser": "^1.1.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",

85
web/pnpm-lock.yaml generated
View File

@@ -8,9 +8,6 @@ importers:
.:
dependencies:
'@ai-sdk/react':
specifier: ^1.2.9
version: 1.2.9(react@19.1.0)(zod@3.24.3)
'@ant-design/icons':
specifier: ^6.0.0
version: 6.0.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
@@ -71,6 +68,9 @@ importers:
'@tailwindcss/typography':
specifier: ^0.5.16
version: 0.5.16(tailwindcss@4.1.4)
'@tiptap/react':
specifier: ^2.11.7
version: 2.11.7(@tiptap/core@2.11.7(@tiptap/pm@2.11.7))(@tiptap/pm@2.11.7)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
best-effort-json-parser:
specifier: ^1.1.3
version: 1.1.3
@@ -222,32 +222,6 @@ importers:
packages:
'@ai-sdk/provider-utils@2.2.7':
resolution: {integrity: sha512-kM0xS3GWg3aMChh9zfeM+80vEZfXzR3JEUBdycZLtbRZ2TRT8xOj3WodGHPb06sUK5yD7pAXC/P7ctsi2fvUGQ==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.23.8
'@ai-sdk/provider@1.1.3':
resolution: {integrity: sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==}
engines: {node: '>=18'}
'@ai-sdk/react@1.2.9':
resolution: {integrity: sha512-/VYm8xifyngaqFDLXACk/1czDRCefNCdALUyp+kIX6DUIYUWTM93ISoZ+qJ8+3E+FiJAKBQz61o8lIIl+vYtzg==}
engines: {node: '>=18'}
peerDependencies:
react: ^18 || ^19 || ^19.0.0-rc
zod: ^3.23.8
peerDependenciesMeta:
zod:
optional: true
'@ai-sdk/ui-utils@1.2.8':
resolution: {integrity: sha512-nls/IJCY+ks3Uj6G/agNhXqQeLVqhNfoJbuNgCny+nX2veY5ADB91EcZUqVeQ/ionul2SeUswPY6Q/DxteY29Q==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.23.8
'@alloc/quick-lru@5.2.0':
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
@@ -2755,9 +2729,6 @@ packages:
json-schema-traverse@1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
json-schema@0.4.0:
resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
json-stable-stringify-without-jsonify@1.0.1:
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
@@ -3609,9 +3580,6 @@ packages:
resolution: {integrity: sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==}
engines: {node: '>= 10.13.0'}
secure-json-parse@2.7.0:
resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==}
selecto@1.26.3:
resolution: {integrity: sha512-gZHgqMy5uyB6/2YDjv3Qqaf7bd2hTDOpPdxXlrez4R3/L0GiEWDCFaUfrflomgqdb3SxHF2IXY0Jw0EamZi7cw==}
@@ -3801,10 +3769,6 @@ packages:
engines: {node: '>=10'}
hasBin: true
throttleit@2.1.0:
resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==}
engines: {node: '>=18'}
tinyglobby@0.2.12:
resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==}
engines: {node: '>=12.0.0'}
@@ -4034,11 +3998,6 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
zod-to-json-schema@3.24.5:
resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==}
peerDependencies:
zod: ^3.24.1
zod@3.24.3:
resolution: {integrity: sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==}
@@ -4080,34 +4039,6 @@ packages:
snapshots:
'@ai-sdk/provider-utils@2.2.7(zod@3.24.3)':
dependencies:
'@ai-sdk/provider': 1.1.3
nanoid: 3.3.11
secure-json-parse: 2.7.0
zod: 3.24.3
'@ai-sdk/provider@1.1.3':
dependencies:
json-schema: 0.4.0
'@ai-sdk/react@1.2.9(react@19.1.0)(zod@3.24.3)':
dependencies:
'@ai-sdk/provider-utils': 2.2.7(zod@3.24.3)
'@ai-sdk/ui-utils': 1.2.8(zod@3.24.3)
react: 19.1.0
swr: 2.3.3(react@19.1.0)
throttleit: 2.1.0
optionalDependencies:
zod: 3.24.3
'@ai-sdk/ui-utils@1.2.8(zod@3.24.3)':
dependencies:
'@ai-sdk/provider': 1.1.3
'@ai-sdk/provider-utils': 2.2.7(zod@3.24.3)
zod: 3.24.3
zod-to-json-schema: 3.24.5(zod@3.24.3)
'@alloc/quick-lru@5.2.0': {}
'@ant-design/colors@8.0.0':
@@ -6747,8 +6678,6 @@ snapshots:
json-schema-traverse@1.0.0: {}
json-schema@0.4.0: {}
json-stable-stringify-without-jsonify@1.0.1: {}
json5@1.0.2:
@@ -7929,8 +7858,6 @@ snapshots:
ajv-formats: 2.1.1(ajv@8.17.1)
ajv-keywords: 5.1.0(ajv@8.17.1)
secure-json-parse@2.7.0: {}
selecto@1.26.3:
dependencies:
'@daybrush/utils': 1.13.0
@@ -8173,8 +8100,6 @@ snapshots:
commander: 2.20.3
source-map-support: 0.5.21
throttleit@2.1.0: {}
tinyglobby@0.2.12:
dependencies:
fdir: 6.4.3(picomatch@4.0.2)
@@ -8495,10 +8420,6 @@ snapshots:
yocto-queue@0.1.0: {}
zod-to-json-schema@3.24.5(zod@3.24.3):
dependencies:
zod: 3.24.3
zod@3.24.3: {}
zustand@4.5.6(@types/react@19.1.2)(react@19.1.0):

View File

@@ -3,6 +3,7 @@
import { useRef } from "react";
import ReportEditor from "~/components/editor";
import { useMessage } from "~/core/store";
import { cn } from "~/lib/utils";
@@ -19,13 +20,20 @@ export function ResearchReportBlock({
}) {
const message = useMessage(messageId);
const contentRef = useRef<HTMLDivElement>(null);
const isCompleted = message?.isStreaming === false && message?.content !== "";
return (
<div
ref={contentRef}
className={cn("relative flex flex-col pb-8", className)}
>
<Markdown animate>{message?.content}</Markdown>
{message?.isStreaming && <LoadingAnimation className="my-12" />}
{isCompleted ? (
<ReportEditor content={message?.content} />
) : (
<>
<Markdown animate>{message?.content}</Markdown>
{message?.isStreaming && <LoadingAnimation className="my-12" />}
</>
)}
</div>
);
}

View File

@@ -14,6 +14,7 @@ import {
handleImageDrop,
handleImagePaste,
} from "novel";
import type { Content } from "@tiptap/react";
import { useEffect, useState } from "react";
import { useDebouncedCallback } from "use-debounce";
import { defaultExtensions } from "./extensions";
@@ -27,7 +28,7 @@ import GenerativeMenuSwitch from "./generative/generative-menu-switch";
import { uploadFn } from "./image-upload";
import { TextButtons } from "./selectors/text-buttons";
import { slashCommand, suggestionItems } from "./slash-command";
import { defaultEditorContent } from "./content";
// import { defaultEditorContent } from "./content";
import "~/styles/prosemirror.css";
@@ -35,10 +36,12 @@ const hljs = require("highlight.js");
const extensions = [...defaultExtensions, slashCommand];
const ReportEditor = () => {
const [initialContent, setInitialContent] = useState<null | JSONContent>(
null,
);
export interface ReportEditorProps {
content: Content;
}
const ReportEditor = ({ content }: ReportEditorProps) => {
const [initialContent, setInitialContent] = useState<Content>(() => content);
const [saveStatus, setSaveStatus] = useState("Saved");
const [charsCount, setCharsCount] = useState();
@@ -76,11 +79,11 @@ const ReportEditor = () => {
500,
);
useEffect(() => {
const content = window.localStorage.getItem("novel-content");
if (content) setInitialContent(JSON.parse(content));
else setInitialContent(defaultEditorContent);
}, []);
// useEffect(() => {
// const content = window.localStorage.getItem("novel-content");
// if (content) setInitialContent(JSON.parse(content));
// else setInitialContent(defaultEditorContent);
// }, []);
if (!initialContent) return null;
@@ -103,7 +106,7 @@ const ReportEditor = () => {
<EditorRoot>
<EditorContent
immediatelyRender={false}
initialContent={initialContent}
initialContent={initialContent as JSONContent}
extensions={extensions}
className="border-muted bg-background relative h-full w-full overflow-auto sm:mb-[calc(20vh)] sm:border sm:shadow-lg"
editorProps={{