mirror of
https://github.com/AndersPier/v0-v0app.git
synced 2025-10-27 10:06:52 +00:00
103 lines
3.6 KiB
TypeScript
103 lines
3.6 KiB
TypeScript
|
|
"use client"
|
||
|
|
|
||
|
|
import { Button } from "@/components/ui/button"
|
||
|
|
import { Separator } from "@/components/ui/separator"
|
||
|
|
import {
|
||
|
|
Bold,
|
||
|
|
Italic,
|
||
|
|
Strikethrough,
|
||
|
|
Code,
|
||
|
|
Link,
|
||
|
|
ImageIcon,
|
||
|
|
List,
|
||
|
|
ListOrdered,
|
||
|
|
Quote,
|
||
|
|
Heading1,
|
||
|
|
Heading2,
|
||
|
|
Heading3,
|
||
|
|
Minus,
|
||
|
|
Table,
|
||
|
|
} from "lucide-react"
|
||
|
|
|
||
|
|
interface MarkdownToolbarProps {
|
||
|
|
onInsertText: (before: string, after?: string, placeholder?: string) => void
|
||
|
|
}
|
||
|
|
|
||
|
|
export function MarkdownToolbar({ onInsertText }: MarkdownToolbarProps) {
|
||
|
|
const toolbarItems = [
|
||
|
|
{
|
||
|
|
group: "text",
|
||
|
|
color: "from-red-500 to-pink-500",
|
||
|
|
items: [
|
||
|
|
{ icon: Bold, label: "Bold", action: () => onInsertText("**", "**", "bold text") },
|
||
|
|
{ icon: Italic, label: "Italic", action: () => onInsertText("*", "*", "italic text") },
|
||
|
|
{ icon: Strikethrough, label: "Strikethrough", action: () => onInsertText("~~", "~~", "strikethrough text") },
|
||
|
|
{ icon: Code, label: "Inline Code", action: () => onInsertText("`", "`", "code") },
|
||
|
|
],
|
||
|
|
},
|
||
|
|
{
|
||
|
|
group: "headings",
|
||
|
|
color: "from-blue-500 to-cyan-500",
|
||
|
|
items: [
|
||
|
|
{ icon: Heading1, label: "Heading 1", action: () => onInsertText("# ", "", "Heading 1") },
|
||
|
|
{ icon: Heading2, label: "Heading 2", action: () => onInsertText("## ", "", "Heading 2") },
|
||
|
|
{ icon: Heading3, label: "Heading 3", action: () => onInsertText("### ", "", "Heading 3") },
|
||
|
|
],
|
||
|
|
},
|
||
|
|
{
|
||
|
|
group: "lists",
|
||
|
|
color: "from-green-500 to-emerald-500",
|
||
|
|
items: [
|
||
|
|
{ icon: List, label: "Bullet List", action: () => onInsertText("- ", "", "List item") },
|
||
|
|
{ icon: ListOrdered, label: "Numbered List", action: () => onInsertText("1. ", "", "List item") },
|
||
|
|
{ icon: Quote, label: "Quote", action: () => onInsertText("> ", "", "Quote text") },
|
||
|
|
],
|
||
|
|
},
|
||
|
|
{
|
||
|
|
group: "media",
|
||
|
|
color: "from-purple-500 to-indigo-500",
|
||
|
|
items: [
|
||
|
|
{ icon: Link, label: "Link", action: () => onInsertText("[", "](url)", "link text") },
|
||
|
|
{ icon: ImageIcon, label: "Image", action: () => onInsertText("", "alt text") },
|
||
|
|
{ icon: Minus, label: "Horizontal Rule", action: () => onInsertText("\n---\n") },
|
||
|
|
{
|
||
|
|
icon: Table,
|
||
|
|
label: "Table",
|
||
|
|
action: () => onInsertText("\n| Header 1 | Header 2 |\n|----------|----------|\n| Cell 1 | Cell 2 |\n"),
|
||
|
|
},
|
||
|
|
],
|
||
|
|
},
|
||
|
|
]
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="flex items-center gap-2 p-3 flex-wrap">
|
||
|
|
{toolbarItems.map((group, groupIndex) => (
|
||
|
|
<div key={group.group} className="flex items-center gap-1">
|
||
|
|
{group.items.map((item, itemIndex) => (
|
||
|
|
<Button
|
||
|
|
key={item.label}
|
||
|
|
variant="ghost"
|
||
|
|
size="sm"
|
||
|
|
onClick={item.action}
|
||
|
|
className={`h-9 w-9 p-0 rounded-xl transition-all duration-200 hover:scale-105 hover:shadow-lg group relative overflow-hidden
|
||
|
|
${itemIndex === 0 ? `hover:bg-gradient-to-r hover:${group.color} hover:text-white` : "hover:bg-gray-100"}
|
||
|
|
`}
|
||
|
|
title={item.label}
|
||
|
|
>
|
||
|
|
<item.icon className="h-4 w-4 relative z-10 transition-transform group-hover:scale-110" />
|
||
|
|
{itemIndex === 0 && (
|
||
|
|
<div
|
||
|
|
className={`absolute inset-0 bg-gradient-to-r ${group.color} opacity-0 group-hover:opacity-100 transition-opacity duration-200`}
|
||
|
|
/>
|
||
|
|
)}
|
||
|
|
</Button>
|
||
|
|
))}
|
||
|
|
{groupIndex < toolbarItems.length - 1 && (
|
||
|
|
<Separator orientation="vertical" className="h-6 mx-2 bg-gradient-to-b from-gray-200 to-gray-300" />
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|