Discussion
Loading...
Files
components/demo.tsx
Features
- User Management: Store and manage user data with avatars and names
- Discussion Threads: Manage discussion data structures with comments
- Current User Tracking: Track the current active user for collaboration
- Data Storage: Pure UI plugin for storing collaboration state
- Selector API: Easy access to user data through plugin selectors
Kit Usage
Installation
The fastest way to add discussion functionality is with the DiscussionKit
, which includes the pre-configured discussionPlugin
along with its Plate UI components.
'use client';
import type { TComment } from '@/components/ui/comment';
import { createPlatePlugin } from 'platejs/react';
import { BlockDiscussion } from '@/components/ui/block-discussion';
export interface TDiscussion {
id: string;
comments: TComment[];
createdAt: Date;
isResolved: boolean;
userId: string;
documentContent?: string;
}
const discussionsData: TDiscussion[] = [
{
id: 'discussion1',
comments: [
{
id: 'comment1',
contentRich: [
{
children: [
{
text: 'This is a comment',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 900_000),
discussionId: 'discussion1',
isEdited: false,
userId: 'alice',
},
],
createdAt: new Date(),
documentContent: 'comments to your content',
isResolved: false,
userId: 'alice',
},
{
id: 'discussion2',
comments: [
{
id: 'comment1',
contentRich: [
{
children: [
{
text: 'Hey, what do you think about this approach?',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 900_000),
discussionId: 'discussion1',
isEdited: false,
userId: 'alice',
},
{
id: 'comment2',
contentRich: [
{
children: [
{
text: 'Looks good!',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 800_000),
discussionId: 'discussion1',
isEdited: false,
userId: 'bob',
},
{
id: 'comment3',
contentRich: [
{
children: [
{
text: 'Thanks for the feedback!',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 700_000),
discussionId: 'discussion1',
isEdited: false,
userId: 'alice',
},
],
createdAt: new Date(),
documentContent: 'collaborate',
isResolved: false,
userId: 'bob',
},
{
id: 'discussion4',
comments: [
{
id: 'comment1',
contentRich: [
{
children: [
{
text: 'Comments are a great way to provide feedback and discuss changes.',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 600_000),
discussionId: 'discussion4',
isEdited: false,
userId: 'charlie',
},
{
id: 'comment2',
contentRich: [
{
children: [
{
text: 'Agreed! The link to the docs makes it easy to learn more.',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 500_000),
discussionId: 'discussion4',
isEdited: false,
userId: 'bob',
},
],
createdAt: new Date(),
documentContent: 'comments',
isResolved: false,
userId: 'charlie',
},
{
id: 'discussion5',
comments: [
{
id: 'comment1',
contentRich: [
{
children: [
{
text: 'This is a good example of how to use comments.',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 400_000),
discussionId: 'discussion5',
isEdited: false,
userId: 'alice',
},
],
createdAt: new Date(),
documentContent: 'comments on many text segments',
isResolved: false,
userId: 'alice',
},
{
id: 'discussion6',
comments: [
{
id: 'comment1',
contentRich: [
{
children: [
{
text: 'Nice demonstration of overlapping annotations with both comments and suggestions!',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 300_000),
discussionId: 'discussion6',
isEdited: false,
userId: 'bob',
},
{
id: 'comment2',
contentRich: [
{
children: [
{
text: 'This helps users understand how powerful the editor can be.',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 200_000),
discussionId: 'discussion6',
isEdited: false,
userId: 'charlie',
},
],
createdAt: new Date(),
documentContent: 'overlapping',
isResolved: false,
userId: 'bob',
},
];
const avatarUrl = (seed: string) =>
`https://api.dicebear.com/9.x/glass/svg?seed=${seed}`;
const usersData: Record<
string,
{ id: string; avatarUrl: string; name: string; hue?: number }
> = {
alice: {
id: 'alice',
avatarUrl: avatarUrl('alice6'),
name: 'Alice',
},
bob: {
id: 'bob',
avatarUrl: avatarUrl('bob4'),
name: 'Bob',
},
charlie: {
id: 'charlie',
avatarUrl: avatarUrl('charlie2'),
name: 'Charlie',
},
};
// This plugin is purely UI. It's only used to store the discussions and users data
export const discussionPlugin = createPlatePlugin({
key: 'discussion',
options: {
currentUserId: 'alice',
discussions: discussionsData,
users: usersData,
},
})
.configure({
render: { aboveNodes: BlockDiscussion },
})
.extendSelectors(({ getOption }) => ({
currentUser: () => getOption('users')[getOption('currentUserId')],
user: (id: string) => getOption('users')[id],
}));
export const DiscussionKit = [discussionPlugin];
BlockDiscussion
: Renders discussion UI above nodes
Add Kit
import { createPlateEditor } from 'platejs/react';
import { DiscussionKit } from '@/components/editor/plugins/discussion-kit';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
...DiscussionKit,
],
});
Manual Usage
Installation
pnpm add @platejs/comment @platejs/suggestion
Create Plugin
import { createPlatePlugin } from 'platejs/react';
import { BlockDiscussion } from '@/components/ui/block-discussion';
export interface TDiscussion {
id: string;
comments: TComment[];
createdAt: Date;
isResolved: boolean;
userId: string;
documentContent?: string;
}
const usersData = {
alice: {
id: 'alice',
avatarUrl: 'https://api.dicebear.com/9.x/glass/svg?seed=alice6',
name: 'Alice',
},
bob: {
id: 'bob',
avatarUrl: 'https://api.dicebear.com/9.x/glass/svg?seed=bob4',
name: 'Bob',
},
};
export const discussionPlugin = createPlatePlugin({
key: 'discussion',
options: {
currentUserId: 'alice',
discussions: [],
users: usersData,
},
})
.configure({
render: { aboveNodes: BlockDiscussion },
})
.extendSelectors(({ getOption }) => ({
currentUser: () => getOption('users')[getOption('currentUserId')],
user: (id: string) => getOption('users')[id],
}));
options.currentUserId
: ID of the current active useroptions.discussions
: Array of discussion data structuresoptions.users
: Object mapping user IDs to user datarender.aboveNodes
: RendersBlockDiscussion
above nodes for discussion UIselectors.currentUser
: Gets the current user dataselectors.user
: Gets user data by ID
Add Plugin
import { createPlateEditor } from 'platejs/react';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
discussionPlugin,
],
});
Plugins
discussionPlugin
Pure UI plugin for managing collaboration state including users and discussion data.
Selectors
currentUser
Gets the current user data.
user
Gets user data by ID.
Types
TDiscussion
Discussion data structure containing comments and metadata.
UserData
User information structure for collaboration.