Skip to content

Commit 2e29fe8

Browse files
authored
Merge pull request #334 from MUFTIATBAKARE/feat/tailwindcss-darkmode
feat: implement tailwindcss dark mode
2 parents 2de86be + d3618de commit 2e29fe8

6 files changed

Lines changed: 189 additions & 177 deletions

File tree

client/src/components/Navbar.tsx

Lines changed: 94 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { useLocation } from "react-router-dom";
44
import logo from "../assets/svg/logo.svg";
55
import tikka from "../assets/svg/Tikka.svg";
66
import WalletButton from "./WalletButton";
7+
import ThemeToggle from "./ThemeToggle";
78
import SignInButton from "./SignInButton";
89
import NotificationBellIcon from "./cards/NotificationBellIcon";
910
import { Search } from "lucide-react";
@@ -14,45 +15,45 @@ import { STELLAR_CONFIG } from "../config/stellar";
1415
const Navbar = ({ onStart }: { onStart?: () => void }) => {
1516
const [open, setOpen] = React.useState(false);
1617
const { isConnected, isWrongNetwork, switchNetwork } = useWalletContext();
17-
18+
1819
const location = useLocation();
1920
const navigate = useNavigate();
2021

2122
const [searchParams] = useSearchParams();
2223
const [searchValue, setSearchValue] = useState(searchParams.get("q") || "");
2324

24-
useEffect(() => {
25-
const delayDebounce = setTimeout(() => {
26-
if (searchValue === "") {
27-
if (location.pathname === "/search") {
28-
navigate("/home");
25+
useEffect(() => {
26+
const delayDebounce = setTimeout(() => {
27+
if (searchValue === "") {
28+
if (location.pathname === "/search") {
29+
navigate("/home");
30+
}
31+
return;
2932
}
30-
return;
31-
}
3233

33-
// Only search if we aren't on detail/create pages
34-
const isForbiddenPage =
35-
location.pathname === "/details" ||
36-
location.pathname.startsWith("/raffles/") ||
37-
location.pathname === "/create" ||
38-
location.pathname === "/leaderboard" ||
39-
location.pathname === "/my-raffles";
40-
if (searchValue.trim() && !isForbiddenPage) {
41-
navigate(`/search?q=${encodeURIComponent(searchValue.trim())}`);
42-
}
43-
}, 400);
34+
// Only search if we aren't on detail/create pages
35+
const isForbiddenPage =
36+
location.pathname === "/details" ||
37+
location.pathname.startsWith("/raffles/") ||
38+
location.pathname === "/create" ||
39+
location.pathname === "/leaderboard" ||
40+
location.pathname === "/my-raffles";
41+
if (searchValue.trim() && !isForbiddenPage) {
42+
navigate(`/search?q=${encodeURIComponent(searchValue.trim())}`);
43+
}
44+
}, 400);
45+
46+
return () => clearTimeout(delayDebounce);
47+
}, [searchValue, navigate, location.pathname]);
4448

45-
return () => clearTimeout(delayDebounce);
46-
}, [searchValue, navigate, location.pathname]);
4749

50+
useEffect(() => {
51+
const searchRelatedPages = ["/home", "/search"];
52+
if (!searchRelatedPages.includes(location.pathname)) {
53+
setSearchValue(""); // Clear the input field text
54+
}
55+
}, [location.pathname]);
4856

49-
useEffect(() => {
50-
const searchRelatedPages = ["/home", "/search"];
51-
if (!searchRelatedPages.includes(location.pathname)) {
52-
setSearchValue(""); // Clear the input field text
53-
}
54-
}, [location.pathname]);
55-
5657
const navItems = [
5758
{ label: "Discover Raffles", href: "/home" },
5859
{ label: "Create Raffle", href: "/create" },
@@ -64,13 +65,13 @@ useEffect(() => {
6465
const targetNetwork = STELLAR_CONFIG.network.charAt(0).toUpperCase() + STELLAR_CONFIG.network.slice(1);
6566

6667
return (
67-
<header className="w-full fixed-top z-50 bg-[#0B0F1C]/40 backdrop-blur-md">
68+
<header className="w-full fixed-top z-50 bg-white/40 dark:bg-[#0B0F1C]/40 backdrop-blur-md transition-colors duration-300">
6869
<nav className="mx-auto flex max-w-7xl items-center justify-between px-6 py-4 md:px-8">
6970
{/* Left: brand */}
7071
<div className="flex items-center gap-8">
7172
<Link to="/" className="flex items-center gap-3">
72-
<img src={logo} alt="logo" className="h-7 w-auto" />
73-
<img src={tikka} alt="tikka" className="h-5 w-auto mt-1" />
73+
<img src={logo} alt="logo" className="h-7 w-auto invert dark:invert-0" />
74+
<img src={tikka} alt="tikka" className="h-5 w-auto mt-1 invert dark:invert-0" />
7475
</Link>
7576

7677
{/* Desktop Search Bar - Integrated into Brand area */}
@@ -81,28 +82,34 @@ useEffect(() => {
8182
value={searchValue}
8283
onChange={(e) => setSearchValue(e.target.value)}
8384
placeholder="Search raffles..."
84-
className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-2 text-sm text-white placeholder:text-white/40 focus:outline-none focus:ring-1 focus:ring-[#FE3796] transition-all"
85+
className="w-full bg-gray-200 dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-xl px-4 py-2 text-sm text-gray-900 dark:text-white placeholder:text-gray-600 dark:text-white/40 focus:outline-none focus:ring-1 focus:ring-[#FE3796] transition-all"
8586
/>
86-
<Search
87+
<Search
8788
size={18}
88-
className="absolute right-4 top-1/2 -translate-y-1/2 text-white"
89+
className="absolute right-4 top-1/2 -translate-y-1/2 text-gray-900 dark:text-white"
8990
/>
9091
</div>
91-
92+
9293
</div>
9394
</div>
9495

9596
{/* Desktop nav */}
9697
<div className="hidden items-center gap-2 lg:flex">
97-
{navItems.map((item) => (
98-
<Link
99-
key={item.label}
100-
to={item.href}
101-
className="px-4 py-2 text-sm text-white/80 hover:text-white transition"
102-
>
103-
{item.label}
104-
</Link>
105-
))}
98+
{navItems.map((item) => {
99+
const isActive = location.pathname === item.href;
100+
return (
101+
<Link
102+
key={item.label}
103+
to={item.href}
104+
className={`px-4 py-2 text-sm text-gray-600 dark:transition ${isActive
105+
? "text-white font-semibold"
106+
: "text-white/80 hover:text-gray-900 dark:text-white"
107+
}`}
108+
>
109+
{item.label}
110+
</Link>
111+
);
112+
})}
106113

107114
{isConnected && (
108115
<div className="flex items-center gap-2 mr-2">
@@ -123,39 +130,38 @@ useEffect(() => {
123130
</div>
124131
)}
125132

126-
<div className="flex items-center gap-4">
127-
128-
<WalletButton />
129-
130-
</div>
131-
132-
<NotificationBellIcon raffleId={0} onAuthRequired={() => { /* optionally open sign-in drawer */ }} />
133+
<ThemeToggle />
134+
<WalletButton />
133135
<SignInButton />
134136
</div>
135137

136138
{/* Mobile: hamburger */}
137-
<button
138-
type="button"
139-
onClick={() => setOpen((s: boolean) => !s)}
140-
className="lg:hidden inline-flex items-center justify-center rounded-lg p-2 hover:bg-white/5 focus:outline-none focus:ring-2 focus:ring-white/40 text-white"
141-
>
142-
{!open ? (
143-
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
144-
<path d="M4 7h16M4 12h16M4 17h16" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
145-
</svg>
146-
) : (
147-
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
148-
<path d="M6 6l12 12M18 6l-12 12" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
149-
</svg>
150-
)}
151-
</button>
139+
<div className="flex gap-4">
140+
<button
141+
type="button"
142+
aria-label={open ? "Close navigation menu" : "Open navigation menu"}
143+
onClick={() => setOpen((s: boolean) => !s)}
144+
className="lg:hidden inline-flex items-center justify-center rounded-lg p-2 hover:bg-gray-200 dark:bg-white/5 focus:outline-none focus:ring-2 focus:ring-white/40 text-gray-900 dark:text-white"
145+
>
146+
{!open ? (
147+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
148+
<path d="M4 7h16M4 12h16M4 17h16" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
149+
</svg>
150+
) : (
151+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
152+
<path d="M6 6l12 12M18 6l-12 12" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
153+
</svg>
154+
)}
155+
</button>
156+
</div>
157+
152158
</nav>
153159

154160
{/* Mobile panel */}
155161
<div
156-
className={`lg:hidden overflow-hidden transition-[max-height,opacity] duration-300 bg-[#0B0F1C] ${
157-
open ? "max-h-screen opacity-100" : "max-h-0 opacity-0"
158-
}`}
162+
data-testid="mobile-nav-panel"
163+
className={`lg:hidden overflow-hidden transition-[max-height,opacity,background-color] duration-300 bg-gray-50 dark:bg-[#0B0F1C] ${open ? "max-h-screen opacity-100" : "max-h-0 opacity-0"
164+
}`}
159165
>
160166
<div className="mx-auto flex max-w-7xl flex-col gap-1 px-6 pb-4 md:px-8">
161167
{/* Mobile Search */}
@@ -165,30 +171,37 @@ useEffect(() => {
165171
value={searchValue}
166172
onChange={(e) => setSearchValue(e.target.value)}
167173
placeholder="Search raffles..."
168-
className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white placeholder:text-white/40 focus:outline-none"
174+
className="w-full bg-gray-200 dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-xl px-4 py-3 text-gray-900 dark:text-white placeholder:text-gray-600 dark:text-white/40 focus:outline-none"
169175
/>
170176
</div>
171177

172-
{navItems.map((item) => (
173-
<Link
174-
key={item.label}
175-
to={item.href}
176-
className="rounded-lg px-3 py-3 text-sm text-white/90 hover:bg-white/5"
177-
onClick={() => setOpen(false)}
178-
>
179-
{item.label}
180-
</Link>
181-
))}
178+
{navItems.map((item) => {
179+
const isActive = location.pathname === item.href;
180+
return (
181+
<Link
182+
key={item.label}
183+
to={item.href}
184+
className={`rounded-lg px-3 py-3 text-sm transition ${isActive
185+
? "text-white font-semibold bg-white/10"
186+
: "text-gray-600 dark:text-white/90 hover:bg-gray-200 dark:bg-white/5"
187+
}`}
188+
onClick={() => setOpen(false)}
189+
>
190+
{item.label}
191+
</Link>
192+
);
193+
})}
182194

183195
<a
184196
onClick={() => {
185197
setOpen(false);
186198
if (onStart) onStart();
187199
}}
188-
className="mt-2 rounded-xl px-6 py-3 text-center text-sm font-medium text-white hover:brightness-110 bg-[#FE3796] cursor-pointer"
200+
className="mt-2 rounded-xl px-6 py-3 text-center text-sm font-medium text-gray-900 dark:text-white hover:brightness-110 bg-[#FE3796] cursor-pointer"
189201
>
190202
Get Started
191203
</a>
204+
<ThemeToggle />
192205
</div>
193206
</div>
194207
</header>

client/src/components/create-raffle/ImageStep.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,8 @@ const ImageStep: React.FC<StepComponentProps> = ({
284284
onClick={onNext}
285285
disabled={!canContinue}
286286
className={`px-6 py-3 rounded-lg font-medium transition-colors duration-200 ${canContinue
287-
? "bg-[#FF389C] hover:bg-[#FF389C]/90 text-gray-900 dark:text-white"
288-
: "bg-gray-600 text-gray-400 cursor-not-allowed"
287+
? "bg-[#FF389C] hover:bg-[#FF389C]/90 text-gray-900 dark:text-white"
288+
: "bg-gray-600 text-gray-400 cursor-not-allowed"
289289
}`}
290290
>
291291
Continue

client/src/components/landing/TrendingRaffles.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const RaffleCardWrapper: React.FC<{
5353

5454
if (error || !raffle) {
5555
return (
56-
<div className="w-full bg-[#11172E] p-4 rounded-3xl">
56+
<div className="w-full bg-white dark:bg-[#11172E] p-4 rounded-3xl">
5757
<ErrorMessage
5858
variant="inline"
5959
title={`Error loading raffle #${raffleId}`}

client/src/components/monitor/LatencyGraph.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,10 @@ export default function LatencyGraph({ latencyData, onRangeChange }: LatencyGrap
4848
<button
4949
key={range.label}
5050
onClick={() => handleRangeClick(range)}
51-
className={`px-3 py-1 rounded text-sm font-medium transition-colors ${
52-
activeRange === range.label
51+
className={`px-3 py-1 rounded text-sm font-medium transition-colors ${activeRange === range.label
5352
? 'bg-indigo-600 text-gray-900 dark:text-white'
5453
: 'bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-600'
55-
}`}
54+
}`}
5655
>
5756
{range.label}
5857
</button>

client/src/pages/RafflePage.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ const RafflePage = () => {
249249
{isActive ? (
250250
<div className="space-y-4">
251251
<div className="flex items-center justify-between bg-black/20 p-1.5 rounded-xl border border-gray-200 dark:border-white/5">
252-
<button
252+
<button
253253
onClick={handleDecrement}
254254
className="w-10 h-10 rounded-lg flex items-center justify-center bg-gray-200 dark:bg-white/5 hover:bg-gray-300 dark:bg-white/10 text-gray-900 dark:text-white transition-colors"
255255
>
@@ -264,7 +264,7 @@ const RafflePage = () => {
264264
</button>
265265
</div>
266266

267-
<button
267+
<button
268268
className="w-full py-4 rounded-xl font-black text-gray-900 dark:text-white tracking-wider shadow-lg shadow-[#FE3796]/20 hover:scale-[1.02] active:scale-[0.98] transition-all"
269269
style={{
270270
background: "linear-gradient(100.92deg, #FE3796 13.57%, #3931F9 97.65%)"

0 commit comments

Comments
 (0)