make zoomable image fallback to link, fix styling, refine text component, search highlighting without remark-directive

This commit is contained in:
keyan 2023-10-02 19:07:05 -05:00
parent 1e23f787bd
commit 62b53e1b3e
10 changed files with 193 additions and 736 deletions

View File

@ -245,8 +245,8 @@ export default {
sort: sortArr, sort: sortArr,
highlight: { highlight: {
fields: { fields: {
title: { number_of_fragments: 0, pre_tags: [':high['], post_tags: [']'] }, title: { number_of_fragments: 0, pre_tags: ['***'], post_tags: ['***'] },
text: { number_of_fragments: 5, order: 'score', pre_tags: [':high['], post_tags: [']'] } text: { number_of_fragments: 5, order: 'score', pre_tags: ['***'], post_tags: ['***'] }
} }
} }
} }
@ -265,7 +265,7 @@ export default {
const item = await getItem(parent, { id: e._source.id }, { me, models }) const item = await getItem(parent, { id: e._source.id }, { me, models })
item.searchTitle = (e.highlight?.title && e.highlight.title[0]) || item.title item.searchTitle = (e.highlight?.title && e.highlight.title[0]) || item.title
item.searchText = (e.highlight?.text && e.highlight.text.join(' `...` ')) || undefined item.searchText = (e.highlight?.text && e.highlight.text.join(' ... ')) || undefined
return item return item
}) })

View File

