Editor improvements (#735)
* Allow focus on all parts of editor * Fix background and text colors * Restrict height of image in comment * Remove "Type *markdown*" placeholder it's a little misleading (can't do markdown links) and messes with focus to be replaced with a highlight menu in the future
This commit is contained in:
parent
c07daafb8d
commit
0b9ca6b7ee
|
@ -65,7 +65,7 @@ function ProfileComment(props: { comment: Comment; className?: string }) {
|
|||
/>{' '}
|
||||
<RelativeTimestamp time={createdTime} />
|
||||
</p>
|
||||
<Content content={content || text} />
|
||||
<Content content={content || text} smallImage />
|
||||
</div>
|
||||
</Row>
|
||||
)
|
||||
|
|
|
@ -3,7 +3,6 @@ import Placeholder from '@tiptap/extension-placeholder'
|
|||
import {
|
||||
useEditor,
|
||||
EditorContent,
|
||||
FloatingMenu,
|
||||
JSONContent,
|
||||
Content,
|
||||
Editor,
|
||||
|
@ -11,13 +10,11 @@ import {
|
|||
import StarterKit from '@tiptap/starter-kit'
|
||||
import { Image } from '@tiptap/extension-image'
|
||||
import { Link } from '@tiptap/extension-link'
|
||||
import { Mention } from '@tiptap/extension-mention'
|
||||
import clsx from 'clsx'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Linkify } from './linkify'
|
||||
import { uploadImage } from 'web/lib/firebase/storage'
|
||||
import { useMutation } from 'react-query'
|
||||
import { exhibitExts } from 'common/util/parse'
|
||||
import { FileUploadButton } from './file-upload-button'
|
||||
import { linkClass } from './site-link'
|
||||
import { useUsers } from 'web/hooks/use-users'
|
||||
|
@ -31,6 +28,18 @@ import { Button } from './button'
|
|||
import { Row } from './layout/row'
|
||||
import { Spacer } from './layout/spacer'
|
||||
|
||||
const DisplayImage = Image.configure({
|
||||
HTMLAttributes: {
|
||||
class: 'max-h-60',
|
||||
},
|
||||
})
|
||||
|
||||
const DisplayLink = Link.configure({
|
||||
HTMLAttributes: {
|
||||
class: clsx('no-underline !text-indigo-700', linkClass),
|
||||
},
|
||||
})
|
||||
|
||||
const proseClass = clsx(
|
||||
'prose prose-p:my-0 prose-ul:my-0 prose-ol:my-0 prose-li:my-0 prose-blockquote:not-italic max-w-none prose-quoteless leading-relaxed',
|
||||
'font-light prose-a:font-light prose-blockquote:font-light'
|
||||
|
@ -64,15 +73,11 @@ export function useTextEditor(props: {
|
|||
Placeholder.configure({
|
||||
placeholder,
|
||||
emptyEditorClass:
|
||||
'before:content-[attr(data-placeholder)] before:text-slate-500 before:float-left before:h-0',
|
||||
'before:content-[attr(data-placeholder)] before:text-slate-500 before:float-left before:h-0 cursor-text',
|
||||
}),
|
||||
CharacterCount.configure({ limit: max }),
|
||||
Image,
|
||||
Link.configure({
|
||||
HTMLAttributes: {
|
||||
class: clsx('no-underline !text-indigo-700', linkClass),
|
||||
},
|
||||
}),
|
||||
simple ? DisplayImage : Image,
|
||||
DisplayLink,
|
||||
DisplayMention.configure({
|
||||
suggestion: mentionSuggestion(users),
|
||||
}),
|
||||
|
@ -132,15 +137,7 @@ export function TextEditor(props: {
|
|||
<>
|
||||
{/* hide placeholder when focused */}
|
||||
<div className="relative w-full [&:focus-within_p.is-empty]:before:content-none">
|
||||
{editor && (
|
||||
<FloatingMenu
|
||||
editor={editor}
|
||||
className={clsx(proseClass, '-ml-2 mr-2 w-full text-slate-300 ')}
|
||||
>
|
||||
Type <em>*markdown*</em>
|
||||
</FloatingMenu>
|
||||
)}
|
||||
<div className="rounded-lg border border-gray-300 shadow-sm focus-within:border-indigo-500 focus-within:ring-1 focus-within:ring-indigo-500">
|
||||
<div className="rounded-lg border border-gray-300 bg-white shadow-sm focus-within:border-indigo-500 focus-within:ring-1 focus-within:ring-indigo-500">
|
||||
<EditorContent editor={editor} />
|
||||
{/* Toolbar, with buttons for images and embeds */}
|
||||
<div className="flex h-9 items-center gap-5 pl-4 pr-1">
|
||||
|
@ -168,7 +165,14 @@ export function TextEditor(props: {
|
|||
<span className="sr-only">Embed an iframe</span>
|
||||
</button>
|
||||
</div>
|
||||
<div className="ml-auto" />
|
||||
{/* Spacer that also focuses editor on click */}
|
||||
<div
|
||||
className="grow cursor-text self-stretch"
|
||||
onMouseDown={() =>
|
||||
editor?.chain().focus('end').createParagraphNear().run()
|
||||
}
|
||||
aria-hidden
|
||||
/>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -258,14 +262,19 @@ const useUploadMutation = (editor: Editor | null) =>
|
|||
}
|
||||
)
|
||||
|
||||
function RichContent(props: { content: JSONContent | string }) {
|
||||
const { content } = props
|
||||
function RichContent(props: {
|
||||
content: JSONContent | string
|
||||
smallImage?: boolean
|
||||
}) {
|
||||
const { content, smallImage } = props
|
||||
const editor = useEditor({
|
||||
editorProps: { attributes: { class: proseClass } },
|
||||
extensions: [
|
||||
// replace tiptap's Mention with ours, to add style and link
|
||||
...exhibitExts.filter((ex) => ex.name !== Mention.name),
|
||||
StarterKit,
|
||||
smallImage ? DisplayImage : Image,
|
||||
DisplayLink,
|
||||
DisplayMention,
|
||||
Iframe,
|
||||
],
|
||||
content,
|
||||
editable: false,
|
||||
|
@ -276,13 +285,16 @@ function RichContent(props: { content: JSONContent | string }) {
|
|||
}
|
||||
|
||||
// backwards compatibility: we used to store content as strings
|
||||
export function Content(props: { content: JSONContent | string }) {
|
||||
export function Content(props: {
|
||||
content: JSONContent | string
|
||||
smallImage?: boolean
|
||||
}) {
|
||||
const { content } = props
|
||||
return typeof content === 'string' ? (
|
||||
<div className="whitespace-pre-line font-light leading-relaxed">
|
||||
<Linkify text={content} />
|
||||
</div>
|
||||
) : (
|
||||
<RichContent content={content} />
|
||||
<RichContent {...props} />
|
||||
)
|
||||
}
|
||||
|
|
|
@ -254,7 +254,7 @@ export function FeedComment(props: {
|
|||
/>
|
||||
</div>
|
||||
<div className="mt-2 text-[15px] text-gray-700">
|
||||
<Content content={content || text} />
|
||||
<Content content={content || text} smallImage />
|
||||
</div>
|
||||
<Row className="mt-2 items-center gap-6 text-xs text-gray-500">
|
||||
<Tipper comment={comment} tips={tips ?? {}} />
|
||||
|
@ -394,8 +394,8 @@ export function CommentInput(props: {
|
|||
/>
|
||||
</div>
|
||||
<div className={'min-w-0 flex-1'}>
|
||||
<div className="pl-0.5 text-sm text-gray-500">
|
||||
<div className={'mb-1'}>
|
||||
<div className="pl-0.5 text-sm">
|
||||
<div className="mb-1 text-gray-500">
|
||||
{mostRecentCommentableBet && (
|
||||
<BetStatusText
|
||||
contract={contract}
|
||||
|
|
|
@ -338,7 +338,7 @@ const GroupMessage = memo(function GroupMessage_(props: {
|
|||
</Row>
|
||||
<div className="mt-2 text-black">
|
||||
{comments.map((comment) => (
|
||||
<Content content={comment.content || comment.text} />
|
||||
<Content content={comment.content || comment.text} smallImage />
|
||||
))}
|
||||
</div>
|
||||
<Row>
|
||||
|
|
Loading…
Reference in New Issue
Block a user