feat: enhance ResearchBlock tab functionality

This commit is contained in:
Jiang Feng 2025-04-27 14:51:00 +08:00
parent 0e10362639
commit f35131da19
18 changed files with 77 additions and 395 deletions

View File

@ -124,7 +124,12 @@ export function ResearchBlock({
</TabsTrigger>
</TabsList>
</div>
<TabsContent className="h-full min-h-0 flex-grow px-8" value="report">
<TabsContent
className="h-full min-h-0 flex-grow px-8"
value="report"
forceMount
hidden={activeTab !== "report"}
>
<ScrollContainer
className="px-5pb-20 h-full"
scrollShadowColor="var(--card)"
@ -141,6 +146,8 @@ export function ResearchBlock({
<TabsContent
className="h-full min-h-0 flex-grow px-8"
value="activities"
forceMount
hidden={activeTab !== "activities"}
>
<ScrollContainer className="h-full" scrollShadowColor="var(--card)">
{researchId && (

View File

@ -1,7 +1,7 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import { useCallback, useEffect, useLayoutEffect, useRef } from "react";
import { useCallback, useRef } from "react";
import ReportEditor from "~/components/editor";
import { useMessage, useStore } from "~/core/store";
@ -48,6 +48,7 @@ export function ResearchReportBlock({
// }, 500);
// }
// }, [isCompleted]);
return (
<div
ref={contentRef}

View File

@ -1,3 +1,6 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import ReportEditor from "~/components/editor";
const content = `

View File

@ -1,356 +0,0 @@
export const defaultEditorContent = {
type: "doc",
content: [
{
type: "heading",
attrs: { level: 2 },
content: [{ type: "text", text: "Introducing Novel" }],
},
{
type: "paragraph",
content: [
{
type: "text",
marks: [
{
type: "link",
attrs: {
href: "https://github.com/steven-tey/novel",
target: "_blank",
},
},
],
text: "Novel",
},
{
type: "text",
text: " is a Notion-style WYSIWYG editor with AI-powered autocompletion. Built with ",
},
{
type: "text",
marks: [
{
type: "link",
attrs: {
href: "https://tiptap.dev/",
target: "_blank",
},
},
],
text: "Tiptap",
},
{ type: "text", text: " + " },
{
type: "text",
marks: [
{
type: "link",
attrs: {
href: "https://sdk.vercel.ai/docs",
target: "_blank",
},
},
],
text: "Vercel AI SDK",
},
{ type: "text", text: "." },
],
},
{
type: "heading",
attrs: { level: 3 },
content: [{ type: "text", text: "Installation" }],
},
{
type: "codeBlock",
attrs: { language: null },
content: [{ type: "text", text: "npm i novel" }],
},
{
type: "heading",
attrs: { level: 3 },
content: [{ type: "text", text: "Usage" }],
},
{
type: "codeBlock",
attrs: { language: null },
content: [
{
type: "text",
text: 'import { Editor } from "novel";\n\nexport default function App() {\n return (\n <Editor />\n )\n}',
},
],
},
{
type: "heading",
attrs: { level: 3 },
content: [{ type: "text", text: "Features" }],
},
{
type: "orderedList",
attrs: { tight: true, start: 1 },
content: [
{
type: "listItem",
content: [
{
type: "paragraph",
content: [{ type: "text", text: "Slash menu & bubble menu" }],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
content: [
{ type: "text", text: "AI autocomplete (type " },
{ type: "text", marks: [{ type: "code" }], text: "++" },
{
type: "text",
text: " to activate, or select from slash menu)",
},
],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
content: [
{
type: "text",
text: "Image uploads (drag & drop / copy & paste, or select from slash menu) ",
},
],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
content: [
{
type: "text",
text: "Add tweets from the command slash menu:",
},
],
},
{
type: "twitter",
attrs: {
src: "https://x.com/elonmusk/status/1800759252224729577",
},
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
content: [
{
type: "text",
text: "Mathematical symbols with LaTeX expression:",
},
],
},
{
type: "orderedList",
attrs: {
tight: true,
start: 1,
},
content: [
{
type: "listItem",
content: [
{
type: "paragraph",
content: [
{
type: "math",
attrs: {
latex: "E = mc^2",
},
},
],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
content: [
{
type: "math",
attrs: {
latex: "a^2 = \\sqrt{b^2 + c^2}",
},
},
],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
content: [
{
type: "math",
attrs: {
latex:
"\\hat{f} (\\xi)=\\int_{-\\infty}^{\\infty}f(x)e^{-2\\pi ix\\xi}dx",
},
},
],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
content: [
{
type: "math",
attrs: {
latex:
"A=\\begin{bmatrix}a&b\\\\c&d \\end{bmatrix}",
},
},
],
},
],
},
{
type: "listItem",
content: [
{
type: "paragraph",
content: [
{
type: "math",
attrs: {
latex: "\\sum_{i=0}^n x_i",
},
},
],
},
],
},
],
},
],
},
],
},
{
type: "image",
attrs: {
src: "https://public.blob.vercel-storage.com/pJrjXbdONOnAeZAZ/banner-2wQk82qTwyVgvlhTW21GIkWgqPGD2C.png",
alt: "banner.png",
title: "banner.png",
width: null,
height: null,
},
},
{ type: "horizontalRule" },
{
type: "heading",
attrs: { level: 3 },
content: [{ type: "text", text: "Learn more" }],
},
{
type: "taskList",
content: [
{
type: "taskItem",
attrs: { checked: false },
content: [
{
type: "paragraph",
content: [
{ type: "text", text: "Star us on " },
{
type: "text",
marks: [
{
type: "link",
attrs: {
href: "https://github.com/steven-tey/novel",
target: "_blank",
},
},
],
text: "GitHub",
},
],
},
],
},
{
type: "taskItem",
attrs: { checked: false },
content: [
{
type: "paragraph",
content: [
{ type: "text", text: "Install the " },
{
type: "text",
marks: [
{
type: "link",
attrs: {
href: "https://www.npmjs.com/package/novel",
target: "_blank",
},
},
],
text: "NPM package",
},
],
},
],
},
{
type: "taskItem",
attrs: { checked: false },
content: [
{
type: "paragraph",
content: [
{
type: "text",
marks: [
{
type: "link",
attrs: {
href: "https://vercel.com/templates/next.js/novel",
target: "_blank",
},
},
],
text: "Deploy your own",
},
{ type: "text", text: " to Vercel" },
],
},
],
},
],
},
],
};

View File

@ -1,3 +1,6 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import {
AIHighlight,
CharacterCount,

View File

@ -1,3 +1,6 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import { CommandGroup, CommandItem, CommandSeparator } from "../../ui/command";
import { useEditor } from "novel";
import { Check, TextQuote, TrashIcon } from "lucide-react";

View File

@ -1,3 +1,6 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import {
ArrowDownWideNarrow,
CheckCheck,
@ -14,6 +17,7 @@ const options = [
label: "Improve writing",
icon: RefreshCcwDot,
},
// TODO: add this back in
// {
// value: "fix",
// label: "Fix grammar",

View File

@ -1,3 +1,6 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
"use client";
import { Command, CommandInput } from "../../ui/command";

View File

@ -1,3 +1,6 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import { EditorBubble, removeAIHighlight, useEditor } from "novel";
import { Fragment, type ReactNode, useEffect } from "react";
import { Button } from "../../ui/button";

View File

@ -1,3 +1,6 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import { createImageUpload } from "novel";
import { toast } from "sonner";
@ -26,7 +29,9 @@ const onUpload = (file: File) => {
// No blob store configured
} else if (res.status === 401) {
resolve(file);
throw new Error("`BLOB_READ_WRITE_TOKEN` environment variable not found, reading image locally instead.");
throw new Error(
"`BLOB_READ_WRITE_TOKEN` environment variable not found, reading image locally instead.",
);
// Unknown error
} else {
throw new Error("Error uploading image. Please try again.");

View File

@ -1,3 +1,6 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
"use client";
import {

View File

@ -1,3 +1,6 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import { Check, ChevronDown } from "lucide-react";
import { EditorBubbleItem, useEditor } from "novel";

View File

@ -1,3 +1,6 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import { Button } from "../../ui/button";
import { PopoverContent } from "../../ui/popover";
import { cn } from "../../../lib/utils";

View File

@ -1,3 +1,6 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import { Button } from "../../ui/button";
import { cn } from "../../../lib/utils";
import { SigmaIcon } from "lucide-react";

View File

@ -1,3 +1,6 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import {
Check,
CheckSquare,

View File

@ -1,3 +1,6 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import { Button } from "../../ui/button";
import { cn } from "../../../lib/utils";
import {

View File

@ -1,3 +1,6 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import {
CheckSquare,
Code,

View File

@ -58,38 +58,27 @@
--color-sidebar-ring: var(--sidebar-ring);
--color-app: var(--app-background);
--color-brand: var(--brand);
--animate-aurora:
aurora 8s ease-in-out infinite alternate;
--animate-aurora: aurora 8s ease-in-out infinite alternate;
@keyframes aurora {
0% {
background-position:
0% 50%;
transform:
rotate(-5deg) scale(0.9);
0% {
background-position: 0% 50%;
transform: rotate(-5deg) scale(0.9);
}
25% {
background-position:
50% 100%;
transform:
rotate(5deg) scale(1.1);
25% {
background-position: 50% 100%;
transform: rotate(5deg) scale(1.1);
}
50% {
background-position:
100% 50%;
transform:
rotate(-3deg) scale(0.95);
50% {
background-position: 100% 50%;
transform: rotate(-3deg) scale(0.95);
}
75% {
background-position:
50% 0%;
transform:
rotate(3deg) scale(1.05);
75% {
background-position: 50% 0%;
transform: rotate(3deg) scale(1.05);
}
100% {
background-position:
0% 50%;
transform:
rotate(-5deg) scale(0.9);
100% {
background-position: 0% 50%;
transform: rotate(-5deg) scale(0.9);
}
}
}
@ -192,7 +181,7 @@
@apply border-border outline-ring/50;
}
body {
@apply text-foreground;
@apply bg-background text-foreground;
}
}
@ -201,11 +190,7 @@ textarea {
outline: none;
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}
[role="button"],
button {
cursor: pointer;
}