mirror of
https://github.com/docmost/docmost.git
synced 2025-11-14 06:01:14 +10:00
switch to nx monorepo
This commit is contained in:
@ -0,0 +1,149 @@
|
||||
import { BubbleMenu, BubbleMenuProps, isNodeSelection } from '@tiptap/react';
|
||||
import { FC, useState } from 'react';
|
||||
import { IconBold, IconCode, IconItalic, IconStrikethrough, IconUnderline, IconMessage } from '@tabler/icons-react';
|
||||
import clsx from 'clsx';
|
||||
import classes from './bubble-menu.module.css';
|
||||
import { ActionIcon, rem, Tooltip } from '@mantine/core';
|
||||
import { ColorSelector } from './color-selector';
|
||||
import { NodeSelector } from './node-selector';
|
||||
import { draftCommentIdAtom, showCommentPopupAtom } from '@/features/comment/atoms/comment-atom';
|
||||
import { useAtom } from 'jotai';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
export interface BubbleMenuItem {
|
||||
name: string;
|
||||
isActive: () => boolean;
|
||||
command: () => void;
|
||||
icon: typeof IconBold;
|
||||
}
|
||||
|
||||
type EditorBubbleMenuProps = Omit<BubbleMenuProps, 'children'>;
|
||||
|
||||
export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
|
||||
const [, setShowCommentPopup] = useAtom(showCommentPopupAtom);
|
||||
const [, setDraftCommentId] = useAtom(draftCommentIdAtom);
|
||||
|
||||
const items: BubbleMenuItem[] = [
|
||||
{
|
||||
name: 'bold',
|
||||
isActive: () => props.editor.isActive('bold'),
|
||||
command: () => props.editor.chain().focus().toggleBold().run(),
|
||||
icon: IconBold,
|
||||
},
|
||||
{
|
||||
name: 'italic',
|
||||
isActive: () => props.editor.isActive('italic'),
|
||||
command: () => props.editor.chain().focus().toggleItalic().run(),
|
||||
icon: IconItalic,
|
||||
},
|
||||
{
|
||||
name: 'underline',
|
||||
isActive: () => props.editor.isActive('underline'),
|
||||
command: () => props.editor.chain().focus().toggleUnderline().run(),
|
||||
icon: IconUnderline,
|
||||
},
|
||||
{
|
||||
name: 'strike',
|
||||
isActive: () => props.editor.isActive('strike'),
|
||||
command: () => props.editor.chain().focus().toggleStrike().run(),
|
||||
icon: IconStrikethrough,
|
||||
},
|
||||
{
|
||||
name: 'code',
|
||||
isActive: () => props.editor.isActive('code'),
|
||||
command: () => props.editor.chain().focus().toggleCode().run(),
|
||||
icon: IconCode,
|
||||
},
|
||||
];
|
||||
|
||||
const commentItem: BubbleMenuItem = {
|
||||
|
||||
name: 'comment',
|
||||
isActive: () => props.editor.isActive('comment'),
|
||||
command: () => {
|
||||
const commentId = uuidv4();
|
||||
|
||||
props.editor.chain().focus().setCommentDecoration().run();
|
||||
setDraftCommentId(commentId);
|
||||
setShowCommentPopup(true);
|
||||
},
|
||||
icon: IconMessage,
|
||||
};
|
||||
|
||||
const bubbleMenuProps: EditorBubbleMenuProps = {
|
||||
...props,
|
||||
shouldShow: ({ state, editor }) => {
|
||||
const { selection } = state;
|
||||
const { empty } = selection;
|
||||
|
||||
if (editor.isActive('image') || empty || isNodeSelection(selection)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
tippyOptions: {
|
||||
moveTransition: 'transform 0.15s ease-out',
|
||||
onHidden: () => {
|
||||
setIsNodeSelectorOpen(false);
|
||||
setIsColorSelectorOpen(false);
|
||||
setIsLinkSelectorOpen(false);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const [isNodeSelectorOpen, setIsNodeSelectorOpen] = useState(false);
|
||||
const [isColorSelectorOpen, setIsColorSelectorOpen] = useState(false);
|
||||
const [isLinkSelectorOpen, setIsLinkSelectorOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<BubbleMenu
|
||||
{...bubbleMenuProps}
|
||||
className={classes.bubbleMenu}
|
||||
>
|
||||
<NodeSelector
|
||||
editor={props.editor}
|
||||
isOpen={isNodeSelectorOpen}
|
||||
setIsOpen={() => {
|
||||
setIsNodeSelectorOpen(!isNodeSelectorOpen);
|
||||
setIsColorSelectorOpen(false);
|
||||
setIsLinkSelectorOpen(false);
|
||||
}}
|
||||
/>
|
||||
|
||||
<ActionIcon.Group>
|
||||
{items.map((item, index) => (
|
||||
<Tooltip key={index} label={item.name} withArrow>
|
||||
|
||||
<ActionIcon key={index} variant="default" size="lg" radius="0" aria-label={item.name}
|
||||
className={clsx({ [classes.active]: item.isActive() })}
|
||||
style={{ border: 'none' }}
|
||||
onClick={item.command}>
|
||||
<item.icon style={{ width: rem(16) }} stroke={2} />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
|
||||
))}
|
||||
</ActionIcon.Group>
|
||||
|
||||
<ColorSelector
|
||||
editor={props.editor}
|
||||
isOpen={isColorSelectorOpen}
|
||||
setIsOpen={() => {
|
||||
setIsColorSelectorOpen(!isColorSelectorOpen);
|
||||
setIsNodeSelectorOpen(false);
|
||||
setIsLinkSelectorOpen(false);
|
||||
}}
|
||||
/>
|
||||
|
||||
<Tooltip label={commentItem.name} withArrow>
|
||||
|
||||
<ActionIcon variant="default" size="lg" radius="0" aria-label={commentItem.name}
|
||||
style={{ border: 'none' }}
|
||||
onClick={commentItem.command}>
|
||||
<IconMessage style={{ width: rem(16) }} stroke={2} />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
|
||||
</BubbleMenu>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user