From 1a755f4c698b5581106d8aaf387f47843305ce95 Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 9 Oct 2024 13:40:20 +0300 Subject: [PATCH] not-module-prosemirror-styles --- src/components/Editor/Editor.tsx | 146 ++-- .../{Editor.module.scss => Prosemirror.scss} | 70 +- .../Editor/Toolbar/TextBubbleMenu.tsx | 711 ++++++++++-------- src/components/Views/EditSettingsView.tsx | 2 +- src/components/Views/EditView.tsx | 4 +- src/context/editor.tsx | 7 +- 6 files changed, 491 insertions(+), 449 deletions(-) rename src/components/Editor/{Editor.module.scss => Prosemirror.scss} (98%) diff --git a/src/components/Editor/Editor.tsx b/src/components/Editor/Editor.tsx index a202aa72..082ad00c 100644 --- a/src/components/Editor/Editor.tsx +++ b/src/components/Editor/Editor.tsx @@ -1,6 +1,6 @@ import { HocuspocusProvider } from '@hocuspocus/provider' import { UploadFile } from '@solid-primitives/upload' -import { Editor, EditorOptions, isTextSelection } from '@tiptap/core' +import { Editor, EditorOptions } from '@tiptap/core' import { BubbleMenu } from '@tiptap/extension-bubble-menu' import { CharacterCount } from '@tiptap/extension-character-count' import { Collaboration } from '@tiptap/extension-collaboration' @@ -8,6 +8,7 @@ import { CollaborationCursor } from '@tiptap/extension-collaboration-cursor' import { FloatingMenu } from '@tiptap/extension-floating-menu' import { Placeholder } from '@tiptap/extension-placeholder' import { Show, createEffect, createMemo, createSignal, on, onCleanup, onMount } from 'solid-js' +import { isServer } from 'solid-js/web' import { createTiptapEditor } from 'solid-tiptap' import uniqolor from 'uniqolor' import { Doc } from 'yjs' @@ -19,15 +20,14 @@ import { Author } from '~/graphql/schema/core.gen' import { base, custom, extended } from '~/lib/editorExtensions' import { handleImageUpload } from '~/lib/handleImageUpload' import { allowedImageTypes, renderUploadedImage } from '../Upload/renderUploadedImage' +import { Panel } from './Panel/Panel' import { BlockquoteBubbleMenu } from './Toolbar/BlockquoteBubbleMenu' import { EditorFloatingMenu } from './Toolbar/EditorFloatingMenu' import { FigureBubbleMenu } from './Toolbar/FigureBubbleMenu' import { IncutBubbleMenu } from './Toolbar/IncutBubbleMenu' import { TextBubbleMenu } from './Toolbar/TextBubbleMenu' -import './Editor.module.scss' -import { isServer } from 'solid-js/web' -import { Panel } from './Panel/Panel' +import './Prosemirror.scss' export type EditorComponentProps = { shoutId: number @@ -43,8 +43,13 @@ export const EditorComponent = (props: EditorComponentProps) => { const { t } = useLocalize() const { session, requireAuthentication } = useSession() const author = createMemo(() => session()?.user?.app_data?.profile as Author) - const [isCommonMarkup, setIsCommonMarkup] = createSignal(false) - const [shouldShowTextBubbleMenu, setShouldShowTextBubbleMenu] = createSignal(false) + const [isCommonMarkup, _setIsCommonMarkup] = createSignal(false) + const createMenuSignal = () => createSignal(false) + const [shouldShowTextBubbleMenu, _setShouldShowTextBubbleMenu] = createMenuSignal() + const [shouldShowBlockquoteBubbleMenu, _setShouldShowBlockquoteBubbleMenu] = createMenuSignal() + const [shouldShowFigureBubbleMenu, _setShouldShowFigureBubbleMenu] = createMenuSignal() + const [shouldShowIncutBubbleMenu, _setShouldShowIncutBubbleMenu] = createMenuSignal() + const [shouldShowFloatingMenu, _setShouldShowFloatingMenu] = createMenuSignal() const { showSnackbar } = useSnackbar() const { countWords, setEditing } = useEditorContext() const [editorOptions, setEditorOptions] = createSignal>({}) @@ -71,11 +76,18 @@ export const EditorComponent = (props: EditorComponentProps) => { } console.log('stage 2: create editor instance without menus', opts) - const old = editor() || { options: {} } + const old = editor() || { options: {} as EditorOptions } + const uniqueExtensions = [ + ...new Map( + [...(old?.options?.extensions || []), ...(opts?.extensions || [])].map((ext) => [ext.name, ext]) + ).values() + ] + const fresh = createTiptapEditor(() => ({ ...old?.options, ...opts, - element: opts.element as HTMLElement + element: opts.element as HTMLElement, + extensions: uniqueExtensions })) if (old instanceof Editor) old?.destroy() setEditor(fresh() || null) @@ -147,7 +159,7 @@ export const EditorComponent = (props: EditorComponentProps) => { }, content: props.initialContent ?? null } - console.log('Editor options created:', options) + console.log(options) setEditorOptions(() => options) } @@ -176,85 +188,39 @@ export const EditorComponent = (props: EditorComponentProps) => { if (editor()) { initializeMenus() } - - // Инициализируем коллаборацию если необходимо - if (!props.disableCollaboration) { - initializeCollaboration() - } }, 1200) }, 'edit') }) const initializeMenus = () => { if (menusInitialized() || !editor()) return - - console.log('stage 3: initialize menus when editor instance is ready') - - if ( - textBubbleMenuRef() && - blockquoteBubbleMenuRef() && - figureBubbleMenuRef() && - incutBubbleMenuRef() && - floatingMenuRef() - ) { - const menus = [ - BubbleMenu.configure({ - pluginKey: 'textBubbleMenu', - element: textBubbleMenuRef(), - shouldShow: ({ editor: e, view, state: { doc, selection }, from, to }) => { - const isEmptyTextBlock = doc.textBetween(from, to).length === 0 && isTextSelection(selection) - isEmptyTextBlock && - e?.chain().focus().removeTextWrap({ class: 'highlight-fake-selection' }).run() - - setIsCommonMarkup(e?.isActive('figcaption')) - const result = - (view.hasFocus() && - !selection.empty && - !isEmptyTextBlock && - !e.isActive('image') && - !e.isActive('figure')) || - e.isActive('footnote') || - (e.isActive('figcaption') && !selection.empty) - setShouldShowTextBubbleMenu(result) - return result - }, - tippyOptions: { - onHide: () => editor()?.commands.focus() as false - } - }), - BubbleMenu.configure({ - pluginKey: 'blockquoteBubbleMenu', - element: blockquoteBubbleMenuRef(), - shouldShow: ({ editor: e, view, state }) => - view.hasFocus() && !state.selection.empty && e?.isActive('blockquote') - }), - BubbleMenu.configure({ - pluginKey: 'figureBubbleMenu', - element: figureBubbleMenuRef(), - shouldShow: ({ editor: e, view, state }) => - view.hasFocus() && !state.selection.empty && e?.isActive('figure') - }), - BubbleMenu.configure({ - pluginKey: 'incutBubbleMenu', - element: incutBubbleMenuRef(), - shouldShow: ({ editor: e, view, state }) => - view.hasFocus() && !state.selection.empty && e?.isActive('figcaption') - }), - FloatingMenu.configure({ - element: floatingMenuRef(), - pluginKey: 'floatingMenu', - shouldShow: ({ editor: e, state: { selection } }) => { - const isRootDepth = selection.$anchor.depth === 1 - const show = - isRootDepth && selection.empty && !(e?.isActive('codeBlock') || e?.isActive('heading')) - console.log('FloatingMenu shouldShow:', show) - return show - } - }) + if (blockquoteBubbleMenuRef() && figureBubbleMenuRef() && incutBubbleMenuRef() && floatingMenuRef()) { + console.log('stage 3: initialize menus when editor instance is ready') + const menuConfigs = [ + { key: 'textBubbleMenu', ref: textBubbleMenuRef, shouldShow: shouldShowTextBubbleMenu }, + { + key: 'blockquoteBubbleMenu', + ref: blockquoteBubbleMenuRef, + shouldShow: shouldShowBlockquoteBubbleMenu + }, + { key: 'figureBubbleMenu', ref: figureBubbleMenuRef, shouldShow: shouldShowFigureBubbleMenu }, + { key: 'incutBubbleMenu', ref: incutBubbleMenuRef, shouldShow: shouldShowIncutBubbleMenu }, + { key: 'floatingMenu', ref: floatingMenuRef, shouldShow: shouldShowFloatingMenu, isFloating: true } ] - const extensions = [...(editorOptions().extensions || []), ...menus] - setEditorOptions((prev) => ({ ...prev, extensions })) - console.log('Editor menus initialized:', extensions) + const menus = menuConfigs.map((config) => + config.isFloating + ? FloatingMenu.configure({ + pluginKey: config.key, + element: config.ref(), + shouldShow: config.shouldShow + }) + : BubbleMenu.configure({ + pluginKey: config.key, + element: config.ref(), + shouldShow: config.shouldShow + }) + ) + setEditorOptions((prev) => ({ ...prev, extensions: [...(prev.extensions || []), ...menus] })) setMenusInitialized(true) } else { console.error('Some menu references are missing') @@ -292,6 +258,13 @@ export const EditorComponent = (props: EditorComponentProps) => { setEditorOptions((prev: Partial) => { const extensions = [...(prev.extensions || [])] + if (props.disableCollaboration) { + // Remove collaboration extensions if they exist + const filteredExtensions = extensions.filter( + (ext) => ext.name !== 'collaboration' && ext.name !== 'collaborationCursor' + ) + return { ...prev, extensions: filteredExtensions } + } extensions.push( Collaboration.configure({ document: yDocs[docName] }), CollaborationCursor.configure({ @@ -316,6 +289,17 @@ export const EditorComponent = (props: EditorComponentProps) => { } } + // Инициализируем коллаборацию если необходимо + createEffect( + on( + () => props.disableCollaboration, + () => { + initializeCollaboration() + }, + { defer: true } + ) + ) + onCleanup(() => { editorElRef()?.removeEventListener('focus', handleFocus) editor()?.destroy() diff --git a/src/components/Editor/Editor.module.scss b/src/components/Editor/Prosemirror.scss similarity index 98% rename from src/components/Editor/Editor.module.scss rename to src/components/Editor/Prosemirror.scss index 468aadd9..a09b9d7b 100644 --- a/src/components/Editor/Editor.module.scss +++ b/src/components/Editor/Prosemirror.scss @@ -86,25 +86,25 @@ mark.highlight { } [data-float='half-left'] { - @include media-breakpoint-up(md) { - max-width: 50%; - min-width: 30%; - } - float: left; margin: 1rem 1rem 0; clear: left; - } - [data-float='half-right'] { @include media-breakpoint-up(md) { max-width: 50%; min-width: 30%; } + } + [data-float='half-right'] { float: right; margin: 1rem 0; clear: right; + + @include media-breakpoint-up(md) { + max-width: 50%; + min-width: 30%; + } } } @@ -114,7 +114,7 @@ mark.highlight { } &[data-type='quote'] { - font-size:1.4rem; + font-size: 1.4rem; border: solid #000; border-width: 0 0 0 2px; margin: 1.6rem 0; @@ -136,6 +136,20 @@ mark.highlight { } &[data-type='punchline'] { + border: solid #000; + border-width: 2px 0; + font-size: 3.2rem; + font-weight: 700; + line-height: 1.2; + margin: 1em 0; + padding: 2.4rem 0; + + &[data-float='left'], + &[data-float='right'] { + font-size: 2.2rem; + line-height: 1.4; + } + @include media-breakpoint-up(sm) { &[data-float='left'] { margin-right: 1.5em; @@ -147,24 +161,16 @@ mark.highlight { clear: right; } } - - font-size:3.2rem; - border: solid #000; - border-width: 2px 0; - font-weight: 700; - line-height: 1.2; - margin: 1em 0; - padding: 2.4rem 0; - - &[data-float='left'], - &[data-float='right'] { - font-size:2.2rem; - line-height: 1.4; - } } } .ProseMirror article[data-type='incut'] { + background: #f1f2f3; + font-size: 1.4rem; + margin: 1em -1rem; + padding: 2em 2rem; + transition: background 0.3s ease-in-out; + @include media-breakpoint-up(sm) { margin-left: -2rem; margin-right: -2rem; @@ -181,12 +187,6 @@ mark.highlight { margin-right: -3em; } - font-size:1.4rem; - background: #f1f2f3; - margin: 1em -1rem; - padding: 2em 2rem; - transition: background 0.3s ease-in-out; - &[data-float] img { float: none; max-width: unset; @@ -196,6 +196,9 @@ mark.highlight { &[data-float='left'], &[data-float='half-left'] { + margin-left: -1rem; + clear: left; + @include media-breakpoint-up(sm) { margin-left: -2rem; margin-right: 2rem; @@ -208,13 +211,13 @@ mark.highlight { @include media-breakpoint-up(xl) { margin-left: -12.5%; } - - margin-left: -1rem; - clear: left; } &[data-float='right'], &[data-float='half-right'] { + margin-right: -1rem; + clear: right; + @include media-breakpoint-up(sm) { margin-left: 2rem; margin-right: -2rem; @@ -227,9 +230,6 @@ mark.highlight { @include media-breakpoint-up(xl) { margin-right: -12.5%; } - - margin-right: -1rem; - clear: right; } *:last-child { @@ -311,4 +311,4 @@ footnote { color: var(--selection-color); border: solid var(--selection-background); border-width: 0; -} +} \ No newline at end of file diff --git a/src/components/Editor/Toolbar/TextBubbleMenu.tsx b/src/components/Editor/Toolbar/TextBubbleMenu.tsx index cc03865d..188de1e3 100644 --- a/src/components/Editor/Toolbar/TextBubbleMenu.tsx +++ b/src/components/Editor/Toolbar/TextBubbleMenu.tsx @@ -1,6 +1,16 @@ import type { Editor } from '@tiptap/core' import { clsx } from 'clsx' -import { Match, Show, Switch, createEffect, createSignal, lazy, onCleanup, onMount } from 'solid-js' +import { + Match, + Show, + Switch, + createEffect, + createMemo, + createSignal, + lazy, + onCleanup, + onMount +} from 'solid-js' import { createEditorTransaction } from 'solid-tiptap' import { Icon } from '~/components/_shared/Icon' import { Popover } from '~/components/_shared/Popover' @@ -21,404 +31,445 @@ type BubbleMenuProps = { export const TextBubbleMenu = (props: BubbleMenuProps) => { const { t } = useLocalize() - const isActive = (name: string, attributes?: Record) => - createEditorTransaction( - () => { - console.log('isActive', name, attributes) - return props.editor - }, - (editor) => editor?.isActive(name, attributes) - ) + const isActive = createMemo( + () => (name: string, attributes?: Record) => + props.editor?.isActive(name, attributes) + ) - const [textSizeBubbleOpen, setTextSizeBubbleOpen] = createSignal(false) - const [listBubbleOpen, setListBubbleOpen] = createSignal(false) - const [linkEditorOpen, setLinkEditorOpen] = createSignal(false) - const [footnoteEditorOpen, setFootnoteEditorOpen] = createSignal(false) - const [footNote, setFootNote] = createSignal() + const [menuState, setMenuState] = createSignal({ + textSizeBubbleOpen: false, + listBubbleOpen: false, + linkEditorOpen: false, + footnoteEditorOpen: false, + footNote: undefined as string | undefined + }) createEffect(() => { if (!props.shouldShow) { - setFootNote() - setFootnoteEditorOpen(false) - setLinkEditorOpen(false) - setTextSizeBubbleOpen(false) - setListBubbleOpen(false) + setMenuState((prev) => ({ + ...prev, + footNote: undefined, + footnoteEditorOpen: false, + linkEditorOpen: false, + textSizeBubbleOpen: false, + listBubbleOpen: false + })) } }) - const isBold = isActive('bold') - const isItalic = isActive('italic') - const isH1 = isActive('heading', { level: 2 }) - const isH2 = isActive('heading', { level: 3 }) - const isH3 = isActive('heading', { level: 4 }) - const isQuote = isActive('blockquote', { 'data-type': 'quote' }) - const isPunchLine = isActive('blockquote', { 'data-type': 'punchline' }) - const isOrderedList = isActive('isOrderedList') - const isBulletList = isActive('isBulletList') - const isLink = isActive('link') - const isHighlight = isActive('highlight') - const isFootnote = isActive('footnote') - const isIncut = isActive('article') + const activeStates = createMemo(() => ({ + bold: isActive()('bold'), + italic: isActive()('italic'), + h1: isActive()('heading', { level: 2 }), + h2: isActive()('heading', { level: 3 }), + h3: isActive()('heading', { level: 4 }), + quote: isActive()('blockquote', { 'data-type': 'quote' }), + punchLine: isActive()('blockquote', { 'data-type': 'punchline' }), + orderedList: isActive()('orderedList'), + bulletList: isActive()('bulletList'), + link: isActive()('link'), + highlight: isActive()('highlight'), + footnote: isActive()('footnote'), + incut: isActive()('article') + // underline: isActive()('underline'), + })) - const toggleTextSizePopup = () => { - if (listBubbleOpen()) { - setListBubbleOpen(false) - } - setTextSizeBubbleOpen((prev) => !prev) - } - const toggleListPopup = () => { - if (textSizeBubbleOpen()) { - setTextSizeBubbleOpen(false) - } - setListBubbleOpen((prev) => !prev) + const togglePopup = (type: 'textSize' | 'list') => { + setMenuState((prev) => ({ + ...prev, + textSizeBubbleOpen: type === 'textSize' ? !prev.textSizeBubbleOpen : false, + listBubbleOpen: type === 'list' ? !prev.listBubbleOpen : false + })) } + const handleKeyDown = (event: KeyboardEvent) => { if (event.code === 'KeyK' && (event.metaKey || event.ctrlKey) && !props.editor.state.selection.empty) { event.preventDefault() - setLinkEditorOpen(true) + setMenuState((prev) => ({ ...prev, linkEditorOpen: true })) } } const updateCurrentFootnoteValue = createEditorTransaction( () => props.editor, (ed) => { - if (!isFootnote()) { + if (!activeStates().footnote) { return } const value = ed.getAttributes('footnote').value - setFootNote(value) + setMenuState((prev) => ({ ...prev, footNote: value })) } ) const handleAddFootnote = (footnote: string) => { - if (footNote()) { + if (menuState().footNote) { props.editor?.chain().focus().updateFootnote({ value: footnote }).run() } else { props.editor?.chain().focus().setFootnote({ value: footnote }).run() } - setFootNote() - setLinkEditorOpen(false) - setFootnoteEditorOpen(false) + setMenuState((prev) => ({ + ...prev, + footNote: undefined, + linkEditorOpen: false, + footnoteEditorOpen: false + })) } const handleOpenFootnoteEditor = () => { updateCurrentFootnoteValue() - setLinkEditorOpen(false) - setFootnoteEditorOpen(true) + setMenuState((prev) => ({ ...prev, linkEditorOpen: false, footnoteEditorOpen: true })) } const handleSetPunchline = () => { - if (isPunchLine()) { + if (activeStates().punchLine) { props.editor?.chain().focus().toggleBlockquote('punchline').run() } props.editor?.chain().focus().toggleBlockquote('quote').run() - toggleTextSizePopup() + togglePopup('textSize') } const handleSetQuote = () => { - if (isQuote()) { + if (activeStates().quote) { props.editor?.chain().focus().toggleBlockquote('quote').run() } props.editor?.chain().focus().toggleBlockquote('punchline').run() - toggleTextSizePopup() + togglePopup('textSize') } onMount(() => { window.addEventListener('keydown', handleKeyDown) onCleanup(() => { window.removeEventListener('keydown', handleKeyDown) - setLinkEditorOpen(false) + setMenuState((prev) => ({ ...prev, linkEditorOpen: false })) }) }) const handleOpenLinkForm = () => { props.editor?.chain().focus().addTextWrap({ class: 'highlight-fake-selection' }).run() - setLinkEditorOpen(true) + setMenuState((prev) => ({ ...prev, linkEditorOpen: true })) } const handleCloseLinkForm = () => { - setLinkEditorOpen(false) + setMenuState((prev) => ({ ...prev, linkEditorOpen: false })) props.editor?.chain().focus().removeTextWrap({ class: 'highlight-fake-selection' }).run() } + const handleFormat = (type: 'Bold' | 'Italic' | 'Underline', _attributes?: Record) => { + props.editor?.chain().focus()[`toggle${type}`]().run() + } + + const ListBubbleMenu = (props: BubbleMenuProps) => { + return ( +
+
{t('Lists')}
+
+ + {(triggerRef: (el: HTMLElement) => void) => ( + + )} + + + {(triggerRef: (el: HTMLElement) => void) => ( + + )} + +
+
+ ) + } + + const CommonMarkupBubbleMenu = (props: BubbleMenuProps) => { + return ( + <> + + {(triggerRef: (el: HTMLElement) => void) => ( + + )} + +
+
+ + + + +
+ + ) + } + + const TextSizeBubbleMenu = (props: BubbleMenuProps) => { + return ( +
+
{t('Headers')}
+
+ + {(triggerRef: (el: HTMLElement) => void) => ( + + )} + + + {(triggerRef: (el: HTMLElement) => void) => ( + + )} + + + {(triggerRef: (el: HTMLElement) => void) => ( + + )} + +
+
{t('Quotes')}
+
+ + {(triggerRef: (el: HTMLElement) => void) => ( + + )} + + + {(triggerRef: (el: HTMLElement) => void) => ( + + )} + +
+
{t('squib')}
+
+ + {(triggerRef: (el: HTMLElement) => void) => ( + + )} + +
+
+ ) + } + + const BaseTextBubbleMenu = (props: BubbleMenuProps) => { + return ( + <> + + <> +
+ + + + +
+
+ + + + {(triggerRef: (el: HTMLElement) => void) => ( + + )} + + + {(triggerRef: (el: HTMLElement) => void) => ( + + )} + + {/* + {(triggerRef: (el: HTMLElement) => void) => ( + + )} + */} + + + {(triggerRef: (el: HTMLElement) => void) => ( + + )} + +
+ + {t('Add url')}
}> + {(triggerRef: (el: HTMLElement) => void) => ( + + )} + + + + + + ) + } return ( -
+
- + - + handleAddFootnote(value)} - content={footNote()} - onCancel={() => { - setFootnoteEditorOpen(false) - }} + onSubmit={handleAddFootnote} + content={menuState().footNote} + onCancel={() => setMenuState((prev) => ({ ...prev, footnoteEditorOpen: false }))} /> - - <> - - <> -
- - -
-
{t('Headers')}
-
- - {(triggerRef: (el: HTMLElement) => void) => ( - - )} - - - {(triggerRef: (el: HTMLElement) => void) => ( - - )} - - - {(triggerRef: (el: HTMLElement) => void) => ( - - )} - -
-
{t('Quotes')}
-
- - {(triggerRef: (el: HTMLElement) => void) => ( - - )} - - - {(triggerRef: (el: HTMLElement) => void) => ( - - )} - -
-
{t('squib')}
-
- - {(triggerRef: (el: HTMLElement) => void) => ( - - )} - -
-
-
-
-
- - - - {(triggerRef: (el: HTMLElement) => void) => ( - - )} - - - {(triggerRef: (el: HTMLElement) => void) => ( - - )} - - - - - {(triggerRef: (el: HTMLElement) => void) => ( - - )} - -
- - {t('Add url')}
}> - {(triggerRef: (el: HTMLElement) => void) => ( - - )} - - - <> - - {(triggerRef: (el: HTMLElement) => void) => ( - - )} - -
-
- - -
-
{t('Lists')}
-
- - {(triggerRef: (el: HTMLElement) => void) => ( - - )} - - - {(triggerRef: (el: HTMLElement) => void) => ( - - )} - -
-
-
-
- - - + +
diff --git a/src/components/Views/EditSettingsView.tsx b/src/components/Views/EditSettingsView.tsx index f8b36f43..a611861e 100644 --- a/src/components/Views/EditSettingsView.tsx +++ b/src/components/Views/EditSettingsView.tsx @@ -95,7 +95,7 @@ export const EditSettingsView = (props: Props) => { if (d) { const draftForm = Object.keys(d).length !== 0 ? d : { shoutId: props.shout.id } setForm(draftForm) - console.debug('draft from localstorage: ', draftForm) + console.debug('got draft from localstorage') } }, { defer: true } diff --git a/src/components/Views/EditView.tsx b/src/components/Views/EditView.tsx index 1f0bc29e..a5b66fb9 100644 --- a/src/components/Views/EditView.tsx +++ b/src/components/Views/EditView.tsx @@ -62,7 +62,8 @@ export const EditView = (props: Props) => { setFormErrors, saveDraft, saveDraftToLocalStorage, - getDraftFromLocalStorage + getDraftFromLocalStorage, + isCollabMode } = useEditorContext() const [subtitleInput, setSubtitleInput] = createSignal() @@ -453,6 +454,7 @@ export const EditView = (props: Props) => { shoutId={form.shoutId} initialContent={form.body} onChange={(body: string) => handleInputChange('body', body)} + disableCollaboration={!isCollabMode()} />
diff --git a/src/context/editor.tsx b/src/context/editor.tsx index 08ea789d..2d1de6fb 100644 --- a/src/context/editor.tsx +++ b/src/context/editor.tsx @@ -50,6 +50,8 @@ export type EditorContextType = { setFormErrors: SetStoreFunction> editing: Accessor setEditing: SetStoreFunction + isCollabMode: Accessor + setIsCollabMode: SetStoreFunction } export const EditorContext = createContext({} as EditorContextType) @@ -99,6 +101,7 @@ export const EditorProvider = (props: { children: JSX.Element }) => { words: 0 }) const toggleEditorPanel = () => setIsEditorPanelVisible((value) => !value) + const [isCollabMode, setIsCollabMode] = createSignal(false) const countWords = (value: WordCounter) => setWordCounter(value) const validate = () => { if (!form.title) { @@ -281,7 +284,9 @@ export const EditorProvider = (props: { children: JSX.Element }) => { countWords, setForm, setFormErrors, - setEditing + setEditing, + isCollabMode, + setIsCollabMode } const value: EditorContextType = {