infoalloggi-monorepo/apps/infoalloggi/src/components/tip-tap/toolbar.tsx

217 lines
6.4 KiB
TypeScript
Raw Normal View History

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