diff --git a/package-lock.json b/package-lock.json
index 38d56f9..867e577 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,9 +12,11 @@
"appwrite": "^17.0.1",
"lucide-react": "^0.487.0",
"next": "15.2.4",
+ "next-themes": "^0.4.6",
"postcss": "^8.5.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
+ "react-icons": "^5.5.0",
"tailwindcss": "^4.1.3"
},
"devDependencies": {
@@ -4311,6 +4313,16 @@
}
}
},
+ "node_modules/next-themes": {
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
+ "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc"
+ }
+ },
"node_modules/next/node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
@@ -4701,6 +4713,15 @@
"react": "^19.1.0"
}
},
+ "node_modules/react-icons": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
+ "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
diff --git a/package.json b/package.json
index f985186..f36573f 100644
--- a/package.json
+++ b/package.json
@@ -13,9 +13,11 @@
"appwrite": "^17.0.1",
"lucide-react": "^0.487.0",
"next": "15.2.4",
+ "next-themes": "^0.4.6",
"postcss": "^8.5.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
+ "react-icons": "^5.5.0",
"tailwindcss": "^4.1.3"
},
"devDependencies": {
diff --git a/postcss.config.mjs b/postcss.config.mjs
index bc9198c..a7475b7 100644
--- a/postcss.config.mjs
+++ b/postcss.config.mjs
@@ -1,5 +1,6 @@
const config = {
- plugins: {
+ darkMode: ['class', '[data-theme="dark"]'],
+ plugins: {
"@tailwindcss/postcss": {},
},
};
diff --git a/src/app/client-layout.js b/src/app/client-layout.js
new file mode 100644
index 0000000..5f1dafa
--- /dev/null
+++ b/src/app/client-layout.js
@@ -0,0 +1,79 @@
+'use client';
+import { useState, useEffect } from "react";
+import { account } from "./lib/appwrite";
+import { useRouter } from "next/navigation";
+import Sidebar from "./components/Sidebar";
+import Navbar from "./components/Navbar";
+import { Menu } from 'lucide-react';
+
+export default function ClientLayout({ children }) {
+ const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);
+ const [isMobileOpen, setIsMobileOpen] = useState(false);
+ const [isLoggedIn, setIsLoggedIn] = useState(false);
+ const [loading, setLoading] = useState(true);
+ const router = useRouter();
+
+ useEffect(() => {
+ const checkAuth = async () => {
+ try {
+ await account.get();
+ setIsLoggedIn(true);
+ } catch (error) {
+ setIsLoggedIn(false);
+ router.push('/login');
+ } finally {
+ setLoading(false);
+ }
+ };
+ checkAuth();
+ }, [router]);
+
+ const toggleMobileSidebar = () => {
+ setIsMobileOpen(!isMobileOpen);
+ };
+
+ if (loading) {
+ return
Loading...
;
+ }
+
+ if (!isLoggedIn) {
+ return (
+
+
+ {children}
+
+
+ );
+ }
+
+ return (
+
+ {/* Mobile Toggle Button (outside sidebar) */}
+
+
+
+
+
+ setIsSidebarCollapsed(!isSidebarCollapsed)}
+ />
+
+
+ {children}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/app/components/Navbar.jsx b/src/app/components/Navbar.jsx
index a538cb3..f21c804 100644
--- a/src/app/components/Navbar.jsx
+++ b/src/app/components/Navbar.jsx
@@ -1,34 +1,126 @@
'use client';
+import { useState, useEffect } from "react";
import { account } from "../lib/appwrite";
-import { useRouter } from 'next/navigation';
-import { LogOut } from 'lucide-react';
+import { useRouter } from "next/navigation";
+import { FaUserCircle, FaMoon, FaSun } from "react-icons/fa";
+import { LogOut, Menu } from "lucide-react";
-export default function Navbar() {
+export default function Navbar({ toggleSidebar }) {
const router = useRouter();
+ const [isDropdownOpen, setIsDropdownOpen] = useState(false);
+ const [user, setUser] = useState(null);
+ const [darkMode, setDarkMode] = useState(false);
+
+ // Initialize dark mode from localStorage or system preference
+ useEffect(() => {
+ const savedMode = localStorage.getItem('darkMode');
+ const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
+
+ if (savedMode !== null) {
+ setDarkMode(savedMode === 'true');
+ } else if (systemPrefersDark) {
+ setDarkMode(true);
+ }
+ }, []);
+
+ // Apply dark mode class to document element
+ useEffect(() => {
+ if (darkMode) {
+ document.documentElement.classList.add('dark');
+ localStorage.setItem('darkMode', 'true');
+ } else {
+ document.documentElement.classList.remove('dark');
+ localStorage.setItem('darkMode', 'false');
+ }
+ }, [darkMode]);
+
+ // Toggle dark mode
+ const toggleDarkMode = () => {
+ setDarkMode(!darkMode);
+ };
+
+ // Fetch current user details
+ useEffect(() => {
+ const getUser = async () => {
+ try {
+ const userData = await account.get();
+ setUser(userData);
+ } catch (error) {
+ console.error("Error fetching user:", error);
+ }
+ };
+ getUser();
+ }, []);
const handleLogout = async () => {
try {
- await account.deleteSession('current');
- router.push('/login');
+ await account.deleteSession("current");
+ router.push("/login");
} catch (error) {
- console.error('Logout failed:', error);
+ console.error("Logout failed:", error);
}
};
return (
-