Files
v0-v0app/components/markdown-toolbar.tsx
v0 efdedf1a34 feat: add complete Docker setup for markdown editor
Create Docker configuration files and setup commands

#VERCEL_SKIP

Co-authored-by: Anders Lehmann Pier <3219386+AndersPier@users.noreply.github.com>
2025-06-19 21:46:26 +00:00

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("![", "](image-url)", "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>
)
}