Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
PRIVATE_KEY=011d4ba8e7b549ee9cd718df4c25abed
RPC_URL_SEPOLIA=https://eth-mainnet.g.alchemy.com/v2/MBGDHRRT3_qjtqKzM2DZk
RPC_URL_FUJI=https://avax-fuji.g.alchemy.com/v2/MBGDHRRT3_qjtqKzM2DZk
ETHERSCAN_KEY=WCU9BD1WA1835GAU9VBTGSPA2DGEPQHYSF
Comment on lines +1 to +4
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Strip secrets from tracked .env.

Lines [1-4] embed a blockchain private key, Alchemy RPC URLs with API keys, and an Etherscan key. These are sensitive credentials that must remain local only. Remove this committed .env, add placeholders/examples instead, rotate every exposed key, and scrub the repository history before merging.

🧰 Tools
🪛 dotenv-linter (3.3.0)

[warning] 1-1: [LeadingCharacter] Invalid leading character detected

(LeadingCharacter)


[warning] 2-2: [LeadingCharacter] Invalid leading character detected

(LeadingCharacter)


[warning] 3-3: [LeadingCharacter] Invalid leading character detected

(LeadingCharacter)


[warning] 3-3: [UnorderedKey] The RPC_URL_FUJI key should go before the RPC_URL_SEPOLIA key

(UnorderedKey)


[warning] 4-4: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)


[warning] 4-4: [LeadingCharacter] Invalid leading character detected

(LeadingCharacter)


[warning] 4-4: [UnorderedKey] The ETHERSCAN_KEY key should go before the PRIVATE_KEY key

(UnorderedKey)

🤖 Prompt for AI Agents
In .env around lines 1 to 4 there are committed secrets (private key, Alchemy
RPC URLs with API keys, and Etherscan key); remove the tracked .env from the
repo, replace it with a .env.example containing placeholder values and usage
notes, add .env to .gitignore so local secrets aren’t committed, rotate/revoke
all exposed credentials immediately (generate new private key and API keys), and
scrub the repository history (use git filter-repo or BFG to remove the secrets
from past commits) before merging; notify the team about key rotation and
provide the new placeholders and instructions for securely injecting the real
values in CI/deploy.

6 changes: 0 additions & 6 deletions blockchain/.env.example

This file was deleted.

4 changes: 0 additions & 4 deletions client/.env.example

This file was deleted.

4 changes: 4 additions & 0 deletions client/.env.lc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
NEXT_PUBLIC_SEPOLIA_RPC_URL = https://eth-mainnet.g.alchemy.com/v2/MBGDHRRT3_qjtqKzM2DZk
NEXT_PUBLIC_AMOY_RPC_URL = https://polygon-amoy.g.alchemy.com/v2/MBGDHRRT3_qjtqKzM2DZk
NEXT_PUBLIC_FUJI_RPC_URL = https://avax-fuji.g.alchemy.com/v2/MBGDHRRT3_qjtqKzM2DZk
NEXT_PUBLIC_PINATA_JWT = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySW5mb3JtYXRpb24iOnsiaWQiOiI3Zjc0NGIzYi03NGZlLTQyOGMtYTY2NS1kMGFjODkwNTE0N2YiLCJlbWFpbCI6ImhlbWFudC5rQGFkeXB1LmVkdS5pbiIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwaW5fcG9saWN5Ijp7InJlZ2lvbnMiOlt7ImRlc2lyZWRSZXBsaWNhdGlvbkNvdW50IjoxLCJpZCI6IkZSQTEifSx7ImRlc2lyZWRSZXBsaWNhdGlvbkNvdW50IjoxLCJpZCI6Ik5ZQzEifV0sInZlcnNpb24iOjF9LCJtZmFfZW5hYmxlZCI6ZmFsc2UsInN0YXR1cyI6IkFDVElWRSJ9LCJhdXRoZW50aWNhdGlvblR5cGUiOiJzY29wZWRLZXkiLCJzY29wZWRLZXlLZXkiOiIzNDRlMDU0ZTRiMDhkZWZjOTlmNiIsInNjb3BlZEtleVNlY3JldCI6IjE2MTcyZWM2YTMyYjVkMTlkZjUzNWE4ZjM2OTZlNzg5NGExMjY4MjViMTBmNTA2OWYzZDM4MWY4ZDBhMWZjNzQiLCJleHAiOjE3OTEzMDUwOTB9.c8lfSqJIUNh4F4DOvys5qI07pMwUc1H91dUBwt8emfI
Comment on lines +1 to +4
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Remove hard-coded credentials immediately.

