might work, basic writing page with linking. no saving.

This commit is contained in:
2026-06-28 10:43:47 -05:00
parent 914c9fbac8
commit c04738f9c4
12 changed files with 745 additions and 3 deletions
+118
View File
@@ -0,0 +1,118 @@
import { Editor, useEditorState } from "@tiptap/react";
import {
AlignCenter,
AlignLeft,
AlignRight,
Bold,
Heading1,
Heading2,
Heading3,
Highlighter,
Italic,
List,
ListOrdered,
} from "lucide-react";
import { Toggle } from "../ui/toggle";
export default function Menubar({ editor }: { editor: Editor | null }) {
if (!editor) {
return null;
}
const editorState = useEditorState({
editor,
selector: (ctx) => {
return {
// Text formatting
isBold: ctx.editor.isActive("bold") ?? false,
isItalic: ctx.editor.isActive("italic") ?? false,
isStrike: ctx.editor.isActive("strike") ?? false,
isHighlight: ctx.editor.isActive("highlight") ?? false,
// Text alignment
isAlignLeft: ctx.editor.isActive({ textAlign: "left" }) ?? false,
isAlignCenter: ctx.editor.isActive({ textAlign: "center" }) ?? false,
isAlignRight: ctx.editor.isActive({ textAlign: "right" }) ?? false,
isAlignJustify: ctx.editor.isActive({ textAlign: "justify" }) ?? false,
// Block types
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,
};
},
});
const options: {
icon: React.ReactNode;
onClick: () => void;
pressed: boolean;
}[] = [
{
icon: <Heading1 className="size-4" />,
onClick: () => editor.chain().focus().toggleHeading({ level: 1 }).run(),
pressed: editor.isActive("heading", { level: 1 }),
},
{
icon: <Heading2 className="size-4" />,
onClick: () => editor.chain().focus().toggleHeading({ level: 2 }).run(),
pressed: editor.isActive("heading", { level: 2 }),
},
{
icon: <Heading3 className="size-4" />,
onClick: () => editor.chain().focus().toggleHeading({ level: 3 }).run(),
pressed: editor.isActive("heading", { level: 3 }),
},
{
icon: <Bold className="size-4" />,
onClick: () => editor.chain().focus().toggleBold().run(),
pressed: editor.isActive("bold"),
},
{
icon: <Italic className="size-4" />,
onClick: () => editor.chain().focus().toggleItalic().run(),
pressed: editor.isActive("italic"),
},
{
icon: <AlignLeft className="size-4" />,
onClick: () => editor.chain().focus().toggleTextAlign("left").run(),
pressed: editor.isActive({ textAlign: "left" }),
},
{
icon: <AlignCenter className="size-4" />,
onClick: () => editor.chain().focus().toggleTextAlign("center").run(),
pressed: editor.isActive({ textAlign: "center" }),
},
{
icon: <AlignRight className="size-4" />,
onClick: () => editor.chain().focus().toggleTextAlign("right").run(),
pressed: editor.isActive({ textAlign: "right" }),
},
{
icon: <List className="size-4" />,
onClick: () => editor.chain().focus().toggleBulletList().run(),
pressed: editor.isActive("bulletList"),
},
{
icon: <ListOrdered className="size-4" />,
onClick: () => editor.chain().focus().toggleOrderedList().run(),
pressed: editor.isActive("orderList"),
},
{
icon: <Highlighter className="size-4" />,
onClick: () => editor.chain().focus().toggleHighlight().run(),
pressed: editor.isActive("highlight"),
},
];
return (
<div className="border rounded-md p-1 mb-1 bg-slate-50 space-x-2 z-50">
{options.map((option, index) => (
<Toggle key={index} pressed={option.pressed} onClick={option.onClick}>
{option.icon}
</Toggle>
))}
</div>
);
}