diff --git a/packages/editor/src/core/components/editors/document/collaborative-editor.tsx b/packages/editor/src/core/components/editors/document/collaborative-editor.tsx index 751c791011f..623ec9508c8 100644 --- a/packages/editor/src/core/components/editors/document/collaborative-editor.tsx +++ b/packages/editor/src/core/components/editors/document/collaborative-editor.tsx @@ -1,5 +1,7 @@ import { Extensions } from "@tiptap/core"; import React from "react"; +// plane imports +import { cn } from "@plane/utils"; // components import { DocumentContentLoader, PageRenderer } from "@/components/editors"; // constants @@ -73,7 +75,11 @@ const CollaborativeDocumentEditor = (props: ICollaborativeDocumentEditor) => { if (!editor) return null; - if (!hasServerSynced && !hasServerConnectionFailed) return ; + const blockWidthClassName = cn("w-full max-w-[720px] mx-auto transition-all duration-200 ease-in-out", { + "max-w-[1152px]": displayConfig.wideLayout, + }); + + if (!hasServerSynced && !hasServerConnectionFailed) return ; return ( { bubbleMenuEnabled={bubbleMenuEnabled} displayConfig={displayConfig} editor={editor} - editorContainerClassName={editorContainerClassNames} + editorContainerClassName={cn(editorContainerClassNames, "document-editor")} id={id} tabIndex={tabIndex} /> diff --git a/packages/editor/src/core/components/editors/document/loader.tsx b/packages/editor/src/core/components/editors/document/loader.tsx index ab9c3b479d7..ece0d4b7709 100644 --- a/packages/editor/src/core/components/editors/document/loader.tsx +++ b/packages/editor/src/core/components/editors/document/loader.tsx @@ -1,42 +1,51 @@ -// ui +// plane imports import { Loader } from "@plane/ui"; +import { cn } from "@plane/utils"; -export const DocumentContentLoader = () => ( -
- -
-
- -
- -
- - -
-
- -
- - -
- - -
-
- -
- -
- -
- -
+type Props = { + className?: string; +}; + +export const DocumentContentLoader = (props: Props) => { + const { className } = props; + + return ( +
+ +
+ +
+ +
+ +
+
+ +
+ + +
+ + +
+
+ +
+ +
+
+
+
+ +
+ +
-
- -
-); + +
+ ); +}; diff --git a/packages/editor/src/core/components/editors/document/page-renderer.tsx b/packages/editor/src/core/components/editors/document/page-renderer.tsx index a297686564d..2b4c094c59f 100644 --- a/packages/editor/src/core/components/editors/document/page-renderer.tsx +++ b/packages/editor/src/core/components/editors/document/page-renderer.tsx @@ -132,7 +132,7 @@ export const PageRenderer = (props: IPageRenderer) => { return ( <> -
+
{ bubbleMenuEnabled={false} displayConfig={displayConfig} editor={editor} - editorContainerClassName={editorContainerClassName} + editorContainerClassName={cn(editorContainerClassName, "document-editor")} id={id} /> ); diff --git a/packages/editor/src/core/components/editors/editor-container.tsx b/packages/editor/src/core/components/editors/editor-container.tsx index b742a526526..02f0a021711 100644 --- a/packages/editor/src/core/components/editors/editor-container.tsx +++ b/packages/editor/src/core/components/editors/editor-container.tsx @@ -74,6 +74,7 @@ export const EditorContainer: FC = (props) => { `editor-container cursor-text relative line-spacing-${displayConfig.lineSpacing ?? DEFAULT_DISPLAY_CONFIG.lineSpacing}`, { "active-editor": editor?.isFocused && editor?.isEditable, + "wide-layout": displayConfig.wideLayout, }, displayConfig.fontSize ?? DEFAULT_DISPLAY_CONFIG.fontSize, displayConfig.fontStyle ?? DEFAULT_DISPLAY_CONFIG.fontStyle, diff --git a/packages/editor/src/core/constants/config.ts b/packages/editor/src/core/constants/config.ts index 788454f9639..ac6d63dd161 100644 --- a/packages/editor/src/core/constants/config.ts +++ b/packages/editor/src/core/constants/config.ts @@ -5,6 +5,7 @@ export const DEFAULT_DISPLAY_CONFIG: TDisplayConfig = { fontSize: "large-font", fontStyle: "sans-serif", lineSpacing: "regular", + wideLayout: false, }; export const ACCEPTED_FILE_MIME_TYPES = ["image/jpeg", "image/jpg", "image/png", "image/webp", "image/gif"]; diff --git a/packages/editor/src/core/helpers/common.ts b/packages/editor/src/core/helpers/common.ts index 8638d2c151d..04f827ece53 100644 --- a/packages/editor/src/core/helpers/common.ts +++ b/packages/editor/src/core/helpers/common.ts @@ -49,7 +49,7 @@ export const isValidHttpUrl = (string: string): boolean => { try { url = new URL(string); - } catch (_) { + } catch { return false; } diff --git a/packages/editor/src/core/types/config.ts b/packages/editor/src/core/types/config.ts index 12df0aa4234..4c91fec5d10 100644 --- a/packages/editor/src/core/types/config.ts +++ b/packages/editor/src/core/types/config.ts @@ -29,4 +29,5 @@ export type TDisplayConfig = { fontStyle?: TEditorFontStyle; fontSize?: TEditorFontSize; lineSpacing?: TEditorLineSpacing; + wideLayout?: boolean; }; diff --git a/packages/editor/src/styles/editor.css b/packages/editor/src/styles/editor.css index be686a5cc77..ba910d1449e 100644 --- a/packages/editor/src/styles/editor.css +++ b/packages/editor/src/styles/editor.css @@ -8,7 +8,7 @@ -moz-user-select: text; -ms-user-select: text; user-select: text; - outline: none; + outline: none !important; cursor: text; font-family: var(--font-style); font-size: var(--font-size-regular); diff --git a/packages/editor/src/styles/variables.css b/packages/editor/src/styles/variables.css index ea70fe1ab87..31b64fa56c2 100644 --- a/packages/editor/src/styles/variables.css +++ b/packages/editor/src/styles/variables.css @@ -1,3 +1,47 @@ +:root { + /* text colors */ + --editor-colors-gray-text: #5c5e63; + --editor-colors-peach-text: #ff5b59; + --editor-colors-pink-text: #f65385; + --editor-colors-orange-text: #fd9038; + --editor-colors-green-text: #0fc27b; + --editor-colors-light-blue-text: #17bee9; + --editor-colors-dark-blue-text: #266df0; + --editor-colors-purple-text: #9162f9; + /* end text colors */ + + /* layout */ + --normal-content-width: 720px; + --wide-content-width: 1152px; + --normal-content-margin: 20px; + --wide-content-margin: 96px; + /* end layout */ +} + +/* text background colors */ +[data-theme*="light"] { + --editor-colors-gray-background: #d6d6d8; + --editor-colors-peach-background: #ffd5d7; + --editor-colors-pink-background: #fdd4e3; + --editor-colors-orange-background: #ffe3cd; + --editor-colors-green-background: #c3f0de; + --editor-colors-light-blue-background: #c5eff9; + --editor-colors-dark-blue-background: #c9dafb; + --editor-colors-purple-background: #e3d8fd; +} +[data-theme*="dark"] { + --editor-colors-gray-background: #404144; + --editor-colors-peach-background: #593032; + --editor-colors-pink-background: #562e3d; + --editor-colors-orange-background: #583e2a; + --editor-colors-green-background: #1d4a3b; + --editor-colors-light-blue-background: #1f495c; + --editor-colors-dark-blue-background: #223558; + --editor-colors-purple-background: #3d325a; +} +/* end text background colors */ + +/* font size and style */ .editor-container { --color-placeholder: rgba(var(--color-text-100), 0.5); @@ -47,6 +91,8 @@ /* end font sizes and line heights */ /* font styles */ + --font-style: "Inter", sans-serif; + &.sans-serif { --font-style: "Inter", sans-serif; } @@ -102,3 +148,94 @@ } /* end spacing */ } +/* end font size and style */ + +/* layout config */ +#page-header-container { + container-name: page-header-container; + container-type: inline-size; + + .page-header-content { + --header-width: var(--normal-content-width); + + &.wide-layout { + --header-width: var(--wide-content-width); + } + + padding-left: calc(((100% - var(--header-width)) / 2) - 10px); + } +} + +#page-content-container { + container-name: page-content-container; + container-type: inline-size; +} + +.editor-container.document-editor { + --editor-content-width: var(--normal-content-width); + + &.wide-layout { + --editor-content-width: var(--wide-content-width); + } + + .ProseMirror { + max-width: var(--editor-content-width); + margin: 0 auto; + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + } +} + +/* keep a static padding of 96px for wide layouts for container width >912px and <1344px */ +@container page-header-container (min-width: 912px) and (max-width: 1344px) { + .page-header-content.wide-layout { + padding-left: var(--wide-content-margin) !important; + } +} + +/* keep a static padding of 96px for wide layouts for container width <912px */ +@container page-header-container (max-width: 912) { + .page-header-content.wide-layout { + padding-left: var(--wide-content-margin) !important; + } +} +/* end layout config */ + +/* keep a static padding of 20px for wide layouts for container width <760px */ +@container page-header-container (max-width: 760px) { + .page-header-content { + padding-left: var(--normal-content-margin) !important; + } +} +/* end layout config */ + +/* keep a static padding of 96px for wide layouts for container width >912px and <1344px */ +@container page-content-container (min-width: 912px) and (max-width: 1344px) { + .editor-container.wide-layout, + .page-title-container { + padding-left: var(--wide-content-margin); + padding-right: var(--wide-content-margin); + } +} + +/* keep a static padding of 20px for wide layouts for container width <912px */ +@container page-content-container (max-width: 912px) { + .editor-container.wide-layout, + .page-title-container { + padding-left: var(--normal-content-margin); + padding-right: var(--normal-content-margin); + } +} + +/* keep a static padding of 20px for normal layouts for container width <760px */ +@container page-content-container (max-width: 760px) { + .editor-container:not(.wide-layout), + .page-title-container { + padding-left: var(--normal-content-margin); + padding-right: var(--normal-content-margin); + } + + .page-summary-container { + display: none; + } +} +/* end layout config */ diff --git a/web/ce/components/pages/editor/embed/issue-embed-upgrade-card.tsx b/web/ce/components/pages/editor/embed/issue-embed-upgrade-card.tsx index b4f68028d84..1f698f0a748 100644 --- a/web/ce/components/pages/editor/embed/issue-embed-upgrade-card.tsx +++ b/web/ce/components/pages/editor/embed/issue-embed-upgrade-card.tsx @@ -8,27 +8,25 @@ import { cn } from "@/helpers/common.helper"; export const IssueEmbedUpgradeCard: React.FC = (props) => (
-
-
- -

- Embed and access work items in pages seamlessly, upgrade to Plane Pro now. -

-
- - Upgrade - +
+ +

+ Embed and access issues in pages seamlessly, upgrade to Plane Pro now. +

+ + Upgrade +
); diff --git a/web/core/components/pages/editor/editor-body.tsx b/web/core/components/pages/editor/editor-body.tsx index aba274affeb..fce7f2e888b 100644 --- a/web/core/components/pages/editor/editor-body.tsx +++ b/web/core/components/pages/editor/editor-body.tsx @@ -1,6 +1,6 @@ import { Dispatch, SetStateAction, useCallback, useMemo } from "react"; import { observer } from "mobx-react"; -// document-editor +// plane imports import { CollaborativeDocumentEditorWithRef, EditorRefApi, @@ -10,15 +10,14 @@ import { TRealtimeConfig, TServerHandler, } from "@plane/editor"; -// plane types import { TSearchEntityRequestPayload, TSearchResponse, TWebhookConnectionQueryParams } from "@plane/types"; -// plane ui -import { Row } from "@plane/ui"; +import { ERowVariant, Row } from "@plane/ui"; +import { cn } from "@plane/utils"; // components import { EditorMentionsRoot } from "@/components/editor"; import { PageContentBrowser, PageContentLoader, PageEditorTitle } from "@/components/pages"; // helpers -import { cn, LIVE_BASE_PATH, LIVE_BASE_URL } from "@/helpers/common.helper"; +import { LIVE_BASE_PATH, LIVE_BASE_URL } from "@/helpers/common.helper"; import { generateRandomColor } from "@/helpers/string.helper"; // hooks import { useEditorMention } from "@/hooks/editor"; @@ -48,7 +47,6 @@ type Props = { handleEditorReady: Dispatch>; handlers: TEditorBodyHandlers; page: TPageInstance; - sidePeekVisible: boolean; webhookConnectionParams: TWebhookConnectionQueryParams; workspaceSlug: string; }; @@ -61,7 +59,6 @@ export const PageEditorBody: React.FC = observer((props) => { handleEditorReady, handlers, page, - sidePeekVisible, webhookConnectionParams, workspaceSlug, } = props; @@ -91,8 +88,9 @@ export const PageEditorBody: React.FC = observer((props) => { () => ({ fontSize, fontStyle, + wideLayout: isFullWidth, }), - [fontSize, fontStyle] + [fontSize, fontStyle, isFullWidth] ); const getAIMenu = useCallback( @@ -152,69 +150,70 @@ export const PageEditorBody: React.FC = observer((props) => { [currentUser?.display_name, currentUser?.id] ); - if (pageId === undefined || !realtimeConfig) return ; + const blockWidthClassName = cn( + "block bg-transparent w-full max-w-[720px] mx-auto transition-all duration-200 ease-in-out", + { + "max-w-[1152px]": isFullWidth, + } + ); + + if (pageId === undefined || !realtimeConfig) return ; return ( -
- -
-
- - { - const res = await fetchMentions(query); - if (!res) throw new Error("Failed in fetching mentions"); - return res; - }, - renderComponent: (props) => , - getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }), - }} - embedHandler={{ - issue: issueEmbedProps, - }} - realtimeConfig={realtimeConfig} - serverHandler={serverHandler} - user={userConfig} - disabledExtensions={disabledExtensions} - aiHandler={{ - menu: getAIMenu, - }} - /> + +
+ {/* table of content */} +
+
+
+
+ +
+
+ +
+
+
+ + { + const res = await fetchMentions(query); + if (!res) throw new Error("Failed in fetching mentions"); + return res; + }, + renderComponent: (props) => , + getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }), + }} + embedHandler={{ + issue: issueEmbedProps, + }} + realtimeConfig={realtimeConfig} + serverHandler={serverHandler} + user={userConfig} + disabledExtensions={disabledExtensions} + aiHandler={{ + menu: getAIMenu, + }} + />
-
-
+
); }); diff --git a/web/core/components/pages/editor/header/extra-options.tsx b/web/core/components/pages/editor/header/extra-options.tsx index 0b81d14522e..d9198b84f13 100644 --- a/web/core/components/pages/editor/header/extra-options.tsx +++ b/web/core/components/pages/editor/header/extra-options.tsx @@ -69,7 +69,7 @@ export const PageExtraOptions: React.FC = observer((props) => { }; return ( -
+
{is_locked && } {archived_at && (
diff --git a/web/core/components/pages/editor/header/mobile-root.tsx b/web/core/components/pages/editor/header/mobile-root.tsx index 22f25e2541f..a3cde27f4ce 100644 --- a/web/core/components/pages/editor/header/mobile-root.tsx +++ b/web/core/components/pages/editor/header/mobile-root.tsx @@ -2,9 +2,7 @@ import { observer } from "mobx-react"; import { EditorRefApi } from "@plane/editor"; // components import { Header, EHeaderVariant } from "@plane/ui"; -import { PageExtraOptions, PageSummaryPopover, PageToolbar } from "@/components/pages"; -// hooks -import { usePageFilters } from "@/hooks/use-page-filters"; +import { PageExtraOptions, PageToolbar } from "@/components/pages"; // plane web hooks import { EPageStoreType } from "@/plane-web/hooks/store"; // store @@ -13,29 +11,17 @@ import { TPageInstance } from "@/store/pages/base-page"; type Props = { editorRef: EditorRefApi; page: TPageInstance; - setSidePeekVisible: (sidePeekState: boolean) => void; - sidePeekVisible: boolean; storeType: EPageStoreType; }; export const PageEditorMobileHeaderRoot: React.FC = observer((props) => { - const { editorRef, page, setSidePeekVisible, sidePeekVisible, storeType } = props; + const { editorRef, page, storeType } = props; // derived values const { isContentEditable } = page; - // page filters - const { isFullWidth } = usePageFilters(); return ( <>
-
- -
diff --git a/web/core/components/pages/editor/header/root.tsx b/web/core/components/pages/editor/header/root.tsx index 552ba60097c..1099e838f69 100644 --- a/web/core/components/pages/editor/header/root.tsx +++ b/web/core/components/pages/editor/header/root.tsx @@ -1,8 +1,7 @@ import { observer } from "mobx-react"; import { EditorRefApi } from "@plane/editor"; // components -import { Header, EHeaderVariant } from "@plane/ui"; -import { PageEditorMobileHeaderRoot, PageExtraOptions, PageSummaryPopover, PageToolbar } from "@/components/pages"; +import { PageEditorMobileHeaderRoot, PageExtraOptions, PageToolbar } from "@/components/pages"; // helpers import { cn } from "@/helpers/common.helper"; // hooks @@ -16,13 +15,11 @@ type Props = { editorReady: boolean; editorRef: React.RefObject; page: TPageInstance; - setSidePeekVisible: (sidePeekState: boolean) => void; - sidePeekVisible: boolean; storeType: EPageStoreType; }; export const PageEditorHeaderRoot: React.FC = observer((props) => { - const { editorReady, editorRef, page, setSidePeekVisible, sidePeekVisible, storeType } = props; + const { editorReady, editorRef, page, storeType } = props; // derived values const { isContentEditable } = page; // page filters @@ -33,39 +30,27 @@ export const PageEditorHeaderRoot: React.FC = observer((props) => { if (!resolvedEditorRef) return null; return ( - <> -
- - {editorReady && ( -
- -
- )} - {isStickyToolbarEnabled && editorReady && isContentEditable && editorRef.current && ( - - )} -
- -
+
+
+
+
+ {isStickyToolbarEnabled && editorReady && isContentEditable && editorRef.current && ( + + )} +
+ +
+
- +
- +
); }); diff --git a/web/core/components/pages/editor/page-root.tsx b/web/core/components/pages/editor/page-root.tsx index c80a52d4349..8949d1556e8 100644 --- a/web/core/components/pages/editor/page-root.tsx +++ b/web/core/components/pages/editor/page-root.tsx @@ -48,7 +48,6 @@ export const PageRoot = observer((props: TPageRootProps) => { // states const [editorReady, setEditorReady] = useState(false); const [hasConnectionFailed, setHasConnectionFailed] = useState(false); - const [sidePeekVisible, setSidePeekVisible] = useState(window.innerWidth >= 768); const [isVersionsOverlayOpen, setIsVersionsOverlayOpen] = useState(false); // refs const editorRef = useRef(null); @@ -104,14 +103,7 @@ export const PageRoot = observer((props: TPageRootProps) => { pageId={page.id ?? ""} restoreEnabled={isContentEditable} /> - setSidePeekVisible(state)} - sidePeekVisible={sidePeekVisible} - storeType={storeType} - /> + { handleEditorReady={setEditorReady} handlers={handlers} page={page} - sidePeekVisible={sidePeekVisible} webhookConnectionParams={webhookConnectionParams} workspaceSlug={workspaceSlug} /> diff --git a/web/core/components/pages/editor/summary/content-browser.tsx b/web/core/components/pages/editor/summary/content-browser.tsx index 16d818aaeb7..f3a92d2aeec 100644 --- a/web/core/components/pages/editor/summary/content-browser.tsx +++ b/web/core/components/pages/editor/summary/content-browser.tsx @@ -7,10 +7,11 @@ import { OutlineHeading1, OutlineHeading2, OutlineHeading3 } from "./heading-com type Props = { editorRef: EditorRefApi | null; setSidePeekVisible?: (sidePeekState: boolean) => void; + showOutline?: boolean; }; export const PageContentBrowser: React.FC = (props) => { - const { editorRef, setSidePeekVisible } = props; + const { editorRef, setSidePeekVisible, showOutline = false } = props; // states const [headings, setHeadings] = useState([]); @@ -37,24 +38,28 @@ export const PageContentBrowser: React.FC = (props) => { }; return ( -
-
- {headings && headings.length !== 0 ? ( - headings.map((marking) => { - const Component = HeadingComponent[marking.level]; - if (!Component) return null; - return ( - handleOnClick(marking)} - /> - ); - }) - ) : ( -

Headings will be displayed here for navigation

- )} -
+
+ {headings.map((marking) => { + const Component = HeadingComponent[marking.level]; + if (!Component) return null; + if (showOutline === true) + return ( +
+ ); + return ( + handleOnClick(marking)} + /> + ); + })}
); }; diff --git a/web/core/components/pages/editor/summary/heading-components.tsx b/web/core/components/pages/editor/summary/heading-components.tsx index 5ed1752de02..c2e78dd67f1 100644 --- a/web/core/components/pages/editor/summary/heading-components.tsx +++ b/web/core/components/pages/editor/summary/heading-components.tsx @@ -1,36 +1,36 @@ -// document editor -import { IMarking } from "@plane/editor"; +// plane editor +import type { IMarking } from "@plane/editor"; -type HeadingProps = { +export type THeadingComponentProps = { marking: IMarking; onClick: (event: React.MouseEvent) => void; }; -export const OutlineHeading1 = ({ marking, onClick }: HeadingProps) => ( +export const OutlineHeading1 = ({ marking, onClick }: THeadingComponentProps) => ( ); -export const OutlineHeading2 = ({ marking, onClick }: HeadingProps) => ( +export const OutlineHeading2 = ({ marking, onClick }: THeadingComponentProps) => ( ); -export const OutlineHeading3 = ({ marking, onClick }: HeadingProps) => ( +export const OutlineHeading3 = ({ marking, onClick }: THeadingComponentProps) => ( diff --git a/web/core/components/pages/editor/summary/index.ts b/web/core/components/pages/editor/summary/index.ts index 3c4afb4d8af..779b7854838 100644 --- a/web/core/components/pages/editor/summary/index.ts +++ b/web/core/components/pages/editor/summary/index.ts @@ -1,2 +1 @@ export * from "./content-browser"; -export * from "./popover"; diff --git a/web/core/components/pages/editor/summary/popover.tsx b/web/core/components/pages/editor/summary/popover.tsx deleted file mode 100644 index 9acc4a7cc0c..00000000000 --- a/web/core/components/pages/editor/summary/popover.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { useState } from "react"; -import { usePopper } from "react-popper"; -import { List } from "lucide-react"; -// document editor -import { EditorRefApi } from "@plane/editor"; -// helpers -import { cn } from "@/helpers/common.helper"; -// components -import { PageContentBrowser } from "./content-browser"; - -type Props = { - editorRef: EditorRefApi | null; - isFullWidth: boolean; - sidePeekVisible: boolean; - setSidePeekVisible: (sidePeekState: boolean) => void; -}; - -export const PageSummaryPopover: React.FC = (props) => { - const { editorRef, sidePeekVisible, setSidePeekVisible } = props; - // refs - const [referenceElement, setReferenceElement] = useState(null); - const [popperElement, setPopperElement] = useState(null); - // popper-js - const { styles: summaryPopoverStyles, attributes: summaryPopoverAttributes } = usePopper( - referenceElement, - popperElement, - { - placement: "bottom-start", - } - ); - - return ( -
- -
- {sidePeekVisible && ( -
- -
- )} -
-
- {!sidePeekVisible && ( -
- -
- )} -
-
- ); -}; diff --git a/web/core/components/pages/editor/title.tsx b/web/core/components/pages/editor/title.tsx index 9e85c33d3bc..f9cd7f1f28e 100644 --- a/web/core/components/pages/editor/title.tsx +++ b/web/core/components/pages/editor/title.tsx @@ -17,26 +17,28 @@ type Props = { readOnly: boolean; title: string | undefined; updateTitle: (title: string) => void; + widthClassName: string; }; export const PageEditorTitle: React.FC = observer((props) => { - const { editorRef, readOnly, title, updateTitle } = props; + const { editorRef, readOnly, title, updateTitle, widthClassName } = props; // states const [isLengthVisible, setIsLengthVisible] = useState(false); // page filters const { fontSize } = usePageFilters(); // ui - const titleClassName = cn("bg-transparent tracking-[-2%] font-bold", { + const titleFontClassName = cn("tracking-[-2%] font-bold", { "text-[1.6rem] leading-[1.9rem]": fontSize === "small-font", "text-[2rem] leading-[2.375rem]": fontSize === "large-font", }); return ( -
+
{readOnly ? (
= observer((props) => { {getPageName(title)}
) : ( - <> +