diff --git a/apps/client/src/components/ui/emoji-picker.tsx b/apps/client/src/components/ui/emoji-picker.tsx
index 952c1171..112c2d9c 100644
--- a/apps/client/src/components/ui/emoji-picker.tsx
+++ b/apps/client/src/components/ui/emoji-picker.tsx
@@ -15,6 +15,11 @@ export interface EmojiPickerInterface {
icon: ReactNode;
removeEmojiAction: () => void;
readOnly: boolean;
+ actionIconProps?: {
+ size?: string;
+ variant?: string;
+ c?: string;
+ };
}
function EmojiPicker({
@@ -22,6 +27,7 @@ function EmojiPicker({
icon,
removeEmojiAction,
readOnly,
+ actionIconProps,
}: EmojiPickerInterface) {
const { t } = useTranslation();
const [opened, handlers] = useDisclosure(false);
@@ -64,7 +70,12 @@ function EmojiPicker({
closeOnEscape={true}
>
-
+
{icon}
diff --git a/apps/client/src/features/editor/components/callout/callout-menu.tsx b/apps/client/src/features/editor/components/callout/callout-menu.tsx
index 56dea233..400460e7 100644
--- a/apps/client/src/features/editor/components/callout/callout-menu.tsx
+++ b/apps/client/src/features/editor/components/callout/callout-menu.tsx
@@ -9,18 +9,21 @@ import {
EditorMenuProps,
ShouldShowProps,
} from "@/features/editor/components/table/types/types.ts";
-import { ActionIcon, Tooltip } from "@mantine/core";
+import { ActionIcon, Tooltip, Divider } from "@mantine/core";
import {
IconAlertTriangleFilled,
IconCircleCheckFilled,
IconCircleXFilled,
IconInfoCircleFilled,
+ IconMoodSmile,
} from "@tabler/icons-react";
import { CalloutType } from "@docmost/editor-ext";
import { useTranslation } from "react-i18next";
+import EmojiPicker from "@/components/ui/emoji-picker.tsx";
export function CalloutMenu({ editor }: EditorMenuProps) {
const { t } = useTranslation();
+
const shouldShow = useCallback(
({ state }: ShouldShowProps) => {
if (!state) {
@@ -56,6 +59,36 @@ export function CalloutMenu({ editor }: EditorMenuProps) {
[editor],
);
+ const setCalloutIcon = useCallback(
+ (emoji: any) => {
+ const emojiChar = emoji?.native || emoji?.emoji || emoji;
+ editor
+ .chain()
+ .focus(undefined, { scrollIntoView: false })
+ .updateCalloutIcon(emojiChar)
+ .run();
+ },
+ [editor],
+ );
+
+ const removeCalloutIcon = useCallback(() => {
+ editor
+ .chain()
+ .focus(undefined, { scrollIntoView: false })
+ .updateCalloutIcon("")
+ .run();
+ }, [editor]);
+
+ const getCurrentIcon = () => {
+ const { selection } = editor.state;
+ const predicate = (node: PMNode) => node.type.name === "callout";
+ const parent = findParentNode(predicate)(selection);
+ const icon = parent?.node.attrs.icon;
+ return icon || null;
+ };
+
+ const currentIcon = getCurrentIcon();
+
return (
+
+
+ }
+ actionIconProps={{
+ size: "lg",
+ variant: "default",
+ c: undefined
+ }}
+ />
+
);
diff --git a/apps/client/src/features/editor/components/callout/callout-view.tsx b/apps/client/src/features/editor/components/callout/callout-view.tsx
index 0df410a3..5583bd87 100644
--- a/apps/client/src/features/editor/components/callout/callout-view.tsx
+++ b/apps/client/src/features/editor/components/callout/callout-view.tsx
@@ -11,7 +11,7 @@ import { CalloutType } from "@docmost/editor-ext";
export default function CalloutView(props: NodeViewProps) {
const { node } = props;
- const { type } = node.attrs;
+ const { type, icon } = node.attrs;
return (
@@ -19,7 +19,7 @@ export default function CalloutView(props: NodeViewProps) {
variant="light"
title=""
color={getCalloutColor(type)}
- icon={getCalloutIcon(type)}
+ icon={getCalloutIcon(type, icon)}
p="xs"
classNames={{
message: classes.message,
@@ -32,7 +32,11 @@ export default function CalloutView(props: NodeViewProps) {
);
}
-function getCalloutIcon(type: CalloutType) {
+function getCalloutIcon(type: CalloutType, customIcon?: string) {
+ if (customIcon && customIcon.trim() !== "") {
+ return {customIcon};
+ }
+
switch (type) {
case "info":
return ;
diff --git a/packages/editor-ext/src/lib/callout/callout.ts b/packages/editor-ext/src/lib/callout/callout.ts
index c756917b..97c5dfcc 100644
--- a/packages/editor-ext/src/lib/callout/callout.ts
+++ b/packages/editor-ext/src/lib/callout/callout.ts
@@ -18,6 +18,10 @@ export interface CalloutAttributes {
* The type of callout.
*/
type: CalloutType;
+ /**
+ * The custom icon name for the callout.
+ */
+ icon?: string;
}
declare module "@tiptap/core" {
@@ -27,6 +31,7 @@ declare module "@tiptap/core" {
unsetCallout: () => ReturnType;
toggleCallout: (attributes?: CalloutAttributes) => ReturnType;
updateCalloutType: (type: CalloutType) => ReturnType;
+ updateCalloutIcon: (icon: string) => ReturnType;
};
}
}
@@ -58,6 +63,13 @@ export const Callout = Node.create({
"data-callout-type": attributes.type,
}),
},
+ icon: {
+ default: null,
+ parseHTML: (element) => element.getAttribute("data-callout-icon"),
+ renderHTML: (attributes) => ({
+ "data-callout-icon": attributes.icon,
+ }),
+ },
};
},
@@ -107,6 +119,13 @@ export const Callout = Node.create({
commands.updateAttributes("callout", {
type: getValidCalloutType(type),
}),
+
+ updateCalloutIcon:
+ (icon: string) =>
+ ({ commands }) =>
+ commands.updateAttributes("callout", {
+ icon: icon || null,
+ }),
};
},