Examples
Collaboration
Threads Sidebar View

Threads Sidebar View

This is another example showcasing threads and comments. However, instead of showing threads floating within the editor, we instead display them in a separate sidebar using the ThreadsSidebar component.

Try it out: Click the "Add comment" button in the Formatting Toolbar to add a comment!

Relevant Docs:

"use client";
 
import {
  DefaultThreadStoreAuth,
  YjsThreadStore,
} from "@blocknote/core/comments";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
import { useCreateBlockNote } from "@blocknote/react";
import { YDocProvider, useYDoc, useYjsProvider } from "@y-sweet/react";
import { useMemo, useState } from "react";
 
import { SettingsSelect } from "./SettingsSelect.js";
import { HARDCODED_USERS, MyUserType, getRandomColor } from "./userdata.js";
 
import "./style.css";
 
// The resolveUsers function fetches information about your users
// (e.g. their name, avatar, etc.). Usually, you'd fetch this from your
// own database or user management system.
// Here, we just return the hardcoded users (from userdata.ts)
async function resolveUsers(userIds: string[]) {
  // fake a (slow) network request
  await new Promise((resolve) => setTimeout(resolve, 1000));
 
  return HARDCODED_USERS.filter((user) => userIds.includes(user.id));
}
 
// This follows the Y-Sweet example to setup a collabotive editor
// (but of course, you also use other collaboration providers
// see the docs for more information)
export default function App() {
  const docId = "my-blocknote-document-with-comments-1";
 
  return (
    <YDocProvider
      docId={docId}
      authEndpoint="https://demos.y-sweet.dev/api/auth">
      <Document />
    </YDocProvider>
  );
}
 
function Document() {
  const [activeUser, setActiveUser] = useState<MyUserType>(HARDCODED_USERS[0]);
 
  const provider = useYjsProvider();
 
  // take the Y.Doc collaborative document from Y-Sweet
  const doc = useYDoc();
 
  // setup the thread store which stores / and syncs thread / comment data
  const threadStore = useMemo(() => {
    // (alternative, use TiptapCollabProvider)
    // const provider = new TiptapCollabProvider({
    //   name: "test",
    //   baseUrl: "https://collab.yourdomain.com",
    //   appId: "test",
    //   document: doc,
    // });
    // return new TiptapThreadStore(
    //   activeUser.id,
    //   provider,
    //   new DefaultThreadStoreAuth(activeUser.id, activeUser.role)
    // );
    return new YjsThreadStore(
      activeUser.id,
      doc.getMap("threads"),
      new DefaultThreadStoreAuth(activeUser.id, activeUser.role)
    );
  }, [doc, activeUser]);
 
  // setup the editor with comments and collaboration
  const editor = useCreateBlockNote(
    {
      resolveUsers,
      comments: {
        threadStore,
      },
      collaboration: {
        provider,
        fragment: doc.getXmlFragment("blocknote"),
        user: { color: getRandomColor(), name: activeUser.username },
      },
    },
    [activeUser, threadStore]
  );
 
  return (
    <BlockNoteView
      className={"comments-main-container"}
      editor={editor}
      editable={activeUser.role === "editor"}>
      {/* We place user settings select within `BlockNoteView` as it uses
      BlockNote UI components and needs the context for them. */}
      <div className={"settings"}>
        <SettingsSelect
          label={"User"}
          items={HARDCODED_USERS.map((user) => ({
            text: `${user.username} (${
              user.role === "editor" ? "Editor" : "Commenter"
            })`,
            icon: null,
            onClick: () => setActiveUser(user),
            isSelected: user.id === activeUser.id,
          }))}
        />
      </div>
    </BlockNoteView>
  );
}