"use client"; import { RefObject } from "react"; import { Heading2, Heading3, Code, Quote, Image, Link, Minus, Bold, FileCode, Grid3X3, Video, Play } from "lucide-react"; interface ShortcutPanelProps { textareaRef: RefObject; value: string; onChange: (value: string) => void; } export default function ShortcutPanel({ textareaRef, value, onChange }: ShortcutPanelProps) { const insert = (before: string, after: string, placeholder: string) => { const el = textareaRef.current; if (!el) { onChange(value + before + placeholder + after); return; } const start = el.selectionStart; const end = el.selectionEnd; const selected = value.slice(start, end) || placeholder; const newVal = value.slice(0, start) + before + selected + after + value.slice(end); onChange(newVal); setTimeout(() => { const pos = start + before.length + selected.length + after.length; el.setSelectionRange(start + before.length, pos); el.focus(); }, 0); }; const insertBlock = (template: string) => { const el = textareaRef.current; if (!el) { onChange(value + template); return; } const start = el.selectionStart; const newVal = value.slice(0, start) + template + value.slice(start); onChange(newVal); setTimeout(() => { el.selectionStart = start + template.length; el.selectionEnd = start + template.length; el.focus(); }, 0); }; const gridTemplate = `{{< grid cols="3" >}} ![描述]() ![描述]() ![描述]() {{< /grid >}} `; const videoTemplate = `{{< video src="/video/example.mp4" caption="视频说明" >}} `; const bilibiliTemplate = `{{< bilibili BV1xx411c7mD >}} `; const youtubeTemplate = `{{< youtube dQw4w9WgXcQ >}} `; const shortcuts = [ { label: "H2", icon: Heading2, action: () => insert("## ", "\n", "二级标题") }, { label: "H3", icon: Heading3, action: () => insert("### ", "\n", "三级标题") }, { label: "粗体", icon: Bold, action: () => insert("**", "**", "粗体文本") }, { label: "代码块", icon: FileCode, action: () => insert("```\n", "\n```\n", "代码") }, { label: "行内代码", icon: Code, action: () => insert("`", "`", "code") }, { label: "引用", icon: Quote, action: () => insert("> ", "\n", "引用内容") }, { label: "图片", icon: Image, action: () => insert("![", "]()", "描述") }, { label: "图片网格", icon: Grid3X3, action: () => insertBlock(gridTemplate) }, { label: "本地视频", icon: Video, action: () => insertBlock(videoTemplate) }, { label: "B站视频", icon: Play, action: () => insertBlock(bilibiliTemplate) }, { label: "YouTube", icon: Play, action: () => insertBlock(youtubeTemplate) }, { label: "链接", icon: Link, action: () => insert("[", "]()", "链接文本") }, { label: "分割线", icon: Minus, action: () => insert("\n---\n", "", "") }, ]; return (

快捷插入

{shortcuts.map((s) => ( ))}

说明

  • 选中文字后点按钮可包裹
  • 未选中则插入模板 + 占位文字
  • 视频需替换 src 中的路径
  • B站/YouTube 替换 BV号/ID
); }