summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Tom van der Lee <tom@vanderlee.io>2022-01-25 21:42:51 +0100
committerGravatar Tom van der Lee <tom@vanderlee.io>2022-01-25 22:06:58 +0100
commitf9cd68181137c72e92c6951efd9b8d29c4b73bc1 (patch)
treea58451fb140d9c5ea023a45bd393127519a7918f /src
parent2f27e222add9bf10b55971ab915ac411e81d24f0 (diff)
downloadclient-f9cd68181137c72e92c6951efd9b8d29c4b73bc1.tar.gz
client-f9cd68181137c72e92c6951efd9b8d29c4b73bc1.tar.bz2
client-f9cd68181137c72e92c6951efd9b8d29c4b73bc1.zip
Added dark mode
Diffstat (limited to 'src')
-rw-r--r--src/components/App/App.tsx94
-rw-r--r--src/components/Content/Content.tsx6
-rw-r--r--src/components/Icons/Moon.tsx11
-rw-r--r--src/components/Icons/Sliders.tsx10
-rw-r--r--src/components/Icons/Sun.tsx9
-rw-r--r--src/components/Icons/Trash.tsx13
-rw-r--r--src/hooks/useDarkMode.tsx21
-rw-r--r--src/hooks/useRequests.tsx5
-rw-r--r--src/index.scss4
-rw-r--r--src/index.tsx2
10 files changed, 158 insertions, 17 deletions
diff --git a/src/components/App/App.tsx b/src/components/App/App.tsx
index cb82abc..bbab612 100644
--- a/src/components/App/App.tsx
+++ b/src/components/App/App.tsx
@@ -1,5 +1,5 @@
1import * as React from "react"; 1import * as React from "react";
2import {useEffect, useMemo, useState} from "react"; 2import {ReactElement, useEffect, useMemo, useState} from "react";
3import useRequests, { 3import useRequests, {
4 ReadyState, 4 ReadyState,
5 RequestResponse 5 RequestResponse
@@ -9,13 +9,24 @@ import styles from './App.module.scss';
9import Details from "../Details/Details"; 9import Details from "../Details/Details";
10import RequestSummary from "../RequestSummary/RequestSummary"; 10import RequestSummary from "../RequestSummary/RequestSummary";
11import {getHost} from "../../utils"; 11import {getHost} from "../../utils";
12import {Container, ListGroup, Navbar} from "react-bootstrap"; 12import {Container, ListGroup, Nav, Navbar, NavDropdown} from "react-bootstrap";
13import classNames from "classnames"; 13import classNames from "classnames";
14import useDarkMode from "../../hooks/useDarkMode";
15import {Sliders} from "../Icons/Sliders";
16import {Sun} from "../Icons/Sun";
17import {Moon} from "../Icons/Moon";
18import Trash from "../Icons/Trash";
14 19
15interface Config { 20interface Config {
16 url: string 21 url: string
17} 22}
18 23
24interface SettingsMenu {
25 icon: ReactElement,
26 label: string,
27 onClick: () => void,
28}
29
19type ReadyStateMap = { 30type ReadyStateMap = {
20 [ReadyState.CONNECTING]: string, 31 [ReadyState.CONNECTING]: string,
21 [ReadyState.OPEN]: string, 32 [ReadyState.OPEN]: string,
@@ -23,18 +34,25 @@ type ReadyStateMap = {
23 [ReadyState.CLOSED]: string, 34 [ReadyState.CLOSED]: string,
24} 35}
25 36
26const statusMap: ReadyStateMap = { 37const statusIconMap: ReadyStateMap = {
27 [ReadyState.CONNECTING]: '🔴', 38 [ReadyState.CONNECTING]: '🔴',
28 [ReadyState.OPEN]: '🟢', 39 [ReadyState.OPEN]: '🟢',
29 [ReadyState.CLOSING]: '🔴', 40 [ReadyState.CLOSING]: '🔴',
30 [ReadyState.CLOSED]: '🔴', 41 [ReadyState.CLOSED]: '🔴',
31} 42}
32 43
33export default function App() { 44const statusTextMap: ReadyStateMap = {
45 [ReadyState.CONNECTING]: 'Connecting...',
46 [ReadyState.OPEN]: 'Connected',
47 [ReadyState.CLOSING]: 'Closing...',
48 [ReadyState.CLOSED]: 'Closed',
49}
34 50
51export default function App() {
52 const { darkMode, toggle } = useDarkMode();
35 const [config, setConfig]= useState<Config | null>(null) 53 const [config, setConfig]= useState<Config | null>(null)
36 54
37 const { calls, readyState } = useRequests({ 55 const { calls, readyState, clear } = useRequests({
38 onConnect: async () => { 56 onConnect: async () => {
39 const response = await fetch(`http://${getHost()}/config/`) 57 const response = await fetch(`http://${getHost()}/config/`)
40 const config = await response.json() 58 const config = await response.json()
@@ -44,7 +62,7 @@ export default function App() {
44 62
45 useEffect(() => { 63 useEffect(() => {
46 const url = new URL(config?.url ?? 'https://loading...'); 64 const url = new URL(config?.url ?? 'https://loading...');
47 document.title = `${statusMap[readyState]} ${url.host} | TTUN`; 65 document.title = `${statusIconMap[readyState]} ${url.host} | TTUN`;
48 }, [readyState, config?.url]) 66 }, [readyState, config?.url])
49 67
50 const [selectedRequestIndex, setSelectedRequestIndex] = useState<number | null>(null); 68 const [selectedRequestIndex, setSelectedRequestIndex] = useState<number | null>(null);
@@ -54,6 +72,23 @@ export default function App() {
54 : calls[selectedRequestIndex] 72 : calls[selectedRequestIndex]
55 ), [selectedRequestIndex, calls]); 73 ), [selectedRequestIndex, calls]);
56 74
75 const settingsMenu: (SettingsMenu | null)[] = [
76 {
77 onClick: toggle,
78 icon: darkMode ? <Sun />: <Moon />,
79 label: darkMode ? "Light mode" : "DarkMode",
80 },
81 null,
82 {
83 onClick: () => {
84 setSelectedRequestIndex(null);
85 clear();
86 },
87 icon: <Trash />,
88 label: "Clear"
89 }
90 ];
91
57 return config && ( 92 return config && (
58 <div className={styles.app}> 93 <div className={styles.app}>
59 <Navbar 94 <Navbar
@@ -63,12 +98,47 @@ export default function App() {
63 as="header" 98 as="header"
64 > 99 >
65 <Container fluid> 100 <Container fluid>
66 <Navbar.Brand> 101 <div>
67 {statusMap[readyState]} TTUN 102 <Navbar.Brand>
68 </Navbar.Brand> 103 TTUN
69 <Navbar.Text> 104 </Navbar.Brand>
70 <a href={config.url} target="_blank">{config.url}</a> 105 <Navbar.Text>
71 </Navbar.Text> 106 {`${statusIconMap[readyState]} ${statusTextMap[readyState]}`}
107 </Navbar.Text>
108 </div>
109 <div className="d-flex">
110 <Navbar.Text>
111 <a href={config.url} target="_blank">{config.url}</a>
112 </Navbar.Text>
113 <Navbar.Toggle aria-controls="settings"/>
114 <Navbar.Collapse id="settings" className="ms-2">
115 <Nav>
116 <NavDropdown
117 align="end"
118 title={<Sliders/>}
119 >
120 {
121 settingsMenu.map((item) => {
122 if (item !== null) {
123 const { onClick, icon, label } = item;
124 return (
125 <NavDropdown.Item
126 onClick={onClick}
127 className="d-flex align-items-center"
128 >
129 {icon}
130 <span className="ms-3">{label}</span>
131 </NavDropdown.Item>
132 )
133 } else {
134 return <NavDropdown.Divider />
135 }
136 })
137 }
138 </NavDropdown>
139 </Nav>
140 </Navbar.Collapse>
141 </div>
72 </Container> 142 </Container>
73 </Navbar> 143 </Navbar>
74 144
diff --git a/src/components/Content/Content.tsx b/src/components/Content/Content.tsx
index 0e63f30..95ee444 100644
--- a/src/components/Content/Content.tsx
+++ b/src/components/Content/Content.tsx
@@ -30,9 +30,9 @@ export default function Content({ raw, setRaw, data }: ContentProps): JSX.Elemen
30 <div className={styles.content}> 30 <div className={styles.content}>
31 <Container fluid className="border-bottom"> 31 <Container fluid className="border-bottom">
32 <Row className="py-3"> 32 <Row className="py-3">
33 <Col> 33 <Col className="form-check form-switch ms-3">
34 <input id='raw' type='checkbox' checked={raw} onChange={() => setRaw(!raw)}/> 34 <input className="form-check-input" id='raw' type='checkbox' checked={raw} role="switch" onChange={() => setRaw(!raw)}/>
35 <label htmlFor='raw' className="ps-1">Raw</label> 35 <label htmlFor='raw' className="form-check-label">Raw</label>
36 </Col> 36 </Col>
37 <Col xs="auto"> 37 <Col xs="auto">
38 { 38 {
diff --git a/src/components/Icons/Moon.tsx b/src/components/Icons/Moon.tsx
new file mode 100644
index 0000000..7e3e680
--- /dev/null
+++ b/src/components/Icons/Moon.tsx
@@ -0,0 +1,11 @@
1import * as React from "react";
2
3export function Moon() {
4 return <svg xmlns="http://www.w3.org/2000/svg"
5 width="16" height="16" fill="currentColor"
6 className="bi bi-moon"
7 viewBox="0 0 16 16">
8 <path
9 d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278zM4.858 1.311A7.269 7.269 0 0 0 1.025 7.71c0 4.02 3.279 7.276 7.319 7.276a7.316 7.316 0 0 0 5.205-2.162c-.337.042-.68.063-1.029.063-4.61 0-8.343-3.714-8.343-8.29 0-1.167.242-2.278.681-3.286z"/>
10 </svg>;
11}
diff --git a/src/components/Icons/Sliders.tsx b/src/components/Icons/Sliders.tsx
new file mode 100644
index 0000000..9feef34
--- /dev/null
+++ b/src/components/Icons/Sliders.tsx
@@ -0,0 +1,10 @@
1import * as React from "react";
2
3export function Sliders() {
4 return <svg xmlns="http://www.w3.org/2000/svg" width="16"
5 height="16" fill="currentColor"
6 className="bi bi-sliders" viewBox="0 0 16 16">
7 <path fill-rule="evenodd"
8 d="M11.5 2a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zM9.05 3a2.5 2.5 0 0 1 4.9 0H16v1h-2.05a2.5 2.5 0 0 1-4.9 0H0V3h9.05zM4.5 7a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zM2.05 8a2.5 2.5 0 0 1 4.9 0H16v1H6.95a2.5 2.5 0 0 1-4.9 0H0V8h2.05zm9.45 4a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zm-2.45 1a2.5 2.5 0 0 1 4.9 0H16v1h-2.05a2.5 2.5 0 0 1-4.9 0H0v-1h9.05z"/>
9 </svg>;
10}
diff --git a/src/components/Icons/Sun.tsx b/src/components/Icons/Sun.tsx
new file mode 100644
index 0000000..93a5187
--- /dev/null
+++ b/src/components/Icons/Sun.tsx
@@ -0,0 +1,9 @@
1import * as React from "react";