Add interactive task lists and table insertion to markdown editor
- Enable task list checkbox toggling in preview mode with live content updates - Add task list and table insertion buttons to InsertToolbar - Implement smart block snippet insertion with automatic newline handling - Add horizontal scroll wrapper for wide tables in preview - Fix editor scroll position preservation during content updates - Use useLayoutEffect to prevent scroll jumps when textarea auto-resizes - Update task list styling
This commit is contained in:
@@ -3,6 +3,8 @@ import { useEffect, useState, useRef, RefObject } from 'react';
|
||||
interface InsertToolbarProps {
|
||||
textareaRef: RefObject<HTMLTextAreaElement | null>;
|
||||
onInsertLink: (text: string, url: string) => void;
|
||||
onInsertTodoItem: () => void;
|
||||
onInsertTable: () => void;
|
||||
onInsertFile: () => void;
|
||||
isUploading?: boolean;
|
||||
}
|
||||
@@ -13,7 +15,7 @@ interface LinkModalState {
|
||||
url: string;
|
||||
}
|
||||
|
||||
export function InsertToolbar({ textareaRef, onInsertLink, onInsertFile, isUploading }: InsertToolbarProps) {
|
||||
export function InsertToolbar({ textareaRef, onInsertLink, onInsertTodoItem, onInsertTable, onInsertFile, isUploading }: InsertToolbarProps) {
|
||||
const [position, setPosition] = useState<{ top: number; left: number } | null>(null);
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
const [linkModal, setLinkModal] = useState<LinkModalState>({ isOpen: false, text: '', url: '' });
|
||||
@@ -58,7 +60,7 @@ export function InsertToolbar({ textareaRef, onInsertLink, onInsertFile, isUploa
|
||||
const left = textareaRect.left + paddingLeft + (currentLineText.length * charWidth) + 20;
|
||||
|
||||
// Keep toolbar within viewport
|
||||
const toolbarWidth = 100;
|
||||
const toolbarWidth = 196;
|
||||
const adjustedLeft = Math.min(left, window.innerWidth - toolbarWidth - 20);
|
||||
let adjustedTop = top - 16; // Center vertically with cursor line
|
||||
|
||||
@@ -137,6 +139,16 @@ export function InsertToolbar({ textareaRef, onInsertLink, onInsertFile, isUploa
|
||||
setIsVisible(false);
|
||||
};
|
||||
|
||||
const handleTodoClick = () => {
|
||||
onInsertTodoItem();
|
||||
setIsVisible(false);
|
||||
};
|
||||
|
||||
const handleTableClick = () => {
|
||||
onInsertTable();
|
||||
setIsVisible(false);
|
||||
};
|
||||
|
||||
if (!isVisible || !position) return null;
|
||||
|
||||
// Link Modal
|
||||
@@ -217,6 +229,28 @@ export function InsertToolbar({ textareaRef, onInsertLink, onInsertFile, isUploa
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={handleTodoClick}
|
||||
className="p-2 rounded hover:bg-gray-700 dark:hover:bg-gray-600 text-white transition-colors"
|
||||
title="Insert To-Do Item"
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 7h11M9 12h11M9 17h11M4 7h.01M4 12h.01M4 17h.01" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="m3.5 12.5 1.5 1.5 3-3" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={handleTableClick}
|
||||
className="p-2 rounded hover:bg-gray-700 dark:hover:bg-gray-600 text-white transition-colors"
|
||||
title="Insert Table"
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 5h16v14H4V5Z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 10h16M10 5v14" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={handleFileClick}
|
||||
|
||||
Reference in New Issue
Block a user