Skip to content

Commit 2ae2b8b

Browse files
authored
feat: dark mode (#32)
* feat: dark mode config * remove dark:* classes from shadcn * fix: global color style * fix: stroke color for select * feat: move dark mode to new hook * fix: other dark mode fixes * fix: many dark mode fixes * feat: add dark mode checkbox to the playground * fix: unite colors with console * fix: darkmode bug with modals * fix: overflow * refactor: rename "darkMode" to "theme" for clarity
1 parent d75de19 commit 2ae2b8b

29 files changed

+976
-157
lines changed

src/components/databrowser/components/display/delete-alert-dialog.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export function DeleteAlertDialog({
4242
<AlertDialogFooter>
4343
<AlertDialogCancel type="button">Cancel</AlertDialogCancel>
4444
<AlertDialogAction
45-
className="bg-red-500 text-gray-50 hover:bg-red-600"
45+
className="bg-red-500 text-zinc-50 hover:bg-red-600"
4646
onClick={onDeleteConfirm}
4747
>
4848
Yes, Delete

src/components/databrowser/components/display/display-simple.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ const EditorDisplayForm = ({
6363
{type === "json" ? <div /> : selector}
6464
</div>
6565

66-
<div className="grow rounded-md border border-zinc-300 bg-white p-1">{editor}</div>
66+
<div className="grow rounded-md border border-zinc-300 bg-white p-1 dark:!bg-[#192321]">
67+
{editor}
68+
</div>
6769
</div>
6870

6971
<div className="flex shrink-0 items-center gap-2">

src/components/databrowser/components/display/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export const DataDisplay = () => {
1818
) : !type ? (
1919
query.isLoading ? (
2020
<div className="flex h-full items-center justify-center">
21-
<span className="text-gray-500">Loading...</span>
21+
<span className="text-zinc-500">Loading...</span>
2222
</div>
2323
) : (
2424
<div />

src/components/databrowser/components/display/input/custom-editor.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useEffect, useRef } from "react"
2+
import { useTheme } from "@/dark-mode-context"
23
import { useTab } from "@/tab-provider"
34
import { Editor, useMonaco } from "@monaco-editor/react"
45

@@ -23,6 +24,7 @@ export const CustomEditor = ({
2324
const { active } = useTab()
2425
const monaco = useMonaco()
2526
const editorRef = useRef()
27+
const theme = useTheme()
2628

2729
useEffect(() => {
2830
if (!active || !monaco || !editorRef.current) {
@@ -35,6 +37,7 @@ export const CustomEditor = ({
3537

3638
const editor = (
3739
<Editor
40+
theme={theme === "dark" ? "vs-dark" : "light"}
3841
loading={undefined}
3942
onMount={(editor) => {
4043
// @ts-expect-error not typing the editor type
@@ -68,7 +71,9 @@ export const CustomEditor = ({
6871
scrollBeyondLastLine: false,
6972
renderLineHighlight: "none",
7073
unusualLineTerminators: "auto",
74+
padding: { top: 0, bottom: 0 },
7175
}}
76+
className="[&_.monaco-editor-background]:!bg-transparent [&_.monaco-editor]:!bg-transparent"
7277
/>
7378
)
7479

src/components/databrowser/components/sidebar/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export function Sidebar() {
2828
<div className="flex gap-1">
2929
<Button
3030
aria-label="Refresh"
31-
className="h-7 w-7 px-0"
31+
className="h-7 w-7 px-0 text-zinc-500"
3232
onClick={() => {
3333
queryClient.invalidateQueries({
3434
queryKey: [FETCH_KEYS_QUERY_KEY],

src/components/databrowser/components/sidebar/keys-list.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useTab } from "@/tab-provider"
12
import type { DataType, RedisKey } from "@/types"
23

34
import { cn } from "@/lib/utils"
@@ -6,7 +7,6 @@ import { TypeTag } from "@/components/databrowser/components/type-tag"
67

78
import { useKeys } from "../../hooks/use-keys"
89
import { SidebarContextMenu } from "../sidebar-context-menu"
9-
import { useTab } from "@/tab-provider"
1010

1111
export const KeysList = () => {
1212
const { keys } = useKeys()

src/components/databrowser/components/sidebar/search-input.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ export const SearchInput = () => {
134134
type="button"
135135
variant="link"
136136
size="icon"
137-
className="absolute right-1 top-1/2 h-5 w-5 -translate-y-1/2 text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100"
137+
className="absolute right-1 top-1/2 h-5 w-5 -translate-y-1/2 text-zinc-500 hover:text-zinc-900"
138138
onClick={() => {
139139
setSearchKey("")
140140
setState("")

src/components/databrowser/components/type-tag.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ import { cva, type VariantProps } from "class-variance-authority"
1313
import { cn } from "@/lib/utils"
1414

1515
const iconsMap = {
16-
string: <IconQuote size={15} stroke={1.3} />,
17-
set: <IconLayersIntersect size={15} stroke={1.3} />,
18-
hash: <IconHash size={15} stroke={1.3} />,
19-
json: <IconCodeDots size={15} stroke={1.3} />,
20-
zset: <IconArrowsSort size={15} stroke={1.3} />,
21-
list: <IconList size={15} stroke={1.3} />,
22-
stream: <IconList size={15} stroke={1.3} />,
16+
string: <IconQuote size={15} stroke={1.2} />,
17+
set: <IconLayersIntersect size={15} stroke={1.2} />,
18+
hash: <IconHash size={15} stroke={1.2} />,
19+
json: <IconCodeDots size={15} stroke={1.2} />,
20+
zset: <IconArrowsSort size={15} stroke={1.2} />,
21+
list: <IconList size={15} stroke={1.2} />,
22+
stream: <IconList size={15} stroke={1.2} />,
2323
} as const
2424

2525
const tagVariants = cva("inline-flex shrink-0 items-center rounded-md justify-center", {

src/components/databrowser/index.tsx

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import "@/globals.css"
22

33
import { useEffect, useMemo, useRef } from "react"
4+
import { DarkModeProvider, useTheme, type DarkModeOption } from "@/dark-mode-context"
45
import { RedisProvider, type RedisCredentials } from "@/redis-context"
56
import type { TabId } from "@/store"
67
import { DatabrowserProvider, useDatabrowserStore } from "@/store"
@@ -9,6 +10,7 @@ import { TooltipProvider } from "@radix-ui/react-tooltip"
910
import { QueryClientProvider } from "@tanstack/react-query"
1011

1112
import { queryClient } from "@/lib/clients"
13+
import { portalWrapper } from "@/lib/portal-root"
1214

1315
import { DatabrowserInstance } from "./components/databrowser-instance"
1416
import { DatabrowserTabs } from "./components/databrowser-tabs"
@@ -27,6 +29,7 @@ export const RedisBrowser = ({
2729
hideTabs,
2830
storage,
2931
onFullScreenClick,
32+
theme = "light",
3033
}: RedisCredentials & {
3134
hideTabs?: boolean
3235

@@ -49,6 +52,21 @@ export const RedisBrowser = ({
4952
* ```
5053
*/
5154
storage?: RedisBrowserStorage
55+
56+
/**
57+
* Theme configuration (light or dark).
58+
*
59+
* @default "light"
60+
* @example
61+
* ```tsx
62+
* // Light mode (default)
63+
* <RedisBrowser theme="light" />
64+
*
65+
* // Dark mode
66+
* <RedisBrowser theme="dark" />
67+
* ```
68+
*/
69+
theme?: DarkModeOption
5270
}) => {
5371
const credentials = useMemo(() => ({ token, url }), [token, url])
5472
const rootRef = useRef<HTMLDivElement>(null)
@@ -60,24 +78,53 @@ export const RedisBrowser = ({
6078
return (
6179
<QueryClientProvider client={queryClient}>
6280
<RedisProvider redisCredentials={credentials}>
63-
<DatabrowserProvider storage={storage} rootRef={rootRef}>
64-
<TooltipProvider>
65-
{/* ups-db is the custom class used to prefix every style in the css bundle */}
66-
<div
67-
className="ups-db"
68-
style={{ height: "100%", display: "flex", flexDirection: "column" }}
69-
ref={rootRef}
70-
>
71-
{!hideTabs && <DatabrowserTabs onFullScreenClick={onFullScreenClick} />}
72-
<DatabrowserInstances />
73-
</div>
74-
</TooltipProvider>
75-
</DatabrowserProvider>
81+
<DarkModeProvider theme={theme}>
82+
<DatabrowserProvider storage={storage} rootRef={rootRef}>
83+
<TooltipProvider>
84+
<RedisBrowserRoot
85+
hideTabs={hideTabs}
86+
rootRef={rootRef}
87+
onFullScreenClick={onFullScreenClick}
88+
/>
89+
</TooltipProvider>
90+
</DatabrowserProvider>
91+
</DarkModeProvider>
7692
</RedisProvider>
7793
</QueryClientProvider>
7894
)
7995
}
8096

97+
const RedisBrowserRoot = ({
98+
hideTabs,
99+
rootRef,
100+
onFullScreenClick,
101+
}: {
102+
hideTabs?: boolean
103+
rootRef: React.RefObject<HTMLDivElement>
104+
onFullScreenClick?: () => void
105+
}) => {
106+
const theme = useTheme()
107+
108+
useEffect(() => {
109+
portalWrapper.classList.add("text-zinc-700")
110+
portalWrapper.classList.toggle("dark", theme === "dark")
111+
}, [theme])
112+
113+
return (
114+
/* ups-db is the custom class used to prefix every style in the css bundle */
115+
<div
116+
className={`ups-db ${theme === "dark" ? "dark" : ""}`}
117+
style={{ height: "100%" }}
118+
ref={rootRef}
119+
>
120+
<div className="flex h-full flex-col text-zinc-700">
121+
{!hideTabs && <DatabrowserTabs onFullScreenClick={onFullScreenClick} />}
122+
<DatabrowserInstances />
123+
</div>
124+
</div>
125+
)
126+
}
127+
81128
const DatabrowserInstances = () => {
82129
const { tabs, selectedTab, selectTab, addTab } = useDatabrowserStore()
83130

src/components/ui/alert-dialog.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const AlertDialogOverlay = React.forwardRef<
2020
>(({ className, ...props }, ref) => (
2121
<AlertDialogPrimitive.Overlay
2222
className={cn(
23-
"fixed inset-0 z-50 bg-white/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 dark:bg-zinc-950/80",
23+
"fixed inset-0 z-50 bg-white/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
2424
className
2525
)}
2626
{...props}
@@ -38,8 +38,8 @@ const AlertDialogContent = React.forwardRef<
3838
<AlertDialogPrimitive.Content
3939
ref={ref}
4040
className={cn(
41-
"antialiased data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0" +
42-
" fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-zinc-200 bg-white p-6 shadow-lg duration-200 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] dark:border-zinc-800 dark:bg-zinc-950 sm:rounded-lg md:w-full",
41+
"antialiased data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 " +
42+
" data-[state=open]:slide-in-from-top-[48%]sm:rounded-lg fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-zinc-200 bg-white p-6 shadow-lg duration-200 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 md:w-full",
4343
className
4444
)}
4545
{...props}
@@ -79,7 +79,7 @@ const AlertDialogDescription = React.forwardRef<
7979
>(({ className, ...props }, ref) => (
8080
<AlertDialogPrimitive.Description
8181
ref={ref}
82-
className={cn("text-sm text-zinc-500 dark:text-zinc-400", className)}
82+
className={cn("text-sm text-zinc-500", className)}
8383
{...props}
8484
/>
8585
))

0 commit comments

Comments
 (0)