| 1 | "use client"; |
| 2 | |
| 3 | import { Link, Link2Off, Trash2 } from "lucide-react"; |
| 4 | import { type TElement } from "platejs"; |
| 5 | |
| 6 | import { |
| 7 | extractEmbedId, |
| 8 | generateEmbedUrl, |
| 9 | getAllEmbedTypes, |
| 10 | } from "@/components/plate/ui/media-embeds"; |
| 11 | import { ToolbarButton, ToolbarGroup } from "@/components/plate/ui/toolbar"; |
| 12 | import { |
| 13 | Select, |
| 14 | SelectContent, |
| 15 | SelectItem, |
| 16 | SelectTrigger, |
| 17 | SelectValue, |
| 18 | } from "@/components/ui/select"; |
| 19 | import { FLOATING_TOOLBAR_IGNORE_CLASS } from "./toolbar-interaction"; |
| 20 | import { useToolbarContext } from "./ToolbarContext"; |
| 21 | |
| 22 | export function EmbedControls() { |
| 23 | const { editor, element, handleNodePropertyUpdate, isMediaEmbedElement } = |
| 24 | useToolbarContext(); |
| 25 | |
| 26 | if (!isMediaEmbedElement || !element) { |
| 27 | return null; |
| 28 | } |
| 29 | |
| 30 | const provider = |
| 31 | typeof element.provider === "string" ? element.provider : "youtube"; |
| 32 | const url = typeof element.url === "string" ? element.url : ""; |
| 33 | const embedTypes = getAllEmbedTypes(); |
| 34 | |
| 35 | const handleProviderChange = (nextProvider: string) => { |
| 36 | handleNodePropertyUpdate("provider", nextProvider); |
| 37 | handleNodePropertyUpdate("url", ""); |
| 38 | handleNodePropertyUpdate("id", ""); |
| 39 | }; |
| 40 | |
| 41 | const normalizeUrl = () => { |
| 42 | if (!url.trim()) return; |
| 43 | |
| 44 | handleNodePropertyUpdate("url", generateEmbedUrl(url, provider)); |
| 45 | handleNodePropertyUpdate("id", extractEmbedId(url, provider) ?? ""); |
| 46 | }; |
| 47 | |
| 48 | const removeUrl = () => { |
| 49 | handleNodePropertyUpdate("url", ""); |
| 50 | handleNodePropertyUpdate("id", ""); |
| 51 | }; |
| 52 | |
| 53 | const deleteEmbed = () => { |
| 54 | const path = editor.api.findPath(element as TElement); |
| 55 | if (!path) return; |
| 56 | editor.tf.removeNodes({ at: path }); |
| 57 | }; |
| 58 | |
| 59 | return ( |
| 60 | <> |
| 61 | <ToolbarGroup> |
| 62 | <Select value={provider} onValueChange={handleProviderChange}> |
| 63 | <SelectTrigger |
| 64 | className={`${FLOATING_TOOLBAR_IGNORE_CLASS} h-8 w-34 border-none bg-transparent px-2 text-xs shadow-none`} |
| 65 | > |
| 66 | <SelectValue placeholder="Provider" /> |
| 67 | </SelectTrigger> |
| 68 | <SelectContent className={FLOATING_TOOLBAR_IGNORE_CLASS}> |
| 69 | {embedTypes.map(({ type, config }) => ( |
| 70 | <SelectItem key={type} value={type}> |
| 71 | {config.name} |
| 72 | </SelectItem> |
| 73 | ))} |
| 74 | </SelectContent> |
| 75 | </Select> |
| 76 | |
| 77 | <ToolbarButton |
| 78 | disabled={!url.trim()} |
| 79 | onClick={normalizeUrl} |
| 80 | size="sm" |
| 81 | tooltip="Normalize Embed Link" |
| 82 | > |
| 83 | <Link className="size-4" /> |
| 84 | </ToolbarButton> |
| 85 | |
| 86 | <ToolbarButton |
| 87 | disabled={!url.trim()} |
| 88 | onClick={removeUrl} |
| 89 | size="sm" |
| 90 | tooltip="Remove Embed Link" |
| 91 | > |
| 92 | <Link2Off className="size-4" /> |
| 93 | </ToolbarButton> |
| 94 | </ToolbarGroup> |
| 95 | |
| 96 | <ToolbarGroup> |
| 97 | <ToolbarButton |
| 98 | onClick={deleteEmbed} |
| 99 | size="sm" |
| 100 | tooltip="Delete Embed" |
| 101 | className="text-destructive hover:bg-destructive/10 hover:text-destructive" |
| 102 | > |
| 103 | <Trash2 className="size-4" /> |
| 104 | </ToolbarButton> |
| 105 | </ToolbarGroup> |
| 106 | </> |
| 107 | ); |
| 108 | } |
| 109 |