collabmode-onoff
This commit is contained in:
parent
0615476dd9
commit
6bd219a2e4
|
@ -32,7 +32,6 @@ export type EditorComponentProps = {
|
||||||
shoutId: number
|
shoutId: number
|
||||||
initialContent?: string
|
initialContent?: string
|
||||||
onChange: (text: string) => void
|
onChange: (text: string) => void
|
||||||
disableCollaboration?: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const yDocs: Record<string, Doc> = {}
|
const yDocs: Record<string, Doc> = {}
|
||||||
|
@ -45,7 +44,7 @@ export const EditorComponent = (props: EditorComponentProps) => {
|
||||||
const [isCommonMarkup, setIsCommonMarkup] = createSignal(false)
|
const [isCommonMarkup, setIsCommonMarkup] = createSignal(false)
|
||||||
const [shouldShowTextBubbleMenu, setShouldShowTextBubbleMenu] = createSignal(false)
|
const [shouldShowTextBubbleMenu, setShouldShowTextBubbleMenu] = createSignal(false)
|
||||||
const { showSnackbar } = useSnackbar()
|
const { showSnackbar } = useSnackbar()
|
||||||
const { countWords, setEditing } = useEditorContext()
|
const { countWords, setEditing, isCollabMode } = useEditorContext()
|
||||||
const [editorOptions, setEditorOptions] = createSignal<Partial<EditorOptions>>({})
|
const [editorOptions, setEditorOptions] = createSignal<Partial<EditorOptions>>({})
|
||||||
const [editorElRef, setEditorElRef] = createSignal<HTMLElement | undefined>()
|
const [editorElRef, setEditorElRef] = createSignal<HTMLElement | undefined>()
|
||||||
const [textBubbleMenuRef, setTextBubbleMenuRef] = createSignal<HTMLDivElement | undefined>()
|
const [textBubbleMenuRef, setTextBubbleMenuRef] = createSignal<HTMLDivElement | undefined>()
|
||||||
|
@ -154,6 +153,7 @@ export const EditorComponent = (props: EditorComponentProps) => {
|
||||||
}
|
}
|
||||||
console.log(options)
|
console.log(options)
|
||||||
setEditorOptions(() => options)
|
setEditorOptions(() => options)
|
||||||
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
// stage 1: create editor options when got author profile
|
// stage 1: create editor options when got author profile
|
||||||
|
@ -166,19 +166,6 @@ export const EditorComponent = (props: EditorComponentProps) => {
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
// Перенос всех эффектов, зависящих от editor, внутрь onMount
|
|
||||||
onMount(() => {
|
|
||||||
console.log('Editor component mounted')
|
|
||||||
editorElRef()?.addEventListener('focus', handleFocus)
|
|
||||||
requireAuthentication(() => {
|
|
||||||
setTimeout(() => {
|
|
||||||
setupEditor()
|
|
||||||
createEditorInstance(editorOptions())
|
|
||||||
initializeMenus()
|
|
||||||
}, 1200)
|
|
||||||
}, 'edit')
|
|
||||||
})
|
|
||||||
|
|
||||||
const isFigcaptionActive = createEditorTransaction(editor as Accessor<Editor | undefined>, (e) =>
|
const isFigcaptionActive = createEditorTransaction(editor as Accessor<Editor | undefined>, (e) =>
|
||||||
e?.isActive('figcaption')
|
e?.isActive('figcaption')
|
||||||
)
|
)
|
||||||
|
@ -276,38 +263,39 @@ export const EditorComponent = (props: EditorComponentProps) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
setEditorOptions((prev: Partial<EditorOptions>) => {
|
||||||
const docName = `shout-${props.shoutId}`
|
const extensions = [...(prev.extensions || [])]
|
||||||
const token = session()?.access_token || ''
|
|
||||||
const profile = author()
|
|
||||||
|
|
||||||
if (!(token && profile)) {
|
try {
|
||||||
throw new Error('Missing authentication data')
|
if (!isCollabMode()) {
|
||||||
}
|
// Remove collaboration extensions and return
|
||||||
|
|
||||||
if (!yDocs[docName]) {
|
|
||||||
yDocs[docName] = new Doc()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!providers[docName]) {
|
|
||||||
providers[docName] = new HocuspocusProvider({
|
|
||||||
url: 'wss://hocuspocus.discours.io',
|
|
||||||
name: docName,
|
|
||||||
document: yDocs[docName],
|
|
||||||
token
|
|
||||||
})
|
|
||||||
console.log(`HocuspocusProvider установлен для ${docName}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
setEditorOptions((prev: Partial<EditorOptions>) => {
|
|
||||||
const extensions = [...(prev.extensions || [])]
|
|
||||||
if (props.disableCollaboration) {
|
|
||||||
// Remove collaboration extensions if they exist
|
|
||||||
const filteredExtensions = extensions.filter(
|
const filteredExtensions = extensions.filter(
|
||||||
(ext) => ext.name !== 'collaboration' && ext.name !== 'collaborationCursor'
|
(ext) => ext.name !== 'collaboration' && ext.name !== 'collaborationCursor'
|
||||||
)
|
)
|
||||||
return { ...prev, extensions: filteredExtensions }
|
return { ...prev, extensions: filteredExtensions }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const docName = `shout-${props.shoutId}`
|
||||||
|
const token = session()?.access_token || ''
|
||||||
|
const profile = author()
|
||||||
|
|
||||||
|
if (!(token && profile)) {
|
||||||
|
throw new Error('Missing authentication data')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!yDocs[docName]) {
|
||||||
|
yDocs[docName] = new Doc()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!providers[docName]) {
|
||||||
|
providers[docName] = new HocuspocusProvider({
|
||||||
|
url: 'wss://hocuspocus.discours.io',
|
||||||
|
name: docName,
|
||||||
|
document: yDocs[docName],
|
||||||
|
token
|
||||||
|
})
|
||||||
|
console.log(`HocuspocusProvider установлен для ${docName}`)
|
||||||
|
}
|
||||||
extensions.push(
|
extensions.push(
|
||||||
Collaboration.configure({ document: yDocs[docName] }),
|
Collaboration.configure({ document: yDocs[docName] }),
|
||||||
CollaborationCursor.configure({
|
CollaborationCursor.configure({
|
||||||
|
@ -315,13 +303,14 @@ export const EditorComponent = (props: EditorComponentProps) => {
|
||||||
user: { name: profile.name, color: uniqolor(profile.slug).color }
|
user: { name: profile.name, color: uniqolor(profile.slug).color }
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
console.log('collab extensions added:', extensions)
|
|
||||||
return { ...prev, extensions }
|
} catch (error) {
|
||||||
})
|
console.error('Error initializing collaboration:', error)
|
||||||
} catch (error) {
|
showSnackbar({ body: t('Failed to initialize collaboration') })
|
||||||
console.error('Error initializing collaboration:', error)
|
}
|
||||||
showSnackbar({ body: t('Failed to initialize collaboration') })
|
console.log('collab extensions added:', extensions)
|
||||||
}
|
return { ...prev, extensions }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleFocus = (event: FocusEvent) => {
|
const handleFocus = (event: FocusEvent) => {
|
||||||
|
@ -332,13 +321,23 @@ export const EditorComponent = (props: EditorComponentProps) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Инициализируем коллаборацию если необходимо
|
onMount(() => {
|
||||||
|
console.log('Editor component mounted')
|
||||||
|
editorElRef()?.addEventListener('focus', handleFocus)
|
||||||
|
requireAuthentication(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const opts = setupEditor()
|
||||||
|
createEditorInstance(opts)
|
||||||
|
initializeMenus()
|
||||||
|
}, 120)
|
||||||
|
}, 'edit')
|
||||||
|
})
|
||||||
|
|
||||||
|
// collab mode on/off
|
||||||
createEffect(
|
createEffect(
|
||||||
on(
|
on(
|
||||||
() => props.disableCollaboration,
|
isCollabMode,
|
||||||
() => {
|
(x) => !x && initializeCollaboration(),
|
||||||
initializeCollaboration()
|
|
||||||
},
|
|
||||||
{ defer: true }
|
{ defer: true }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { useLocalize } from '~/context/localize'
|
||||||
import { useUI } from '~/context/ui'
|
import { useUI } from '~/context/ui'
|
||||||
import { useEscKeyDownHandler } from '~/lib/useEscKeyDownHandler'
|
import { useEscKeyDownHandler } from '~/lib/useEscKeyDownHandler'
|
||||||
import { useOutsideClickHandler } from '~/lib/useOutsideClickHandler'
|
import { useOutsideClickHandler } from '~/lib/useOutsideClickHandler'
|
||||||
|
|
||||||
import styles from './Panel.module.scss'
|
import styles from './Panel.module.scss'
|
||||||
|
|
||||||
const typograf = new Typograf({ locale: ['ru', 'en-US'] })
|
const typograf = new Typograf({ locale: ['ru', 'en-US'] })
|
||||||
|
@ -23,6 +24,7 @@ export const Panel = (props: Props) => {
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
const { showModal } = useUI()
|
const { showModal } = useUI()
|
||||||
const {
|
const {
|
||||||
|
setIsCollabMode,
|
||||||
isEditorPanelVisible,
|
isEditorPanelVisible,
|
||||||
wordCounter,
|
wordCounter,
|
||||||
form,
|
form,
|
||||||
|
@ -32,13 +34,12 @@ export const Panel = (props: Props) => {
|
||||||
publishShout,
|
publishShout,
|
||||||
editing: editor
|
editing: editor
|
||||||
} = useEditorContext()
|
} = useEditorContext()
|
||||||
|
const [containerRef, setAsideContainerRef] = createSignal<HTMLElement | undefined>()
|
||||||
let containerRef: HTMLElement | undefined
|
|
||||||
const [isShortcutsVisible, setIsShortcutsVisible] = createSignal(false)
|
const [isShortcutsVisible, setIsShortcutsVisible] = createSignal(false)
|
||||||
const [isTypographyFixed, setIsTypographyFixed] = createSignal(false)
|
const [isTypographyFixed, setIsTypographyFixed] = createSignal(false)
|
||||||
|
|
||||||
useOutsideClickHandler({
|
useOutsideClickHandler({
|
||||||
containerRef,
|
containerRef: containerRef(),
|
||||||
predicate: () => isEditorPanelVisible(),
|
predicate: () => isEditorPanelVisible(),
|
||||||
handler: () => toggleEditorPanel()
|
handler: () => toggleEditorPanel()
|
||||||
})
|
})
|
||||||
|
@ -67,7 +68,7 @@ export const Panel = (props: Props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside
|
<aside
|
||||||
ref={(el) => (containerRef = el)}
|
ref={setAsideContainerRef}
|
||||||
class={clsx('col-md-6', styles.Panel, { [styles.hidden]: !isEditorPanelVisible() })}
|
class={clsx('col-md-6', styles.Panel, { [styles.hidden]: !isEditorPanelVisible() })}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
|
@ -96,6 +97,13 @@ export const Panel = (props: Props) => {
|
||||||
{t('Invite co-authors')}
|
{t('Invite co-authors')}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
|
{/* TODO: <Show when={coauthorsCount() > 0}> */}
|
||||||
|
<p>
|
||||||
|
<span class={styles.link} onClick={() => setIsCollabMode((x) => !x)}>
|
||||||
|
{t('Collaborative mode')}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
{/*</Show> */}
|
||||||
<p>
|
<p>
|
||||||
<A
|
<A
|
||||||
class={styles.link}
|
class={styles.link}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { ToolbarControl } from './ToolbarControl'
|
||||||
|
|
||||||
import { Popover } from '~/components/_shared/Popover/Popover'
|
import { Popover } from '~/components/_shared/Popover/Popover'
|
||||||
import styles from './FullBubbleMenu.module.scss'
|
import styles from './FullBubbleMenu.module.scss'
|
||||||
|
import { useEditorContext } from '~/context/editor'
|
||||||
|
|
||||||
type FullBubbleMenuProps = {
|
type FullBubbleMenuProps = {
|
||||||
editor: () => Editor | undefined
|
editor: () => Editor | undefined
|
||||||
|
@ -20,6 +21,7 @@ type FullBubbleMenuProps = {
|
||||||
|
|
||||||
export const FullBubbleMenu = (props: FullBubbleMenuProps) => {
|
export const FullBubbleMenu = (props: FullBubbleMenuProps) => {
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
|
const { isCollabMode, setIsCollabMode } = useEditorContext()
|
||||||
|
|
||||||
// SIGNALS
|
// SIGNALS
|
||||||
const [textSizeBubbleOpen, setTextSizeBubbleOpen] = createSignal(false)
|
const [textSizeBubbleOpen, setTextSizeBubbleOpen] = createSignal(false)
|
||||||
|
@ -259,6 +261,18 @@ export const FullBubbleMenu = (props: FullBubbleMenuProps) => {
|
||||||
<div style={{ width: '5px' }} />
|
<div style={{ width: '5px' }} />
|
||||||
|
|
||||||
<ListDropdown />
|
<ListDropdown />
|
||||||
|
|
||||||
|
<div class={styles.dropDownHolder}>
|
||||||
|
<Popover content={t('Collaborative mode')}>
|
||||||
|
{(triggerRef: (el: HTMLButtonElement) => void) => (
|
||||||
|
<button ref={triggerRef} type="button" class={styles.actionButton}
|
||||||
|
onClick={() => setIsCollabMode(x => !x)}
|
||||||
|
>
|
||||||
|
<Icon name={`comment${isCollabMode() ? '-hover' : ''}`} />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user