update common shared add

This commit is contained in:
Nate Kelley 2025-08-02 19:26:41 -06:00
parent 19862ceaf6
commit 58ded517d5
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
6 changed files with 264 additions and 365 deletions

View File

@ -201,6 +201,16 @@ const value: ReportElements = [
id: '39ZlrKsOyn',
lineHeight: 3
},
{
children: [
{
text: 'sdfasdf'
}
],
icon: '😄',
type: 'callout',
id: 'KQ0_YKgdqy'
},
{
type: 'p',
id: 'k5Id6hcBYM',

View File

@ -15,9 +15,9 @@ function gridLayoutCols3(props: iconProps) {
transform="rotate(90 9 9)"
fill="none"
stroke="#212121"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"></rect>
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"></rect>
<rect
x="8.25"
y="7.75"
@ -28,9 +28,9 @@ function gridLayoutCols3(props: iconProps) {
transform="rotate(90 14.5 9)"
fill="none"
stroke="#212121"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"></rect>
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"></rect>
<rect
x="-2.75"
y="7.75"
@ -41,9 +41,9 @@ function gridLayoutCols3(props: iconProps) {
transform="rotate(90 3.5 9)"
fill="none"
stroke="#212121"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"></rect>
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"></rect>
</g>
</svg>
);

View File

@ -0,0 +1,235 @@
'use client';
import * as React from 'react';
import type { PlateEditor } from 'platejs/react';
import { KEYS } from 'platejs';
import { AIChatPlugin } from '@platejs/ai/react';
import { Minus } from '@/components/ui/icons';
import { NodeTypeIcons } from './icons';
import { NodeTypeLabels, MenuGroupLabels } from './labels';
import { insertBlock, insertInlineElement } from '../elements/transforms';
// Shared types for menu items
export interface MenuItem {
icon: React.ReactNode;
value: string;
onSelect: (editor: PlateEditor, value: string) => void;
className?: string;
focusEditor?: boolean;
keywords?: readonly string[];
label?: string;
description?: string;
}
export interface MenuGroup {
group: string;
items: MenuItem[];
}
// Shared menu groups used by both SlashNode and InsertToolbarButton
export const menuGroups: MenuGroup[] = [
// {
// group: 'AI',
// items: [
// {
// focusEditor: false,
// icon: <NodeTypeIcons.sparkleAI />,
// label: NodeTypeLabels.aiChat.label,
// keywords: NodeTypeLabels.aiChat.keywords,
// value: 'AI',
// onSelect: (editor) => {
// editor.getApi(AIChatPlugin).aiChat.show();
// }
// }
// ]
// },
{
group: MenuGroupLabels.basicBlocks,
items: [
{
icon: <NodeTypeIcons.paragraph />,
keywords: NodeTypeLabels.paragraph.keywords,
label: NodeTypeLabels.paragraph.label,
value: KEYS.p
},
{
icon: <NodeTypeIcons.h1 />,
keywords: NodeTypeLabels.h1.keywords,
label: NodeTypeLabels.h1.label,
value: 'h1'
},
{
icon: <NodeTypeIcons.h2 />,
keywords: NodeTypeLabels.h2.keywords,
label: NodeTypeLabels.h2.label,
value: 'h2'
},
{
icon: <NodeTypeIcons.h3 />,
keywords: NodeTypeLabels.h3.keywords,
label: NodeTypeLabels.h3.label,
value: 'h3'
},
{
icon: <NodeTypeIcons.table />,
keywords: NodeTypeLabels.table.keywords,
label: NodeTypeLabels.table.label,
value: KEYS.table
},
{
icon: <NodeTypeIcons.code />,
keywords: NodeTypeLabels.codeBlock.keywords,
label: NodeTypeLabels.codeBlock.label,
value: KEYS.codeBlock
},
{
icon: <NodeTypeIcons.quote />,
keywords: NodeTypeLabels.blockquote.keywords,
label: NodeTypeLabels.blockquote.label,
value: KEYS.blockquote
},
{
icon: <Minus />,
label: NodeTypeLabels.divider.label,
value: KEYS.hr
},
{
description: 'Insert a highlighted block.',
icon: <NodeTypeIcons.callout />,
keywords: NodeTypeLabels.callout.keywords,
label: NodeTypeLabels.callout.label,
value: KEYS.callout
}
].map((item) => ({
...item,
onSelect: (editor, value) => {
insertBlock(editor, value);
}
}))
},
{
group: MenuGroupLabels.lists,
items: [
{
icon: <NodeTypeIcons.bulletedList />,
keywords: NodeTypeLabels.bulletedList.keywords,
label: NodeTypeLabels.bulletedList.label,
value: KEYS.ul
},
{
icon: <NodeTypeIcons.numberedList />,
keywords: NodeTypeLabels.numberedList.keywords,
label: NodeTypeLabels.numberedList.label,
value: KEYS.ol
},
{
icon: <NodeTypeIcons.todoList />,
keywords: NodeTypeLabels.todoList.keywords,
label: NodeTypeLabels.todoList.label,
value: KEYS.listTodo
},
{
icon: <NodeTypeIcons.toggle />,
keywords: NodeTypeLabels.toggleList.keywords,
label: NodeTypeLabels.toggleList.label,
value: KEYS.toggle
}
].map((item) => ({
...item,
onSelect: (editor, value) => {
insertBlock(editor, value);
}
}))
},
{
group: MenuGroupLabels.media,
items: [
{
icon: <NodeTypeIcons.image />,
keywords: NodeTypeLabels.image?.keywords,
label: NodeTypeLabels.image.label,
value: KEYS.img
},
{
icon: <NodeTypeIcons.embed />,
keywords: NodeTypeLabels.embed?.keywords,
label: NodeTypeLabels.embed.label,
value: KEYS.mediaEmbed
}
].map((item) => ({
...item,
onSelect: (editor, value) => {
insertBlock(editor, value);
}
}))
},
{
group: MenuGroupLabels.advancedBlocks,
items: [
{
icon: <NodeTypeIcons.tableOfContents />,
keywords: NodeTypeLabels.tableOfContents.keywords,
label: NodeTypeLabels.tableOfContents.label,
value: KEYS.toc
},
{
icon: <NodeTypeIcons.columnsThree />,
keywords: NodeTypeLabels.columnsThree.keywords,
label: NodeTypeLabels.columnsThree.label,
value: 'action_three_columns'
},
{
focusEditor: false,
icon: <NodeTypeIcons.equation />,
keywords: NodeTypeLabels.equation.keywords,
label: NodeTypeLabels.equation.label,
value: KEYS.equation
}
].map((item) => ({
...item,
onSelect: (editor, value) => {
insertBlock(editor, value);
}
}))
},
{
group: MenuGroupLabels.inline,
items: [
{
icon: <NodeTypeIcons.link />,
keywords: NodeTypeLabels.link?.keywords,
label: NodeTypeLabels.link.label,
value: KEYS.link
},
{
focusEditor: true,
icon: <NodeTypeIcons.calendar />,
keywords: NodeTypeLabels.date.keywords,
label: NodeTypeLabels.date.label,
value: KEYS.date
},
{
focusEditor: false,
icon: <NodeTypeIcons.equation />,
keywords: NodeTypeLabels.inlineEquation.keywords,
label: NodeTypeLabels.inlineEquation.label,
value: KEYS.inlineEquation
}
].map((item) => ({
...item,
onSelect: (editor, value) => {
insertInlineElement(editor, value);
}
}))
}
];
// Helper function to get groups for slash command and insert button
export function getSlashGroups(): MenuGroup[] {
return menuGroups;
}
// Helper function to get groups for insert button (same as slash groups)
export function getInsertGroups(): MenuGroup[] {
return menuGroups;
}

View File

@ -57,7 +57,7 @@ export function CalloutElement({
}>
<EmojiPicker {...emojiPickerState} {...calloutProps} />
</EmojiPopover>
<div className="mt-1.5 w-full">{children}</div>
<div className="mt-0.5 w-full">{children}</div>
</div>
</PlateElement>
);

View File

@ -4,11 +4,10 @@ import * as React from 'react';
import type { DropdownMenuProps } from '@radix-ui/react-dropdown-menu';
import { Minus, Plus } from '@/components/ui/icons';
import { NodeTypeIcons } from '../config/icons';
import { createLabel, NodeTypeLabels, MenuGroupLabels } from '../config/labels';
import { KEYS } from 'platejs';
import { type PlateEditor, useEditorRef } from 'platejs/react';
import { Plus } from '@/components/ui/icons';
import { createLabel } from '../config/labels';
import { useEditorRef } from 'platejs/react';
import { getInsertGroups } from '../config/addMenuItems';
import {
DropdownMenu,
@ -16,183 +15,10 @@ import {
DropdownMenuItem,
DropdownMenuTrigger
} from '@/components/ui/dropdown-menu';
import { insertBlock, insertInlineElement } from './transforms';
import { ToolbarButton, ToolbarMenuGroup } from '@/components/ui/toolbar/Toolbar';
type Group = {
group: string;
items: Item[];
};
interface Item {
icon: React.ReactNode;
value: string;
onSelect: (editor: PlateEditor, value: string) => void;
focusEditor?: boolean;
label?: string;
}
const groups: Group[] = [
{
group: MenuGroupLabels.basicBlocks,
items: [
{
icon: <NodeTypeIcons.paragraph />,
label: NodeTypeLabels.paragraph.label,
value: KEYS.p
},
{
icon: <NodeTypeIcons.h1 />,
label: NodeTypeLabels.h1.label,
value: 'h1'
},
{
icon: <NodeTypeIcons.h2 />,
label: NodeTypeLabels.h2.label,
value: 'h2'
},
{
icon: <NodeTypeIcons.h3 />,
label: NodeTypeLabels.h3.label,
value: 'h3'
},
{
icon: <NodeTypeIcons.table />,
label: NodeTypeLabels.table.label,
value: KEYS.table
},
{
icon: <NodeTypeIcons.code />,
label: NodeTypeLabels.codeBlock.label,
value: KEYS.codeBlock
},
{
icon: <NodeTypeIcons.quote />,
label: NodeTypeLabels.blockquote.label,
value: KEYS.blockquote
},
{
icon: <Minus />,
label: NodeTypeLabels.divider.label,
value: KEYS.hr
},
{
icon: <NodeTypeIcons.callout />,
label: NodeTypeLabels.callout.label,
value: KEYS.callout
}
].map((item) => ({
...item,
onSelect: (editor, value) => {
insertBlock(editor, value);
}
}))
},
{
group: MenuGroupLabels.lists,
items: [
{
icon: <NodeTypeIcons.bulletedList />,
label: NodeTypeLabels.bulletedList.label,
value: KEYS.ul
},
{
icon: <NodeTypeIcons.numberedList />,
label: NodeTypeLabels.numberedList.label,
value: KEYS.ol
},
{
icon: <NodeTypeIcons.shape />,
label: NodeTypeLabels.todoList.label,
value: KEYS.listTodo
},
{
icon: <NodeTypeIcons.toggle />,
label: NodeTypeLabels.toggleList.label,
value: KEYS.toggle
}
].map((item) => ({
...item,
onSelect: (editor, value) => {
insertBlock(editor, value);
}
}))
},
{
group: MenuGroupLabels.media,
items: [
{
icon: <NodeTypeIcons.image />,
label: NodeTypeLabels.image.label,
value: KEYS.img
},
{
icon: <NodeTypeIcons.embed />,
label: NodeTypeLabels.embed.label,
value: KEYS.mediaEmbed
}
].map((item) => ({
...item,
onSelect: (editor, value) => {
insertBlock(editor, value);
}
}))
},
{
group: MenuGroupLabels.advancedBlocks,
items: [
{
icon: <NodeTypeIcons.tableOfContents />,
label: NodeTypeLabels.tableOfContents.label,
value: KEYS.toc
},
{
icon: <NodeTypeIcons.columnsThree />,
label: NodeTypeLabels.columnsThree.label,
value: 'action_three_columns'
},
{
focusEditor: false,
icon: <NodeTypeIcons.equation />,
label: NodeTypeLabels.equation.label,
value: KEYS.equation
}
].map((item) => ({
...item,
onSelect: (editor, value) => {
insertBlock(editor, value);
}
}))
},
{
group: MenuGroupLabels.inline,
items: [
{
icon: <NodeTypeIcons.link />,
label: NodeTypeLabels.link.label,
value: KEYS.link
},
{
focusEditor: true,
icon: <NodeTypeIcons.calendar />,
label: NodeTypeLabels.date.label,
value: KEYS.date
},
{
focusEditor: false,
icon: <NodeTypeIcons.equation />,
label: NodeTypeLabels.inlineEquation.label,
value: KEYS.inlineEquation
}
].map((item) => ({
...item,
onSelect: (editor, value) => {
insertInlineElement(editor, value);
}
}))
}
];
const groups = getInsertGroups();
export function InsertToolbarButton(props: DropdownMenuProps) {
const editor = useEditorRef();

View File

@ -2,15 +2,11 @@
import * as React from 'react';
import type { PlateEditor, PlateElementProps } from 'platejs/react';
import type { PlateElementProps } from 'platejs/react';
import { AIChatPlugin } from '@platejs/ai/react';
import { type TComboboxInputElement, KEYS } from 'platejs';
import { type TComboboxInputElement } from 'platejs';
import { PlateElement } from 'platejs/react';
import { NodeTypeIcons } from '../config/icons';
import { NodeTypeLabels, MenuGroupLabels } from '../config/labels';
import { insertBlock, insertInlineElement } from './transforms';
import { getSlashGroups } from '../config/addMenuItems';
import {
InlineCombobox,
@ -22,175 +18,7 @@ import {
InlineComboboxItem
} from './InlineCombobox';
type Group = {
group: string;
items: Item[];
};
interface Item {
icon: React.ReactNode;
value: string;
onSelect: (editor: PlateEditor, value: string) => void;
className?: string;
focusEditor?: boolean;
keywords?: readonly string[];
label?: string;
description?: string;
}
const groups: Group[] = [
// {
// group: 'AI',
// items: [
// {
// focusEditor: false,
// icon: <NodeTypeIcons.sparkleAI />,
// label: NodeTypeLabels.aiChat.label,
// keywords: NodeTypeLabels.aiChat.keywords,
// value: 'AI',
// onSelect: (editor) => {
// editor.getApi(AIChatPlugin).aiChat.show();
// }
// }
// ]
// },
{
group: MenuGroupLabels.basicBlocks,
items: [
{
icon: <NodeTypeIcons.paragraph />,
keywords: NodeTypeLabels.paragraph.keywords,
label: NodeTypeLabels.paragraph.label,
value: KEYS.p
},
{
icon: <NodeTypeIcons.h1 />,
keywords: NodeTypeLabels.h1.keywords,
label: NodeTypeLabels.h1.label,
value: KEYS.h1
},
{
icon: <NodeTypeIcons.h2 />,
keywords: NodeTypeLabels.h2.keywords,
label: NodeTypeLabels.h2.label,
value: KEYS.h2
},
{
icon: <NodeTypeIcons.h3 />,
keywords: NodeTypeLabels.h3.keywords,
label: NodeTypeLabels.h3.label,
value: KEYS.h3
},
{
icon: <NodeTypeIcons.bulletedList />,
keywords: NodeTypeLabels.bulletedList.keywords,
label: NodeTypeLabels.bulletedList.label,
value: KEYS.ul
},
{
icon: <NodeTypeIcons.numberedList />,
keywords: NodeTypeLabels.numberedList.keywords,
label: NodeTypeLabels.numberedList.label,
value: KEYS.ol
},
{
icon: <NodeTypeIcons.todoList />,
keywords: NodeTypeLabels.todoList.keywords,
label: NodeTypeLabels.todoList.label,
value: KEYS.listTodo
},
{
icon: <NodeTypeIcons.toggle />,
keywords: NodeTypeLabels.toggleList.keywords,
label: NodeTypeLabels.toggleList.label,
value: KEYS.toggle
},
{
icon: <NodeTypeIcons.code />,
keywords: NodeTypeLabels.codeBlock.keywords,
label: NodeTypeLabels.codeBlock.label,
value: KEYS.codeBlock
},
{
icon: <NodeTypeIcons.table />,
keywords: NodeTypeLabels.table.keywords,
label: NodeTypeLabels.table.label,
value: KEYS.table
},
{
icon: <NodeTypeIcons.quote />,
keywords: NodeTypeLabels.blockquote.keywords,
label: NodeTypeLabels.blockquote.label,
value: KEYS.blockquote
},
{
description: 'Insert a highlighted block.',
icon: <NodeTypeIcons.callout />,
keywords: NodeTypeLabels.callout.keywords,
label: NodeTypeLabels.callout.label,
value: KEYS.callout
}
].map((item) => ({
...item,
onSelect: (editor, value) => {
insertBlock(editor, value);
}
}))
},
{
group: MenuGroupLabels.advancedBlocks,
items: [
{
icon: <NodeTypeIcons.searchContent />,
keywords: NodeTypeLabels.tableOfContents.keywords,
label: NodeTypeLabels.tableOfContents.label,
value: KEYS.toc
},
{
icon: <NodeTypeIcons.columnsThree />,
keywords: NodeTypeLabels.columnsThree.keywords,
label: NodeTypeLabels.columnsThree.label,
value: 'action_three_columns'
},
{
focusEditor: false,
icon: <NodeTypeIcons.equation />,
keywords: NodeTypeLabels.equation.keywords,
label: NodeTypeLabels.equation.label,
value: KEYS.equation
}
].map((item) => ({
...item,
onSelect: (editor, value) => {
insertBlock(editor, value);
}
}))
},
{
group: MenuGroupLabels.inline,
items: [
{
focusEditor: true,
icon: <NodeTypeIcons.calendar />,
keywords: NodeTypeLabels.date.keywords,
label: NodeTypeLabels.date.label,
value: KEYS.date
},
{
focusEditor: false,
icon: <NodeTypeIcons.equation />,
keywords: NodeTypeLabels.inlineEquation.keywords,
label: NodeTypeLabels.inlineEquation.label,
value: KEYS.inlineEquation
}
].map((item) => ({
...item,
onSelect: (editor, value) => {
insertInlineElement(editor, value);
}
}))
}
];
const groups = getSlashGroups();
export function SlashInputElement(props: PlateElementProps<TComboboxInputElement>) {
const { editor, element } = props;