summaryrefslogtreecommitdiffstats
path: root/src/components/Content
diff options
context:
space:
mode:
authorGravatar Tom van der Lee <tom@vanderlee.io>2021-12-30 09:51:00 +0100
committerGravatar Tom van der Lee <tom@vanderlee.io>2022-01-11 00:00:22 +0100
commitbcb77d979d817e1e609adb4d007bbbcc3f61efbd (patch)
tree093c5a2914ee0f6e1ec559b3b98725190fee7285 /src/components/Content
downloadclient-bcb77d979d817e1e609adb4d007bbbcc3f61efbd.tar.gz
client-bcb77d979d817e1e609adb4d007bbbcc3f61efbd.tar.bz2
client-bcb77d979d817e1e609adb4d007bbbcc3f61efbd.zip
Prepare for githubv1.0.0
Diffstat (limited to 'src/components/Content')
-rw-r--r--src/components/Content/Content.module.scss51
-rw-r--r--src/components/Content/Content.tsx100
2 files changed, 151 insertions, 0 deletions
diff --git a/src/components/Content/Content.module.scss b/src/components/Content/Content.module.scss
new file mode 100644
index 0000000..8908516
--- /dev/null
+++ b/src/components/Content/Content.module.scss
@@ -0,0 +1,51 @@
1.content {
2 width: 100%;
3 height: 100%;
4 display: flex;
5 flex-flow: column nowrap;
6 overflow: hidden;
7}
8
9.header {
10 flex-shrink: 0;
11 flex-grow: 0;
12 width: 100%;
13 display: flex;
14 padding: 0.5em;
15 background-color: black;
16 color: white;
17}
18
19.body {
20 flex-grow: 1;
21 flex-shrink: 1;
22 overflow-y: auto;
23
24 pre {
25 width: 100%;
26 height: 100%;
27 padding: 1em;
28 font-family: monospace;
29 overflow: auto;
30 }
31
32 iframe {
33 height: 100%;
34 width: 100%;
35 }
36}
37
38.renderError {
39 width: 100%;
40 height: 100%;
41 display: flex;
42 flex-flow: column nowrap;
43 justify-content: center;
44 align-items: center;
45
46 a {
47 margin-top: 1em;
48 text-decoration: underline;
49 color: blue;
50 }
51}
diff --git a/src/components/Content/Content.tsx b/src/components/Content/Content.tsx
new file mode 100644
index 0000000..a7b5949
--- /dev/null
+++ b/src/components/Content/Content.tsx
@@ -0,0 +1,100 @@
1import styles from "~components/Details/Details.module.scss";
2import * as React from "react";
3import classNames from "classnames";
4import {RequestPayload, ResponsePayload} from "~hooks/useRequests";
5import {
6 Dispatch,
7 forwardRef, SetStateAction,
8 useEffect,
9 useImperativeHandle,
10 useMemo,
11 useRef,
12 useState
13} from "react";
14import ReactJson from 'react-json-view';
15import styles from './Content.module.scss';
16
17interface ContentProps {
18 data: RequestPayload | ResponsePayload
19 setRaw: Dispatch<SetStateAction<boolean>>
20 raw?: boolean
21}
22
23export default function Content({ raw, setRaw, ...props }: ContentProps): JSX.Element {
24 return (
25 <div className={styles.content}>
26 <div className={styles.header}>
27 <input id='raw' type='checkbox' checked={raw} onChange={() => setRaw(!raw)}/>
28 <label htmlFor='raw'>Raw</label>
29 </div>
30 <div className={styles.body}>
31 {(() => {
32 try {
33 return ContentBody({ ...props, raw })
34 } catch {
35 return (
36 <div className={styles.renderError}>
37 <p>Body could not be rendered</p>
38 <a onClick={() => setRaw(true)}>View raw</a>
39 </div>
40 )
41 }
42 })()}
43 </div>
44 </div>
45 )
46};
47
48function ContentBody({ data, raw = false }: Omit<ContentProps, 'setRaw'>) {
49 const contentType = useMemo(() => {
50 if (raw) {
51 return '';
52 }
53
54 const [_, type] = (
55 Object
56 .entries(data.headers)
57 .find(([key]) => key.toLowerCase() === 'content-type')
58 );
59
60 return type.toLowerCase().split(';')[0];
61 }, [data, raw]);
62
63 if (raw) {
64 return <pre>{atob(data.body)}</pre>
65 }
66
67 if (['application/pdf', 'text/html'].includes(contentType)) {
68 return <iframe
69 src={`data:${contentType};base64,${data.body}`}
70 srcDoc={contentType === 'text/html' ? atob(data.body) : undefined}
71 loading='lazy'
72 sandbox=''
73 />
74 }
75
76 if (contentType.startsWith('application/json')) {
77 return <ReactJson
78 src={JSON.parse(atob(data.body))}
79 style={{
80 padding: '1em',
81 width: '100%',
82 height: '100%',
83 }}
84 />
85 }
86
87 if (contentType.startsWith('audio')) {
88 return <audio src={`data:${contentType};base64,${data.body}`} />
89 }
90
91 if (contentType.startsWith('video')) {
92 return <video src={`data:${contentType};base64,${data.body}`} />
93 }
94
95 if (contentType.startsWith('image')) {
96 return <img src={`data:${contentType};base64,${data.body}`} alt=''/>
97 }
98
99 throw new Error('Not Rendered');
100};