diff --git a/apps/console/src/pages/organizations/documents/description/DocumentDescriptionPage.tsx b/apps/console/src/pages/organizations/documents/description/DocumentDescriptionPage.tsx index 7e672894c..54c4380c5 100644 --- a/apps/console/src/pages/organizations/documents/description/DocumentDescriptionPage.tsx +++ b/apps/console/src/pages/organizations/documents/description/DocumentDescriptionPage.tsx @@ -23,6 +23,8 @@ import { useDebounceCallback } from "usehooks-ts"; import type { DocumentDescriptionPage_updateContentMutation } from "#/__generated__/core/DocumentDescriptionPage_updateContentMutation.graphql"; import type { DocumentDescriptionPageQuery } from "#/__generated__/core/DocumentDescriptionPageQuery.graphql"; +const autoSaveIntervalMs = 1000; + export const documentDescriptionPageQuery = graphql` query DocumentDescriptionPageQuery($documentId: ID! $versionId: ID! $versionSpecified: Boolean!) { # We use this on /documents/:documentId/versions/:versionId/description @@ -113,7 +115,7 @@ export function DocumentDescriptionPage(props: { queryRef: PreloadedQuery=10" + }, + "peerDependencies": { + "react": ">= 16.8", + "react-dom": ">= 16.8" + } + }, "node_modules/@playwright/test": { "version": "1.58.2", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz", @@ -19702,6 +19715,7 @@ "dependencies": { "@ariakit/react": "^0.4.17", "@floating-ui/react": "^0.27.19", + "@phosphor-icons/react": "^2.1.10", "@probo/helpers": "1.0.0", "@probo/i18n": "1.0.0", "@radix-ui/react-alert-dialog": "^1.1.15", diff --git a/packages/ui/package.json b/packages/ui/package.json index c93267105..fbe5cbfdf 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -14,6 +14,7 @@ "dependencies": { "@ariakit/react": "^0.4.17", "@floating-ui/react": "^0.27.19", + "@phosphor-icons/react": "^2.1.10", "@probo/helpers": "1.0.0", "@probo/i18n": "1.0.0", "@radix-ui/react-alert-dialog": "^1.1.15", diff --git a/packages/ui/src/RichEditor/BlockMenu.tsx b/packages/ui/src/RichEditor/BlockMenu.tsx index 4b5dbd876..b922fc526 100644 --- a/packages/ui/src/RichEditor/BlockMenu.tsx +++ b/packages/ui/src/RichEditor/BlockMenu.tsx @@ -9,21 +9,20 @@ import { useFloatingRootContext, useInteractions, } from "@floating-ui/react"; +import { CodeBlockIcon, ListBulletsIcon, ListNumbersIcon, MinusIcon, PlusIcon, QuotesIcon, TextHOneIcon, TextHThreeIcon, TextHTwoIcon, TextTIcon } from "@phosphor-icons/react"; import { type useEditor } from "@tiptap/react"; import { useEffect, useLayoutEffect, useRef, useState } from "react"; import { tv } from "tailwind-variants"; -import { IconPlusSmall } from "../Atoms/Icons"; - import { MenuButton } from "./MenuButton"; const blockMenuVariants = tv({ slots: { trigger: [ - "z-50 flex size-6 items-center justify-center", + "z-10 flex size-6 items-center justify-center", "rounded text-txt-tertiary hover:bg-subtle hover:text-txt-primary text-xl font-light cursor-pointer", ], - menu: ["flex items-center gap-1 rounded-lg border border-border-mid bg-level-0 p-1 shadow-md z-50"], + menu: ["rounded-lg border border-border-mid bg-level-0 p-1 shadow-md z-20"], }, }); @@ -170,7 +169,7 @@ export function BlockMenu({ editor }: BlockMenuProps) { }} className={trigger()} > - + {menuOpen && (
e.preventDefault()} className={menu()} > +
Style
handleAction(chain => chain.setParagraph())} + > + + Text + + handleAction(chain => chain.toggleHeading({ level: 1 }))} - /> + > + + Heading 1 + handleAction(chain => chain.toggleHeading({ level: 2 }))} - /> + > + + Heading 2 + handleAction(chain => chain.toggleHeading({ level: 3 }))} - /> + > + + Heading 3 + handleAction(chain => chain.toggleBulletList())} - /> + > + + Bullet List + handleAction(chain => chain.toggleOrderedList())} - /> + > + + Ordered List + handleAction(chain => chain.toggleCode())} - /> - handleAction(chain => chain.toggleCodeBlock())} - /> + > + + Code Block + handleAction(chain => chain.toggleBlockquote())} - /> + > + + Blockquote + handleAction(chain => chain.setHorizontalRule())} - /> + > + + Divider +
)} diff --git a/packages/ui/src/RichEditor/BubbleMenu.tsx b/packages/ui/src/RichEditor/BubbleMenu.tsx index 45b336401..606bc8267 100644 --- a/packages/ui/src/RichEditor/BubbleMenu.tsx +++ b/packages/ui/src/RichEditor/BubbleMenu.tsx @@ -1,3 +1,4 @@ +import { CodeIcon, LinkIcon, TextBIcon, TextItalicIcon, TextStrikethroughIcon, TextUnderlineIcon } from "@phosphor-icons/react"; import type { useEditor } from "@tiptap/react"; import { BubbleMenu as BaseBubbleMenu } from "@tiptap/react/menus"; import { tv } from "tailwind-variants"; @@ -21,32 +22,36 @@ export function BubbleMenu(props: BubbleMenuProps) { className={bubbleMenuVariants()} > editor.chain().focus().toggleBold().run()} - /> + > + + editor.chain().focus().toggleItalic().run()} - /> + > + + editor.chain().focus().toggleUnderline().run()} - /> + > + + editor.chain().focus().toggleStrike().run()} - /> + > + + editor.chain().focus().toggleCode().run()} - /> + > + + { if (editor.isActive("link")) { @@ -58,7 +63,9 @@ export function BubbleMenu(props: BubbleMenuProps) { editor.chain().focus().setLink({ href: url }).run(); } }} - /> + > + + ); } diff --git a/packages/ui/src/RichEditor/MenuButton.tsx b/packages/ui/src/RichEditor/MenuButton.tsx index 7d9e6f2b3..ed9d07519 100644 --- a/packages/ui/src/RichEditor/MenuButton.tsx +++ b/packages/ui/src/RichEditor/MenuButton.tsx @@ -1,7 +1,11 @@ +import type { PropsWithChildren } from "react"; import { tv } from "tailwind-variants"; const menuButtonVariants = tv({ - base: ["px-2 py-1 text-sm rounded-sm font-semibold bg-level-0 hover:bg-subtle"], + base: [ + "flex items-center gap-2 w-full", + "px-2 py-1.5 text-sm rounded-sm bg-level-0 hover:bg-subtle cursor-pointer", + ], variants: { active: { true: ["bg-active"], @@ -10,19 +14,18 @@ const menuButtonVariants = tv({ }); type MenuButtonProps = { - label: string; active?: boolean; onClick: () => void; }; -export function MenuButton({ label, active, onClick }: MenuButtonProps) { +export function MenuButton({ children, active, onClick }: PropsWithChildren) { return ( ); } diff --git a/packages/ui/src/RichEditor/OptionsMenu.tsx b/packages/ui/src/RichEditor/OptionsMenu.tsx index 5f2d53ce3..43e9e8bc5 100644 --- a/packages/ui/src/RichEditor/OptionsMenu.tsx +++ b/packages/ui/src/RichEditor/OptionsMenu.tsx @@ -9,23 +9,22 @@ import { useFloatingRootContext, useInteractions, } from "@floating-ui/react"; +import { CodeBlockIcon, DotsSixVerticalIcon, ListBulletsIcon, ListNumbersIcon, QuotesIcon, TextHOneIcon, TextHThreeIcon, TextHTwoIcon, TextTIcon } from "@phosphor-icons/react"; import { NodeSelection, TextSelection } from "@tiptap/pm/state"; import type { EditorView } from "@tiptap/pm/view"; import { type useEditor } from "@tiptap/react"; import { type DragEvent, useEffect, useLayoutEffect, useRef, useState } from "react"; import { tv } from "tailwind-variants"; -import { IconChevronGrabberVertical } from "../Atoms/Icons"; - import { MenuButton } from "./MenuButton"; const optionsMenuVariants = tv({ slots: { trigger: [ - "z-50 flex size-6 items-center justify-center", + "z-10 flex size-6 items-center justify-center", "rounded text-txt-tertiary hover:bg-subtle hover:text-txt-primary cursor-grab", ], - menu: ["flex items-center gap-1 rounded-lg border border-border-mid bg-level-0 p-1 shadow-md z-50"], + menu: ["rounded-lg border border-border-mid bg-level-0 p-1 shadow-md z-20"], }, }); @@ -265,7 +264,7 @@ export function OptionsMenu({ editor }: OptionsMenuProps) { }} className={trigger()} > - + {menuOpen && (
e.preventDefault()} className={menu()} > +
Turn into
+ handleAction(chain => chain.setParagraph())} + > + + Text + handleAction(chain => chain.toggleHeading({ level: 1 }))} - /> + > + + Heading 1 + handleAction(chain => chain.toggleHeading({ level: 2 }))} - /> + > + + Heading 2 + handleAction(chain => chain.toggleHeading({ level: 3 }))} - /> + > + + Heading 3 + handleAction(chain => chain.toggleBulletList())} - /> + > + + Bullet List + handleAction(chain => chain.toggleOrderedList())} - /> + > + + Ordered List + handleAction(chain => chain.toggleCode())} - /> - handleAction(chain => chain.toggleCodeBlock())} - /> + > + + Code Block + handleAction(chain => chain.toggleBlockquote())} - /> + > + + Blockquote +
)} diff --git a/packages/ui/src/RichEditor/RichEditor.tsx b/packages/ui/src/RichEditor/RichEditor.tsx index 66f79ecd5..9d200adae 100644 --- a/packages/ui/src/RichEditor/RichEditor.tsx +++ b/packages/ui/src/RichEditor/RichEditor.tsx @@ -14,13 +14,12 @@ import { Text } from "@tiptap/extension-text"; import { Underline } from "@tiptap/extension-underline"; import { Dropcursor, Gapcursor, UndoRedo } from "@tiptap/extensions"; import { type Content, EditorContent, useEditor, useEditorState } from "@tiptap/react"; -import { BubbleMenu } from "@tiptap/react/menus"; import { type ComponentProps, useEffect, useRef } from "react"; import { tv } from "tailwind-variants"; import { BlockMenu } from "./BlockMenu"; +import { BubbleMenu } from "./BubbleMenu"; import { LinkExtension } from "./LinkExtension"; -import { MenuButton } from "./MenuButton"; import { OptionsMenu } from "./OptionsMenu"; const extensions = [ @@ -49,14 +48,9 @@ const extensions = [ ]; const richEditorVariants = tv({ - slots: { - bubbleMenu: ["flex items-center gap-1 rounded-lg border border-border-mid bg-level-0 p-1 shadow-md"], - editor: ["h-full px-12"], - }, + base: ["h-full px-12"], }); -const { bubbleMenu, editor: editorVariants } = richEditorVariants(); - type RichEditorProps = ComponentProps<"div"> & { content: string; disabled?: boolean; @@ -94,55 +88,10 @@ export function RichEditor(props: RichEditorProps) { }, [content, watchedContent, onChangeContent]); return ( -
- - editor.chain().focus().toggleBold().run()} - /> - editor.chain().focus().toggleItalic().run()} - /> - editor.chain().focus().toggleUnderline().run()} - /> - editor.chain().focus().toggleStrike().run()} - /> - editor.chain().focus().toggleCode().run()} - /> - { - if (editor.isActive("link")) { - editor.chain().focus().unsetLink().run(); - return; - } - const url = window.prompt("URL"); - if (url) { - editor.chain().focus().setLink({ href: url }).run(); - } - }} - /> - - +
+ -
);