Skip to content

Commit ee41291

Browse files
CopilotJustinhSE
andauthored
Fix 404 nav links, add user dropdown, improve dark mode design
Agent-Logs-Url: https://github.com/Debugging-Disciples/community-software/sessions/24a1b0c8-d097-4eee-98fb-afedc5f4f4ec Co-authored-by: JustinhSE <84724234+JustinhSE@users.noreply.github.com>
1 parent 424f540 commit ee41291

6 files changed

Lines changed: 141 additions & 74 deletions

File tree

app/globals.css

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
@import "tailwindcss";
22

33
@theme {
4-
--color-tech-dark: #000000;
5-
--color-tech-darker: #0a0a0a;
4+
--color-tech-dark: #0f172a;
5+
--color-tech-darker: #0b1220;
6+
--color-tech-surface: #1e293b;
7+
--color-tech-border: rgba(255, 255, 255, 0.08);
68
--color-brand-cyan: #06b6d4;
79
--color-brand-purple: #8b5cf6;
810
--color-tech-blue: #3b82f6;
911
--color-fafafa: #fafafa;
1012
}
1113

1214
:root {
13-
--foreground-rgb: 250, 250, 250;
14-
--background: #000000;
15+
--foreground-rgb: 226, 232, 240;
16+
--background: #0f172a;
1517
}
1618

