diff --git a/src/interface/web/app/agents/layout.tsx b/src/interface/web/app/agents/layout.tsx
index 04855b43..26935325 100644
--- a/src/interface/web/app/agents/layout.tsx
+++ b/src/interface/web/app/agents/layout.tsx
@@ -2,6 +2,7 @@ import type { Metadata } from "next";
import { noto_sans, noto_sans_arabic } from "@/app/fonts";
import "../globals.css";
import { ContentSecurityPolicy } from "../common/layoutHelper";
+import { ThemeProvider } from "../components/providers/themeProvider";
export const metadata: Metadata = {
title: "Khoj AI - Agents",
@@ -40,8 +41,26 @@ export default function RootLayout({
}>) {
return (
+
+
+
- {children}
+
+
+ {children}
+
+
);
}
diff --git a/src/interface/web/app/agents/page.tsx b/src/interface/web/app/agents/page.tsx
index 3ef2abaf..532af822 100644
--- a/src/interface/web/app/agents/page.tsx
+++ b/src/interface/web/app/agents/page.tsx
@@ -20,7 +20,7 @@ import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "@/components
import LoginPrompt from "../components/loginPrompt/loginPrompt";
import { InlineLoading } from "../components/loading/loading";
import { Alert, AlertDescription } from "@/components/ui/alert";
-import { useIsMobileWidth } from "../common/utils";
+import { useIsDarkMode, useIsMobileWidth } from "../common/utils";
import {
AgentCard,
EditAgentSchema,
diff --git a/src/interface/web/app/chat/layout.tsx b/src/interface/web/app/chat/layout.tsx
index 25579510..8a97bb9b 100644
--- a/src/interface/web/app/chat/layout.tsx
+++ b/src/interface/web/app/chat/layout.tsx
@@ -2,6 +2,7 @@ import type { Metadata } from "next";
import { noto_sans, noto_sans_arabic } from "@/app/fonts";
import "../globals.css";
import { ContentSecurityPolicy } from "../common/layoutHelper";
+import { ThemeProvider } from "../components/providers/themeProvider";
export const metadata: Metadata = {
title: "Khoj AI - Chat",
@@ -40,14 +41,30 @@ export default function RootLayout({
}>) {
return (
-
-
- {children}
+
+
+
+
+
+ {children}
+
+
);
diff --git a/src/interface/web/app/common/utils.ts b/src/interface/web/app/common/utils.ts
index 55df7a35..b3520c00 100644
--- a/src/interface/web/app/common/utils.ts
+++ b/src/interface/web/app/common/utils.ts
@@ -89,6 +89,40 @@ export const useMutationObserver = (
}, [ref, callback, options])
}
+export function useIsDarkMode() {
+ const [darkMode, setDarkMode] = useState(false);
+ const [initialLoadDone, setInitialLoadDone] = useState(false);
+
+ useEffect(() => {
+ if (localStorage.getItem("theme") === "dark") {
+ document.documentElement.classList.add("dark");
+ setDarkMode(true);
+ } else if (localStorage.getItem("theme") === "light") {
+ document.documentElement.classList.remove("dark");
+ setDarkMode(false);
+ } else {
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
+ if (mq.matches) {
+ document.documentElement.classList.add("dark");
+ setDarkMode(true);
+ }
+ }
+ setInitialLoadDone(true);
+ }, []);
+
+ useEffect(() => {
+ if (!initialLoadDone) return;
+ if (darkMode) {
+ document.documentElement.classList.add("dark");
+ } else {
+ document.documentElement.classList.remove("dark");
+ }
+ localStorage.setItem("theme", darkMode ? "dark" : "light");
+ }, [darkMode, initialLoadDone]);
+
+ return [darkMode, setDarkMode] as const;
+}
+
export const convertBytesToText = (fileSize: number) => {
if (fileSize < 1024) {
return `${fileSize} B`;
diff --git a/src/interface/web/app/components/appSidebar/appSidebar.tsx b/src/interface/web/app/components/appSidebar/appSidebar.tsx
index 6916a621..85901371 100644
--- a/src/interface/web/app/components/appSidebar/appSidebar.tsx
+++ b/src/interface/web/app/components/appSidebar/appSidebar.tsx
@@ -22,7 +22,7 @@ import { useEffect, useState } from "react";
import AllConversations from "../allConversations/allConversations";
import FooterMenu from "../navMenu/navMenu";
import { useSidebar } from "@/components/ui/sidebar";
-import { useIsMobileWidth } from "@/app/common/utils";
+import { useIsDarkMode, useIsMobileWidth } from "@/app/common/utils";
import { UserPlusIcon } from "lucide-react";
import { useAuthenticatedData, UserProfile } from "@/app/common/auth";
import LoginPrompt from "../loginPrompt/loginPrompt";
diff --git a/src/interface/web/app/components/navMenu/navMenu.tsx b/src/interface/web/app/components/navMenu/navMenu.tsx
index 583ffdad..f86cf6ee 100644
--- a/src/interface/web/app/components/navMenu/navMenu.tsx
+++ b/src/interface/web/app/components/navMenu/navMenu.tsx
@@ -13,7 +13,7 @@ import {
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Moon, Sun, UserCircle, Question, ArrowRight, Code, BuildingOffice } from "@phosphor-icons/react";
-import { useIsMobileWidth } from "@/app/common/utils";
+import { useIsDarkMode, useIsMobileWidth } from "@/app/common/utils";
import LoginPrompt from "../loginPrompt/loginPrompt";
import { Button } from "@/components/ui/button";
import { SidebarMenu, SidebarMenuButton, SidebarMenuItem } from "@/components/ui/sidebar";
@@ -49,44 +49,10 @@ export default function FooterMenu({ sideBarIsOpen }: NavMenuProps) {
error: authenticationError,
isLoading: authenticationLoading,
} = useAuthenticatedData();
- const [darkMode, setDarkMode] = useState(false);
- const [initialLoadDone, setInitialLoadDone] = useState(false);
+ const [darkMode, setDarkMode] = useIsDarkMode();
const [showLoginPrompt, setShowLoginPrompt] = useState(false);
const isMobileWidth = useIsMobileWidth();
- useEffect(() => {
- if (localStorage.getItem("theme") === "dark") {
- document.documentElement.classList.add("dark");
- setDarkMode(true);
- } else if (localStorage.getItem("theme") === "light") {
- document.documentElement.classList.remove("dark");
- setDarkMode(false);
- } else {
- const mq = window.matchMedia("(prefers-color-scheme: dark)");
-
- if (mq.matches) {
- document.documentElement.classList.add("dark");
- setDarkMode(true);
- }
- }
-
- setInitialLoadDone(true);
- }, []);
-
- useEffect(() => {
- if (!initialLoadDone) return;
- toggleDarkMode(darkMode);
- }, [darkMode, initialLoadDone]);
-
- function toggleDarkMode(darkMode: boolean) {
- if (darkMode) {
- document.documentElement.classList.add("dark");
- } else {
- document.documentElement.classList.remove("dark");
- }
- localStorage.setItem("theme", darkMode ? "dark" : "light");
- }
-
const menuItems = [
{
title: "Help",
diff --git a/src/interface/web/app/components/providers/themeProvider.tsx b/src/interface/web/app/components/providers/themeProvider.tsx
new file mode 100644
index 00000000..9ec14f59
--- /dev/null
+++ b/src/interface/web/app/components/providers/themeProvider.tsx
@@ -0,0 +1,8 @@
+'use client'
+
+import { useIsDarkMode } from '@/app/common/utils'
+
+export function ThemeProvider({ children }: { children: React.ReactNode }) {
+ const [darkMode, setDarkMode] = useIsDarkMode();
+ return <>{children}>;
+}
diff --git a/src/interface/web/app/layout.tsx b/src/interface/web/app/layout.tsx
index 3d2cd4f7..b825f4ac 100644
--- a/src/interface/web/app/layout.tsx
+++ b/src/interface/web/app/layout.tsx
@@ -2,6 +2,7 @@ import type { Metadata } from "next";
import { noto_sans, noto_sans_arabic } from "@/app/fonts";
import "./globals.css";
import { ContentSecurityPolicy } from "./common/layoutHelper";
+import { ThemeProvider } from "./components/providers/themeProvider";
export const metadata: Metadata = {
title: "Khoj AI - Ask Anything",
@@ -48,8 +49,26 @@ export default function RootLayout({
}>) {
return (
+
+
+
- {children}
+
+
+ {children}
+
+
);
}
diff --git a/src/interface/web/app/page.tsx b/src/interface/web/app/page.tsx
index f0a3ee1e..7380cf8c 100644
--- a/src/interface/web/app/page.tsx
+++ b/src/interface/web/app/page.tsx
@@ -25,7 +25,6 @@ import {
stepOneSuggestions,
StepTwoSuggestion,
getStepTwoSuggestions,
- SuggestionType,
} from "@/app/components/suggestions/suggestionsData";
import LoginPrompt from "@/app/components/loginPrompt/loginPrompt";
diff --git a/src/interface/web/app/search/layout.tsx b/src/interface/web/app/search/layout.tsx
index cdb0976f..88187302 100644
--- a/src/interface/web/app/search/layout.tsx
+++ b/src/interface/web/app/search/layout.tsx
@@ -3,6 +3,7 @@ import type { Metadata } from "next";
import "../globals.css";
import { ContentSecurityPolicy } from "../common/layoutHelper";
import { Toaster } from "@/components/ui/toaster";
+import { ThemeProvider } from "../components/providers/themeProvider";
export const metadata: Metadata = {
title: "Khoj AI - Search",
@@ -35,10 +36,25 @@ export default function RootLayout({
}>) {
return (
+
+
+
- {children}
-
+
+ {children}
+
);
diff --git a/src/interface/web/app/settings/layout.tsx b/src/interface/web/app/settings/layout.tsx
index 7a33477c..fc0f2604 100644
--- a/src/interface/web/app/settings/layout.tsx
+++ b/src/interface/web/app/settings/layout.tsx
@@ -4,6 +4,7 @@ import "../globals.css";
import { Toaster } from "@/components/ui/toaster";
import { ContentSecurityPolicy } from "../common/layoutHelper";
import { ChatwootWidget } from "../components/chatWoot/ChatwootWidget";
+import { ThemeProvider } from "../components/providers/themeProvider";
export const metadata: Metadata = {
title: "Khoj AI - Settings",
@@ -40,11 +41,27 @@ export default function RootLayout({
}>) {
return (
+
+
+
- {children}
-
-
+
+ {children}
+
+
+
);
diff --git a/src/interface/web/app/share/chat/layout.tsx b/src/interface/web/app/share/chat/layout.tsx
index 17433009..7373de25 100644
--- a/src/interface/web/app/share/chat/layout.tsx
+++ b/src/interface/web/app/share/chat/layout.tsx
@@ -2,6 +2,7 @@ import type { Metadata } from "next";
import { noto_sans, noto_sans_arabic } from "@/app/fonts";
import "../../globals.css";
import { ContentSecurityPolicy } from "@/app/common/layoutHelper";
+import { ThemeProvider } from "@/app/components/providers/themeProvider";
export const metadata: Metadata = {
title: "Khoj AI - Ask Anything",
@@ -40,14 +41,30 @@ export default function RootLayout({
}>) {
return (
-
-
- {children}
+
+
+
+
+
+ {children}
+
+
);