clued
This commit is contained in:
parent
0061b68257
commit
751157b421
|
@ -6,11 +6,11 @@ import { useLocalize } from '~/context/localize'
|
||||||
import { useReactions } from '~/context/reactions'
|
import { useReactions } from '~/context/reactions'
|
||||||
import { useSession } from '~/context/session'
|
import { useSession } from '~/context/session'
|
||||||
import {
|
import {
|
||||||
Author,
|
|
||||||
QueryLoad_Reactions_ByArgs,
|
QueryLoad_Reactions_ByArgs,
|
||||||
Reaction,
|
Reaction,
|
||||||
ReactionKind,
|
ReactionKind,
|
||||||
ReactionSort
|
ReactionSort,
|
||||||
|
Shout
|
||||||
} from '~/graphql/schema/core.gen'
|
} from '~/graphql/schema/core.gen'
|
||||||
import { byCreated, byStat } from '~/lib/sort'
|
import { byCreated, byStat } from '~/lib/sort'
|
||||||
import { SortFunction } from '~/types/common'
|
import { SortFunction } from '~/types/common'
|
||||||
|
@ -24,22 +24,22 @@ import { Comment } from './Comment'
|
||||||
const SimplifiedEditor = lazy(() => import('../Editor/SimplifiedEditor'))
|
const SimplifiedEditor = lazy(() => import('../Editor/SimplifiedEditor'))
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
articleAuthors: Author[]
|
shout: Shout
|
||||||
shoutSlug: string
|
|
||||||
shoutId: number
|
|
||||||
}
|
}
|
||||||
const COMMENTS_PER_PAGE = 50
|
const COMMENTS_PER_PAGE = 50
|
||||||
|
|
||||||
export const CommentsTree = (props: Props) => {
|
export const CommentsTree = (props: Props) => {
|
||||||
const { session } = useSession()
|
const { session } = useSession()
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
|
const { reactionEntities, createReaction, loadReactionsBy, addReactions } = useReactions()
|
||||||
|
const { seen } = useFeed()
|
||||||
const [commentsOrder, setCommentsOrder] = createSignal<ReactionSort>(ReactionSort.Newest)
|
const [commentsOrder, setCommentsOrder] = createSignal<ReactionSort>(ReactionSort.Newest)
|
||||||
const [onlyNew, setOnlyNew] = createSignal(false)
|
const [onlyNew, setOnlyNew] = createSignal(false)
|
||||||
const [newReactions, setNewReactions] = createSignal<Reaction[]>([])
|
const [newReactions, setNewReactions] = createSignal<Reaction[]>([])
|
||||||
const [clearEditor, setClearEditor] = createSignal(false)
|
const [clearEditor, setClearEditor] = createSignal(false)
|
||||||
const [clickedReplyId, setClickedReplyId] = createSignal<number>()
|
const [clickedReplyId, setClickedReplyId] = createSignal<number>()
|
||||||
const { reactionEntities, createReaction, loadReactionsBy, addReactions } = useReactions()
|
|
||||||
|
|
||||||
|
const shoutLastSeen = createMemo(() => seen()[props.shout.slug] ?? 0)
|
||||||
const comments = createMemo(() =>
|
const comments = createMemo(() =>
|
||||||
Object.values(reactionEntities).filter((reaction) => reaction.kind === 'COMMENT')
|
Object.values(reactionEntities).filter((reaction) => reaction.kind === 'COMMENT')
|
||||||
)
|
)
|
||||||
|
@ -57,12 +57,9 @@ export const CommentsTree = (props: Props) => {
|
||||||
}
|
}
|
||||||
return newSortedComments
|
return newSortedComments
|
||||||
})
|
})
|
||||||
const { seen } = useFeed()
|
|
||||||
const shoutLastSeen = createMemo(() => seen()[props.shoutSlug] ?? 0)
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const currentDate = new Date()
|
const currentDate = new Date()
|
||||||
const setCookie = () => localStorage?.setItem(`${props.shoutSlug}`, `${currentDate}`)
|
const setCookie = () => localStorage?.setItem(`${props.shout.slug}`, `${currentDate}`)
|
||||||
if (!shoutLastSeen()) {
|
if (!shoutLastSeen()) {
|
||||||
setCookie()
|
setCookie()
|
||||||
} else if (currentDate.getTime() > shoutLastSeen()) {
|
} else if (currentDate.getTime() > shoutLastSeen()) {
|
||||||
|
@ -80,24 +77,6 @@ export const CommentsTree = (props: Props) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const [posting, setPosting] = createSignal(false)
|
const [posting, setPosting] = createSignal(false)
|
||||||
const handleSubmitComment = async (value: string) => {
|
|
||||||
setPosting(true)
|
|
||||||
try {
|
|
||||||
await createReaction({
|
|
||||||
reaction: {
|
|
||||||
kind: ReactionKind.Comment,
|
|
||||||
body: value,
|
|
||||||
shout: props.shoutId
|
|
||||||
}
|
|
||||||
})
|
|
||||||
setClearEditor(true)
|
|
||||||
await loadReactionsBy({ by: { shout: props.shoutSlug } })
|
|
||||||
} catch (error) {
|
|
||||||
console.error('[handleCreate reaction]:', error)
|
|
||||||
}
|
|
||||||
setClearEditor(false)
|
|
||||||
setPosting(false)
|
|
||||||
}
|
|
||||||
const [commentsLoading, setCommentsLoading] = createSignal(false)
|
const [commentsLoading, setCommentsLoading] = createSignal(false)
|
||||||
const [pagination, setPagination] = createSignal(0)
|
const [pagination, setPagination] = createSignal(0)
|
||||||
const loadMoreComments = async () => {
|
const loadMoreComments = async () => {
|
||||||
|
@ -105,7 +84,7 @@ export const CommentsTree = (props: Props) => {
|
||||||
const next = pagination() + 1
|
const next = pagination() + 1
|
||||||
const offset = next * COMMENTS_PER_PAGE
|
const offset = next * COMMENTS_PER_PAGE
|
||||||
const opts: QueryLoad_Reactions_ByArgs = {
|
const opts: QueryLoad_Reactions_ByArgs = {
|
||||||
by: { comment: true, shout: props.shoutSlug },
|
by: { comment: true, shout: props.shout.slug },
|
||||||
limit: COMMENTS_PER_PAGE,
|
limit: COMMENTS_PER_PAGE,
|
||||||
offset
|
offset
|
||||||
}
|
}
|
||||||
|
@ -116,6 +95,24 @@ export const CommentsTree = (props: Props) => {
|
||||||
return rrr as LoadMoreItems
|
return rrr as LoadMoreItems
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleSubmitComment = async (value: string) => {
|
||||||
|
setPosting(true)
|
||||||
|
try {
|
||||||
|
await createReaction({
|
||||||
|
reaction: {
|
||||||
|
kind: ReactionKind.Comment,
|
||||||
|
body: value,
|
||||||
|
shout: props.shout.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setClearEditor(true)
|
||||||
|
await loadMoreComments()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[handleCreate reaction]:', error)
|
||||||
|
}
|
||||||
|
setClearEditor(false)
|
||||||
|
setPosting(false)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div class={styles.commentsHeaderWrapper}>
|
<div class={styles.commentsHeaderWrapper}>
|
||||||
|
@ -159,16 +156,14 @@ export const CommentsTree = (props: Props) => {
|
||||||
<LoadMoreWrapper
|
<LoadMoreWrapper
|
||||||
loadFunction={loadMoreComments}
|
loadFunction={loadMoreComments}
|
||||||
pageSize={COMMENTS_PER_PAGE}
|
pageSize={COMMENTS_PER_PAGE}
|
||||||
hidden={commentsLoading()}
|
hidden={commentsLoading() || comments().length >= (props.shout?.stat?.commented || 0)}
|
||||||
>
|
>
|
||||||
<ul class={styles.comments}>
|
<ul class={styles.comments}>
|
||||||
<For each={sortedComments().filter((r) => !r.reply_to)}>
|
<For each={sortedComments().filter((r) => !r.reply_to)}>
|
||||||
{(reaction) => (
|
{(reaction) => (
|
||||||
<Comment
|
<Comment
|
||||||
sortedComments={sortedComments()}
|
sortedComments={sortedComments()}
|
||||||
isArticleAuthor={Boolean(
|
isArticleAuthor={props.shout.authors?.some((a) => a && reaction.created_by.id === a.id)}
|
||||||
props.articleAuthors.some((a) => a?.id === reaction.created_by.id)
|
|
||||||
)}
|
|
||||||
comment={reaction}
|
comment={reaction}
|
||||||
clickedReply={(id) => setClickedReplyId(id)}
|
clickedReply={(id) => setClickedReplyId(id)}
|
||||||
clickedReplyId={clickedReplyId()}
|
clickedReplyId={clickedReplyId()}
|
||||||
|
|
|
@ -560,11 +560,7 @@ export const FullArticle = (props: Props) => {
|
||||||
</For>
|
</For>
|
||||||
</div>
|
</div>
|
||||||
<div id="comments" ref={(el) => (commentsRef = el)}>
|
<div id="comments" ref={(el) => (commentsRef = el)}>
|
||||||
<CommentsTree
|
<CommentsTree shout={props.article} />
|
||||||
shoutId={props.article.id}
|
|
||||||
shoutSlug={props.article.slug}
|
|
||||||
articleAuthors={props.article.authors as Author[]}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -162,7 +162,7 @@ export const AuthorCard = (props: Props) => {
|
||||||
<For each={authorSubs()}>
|
<For each={authorSubs()}>
|
||||||
{(subscription) =>
|
{(subscription) =>
|
||||||
'name' in subscription ? (
|
'name' in subscription ? (
|
||||||
<AuthorBadge author={subscription as Author} subscriptionsMode={true} />
|
<AuthorBadge author={subscription as Author} nameOnly={true} />
|
||||||
) : (
|
) : (
|
||||||
<TopicBadge topic={subscription as Topic} subscriptionsMode={true} />
|
<TopicBadge topic={subscription as Topic} subscriptionsMode={true} />
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { Editor } from '@tiptap/core'
|
||||||
import { Blockquote } from '@tiptap/extension-blockquote'
|
import { Blockquote } from '@tiptap/extension-blockquote'
|
||||||
import { Bold } from '@tiptap/extension-bold'
|
import { Bold } from '@tiptap/extension-bold'
|
||||||
import { BubbleMenu } from '@tiptap/extension-bubble-menu'
|
import { BubbleMenu } from '@tiptap/extension-bubble-menu'
|
||||||
|
@ -10,7 +11,7 @@ import { Paragraph } from '@tiptap/extension-paragraph'
|
||||||
import { Placeholder } from '@tiptap/extension-placeholder'
|
import { Placeholder } from '@tiptap/extension-placeholder'
|
||||||
import { Text } from '@tiptap/extension-text'
|
import { Text } from '@tiptap/extension-text'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { Show, createEffect, createMemo, createSignal, on, onCleanup, onMount } from 'solid-js'
|
import { Show, createEffect, createMemo, createSignal, onCleanup, onMount } from 'solid-js'
|
||||||
import { Portal } from 'solid-js/web'
|
import { Portal } from 'solid-js/web'
|
||||||
import {
|
import {
|
||||||
createEditorTransaction,
|
createEditorTransaction,
|
||||||
|
@ -19,26 +20,23 @@ import {
|
||||||
useEditorIsEmpty,
|
useEditorIsEmpty,
|
||||||
useEditorIsFocused
|
useEditorIsFocused
|
||||||
} from 'solid-tiptap'
|
} from 'solid-tiptap'
|
||||||
|
import { Modal } from '~/components/_shared/Modal'
|
||||||
import { useEditorContext } from '~/context/editor'
|
import { useUI } from '~/context/ui'
|
||||||
import { useLocalize } from '~/context/localize'
|
|
||||||
import { UploadedFile } from '~/types/upload'
|
import { UploadedFile } from '~/types/upload'
|
||||||
|
import { useEditorContext } from '../../context/editor'
|
||||||
|
import { useLocalize } from '../../context/localize'
|
||||||
import { Button } from '../_shared/Button'
|
import { Button } from '../_shared/Button'
|
||||||
import { Icon } from '../_shared/Icon'
|
import { Icon } from '../_shared/Icon'
|
||||||
import { Loading } from '../_shared/Loading'
|
import { Loading } from '../_shared/Loading'
|
||||||
import { Modal } from '../_shared/Modal'
|
|
||||||
import { Popover } from '../_shared/Popover'
|
import { Popover } from '../_shared/Popover'
|
||||||
import { ShowOnlyOnClient } from '../_shared/ShowOnlyOnClient'
|
import { ShowOnlyOnClient } from '../_shared/ShowOnlyOnClient'
|
||||||
import { LinkBubbleMenuModule } from './LinkBubbleMenu'
|
import { LinkBubbleMenuModule } from './LinkBubbleMenu'
|
||||||
|
import styles from './SimplifiedEditor.module.scss'
|
||||||
import { TextBubbleMenu } from './TextBubbleMenu'
|
import { TextBubbleMenu } from './TextBubbleMenu'
|
||||||
import { UploadModalContent } from './UploadModalContent'
|
import { UploadModalContent } from './UploadModalContent'
|
||||||
import { Figcaption } from './extensions/Figcaption'
|
import { Figcaption } from './extensions/Figcaption'
|
||||||
import { Figure } from './extensions/Figure'
|
import { Figure } from './extensions/Figure'
|
||||||
|
|
||||||
import { Editor } from '@tiptap/core'
|
|
||||||
import { useUI } from '~/context/ui'
|
|
||||||
import styles from './SimplifiedEditor.module.scss'
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
placeholder: string
|
placeholder: string
|
||||||
initialContent?: string
|
initialContent?: string
|
||||||
|
@ -67,98 +65,87 @@ type Props = {
|
||||||
const DEFAULT_MAX_LENGTH = 400
|
const DEFAULT_MAX_LENGTH = 400
|
||||||
|
|
||||||
const SimplifiedEditor = (props: Props) => {
|
const SimplifiedEditor = (props: Props) => {
|
||||||
const { t } = useLocalize()
|
const maxLength = props.maxLength ?? DEFAULT_MAX_LENGTH
|
||||||
|
let wrapperEditorElRef: HTMLElement | undefined
|
||||||
|
let editorElRef: HTMLElement | undefined
|
||||||
|
let textBubbleMenuRef: HTMLDivElement | undefined
|
||||||
|
let linkBubbleMenuRef: HTMLDivElement | undefined
|
||||||
const { showModal, hideModal } = useUI()
|
const { showModal, hideModal } = useUI()
|
||||||
|
const { t } = useLocalize()
|
||||||
const [counter, setCounter] = createSignal<number>(0)
|
const [counter, setCounter] = createSignal<number>(0)
|
||||||
const [shouldShowLinkBubbleMenu, setShouldShowLinkBubbleMenu] = createSignal(false)
|
const [shouldShowLinkBubbleMenu, setShouldShowLinkBubbleMenu] = createSignal(false)
|
||||||
const isCancelButtonVisible = createMemo(() => props.isCancelButtonVisible !== false)
|
const isCancelButtonVisible = createMemo(() => props.isCancelButtonVisible !== false)
|
||||||
const [editorElement, setEditorElement] = createSignal<HTMLDivElement>()
|
const { setEditor, editor } = useEditorContext()
|
||||||
const { editor, setEditor } = useEditorContext()
|
|
||||||
|
|
||||||
const maxLength = props.maxLength ?? DEFAULT_MAX_LENGTH
|
|
||||||
let wrapperEditorElRef: HTMLElement | undefined
|
|
||||||
let textBubbleMenuRef: HTMLDivElement | undefined
|
|
||||||
let linkBubbleMenuRef: HTMLDivElement | undefined
|
|
||||||
|
|
||||||
const ImageFigure = Figure.extend({
|
const ImageFigure = Figure.extend({
|
||||||
name: 'capturedImage',
|
name: 'capturedImage',
|
||||||
content: 'figcaption image'
|
content: 'figcaption image'
|
||||||
})
|
})
|
||||||
|
createEffect(() => {
|
||||||
createEffect(
|
const e = createTiptapEditor(() => ({
|
||||||
on(
|
element: editorElRef as HTMLElement,
|
||||||
() => editorElement(),
|
editorProps: {
|
||||||
(ee: HTMLDivElement | undefined) => {
|
attributes: {
|
||||||
if (ee && textBubbleMenuRef && linkBubbleMenuRef) {
|
class: styles.simplifiedEditorField
|
||||||
const freshEditor = createTiptapEditor<HTMLElement>(() => ({
|
|
||||||
element: ee,
|
|
||||||
editorProps: {
|
|
||||||
attributes: {
|
|
||||||
class: styles.simplifiedEditorField
|
|
||||||
}
|
|
||||||
},
|
|
||||||
extensions: [
|
|
||||||
Document,
|
|
||||||
Text,
|
|
||||||
Paragraph,
|
|
||||||
Bold,
|
|
||||||
Italic,
|
|
||||||
Link.extend({
|
|
||||||
inclusive: false
|
|
||||||
}).configure({
|
|
||||||
autolink: true,
|
|
||||||
openOnClick: false
|
|
||||||
}),
|
|
||||||
CharacterCount.configure({
|
|
||||||
limit: props.noLimits ? null : maxLength
|
|
||||||
}),
|
|
||||||
Blockquote.configure({
|
|
||||||
HTMLAttributes: {
|
|
||||||
class: styles.blockQuote
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
BubbleMenu.configure({
|
|
||||||
pluginKey: 'textBubbleMenu',
|
|
||||||
element: textBubbleMenuRef,
|
|
||||||
shouldShow: ({ view, state }) => {
|
|
||||||
if (!props.onlyBubbleControls) return false
|
|
||||||
const { selection } = state
|
|
||||||
const { empty } = selection
|
|
||||||
return view.hasFocus() && !empty
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
BubbleMenu.configure({
|
|
||||||
pluginKey: 'linkBubbleMenu',
|
|
||||||
element: linkBubbleMenuRef,
|
|
||||||
shouldShow: ({ state }) => {
|
|
||||||
const { selection } = state
|
|
||||||
const { empty } = selection
|
|
||||||
return !empty && shouldShowLinkBubbleMenu()
|
|
||||||
},
|
|
||||||
tippyOptions: {
|
|
||||||
placement: 'bottom'
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
ImageFigure,
|
|
||||||
Image,
|
|
||||||
Figcaption,
|
|
||||||
Placeholder.configure({
|
|
||||||
emptyNodeClass: styles.emptyNode,
|
|
||||||
placeholder: props.placeholder
|
|
||||||
})
|
|
||||||
],
|
|
||||||
autofocus: props.autoFocus,
|
|
||||||
content: props.initialContent || null
|
|
||||||
}))
|
|
||||||
const editorInstance = freshEditor()
|
|
||||||
if (!editorInstance) return
|
|
||||||
setEditor(editorInstance)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ defer: true }
|
extensions: [
|
||||||
)
|
Document,
|
||||||
)
|
Text,
|
||||||
|
Paragraph,
|
||||||
|
Bold,
|
||||||
|
Italic,
|
||||||
|
Link.extend({
|
||||||
|
inclusive: false
|
||||||
|
}).configure({
|
||||||
|
autolink: true,
|
||||||
|
openOnClick: false
|
||||||
|
}),
|
||||||
|
CharacterCount.configure({
|
||||||
|
limit: props.noLimits ? null : maxLength
|
||||||
|
}),
|
||||||
|
Blockquote.configure({
|
||||||
|
HTMLAttributes: {
|
||||||
|
class: styles.blockQuote
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
BubbleMenu.configure({
|
||||||
|
pluginKey: 'textBubbleMenu',
|
||||||
|
element: textBubbleMenuRef,
|
||||||
|
shouldShow: ({ view, state }) => {
|
||||||
|
if (!props.onlyBubbleControls) return false
|
||||||
|
const { selection } = state
|
||||||
|
const { empty } = selection
|
||||||
|
return view.hasFocus() && !empty
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
BubbleMenu.configure({
|
||||||
|
pluginKey: 'linkBubbleMenu',
|
||||||
|
element: linkBubbleMenuRef,
|
||||||
|
shouldShow: ({ state }) => {
|
||||||
|
const { selection } = state
|
||||||
|
const { empty } = selection
|
||||||
|
return !empty && shouldShowLinkBubbleMenu()
|
||||||
|
},
|
||||||
|
tippyOptions: {
|
||||||
|
placement: 'bottom'
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
ImageFigure,
|
||||||
|
Image,
|
||||||
|
Figcaption,
|
||||||
|
Placeholder.configure({
|
||||||
|
emptyNodeClass: styles.emptyNode,
|
||||||
|
placeholder: props.placeholder
|
||||||
|
})
|
||||||
|
],
|
||||||
|
autofocus: props.autoFocus,
|
||||||
|
content: content ?? null
|
||||||
|
}))
|
||||||
|
|
||||||
|
e() && setEditor(e() as Editor)
|
||||||
|
})
|
||||||
|
const content = props.initialContent
|
||||||
const isEmpty = useEditorIsEmpty(() => editor())
|
const isEmpty = useEditorIsEmpty(() => editor())
|
||||||
const isFocused = useEditorIsFocused(() => editor())
|
const isFocused = useEditorIsFocused(() => editor())
|
||||||
|
|
||||||
|
@ -211,7 +198,7 @@ const SimplifiedEditor = (props: Props) => {
|
||||||
}
|
}
|
||||||
if (props.resetToInitial) {
|
if (props.resetToInitial) {
|
||||||
editor()?.commands.clearContent(true)
|
editor()?.commands.clearContent(true)
|
||||||
if (props.initialContent) editor()?.commands.setContent(props.initialContent)
|
props.initialContent && editor()?.commands.setContent(props.initialContent)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -290,7 +277,11 @@ const SimplifiedEditor = (props: Props) => {
|
||||||
<Show when={props.label && counter() > 0}>
|
<Show when={props.label && counter() > 0}>
|
||||||
<div class={styles.label}>{props.label}</div>
|
<div class={styles.label}>{props.label}</div>
|
||||||
</Show>
|
</Show>
|
||||||
<div style={props.maxHeight ? maxHeightStyle : undefined} ref={setEditorElement} />
|
|
||||||
|
<Show when={props.maxHeight} fallback={<div ref={(el) => (editorElRef = el)} />}>
|
||||||
|
<div style={maxHeightStyle} ref={(el) => (editorElRef = el)} />
|
||||||
|
</Show>
|
||||||
|
|
||||||
<Show when={!props.onlyBubbleControls}>
|
<Show when={!props.onlyBubbleControls}>
|
||||||
<div class={clsx(styles.controls, { [styles.alwaysVisible]: props.controlsAlwaysVisible })}>
|
<div class={clsx(styles.controls, { [styles.alwaysVisible]: props.controlsAlwaysVisible })}>
|
||||||
<div class={styles.actions}>
|
<div class={styles.actions}>
|
||||||
|
@ -379,27 +370,25 @@ const SimplifiedEditor = (props: Props) => {
|
||||||
<Show when={props.imageEnabled}>
|
<Show when={props.imageEnabled}>
|
||||||
<Portal>
|
<Portal>
|
||||||
<Modal variant="narrow" name="simplifiedEditorUploadImage">
|
<Modal variant="narrow" name="simplifiedEditorUploadImage">
|
||||||
<UploadModalContent
|
<UploadModalContent onClose={(value) => value && renderImage(value)} />
|
||||||
onClose={(value) => {
|
|
||||||
renderImage(value as UploadedFile)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Modal>
|
</Modal>
|
||||||
</Portal>
|
</Portal>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={props.onlyBubbleControls}>
|
<Show when={!!editor()}>
|
||||||
<TextBubbleMenu
|
<Show when={props.onlyBubbleControls}>
|
||||||
shouldShow={true}
|
<TextBubbleMenu
|
||||||
isCommonMarkup={true}
|
shouldShow={true}
|
||||||
|
isCommonMarkup={true}
|
||||||
|
editor={editor() as Editor}
|
||||||
|
ref={(el) => (textBubbleMenuRef = el)}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
<LinkBubbleMenuModule
|
||||||
editor={editor() as Editor}
|
editor={editor() as Editor}
|
||||||
ref={(el) => (textBubbleMenuRef = el)}
|
ref={(el) => (linkBubbleMenuRef = el)}
|
||||||
|
onClose={handleHideLinkBubble}
|
||||||
/>
|
/>
|
||||||
</Show>
|
</Show>
|
||||||
<LinkBubbleMenuModule
|
|
||||||
editor={editor() as Editor}
|
|
||||||
ref={(el) => (linkBubbleMenuRef = el)}
|
|
||||||
onClose={handleHideLinkBubble}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</ShowOnlyOnClient>
|
</ShowOnlyOnClient>
|
||||||
)
|
)
|
||||||
|
|
|
@ -753,7 +753,12 @@
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rightItem {
|
||||||
|
margin-right: 0;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a:link,
|
a:link,
|
||||||
|
@ -796,6 +801,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rightItemIcon {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 0.3em;
|
||||||
|
position: relative;
|
||||||
|
top: 0.15em;
|
||||||
|
}
|
||||||
|
|
||||||
.editorPopup {
|
.editorPopup {
|
||||||
border: 1px solid rgb(0 0 0 / 15%) !important;
|
border: 1px solid rgb(0 0 0 / 15%) !important;
|
||||||
border-radius: 1.6rem;
|
border-radius: 1.6rem;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user