1719
body {

app/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export default function RootLayout({
1414
}) {
1515
return (
1616
<html lang="en">
17-
<body className="font-sans bg-tech-dark text-white min-h-screen">
17+
<body className="font-sans bg-tech-dark text-slate-200 min-h-screen antialiased">
1818
<AuthProvider>{children}</AuthProvider>
1919
</body>
2020
</html>

app/profile/[id]/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@ export default async function ProfilePage({ params }: { params: Promise<{ id: st
5151
const isOwnProfile = (session.user as { id?: string }).id === id;
5252

5353
return (
54-
<div className="min-h-screen bg-tech-dark text-white">
54+
<div className="min-h-screen bg-tech-dark text-slate-200">
5555
<div
56-
className="fixed inset-0 opacity-30 pointer-events-none"
56+
className="fixed inset-0 opacity-20 pointer-events-none"
5757
style={{
5858
backgroundImage:
59-
"radial-gradient(circle at 25px 25px, rgba(59,130,246,0.15) 1px, transparent 0), radial-gradient(circle at 75px 75px, rgba(139,92,246,0.15) 1px, transparent 0)",
59+
"radial-gradient(circle at 25px 25px, rgba(59,130,246,0.10) 1px, transparent 0), radial-gradient(circle at 75px 75px, rgba(139,92,246,0.08) 1px, transparent 0)",
6060
backgroundSize: "100px 100px",
6161
}}
6262
/>

components/DashboardClient.tsx

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ const ctaCards = [
125125
href: "#",
126126
},
127127
{
128-
id: "4",
128+
id: "update-profile",
129129
icon: "👤",
130130
title: "Update Your Profile",
131131
description: "Help others get to know you better",
@@ -161,16 +161,21 @@ function MiniAvatar({ image, name }: { image: string | null; name: string }) {
161161

162162
export function DashboardClient({ session, trendingResources }: DashboardClientProps) {
163163
const user = session.user;
164+
const userId = (user as { id?: string }).id;
164165
const joinDate = "March 2024"; // In production, comes from Slack API
165166

167+
const resolvedCtaCards = ctaCards.map((card) =>
168+
card.id === "update-profile" ? { ...card, href: userId ? `/profile/${userId}` : "#" } : card
169+
);
170+
166171
return (
167-
<div className="min-h-screen text-white" style={{ background: "linear-gradient(to bottom, #0a0a0a, #000000)" }}>
168-
{/* Circuit pattern background */}
172+
<div className="min-h-screen text-white" style={{ background: "linear-gradient(160deg, #0f172a 0%, #0b1628 50%, #0f172a 100%)" }}>
173+
{/* Subtle background texture */}
169174
<div
170-
className="fixed inset-0 opacity-30 pointer-events-none"
175+
className="fixed inset-0 opacity-20 pointer-events-none"
171176
style={{
172177
backgroundImage:
173-
"radial-gradient(circle at 25px 25px, rgba(59,130,246,0.15) 1px, transparent 0), radial-gradient(circle at 75px 75px, rgba(139,92,246,0.15) 1px, transparent 0)",
178+
"radial-gradient(circle at 25px 25px, rgba(59,130,246,0.10) 1px, transparent 0), radial-gradient(circle at 75px 75px, rgba(139,92,246,0.08) 1px, transparent 0)",
174179
backgroundSize: "100px 100px",
175180
}}
176181
/>
@@ -181,7 +186,7 @@ export function DashboardClient({ session, trendingResources }: DashboardClientP
181186
{/* Welcome card */}
182187
<div
183188
className="p-6 rounded-2xl border border-white/10"
184-
style={{ background: "linear-gradient(to bottom right, rgba(255,255,255,0.05), rgba(255,255,255,0.10))", backdropFilter: "blur(12px)" }}
189+
style={{ background: "linear-gradient(135deg, rgba(30,41,59,0.8), rgba(15,23,42,0.9))", backdropFilter: "blur(12px)" }}
185190
>
186191
<h1 className="text-3xl font-bold mb-1">
187192
<span
@@ -200,8 +205,8 @@ export function DashboardClient({ session, trendingResources }: DashboardClientP
200205
<div
201206
className="p-6 rounded-2xl"
202207
style={{
203-
background: "rgba(10,10,10,0.8)",
204-
border: "1px solid rgba(6,182,212,0.3)",
208+
background: "rgba(30,41,59,0.7)",
209+
border: "1px solid rgba(6,182,212,0.25)",
205210
borderRadius: 16,
206211
}}
207212
>
@@ -259,7 +264,7 @@ export function DashboardClient({ session, trendingResources }: DashboardClientP
259264
<div
260265
key={event.id}
261266
className="p-4 rounded-xl border border-white/10 flex items-center gap-3"
262-
style={{ background: "linear-gradient(to right, rgba(6,182,212,0.10), rgba(139,92,246,0.10))", backdropFilter: "blur(8px)" }}
267+
style={{ background: "rgba(30,41,59,0.6)", backdropFilter: "blur(8px)" }}
263268
>
264269
<span className="text-2xl flex-shrink-0">{event.icon}</span>
265270
<div className="flex-1 min-w-0">
@@ -290,7 +295,7 @@ export function DashboardClient({ session, trendingResources }: DashboardClientP
290295
🏆 Top Members This Month
291296
</h2>
292297
</div>
293-
<div className="rounded-2xl overflow-hidden border border-white/10" style={{ background: "rgba(255,255,255,0.03)" }}>
298+
<div className="rounded-2xl overflow-hidden border border-white/10" style={{ background: "rgba(30,41,59,0.5)" }}>
294299
{topMembers.map((member, idx) => (
295300
<div
296301
key={member.rank}
@@ -330,7 +335,7 @@ export function DashboardClient({ session, trendingResources }: DashboardClientP
330335
{/* Community Activity Feed */}
331336
<section>
332337
<h2 className="text-xl font-semibold text-white mb-4">Community Activity</h2>
333-
<div className="rounded-2xl border border-white/10 overflow-hidden" style={{ background: "rgba(255,255,255,0.03)" }}>
338+
<div className="rounded-2xl border border-white/10 overflow-hidden" style={{ background: "rgba(30,41,59,0.5)" }}>
334339
{communityFeed.map((section, sIdx) => (
335340
<div key={section.id}>
336341
{/* Section divider */}
@@ -371,12 +376,12 @@ export function DashboardClient({ session, trendingResources }: DashboardClientP
371376
<section>
372377
<h2 className="text-xl font-semibold text-white mb-4">Suggested Actions</h2>
373378
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
374-
{ctaCards.map((card) => (
379+
{resolvedCtaCards.map((card) => (
375380
<div
376381
key={card.id}
377382
className="p-5 rounded-2xl border border-white/10 flex flex-col gap-3"
378383
style={{
379-
background: "linear-gradient(to bottom right, rgba(6,182,212,0.10), rgba(139,92,246,0.10))",
384+
background: "rgba(30,41,59,0.6)",
380385
backdropFilter: "blur(8px)",
381386
borderLeftWidth: 3,
382387
borderLeftColor: card.accent,

components/Navbar.tsx

Lines changed: 97 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { signOut } from "next-auth/react";
44
import Image from "next/image";
55
import Link from "next/link";
66
import { usePathname } from "next/navigation";
7+
import { useEffect, useRef, useState } from "react";
78

89
interface NavbarProps {
910
user?: {
@@ -15,76 +16,120 @@ interface NavbarProps {
1516

1617
const navLinks = [
1718
{ href: "/dashboard", label: "Home" },
18-
{ href: "/leaderboards", label: "Leaderboards" },
19-
{ href: "/prayers", label: "Prayers" },
20-
{ href: "/questions", label: "Questions" },
19+
{ href: "/leaderboard", label: "Leaderboard" },
20+
{ href: "/prayer", label: "Prayers" },
2121
{ href: "/resources", label: "Resources" },
22-
{ href: "/directory", label: "Directory" },
23-
{ href: "/events", label: "Events" },
2422
];
2523

2624
export function Navbar({ user }: NavbarProps) {
2725
const pathname = usePathname();
26+
const [dropdownOpen, setDropdownOpen] = useState(false);
27+
const dropdownRef = useRef<HTMLDivElement>(null);
28+
29+
useEffect(() => {
30+
function handleClickOutside(event: MouseEvent) {
31+
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
32+
setDropdownOpen(false);
33+
}
34+
}
35+
if (dropdownOpen) {
36+
document.addEventListener("mousedown", handleClickOutside);
37+
}
38+
return () => document.removeEventListener("mousedown", handleClickOutside);
39+
}, [dropdownOpen]);
2840

2941
return (
30-
<nav className="relative z-20 border-b border-white/10 bg-tech-darker/80 backdrop-blur-sm">
31-
<div className="max-w-6xl mx-auto px-6 h-16 flex items-center justify-between">
42+
<nav className="relative z-20 border-b border-white/10 bg-tech-darker/90 backdrop-blur-md sticky top-0">
43+
<div className="max-w-6xl mx-auto px-6 h-16 flex items-center justify-between gap-4">
3244
<Link href="/dashboard" className="flex items-center gap-2 shrink-0">
33-
<span className="text-2xl">🐛</span>
34-
<span className="font-bold text-white">Debugging Disciples</span>
45+
<span className="text-xl">🐛</span>
46+
<span className="font-bold text-white text-sm sm:text-base tracking-tight">Debugging Disciples</span>
3547
</Link>
3648

37-
<div className="flex items-center gap-1 overflow-x-auto scrollbar-none mx-4">
49+
<div className="flex items-center gap-0.5 overflow-x-auto scrollbar-none">
3850
{navLinks.map(({ href, label }) => {
39-
// 1. Exact match for the current page
40-
const isExact = pathname === href;
41-
42-
// 2. Nested match: pathname starts with href + '/'
43-
// We check for the '/' to avoid matching /settings-old when the link is /settings
44-
const isNested = pathname.startsWith(`${href}/`);
45-
46-
// 3. Special handling for root/dashboard to avoid highlighting everything
47-
const isActive = (href === '/dashboard' || href === '/')
48-
? isExact
49-
: (isExact || isNested);
50-
51-
return (
52-
<Link
53-
key={href}
54-
href={href}
55-
// Accessibility: Tell screen readers this is the current page
56-
aria-current={isActive ? 'page' : undefined}
57-
className={`px-3 py-1.5 rounded-lg text-sm whitespace-nowrap transition-colors ${
58-
isActive
59-
? "text-brand-cyan bg-brand-cyan/10 font-medium"
60-
: "text-gray-400 hover:text-brand-cyan hover:bg-white/5"
61-
}`}
62-
>
63-
{label}
64-
</Link>
65-
);
66-
})}
51+
const isExact = pathname === href;
52+
const isNested = pathname.startsWith(`${href}/`);
53+
const isActive = href === "/dashboard" ? isExact : isExact || isNested;
6754

55+
return (
56+
<Link
57+
key={href}
58+
href={href}
59+
aria-current={isActive ? "page" : undefined}
60+
className={`px-3 py-1.5 rounded-lg text-sm whitespace-nowrap transition-colors ${
61+
isActive
62+
? "text-brand-cyan bg-brand-cyan/10 font-medium"
63+
: "text-slate-400 hover:text-white hover:bg-white/5"
64+
}`}
65+
>
66+
{label}
67+
</Link>
68+
);
69+
})}
6870
</div>
6971

7072
{user && (
71-
<div className="flex items-center gap-3 shrink-0">
72-
{user.image && (
73-
<div className="relative w-8 h-8 rounded-full overflow-hidden border-2 border-brand-cyan/50">
74-
<Image
75-
src={user.image}
76-
alt={user.name ?? "User"}
77-
fill
78-
className="object-cover"
79-
/>
80-
</div>
81-
)}
73+
<div className="relative shrink-0" ref={dropdownRef}>
8274
<button
83-
onClick={() => signOut({ callbackUrl: "/" })}
84-
className="text-sm text-gray-400 hover:text-white transition-colors"
75+
onClick={() => setDropdownOpen((prev) => !prev)}
76+
className="flex items-center gap-2 px-2 py-1.5 rounded-xl hover:bg-white/5 transition-colors group"
77+
aria-expanded={dropdownOpen}
78+
aria-haspopup="true"
8579
>
86-
Sign out
80+
{user.image ? (
81+
<div className="relative w-8 h-8 rounded-full overflow-hidden border-2 border-brand-cyan/40 flex-shrink-0">
82+
<Image
83+
src={user.image}
84+
alt={user.name ?? "User"}
85+
fill
86+
className="object-cover"
87+
sizes="32px"
88+
/>
89+
</div>
90+
) : (
91+
<div className="w-8 h-8 rounded-full border-2 border-brand-cyan/40 bg-gradient-to-br from-brand-cyan/20 to-brand-purple/20 flex items-center justify-center text-brand-cyan font-bold text-xs flex-shrink-0">
92+
{(user.name ?? "U").trim().split(/\s+/).filter(Boolean).map((n) => n[0]).join("").slice(0, 2).toUpperCase()}
93+
</div>
94+
)}
95+
<span className="hidden sm:block text-sm text-slate-200 font-medium max-w-[120px] truncate group-hover:text-white transition-colors">
96+
{user.name?.trim().split(/\s+/)[0] ?? "User"}
97+
</span>
98+
<svg
99+
className={`w-4 h-4 text-slate-400 flex-shrink-0 transition-transform duration-200 ${dropdownOpen ? "rotate-180" : ""}`}
100+
fill="none"
101+
stroke="currentColor"
102+
viewBox="0 0 24 24"
103+
>
104+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
105+
</svg>
87106
</button>
107+
108+
{dropdownOpen && (
109+
<div
110+
className="absolute right-0 mt-2 w-56 rounded-xl border border-white/10 shadow-2xl z-50 overflow-hidden"
111+
style={{ background: "rgba(11,18,32,0.97)", backdropFilter: "blur(16px)" }}
112+
>
113+
<div className="px-4 py-3 border-b border-white/10">
114+
<p className="text-white text-sm font-semibold truncate">{user.name}</p>
115+
{user.email && <p className="text-slate-400 text-xs mt-0.5 truncate">{user.email}</p>}
116+
</div>
117+
<div className="p-1.5">
118+
<button
119+
onClick={() => {
120+
setDropdownOpen(false);
121+
signOut({ callbackUrl: "/" });
122+
}}
123+
className="w-full text-left flex items-center gap-2.5 px-3 py-2 text-sm text-slate-300 hover:text-white hover:bg-white/5 rounded-lg transition-colors"
124+
>
125+
<svg className="w-4 h-4 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
126+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
127+
</svg>
128+
Sign out
129+
</button>
130+
</div>
131+
</div>
132+
)}
88133
</div>
89134
)}
90135
</div>

next.config.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
11
import type { NextConfig } from "next";
22

33
const nextConfig: NextConfig = {
4-
/* config options here */
4+
images: {
5+
remotePatterns: [
6+
{
7+
protocol: "https",
8+
hostname: "avatars.slack-edge.com",
9+
},
10+
{
11+
protocol: "https",
12+
hostname: "secure.gravatar.com",
13+
},
14+
{
15+
protocol: "https",
16+
hostname: "*.slack-edge.com",
17+
},
18+
],
19+
},
520
};
621

722
export default nextConfig;

0 commit comments

Comments
 (0)