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:
Sinclair Chen 2022-08-09 19:04:55 -07:00 committed by GitHub
parent c07daafb8d
commit 0b9ca6b7ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 31 deletions

View File

@ -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>
)

View File

@ -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} />
)
}

View File

@ -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}

View File

@ -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>