1
- import React , { useEffect , useState } from 'react' ;
1
+ import React , { useEffect , useState } from 'react' ;
2
2
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' ;
6
16
7
17
import config from "../config.json" ;
8
18
import api from "../utils/api" ;
9
- import { useDarkMode } from './contexts/DarkModeContext' ;
10
19
11
- function DocumentRenderer ( { endpoint, defaultTextClass } ) {
20
+ function DocumentRenderer ( { endpoint} ) {
12
21
const [ title , setTitle ] = useState ( '' ) ;
13
22
const [ lastUpdated , setLastUpdated ] = useState ( '' ) ;
14
23
const [ content , setContent ] = useState ( '' ) ;
15
24
const [ loading , setLoading ] = useState ( true ) ;
16
- const { modeClasses } = useDarkMode ( ) ;
25
+ const theme = useTheme ( ) ;
17
26
18
27
useEffect ( ( ) => {
19
28
const fetchDocument = async ( ) => {
@@ -25,35 +34,71 @@ function DocumentRenderer({endpoint, defaultTextClass}) {
25
34
} catch ( error ) {
26
35
console . error ( `Error fetching document from ${ endpoint } :` , error ) ;
27
36
} finally {
28
- setLoading ( false ) ; // Set loading to false after data is fetched or if there's an error
37
+ setLoading ( false ) ;
29
38
}
30
39
} ;
31
40
32
-
33
41
fetchDocument ( ) ;
34
42
} , [ endpoint ] ) ;
35
43
36
44
return (
37
- < >
45
+ < Container maxWidth = "md" >
38
46
< Helmet >
39
47
< title > { loading ? 'Loading...' : `${ title } - ${ config . siteName } ` } </ title >
40
48
< meta name = "description" content = { loading ? 'Loading...' : `Read ${ title } at ${ config . siteName } ` } />
41
49
</ 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 >
57
102
) ;
58
103
}
59
104
0 commit comments