216 lines
5.8 KiB
TypeScript
216 lines
5.8 KiB
TypeScript
"use client";
|
|
import { type Editor, useEditorState } from "@tiptap/react";
|
|
|
|
import {
|
|
Bold,
|
|
BrushCleaning,
|
|
Heading1,
|
|
Heading2,
|
|
Heading3,
|
|
Heading4,
|
|
Heading5,
|
|
Heading6,
|
|
Italic,
|
|
List,
|
|
ListOrdered,
|
|
Quote,
|
|
Redo,
|
|
SeparatorHorizontal,
|
|
StrikethroughIcon,
|
|
Text,
|
|
Underline,
|
|
Undo,
|
|
} from "lucide-react";
|
|
import { Button } from "~/components/ui/button";
|
|
import { Toggle } from "~/components/ui/toggle";
|
|
|
|
function ToolBar({ editor }: { editor: Editor }) {
|
|
const editorState = useEditorState({
|
|
editor,
|
|
selector: (ctx) => {
|
|
return {
|
|
canBold: ctx.editor.can().chain().toggleBold().run() ?? false,
|
|
canClearMarks: ctx.editor.can().chain().unsetAllMarks().run() ?? false,
|
|
canItalic: ctx.editor.can().chain().toggleItalic().run() ?? false,
|
|
canRedo: ctx.editor.can().chain().redo().run() ?? false,
|
|
canStrike: ctx.editor.can().chain().toggleStrike().run() ?? false,
|
|
canUnderline: ctx.editor.can().chain().toggleUnderline().run() ?? false,
|
|
canUndo: ctx.editor.can().chain().undo().run() ?? false,
|
|
isBlockquote: ctx.editor.isActive("blockquote") ?? false,
|
|
isBold: ctx.editor.isActive("bold") ?? false,
|
|
isBulletList: ctx.editor.isActive("bulletList") ?? false,
|
|
isHeading1: ctx.editor.isActive("heading", { level: 1 }) ?? false,
|
|
isHeading2: ctx.editor.isActive("heading", { level: 2 }) ?? false,
|
|
isHeading3: ctx.editor.isActive("heading", { level: 3 }) ?? false,
|
|
isHeading4: ctx.editor.isActive("heading", { level: 4 }) ?? false,
|
|
isHeading5: ctx.editor.isActive("heading", { level: 5 }) ?? false,
|
|
isHeading6: ctx.editor.isActive("heading", { level: 6 }) ?? false,
|
|
isItalic: ctx.editor.isActive("italic") ?? false,
|
|
isOrderedList: ctx.editor.isActive("orderedList") ?? false,
|
|
isParagraph: ctx.editor.isActive("paragraph") ?? false,
|
|
isStrike: ctx.editor.isActive("strike") ?? false,
|
|
isUnderline: ctx.editor.isActive("underline") ?? false,
|
|
};
|
|
},
|
|
});
|
|
|
|
return (
|
|
<div className="my-2 flex flex-wrap gap-3 rounded-lg border border-input p-1">
|
|
<Toggle
|
|
onPressedChange={() => editor.chain().focus().setParagraph().run()}
|
|
pressed={editorState.isParagraph}
|
|
>
|
|
<Text className="size-4" />
|
|
</Toggle>
|
|
<Toggle
|
|
onPressedChange={() =>
|
|
editor.chain().focus().toggleHeading({ level: 1 }).run()
|
|
}
|
|
pressed={editorState.isHeading1}
|
|
size="sm"
|
|
>
|
|
<Heading1 className="size-4" />
|
|
</Toggle>
|
|
<Toggle
|
|
onPressedChange={() =>
|
|
editor.chain().focus().toggleHeading({ level: 2 }).run()
|
|
}
|
|
pressed={editorState.isHeading2}
|
|
size="sm"
|
|
>
|
|
<Heading2 className="size-4" />
|
|
</Toggle>
|
|
<Toggle
|
|
onPressedChange={() =>
|
|
editor.chain().focus().toggleHeading({ level: 3 }).run()
|
|
}
|
|
pressed={editorState.isHeading3}
|
|
size="sm"
|
|
>
|
|
<Heading3 className="size-4" />
|
|
</Toggle>
|
|
<Toggle
|
|
onPressedChange={() =>
|
|
editor.chain().focus().toggleHeading({ level: 4 }).run()
|
|
}
|
|
pressed={editorState.isHeading4}
|
|
size="sm"
|
|
>
|
|
<Heading4 className="size-4" />
|
|
</Toggle>
|
|
<Toggle
|
|
onPressedChange={() =>
|
|
editor.chain().focus().toggleHeading({ level: 5 }).run()
|
|
}
|
|
pressed={editorState.isHeading5}
|
|
size="sm"
|
|
>
|
|
<Heading5 className="size-4" />
|
|
</Toggle>
|
|
<Toggle
|
|
onPressedChange={() =>
|
|
editor.chain().focus().toggleHeading({ level: 6 }).run()
|
|
}
|
|
pressed={editorState.isHeading6}
|
|
size="sm"
|
|
>
|
|
<Heading6 className="size-4" />
|
|
</Toggle>
|
|
|
|
<Toggle
|
|
disabled={!editorState.canBold}
|
|
onPressedChange={() => editor.chain().focus().toggleBold().run()}
|
|
pressed={editorState.isBold}
|
|
size="sm"
|
|
>
|
|
<Bold className="size-4" />
|
|
</Toggle>
|
|
<Toggle
|
|
disabled={!editorState.canItalic}
|
|
onPressedChange={() => editor.chain().focus().toggleItalic().run()}
|
|
pressed={editorState.isItalic}
|
|
size="sm"
|
|
>
|
|
<Italic className="size-4" />
|
|
</Toggle>
|
|
<Toggle
|
|
disabled={!editorState.canUnderline}
|
|
onPressedChange={() => editor.chain().focus().toggleUnderline().run()}
|
|
pressed={editorState.isUnderline}
|
|
size="sm"
|
|
>
|
|
<Underline className="size-4" />
|
|
</Toggle>
|
|
<Toggle
|
|
disabled={!editorState.canStrike}
|
|
onPressedChange={() => editor.chain().focus().toggleStrike().run()}
|
|
pressed={editorState.isStrike}
|
|
size="sm"
|
|
>
|
|
<StrikethroughIcon className="size-4" />
|
|
</Toggle>
|
|
<Toggle
|
|
onPressedChange={() => editor.chain().focus().toggleBulletList().run()}
|
|
pressed={editorState.isBulletList}
|
|
size="sm"
|
|
>
|
|
<List className="size-4" />
|
|
</Toggle>
|
|
<Toggle
|
|
onPressedChange={() => editor.chain().focus().toggleOrderedList().run()}
|
|
pressed={editorState.isOrderedList}
|
|
size="sm"
|
|
>
|
|
<ListOrdered className="size-4" />
|
|
</Toggle>
|
|
<Toggle
|
|
onPressedChange={() => editor.chain().focus().toggleBlockquote().run()}
|
|
pressed={editorState.isBlockquote}
|
|
size="sm"
|
|
>
|
|
<Quote className="size-4" />
|
|
</Toggle>
|
|
<Button
|
|
onClick={() => editor.chain().focus().setHorizontalRule().run()}
|
|
type="button"
|
|
variant="ghost"
|
|
>
|
|
<SeparatorHorizontal className="size-4" />
|
|
</Button>
|
|
<Button
|
|
onClick={() => editor.chain().focus().setHardBreak().run()}
|
|
type="button"
|
|
variant="ghost"
|
|
>
|
|
Hard break
|
|
</Button>
|
|
<Button
|
|
disabled={!editorState.canClearMarks}
|
|
onClick={() => editor.chain().focus().unsetAllMarks().run()}
|
|
type="button"
|
|
variant="ghost"
|
|
>
|
|
<BrushCleaning className="size-4" />
|
|
</Button>
|
|
|
|
<Button
|
|
disabled={!editorState.canUndo}
|
|
onClick={() => editor.chain().focus().undo().run()}
|
|
type="button"
|
|
variant="ghost"
|
|
>
|
|
<Undo className="size-4" />
|
|
</Button>
|
|
<Button
|
|
disabled={!editorState.canRedo}
|
|
onClick={() => editor.chain().focus().redo().run()}
|
|
type="button"
|
|
variant="ghost"
|
|
>
|
|
<Redo className="size-4" />
|
|
</Button>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default ToolBar;
|