editor update

This commit is contained in:
Michael Freno
2025-12-23 17:30:03 -05:00
parent 9df69fe8d5
commit 0677eac721
2 changed files with 144 additions and 177 deletions

View File

@@ -566,7 +566,7 @@ export default function PostForm(props: PostFormProps) {
<div class="mt-2 flex justify-center"> <div class="mt-2 flex justify-center">
<a <a
href={`/blog/${encodeURIComponent(title().replaceAll(" ", "_"))}`} href={`/blog/${encodeURIComponent(title().replaceAll(" ", "_"))}`}
class="border-blue bg-blue hover:bg-blue rounded border px-4 py-2 shadow-md transition-all duration-300 ease-in-out hover:brightness-125 active:scale-90" class="border-lavender bg-blue rounded border px-4 py-2 text-base shadow-md transition-all duration-300 ease-in-out hover:brightness-125 active:scale-90"
> >
Go to Post Go to Post
</a> </a>

View File

@@ -1,5 +1,5 @@
import { Show, untrack, createEffect, on, createSignal, For } from "solid-js"; import { Show, untrack, createEffect, on, createSignal, For } from "solid-js";
import { createTiptapEditor, useEditorHTML } from "solid-tiptap"; import { createTiptapEditor } from "solid-tiptap";
import StarterKit from "@tiptap/starter-kit"; import StarterKit from "@tiptap/starter-kit";
import Link from "@tiptap/extension-link"; import Link from "@tiptap/extension-link";
import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight"; import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
@@ -397,6 +397,32 @@ export default function TextEditor(props: TextEditorProps) {
const [keyboardVisible, setKeyboardVisible] = createSignal(false); const [keyboardVisible, setKeyboardVisible] = createSignal(false);
const [keyboardHeight, setKeyboardHeight] = createSignal(0); const [keyboardHeight, setKeyboardHeight] = createSignal(0);
// Force reactive updates for button states
const [editorState, setEditorState] = createSignal(0);
// Helper to check editor active state reactively
const isActive = (type: string, attrs?: Record<string, any>) => {
editorState(); // Track reactive dependency
const instance = editor();
return instance ? instance.isActive(type, attrs) : false;
};
const isAlignActive = (alignment: string) => {
editorState();
const instance = editor();
if (!instance) return false;
const { $from } = instance.state.selection;
const node = $from.node($from.depth);
const currentAlign = node?.attrs?.textAlign;
if (currentAlign) {
return currentAlign === alignment;
}
return alignment === "left";
};
const editor = createTiptapEditor(() => ({ const editor = createTiptapEditor(() => ({
element: editorRef, element: editorRef,
extensions: [ extensions: [
@@ -498,6 +524,9 @@ export default function TextEditor(props: TextEditorProps) {
}); });
}, },
onSelectionUpdate: ({ editor }) => { onSelectionUpdate: ({ editor }) => {
// Force reactive update for button states
setEditorState((prev) => prev + 1);
const { from, to } = editor.state.selection; const { from, to } = editor.state.selection;
const hasSelection = from !== to; const hasSelection = from !== to;
@@ -1411,7 +1440,7 @@ export default function TextEditor(props: TextEditorProps) {
ref={containerRef} ref={containerRef}
class="border-surface2 text-text w-full max-w-full overflow-hidden rounded-md border px-4 py-2" class="border-surface2 text-text w-full max-w-full overflow-hidden rounded-md border px-4 py-2"
classList={{ classList={{
"fixed inset-0 z-[100] m-0 h-screen max-h-screen rounded-none flex flex-col": "fixed inset-0 z-100 m-0 h-screen max-h-screen rounded-none flex flex-col":
isFullscreen(), isFullscreen(),
"bg-base": isFullscreen() "bg-base": isFullscreen()
}} }}
@@ -1423,7 +1452,7 @@ export default function TextEditor(props: TextEditorProps) {
<Show when={showBubbleMenu()}> <Show when={showBubbleMenu()}>
<div <div
ref={bubbleMenuRef} ref={bubbleMenuRef}
class="bg-mantle text-text fixed z-[110] w-fit rounded p-2 text-sm whitespace-nowrap shadow-lg" class="bg-crust text-text absolute z-110 w-fit rounded p-2 text-sm whitespace-nowrap shadow-xl"
style={{ style={{
top: `${bubbleMenuPosition().top}px`, top: `${bubbleMenuPosition().top}px`,
left: `${bubbleMenuPosition().left}px`, left: `${bubbleMenuPosition().left}px`,
@@ -1431,7 +1460,7 @@ export default function TextEditor(props: TextEditorProps) {
"margin-top": "-8px" "margin-top": "-8px"
}} }}
> >
<div class="flex flex-wrap gap-1"> <div class="flex scale-105 flex-wrap gap-1">
<button <button
type="button" type="button"
onClick={() => onClick={() =>
@@ -1442,10 +1471,10 @@ export default function TextEditor(props: TextEditorProps) {
.run() .run()
} }
class={`${ class={`${
instance().isActive("heading", { level: 1 }) isActive("heading", { level: 1 })
? "bg-surface2" ? "bg-surface2"
: "hover:bg-surface1" : "hover:bg-surface1"
} rounded px-2 py-1`} } touch-manipulation rounded px-2 py-1 select-none`}
> >
H1 H1
</button> </button>
@@ -1459,10 +1488,10 @@ export default function TextEditor(props: TextEditorProps) {
.run() .run()
} }
class={`${ class={`${
instance().isActive("heading", { level: 2 }) isActive("heading", { level: 2 })
? "bg-surface2" ? "bg-surface2"
: "hover:bg-surface1" : "hover:bg-surface1"
} rounded px-2 py-1`} } touch-manipulation rounded px-2 py-1 select-none`}
> >
H2 H2
</button> </button>
@@ -1476,10 +1505,10 @@ export default function TextEditor(props: TextEditorProps) {
.run() .run()
} }
class={`${ class={`${
instance().isActive("heading", { level: 3 }) isActive("heading", { level: 3 })
? "bg-surface2" ? "bg-surface2"
: "hover:bg-surface1" : "hover:bg-surface1"
} rounded px-2 py-1`} } touch-manipulation rounded px-2 py-1 select-none`}
> >
H3 H3
</button> </button>
@@ -1489,10 +1518,8 @@ export default function TextEditor(props: TextEditorProps) {
instance().chain().focus().toggleBold().run() instance().chain().focus().toggleBold().run()
} }
class={`${ class={`${
instance().isActive("bold") isActive("bold") && "bg-crust"
? "bg-crust" } bg-opacity-30 hover:bg-opacity-30 touch-manipulation rounded px-2 py-1 select-none`}
: "hover:bg-crust"
} bg-opacity-30 hover:bg-opacity-30 rounded px-2 py-1`}
> >
<strong>B</strong> <strong>B</strong>
</button> </button>
@@ -1502,10 +1529,8 @@ export default function TextEditor(props: TextEditorProps) {
instance().chain().focus().toggleItalic().run() instance().chain().focus().toggleItalic().run()
} }
class={`${ class={`${
instance().isActive("italic") isActive("italic") && "bg-crust"
? "bg-crust" } bg-opacity-30 hover:bg-opacity-30 touch-manipulation rounded px-2 py-1 select-none`}
: "hover:bg-crust"
} bg-opacity-30 hover:bg-opacity-30 rounded px-2 py-1`}
> >
<em>I</em> <em>I</em>
</button> </button>
@@ -1515,10 +1540,8 @@ export default function TextEditor(props: TextEditorProps) {
instance().chain().focus().toggleStrike().run() instance().chain().focus().toggleStrike().run()
} }
class={`${ class={`${
instance().isActive("strike") isActive("strike") && "bg-crust"
? "bg-crust" } bg-opacity-30 hover:bg-opacity-30 touch-manipulation rounded px-2 py-1 select-none`}
: "hover:bg-crust"
} bg-opacity-30 hover:bg-opacity-30 rounded px-2 py-1`}
> >
<s>S</s> <s>S</s>
</button> </button>
@@ -1526,36 +1549,19 @@ export default function TextEditor(props: TextEditorProps) {
type="button" type="button"
onClick={setLink} onClick={setLink}
class={`${ class={`${
instance().isActive("link") isActive("link") && "bg-crust"
? "bg-crust" } bg-opacity-30 hover:bg-opacity-30 touch-manipulation rounded px-2 py-1 select-none`}
: "hover:bg-crust"
} bg-opacity-30 hover:bg-opacity-30 rounded px-2 py-1`}
> >
Link Link
</button> </button>
<button
type="button"
onClick={() =>
instance().chain().focus().toggleCode().run()
}
class={`${
instance().isActive("code")
? "bg-crust"
: "hover:bg-crust"
} bg-opacity-30 hover:bg-opacity-30 rounded px-2 py-1`}
>
Code
</button>
<button <button
type="button" type="button"
onClick={() => onClick={() =>
instance().chain().focus().toggleSuperscript().run() instance().chain().focus().toggleSuperscript().run()
} }
class={`${ class={`${
instance().isActive("superscript") isActive("superscript") && "bg-crust"
? "bg-crust" } bg-opacity-30 hover:bg-opacity-30 touch-manipulation rounded px-2 py-1 select-none`}
: "hover:bg-crust"
} bg-opacity-30 hover:bg-opacity-30 rounded px-2 py-1`}
title="Superscript (Reference)" title="Superscript (Reference)"
> >
X<sup>n</sup> X<sup>n</sup>
@@ -1566,31 +1572,14 @@ export default function TextEditor(props: TextEditorProps) {
instance().chain().focus().toggleSubscript().run() instance().chain().focus().toggleSubscript().run()
} }
class={`${ class={`${
instance().isActive("subscript") isActive("subscript") && "bg-crust"
? "bg-crust" } bg-opacity-30 hover:bg-opacity-30 touch-manipulation rounded px-2 py-1 select-none`}
: "hover:bg-crust"
} bg-opacity-30 hover:bg-opacity-30 rounded px-2 py-1`}
title="Subscript" title="Subscript"
> >
X<sub>n</sub> X<sub>n</sub>
</button> </button>
<button
type="button"
onClick={() =>
instance().chain().focus().toggleTaskList().run()
}
class={`${
instance().isActive("taskList")
? "bg-crust"
: "hover:bg-crust"
} bg-opacity-30 hover:bg-opacity-30 rounded px-2 py-1`}
title="Task List"
>
</button>
{/* Table controls in bubble menu */} {/* Table controls in bubble menu */}
<Show when={instance().isActive("table")}> <Show when={isActive("table")}>
<div class="border-crust mx-1 border-l opacity-30"></div> <div class="border-crust mx-1 border-l opacity-30"></div>
<button <button
@@ -1598,7 +1587,7 @@ export default function TextEditor(props: TextEditorProps) {
onClick={() => onClick={() =>
instance().chain().focus().addRowBefore().run() instance().chain().focus().addRowBefore().run()
} }
class="hover:bg-crust hover:bg-opacity-30 rounded px-2 py-1" class="hover:bg-crust hover:bg-opacity-30 touch-manipulation rounded px-2 py-1 select-none"
title="Add Row Before" title="Add Row Before"
> >
Row Row
@@ -1609,7 +1598,7 @@ export default function TextEditor(props: TextEditorProps) {
onClick={() => onClick={() =>
instance().chain().focus().addRowAfter().run() instance().chain().focus().addRowAfter().run()
} }
class="hover:bg-crust hover:bg-opacity-30 rounded px-2 py-1" class="hover:bg-crust hover:bg-opacity-30 touch-manipulation rounded px-2 py-1 select-none"
title="Add Row After" title="Add Row After"
> >
Row Row
@@ -1618,7 +1607,7 @@ export default function TextEditor(props: TextEditorProps) {
<button <button
type="button" type="button"
onClick={deleteRowWithConfirmation} onClick={deleteRowWithConfirmation}
class="hover:bg-red hover:bg-opacity-30 rounded px-2 py-1" class="hover:bg-red hover:bg-opacity-30 touch-manipulation rounded px-2 py-1 select-none"
title="Delete Row" title="Delete Row"
> >
Row Row
@@ -1631,7 +1620,7 @@ export default function TextEditor(props: TextEditorProps) {
onClick={() => onClick={() =>
instance().chain().focus().addColumnBefore().run() instance().chain().focus().addColumnBefore().run()
} }
class="hover:bg-crust hover:bg-opacity-30 rounded px-2 py-1" class="hover:bg-crust hover:bg-opacity-30 touch-manipulation rounded px-2 py-1 select-none"
title="Add Column Before" title="Add Column Before"
> >
Col Col
@@ -1642,7 +1631,7 @@ export default function TextEditor(props: TextEditorProps) {
onClick={() => onClick={() =>
instance().chain().focus().addColumnAfter().run() instance().chain().focus().addColumnAfter().run()
} }
class="hover:bg-crust hover:bg-opacity-30 rounded px-2 py-1" class="hover:bg-crust hover:bg-opacity-30 touch-manipulation rounded px-2 py-1 select-none"
title="Add Column After" title="Add Column After"
> >
Col Col
@@ -1651,7 +1640,7 @@ export default function TextEditor(props: TextEditorProps) {
<button <button
type="button" type="button"
onClick={deleteColumnWithConfirmation} onClick={deleteColumnWithConfirmation}
class="hover:bg-red hover:bg-opacity-30 rounded px-2 py-1" class="hover:bg-red hover:bg-opacity-30 touch-manipulation rounded px-2 py-1 select-none"
title="Delete Column" title="Delete Column"
> >
Col Col
@@ -1664,7 +1653,7 @@ export default function TextEditor(props: TextEditorProps) {
onClick={() => onClick={() =>
instance().chain().focus().mergeCells().run() instance().chain().focus().mergeCells().run()
} }
class="hover:bg-crust hover:bg-opacity-30 rounded px-2 py-1" class="hover:bg-crust hover:bg-opacity-30 touch-manipulation rounded px-2 py-1 select-none"
title="Merge Cells" title="Merge Cells"
> >
@@ -1675,7 +1664,7 @@ export default function TextEditor(props: TextEditorProps) {
onClick={() => onClick={() =>
instance().chain().focus().splitCell().run() instance().chain().focus().splitCell().run()
} }
class="hover:bg-crust hover:bg-opacity-30 rounded px-2 py-1" class="hover:bg-crust hover:bg-opacity-30 touch-manipulation rounded px-2 py-1 select-none"
title="Split Cell" title="Split Cell"
> >
@@ -1684,7 +1673,7 @@ export default function TextEditor(props: TextEditorProps) {
<button <button
type="button" type="button"
onClick={deleteTableWithConfirmation} onClick={deleteTableWithConfirmation}
class="hover:bg-red hover:bg-opacity-30 rounded px-2 py-1" class="hover:bg-red hover:bg-opacity-30 touch-manipulation rounded px-2 py-1 select-none"
title="Delete Table" title="Delete Table"
> >
Table Table
@@ -1785,10 +1774,10 @@ export default function TextEditor(props: TextEditorProps) {
instance().chain().focus().toggleHeading({ level: 1 }).run() instance().chain().focus().toggleHeading({ level: 1 }).run()
} }
class={`${ class={`${
instance().isActive("heading", { level: 1 }) isActive("heading", { level: 1 })
? "bg-surface2" ? "bg-surface2"
: "hover:bg-surface1" : "hover:bg-surface1"
} rounded px-2 py-1 text-xs`} } touch-manipulation rounded px-2 py-1 text-xs select-none`}
title="Heading 1" title="Heading 1"
> >
H1 H1
@@ -1799,10 +1788,10 @@ export default function TextEditor(props: TextEditorProps) {
instance().chain().focus().toggleHeading({ level: 2 }).run() instance().chain().focus().toggleHeading({ level: 2 }).run()
} }
class={`${ class={`${
instance().isActive("heading", { level: 2 }) isActive("heading", { level: 2 })
? "bg-surface2" ? "bg-surface2"
: "hover:bg-surface1" : "hover:bg-surface1"
} rounded px-2 py-1 text-xs`} } touch-manipulation rounded px-2 py-1 text-xs select-none`}
title="Heading 2" title="Heading 2"
> >
H2 H2
@@ -1813,10 +1802,10 @@ export default function TextEditor(props: TextEditorProps) {
instance().chain().focus().toggleHeading({ level: 3 }).run() instance().chain().focus().toggleHeading({ level: 3 }).run()
} }
class={`${ class={`${
instance().isActive("heading", { level: 3 }) isActive("heading", { level: 3 })
? "bg-surface2" ? "bg-surface2"
: "hover:bg-surface1" : "hover:bg-surface1"
} rounded px-2 py-1 text-xs`} } touch-manipulation rounded px-2 py-1 text-xs select-none`}
title="Heading 3" title="Heading 3"
> >
H3 H3
@@ -1826,10 +1815,8 @@ export default function TextEditor(props: TextEditorProps) {
type="button" type="button"
onClick={() => instance().chain().focus().toggleBold().run()} onClick={() => instance().chain().focus().toggleBold().run()}
class={`${ class={`${
instance().isActive("bold") isActive("bold") && "bg-surface2"
? "bg-surface2" } touch-manipulation rounded px-2 py-1 text-xs select-none`}
: "hover:bg-surface1"
} rounded px-2 py-1 text-xs`}
title="Bold" title="Bold"
> >
<strong>B</strong> <strong>B</strong>
@@ -1840,10 +1827,8 @@ export default function TextEditor(props: TextEditorProps) {
instance().chain().focus().toggleItalic().run() instance().chain().focus().toggleItalic().run()
} }
class={`${ class={`${
instance().isActive("italic") isActive("italic") && "bg-surface2"
? "bg-surface2" } touch-manipulation rounded px-2 py-1 text-xs select-none`}
: "hover:bg-surface1"
} rounded px-2 py-1 text-xs`}
title="Italic" title="Italic"
> >
<em>I</em> <em>I</em>
@@ -1854,10 +1839,8 @@ export default function TextEditor(props: TextEditorProps) {
instance().chain().focus().toggleStrike().run() instance().chain().focus().toggleStrike().run()
} }
class={`${ class={`${
instance().isActive("strike") isActive("strike") && "bg-surface2"
? "bg-surface2" } touch-manipulation rounded px-2 py-1 text-xs select-none`}
: "hover:bg-surface1"
} rounded px-2 py-1 text-xs`}
title="Strikethrough" title="Strikethrough"
> >
<s>S</s> <s>S</s>
@@ -1868,10 +1851,10 @@ export default function TextEditor(props: TextEditorProps) {
instance().chain().focus().toggleSuperscript().run() instance().chain().focus().toggleSuperscript().run()
} }
class={`${ class={`${
instance().isActive("superscript") isActive("superscript")
? "bg-surface2" ? "bg-surface2"
: "hover:bg-surface1" : "hover:bg-surface1"
} rounded px-2 py-1 text-xs`} } touch-manipulation rounded px-2 py-1 text-xs select-none`}
title="Superscript (for references)" title="Superscript (for references)"
> >
X<sup class="text-[0.6em]">n</sup> X<sup class="text-[0.6em]">n</sup>
@@ -1882,10 +1865,8 @@ export default function TextEditor(props: TextEditorProps) {
instance().chain().focus().toggleSubscript().run() instance().chain().focus().toggleSubscript().run()
} }
class={`${ class={`${
instance().isActive("subscript") isActive("subscript") && "bg-surface2"
? "bg-surface2" } touch-manipulation rounded px-2 py-1 text-xs select-none`}
: "hover:bg-surface1"
} rounded px-2 py-1 text-xs`}
title="Subscript" title="Subscript"
> >
X<sub class="text-[0.6em]">n</sub> X<sub class="text-[0.6em]">n</sub>
@@ -1897,10 +1878,8 @@ export default function TextEditor(props: TextEditorProps) {
instance().chain().focus().toggleBulletList().run() instance().chain().focus().toggleBulletList().run()
} }
class={`${ class={`${
instance().isActive("bulletList") isActive("bulletList") && "bg-surface2"
? "bg-surface2" } touch-manipulation rounded px-2 py-1 text-xs select-none`}
: "hover:bg-surface1"
} rounded px-2 py-1 text-xs`}
title="Bullet List" title="Bullet List"
> >
List List
@@ -1911,10 +1890,10 @@ export default function TextEditor(props: TextEditorProps) {
instance().chain().focus().toggleOrderedList().run() instance().chain().focus().toggleOrderedList().run()
} }
class={`${ class={`${
instance().isActive("orderedList") isActive("orderedList")
? "bg-surface2" ? "bg-surface2"
: "hover:bg-surface1" : "hover:bg-surface1"
} rounded px-2 py-1 text-xs`} } touch-manipulation rounded px-2 py-1 text-xs select-none`}
title="Ordered List" title="Ordered List"
> >
1. List 1. List
@@ -1925,10 +1904,8 @@ export default function TextEditor(props: TextEditorProps) {
instance().chain().focus().toggleTaskList().run() instance().chain().focus().toggleTaskList().run()
} }
class={`${ class={`${
instance().isActive("taskList") isActive("taskList") && "bg-surface2"
? "bg-surface2" } touch-manipulation rounded px-2 py-1 text-xs select-none`}
: "hover:bg-surface1"
} rounded px-2 py-1 text-xs`}
title="Task List" title="Task List"
> >
Tasks Tasks
@@ -1939,10 +1916,8 @@ export default function TextEditor(props: TextEditorProps) {
instance().chain().focus().toggleBlockquote().run() instance().chain().focus().toggleBlockquote().run()
} }
class={`${ class={`${
instance().isActive("blockquote") isActive("blockquote") && "bg-surface2"
? "bg-surface2" } touch-manipulation rounded px-2 py-1 text-xs select-none`}
: "hover:bg-surface1"
} rounded px-2 py-1 text-xs`}
title="Blockquote" title="Blockquote"
> >
" Quote " Quote
@@ -1950,7 +1925,7 @@ export default function TextEditor(props: TextEditorProps) {
<button <button
type="button" type="button"
onClick={insertCollapsibleSection} onClick={insertCollapsibleSection}
class="hover:bg-surface1 rounded px-2 py-1 text-xs" class="hover:bg-surface1 touch-manipulation rounded px-2 py-1 text-xs select-none"
title="Insert Collapsible Section" title="Insert Collapsible Section"
> >
▼ Details ▼ Details
@@ -1960,59 +1935,55 @@ export default function TextEditor(props: TextEditorProps) {
{/* Text Alignment */} {/* Text Alignment */}
<button <button
type="button" type="button"
onClick={() => onClick={() => {
instance().chain().focus().setTextAlign("left").run() instance().chain().focus().setTextAlign("left").run();
} setEditorState((prev) => prev + 1);
}}
class={`${ class={`${
instance().isActive({ textAlign: "left" }) isAlignActive("left") && "bg-surface2"
? "bg-surface2" } touch-manipulation rounded px-2 py-1 text-xs select-none`}
: "hover:bg-surface1"
} rounded px-2 py-1 text-xs`}
title="Align Left" title="Align Left"
> >
</button> </button>
<button <button
type="button" type="button"
onClick={() => onClick={() => {
instance().chain().focus().setTextAlign("center").run() instance().chain().focus().setTextAlign("center").run();
} setEditorState((prev) => prev + 1);
}}
class={`${ class={`${
instance().isActive({ textAlign: "center" }) isAlignActive("center") && "bg-surface2"
? "bg-surface2" } touch-manipulation rounded px-2 py-1 text-xs select-none`}
: "hover:bg-surface1"
} rounded px-2 py-1 text-xs`}
title="Align Center" title="Align Center"
> >
</button> </button>
<button <button
type="button" type="button"
onClick={() => onClick={() => {
instance().chain().focus().setTextAlign("right").run() instance().chain().focus().setTextAlign("right").run();
} setEditorState((prev) => prev + 1);
}}
class={`${ class={`${
instance().isActive({ textAlign: "right" }) isAlignActive("right") && "bg-surface2"
? "bg-surface2" } touch-manipulation rounded px-2 py-1 text-xs select-none`}
: "hover:bg-surface1"
} rounded px-2 py-1 text-xs`}
title="Align Right" title="Align Right"
> >
</button> </button>
<button <button
type="button" type="button"
onClick={() => onClick={() => {
instance().chain().focus().setTextAlign("justify").run() instance().chain().focus().setTextAlign("justify").run();
} setEditorState((prev) => prev + 1);
}}
class={`${ class={`${
instance().isActive({ textAlign: "justify" }) isAlignActive("justify") && "bg-surface2"
? "bg-surface2" } touch-manipulation rounded px-2 py-1 text-xs select-none`}
: "hover:bg-surface1"
} rounded px-2 py-1 text-xs`}
title="Justify" title="Justify"
> >
</button> </button>
<div class="border-surface2 mx-1 border-l"></div> <div class="border-surface2 mx-1 border-l"></div>
<button <button
@@ -2020,10 +1991,9 @@ export default function TextEditor(props: TextEditorProps) {
onClick={showLanguagePicker} onClick={showLanguagePicker}
data-language-picker-trigger data-language-picker-trigger
class={`${ class={`${
instance().isActive("codeBlock") (showLanguageSelector() || isActive("codeBlock")) &&
? "bg-surface2" "bg-surface2"
: "hover:bg-surface1" } touch-manipulation rounded px-2 py-1 text-xs select-none`}
} rounded px-2 py-1 text-xs`}
title="Code Block" title="Code Block"
> >
{"</>"} {"</>"}
@@ -2032,10 +2002,8 @@ export default function TextEditor(props: TextEditorProps) {
type="button" type="button"
onClick={setLink} onClick={setLink}
class={`${ class={`${
instance().isActive("link") isActive("link") && "bg-surface2"
? "bg-surface2" } touch-manipulation rounded px-2 py-1 text-xs select-none`}
: "hover:bg-surface1"
} rounded px-2 py-1 text-xs`}
title="Add Link" title="Add Link"
> >
🔗 Link 🔗 Link
@@ -2043,7 +2011,7 @@ export default function TextEditor(props: TextEditorProps) {
<button <button
type="button" type="button"
onClick={addImage} onClick={addImage}
class="hover:bg-surface1 rounded px-2 py-1 text-xs" class="touch-manipulation rounded px-2 py-1 text-xs select-none"
title="Add Image" title="Add Image"
> >
🖼 Image 🖼 Image
@@ -2051,7 +2019,7 @@ export default function TextEditor(props: TextEditorProps) {
<button <button
type="button" type="button"
onClick={addIframe} onClick={addIframe}
class="hover:bg-surface1 rounded px-2 py-1 text-xs" class="touch-manipulation rounded px-2 py-1 text-xs select-none"
title="Add Iframe" title="Add Iframe"
> >
📺 Iframe 📺 Iframe
@@ -2061,10 +2029,8 @@ export default function TextEditor(props: TextEditorProps) {
onClick={showTableInserter} onClick={showTableInserter}
data-table-trigger data-table-trigger
class={`${ class={`${
instance().isActive("table") (showTableMenu() || isActive("table")) && "bg-surface2"
? "bg-surface2" } touch-manipulation rounded px-2 py-1 text-xs select-none`}
: "hover:bg-surface1"
} rounded px-2 py-1 text-xs`}
title="Insert Table" title="Insert Table"
> >
⊞ Table ⊞ Table
@@ -2073,7 +2039,9 @@ export default function TextEditor(props: TextEditorProps) {
type="button" type="button"
onClick={showMermaidSelector} onClick={showMermaidSelector}
data-mermaid-trigger data-mermaid-trigger
class="hover:bg-surface1 rounded px-2 py-1 text-xs" class={`${
showMermaidTemplates() && "bg-surface2"
} touch-manipulation rounded px-2 py-1 text-xs select-none`}
title="Insert Diagram" title="Insert Diagram"
> >
📊 Diagram 📊 Diagram
@@ -2083,10 +2051,9 @@ export default function TextEditor(props: TextEditorProps) {
onClick={showConditionalConfigurator} onClick={showConditionalConfigurator}
data-conditional-trigger data-conditional-trigger
class={`${ class={`${
instance().isActive("conditionalBlock") (showConditionalConfig() || isActive("conditionalBlock")) &&
? "bg-surface2" "bg-surface2"
: "hover:bg-surface1" } rounded px-2 py-1 text-xs select-none`}
} rounded px-2 py-1 text-xs`}
title="Insert Conditional Block" title="Insert Conditional Block"
> >
🔒 Conditional 🔒 Conditional
@@ -2097,7 +2064,7 @@ export default function TextEditor(props: TextEditorProps) {
onClick={() => onClick={() =>
instance().chain().focus().setHorizontalRule().run() instance().chain().focus().setHorizontalRule().run()
} }
class="bg-surface0 hover:bg-surface1 rounded px-3 py-1 text-xs" class="hover:bg-surface1 rounded px-3 py-1 text-xs"
title="Horizontal Rule" title="Horizontal Rule"
> >
━━ HR ━━ HR
@@ -2106,7 +2073,7 @@ export default function TextEditor(props: TextEditorProps) {
<button <button
type="button" type="button"
onClick={toggleFullscreen} onClick={toggleFullscreen}
class="hover:bg-surface1 rounded px-2 py-1 text-xs" class="hover:bg-surface1 touch-manipulation rounded px-2 py-1 text-xs select-none"
title={ title={
isFullscreen() isFullscreen()
? "Exit Fullscreen (ESC)" ? "Exit Fullscreen (ESC)"
@@ -2118,14 +2085,14 @@ export default function TextEditor(props: TextEditorProps) {
<button <button
type="button" type="button"
onClick={() => setShowKeyboardHelp(!showKeyboardHelp())} onClick={() => setShowKeyboardHelp(!showKeyboardHelp())}
class="hover:bg-surface1 rounded px-2 py-1 text-xs" class="hover:bg-surface1 touch-manipulation rounded px-2 py-1 text-xs select-none"
title="Keyboard Shortcuts" title="Keyboard Shortcuts"
> >
⌨ Help ⌨ Help
</button> </button>
{/* Table controls - shown when cursor is in a table */} {/* Table controls - shown when cursor is in a table */}
<Show when={instance().isActive("table")}> <Show when={isActive("table")}>
<div class="border-surface2 mx-1 border-l"></div> <div class="border-surface2 mx-1 border-l"></div>
<button <button
@@ -2133,7 +2100,7 @@ export default function TextEditor(props: TextEditorProps) {
onClick={() => onClick={() =>
instance().chain().focus().addColumnBefore().run() instance().chain().focus().addColumnBefore().run()
} }
class="hover:bg-surface1 rounded px-2 py-1 text-xs" class="hover:bg-surface1 touch-manipulation rounded px-2 py-1 text-xs select-none"
title="Add Column Before" title="Add Column Before"
> >
← Col ← Col
@@ -2144,7 +2111,7 @@ export default function TextEditor(props: TextEditorProps) {
onClick={() => onClick={() =>
instance().chain().focus().addColumnAfter().run() instance().chain().focus().addColumnAfter().run()
} }
class="hover:bg-surface1 rounded px-2 py-1 text-xs" class="hover:bg-surface1 touch-manipulation rounded px-2 py-1 text-xs select-none"
title="Add Column After" title="Add Column After"
> >
Col → Col →
@@ -2153,7 +2120,7 @@ export default function TextEditor(props: TextEditorProps) {
<button <button
type="button" type="button"
onClick={deleteColumnWithConfirmation} onClick={deleteColumnWithConfirmation}
class="hover:bg-red bg-opacity-20 rounded px-2 py-1 text-xs" class="hover:bg-red bg-opacity-20 touch-manipulation rounded px-2 py-1 text-xs select-none"
title="Delete Column" title="Delete Column"
> >
✕ Col ✕ Col
@@ -2166,7 +2133,7 @@ export default function TextEditor(props: TextEditorProps) {
onClick={() => onClick={() =>
instance().chain().focus().addRowBefore().run() instance().chain().focus().addRowBefore().run()
} }
class="hover:bg-surface1 rounded px-2 py-1 text-xs" class="hover:bg-surface1 touch-manipulation rounded px-2 py-1 text-xs select-none"
title="Add Row Before" title="Add Row Before"
> >
↑ Row ↑ Row
@@ -2177,7 +2144,7 @@ export default function TextEditor(props: TextEditorProps) {
onClick={() => onClick={() =>
instance().chain().focus().addRowAfter().run() instance().chain().focus().addRowAfter().run()
} }
class="hover:bg-surface1 rounded px-2 py-1 text-xs" class="hover:bg-surface1 touch-manipulation rounded px-2 py-1 text-xs select-none"
title="Add Row After" title="Add Row After"
> >
Row ↓ Row ↓
@@ -2186,7 +2153,7 @@ export default function TextEditor(props: TextEditorProps) {
<button <button
type="button" type="button"
onClick={deleteRowWithConfirmation} onClick={deleteRowWithConfirmation}
class="hover:bg-red bg-opacity-20 rounded px-2 py-1 text-xs" class="hover:bg-red bg-opacity-20 touch-manipulation rounded px-2 py-1 text-xs select-none"
title="Delete Row" title="Delete Row"
> >
✕ Row ✕ Row
@@ -2197,7 +2164,7 @@ export default function TextEditor(props: TextEditorProps) {
<button <button
type="button" type="button"
onClick={deleteTableWithConfirmation} onClick={deleteTableWithConfirmation}
class="hover:bg-red rounded px-2 py-1 text-xs" class="hover:bg-red touch-manipulation rounded px-2 py-1 text-xs select-none"
title="Delete Table" title="Delete Table"
> >
✕ Table ✕ Table
@@ -2209,10 +2176,10 @@ export default function TextEditor(props: TextEditorProps) {
instance().chain().focus().toggleHeaderRow().run() instance().chain().focus().toggleHeaderRow().run()
} }
class={`${ class={`${
instance().isActive("tableHeader") isActive("tableHeader")
? "bg-surface2" ? "bg-surface2"
: "hover:bg-surface1" : "hover:bg-surface1"
} rounded px-2 py-1 text-xs`} } touch-manipulation rounded px-2 py-1 text-xs select-none`}
title="Toggle Header Row" title="Toggle Header Row"
> >
≡ Header ≡ Header
@@ -2223,7 +2190,7 @@ export default function TextEditor(props: TextEditorProps) {
onClick={() => onClick={() =>
instance().chain().focus().mergeCells().run() instance().chain().focus().mergeCells().run()
} }
class="hover:bg-surface1 rounded px-2 py-1 text-xs" class="hover:bg-surface1 touch-manipulation rounded px-2 py-1 text-xs select-none"
title="Merge Cells" title="Merge Cells"
> >
⊡ Merge ⊡ Merge
@@ -2232,7 +2199,7 @@ export default function TextEditor(props: TextEditorProps) {
<button <button
type="button" type="button"
onClick={() => instance().chain().focus().splitCell().run()} onClick={() => instance().chain().focus().splitCell().run()}
class="hover:bg-surface1 rounded px-2 py-1 text-xs" class="hover:bg-surface1 touch-manipulation rounded px-2 py-1 text-xs select-none"
title="Split Cell" title="Split Cell"
> >
⊞ Split ⊞ Split