diff --git a/frontend/app/about/page.tsx b/frontend/app/about/page.tsx
index b231ac9..17f1c65 100644
--- a/frontend/app/about/page.tsx
+++ b/frontend/app/about/page.tsx
@@ -2,6 +2,7 @@ import React from "react";
import Header from "@/components/Header";
import { NumberTicker } from "@/components/NumberTicker";
import { getRepoDetails } from "@/lib/getRepoDetails";
+import IconCloud from "@/components/ui/icon-cloud";
export const revalidate = 1200 // Invalidate the cache every 20 minutes;
@@ -20,7 +21,7 @@ export default async function About() {
Here are some information about our project. Support us with a{" "}
- Star ⭐️ on Github
+ Star ⭐️ on Github
@@ -29,7 +30,7 @@ export default async function About() {
-
+
@@ -37,25 +38,93 @@ export default async function About() {
+
+
+
+
+
+ Our Techstack
+
+
+
+ Here are some information about the techstack we used while developing our project.
+
+
+
+
+
+
+
+
+
+
Backend
+
Languages & Frameworks
+
Python Flask
+
Python Libraries
+
Blinker Click Colorama Flask Itsdangerous
+
Joblib MarkupSafe NLTK NumPy Regex
+
Scikit-learn SciPy Threadpoolctl TQDM
+
Pymongo Langchain_community
+
Langchain_google_genai Fitz Qdrant
+
Python.ENV Jinja2 GROQ Werkzeug
+
+
+
+
+
+
+
Frontend
+
Languages & Frameworks
+
HTML CSS Python TypeScript Next.js
+
Libraries & Tools
+
+ React TailwindCSS PostCSS Lucide CLSx
+
+ RadixUI ESlint ESlint-config-next
+
Utilities
+
JSON NextResponse Vercel
+
diff --git a/frontend/components/ui/icon-cloud.tsx b/frontend/components/ui/icon-cloud.tsx
new file mode 100644
index 0000000..0b55ed1
--- /dev/null
+++ b/frontend/components/ui/icon-cloud.tsx
@@ -0,0 +1,88 @@
+"use client";
+
+import { useEffect, useMemo, useState } from "react";
+import { useTheme } from "next-themes";
+import {
+ Cloud,
+ fetchSimpleIcons,
+ ICloud,
+ renderSimpleIcon,
+ SimpleIcon,
+} from "react-icon-cloud";
+
+export const cloudProps: Omit = {
+ containerProps: {
+ style: {
+ display: "flex",
+ justifyContent: "center",
+ alignItems: "center",
+ width: "88%",
+ paddingTop: 40,
+ },
+ },
+ options: {
+ reverse: true,
+ depth: 1,
+ wheelZoom: false,
+ imageScale: 2,
+ activeCursor: "default",
+ tooltip: "native",
+ initial: [0.1, -0.1],
+ clickToFront: 500,
+ tooltipDelay: 0,
+ outlineColour: "#0000",
+ maxSpeed: 0.04,
+ minSpeed: 0.02,
+ // dragControl: false,
+ },
+};
+
+export const renderCustomIcon = (icon: SimpleIcon, theme: string) => {
+ const bgHex = theme === "light" ? "#f3f2ef" : "#080510";
+ const fallbackHex = theme === "light" ? "#6e6e73" : "#ffffff";
+ const minContrastRatio = theme === "dark" ? 2 : 1.2;
+
+ return renderSimpleIcon({
+ icon,
+ bgHex,
+ fallbackHex,
+ minContrastRatio,
+ size: 42,
+ aProps: {
+ href: undefined,
+ target: undefined,
+ rel: undefined,
+ onClick: (e: any) => e.preventDefault(),
+ },
+ });
+};
+
+export type DynamicCloudProps = {
+ iconSlugs: string[];
+};
+
+type IconData = Awaited>;
+
+export default function IconCloud({ iconSlugs }: DynamicCloudProps) {
+ const [data, setData] = useState(null);
+ const { theme } = useTheme();
+
+ useEffect(() => {
+ fetchSimpleIcons({ slugs: iconSlugs }).then(setData);
+ }, [iconSlugs]);
+
+ const renderedIcons = useMemo(() => {
+ if (!data) return null;
+
+ return Object.values(data.simpleIcons).map((icon) =>
+ renderCustomIcon(icon, theme || "light"),
+ );
+ }, [data, theme]);
+
+ return (
+ //@ts-expect-error this may throw some errors but we're handling it somewhere else
+
+ <>{renderedIcons}>
+
+ );
+}
\ No newline at end of file
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 9d7c7c1..3f0ffbf 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -14,8 +14,10 @@
"framer-motion": "^11.5.6",
"lucide-react": "^0.445.0",
"next": "14.2.13",
+ "next-themes": "^0.3.0",
"react": "^18",
"react-dom": "^18",
+ "react-icon-cloud": "^4.1.4",
"tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7"
},
@@ -41,6 +43,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/@csstools/convert-colors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-2.0.0.tgz",
+ "integrity": "sha512-P7BVvddsP2Wl5v3drJ3ArzpdfXMqoZ/oHOV/yFiGFb3JQr9Z9UXZ9tnHAKJsO89lfprR1F9ExW3Yij21EjEBIA==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/@eslint-community/eslint-utils": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@@ -3314,6 +3324,15 @@
}
}
},
+ "node_modules/next-themes": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz",
+ "integrity": "sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==",
+ "peerDependencies": {
+ "react": "^16.8 || ^17 || ^18",
+ "react-dom": "^16.8 || ^17 || ^18"
+ }
+ },
"node_modules/next/node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
@@ -3856,6 +3875,20 @@
"react": "^18.3.1"
}
},
+ "node_modules/react-icon-cloud": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/react-icon-cloud/-/react-icon-cloud-4.1.4.tgz",
+ "integrity": "sha512-hc8yGNU98V6ObPdeNIt75M016xGMxbTWqB4l6exo1uwE5bvFU095unMbX2K3YBKYhGKEV3c7fSmq3jD3cRWX+A==",
+ "dependencies": {
+ "@csstools/convert-colors": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "react": ">=16"
+ }
+ },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 9c74fcf..c089052 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -14,9 +14,11 @@
"clsx": "^2.1.1",
"framer-motion": "^11.5.6",
"lucide-react": "^0.445.0",
- "next": "14.2.13",
+ "next": "^15.0.1",
+ "next-themes": "^0.3.0",
"react": "^18",
"react-dom": "^18",
+ "react-icon-cloud": "^4.1.4",
"tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7"
},
@@ -30,4 +32,4 @@
"tailwindcss": "^3.4.1",
"typescript": "^5"
}
-}
+}
\ No newline at end of file