Lines [1-4] check in live Alchemy API keys and a Pinata JWT. These values grant direct access to third-party services and must never be stored in the repo. Purge the file from git history (or replace with placeholder/env.example) and provision fresh keys that haven’t been exposed.

🧰 Tools
🪛 dotenv-linter (3.3.0)

[warning] 1-1: [SpaceCharacter] The line has spaces around equal sign

(SpaceCharacter)


[warning] 2-2: [SpaceCharacter] The line has spaces around equal sign

(SpaceCharacter)


[warning] 2-2: [UnorderedKey] The NEXT_PUBLIC_AMOY_RPC_URL key should go before the NEXT_PUBLIC_SEPOLIA_RPC_URL key

(UnorderedKey)


[warning] 3-3: [SpaceCharacter] The line has spaces around equal sign

(SpaceCharacter)


[warning] 3-3: [UnorderedKey] The NEXT_PUBLIC_FUJI_RPC_URL key should go before the NEXT_PUBLIC_SEPOLIA_RPC_URL key

(UnorderedKey)


[warning] 4-4: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)


[warning] 4-4: [SpaceCharacter] The line has spaces around equal sign

(SpaceCharacter)


[warning] 4-4: [UnorderedKey] The NEXT_PUBLIC_PINATA_JWT key should go before the NEXT_PUBLIC_SEPOLIA_RPC_URL key

(UnorderedKey)

🤖 Prompt for AI Agents
In client/.env.lc around lines 1-4 you have committed live Alchemy API keys and
a Pinata JWT; remove these secrets immediately, replace the file content with
placeholder variables (or add a client/.env.example) and add client/.env.lc to
.gitignore so no local secrets are committed; purge the sensitive values from
repository history using a tool like git filter-repo or BFG (or follow your
org’s secret-removal procedure), rotate/revoke the exposed Alchemy and Pinata
credentials and provision new keys, notify the team/security and update
deployment/config to use the new secrets (prefer environment-based secret
storage), and add a pre-commit secret scan hook (git-secrets or similar) to
prevent future accidental commits.

25 changes: 14 additions & 11 deletions client/app/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
} from "@heroicons/react/24/outline";
import Web3Connect from "../Helper/Web3Connect";
import Image from "next/image";
import ThemeToggle from "../ThemeToggle/ThemeToggle";