@ -1,6 +1,6 @@
import itemStyles from './item.module.css' import itemStyles from './item.module.css'
import styles from './comment.module.css' import styles from './comment.module.css'
import Text from './text' import Text, { SearchText } from './text'
import Link from 'next/link' import Link from 'next/link'
import Reply, { ReplyOnAnotherPage } from './reply' import Reply, { ReplyOnAnotherPage } from './reply'
import { useEffect, useMemo, useRef, useState } from 'react' import { useEffect, useMemo, useRef, useState } from 'react'
@ -208,9 +208,12 @@ export default function Comment ({
) )
: ( : (
<div className={styles.text}> <div className={styles.text}>
<Text topLevel={topLevel} nofollow={item.sats + item.boost < NOFOLLOW_LIMIT} imgproxyUrls={item.imgproxyUrls}> {item.searchText
{truncate ? truncateString(item.text) : item.searchText || item.text} ? <SearchText text={item.searchText} />
</Text> : (
<Text topLevel={topLevel} nofollow={item.sats + item.boost < NOFOLLOW_LIMIT} imgproxyUrls={item.imgproxyUrls}>
{truncate ? truncateString(item.text) : item.text}
</Text>)}
</div> </div>
)} )}
</div> </div>

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,8 @@ import Item from './item'
import ItemJob from './item-job' import ItemJob from './item-job'
import Reply from './reply' import Reply from './reply'
import Comment from './comment' import Comment from './comment'
import Text, { ZoomableImage } from './text' import Text, { SearchText } from './text'
import ZoomableImage from './image'
import Comments from './comments' import Comments from './comments'
import styles from '../styles/item.module.css' import styles from '../styles/item.module.css'
import itemStyles from './item.module.css' import itemStyles from './item.module.css'
@ -165,7 +166,9 @@ function TopLevelItem ({ item, noReply, ...props }) {
} }
function ItemText ({ item }) { function ItemText ({ item }) {
return <Text topLevel nofollow={item.sats + item.boost < NOFOLLOW_LIMIT} imgproxyUrls={item.imgproxyUrls}>{item.searchText || item.text}</Text> return item.searchText
? <SearchText text={item.searchText} />
: <Text topLevel nofollow={item.sats + item.boost < NOFOLLOW_LIMIT} imgproxyUrls={item.imgproxyUrls}>{item.text}</Text>
} }
export default function ItemFull ({ item, bio, rank, ...props }) { export default function ItemFull ({ item, bio, rank, ...props }) {

View File

@ -19,8 +19,8 @@ import { Badge } from 'react-bootstrap'
import AdIcon from '../svgs/advertisement-fill.svg' import AdIcon from '../svgs/advertisement-fill.svg'
export function SearchTitle ({ title }) { export function SearchTitle ({ title }) {
return reactStringReplace(title, /:high\[([^\]]+)\]/g, (match, i) => { return reactStringReplace(title, /\*\*\*([^*]+)\*\*\*/g, (match, i) => {
return <mark key={`mark-${match}`}>{match}</mark> return <mark key={`strong-${match}`}>{match}</mark>
}) })
} }

View File

@ -5,39 +5,50 @@ import { LightAsync as SyntaxHighlighter } from 'react-syntax-highlighter'
import atomDark from 'react-syntax-highlighter/dist/cjs/styles/prism/atom-dark' import atomDark from 'react-syntax-highlighter/dist/cjs/styles/prism/atom-dark'
import mention from '../lib/remark-mention' import mention from '../lib/remark-mention'
import sub from '../lib/remark-sub' import sub from '../lib/remark-sub'
import remarkDirective from 'remark-directive' import React, { useState, memo, useRef, useCallback, useMemo } from 'react'
import { visit } from 'unist-util-visit'
import reactStringReplace from 'react-string-replace'
import React, { useState, memo } from 'react'
import GithubSlugger from 'github-slugger' import GithubSlugger from 'github-slugger'
import LinkIcon from '../svgs/link.svg' import LinkIcon from '../svgs/link.svg'
import Thumb from '../svgs/thumb-up-fill.svg' import Thumb from '../svgs/thumb-up-fill.svg'
import { toString } from 'mdast-util-to-string' import { toString } from 'mdast-util-to-string'
import copy from 'clipboard-copy' import copy from 'clipboard-copy'
import { useImgUrlCache, IMG_CACHE_STATES, ZoomableImage, decodeOriginalUrl } from './image' import { ZoomableImage, decodeOriginalUrl } from './image'
import { IMGPROXY_URL_REGEXP } from '../lib/url' import { IMGPROXY_URL_REGEXP } from '../lib/url'
import reactStringReplace from 'react-string-replace'
function searchHighlighter () { export function SearchText ({ text }) {
return (tree) => { return (
visit(tree, (node) => { <div className={styles.text}>
if ( <p className={styles.p}>
node.type === 'textDirective' || {reactStringReplace(text, /\*\*\*([^*]+)\*\*\*/g, (match, i) => {
node.type === 'leafDirective' return <mark key={`strong-${match}`}>{match}</mark>
) { })}
if (node.name !== 'high') return </p>
</div>
const data = node.data || (node.data = {}) )
data.hName = 'mark'
data.hProperties = {}
}
})
}
} }
function Heading ({ h, slugger, noFragments, topLevel, children, node, ...props }) { function Heading ({ level, slugger, noFragments, topLevel, children, node, ...props }) {
const [copied, setCopied] = useState(false) const [copied, setCopied] = useState(false)
const [id] = useState(noFragments ? undefined : slugger.slug(toString(node).replace(/[^\w\-\s]+/gi, ''))) const id = useMemo(() =>
noFragments ? undefined : slugger.slug(toString(node).replace(/[^\w\-\s]+/gi, '')), [node, noFragments, slugger])
const h = useMemo(() => {
switch (level) {
case 1:
return topLevel ? 'h1' : 'h4'
case 2:
return topLevel ? 'h2' : 'h5'
case 3:
return topLevel ? 'h3' : 'h6'
case 4:
return topLevel ? 'h4' : 'h6'
case 5:
return topLevel ? 'h5' : 'h6'
case 6:
return 'h6'
default:
return 'h6'
}
}, [level, topLevel])
const Icon = copied ? Thumb : LinkIcon const Icon = copied ? Thumb : LinkIcon
return ( return (
@ -63,88 +74,64 @@ function Heading ({ h, slugger, noFragments, topLevel, children, node, ...props
} }
// this is one of the slowest components to render // this is one of the slowest components to render
export default memo(function Text ({ topLevel, noFragments, nofollow, imgproxyUrls, children, tab }) { export default memo(function Text ({ nofollow, imgproxyUrls, children, tab, ...outerProps }) {
// all the reactStringReplace calls are to facilitate search highlighting // all the reactStringReplace calls are to facilitate search highlighting
const slugger = new GithubSlugger() const slugger = useRef(new GithubSlugger())
const HeadingWrapper = (props) => Heading({ topLevel, slugger, noFragments, ...props }) const Table = useCallback(({ node, ...props }) =>
<span className='table-responsive'>
<table className='table table-bordered table-sm' {...props} />
</span>, [])
const imgUrlCache = useImgUrlCache(children, { imgproxyUrls, tab }) const Code = useCallback(({ node, inline, className, children, style, ...props }) => {
return inline
? (
<code className={className} style={atomDark} {...props}>
{children}
</code>
)
: (
<SyntaxHighlighter showLineNumbers style={atomDark} PreTag='div' {...props}>
{children}
</SyntaxHighlighter>
)
}, [])
const P = useCallback(({ children, ...props }) => <div className={styles.p} {...props}>{children}</div>, [])
const Img = useCallback(({ node, src, ...props }) => {
const url = IMGPROXY_URL_REGEXP.test(src) ? decodeOriginalUrl(src) : src
// if `srcSet` is undefined, it means the image was not processed by worker yet
// if `srcSet` is null, image was processed but this specific url was not detected as an image by the worker
const srcSet = imgproxyUrls?.[url]
return <ZoomableImage srcSet={srcSet} tab={tab} src={src} {...props} {...outerProps} />
}, [imgproxyUrls, outerProps, tab])
return ( return (
<div className={styles.text}> <div className={styles.text}>
<ReactMarkdown <ReactMarkdown
components={{ components={{
h1: (props) => HeadingWrapper({ h: topLevel ? 'h1' : 'h3', ...props }), h1: (props) => <Heading {...props} {...outerProps} slugger={slugger.current} />,
h2: (props) => HeadingWrapper({ h: topLevel ? 'h2' : 'h4', ...props }), h2: (props) => <Heading {...props} {...outerProps} slugger={slugger.current} />,
h3: (props) => HeadingWrapper({ h: topLevel ? 'h3' : 'h5', ...props }), h3: (props) => <Heading {...props} {...outerProps} slugger={slugger.current} />,
h4: (props) => HeadingWrapper({ h: topLevel ? 'h4' : 'h6', ...props }), h4: (props) => <Heading {...props} {...outerProps} slugger={slugger.current} />,
h5: (props) => HeadingWrapper({ h: topLevel ? 'h5' : 'h6', ...props }), h5: (props) => <Heading {...props} {...outerProps} slugger={slugger.current} />,
h6: (props) => HeadingWrapper({ h: 'h6', ...props }), h6: (props) => <Heading {...props} {...outerProps} slugger={slugger.current} />,
table: ({ node, ...props }) => table: Table,
<span className='table-responsive'> p: P,
<table className='table table-bordered table-sm' {...props} /> code: Code,
</span>,
p: ({ children, ...props }) => <div className={styles.p} {...props}>{children}</div>,
code ({ node, inline, className, children, style, ...props }) {
return !inline
? (
<SyntaxHighlighter showLineNumbers style={atomDark} PreTag='div' {...props}>
{reactStringReplace(String(children).replace(/\n$/, ''), /:high\[([^\]]+)\]/g, (match, i) => {
return match
}).join('')}
</SyntaxHighlighter>
)
: (
<code className={className} style={atomDark} {...props}>
{reactStringReplace(String(children), /:high\[([^\]]+)\]/g, (match, i) => {
return <mark key={`mark-${match}`}>{match}</mark>
})}
</code>
)
},
a: ({ node, href, children, ...props }) => { a: ({ node, href, children, ...props }) => {
// don't allow zoomable images to be wrapped in links
if (children?.some(e => e?.props?.node?.tagName === 'img')) { if (children?.some(e => e?.props?.node?.tagName === 'img')) {
return <>{children}</> return <>{children}</>
} }
if (imgUrlCache[href] === IMG_CACHE_STATES.LOADED) { // assume the link is an image which will fallback to link if it's not
const url = IMGPROXY_URL_REGEXP.test(href) ? decodeOriginalUrl(href) : href return <Img src={href} nofollow={nofollow} {...props}>{children}</Img>
// if `srcSet` is undefined, it means the image was not processed by worker yet
// if `srcSet` is null, image was processed but this specific url was not detected as an image by the worker
const srcSet = imgproxyUrls ? (imgproxyUrls[url] || null) : undefined
return <ZoomableImage topLevel={topLevel} srcSet={srcSet} tab={tab} {...props} src={href} />
}
// map: fix any highlighted links
children = children?.map(e =>
typeof e === 'string'
? reactStringReplace(e, /:high\[([^\]]+)\]/g, (match, i) => {
return <mark key={`mark-${match}-${i}`}>{match}</mark>
})
: e)
return (
/* eslint-disable-next-line */
<a
target='_blank' rel={nofollow ? 'nofollow' : 'noreferrer'}
href={reactStringReplace(href, /:high%5B([^%5D]+)%5D/g, (match, i) => {
return match
}).join('')} {...props}
>
{children}
</a>
)
}, },
img: ({ node, src, ...props }) => { img: Img
const url = IMGPROXY_URL_REGEXP.test(src) ? decodeOriginalUrl(src) : src
// if `srcSet` is undefined, it means the image was not processed by worker yet
// if `srcSet` is null, image was processed but this specific url was not detected as an image by the worker
const srcSet = imgproxyUrls ? (imgproxyUrls[url] || null) : undefined
return <ZoomableImage topLevel={topLevel} srcSet={srcSet} tab={tab} src={src} {...props} />
}
}} }}
remarkPlugins={[gfm, mention, sub, remarkDirective, searchHighlighter]} remarkPlugins={[gfm, mention, sub]}
> >
{children} {children}
</ReactMarkdown> </ReactMarkdown>

View File

@ -76,11 +76,34 @@
border-radius: .4rem; border-radius: .4rem;
width: auto; width: auto;
max-width: 100%; max-width: 100%;
cursor: zoom-in;
max-height: 25vh;
} }
.text img.topLevel { .text img.topLevel {
margin-top: .75rem; margin-top: .75rem;
margin-bottom: .75rem; margin-bottom: .75rem;
max-height: 35vh;
}
img.fullScreen {
cursor: zoom-out !important;
max-height: 100%;
max-width: 100vw;
min-width: 0;
min-height: 0;
align-self: center;
justify-self: center;
}
.fullScreenContainer {
--bs-columns: 1;
--bs-rows: 1;
display: grid;
width: 100%;
height: 100%;
align-content: center;
justify-content: center;
} }
.text table { .text table {

467
package-lock.json generated
View File

@ -69,7 +69,6 @@
"react-twitter-embed": "^4.0.4", "react-twitter-embed": "^4.0.4",
"react-youtube": "^10.1.0", "react-youtube": "^10.1.0",
"recharts": "^2.7.3", "recharts": "^2.7.3",
"remark-directive": "^2.0.1",
"remark-gfm": "^3.0.1", "remark-gfm": "^3.0.1",
"remove-markdown": "^0.5.0", "remove-markdown": "^0.5.0",
"sass": "^1.65.1", "sass": "^1.65.1",
@ -5257,15 +5256,6 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/character-entities-html4": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz",
"integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/character-entities-legacy": { "node_modules/character-entities-legacy": {
"version": "1.1.4", "version": "1.1.4",
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
@ -9835,134 +9825,6 @@
"url": "https://opencollective.com/unified" "url": "https://opencollective.com/unified"
} }
}, },
"node_modules/mdast-util-directive": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-2.2.1.tgz",
"integrity": "sha512-yZRRuaulzc6bM4IOyZfkOrVs+9Sf1BC+rldRXJyl/Ej6S/6ewQQ9jt75HvEoqZZ4m9ealVTHiS4MP2GRUE7INA==",
"dependencies": {
"@types/mdast": "^3.0.0",
"@types/unist": "^2.0.0",
"mdast-util-to-markdown": "^1.3.0",
"parse-entities": "^4.0.0",
"stringify-entities": "^4.0.0",
"unist-util-visit-parents": "^5.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/mdast-util-directive/node_modules/character-entities": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz",
"integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/mdast-util-directive/node_modules/character-entities-legacy": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz",
"integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/mdast-util-directive/node_modules/character-reference-invalid": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz",
"integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/mdast-util-directive/node_modules/is-alphabetical": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
"integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/mdast-util-directive/node_modules/is-alphanumerical": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
"integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
"dependencies": {
"is-alphabetical": "^2.0.0",
"is-decimal": "^2.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/mdast-util-directive/node_modules/is-decimal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
"integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/mdast-util-directive/node_modules/is-hexadecimal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz",
"integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/mdast-util-directive/node_modules/parse-entities": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz",
"integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==",
"dependencies": {
"@types/unist": "^2.0.0",
"character-entities": "^2.0.0",
"character-entities-legacy": "^3.0.0",
"character-reference-invalid": "^2.0.0",
"decode-named-character-reference": "^1.0.0",
"is-alphanumerical": "^2.0.0",
"is-decimal": "^2.0.0",
"is-hexadecimal": "^2.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/mdast-util-directive/node_modules/unist-util-is": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz",
"integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==",
"dependencies": {
"@types/unist": "^2.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/mdast-util-directive/node_modules/unist-util-visit-parents": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz",
"integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==",
"dependencies": {
"@types/unist": "^2.0.0",
"unist-util-is": "^5.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/mdast-util-find-and-replace": { "node_modules/mdast-util-find-and-replace": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.0.tgz", "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.0.tgz",
@ -11227,110 +11089,6 @@
"uvu": "^0.5.0" "uvu": "^0.5.0"
} }
}, },
"node_modules/micromark-extension-directive": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-2.1.1.tgz",
"integrity": "sha512-+7MYZ3a10cpPrQRg3530srFMSBx0EL7gQaJ3ekguOQFSlJHLikW15AphBmNxvCNdRSWTX1R8RepzjKQra8INQw==",
"dependencies": {
"micromark-factory-space": "^1.0.0",
"micromark-factory-whitespace": "^1.0.0",
"micromark-util-character": "^1.0.0",
"micromark-util-symbol": "^1.0.0",
"micromark-util-types": "^1.0.0",
"parse-entities": "^4.0.0",
"uvu": "^0.5.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/micromark-extension-directive/node_modules/character-entities": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz",
"integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/micromark-extension-directive/node_modules/character-entities-legacy": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz",
"integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/micromark-extension-directive/node_modules/character-reference-invalid": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz",
"integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/micromark-extension-directive/node_modules/is-alphabetical": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
"integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/micromark-extension-directive/node_modules/is-alphanumerical": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
"integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
"dependencies": {
"is-alphabetical": "^2.0.0",
"is-decimal": "^2.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/micromark-extension-directive/node_modules/is-decimal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
"integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/micromark-extension-directive/node_modules/is-hexadecimal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz",
"integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/micromark-extension-directive/node_modules/parse-entities": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz",
"integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==",
"dependencies": {
"@types/unist": "^2.0.0",
"character-entities": "^2.0.0",
"character-entities-legacy": "^3.0.0",
"character-reference-invalid": "^2.0.0",
"decode-named-character-reference": "^1.0.0",
"is-alphanumerical": "^2.0.0",
"is-decimal": "^2.0.0",
"is-hexadecimal": "^2.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/micromark-extension-gfm": { "node_modules/micromark-extension-gfm": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz",
@ -15219,21 +14977,6 @@
"jsesc": "bin/jsesc" "jsesc": "bin/jsesc"
} }
}, },
"node_modules/remark-directive": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-2.0.1.tgz",
"integrity": "sha512-oosbsUAkU/qmUE78anLaJePnPis4ihsE7Agp0T/oqTzvTea8pOiaYEtfInU/+xMOVTS9PN5AhGOiaIVe4GD8gw==",
"dependencies": {
"@types/mdast": "^3.0.0",
"mdast-util-directive": "^2.0.0",
"micromark-extension-directive": "^2.0.0",
"unified": "^10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/remark-gfm": { "node_modules/remark-gfm": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz", "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz",
@ -16643,28 +16386,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/stringify-entities": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.2.tgz",
"integrity": "sha512-MTxTVcEkorNtBbNpoFJPEh0kKdM6+QbMjLbaxmvaPMmayOXdr/AIVIIJX7FReUVweRBFJfZepK4A4AKgwuFpMQ==",
"dependencies": {
"character-entities-html4": "^2.0.0",
"character-entities-legacy": "^3.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/stringify-entities/node_modules/character-entities-legacy": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz",
"integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/stringify-object": { "node_modules/stringify-object": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
@ -22408,11 +22129,6 @@
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
"integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==" "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw=="
}, },
"character-entities-html4": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz",
"integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="
},
"character-entities-legacy": { "character-entities-legacy": {
"version": "1.1.4", "version": "1.1.4",
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
@ -25708,92 +25424,6 @@
} }
} }
}, },
"mdast-util-directive": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-2.2.1.tgz",
"integrity": "sha512-yZRRuaulzc6bM4IOyZfkOrVs+9Sf1BC+rldRXJyl/Ej6S/6ewQQ9jt75HvEoqZZ4m9ealVTHiS4MP2GRUE7INA==",
"requires": {
"@types/mdast": "^3.0.0",
"@types/unist": "^2.0.0",
"mdast-util-to-markdown": "^1.3.0",
"parse-entities": "^4.0.0",
"stringify-entities": "^4.0.0",
"unist-util-visit-parents": "^5.0.0"
},
"dependencies": {
"character-entities": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz",
"integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="
},
"character-entities-legacy": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz",
"integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="
},
"character-reference-invalid": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz",
"integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="
},
"is-alphabetical": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
"integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="
},
"is-alphanumerical": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
"integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
"requires": {
"is-alphabetical": "^2.0.0",
"is-decimal": "^2.0.0"
}
},
"is-decimal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
"integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="
},
"is-hexadecimal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz",
"integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="
},
"parse-entities": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz",
"integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==",
"requires": {
"@types/unist": "^2.0.0",
"character-entities": "^2.0.0",
"character-entities-legacy": "^3.0.0",
"character-reference-invalid": "^2.0.0",
"decode-named-character-reference": "^1.0.0",
"is-alphanumerical": "^2.0.0",
"is-decimal": "^2.0.0",
"is-hexadecimal": "^2.0.0"
}
},
"unist-util-is": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz",
"integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==",
"requires": {
"@types/unist": "^2.0.0"
}
},
"unist-util-visit-parents": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz",
"integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==",
"requires": {
"@types/unist": "^2.0.0",
"unist-util-is": "^5.0.0"
}
}
}
},
"mdast-util-find-and-replace": { "mdast-util-find-and-replace": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.0.tgz", "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.0.tgz",
@ -26771,76 +26401,6 @@
"uvu": "^0.5.0" "uvu": "^0.5.0"
} }
}, },
"micromark-extension-directive": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-2.1.1.tgz",
"integrity": "sha512-+7MYZ3a10cpPrQRg3530srFMSBx0EL7gQaJ3ekguOQFSlJHLikW15AphBmNxvCNdRSWTX1R8RepzjKQra8INQw==",
"requires": {
"micromark-factory-space": "^1.0.0",
"micromark-factory-whitespace": "^1.0.0",
"micromark-util-character": "^1.0.0",
"micromark-util-symbol": "^1.0.0",
"micromark-util-types": "^1.0.0",
"parse-entities": "^4.0.0",
"uvu": "^0.5.0"
},
"dependencies": {
"character-entities": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz",
"integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="
},
"character-entities-legacy": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz",
"integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="
},
"character-reference-invalid": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz",
"integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="
},
"is-alphabetical": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
"integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="
},
"is-alphanumerical": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
"integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
"requires": {
"is-alphabetical": "^2.0.0",
"is-decimal": "^2.0.0"
}
},
"is-decimal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
"integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="
},
"is-hexadecimal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz",
"integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="
},
"parse-entities": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz",
"integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==",
"requires": {
"@types/unist": "^2.0.0",
"character-entities": "^2.0.0",
"character-entities-legacy": "^3.0.0",
"character-reference-invalid": "^2.0.0",
"decode-named-character-reference": "^1.0.0",
"is-alphanumerical": "^2.0.0",
"is-decimal": "^2.0.0",
"is-hexadecimal": "^2.0.0"
}
}
}
},
"micromark-extension-gfm": { "micromark-extension-gfm": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz",
@ -29080,17 +28640,6 @@
} }
} }
}, },
"remark-directive": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-2.0.1.tgz",
"integrity": "sha512-oosbsUAkU/qmUE78anLaJePnPis4ihsE7Agp0T/oqTzvTea8pOiaYEtfInU/+xMOVTS9PN5AhGOiaIVe4GD8gw==",
"requires": {
"@types/mdast": "^3.0.0",
"mdast-util-directive": "^2.0.0",
"micromark-extension-directive": "^2.0.0",
"unified": "^10.0.0"
}
},
"remark-gfm": { "remark-gfm": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz", "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz",
@ -30140,22 +29689,6 @@
"es-abstract": "^1.19.5" "es-abstract": "^1.19.5"
} }
}, },
"stringify-entities": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.2.tgz",
"integrity": "sha512-MTxTVcEkorNtBbNpoFJPEh0kKdM6+QbMjLbaxmvaPMmayOXdr/AIVIIJX7FReUVweRBFJfZepK4A4AKgwuFpMQ==",
"requires": {
"character-entities-html4": "^2.0.0",
"character-entities-legacy": "^3.0.0"
},
"dependencies": {
"character-entities-legacy": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz",
"integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="
}
}
},
"stringify-object": { "stringify-object": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",

View File

@ -72,7 +72,6 @@
"react-twitter-embed": "^4.0.4", "react-twitter-embed": "^4.0.4",
"react-youtube": "^10.1.0", "react-youtube": "^10.1.0",
"recharts": "^2.7.3", "recharts": "^2.7.3",
"remark-directive": "^2.0.1",
"remark-gfm": "^3.0.1", "remark-gfm": "^3.0.1",
"remove-markdown": "^0.5.0", "remove-markdown": "^0.5.0",
"sass": "^1.65.1", "sass": "^1.65.1",

View File

@ -210,7 +210,7 @@ $btn-close-bg: none;
} }
.modal-body.fullscreen { .modal-body.fullscreen {
width: 100vw; width: 100vw;
height: calc(100svh - 6rem); height: calc(100svh - 6.8rem);
padding: 0; padding: 0;
background-color: transparent; background-color: transparent;
} }