From de0b5f0046538996e66f9e9ad56ba07bf0f6c145 Mon Sep 17 00:00:00 2001 From: fuscodev Date: Thu, 6 Feb 2025 17:24:36 +0100 Subject: [PATCH] feat: add text alignment (#667) * feat: text alignment * fix text case --------- Co-authored-by: Philipinho <16838612+Philipinho@users.noreply.github.com> --- .../public/locales/en-US/translation.json | 1 + .../components/bubble-menu/bubble-menu.tsx | 23 ++++ .../bubble-menu/text-alignment-selector.tsx | 107 ++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 apps/client/src/features/editor/components/bubble-menu/text-alignment-selector.tsx diff --git a/apps/client/public/locales/en-US/translation.json b/apps/client/public/locales/en-US/translation.json index d3e06d26..571de47f 100644 --- a/apps/client/public/locales/en-US/translation.json +++ b/apps/client/public/locales/en-US/translation.json @@ -244,6 +244,7 @@ "Align left": "Align left", "Align right": "Align right", "Align center": "Align center", + "Justify": "Justify", "Merge cells": "Merge cells", "Split cell": "Split cell", "Delete column": "Delete column", diff --git a/apps/client/src/features/editor/components/bubble-menu/bubble-menu.tsx b/apps/client/src/features/editor/components/bubble-menu/bubble-menu.tsx index 5ee16c38..6d948ebf 100644 --- a/apps/client/src/features/editor/components/bubble-menu/bubble-menu.tsx +++ b/apps/client/src/features/editor/components/bubble-menu/bubble-menu.tsx @@ -18,6 +18,7 @@ import classes from "./bubble-menu.module.css"; import { ActionIcon, rem, Tooltip } from "@mantine/core"; import { ColorSelector } from "./color-selector"; import { NodeSelector } from "./node-selector"; +import { TextAlignmentSelector } from "./text-alignment-selector"; import { draftCommentIdAtom, showCommentPopupAtom, @@ -117,6 +118,7 @@ export const EditorBubbleMenu: FC = (props) => { moveTransition: "transform 0.15s ease-out", onHide: () => { setIsNodeSelectorOpen(false); + setIsTextAlignmentOpen(false); setIsColorSelectorOpen(false); setIsLinkSelectorOpen(false); }, @@ -124,6 +126,7 @@ export const EditorBubbleMenu: FC = (props) => { }; const [isNodeSelectorOpen, setIsNodeSelectorOpen] = useState(false); + const [isTextAlignmentSelectorOpen, setIsTextAlignmentOpen] = useState(false); const [isColorSelectorOpen, setIsColorSelectorOpen] = useState(false); const [isLinkSelectorOpen, setIsLinkSelectorOpen] = useState(false); @@ -135,6 +138,20 @@ export const EditorBubbleMenu: FC = (props) => { isOpen={isNodeSelectorOpen} setIsOpen={() => { setIsNodeSelectorOpen(!isNodeSelectorOpen); + setIsTextAlignmentOpen(false); + setIsColorSelectorOpen(false); + setIsLinkSelectorOpen(false); + }} + /> + + { + setIsTextAlignmentOpen(!isTextAlignmentSelectorOpen); + setIsNodeSelectorOpen(false); + setIsColorSelectorOpen(false); + setIsLinkSelectorOpen(false); }} /> @@ -162,6 +179,9 @@ export const EditorBubbleMenu: FC = (props) => { isOpen={isLinkSelectorOpen} setIsOpen={() => { setIsLinkSelectorOpen(!isLinkSelectorOpen); + setIsNodeSelectorOpen(false); + setIsTextAlignmentOpen(false); + setIsColorSelectorOpen(false); }} /> @@ -170,6 +190,9 @@ export const EditorBubbleMenu: FC = (props) => { isOpen={isColorSelectorOpen} setIsOpen={() => { setIsColorSelectorOpen(!isColorSelectorOpen); + setIsNodeSelectorOpen(false); + setIsTextAlignmentOpen(false); + setIsLinkSelectorOpen(false); }} /> diff --git a/apps/client/src/features/editor/components/bubble-menu/text-alignment-selector.tsx b/apps/client/src/features/editor/components/bubble-menu/text-alignment-selector.tsx new file mode 100644 index 00000000..8330684b --- /dev/null +++ b/apps/client/src/features/editor/components/bubble-menu/text-alignment-selector.tsx @@ -0,0 +1,107 @@ +import React, { Dispatch, FC, SetStateAction } from "react"; +import { + IconAlignCenter, + IconAlignJustified, + IconAlignLeft, + IconAlignRight, + IconCheck, + IconChevronDown, +} from "@tabler/icons-react"; +import { Popover, Button, ScrollArea, rem } from "@mantine/core"; +import { useEditor } from "@tiptap/react"; +import { useTranslation } from "react-i18next"; + +interface TextAlignmentProps { + editor: ReturnType; + isOpen: boolean; + setIsOpen: Dispatch>; +} + +export interface BubbleMenuItem { + name: string; + icon: React.ElementType; + command: () => void; + isActive: () => boolean; +} + +export const TextAlignmentSelector: FC = ({ + editor, + isOpen, + setIsOpen, +}) => { + const { t } = useTranslation(); + + const items: BubbleMenuItem[] = [ + { + name: "Align left", + isActive: () => editor.isActive({ textAlign: "left" }), + command: () => editor.chain().focus().setTextAlign("left").run(), + icon: IconAlignLeft, + }, + { + name: "Align center", + isActive: () => editor.isActive({ textAlign: "center" }), + command: () => editor.chain().focus().setTextAlign("center").run(), + icon: IconAlignCenter, + }, + { + name: "Align right", + isActive: () => editor.isActive({ textAlign: "right" }), + command: () => editor.chain().focus().setTextAlign("right").run(), + icon: IconAlignRight, + }, + { + name: "Justify", + isActive: () => editor.isActive({ textAlign: "justify" }), + command: () => editor.chain().focus().setTextAlign("justify").run(), + icon: IconAlignJustified, + }, + ]; + + const activeItem = items.filter((item) => item.isActive()).pop() ?? { + name: "Multiple", + }; + + return ( + + + + + + + + + {items.map((item, index) => ( + + ))} + + + + + ); +};