diff options
| author | 2022-01-25 21:42:51 +0100 | |
|---|---|---|
| committer | 2022-01-25 22:06:58 +0100 | |
| commit | f9cd68181137c72e92c6951efd9b8d29c4b73bc1 (patch) | |
| tree | a58451fb140d9c5ea023a45bd393127519a7918f /src/components | |
| parent | 2f27e222add9bf10b55971ab915ac411e81d24f0 (diff) | |
| download | client-f9cd68181137c72e92c6951efd9b8d29c4b73bc1.tar.gz client-f9cd68181137c72e92c6951efd9b8d29c4b73bc1.tar.bz2 client-f9cd68181137c72e92c6951efd9b8d29c4b73bc1.zip | |
Added dark mode
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/App/App.tsx | 94 | ||||
| -rw-r--r-- | src/components/Content/Content.tsx | 6 | ||||
| -rw-r--r-- | src/components/Icons/Moon.tsx | 11 | ||||
| -rw-r--r-- | src/components/Icons/Sliders.tsx | 10 | ||||
| -rw-r--r-- | src/components/Icons/Sun.tsx | 9 | ||||
| -rw-r--r-- | src/components/Icons/Trash.tsx | 13 |
6 files changed, 128 insertions, 15 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 @@ | |||
| 1 | import * as React from "react"; | 1 | import * as React from "react"; |
| 2 | import {useEffect, useMemo, useState} from "react"; | 2 | import {ReactElement, useEffect, useMemo, useState} from "react"; |
| 3 | import useRequests, { | 3 | import useRequests, { |
| 4 | ReadyState, | 4 | ReadyState, |
| 5 | RequestResponse | 5 | RequestResponse |
| @@ -9,13 +9,24 @@ import styles from './App.module.scss'; | |||
| 9 | import Details from "../Details/Details"; | 9 | import Details from "../Details/Details"; |
| 10 | import RequestSummary from "../RequestSummary/RequestSummary"; | 10 | import RequestSummary from "../RequestSummary/RequestSummary"; |
| 11 | import {getHost} from "../../utils"; | 11 | import {getHost} from "../../utils"; |
| 12 | import {Container, ListGroup, Navbar} from "react-bootstrap"; | 12 | import {Container, ListGroup, Nav, Navbar, NavDropdown} from "react-bootstrap"; |
| 13 | import classNames from "classnames"; | 13 | import classNames from "classnames"; |
| 14 | import useDarkMode from "../../hooks/useDarkMode"; | ||
| 15 | import {Sliders} from "../Icons/Sliders"; | ||
| 16 | import {Sun} from "../Icons/Sun"; | ||
| 17 | import {Moon} from "../Icons/Moon"; | ||
| 18 | import Trash from "../Icons/Trash"; | ||
| 14 | 19 | ||
| 15 | interface Config { | 20 | interface Config { |
| 16 | url: string | 21 | url: string |
| 17 | } | 22 | } |
| 18 | 23 | ||
| 24 | interface SettingsMenu { | ||
| 25 | icon: ReactElement, | ||
| 26 | label: string, | ||
| 27 | onClick: () => void, | ||
| 28 | } | ||
| 29 | |||
| 19 | type ReadyStateMap = { | 30 | type 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 | ||
| 26 | const statusMap: ReadyStateMap = { | 37 | const 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 | ||
| 33 | export default function App() { | 44 | const statusTextMap: ReadyStateMap = { |
| 45 | [ReadyState.CONNECTING]: 'Connecting...', | ||
| 46 | [ReadyState.OPEN]: 'Connected', | ||
| 47 | [ReadyState.CLOSING]: 'Closing...', | ||
| 48 | [ReadyState.CLOSED]: 'Closed', | ||
| 49 | } | ||
| 34 | 50 | ||
| 51 | export 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 @@ | |||
| 1 | import * as React from "react"; | ||
| 2 | |||
| 3 | export 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 @@ | |||
| 1 | import * as React from "react"; | ||
| 2 | |||
| 3 | export 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 @@ | |||
| 1 | import * as React from "react"; | ||
| 2 | |||
| 3 | export function Sun() { | ||
| 4 | return <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" | ||
| 5 | fill="currentColor" className="bi bi-sun" viewBox="0 0 16 16"> | ||
| 6 | <path | ||
