improved heading and images for markdown
This commit is contained in:
parent
d7210662b3
commit
08defc561b
|
@ -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>
|
||||
|
|
|
@ -62,6 +62,7 @@ export function DiscussionForm ({
|
|||
autoFocus
|
||||
/>
|
||||
<MarkdownInput
|
||||
topLevel
|
||||
label={<>{textLabel} <small className='text-muted ml-2'>optional</small></>}
|
||||
name='text'
|
||||
as={TextareaAutosize}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -160,6 +160,7 @@ export default function JobForm ({ item, sub }) {
|
|||
/>
|
||||
</BForm.Row>
|
||||
<MarkdownInput
|
||||
topLevel
|
||||
label='description'
|
||||
name='text'
|
||||
as={TextareaAutosize}
|
||||
|
|
|
@ -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,38 @@ 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({
|
||||
cursor: 'zoom-out'
|
||||
})
|
||||
} else {
|
||||
setMediaStyle(defaultMediaStyle)
|
||||
}
|
||||
}
|
||||
|
||||
return <img
|
||||
className={topLevel ? styles.topLevel : undefined}
|
||||
style={mediaStyle}
|
||||
src={src}
|
||||
onClick={handleClick}
|
||||
{...props}
|
||||
/>
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
@ -46,4 +58,28 @@
|
|||
border-left: 2px solid var(--theme-grey);
|
||||
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;
|
||||
}
|
|
@ -64,6 +64,7 @@ export function BioForm ({ handleSuccess, bio }) {
|
|||
}}
|
||||
>
|
||||
<MarkdownInput
|
||||
topLevel
|
||||
name='bio'
|
||||
as={TextareaAutosize}
|
||||
minRows={6}
|
||||
|
|
Loading…
Reference in New Issue