返回 presentation-ai
CalloutVariantControl.tsx
根目录 / src / components / presentation / floating-toolbar / CalloutVariantControl.tsx
1 "use client";
2
3 import { MessageSquareWarning } from "lucide-react";
4 import { type TElement } from "platejs";
5 import * as React from "react";
6
7 import { PALETTE_DROP_MUTABLE_KEY } from "@/components/notebook/presentation/editor/utils/paletteDrop";
8 import {
9 CALLOUT_VARIANTS,
10 type CalloutVariant,
11 } from "@/components/plate/ui/callout-variants";
12 import {
13 DropdownMenu,
14 DropdownMenuContent,
15 DropdownMenuRadioItem,
16 DropdownMenuTrigger,
17 } from "@/components/plate/ui/dropdown-menu";
18 import {
19 ToolbarButton,
20 ToolbarGroup,
21 ToolbarMenuGroup,
22 } from "@/components/plate/ui/toolbar";
23 import { usePresentationState } from "@/states/presentation-state";
24 import { useToolbarContext } from "./ToolbarContext";
25
26 const CALLOUT_VARIANT_OPTIONS = Object.keys(
27 CALLOUT_VARIANTS,
28 ) as CalloutVariant[];
29
30 function getCalloutVariant(value: string): CalloutVariant {
31 return CALLOUT_VARIANT_OPTIONS.includes(value as CalloutVariant)
32 ? (value as CalloutVariant)
33 : "note";
34 }
35
36 export function CalloutVariantControl() {
37 const [open, setOpen] = React.useState(false);
38 const { currentVariant, editor, element } = useToolbarContext();
39 const setPaletteDropTarget = usePresentationState(
40 (state) => state.setPaletteDropTarget,
41 );
42 const selectedVariant = getCalloutVariant(currentVariant);
43
44 const updateVariant = (nextVariant: string) => {
45 if (!element) return;
46
47 const variant = getCalloutVariant(nextVariant);
48 const variantConfig = CALLOUT_VARIANTS[variant];
49 const path = editor.api.findPath(element as TElement);
50 if (!path) return;
51
52 setPaletteDropTarget(null);
53 editor.tf.setNodes(
54 {
55 variant,
56 backgroundColor: variantConfig.backgroundColor,
57 icon: variantConfig.icon,
58 [PALETTE_DROP_MUTABLE_KEY]: false,
59 },
60 { at: path },
61 );
62 };
63
64 return (
65 <ToolbarGroup>
66 <DropdownMenu open={open} onOpenChange={setOpen} modal={false}>
67 <DropdownMenuTrigger asChild>
68 <ToolbarButton
69 className="min-w-24"
70 isDropdown
71 pressed={open}
72 tooltip="Callout variant"
73 >
74 <MessageSquareWarning className="size-4" />
75 <span className="capitalize">{selectedVariant}</span>
76 </ToolbarButton>
77 </DropdownMenuTrigger>
78 <DropdownMenuContent
79 align="start"
80 className="ignore-click-outside/toolbar min-w-0"
81 >
82 <ToolbarMenuGroup
83 label="Variant"
84 onValueChange={updateVariant}
85 value={selectedVariant}
86 >
87 {CALLOUT_VARIANT_OPTIONS.map((variant) => (
88 <DropdownMenuRadioItem key={variant} value={variant}>
89 <span className="capitalize">{variant}</span>
90 </DropdownMenuRadioItem>
91 ))}
92 </ToolbarMenuGroup>
93 </DropdownMenuContent>
94 </DropdownMenu>
95 </ToolbarGroup>
96 );
97 }
98
98 lines Plain Text