improved heading and images for markdown

This commit is contained in:
keyan 2022-07-13 18:00:48 -05:00
parent d7210662b3
commit 5457026bd3
8 changed files with 97 additions and 19 deletions

View File

@ -72,7 +72,7 @@ export function CommentFlat ({ item, ...props }) {
}
export default function Comment ({
item, children, replyOpen, includeParent,
item, children, replyOpen, includeParent, topLevel,
rootText, noComments, noReply, truncate, depth
}) {
const [edit, setEdit] = useState()
@ -173,7 +173,7 @@ export default function Comment ({
)
: (
<div className={styles.text}>
<Text nofollow={item.sats + item.boost < NOFOLLOW_LIMIT}>
<Text topLevel={topLevel} nofollow={item.sats + item.boost < NOFOLLOW_LIMIT}>
{truncate ? truncateString(item.text) : item.searchText || item.text}
</Text>
</div>

View File

@ -62,6 +62,7 @@ export function DiscussionForm ({
autoFocus
/>
<MarkdownInput
topLevel
label={<>{textLabel} <small className='text-muted ml-2'>optional</small></>}
name='text'
as={TextareaAutosize}

View File

@ -71,7 +71,7 @@ export function InputSkeleton ({ label, hint }) {
)
}
export function MarkdownInput ({ label, groupClassName, ...props }) {
export function MarkdownInput ({ label, topLevel, groupClassName, ...props }) {
const [tab, setTab] = useState('write')
const [, meta] = useField(props)
@ -103,7 +103,7 @@ export function MarkdownInput ({ label, groupClassName, ...props }) {
</div>
<div className={tab !== 'preview' ? 'd-none' : 'form-group'}>
<div className={`${styles.text} form-control`}>
{tab === 'preview' && <Text>{meta.value}</Text>}
{tab === 'preview' && <Text topLevel={topLevel}>{meta.value}</Text>}
</div>
</div>
</div>

View File

@ -92,14 +92,14 @@ function TopLevelItem ({ item, noReply, ...props }) {
}
function ItemText ({ item }) {
return <Text nofollow={item.sats + item.boost < NOFOLLOW_LIMIT}>{item.searchText || item.text}</Text>
return <Text topLevel nofollow={item.sats + item.boost < NOFOLLOW_LIMIT}>{item.searchText || item.text}</Text>
}
export default function ItemFull ({ item, bio, ...props }) {
return (
<>
{item.parentId
? <Comment item={item} replyOpen includeParent noComments {...props} />
? <Comment topLevel item={item} replyOpen includeParent noComments {...props} />
: (
<div className='mt-1'>{
bio

View File

@ -160,6 +160,7 @@ export default function JobForm ({ item, sub }) {
/>
</BForm.Row>
<MarkdownInput
topLevel
label='description'
name='text'
as={TextareaAutosize}

View File

@ -9,6 +9,7 @@ import sub from '../lib/remark-sub'
import remarkDirective from 'remark-directive'
import { visit } from 'unist-util-visit'
import reactStringReplace from 'react-string-replace'
import { useEffect, useState } from 'react'
function myRemarkPlugin () {
return (tree) => {
@ -27,17 +28,18 @@ function myRemarkPlugin () {
}
}
export default function Text ({ nofollow, children }) {
export default function Text ({ topLevel, nofollow, children }) {
// all the reactStringReplace calls are to facilitate search highlighting
return (
<div className={styles.text}>
<ReactMarkdown
components={{
h1: 'h6',
h2: 'h6',
h3: 'h6',
h4: 'h6',
h5: 'h6',
h1: ({children, node, ...props}) => topLevel ? <h1 {...props}>{children}</h1> : <h3 {...props}>{children}</h3>,
h2: ({children, node, ...props}) => topLevel ? <h2 {...props}>{children}</h2> : <h4 {...props}>{children}</h4>,
h3: ({children, node, ...props}) => topLevel ? <h3 {...props}>{children}</h3> : <h5 {...props}>{children}</h5>,
h4: ({children, node, ...props}) => topLevel ? <h4 {...props}>{children}</h4> : <h6 {...props}>{children}</h6>,
h5: ({children, node, ...props}) => topLevel ? <h5 {...props}>{children}</h5> : <h6 {...props}>{children}</h6>,
h6: 'h6',
table: ({ node, ...props }) =>
<div className='table-responsive'>
@ -79,7 +81,8 @@ export default function Text ({ nofollow, children }) {
{children}
</a>
)
}
},
img: ({node, ...props}) => <ZoomableImage topLevel={topLevel} {...props}/>
}}
remarkPlugins={[gfm, mention, sub, remarkDirective, myRemarkPlugin]}
>
@ -88,3 +91,39 @@ export default function Text ({ nofollow, children }) {
</div>
)
}
function ZoomableImage ({ src, topLevel, ...props }) {
if (!src) {
return null
}
const defaultMediaStyle = {
maxHeight: topLevel ? '75vh' : '25vh',
cursor: 'zoom-in'
}
// if image changes we need to update state
const [mediaStyle, setMediaStyle] = useState(defaultMediaStyle)
useEffect(() => {
setMediaStyle(defaultMediaStyle)
}, [src])
const handleClick = () => {
if (mediaStyle.cursor === 'zoom-in') {
setMediaStyle({
width: '100%',
cursor: 'zoom-out'
})
} else {
setMediaStyle(defaultMediaStyle)
}
}
return <img
className={topLevel ? styles.topLevel : undefined}
style={mediaStyle}
src={src}
onClick={handleClick}
{...props}
/>
}

View File

@ -7,9 +7,13 @@
@media screen and (min-width: 767px) {
.text {
line-height: 130%;
line-height: 130%;
}
}
}
.text hr {
border-top: 1px solid var(--theme-clickToContextColor);
}
.text p {
margin-bottom: .5rem;
@ -21,21 +25,29 @@
margin-bottom: .5rem;
}
.text pre > div {
.text pre>div {
margin: 0 !important;
}
.text > *:last-child {
.text>*:last-child {
margin-bottom: 0 !important;
}
.text blockquote > *:last-child {
.text blockquote>*:last-child {
margin-bottom: 0 !important;
}
.text img {
display: block;
margin-top: .5rem;
border-radius: .4rem;
width: min-content;
max-width: 100%;
max-height: 300px;
}
.text img.topLevel {
margin-top: .75rem;
margin-bottom: .75rem;
}
.text table {
@ -47,3 +59,27 @@
padding-left: 1rem;
margin: 0 0 0.5rem 0.5rem !important;
}
.text h1 {
font-size: 1.6rem;
}
.text h2 {
font-size: 1.45rem;
}
.text h3 {
font-size: 1.3rem;
}
.text h4 {
font-size: 1.15rem;
}
.text h5 {
font-size: 1rem;
}
.text h6 {
font-size: .85rem;
}

View File

@ -64,6 +64,7 @@ export function BioForm ({ handleSuccess, bio }) {
}}
>
<MarkdownInput
topLevel
name='bio'
as={TextareaAutosize}
minRows={6}