const menuItems = [
{ name: "Home", href: "/", icon: HomeIcon },
Expand All @@ -29,7 +30,7 @@ const Header = () => {
return (
<>
<motion.header
className="bg-white border-b border-gray-200 fixed w-full z-30 shadow-sm"
className="bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700 fixed w-full z-30 shadow-sm"
initial={{ y: -100 }}
animate={{ y: 0 }}
transition={{ type: "spring", stiffness: 300, damping: 30 }}
Expand All @@ -44,7 +45,7 @@ const Header = () => {
src="/aossie.png"
alt="Agora Blockchain"
/>
<h1 className="ml-3 text-xl font-bold text-gray-800 hidden sm:block">
<h1 className="ml-3 text-xl font-bold text-gray-800 dark:text-gray-100 hidden sm:block">
Agora Blockchain
</h1>
</Link>
Expand All @@ -56,9 +57,9 @@ const Header = () => {
<motion.button
className={`inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md ${
pathname === item.href
? "text-indigo-600"
: "text-gray-700 hover:text-indigo-600"
} bg-white hover:bg-gray-50`}
? "text-indigo-600 dark:text-indigo-400"
: "text-gray-700 dark:text-gray-300 hover:text-indigo-600 dark:hover:text-indigo-400"
} bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700`}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
Expand All @@ -67,7 +68,7 @@ const Header = () => {
</motion.button>
{pathname === item.href && (
<motion.div
className="absolute bottom-0 left-0 right-0 h-0.5 bg-indigo-600"
className="absolute bottom-0 left-0 right-0 h-0.5 bg-indigo-600 dark:bg-indigo-400"
layoutId="underline"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
Expand All @@ -76,19 +77,21 @@ const Header = () => {
)}
</Link>
))}
<ThemeToggle />
<div className="hidden lg:block">
<Web3Connect />
</div>
</nav>

{/* Mobile/Tablet Menu Button */}
<div className="lg:hidden flex items-center space-x-2">
<ThemeToggle />
<div className="scale-90">
<Web3Connect />
</div>
<button
onClick={toggleSidebar}
className="p-2 rounded-md text-gray-600 hover:text-gray-900 hover:bg-gray-100"
className="p-2 rounded-md text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700"
>
<Bars3Icon className="h-6 w-6" />
</button>
Expand All @@ -109,7 +112,7 @@ const Header = () => {
onClick={toggleSidebar}
/>
<motion.div
className="fixed right-0 top-0 h-full w-72 bg-white z-50 shadow-lg"
className="fixed right-0 top-0 h-full w-72 bg-white dark:bg-gray-900 z-50 shadow-lg"
initial={{ x: "100%" }}
animate={{ x: 0 }}
exit={{ x: "100%" }}
Expand All @@ -118,7 +121,7 @@ const Header = () => {
<div className="p-6">
<button
onClick={toggleSidebar}
className="absolute top-4 right-4 p-2 rounded-md text-gray-600 hover:text-gray-900 hover:bg-gray-100"
className="absolute top-4 right-4 p-2 rounded-md text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-800"
>
<XMarkIcon className="h-6 w-6" />
</button>
Expand All @@ -130,8 +133,8 @@ const Header = () => {
onClick={toggleSidebar}
className={`flex items-center p-4 rounded-lg transition-colors ${
pathname === item.href
? "bg-indigo-50 text-indigo-600"
: "text-gray-700 hover:bg-gray-50"
? "bg-indigo-50 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400"
: "text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800"
}`}
>
<item.icon className="h-6 w-6 mr-4" />
Expand Down
26 changes: 26 additions & 0 deletions client/app/components/ThemeProvider/ThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"use client";

import React, { useEffect } from "react";
import { useThemeStore } from "@/app/store/themeStore";

export default function ThemeProvider({
children,
}: {
children: React.ReactNode;
}) {
const theme = useThemeStore((state) => state.theme);

useEffect(() => {
// Apply theme class to html element
const root = document.documentElement;
if (theme === "dark") {
root.classList.add("dark");
root.setAttribute("data-theme", "dark");
} else {
root.classList.remove("dark");
root.setAttribute("data-theme", "light");
}
}, [theme]);

return <>{children}</>;
}
61 changes: 61 additions & 0 deletions client/app/components/ThemeToggle/ThemeToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"use client";

import React, { useEffect } from "react";
import { motion } from "framer-motion";
import { SunIcon, MoonIcon } from "@heroicons/react/24/outline";
import { useThemeStore } from "@/app/store/themeStore";

const ThemeToggle = () => {
const { theme, toggleTheme } = useThemeStore();

useEffect(() => {
// Apply theme to document
if (theme === "dark") {
document.documentElement.classList.add("dark");
document.documentElement.setAttribute("data-theme", "dark");
} else {
document.documentElement.classList.remove("dark");
document.documentElement.setAttribute("data-theme", "light");
}
}, [theme]);
Comment on lines +11 to +20
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Remove duplicate theme application logic.

The useEffect in ThemeToggle directly manipulates document.documentElement, but per the PR's AI summary, ThemeProvider (client/app/components/ThemeProvider/ThemeProvider.tsx) is responsible for applying the theme class and data-theme attribute to the document root. This duplicates the theme application logic, violating single responsibility and potentially causing synchronization issues.

The ThemeToggle should only call toggleTheme from the store; the provider should react to store changes and apply the theme.

Apply this diff to remove the duplicate logic:

-  useEffect(() => {
-    // Apply theme to document
-    if (theme === "dark") {
-      document.documentElement.classList.add("dark");
-      document.documentElement.setAttribute("data-theme", "dark");
-    } else {
-      document.documentElement.classList.remove("dark");
-      document.documentElement.setAttribute("data-theme", "light");
-    }
-  }, [theme]);
-
   return (

Verify that ThemeProvider handles theme application:


🏁 Script executed:

#!/bin/bash
# Verify ThemeProvider applies the theme to document root

rg -A 10 -B 2 'documentElement' client/app/components/ThemeProvider/ThemeProvider.tsx

Length of output: 358


Remove duplicate theme application in ThemeToggle
ThemeToggle’s useEffect duplicates ThemeProvider’s DOM updates. Delete lines 11–20 so ThemeToggle only calls toggleTheme, and let ThemeProvider handle applying the dark class and data-theme attribute.

-  useEffect(() => {
-    // Apply theme to document
-    if (theme === "dark") {
-      document.documentElement.classList.add("dark");
-      document.documentElement.setAttribute("data-theme", "dark");
-    } else {
-      document.documentElement.classList.remove("dark");
-      document.documentElement.setAttribute("data-theme", "light");
-    }
-  }, [theme]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useEffect(() => {
// Apply theme to document
if (theme === "dark") {
document.documentElement.classList.add("dark");
document.documentElement.setAttribute("data-theme", "dark");
} else {
document.documentElement.classList.remove("dark");
document.documentElement.setAttribute("data-theme", "light");
}
}, [theme]);
🤖 Prompt for AI Agents
In client/app/components/ThemeToggle/ThemeToggle.tsx around lines 11 to 20,
remove the useEffect block that applies the theme to document (the DOM updates
adding/removing the "dark" class and setting data-theme) so ThemeToggle no
longer manipulates the DOM; leave the component to only call toggleTheme and
rely on ThemeProvider to apply the "dark" class and data-theme attribute.


return (
<motion.button
onClick={toggleTheme}
className="relative inline-flex items-center justify-center p-2 rounded-lg bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors"
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
aria-label="Toggle theme"
title={`Switch to ${theme === "light" ? "dark" : "light"} mode`}
>
<motion.div
initial={false}
animate={{
rotate: theme === "dark" ? 180 : 0,
scale: theme === "dark" ? 0 : 1,
}}
transition={{ duration: 0.3 }}
className="absolute"
>
<SunIcon className="h-5 w-5 text-yellow-500" />
</motion.div>
<motion.div
initial={false}
animate={{
rotate: theme === "dark" ? 0 : -180,
scale: theme === "dark" ? 1 : 0,
}}
transition={{ duration: 0.3 }}
className="absolute"
>
<MoonIcon className="h-5 w-5 text-indigo-400" />
</motion.div>
{/* Invisible spacer to maintain button size */}
<div className="h-5 w-5 opacity-0">
<SunIcon />
</div>
</motion.button>
);
};

export default ThemeToggle;
38 changes: 19 additions & 19 deletions client/app/create/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,15 @@ const CreatePage: React.FC = () => {
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
className="h-screen w-full bg-gradient-to-br pt-[50px] from-gray-100 to-gray-200 flex flex-col items-center justify-start p-4 overflow-y-auto"
className="h-screen w-full bg-gradient-to-br pt-[50px] from-gray-100 to-gray-200 dark:from-gray-800 dark:to-gray-900 flex flex-col items-center justify-start p-4 overflow-y-auto"
>
<motion.div
initial={{ y: 20, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ delay: 0.2, duration: 0.5 }}
className="w-full max-w-2xl bg-white rounded-3xl shadow-2xl p-8 space-y-8 my-12"
className="w-full max-w-2xl bg-white dark:bg-gray-800 rounded-3xl shadow-2xl p-8 space-y-8 my-12"
>
<h2 className="text-3xl font-extrabold text-gray-800 mb-6 text-center">
<h2 className="text-3xl font-extrabold text-gray-800 dark:text-gray-100 mb-6 text-center">
Create New Election
</h2>
<form onSubmit={createElection} className="space-y-6">
Expand All @@ -132,7 +132,7 @@ const CreatePage: React.FC = () => {
{/* candidate section shows placeholder if empty candidate and allows to add cnadidates*/ }
<div className="space-y-4">
<div className="flex justify-between items-center">
<h3 className="text-lg font-medium text-gray-900">Candidates</h3>
<h3 className="text-lg font-medium text-gray-900 dark:text-gray-100">Candidates</h3>
<motion.button
type="button"
onClick={addCandidate}
Expand All @@ -146,19 +146,19 @@ const CreatePage: React.FC = () => {
</div>

{candidates.length === 0 ? (
<p className="text-gray-500 text-sm italic text-center py-4">
No candidates added yet. Click "Add Candidate" to begin adding candidates.
<p className="text-gray-500 dark:text-gray-400 text-sm italic text-center py-4">
No candidates added yet. Click &quot;Add Candidate&quot; to begin adding candidates.
</p>
) : (
candidates.map((candidate, index) => (
<motion.div
key={index}
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
className="p-4 border border-gray-200 rounded-lg space-y-3"
className="p-4 border border-gray-200 dark:border-gray-700 rounded-lg space-y-3"
>
<div className="flex justify-between items-center">
<h4 className="text-md font-medium text-gray-700">
<h4 className="text-md font-medium text-gray-700 dark:text-gray-300">
Candidate {index + 1}
</h4>
<motion.button
Expand All @@ -176,15 +176,15 @@ const CreatePage: React.FC = () => {
value={candidate.name}
onChange={(e) => updateCandidate(index, "name", e.target.value)}
placeholder="Candidate Name"
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
className="block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
required
/>
<textarea
value={candidate.description}
onChange={(e) => updateCandidate(index, "description", e.target.value)}
placeholder="Candidate Description"
rows={2}
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
className="block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
required
/>
</motion.div>
Expand All @@ -193,14 +193,14 @@ const CreatePage: React.FC = () => {
</div>

<div className="space-y-2">
<label className="block text-sm font-medium text-gray-700">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
Voting Type
</label>
<div className="flex items-center space-x-2">
<select
value={selectedBallot}
onChange={handleBallotChange}
className="block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
className="block w-full px-3 py-2 bg-white dark:bg-gray-700 dark:text-gray-100 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
>
{Object.entries(ballotTypeMap).map(([key, value]) => (
<option key={key} value={key}>
Expand Down Expand Up @@ -256,14 +256,14 @@ const InputField: React.FC<InputFieldProps> = ({
animate={{ x: 0, opacity: 1 }}
transition={{ delay: 0.3, duration: 0.5 }}
>
<label htmlFor={name} className="block text-sm font-medium text-gray-700">
<label htmlFor={name} className="block text-sm font-medium text-gray-700 dark:text-gray-300">
{label}
</label>
<input
type="text"
name={name}
id={name}
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
className="block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
placeholder={placeholder}
required
/>
Expand All @@ -281,14 +281,14 @@ const TextareaField: React.FC<InputFieldProps> = ({
animate={{ x: 0, opacity: 1 }}
transition={{ delay: 0.4, duration: 0.5 }}
>
<label htmlFor={name} className="block text-sm font-medium text-gray-700">
<label htmlFor={name} className="block text-sm font-medium text-gray-700 dark:text-gray-300">
{label}
</label>
<textarea
name={name}
id={name}
rows={4}
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
className="block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
placeholder={placeholder}
required
></textarea>
Expand All @@ -307,7 +307,7 @@ const DatePickerField: React.FC<DatePickerFieldProps> = ({
label,
}) => (
<div className="space-y-1">
<label className="block text-sm font-medium text-gray-700">{label}</label>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">{label}</label>
<DatePicker
value={value}
placement="topStart"
Expand Down Expand Up @@ -338,9 +338,9 @@ const ChainSwitchModal: React.FC<ChainSwitchModalProps> = ({ onSwitch }) => (
initial={{ scale: 0.9, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ type: "spring", stiffness: 300, damping: 30 }}
className="bg-white rounded-lg p-8 shadow-xl text-center"
className="bg-white dark:bg-gray-800 rounded-lg p-8 shadow-xl text-center"
>
<p className="text-xl mb-4 text-gray-800">
<p className="text-xl mb-4 text-gray-800 dark:text-gray-100">
Creating Elections is supported only on Sepolia
</p>
<motion.button
Expand Down
18 changes: 18 additions & 0 deletions client/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ body {
background-color: #ffffff;
margin: 0;
overflow: hidden;
transition: background-color 0.3s ease;
}

.dark body {
background-color: #1a1a1a;
}

html {
Expand All @@ -23,13 +28,26 @@ html {
border-radius: 4px;
}

.dark ::-webkit-scrollbar-track {
background: #2a2a2a;
}

/* Scrollbar thumb */
::-webkit-scrollbar-thumb {
background-color: #cfcaca;
border-radius: 1px;
border: 2px solid #f0f0f0;
}

.dark ::-webkit-scrollbar-thumb {
background-color: #4a4a4a;
border: 2px solid #2a2a2a;
}

::-webkit-scrollbar-thumb:hover {
background-color: #ebe4e4;
}

.dark ::-webkit-scrollbar-thumb:hover {
background-color: #5a5a5a;
}
Loading