145 lines
4.7 KiB
TypeScript
145 lines
4.7 KiB
TypeScript
"use client"
|
|
|
|
import type { Editor } from "@tiptap/react"
|
|
import {
|
|
ContextMenu,
|
|
ContextMenuContent,
|
|
ContextMenuItem,
|
|
ContextMenuSeparator,
|
|
ContextMenuSub,
|
|
ContextMenuSubContent,
|
|
ContextMenuSubTrigger,
|
|
ContextMenuTrigger,
|
|
} from "@/components/ui/context-menu"
|
|
import { openDocsGraphicDrawEditor } from "@/lib/drive/docs-graphic-draw-bridge"
|
|
import {
|
|
DOCS_GRAPHIC_WRAP_LABELS,
|
|
parseGraphicAttrs,
|
|
type DocsGraphicWrap,
|
|
} from "@/lib/drive/docs-graphic-types"
|
|
|
|
export function DocsGraphicContextMenu({
|
|
editor,
|
|
children,
|
|
onCrop,
|
|
onOpenOptions,
|
|
onReplaceImage,
|
|
}: {
|
|
editor: Editor
|
|
children: React.ReactNode
|
|
onCrop?: () => void
|
|
onOpenOptions?: () => void
|
|
onReplaceImage?: () => void
|
|
}) {
|
|
const active =
|
|
editor.isActive("docsGraphic") || editor.isActive("docsInlineGraphic")
|
|
if (!active) return <>{children}</>
|
|
|
|
const name = editor.isActive("docsInlineGraphic") ? "docsInlineGraphic" : "docsGraphic"
|
|
const attrs = parseGraphicAttrs(editor.getAttributes(name) as Record<string, unknown>)
|
|
const isImage = attrs.graphicType === "image"
|
|
|
|
const applyWrap = (wrap: DocsGraphicWrap) => {
|
|
editor.chain().setDocsGraphicWrap(wrap).run()
|
|
}
|
|
|
|
const downloadImage = () => {
|
|
if (!attrs.src) return
|
|
const link = document.createElement("a")
|
|
link.href = attrs.src
|
|
link.download = "image"
|
|
link.click()
|
|
}
|
|
|
|
return (
|
|
<ContextMenu>
|
|
<ContextMenuTrigger asChild>{children}</ContextMenuTrigger>
|
|
<ContextMenuContent
|
|
className="min-w-52"
|
|
onCloseAutoFocus={(event) => event.preventDefault()}
|
|
>
|
|
<ContextMenuItem
|
|
onClick={() => document.execCommand("cut")}
|
|
>
|
|
Couper
|
|
</ContextMenuItem>
|
|
<ContextMenuItem
|
|
onClick={() => document.execCommand("copy")}
|
|
>
|
|
Copier
|
|
</ContextMenuItem>
|
|
<ContextMenuItem
|
|
onClick={() => document.execCommand("paste")}
|
|
>
|
|
Coller
|
|
</ContextMenuItem>
|
|
<ContextMenuItem
|
|
onClick={() => editor.chain().focus().deleteSelection().run()}
|
|
>
|
|
Supprimer
|
|
</ContextMenuItem>
|
|
<ContextMenuSeparator />
|
|
{isImage ? (
|
|
<>
|
|
<ContextMenuItem onClick={onReplaceImage}>Remplacer l'image…</ContextMenuItem>
|
|
<ContextMenuItem onClick={onCrop}>Recadrer</ContextMenuItem>
|
|
<ContextMenuItem onClick={onOpenOptions}>Options image…</ContextMenuItem>
|
|
<ContextMenuItem
|
|
onClick={() => {
|
|
const alt = window.prompt("Texte alternatif", attrs.alt)
|
|
if (alt != null) editor.chain().focus().updateDocsGraphic({ alt }).run()
|
|
}}
|
|
>
|
|
Texte alternatif…
|
|
</ContextMenuItem>
|
|
<ContextMenuItem onClick={downloadImage} disabled={!attrs.src}>
|
|
Télécharger l'image
|
|
</ContextMenuItem>
|
|
</>
|
|
) : attrs.graphicType === "draw" ? (
|
|
<ContextMenuItem onClick={() => openDocsGraphicDrawEditor(editor)}>
|
|
Modifier le dessin…
|
|
</ContextMenuItem>
|
|
) : attrs.graphicType === "shape" ? (
|
|
<>
|
|
<ContextMenuItem
|
|
onClick={() => {
|
|
const fill = window.prompt("Couleur de remplissage", attrs.fill)
|
|
if (fill) editor.chain().focus().updateDocsGraphic({ fill }).run()
|
|
}}
|
|
>
|
|
Modifier le remplissage…
|
|
</ContextMenuItem>
|
|
<ContextMenuItem
|
|
onClick={() => {
|
|
const stroke = window.prompt("Couleur du contour", attrs.stroke)
|
|
if (stroke) editor.chain().focus().updateDocsGraphic({ stroke }).run()
|
|
}}
|
|
>
|
|
Modifier le contour…
|
|
</ContextMenuItem>
|
|
</>
|
|
) : null}
|
|
<ContextMenuSeparator />
|
|
<ContextMenuSub>
|
|
<ContextMenuSubTrigger>Habillage texte</ContextMenuSubTrigger>
|
|
<ContextMenuSubContent onCloseAutoFocus={(event) => event.preventDefault()}>
|
|
{(Object.keys(DOCS_GRAPHIC_WRAP_LABELS) as DocsGraphicWrap[]).map((wrap) => (
|
|
<ContextMenuItem key={wrap} onClick={() => applyWrap(wrap)}>
|
|
{DOCS_GRAPHIC_WRAP_LABELS[wrap]}
|
|
</ContextMenuItem>
|
|
))}
|
|
</ContextMenuSubContent>
|
|
</ContextMenuSub>
|
|
<ContextMenuSeparator />
|
|
<ContextMenuItem onClick={() => editor.chain().focus().bringDocsGraphicForward().run()}>
|
|
Avancer
|
|
</ContextMenuItem>
|
|
<ContextMenuItem onClick={() => editor.chain().focus().sendDocsGraphicBackward().run()}>
|
|
Reculer
|
|
</ContextMenuItem>
|
|
</ContextMenuContent>
|
|
</ContextMenu>
|
|
)
|
|
}
|