Skip to content

Commit 00b620b

Browse files
committed
refac[frontend]: split darkModeToggle component
1 parent ea61b71 commit 00b620b

File tree

2 files changed

+53
-43
lines changed

2 files changed

+53
-43
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React, { JSX } from "react"
2+
import { computerIcon, moonIcon, sunIcon } from "../icons.js"
3+
import { Tooltip, TooltipProps } from "@heroui/react"
4+
5+
export type DarkMode = "dark" | "light" | "system"
6+
7+
interface MyComponentProps extends TooltipProps {
8+
mode: DarkMode
9+
onModeChange: (newMode: DarkMode) => void
10+
}
11+
12+
const icons: { name: DarkMode; icon: JSX.Element }[] = [
13+
{ name: "system", icon: computerIcon },
14+
{ name: "dark", icon: moonIcon },
15+
{ name: "light", icon: sunIcon },
16+
]
17+
18+
export function defaultDarkMode(): DarkMode {
19+
const storedDarkModeSelect = localStorage.getItem("darkModeSelect")
20+
21+
if (storedDarkModeSelect !== null && ["light", "dark", "system"].includes(storedDarkModeSelect)) {
22+
return storedDarkModeSelect as DarkMode
23+
} else {
24+
return "system"
25+
}
26+
}
27+
28+
export function shouldBeDark(mode: DarkMode): boolean {
29+
// when matchMedia not available (e.g. in tests), set to light mode
30+
const systemDark = window.matchMedia ? window.matchMedia("(prefers-color-scheme: dark)").matches : false
31+
return mode === "system" ? systemDark : mode === "dark"
32+
}
33+
34+
export function DarkModeToggle({ mode, onModeChange, ...rest }: MyComponentProps) {
35+
return (
36+
<Tooltip content="Toggle Dark Mode" {...rest}>
37+
<span
38+
className="absolute right-0"
39+
data-testid="pastebin-darkmode-toggle"
40+
onClick={() => {
41+
const curModeIdx = icons.findIndex(({ name }) => name === mode)
42+
onModeChange(icons[(curModeIdx + 1) % icons.length].name)
43+
}}
44+
>
45+
{icons.find(({ name }) => name === mode)!.icon}
46+
</span>
47+
</Tooltip>
48+
)
49+
}

frontend/pb.tsx

Lines changed: 4 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ import {
2020
ModalContent,
2121
ModalHeader,
2222
ModalFooter,
23-
Tooltip,
2423
} from "@heroui/react"
2524

2625
import { PasteResponse, parsePath, parseFilenameFromContentDisposition } from "../src/shared.js"
2726

27+
import { DarkModeToggle, DarkMode, defaultDarkMode, shouldBeDark } from "./components/darkModeToggle.js"
28+
2829
import {
2930
verifyExpiration,
3031
verifyManageUrl,
@@ -36,20 +37,9 @@ import {
3637
} from "./utils.js"
3738

3839
import "./style.css"
39-
import { computerIcon, moonIcon, sunIcon } from "./icons.js"
4040

4141
type EditKind = "edit" | "file"
4242
type UploadKind = "short" | "long" | "custom" | "manage"
43-
type DarkMode = "dark" | "light" | "system"
44-
45-
function defaultDarkMode(): DarkMode {
46-
const storedDarkModeSelect = localStorage.getItem("darkModeSelect")
47-
if (storedDarkModeSelect !== null && ["light", "dark", "system"].includes(storedDarkModeSelect)) {
48-
return storedDarkModeSelect as DarkMode
49-
} else {
50-
return "system"
51-
}
52-
}
5343

5444
export function PasteBin() {
5545
const [editKind, setEditKind] = useState<EditKind>("edit")
@@ -72,10 +62,6 @@ export function PasteBin() {
7262

7363
const [darkModeSelect, setDarkModeSelect] = useState<DarkMode>(defaultDarkMode())
7464

75-
// when matchMedia not available (e.g. in tests), set to light mode
76-
const systemDark = window.matchMedia ? window.matchMedia("(prefers-color-scheme: dark)").matches : false
77-
const isDark = darkModeSelect === "system" ? systemDark : darkModeSelect === "dark"
78-
7965
function showModal(err: string, title: string) {
8066
setModalErrMsg(err)
8167
setModalErrTitle(title)
@@ -242,35 +228,10 @@ export function PasteBin() {
242228
}
243229
}
244230

245-
const iconsMap = new Map([
246-
["system", computerIcon],
247-
["dark", moonIcon],
248-
["light", sunIcon],
249-
])
250-
const toggleDarkModeButton = (
251-
<Tooltip content="Toggle Dark Mode">
252-
<span
253-
className="absolute right-0"
254-
data-testid="pastebin-darkmode-toggle"
255-
onClick={() => {
256-
if (darkModeSelect === "system") {
257-
setDarkModeSelect("dark")
258-
} else if (darkModeSelect === "dark") {
259-
setDarkModeSelect("light")
260-
} else {
261-
setDarkModeSelect("system")
262-
}
263-
}}
264-
>
265-
{iconsMap.get(darkModeSelect)}
266-
</span>
267-
</Tooltip>
268-
)
269-
270231
const info = (
271232
<div className="mx-4 lg:mx-0">
272233
<h1 className="text-3xl mt-8 mb-4 relative">
273-
{INDEX_PAGE_TITLE} {toggleDarkModeButton}
234+
{INDEX_PAGE_TITLE} <DarkModeToggle mode={darkModeSelect} onModeChange={setDarkModeSelect} />
274235
</h1>
275236
<p className="my-2">This is an open source pastebin deployed on Cloudflare Workers. </p>
276237
<p className="my-2">
@@ -538,7 +499,7 @@ export function PasteBin() {
538499
data-testid="pastebin-main"
539500
className={
540501
"flex flex-col items-center min-h-screen font-sans bg-background text-foreground" +
541-
(isDark ? " dark" : " light")
502+
(shouldBeDark(darkModeSelect) ? " dark" : " light")
542503
}
543504
>
544505
<div className="grow w-full max-w-[64rem]">

0 commit comments

Comments
 (0)