Skip to content

Commit f300066

Browse files
authored
Merge pull request #45 from clidey/hk/feature/darkmode
[Feature] Add dark mode
2 parents c268831 + 38cb293 commit f300066

29 files changed

+197
-91
lines changed

frontend/src/App.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@ import { map } from "lodash";
22
import { Navigate, Route, Routes } from "react-router-dom";
33
import { Notifications } from './components/notifications';
44
import { InternalRoutes, PrivateRoute, PublicRoutes, getRoutes } from './config/routes';
5+
import { useAppSelector } from "./store/hooks";
6+
import classNames from "classnames";
57

68
export const App = () => {
9+
const darkModeEnabled = useAppSelector(state => state.global.theme === "dark");
710
return (
8-
<div className="h-[100vh] w-[100vw]">
11+
<div className={classNames("h-[100vh] w-[100vw]", {
12+
"dark": darkModeEnabled,
13+
})} id="whodb-app-container">
914
<Notifications />
1015
<Routes>
1116
<Route path="/" element={<PrivateRoute />}>

frontend/src/app.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@ import { map } from "lodash";
22
import { Navigate, Route, Routes } from "react-router-dom";
33
import { Notifications } from './components/notifications';
44
import { InternalRoutes, PrivateRoute, PublicRoutes, getRoutes } from './config/routes';
5+
import { useAppSelector } from "./store/hooks";
6+
import classNames from "classnames";
57

68
export const App = () => {
9+
const darkModeEnabled = useAppSelector(state => state.global.theme === "dark");
710
return (
8-
<div className="h-[100vh] w-[100vw]">
11+
<div className={classNames("h-[100vh] w-[100vw]", {
12+
"dark": darkModeEnabled,
13+
})} id="whodb-app-container">
914
<Notifications />
1015
<Routes>
1116
<Route path="/" element={<PrivateRoute />}>

frontend/src/components/breadcrumbs.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@ export const Breadcrumb: FC<IBreadcrumbProps> = ({ routes, active }) => {
1919
{
2020
routes.map((route, i) => (
2121
<li>
22-
<div className="flex items-center transition-all gap-2 hover:gap-3 group/breadcrumb">
22+
<div className="flex items-center transition-all gap-2 hover:gap-3 group/breadcrumb dark:text-neutral-300">
2323
{i > 0 && Icons.RightChevron}
24-
<div onClick={() => handleNavigate(route.path)} className={classNames("cursor-pointer text-sm font-medium text-gray-700 hover:text-teal-500 flex items-center gap-2 hover:gap-3 transition-all", {
25-
"text-teal-800": active === route,
24+
<div onClick={() => handleNavigate(route.path)} className={classNames("cursor-pointer text-sm font-medium text-gray-700 hover:text-teal-500 flex items-center gap-2 hover:gap-3 transition-all dark:text-neutral-300", {
25+
"text-teal-800 dark:text-teal-500": active === route,
2626
})}>
2727
{
2828
i === 0 &&
29-
<div className="inline-flex items-center text-sm font-medium text-gray-700">
29+
<div className="inline-flex items-center text-sm font-medium text-gray-700 dark:text-neutral-300">
3030
{cloneElement(Icons.Home, {
3131
className: classNames("w-3 h-3 group-hover/breadcrumb:fill-teal-500", {
32-
"fill-teal-800": active === route,
32+
"fill-teal-800 dark:fill-teal-500": active === route,
3333
})
3434
})
3535
}

frontend/src/components/button.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ export type IButtonProps = {
1515
}
1616

1717
export const Button: FC<IButtonProps> = (props) => {
18-
return <motion.button className={twMerge(classNames("rounded-lg border flex justify-center items-center text-xs px-2 py-1 cursor-pointer gap-1 bg-white hover:bg-gray-100", props.className, {
18+
return <motion.button className={twMerge(classNames("rounded-lg border flex justify-center items-center text-xs px-2 py-1 cursor-pointer gap-1 bg-white hover:bg-gray-100 dark:bg-white/10 dark:hover:bg-white/15 dark:border-white/20 dark:backdrop-blur-md", props.className, {
1919
"cursor-not-allowed": props.disabled,
2020
"h-[35px] rounded-[4px] gap-2 hover:gap-3": props.type === "lg",
2121
}))} onClick={props.onClick} disabled={props.disabled} whileTap={{ scale: 0.8 }}>
22-
<div className={classNames("text-xs text-gray-600", props.labelClassName)}>
22+
<div className={classNames("text-xs text-gray-600 dark:text-neutral-100", props.labelClassName)}>
2323
{props.label}
2424
</div>
2525
{cloneElement(props.icon, {
26-
className: classNames("w-4 h-4 stroke-gray-600", props.iconClassName),
26+
className: classNames("w-4 h-4 stroke-gray-600 dark:stroke-white", props.iconClassName),
2727
})}
2828
</motion.button>
2929
}
@@ -45,12 +45,12 @@ export type IActionButtonProps = {
4545
export const ActionButton: FC<IActionButtonProps> = ({ onClick, icon, className, containerClassName, disabled, children }) => {
4646
return (
4747
<div className="group relative">
48-
<motion.button className={twMerge(classNames("rounded-full bg-white h-12 w-12 transition-all border border-gray-300 shadow-sm flex items-center justify-center", containerClassName, {
48+
<motion.button className={twMerge(classNames("rounded-full bg-white border-gray-200 dark:bg-white/10 dark:border-white/5 dark:backdrop-blur-sm h-12 w-12 transition-all border shadow-sm flex items-center justify-center", containerClassName, {
4949
"cursor-not-allowed": disabled,
5050
"hover:shadow-lg hover:cursor-pointer hover:scale-110": !disabled,
5151
}))} onClick={disabled ? undefined : onClick} whileTap={{ scale: 0.6, transition: { duration: 0.05 }, }}>
5252
{cloneElement(icon, {
53-
className: twMerge(classNames("w-8 h-8 stroke-gray-500 cursor-pointer", className))
53+
className: twMerge(classNames("w-8 h-8 stroke-neutral-500 cursor-pointer dark:stroke-neutral-300", className))
5454
})}
5555
</motion.button>
5656
{children}

frontend/src/components/card.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ type ICardProps = {
3131

3232
export const Icon: FC<ICardIcon> = memo((propsIcon) => (<div
3333
className={twMerge(classNames(
34-
"h-[40px] w-[40px] rounded-lg flex justify-center items-center shadow border",
34+
"h-[40px] w-[40px] rounded-lg flex justify-center items-center shadow border dark:border-white/5",
3535
propsIcon.bgClassName
3636
))}
3737
>
@@ -73,7 +73,7 @@ export const Card: FC<ICardProps> = ({
7373
<motion.div
7474
className={twMerge(
7575
classNames(
76-
"bg-white h-[200px] w-[200px] rounded-3xl shadow-sm border p-4 flex flex-col justify-between relative transition-all duration-300 overflow-y-auto",
76+
"bg-white h-[200px] w-[200px] rounded-3xl shadow-sm border p-4 flex flex-col justify-between relative transition-all duration-300 overflow-y-auto dark:bg-white/10 dark:border-white/5",
7777
{
7878
"shadow-2xl z-10": highlightStatus,
7979
},
@@ -85,7 +85,7 @@ export const Card: FC<ICardProps> = ({
8585
<Loading loadingText={loadingText} />
8686
) : (
8787
<>
88-
<div className="flex justify-between items-start">
88+
<div className="flex justify-between items-start dark:text-neutral-300">
8989
{icon}
9090
{tag}
9191
</div>

frontend/src/components/classes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export const BASE_CARD_CLASS = "bg-white h-[200px] w-[200px] rounded-3xl shadow-sm border p-4 flex flex-col justify-between";
1+
export const BASE_CARD_CLASS = "bg-white h-[200px] w-[200px] rounded-3xl shadow-sm border p-4 flex flex-col justify-between dark:bg-white/10 dark:border-white/5";
22
export const BRAND_COLOR = "text-[#ca6f1e]";

frontend/src/components/common.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ type IEmptyMessageProps = {
88

99
export const EmptyMessage: FC<IEmptyMessageProps> = ({ icon, label }) => {
1010
return (
11-
<div className="flex gap-2 items-center justify-center absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
11+
<div className="flex gap-2 items-center justify-center absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 dark:text-neutral-300">
1212
{icon}
1313
{label}
1414
</div>
@@ -20,5 +20,5 @@ interface PortalProps {
2020
}
2121

2222
export const Portal: FC<PortalProps> = ({ children }) => {
23-
return createPortal(children, document.body);
23+
return createPortal(children, document.querySelector("#whodb-app-container")!);
2424
};

frontend/src/components/dropdown.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export type IDropdownProps = {
2525
noItemsLabel?: string;
2626
}
2727

28-
const ITEM_CLASS = "group/item flex items-center gap-1 transition-all cursor-pointer relative hover:bg-black/10 py-1 mx-2 px-4 rounded-lg pl-1";
28+
const ITEM_CLASS = "group/item flex items-center gap-1 transition-all cursor-pointer relative hover:bg-black/10 py-1 mx-2 px-4 rounded-lg pl-1 dark:text-neutral-300/100";
2929

3030
export const Dropdown: FC<IDropdownProps> = (props) => {
3131
const [hover, setHover] = useState(false);
@@ -46,15 +46,15 @@ export const Dropdown: FC<IDropdownProps> = (props) => {
4646
return (
4747
<button className={classNames("relative", props.className)} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
4848
{props.loading ? <Loading hideText={true} /> :
49-
<> <div className="flex justify-between items-center border border-gray-200 rounded-lg w-full p-1 h-[34px] px-2">
50-
<div className="flex gap-1 text-gray-700 text-sm truncate items-center">
49+
<> <div className="flex justify-between items-center border border-gray-200 rounded-lg w-full p-1 h-[34px] px-2 dark:bg-white/10 dark:border-white/20">
50+
<div className="flex gap-1 text-gray-700 text-sm truncate items-center dark:text-neutral-300">
5151
{props.value?.icon} {props.value?.label}
5252
</div>
5353
{cloneElement(Icons.DownCaret, {
5454
className: "w-4 h-4 stroke-gray-600",
5555
})}
5656
</div>
57-
<div className={classNames("absolute z-10 divide-y rounded-lg shadow bg-white py-1 border border-gray-200 overflow-y-auto max-h-40", {
57+
<div className={classNames("absolute z-10 divide-y rounded-lg shadow bg-white py-1 border border-gray-200 overflow-y-auto max-h-40 dark:bg-white/10 dark:backdrop-blur-md dark:border-white/20", {
5858
"hidden": !hover,
5959
"block animate-fade": hover,
6060
"w-fit min-w-[200px]": !props.fullWidth,

frontend/src/components/editor.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ import MarkdownPreview from "@uiw/react-markdown-preview";
33
import classNames from "classnames";
44
import { KeyCode, editor, languages } from "monaco-editor";
55
import { FC, cloneElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
6+
import ReactJson from 'react-json-view';
7+
import { useAppSelector } from "../store/hooks";
68
import { Icons } from "./icons";
79
import { Loading } from "./loading";
8-
import ReactJson from 'react-json-view';
910

1011
languages.register({ id: 'markdown' });
1112
languages.register({ id: 'json' });
@@ -24,6 +25,7 @@ type ICodeEditorProps = {
2425
export const CodeEditor: FC<ICodeEditorProps> = ({ value, setValue, language, options = {}, onRun, defaultShowPreview, disabled }) => {
2526
const [showPreview, setShowPreview] = useState(defaultShowPreview);
2627
const editorRef = useRef<editor.IStandaloneCodeEditor>();
28+
const darkModeEnabled = useAppSelector(state => state.global.theme === "dark");
2729

2830
const handleEditorDidMount: OnMount = useCallback(editor => {
2931
editorRef.current = editor;
@@ -81,8 +83,9 @@ export const CodeEditor: FC<ICodeEditorProps> = ({ value, setValue, language, op
8183
width="100%"
8284
language={language}
8385
value={value}
86+
theme={darkModeEnabled ? "vs-dark" : "light"}
8487
onChange={handleChange}
85-
loading={<div className="flex justify-center items-center h-full w-full bg-white p-2 rounded-full">
88+
loading={<div className="flex justify-center items-center h-full w-full p-2 rounded-md">
8689
<Loading hideText={true} />
8790
</div>}
8891
options={{
@@ -95,7 +98,7 @@ export const CodeEditor: FC<ICodeEditorProps> = ({ value, setValue, language, op
9598
}}
9699
onMount={handleEditorDidMount}
97100
/>;
98-
}, [disabled, handleChange, handleEditorDidMount, language, options, showPreview, value]);
101+
}, [darkModeEnabled, disabled, handleChange, handleEditorDidMount, language, options, showPreview, value]);
99102

100103
const actionButtons = useMemo(() => {
101104
return <button className="transition-all cursor-pointer hover:scale-110 hover:bg-gray-100/50 rounded-full p-1" onClick={handlePreviewToggle}>

frontend/src/components/graph/edge.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,15 @@ export const GraphEdgeConnectionLine: FC<ConnectionLineComponentProps> = ({ toX,
3030
<g>
3131
<path
3232
fill="none"
33-
stroke="#222"
33+
className="stroke-neutral-800 dark:stroke-neutral-300 animated"
3434
strokeWidth={1.5}
35-
className="animated"
3635
d={edgePath}
3736
/>
3837
<circle
38+
className="fill-white stroke-neutral-800 dark:stroke-neutral-300"
3939
cx={toX}
4040
cy={toY}
41-
fill="#fff"
4241
r={3}
43-
stroke="#222"
4442
strokeWidth={1.5}
4543
/>
4644
</g>

0 commit comments

Comments
 (0)