mirror of
https://github.com/MichaelMure/git-bug.git
synced 2024-12-15 02:01:43 +03:00
Merge pull request #624 from GlancingMind/upstream-fix-and-improve-rendering-of-markdown-elements
WebUI: Fix and improve rendering of markdown elements
This commit is contained in:
commit
62fb09a53c
26
webui/package-lock.json
generated
26
webui/package-lock.json
generated
@ -12325,6 +12325,11 @@
|
||||
"resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
|
||||
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
|
||||
},
|
||||
"gemoji": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/gemoji/-/gemoji-6.1.0.tgz",
|
||||
"integrity": "sha512-MOlX3doQ1fsfzxQX8Y+u6bC5Ssc1pBUBIPVyrS69EzKt+5LIZAOm0G5XGVNhwXFgkBF3r+Yk88ONyrFHo8iNFA=="
|
||||
},
|
||||
"generic-names": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz",
|
||||
@ -12572,7 +12577,8 @@
|
||||
"growly": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
|
||||
"integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE="
|
||||
"integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
|
||||
"optional": true
|
||||
},
|
||||
"gzip-size": {
|
||||
"version": "5.1.1",
|
||||
@ -16118,6 +16124,7 @@
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.1.tgz",
|
||||
"integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"growly": "^1.3.0",
|
||||
"is-wsl": "^2.2.0",
|
||||
@ -16131,6 +16138,7 @@
|
||||
"version": "7.3.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
|
||||
"integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
@ -16138,12 +16146,14 @@
|
||||
"uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"optional": true
|
||||
},
|
||||
"which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"isexe": "^2.0.0"
|
||||
}
|
||||
@ -19227,6 +19237,15 @@
|
||||
"fbjs": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"remark-gemoji": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/remark-gemoji/-/remark-gemoji-6.0.0.tgz",
|
||||
"integrity": "sha512-LDW2h6QqNzAbAcOjscgfkJW9/8TGBasBe/ji+3mCxHlJdhF2IEXFSmm/3tdEPP1JJDZ4y+Ea+xlFQ4tOIU9WvA==",
|
||||
"requires": {
|
||||
"gemoji": "^6.0.0",
|
||||
"unist-util-visit": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"remark-html": {
|
||||
"version": "12.0.0",
|
||||
"resolved": "https://registry.npmjs.org/remark-html/-/remark-html-12.0.0.tgz",
|
||||
@ -20219,7 +20238,8 @@
|
||||
"shellwords": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
|
||||
"integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww=="
|
||||
"integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
|
||||
"optional": true
|
||||
},
|
||||
"side-channel": {
|
||||
"version": "1.0.3",
|
||||
|
@ -22,6 +22,7 @@
|
||||
"react-router": "^5.2.0",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-scripts": "^4.0.0-next.98",
|
||||
"remark-gemoji": "^6.0.0",
|
||||
"remark-html": "^12.0.0",
|
||||
"remark-parse": "^8.0.3",
|
||||
"remark-react": "^7.0.1",
|
||||
|
@ -5,7 +5,7 @@ import Tabs from '@material-ui/core/Tabs';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
|
||||
import Content from 'src/components/Content';
|
||||
import Content from '../Content';
|
||||
|
||||
/**
|
||||
* Styles
|
||||
|
38
webui/src/components/Content/AnchorTag.tsx
Normal file
38
webui/src/components/Content/AnchorTag.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
tag: {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
}));
|
||||
|
||||
const AnchorTag = ({ children, href }: React.HTMLProps<HTMLAnchorElement>) => {
|
||||
const classes = useStyles();
|
||||
const origin = window.location.origin;
|
||||
const destination = href === undefined ? '' : href;
|
||||
const isInternalLink =
|
||||
destination.startsWith('/') || destination.startsWith(origin);
|
||||
const internalDestination = destination.replace(origin, '');
|
||||
const internalLink = (
|
||||
<Link className={classes.tag} to={internalDestination}>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
const externalLink = (
|
||||
<a
|
||||
className={classes.tag}
|
||||
href={destination}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
|
||||
return isInternalLink ? internalLink : externalLink;
|
||||
};
|
||||
|
||||
export default AnchorTag;
|
21
webui/src/components/Content/BlockQuoteTag.tsx
Normal file
21
webui/src/components/Content/BlockQuoteTag.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
tag: {
|
||||
color: theme.palette.text.secondary,
|
||||
borderLeftWidth: '0.5ch',
|
||||
borderLeftStyle: 'solid',
|
||||
borderLeftColor: theme.palette.text.secondary,
|
||||
marginLeft: 0,
|
||||
paddingLeft: '0.5rem',
|
||||
},
|
||||
}));
|
||||
|
||||
const BlockQuoteTag = (props: React.HTMLProps<HTMLPreElement>) => {
|
||||
const classes = useStyles();
|
||||
return <blockquote className={classes.tag} {...props} />;
|
||||
};
|
||||
|
||||
export default BlockQuoteTag;
|
@ -14,9 +14,12 @@ const ImageTag = ({
|
||||
}: React.ImgHTMLAttributes<HTMLImageElement>) => {
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<a href={props.src} target="_blank" rel="noopener noreferrer nofollow">
|
||||
<img className={classes.tag} alt={alt} {...props} />
|
||||
</a>
|
||||
<>
|
||||
<a href={props.src} target="_blank" rel="noopener noreferrer nofollow">
|
||||
<img className={classes.tag} alt={alt} {...props} />
|
||||
</a>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,26 +1,32 @@
|
||||
import React from 'react';
|
||||
import gemoji from 'remark-gemoji';
|
||||
import html from 'remark-html';
|
||||
import parse from 'remark-parse';
|
||||
import remark2react from 'remark-react';
|
||||
import unified from 'unified';
|
||||
|
||||
import AnchorTag from './AnchorTag';
|
||||
import BlockQuoteTag from './BlockQuoteTag';
|
||||
import ImageTag from './ImageTag';
|
||||
import PreTag from './PreTag';
|
||||
|
||||
type Props = { markdown: string };
|
||||
const Content: React.FC<Props> = ({ markdown }: Props) => {
|
||||
const processor = unified()
|
||||
const content = unified()
|
||||
.use(parse)
|
||||
.use(gemoji)
|
||||
.use(html)
|
||||
.use(remark2react, {
|
||||
remarkReactComponents: {
|
||||
img: ImageTag,
|
||||
pre: PreTag,
|
||||
a: AnchorTag,
|
||||
blockquote: BlockQuoteTag,
|
||||
},
|
||||
});
|
||||
})
|
||||
.processSync(markdown).result;
|
||||
|
||||
const contents: React.ReactNode = processor.processSync(markdown).contents;
|
||||
return <>{contents}</>;
|
||||
return <>{content}</>;
|
||||
};
|
||||
|
||||
export default Content;
|
||||
|
@ -17,14 +17,6 @@ const useStyles = makeStyles<Theme, StyleProps>((theme) => ({
|
||||
container: {
|
||||
padding: theme.spacing(0, 2, 2, 2),
|
||||
},
|
||||
textarea: {},
|
||||
tabContent: {
|
||||
margin: theme.spacing(2, 0),
|
||||
},
|
||||
preview: {
|
||||
borderBottom: `solid 3px ${theme.palette.grey['200']}`,
|
||||
minHeight: '5rem',
|
||||
},
|
||||
actions: {
|
||||
display: 'flex',
|
||||
gap: '1em',
|
||||
|
@ -57,7 +57,8 @@ const useStyles = makeStyles((theme) => ({
|
||||
},
|
||||
body: {
|
||||
...theme.typography.body2,
|
||||
padding: '0.5rem',
|
||||
paddingLeft: theme.spacing(1),
|
||||
paddingRight: theme.spacing(1),
|
||||
},
|
||||
headerActions: {
|
||||
color: theme.palette.info.contrastText,
|
||||
|
@ -22,6 +22,8 @@ import {
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
||||
|
||||
import Content from '../../components/Content';
|
||||
|
||||
import { AddCommentFragment } from './MessageCommentFragment.generated';
|
||||
import { CreateFragment } from './MessageCreateFragment.generated';
|
||||
import { useMessageHistoryQuery } from './MessageHistory.generated';
|
||||
@ -108,6 +110,7 @@ const AccordionSummary = withStyles((theme) => ({
|
||||
|
||||
const AccordionDetails = withStyles((theme) => ({
|
||||
root: {
|
||||
display: 'block',
|
||||
padding: theme.spacing(2),
|
||||
},
|
||||
}))(MuiAccordionDetails);
|
||||
@ -214,6 +217,7 @@ function MessageHistoryDialog({ bugId, commentId, open, onClose }: Props) {
|
||||
{history?.map((edit, index) => (
|
||||
<Accordion
|
||||
square
|
||||
key={index}
|
||||
expanded={expanded === 'panel' + index}
|
||||
onChange={handleChange('panel' + index)}
|
||||
>
|
||||
@ -224,7 +228,9 @@ function MessageHistoryDialog({ bugId, commentId, open, onClose }: Props) {
|
||||
>
|
||||
<Typography>{getSummary(index, edit.date)}</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>{edit.message}</AccordionDetails>
|
||||
<AccordionDetails>
|
||||
<Content markdown={edit.message} />
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
))}
|
||||
</DialogContent>
|
||||
|
6
webui/types/remark-gemoji/index.d.ts
vendored
Normal file
6
webui/types/remark-gemoji/index.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
declare module 'remark-gemoji' {
|
||||
import { Plugin } from 'unified';
|
||||
|
||||
const plugin: Plugin;
|
||||
export default plugin;
|
||||
}
|
Loading…
Reference in New Issue
Block a user