Skip to content

Commit 84cd880

Browse files
committed
Materialize document renderer
1 parent b11e839 commit 84cd880

File tree

3 files changed

+154
-25
lines changed

3 files changed

+154
-25
lines changed

frontend/package-lock.json

Lines changed: 82 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
"react-markdown": "^9.0.1",
2828
"react-router-dom": "^6.26.2",
2929
"react-toastify": "^10.0.5",
30+
"rehype-autolink-headings": "^7.1.0",
31+
"rehype-slug": "^6.0.0",
3032
"svgo": "^3.3.2",
3133
"web-vitals": "^4.2.3",
3234
"yup": "^1.4.0"

frontend/src/components/DocumentRenderer.jsx

Lines changed: 70 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
1-
import React, {useEffect, useState} from 'react';
1+
import React, { useEffect, useState } from 'react';
22
import ReactMarkdown from 'react-markdown';
3-
import {Helmet} from 'react-helmet-async';
4-
import Skeleton from "react-loading-skeleton";
5-
import "react-loading-skeleton/dist/skeleton.css";
3+
import rehypeSlug from 'rehype-slug';
4+
import rehypeAutolinkHeadings from 'rehype-autolink-headings';
5+
import { Helmet } from 'react-helmet-async';
6+
import {
7+
Typography,
8+
Paper,
9+
Container,
10+
Skeleton,
11+
useTheme,
12+
Box,
13+
Link
14+
} from '@mui/material';
15+
import LinkIcon from '@mui/icons-material/Link';
616

717
import config from "../config.json";
818
import api from "../utils/api";
9-
import { useDarkMode } from './contexts/DarkModeContext';
1019

11-
function DocumentRenderer({endpoint, defaultTextClass}) {
20+
function DocumentRenderer({endpoint}) {
1221
const [title, setTitle] = useState('');
1322
const [lastUpdated, setLastUpdated] = useState('');
1423
const [content, setContent] = useState('');
1524
const [loading, setLoading] = useState(true);
16-
const { modeClasses } = useDarkMode();
25+
const theme = useTheme();
1726

1827
useEffect(() => {
1928
const fetchDocument = async () => {
@@ -25,35 +34,71 @@ function DocumentRenderer({endpoint, defaultTextClass}) {
2534
} catch (error) {
2635
console.error(`Error fetching document from ${endpoint}:`, error);
2736
} finally {
28-
setLoading(false); // Set loading to false after data is fetched or if there's an error
37+
setLoading(false);
2938
}
3039
};
3140

32-
3341
fetchDocument();
3442
}, [endpoint]);
3543

3644
return (
37-
<>
45+
<Container maxWidth="md">
3846
<Helmet>
3947
<title>{loading ? 'Loading...' : `${title} - ${config.siteName}`}</title>
4048
<meta name="description" content={loading ? 'Loading...' : `Read ${title} at ${config.siteName}`}/>
4149
</Helmet>
42-
<h1 className={modeClasses.textClass}>{loading ? <Skeleton width={200}/> : title}</h1>
43-
<p className={modeClasses.textClass}>{loading ? <Skeleton width={150}/> : `Last updated: ${lastUpdated}`}</p>
44-
{loading ? (
45-
<div className="text-start">
46-
<Skeleton width="90%" height={30} /> {/* Headline */}
47-
<Skeleton width="95%" height={15} count={3} /> {/* Paragraph */}
48-
<Skeleton width="60%" height={30} /> {/* Headline */}
49-
<Skeleton width="85%" height={15} count={3} /> {/* Paragraph */}
50-
<Skeleton width="80%" height={30} /> {/* Headline */}
51-
<Skeleton width="90%" height={15} count={3} /> {/* Paragraph */}
52-
</div>
53-
) : (
54-
<ReactMarkdown className={`${modeClasses.textClass} text-start`}>{content}</ReactMarkdown>
55-
)}
56-
</>
50+
<Paper elevation={3} sx={{ padding: theme.spacing(3), marginTop: theme.spacing(3) }}>
51+
<Box sx={{ textAlign: 'left' }}>
52+
{loading ? (
53+
<>
54+
<Skeleton variant="text" width="60%" height={60} />
55+
<Skeleton variant="text" width="40%" height={30} />
56+
<Skeleton variant="rectangular" height={400} />
57+
</>
58+
) : (
59+
<>
60+
<Typography variant="h3" gutterBottom>{title}</Typography>
61+
<Typography variant="subtitle1" gutterBottom>Last updated: {lastUpdated}</Typography>
62+
<ReactMarkdown
63+
components={{
64+
h1: ({node, ...props}) => <Typography variant="h4" gutterBottom {...props} />,
65+
h2: ({node, ...props}) => <Typography variant="h5" gutterBottom {...props} />,
66+
h3: ({node, ...props}) => <Typography variant="h6" gutterBottom {...props} />,
67+
p: ({node, ...props}) => <Typography variant="body1" component="p" sx={{marginBottom: theme.spacing(2)}} {...props} />,
68+
a: ({node, ...props}) => (
69+
<Link
70+
{...props}
71+
color="textPrimary"
72+
underline="none"
73+
sx={{
74+
'&:hover': {
75+
color: 'primary.main',
76+
'& .MuiSvgIcon-root': { opacity: 1 }
77+
},
78+
'& .MuiSvgIcon-root': {
79+
marginLeft: 1,
80+
opacity: 0,
81+
transition: 'opacity 0.2s'
82+
}
83+
}}
84+
>
85+
{props.children}
86+
<LinkIcon fontSize="small" />
87+
</Link>
88+
)
89+
}}
90+
rehypePlugins={[
91+
rehypeSlug,
92+
[rehypeAutolinkHeadings, { behavior: 'wrap' }]
93+
]}
94+
>
95+
{content}
96+
</ReactMarkdown>
97+
</>
98+
)}
99+
</Box>
100+
</Paper>
101+
</Container>
57102
);
58103
}
59104

0 commit comments

Comments
 (0)