"use client" import { useRef } from "react" import type { Editor } from "@tiptap/react" import { Icon } from "@iconify/react" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Button } from "@/components/ui/button" import { buildInsertGraphicAttrs } from "@/lib/drive/extensions/docs-graphic" import { DOCS_GRAPHIC_PLACEMENT_LABELS, DOCS_GRAPHIC_WRAP_LABELS, type DocsGraphicFloatSide, type DocsGraphicPlacement, type DocsGraphicWrap, parseGraphicAttrs, } from "@/lib/drive/docs-graphic-types" function readSelectedGraphicAttrs(editor: Editor) { if (editor.isActive("docsGraphic")) { return parseGraphicAttrs(editor.getAttributes("docsGraphic") as Record) } if (editor.isActive("docsInlineGraphic")) { return parseGraphicAttrs(editor.getAttributes("docsInlineGraphic") as Record) } return null } export function DocsGraphicInsertMenu({ editor, disabled, }: { editor: Editor | null disabled?: boolean }) { const imageInputRef = useRef(null) if (!editor) return null const insertImage = (file: File, options?: { wrap?: DocsGraphicWrap; placement?: DocsGraphicPlacement }) => { const reader = new FileReader() reader.onload = () => { const src = reader.result as string editor .chain() .focus() .insertDocsGraphic( buildInsertGraphicAttrs("image", { src, wrap: options?.wrap ?? "square", placement: options?.placement ?? "block", width: 280, height: 180, }) ) .run() } reader.readAsDataURL(file) } return ( <> imageInputRef.current?.click()}> Image… Forme {(["rect", "ellipse", "line", "arrow"] as const).map((shapeType) => ( editor .chain() .focus() .insertDocsGraphic(buildInsertGraphicAttrs("shape", { shapeType })) .run() } > {shapeType === "rect" ? "Rectangle" : shapeType === "ellipse" ? "Ellipse" : shapeType === "line" ? "Ligne" : "Flèche"} ))} editor .chain() .focus() .insertDocsGraphic(buildInsertGraphicAttrs("gradient")) .run() } > Dégradé { const file = event.target.files?.[0] if (file) insertImage(file) event.target.value = "" }} /> ) } export function DocsGraphicLayoutMenu({ editor, disabled, }: { editor: Editor | null disabled?: boolean }) { if (!editor) return null const attrs = readSelectedGraphicAttrs(editor) if (!attrs) return null const applyWrap = (wrap: DocsGraphicWrap) => { editor.chain().focus().setDocsGraphicWrap(wrap).run() } const applyPlacement = (placement: DocsGraphicPlacement) => { editor.chain().focus().setDocsGraphicPlacement(placement).run() } const applyFloatSide = (floatSide: DocsGraphicFloatSide) => { editor.chain().focus().setDocsGraphicFloatSide(floatSide).run() } return ( Habillage texte {(Object.keys(DOCS_GRAPHIC_WRAP_LABELS) as DocsGraphicWrap[]).map((wrap) => ( applyWrap(wrap)}> {DOCS_GRAPHIC_WRAP_LABELS[wrap]} {attrs.wrap === wrap ? " ✓" : ""} ))} Placement {(Object.keys(DOCS_GRAPHIC_PLACEMENT_LABELS) as DocsGraphicPlacement[]).map( (placement) => ( applyPlacement(placement)}> {DOCS_GRAPHIC_PLACEMENT_LABELS[placement]} {attrs.placement === placement ? " ✓" : ""} ) )} Côté du flottement {(["left", "right", "center"] as const).map((side) => ( applyFloatSide(side)}> {side === "left" ? "Gauche" : side === "right" ? "Droite" : "Centre"} {attrs.floatSide === side ? " ✓" : ""} ))} ) } export function readGraphicToolbarActive(editor: Editor | null): boolean { if (!editor) return false return editor.isActive("docsGraphic") || editor.isActive("docsInlineGraphic") }