mirror of
https://github.com/quay/quay.git
synced 2025-04-18 10:44:06 +03:00
ui: render modelcard markdown tables (PROJQUAY-8680) (#3708)
* ui: render modelcard markdown tables (PROJQUAY-8680) * ui: oembed to render embeded video in markdown (PROJQUAY-8679) * ui: render tables and embeded links in markdown (PROJQUAY-8673) * Github linked videos and Patternfly code block * Limit img source to github and huggingface
This commit is contained in:
parent
a6713a669d
commit
1af42c0b5a
3437
web/package-lock.json
generated
3437
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -27,12 +27,15 @@
|
|||||||
"null-loader": "^4.0.1",
|
"null-loader": "^4.0.1",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-remark": "^2.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"react-router-dom": "^6.15.0",
|
"react-router-dom": "^6.15.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"recoil": "^0.7.7",
|
"recoil": "^0.7.7",
|
||||||
"recoil-persist": "^4.2.0",
|
"recoil-persist": "^4.2.0",
|
||||||
|
"rehype-raw": "^7.0.0",
|
||||||
|
"rehype-video": "^2.3.0",
|
||||||
"remark-gemoji": "^8.0.0",
|
"remark-gemoji": "^8.0.0",
|
||||||
|
"remark-gfm": "^4.0.1",
|
||||||
"ts-jest": "^29.1.1",
|
"ts-jest": "^29.1.1",
|
||||||
"typescript": "^4.6.3",
|
"typescript": "^4.6.3",
|
||||||
"use-react-router-breadcrumbs": "^4.0.1",
|
"use-react-router-breadcrumbs": "^4.0.1",
|
||||||
|
@ -1,14 +1,110 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
CodeBlock,
|
||||||
|
CodeBlockAction,
|
||||||
|
CodeBlockCode,
|
||||||
|
ClipboardCopyButton,
|
||||||
|
} from '@patternfly/react-core';
|
||||||
import {PageSection, Divider, TextContent} from '@patternfly/react-core';
|
import {PageSection, Divider, TextContent} from '@patternfly/react-core';
|
||||||
|
import {Table, Caption, Th, Td} from '@patternfly/react-table';
|
||||||
|
|
||||||
import {Remark} from 'react-remark';
|
import Markdown from 'react-markdown';
|
||||||
|
import remarkGfm from 'remark-gfm';
|
||||||
|
import rehypeRaw from 'rehype-raw';
|
||||||
|
import rehypeVideo from 'rehype-video';
|
||||||
|
|
||||||
|
export const MarkdownCodeBlock: React.FunctionComponent = (props) => {
|
||||||
|
const [copied, setCopied] = React.useState(false);
|
||||||
|
|
||||||
|
const clipboardCopyFunc = (event, text) => {
|
||||||
|
navigator.clipboard.writeText(text.toString());
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClick = (event, text) => {
|
||||||
|
clipboardCopyFunc(event, text);
|
||||||
|
setCopied(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const actions = (
|
||||||
|
<React.Fragment>
|
||||||
|
<CodeBlockAction>
|
||||||
|
<ClipboardCopyButton
|
||||||
|
id="basic-copy-button"
|
||||||
|
textId="code-content"
|
||||||
|
aria-label="Copy to clipboard"
|
||||||
|
onClick={(e) => onClick(e, props.code)}
|
||||||
|
exitDelay={copied ? 1500 : 600}
|
||||||
|
maxWidth="110px"
|
||||||
|
variant="plain"
|
||||||
|
onTooltipHidden={() => setCopied(false)}
|
||||||
|
>
|
||||||
|
{copied ? 'Successfully copied to clipboard!' : 'Copy to clipboard'}
|
||||||
|
</ClipboardCopyButton>
|
||||||
|
</CodeBlockAction>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CodeBlock actions={actions}>
|
||||||
|
<CodeBlockCode id="code-content">{props.code}</CodeBlockCode>
|
||||||
|
</CodeBlock>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export function ModelCard(props: ModelCardProps) {
|
export function ModelCard(props: ModelCardProps) {
|
||||||
|
const modelcard = props.modelCard;
|
||||||
|
const isValidImgSrc = (src) =>
|
||||||
|
src &&
|
||||||
|
(src.startsWith('https://github.com/') ||
|
||||||
|
src.startsWith('https://huggingface.co/'));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Divider />
|
<Divider />
|
||||||
<PageSection>
|
<PageSection>
|
||||||
<TextContent>
|
<TextContent>
|
||||||
<Remark>{props.modelCard}</Remark>
|
<Markdown
|
||||||
|
remarkPlugins={[remarkGfm]}
|
||||||
|
rehypePlugins={[
|
||||||
|
[rehypeRaw],
|
||||||
|
[
|
||||||
|
rehypeVideo,
|
||||||
|
{
|
||||||
|
test: new RegExp(
|
||||||
|
'(.*)(githubusercontent.com|github.com|huggingface.co)(.*)(.mp4|.mov)$',
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]}
|
||||||
|
components={{
|
||||||
|
code({node, inline, className, children, ...props}) {
|
||||||
|
return <MarkdownCodeBlock code={children} />;
|
||||||
|
},
|
||||||
|
table: ({children}) => (
|
||||||
|
<Table borders={true} variant={'compact'}>
|
||||||
|
{children}
|
||||||
|
</Table>
|
||||||
|
),
|
||||||
|
caption: 'Caption',
|
||||||
|
th: ({children}) => (
|
||||||
|
<Th style={{border: '1px solid black', padding: '8px'}}>
|
||||||
|
{children}
|
||||||
|
</Th>
|
||||||
|
),
|
||||||
|
td: ({children}) => (
|
||||||
|
<Td style={{border: '1px solid black', padding: '8px'}}>
|
||||||
|
{children}
|
||||||
|
</Td>
|
||||||
|
),
|
||||||
|
img: ({src, alt}) =>
|
||||||
|
isValidImgSrc(src) ? (
|
||||||
|
<img src={src} alt={alt} style={{maxWidth: '100%'}} />
|
||||||
|
) : null,
|
||||||
|
iframe: () => null,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{modelcard}
|
||||||
|
</Markdown>
|
||||||
</TextContent>
|
</TextContent>
|
||||||
</PageSection>
|
</PageSection>
|
||||||
</>
|
</>
|
||||||
|
@ -160,6 +160,10 @@ module.exports = (env) => {
|
|||||||
],
|
],
|
||||||
symlinks: false,
|
symlinks: false,
|
||||||
cacheWithContext: false,
|
cacheWithContext: false,
|
||||||
|
alias: {
|
||||||
|
'react/jsx-dev-runtime': 'react/jsx-dev-runtime.js',
|
||||||
|
'react/jsx-runtime': 'react/jsx-runtime.js',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user