diff --git a/client/package-lock.json b/client/package-lock.json
index 165d073..8105223 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -21,6 +21,7 @@
"react-icons": "^5.5.0",
"react-router-dom": "^6.30.1",
"recharts": "^3.0.2",
+ "styled-components": "^6.1.19",
"tailwindcss": "^4.1.10"
},
"devDependencies": {
@@ -318,6 +319,27 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@emotion/is-prop-valid": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz",
+ "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/memoize": "^0.8.1"
+ }
+ },
+ "node_modules/@emotion/memoize": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
+ "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/unitless": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz",
+ "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==",
+ "license": "MIT"
+ },
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
@@ -2345,6 +2367,12 @@
"@types/react": "^19.0.0"
}
},
+ "node_modules/@types/stylis": {
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz",
+ "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==",
+ "license": "MIT"
+ },
"node_modules/@types/trusted-types": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
@@ -2556,6 +2584,15 @@
"node": ">=6"
}
},
+ "node_modules/camelize": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
+ "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/caniuse-lite": {
"version": "1.0.30001723",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001723.tgz",
@@ -2715,6 +2752,15 @@
"node": ">= 8"
}
},
+ "node_modules/css-color-keywords": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
+ "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
@@ -2724,11 +2770,21 @@
"utrie": "^1.0.2"
}
},
+ "node_modules/css-to-react-native": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
+ "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "camelize": "^1.0.0",
+ "css-color-keywords": "^1.0.0",
+ "postcss-value-parser": "^4.0.2"
+ }
+ },
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
- "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "devOptional": true
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"node_modules/d3-array": {
"version": "3.2.4",
@@ -4014,6 +4070,7 @@
"version": "0.522.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.522.0.tgz",
"integrity": "sha512-jnJbw974yZ7rQHHEFKJOlWAefG3ATSCZHANZxIdx8Rk/16siuwjgA4fBULpXEAWx/RlTs3FzmKW/udWUuO0aRw==",
+ "license": "ISC",
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
@@ -4259,6 +4316,12 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "license": "MIT"
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -4564,6 +4627,12 @@
"semver": "bin/semver.js"
}
},
+ "node_modules/shallowequal": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
+ "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==",
+ "license": "MIT"
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -4638,6 +4707,74 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/styled-components": {
+ "version": "6.1.19",
+ "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.19.tgz",
+ "integrity": "sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/is-prop-valid": "1.2.2",
+ "@emotion/unitless": "0.8.1",
+ "@types/stylis": "4.2.5",
+ "css-to-react-native": "3.2.0",
+ "csstype": "3.1.3",
+ "postcss": "8.4.49",
+ "shallowequal": "1.1.0",
+ "stylis": "4.3.2",
+ "tslib": "2.6.2"
+ },
+ "engines": {
+ "node": ">= 16"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/styled-components"
+ },
+ "peerDependencies": {
+ "react": ">= 16.8.0",
+ "react-dom": ">= 16.8.0"
+ }
+ },
+ "node_modules/styled-components/node_modules/postcss": {
+ "version": "8.4.49",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
+ "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.7",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/styled-components/node_modules/tslib": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
+ "license": "0BSD"
+ },
+ "node_modules/stylis": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz",
+ "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==",
+ "license": "MIT"
+ },
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
diff --git a/client/package.json b/client/package.json
index 9ef6783..944bfbc 100644
--- a/client/package.json
+++ b/client/package.json
@@ -23,6 +23,7 @@
"react-icons": "^5.5.0",
"react-router-dom": "^6.30.1",
"recharts": "^3.0.2",
+ "styled-components": "^6.1.19",
"tailwindcss": "^4.1.10"
},
"devDependencies": {
diff --git a/client/src/App.jsx b/client/src/App.jsx
index 7ebc50c..fdf995f 100644
--- a/client/src/App.jsx
+++ b/client/src/App.jsx
@@ -28,6 +28,7 @@ function App() {
);
+
}
export default App;
diff --git a/client/src/components/ThemeToggle.jsx b/client/src/components/ThemeToggle.jsx
new file mode 100644
index 0000000..be49f68
--- /dev/null
+++ b/client/src/components/ThemeToggle.jsx
@@ -0,0 +1,35 @@
+import { useEffect, useState } from "react";
+import { Moon, Sun } from "lucide-react";
+
+const ThemeToggle = () => {
+
+ const [isDarkMode, setIsDarkMode] = useState(false);
+
+ useEffect(() => {
+ if( localStorage.getItem('theme') === 'dark' ){
+ document.documentElement.classList.add('dark');
+ setIsDarkMode(true);
+ }
+
+ },[])
+ const toggleTheme = () => {
+ if(isDarkMode){
+ document.documentElement.classList.remove('dark');
+ localStorage.setItem('theme', 'light');
+ setIsDarkMode(false);
+ }else{
+ document.documentElement.classList.add('dark');
+ localStorage.setItem('theme', 'dark');
+ setIsDarkMode(true);
+ }
+ }
+ return (
+
+ )
+};
+
+export default ThemeToggle;
\ No newline at end of file
diff --git a/client/src/components/TopBar.jsx b/client/src/components/TopBar.jsx
new file mode 100644
index 0000000..d6460ae
--- /dev/null
+++ b/client/src/components/TopBar.jsx
@@ -0,0 +1,88 @@
+import React, { useEffect } from "react";
+import { ArrowBigUp } from "lucide-react";
+import Styled from "styled-components";
+
+const OnTopBar = () => {
+ const [isvisible, setIsVisible] = React.useState(false);
+ const [scrollProgress, setScrollProgress] = React.useState(0);
+
+ const onTopbtn = () => {
+ window.scrollTo({
+ top: 0,
+ left: 0,
+ behavior: "smooth",
+ });
+ };
+
+ // Updated scroll handler to calculate progress
+ const handleScroll = () => {
+ const winScroll = document.documentElement.scrollTop;
+ const height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
+ const scrolled = (winScroll / height) * 100;
+
+ setScrollProgress(scrolled);
+
+ if (window.scrollY > 100) {
+ setIsVisible(true);
+ } else {
+ setIsVisible(false);
+ }
+ };
+
+ useEffect(() => {
+ window.addEventListener("scroll", handleScroll);
+ return () => {
+ window.removeEventListener("scroll", handleScroll);
+ };
+ }, []);
+
+ return (
+
+
+ {isvisible && (
+
+ )}
+
+ );
+};
+
+const Container = Styled.section`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+
+ .progress-bar {
+ position: fixed;
+ top: 0;
+ left: 0;
+ height: 2px;
+ background: #00abff;
+
+ }
+
+ .on-top-bar {
+ position: fixed;
+ bottom: 20px;
+ right: 18px;
+ background-color: #fff;
+ color: #1a1a1a;
+ border-radius: 50%;
+ width: 40px;
+ height: 40px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+ transition: background-color 0.2s ease-in-out;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
+
+ &:hover {
+ background-color: #0039ff;
+ }
+ }
+`;
+
+export default OnTopBar;
\ No newline at end of file
diff --git a/client/src/styles/index.css b/client/src/styles/index.css
index 3d0345e..5d298d7 100644
--- a/client/src/styles/index.css
+++ b/client/src/styles/index.css
@@ -31,3 +31,13 @@ html {
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background: #056896;
}
+
+:body {
+ background-color: #1a1a1a;
+ color: #f3f4f6;
+}
+
+.dark {
+ background-color: #f3f4f6;
+ color: #1a1a1a;
+}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..bc817cd
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,6 @@
+{
+ "name": "prepedge-ai",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {}
+}