diff --git a/src/components/blog/TextEditor.tsx b/src/components/blog/TextEditor.tsx
index 5ae8d1b..9d80ae1 100644
--- a/src/components/blog/TextEditor.tsx
+++ b/src/components/blog/TextEditor.tsx
@@ -354,15 +354,12 @@ export default function TextEditor(props: TextEditorProps) {
const instance = editor();
if (!instance) return;
- console.log("Inserting table:", rows, "x", cols);
-
instance
.chain()
.focus()
.insertTable({ rows, cols, withHeaderRow: true })
.run();
- console.log("Table inserted, isActive:", instance.isActive("table"));
setShowTableMenu(false);
};
@@ -375,6 +372,120 @@ export default function TextEditor(props: TextEditorProps) {
setShowTableMenu(!showTableMenu());
};
+ const deleteTableWithConfirmation = () => {
+ const instance = editor();
+ if (!instance) return;
+
+ const confirmed = window.confirm(
+ "Are you sure you want to delete this table?"
+ );
+ if (!confirmed) return;
+
+ instance.chain().focus().deleteTable().run();
+ };
+
+ const deleteRowWithConfirmation = () => {
+ const instance = editor();
+ if (!instance) return;
+
+ const { state } = instance;
+ const { selection } = state;
+
+ // Find the row node
+ let rowNode = null;
+ let depth = 0;
+ for (let d = selection.$anchor.depth; d > 0; d--) {
+ const node = selection.$anchor.node(d);
+ if (node.type.name === "tableRow") {
+ rowNode = node;
+ depth = d;
+ break;
+ }
+ }
+
+ if (rowNode) {
+ let hasContent = false;
+ rowNode.descendants((node) => {
+ if (node.textContent.trim().length > 0) {
+ hasContent = true;
+ return false;
+ }
+ });
+
+ if (hasContent) {
+ const confirmed = window.confirm(
+ "This row contains content. Are you sure you want to delete it?"
+ );
+ if (!confirmed) return;
+ }
+ }
+
+ instance.chain().focus().deleteRow().run();
+ };
+
+ const deleteColumnWithConfirmation = () => {
+ const instance = editor();
+ if (!instance) return;
+
+ const { state } = instance;
+ const { selection } = state;
+
+ // Get the current cell position
+ const cellPos = selection.$anchor;
+
+ // Find table and column index
+ let tableNode = null;
+ let tableDepth = 0;
+ for (let d = cellPos.depth; d > 0; d--) {
+ const node = cellPos.node(d);
+ if (node.type.name === "table") {
+ tableNode = node;
+ tableDepth = d;
+ break;
+ }
+ }
+
+ if (tableNode) {
+ // Find which column we're in
+ let colIndex = 0;
+ const cellNode = cellPos.node(cellPos.depth);
+ const rowNode = cellPos.node(cellPos.depth - 1);
+
+ rowNode.forEach((node, offset, index) => {
+ if (
+ cellPos.pos >= cellPos.start(cellPos.depth - 1) + offset &&
+ cellPos.pos <
+ cellPos.start(cellPos.depth - 1) + offset + node.nodeSize
+ ) {
+ colIndex = index;
+ }
+ });
+
+ // Check if this column has content
+ let hasContent = false;
+ tableNode.descendants((node, pos, parent) => {
+ if (parent && parent.type.name === "tableRow") {
+ let currentCol = 0;
+ parent.forEach((cell, offset, index) => {
+ if (index === colIndex && cell.textContent.trim().length > 0) {
+ hasContent = true;
+ return false;
+ }
+ });
+ }
+ });
+
+ if (hasContent) {
+ const confirmed = window.confirm(
+ "This column contains content. Are you sure you want to delete it?"
+ );
+ if (!confirmed) return;
+ }
+ }
+
+ instance.chain().focus().deleteColumn().run();
+ };
+
// Close language selector on outside click
createEffect(() => {
if (showLanguageSelector()) {
@@ -600,6 +711,108 @@ export default function TextEditor(props: TextEditorProps) {
>
Code
+
+ {/* Table controls in bubble menu */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -858,9 +1071,7 @@ export default function TextEditor(props: TextEditorProps) {