diff --git a/app/components/dashboard/Navbar.tsx b/app/components/dashboard/Navbar.tsx
index b950cc2..fea4d73 100644
--- a/app/components/dashboard/Navbar.tsx
+++ b/app/components/dashboard/Navbar.tsx
@@ -239,7 +239,7 @@ export default function DashboardLayout({
diff --git a/app/components/landing-page/Contributors.tsx b/app/components/landing-page/Contributors.tsx
index c0ebc65..decae95 100644
--- a/app/components/landing-page/Contributors.tsx
+++ b/app/components/landing-page/Contributors.tsx
@@ -24,7 +24,7 @@ export default async function Contributors() {
return (
diff --git a/app/components/landing-page/LosserMembers.tsx b/app/components/landing-page/LosserMembers.tsx
index ddad6a5..9257c6e 100644
--- a/app/components/landing-page/LosserMembers.tsx
+++ b/app/components/landing-page/LosserMembers.tsx
@@ -23,15 +23,9 @@ export default function LosserMembers({
return (
<>
{losser_members && losser_members.length > 0 && (
-
+
-
- Team Insight
-
Lower Activity Leaderboard
@@ -80,7 +74,7 @@ export default function LosserMembers({
diff --git a/app/components/landing-page/RecentLeaderboard.tsx b/app/components/landing-page/RecentLeaderboard.tsx
index 23c0d75..cce47f1 100644
--- a/app/components/landing-page/RecentLeaderboard.tsx
+++ b/app/components/landing-page/RecentLeaderboard.tsx
@@ -18,15 +18,9 @@ export default function RecentLeaderboard({
return (
<>
{leaderboards && leaderboards.length > 0 && (
-
+
-
- Board Arena
-
Active Leaderboards
@@ -35,20 +29,6 @@ export default function RecentLeaderboard({
coding consistency.
-
-
- {leaderboards.length} active boards
-
-
- Create yours
-
- →
-
-
-
{featuredBoard && (
@@ -56,42 +36,16 @@ export default function RecentLeaderboard({
href={`/leaderboard/${featuredBoard.slug}`}
className="block glass-card rounded-3xl border-gray-200 bg-gray-50 p-6 mb-4 group hover:border-blue-500/20 transition-colors"
>
-
-
-
- Featured Arena
-
-
- {featuredBoard.name}
-
-
- Most recently launched board with open competition access.
-
-
-
-
-
- Status
-
-
- Live
-
-
-
-
-
- Action
-
-
- Enter
-
-
-
+
+
+ Featured Leaderboard
+
+
+ {featuredBoard.name}
+
+
+ Most recently launched board with open competition access.
+
)}
@@ -106,19 +60,14 @@ export default function RecentLeaderboard({
key={board.id}
href={`/leaderboard/${board.slug}`}
className="rounded-2xl glass-card border-gray-200 bg-gray-50 p-4 group hover:bg-white/[0.035] hover:border-blue-500/20 transition-all"
-
+
data-aos-delay={(i * 60).toString()}
>
-
-
- Arena #{i + 2}
-
-
- Open
-
-
+
+ Leaderboard #{i + 2}
+
-
+
{board.name}
@@ -129,14 +78,9 @@ export default function RecentLeaderboard({
/>
-
-
- /leaderboard/{board.slug}
-
-
- Enter →
-
-
+
+ /leaderboard/{board.slug}
+
),
)}
@@ -165,8 +109,6 @@ export default function RecentLeaderboard({
Join with invite code
-
-
)}
>
diff --git a/app/components/landing-page/TopLeaderbord.tsx b/app/components/landing-page/TopLeaderbord.tsx
index efa5986..e986d5a 100644
--- a/app/components/landing-page/TopLeaderbord.tsx
+++ b/app/components/landing-page/TopLeaderbord.tsx
@@ -4,7 +4,7 @@ import { BADGE_LEGEND_HOURS, getBadgeInfoFromHours } from "@/app/utils/badge";
export interface TopMember {
email: string;
total_seconds: number;
- categories: { name: string; total_seconds: number }[] | null;
+ categories: { name: string; total_seconds: number; percent: number }[] | null;
user_id: string | null;
}
@@ -44,26 +44,15 @@ export default function TopLeaderboard({
return (
<>
{top_members && top_members.length > 0 && (
-
-
-
-
- Real Leaderboard
-
-
- Top Developers of the Week
-
-
- Ranked by weekly coding time with clear podium cutoffs and
- progress to the top.
-
-
-
- {rankedTopMembers.length} ranked developers
-
+
+
+
+ Top Developers of the Week
+
+
+ Ranked by weekly coding time with clear podium cutoffs and
+ progress to the top.
+
@@ -85,15 +74,11 @@ export default function TopLeaderboard({
{rankedTopMembers.map((member, i) => {
const rank = i + 1;
- const badgeInfo = getBadgeInfoFromHours(
- member.total_seconds / 3600,
- );
-
+ const badgeInfo = getBadgeInfoFromHours(member.total_seconds / 3600);
return (
{formatRank(rank)}
-
+
{member.email.split("@")[0]}
-
- {rank <= 3 ? "Podium zone" : "Chasing podium"}
+
+
+ {rank <= 3 ? "Podium zone" : "Chasing podium"}
+
-
+
{formatDuration(member.total_seconds)}
-
+
{badgeInfo.icon && (
-
+
)}
{badgeInfo.label}
@@ -138,7 +122,7 @@ export default function TopLeaderboard({
Rankings Legend
-
+
{BADGE_LEGEND_HOURS.map((hours) => {
const b = getBadgeInfoFromHours(hours);
return (
diff --git a/app/components/landing-page/VibeCoders.tsx b/app/components/landing-page/VibeCoders.tsx
index 1043a92..f525a91 100644
--- a/app/components/landing-page/VibeCoders.tsx
+++ b/app/components/landing-page/VibeCoders.tsx
@@ -6,105 +6,87 @@ function formatDuration(totalSeconds: number) {
return `${hours}h ${minutes}m`;
}
+function getAiCodingPercent(member: TopMember): number {
+ const aiCategory = member.categories?.find((c) => c.name === "AI Coding");
+ return aiCategory ? Math.round(aiCategory.percent) : 0;
+}
+
export default function VibeCoders({
vibe_coders,
}: {
vibe_coders: TopMember[];
}) {
+ if (!vibe_coders || vibe_coders.length === 0) {
+ return null;
+ }
+
const visibleVibeCoders = vibe_coders.slice(0, 6);
return (
- <>
- {vibe_coders && vibe_coders.length > 0 && (
-
-
-
-
- AI Category
-
-
- Vibe Coders Leaderboard
-
-
- Snapshot of developers investing the most time in AI Coding.
-
-
-
- AI coding signal
-
-
- {(!vibe_coders || vibe_coders.length === 0) && (
-
- No AI coding activity recorded yet.
-
- )}
-
-
-
- Category Focus
-
-
- Prompt-to-Code Rhythm
-
-
- Measure how teams are adopting AI tooling without losing coding
- consistency and technical depth.
-
-
+
+
+
+ Agentic Coders
+
+
+ A snapshot of developers investing the most time in Agentic Coding.
+
+
-
- {visibleVibeCoders.map(
- (
- member: { email: string; total_seconds: number },
- i: number,
- ) => (
-
-
-
-
- #{i + 1}
-
-
- {member.email.split("@")[0]}
-
-
-
- {formatDuration(member.total_seconds)}
-
-
+
+
+
+ Prompt-to-Code Rhythm
+
+
+ Measure how teams are adopting AI tooling without losing coding
+ consistency and technical depth.
+
+
-
+
+ {visibleVibeCoders.map((member, i) => {
+ const pct = getAiCodingPercent(member);
-
- AI coding contribution
-
-
- ),
- )}
-
-
-
- Note: Values represent tracked time inside the AI Coding category.
-
+ return (
+
+
+
+
+ #{i + 1}
+
+
+ {member.email.split("@")[0]}
+
+
+
+ {formatDuration(member.total_seconds)}
+
+
-
-
- )}
- >
+
+
+ AI coding contribution
+
+
+ {pct}%
+
+
+
+
+ );
+ })}
+
+
+
);
}
diff --git a/app/components/layout/Footer.tsx b/app/components/layout/Footer.tsx
index 2ad88d1..f41dff7 100644
--- a/app/components/layout/Footer.tsx
+++ b/app/components/layout/Footer.tsx
@@ -2,9 +2,9 @@ import Link from "next/link";
export default function Footer() {
return (
-
+
-
+
© {new Date().getFullYear()} Devpulse
@@ -44,8 +44,6 @@ export default function Footer() {
-
-
Made with ❤️ by Hall of Codes
diff --git a/app/components/layout/Nav.tsx b/app/components/layout/Nav.tsx
index d16a3a5..a8f2ac2 100644
--- a/app/components/layout/Nav.tsx
+++ b/app/components/layout/Nav.tsx
@@ -12,9 +12,13 @@ export default async function Nav() {
-
+
Devpulse
@@ -26,11 +30,7 @@ export default async function Nav() {
type="navbar"
/>
) : (
-
+
-
- {/* Top actions overlay */}
-
-
+
diff --git a/app/components/leaderboard/LeaderboardStats.tsx b/app/components/leaderboard/LeaderboardStats.tsx
index 6d31568..a0856eb 100644
--- a/app/components/leaderboard/LeaderboardStats.tsx
+++ b/app/components/leaderboard/LeaderboardStats.tsx
@@ -113,43 +113,34 @@ export default function LeaderboardStats({
];
return (
-
-
-
- Leaderboard Stats
-
-
- {statCards.map((card, idx) => (
-
-
-
- {card.label}
-
-
- {card.trend}
-
-
-
-
-
- {card.value}
-
-
- {card.sub}
-
+
+
+ {statCards.map((card, idx) => (
+
+
+
+ {card.label}
+
+
+ {card.trend}
- ))}
-
+
+
+ {card.value}
+
+
+ {card.sub}
+
+
+
+ ))}
);
diff --git a/app/components/leaderboard/LeaderboardTable.tsx b/app/components/leaderboard/LeaderboardTable.tsx
index ee6ea0d..dd30c4b 100644
--- a/app/components/leaderboard/LeaderboardTable.tsx
+++ b/app/components/leaderboard/LeaderboardTable.tsx
@@ -2,6 +2,7 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { BADGE_LEGEND_HOURS, getBadgeInfoFromHours } from "@/app/utils/badge";
+import LeaderboardStats from "./LeaderboardStats";
export interface NonNullableMember {
user_id: string;
@@ -13,111 +14,6 @@ export interface NonNullableMember {
editors: { name: string }[];
}
-function LeaderboardPodium({
- topUsers,
-}: {
- topUsers: {
- user_id: string;
- rank: number;
- email: string | null;
- hours: number;
- role: string | null;
- languages: string[];
- os: string;
- editor: string;
- }[];
-}) {
- if (topUsers.length === 0) return null;
-
- return (
-
- {topUsers.map((user, idx) => {
- const rankColor =
- idx === 0
- ? "text-yellow-400 drop-shadow-[0_0_8px_rgba(250,204,21,0.4)]"
- : idx === 1
- ? "text-gray-600 drop-shadow-[0_0_8px_rgba(209,213,219,0.4)]"
- : "text-amber-600 drop-shadow-[0_0_8px_rgba(217,119,6,0.4)]";
-
- const badgeInfo = getBadgeInfoFromHours(user.hours);
- const initial = (user.email?.[0] || "?").toUpperCase();
-
- return (
-
- {/* Minimal Background Glow based on rank */}
-
-
-
-
-
- {initial}
-
-
-
- {user.email?.split("@")[0] || "Unknown"}
-
-
- {badgeInfo.icon && (
-
- )}
- {badgeInfo.label}
-
-
-
-
-
-
- {idx === 0 ? "01" : idx === 1 ? "02" : "03"}
-
-
-
-
- {/* Stats Row */}
-
-
-
- Hours
-
-
- {user.hours}
-
-
-
-
- Language
-
-
- {user.languages?.[0] || "N/A"}
-
-
-
-
- Editor
-
-
- {user.editor || "N/A"}
-
-
-
-
- );
- })}
-
- );
-}
-
-import LeaderboardStats from "./LeaderboardStats";
-
export default function LeaderboardTable({
members,
}: {
@@ -136,7 +32,6 @@ export default function LeaderboardTable({
editor: member.editors?.[0]?.name || "N/A",
}));
- const maxHours = ranked[0]?.hours || 1;
const formatRank = (rank: number) => rank.toString().padStart(2, "0");
const getRankColor = (rank: number) => {
@@ -148,12 +43,8 @@ export default function LeaderboardTable({
};
return (
-
-
-
+ <>
-
-
{ranked.length === 0 ? (
@@ -173,8 +64,7 @@ export default function LeaderboardTable({
{/* List Body */}
- {ranked.slice(3).map((user) => {
- const pct = Math.max(2, (user.hours / maxHours) * 100);
+ {ranked.map((user) => {
const badgeInfo = getBadgeInfoFromHours(user.hours);
return (
@@ -182,13 +72,6 @@ export default function LeaderboardTable({
key={user.user_id}
className="group relative flex flex-col md:flex-row items-start md:items-center px-4 sm:px-6 py-4 md:py-4 transition-colors hover:bg-gray-100 bg-transparent"
>
- {/* Background Progress Bar */}
-
-
- {/* MOBILE TOP ROW / DESKTOP LEFT FLEX */}
{/* Rank */}
@@ -201,9 +84,6 @@ export default function LeaderboardTable({
{/* Profile + Badges */}
-
- {user.email?.charAt(0) || "?"}
-
@@ -291,38 +171,6 @@ export default function LeaderboardTable({
)}
-
- {/* Rankings Legend */}
-
-
-
- Rankings Legend
-
-
- {BADGE_LEGEND_HOURS.map((hours) => {
- const b = getBadgeInfoFromHours(hours);
- return (
-
-
- {b.icon && (
-
- )}
- {b.label}
-
-
- {hours === 0 ? "0 hrs" : `${hours}+`}
-
-
- );
- })}
-
-
-
-
+ >
);
}
diff --git a/app/d/flex/page.tsx b/app/d/flex/page.tsx
index 9f67bda..92e3dee 100644
--- a/app/d/flex/page.tsx
+++ b/app/d/flex/page.tsx
@@ -4,7 +4,7 @@ import { Metadata } from "next/types";
import { redirect } from "next/navigation";
export const metadata: Metadata = {
- title: "Flexes - Devpulse",
+ title: "Flex - Devpulse",
};
export default async function FlexPage() {
diff --git a/app/d/update-password/page.tsx b/app/d/update-password/page.tsx
index 995ea8e..1675199 100644
--- a/app/d/update-password/page.tsx
+++ b/app/d/update-password/page.tsx
@@ -10,7 +10,7 @@ export const metadata: Metadata = {
export default async function UpdatePassword() {
return (
<>
-
+
diff --git a/app/layout.tsx b/app/layout.tsx
index 6e68104..fc99a3e 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -135,7 +135,7 @@ export default function RootLayout({
-
+
diff --git a/app/legal/contribution-guidelines/page.tsx b/app/legal/contribution-guidelines/page.tsx
index f17417e..9e58b84 100644
--- a/app/legal/contribution-guidelines/page.tsx
+++ b/app/legal/contribution-guidelines/page.tsx
@@ -12,11 +12,11 @@ export const metadata: Metadata = {
export default function ContributionGuidelines() {
return (
-
+
-
+
Contribution Guidelines
diff --git a/app/legal/privacy/page.tsx b/app/legal/privacy/page.tsx
index d1e91cd..5180ef5 100644
--- a/app/legal/privacy/page.tsx
+++ b/app/legal/privacy/page.tsx
@@ -12,11 +12,11 @@ export const metadata: Metadata = {
export default function Privacy() {
return (
-
+
-
+
Privacy Policy
diff --git a/app/legal/terms/page.tsx b/app/legal/terms/page.tsx
index 0c09c99..2f970a9 100644
--- a/app/legal/terms/page.tsx
+++ b/app/legal/terms/page.tsx
@@ -12,11 +12,11 @@ export const metadata: Metadata = {
export default function Terms() {
return (
-
+
-
+
Terms of Service
diff --git a/app/lib/proxy/auth.ts b/app/lib/proxy/auth.ts
index b3c5e0b..ea950b8 100644
--- a/app/lib/proxy/auth.ts
+++ b/app/lib/proxy/auth.ts
@@ -22,12 +22,7 @@ export default async function Auth(req: NextRequest) {
}
}
- const authRoutes = [
- "/login",
- "/signup",
- "/forgot-password",
- "/reset-password",
- ];
+ const authRoutes = ["/login", "/signup", "/forgot-password"];
if (authRoutes.includes(pathname) && session) {
if (!session.user.email_verified) {
@@ -39,6 +34,10 @@ export default async function Auth(req: NextRequest) {
return NextResponse.redirect(new URL("/d", req.url));
}
+ if (pathname === "/reset-password") {
+ return null;
+ }
+
if (
(pathname === "/verify-email" && session?.user.email_verified) ||
(pathname === "/verify-wakatime" && session?.user.wakatime_api_key)
diff --git a/app/page.tsx b/app/page.tsx
index 43c256f..66ab2e6 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -13,6 +13,7 @@ import VibeCoders from "./components/landing-page/VibeCoders";
import Nav from "./components/layout/Nav";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
+ faArrowDown,
faBolt,
faLock,
faStar,
@@ -134,16 +135,14 @@ export default async function Home() {
dangerouslySetInnerHTML={{ __html: JSON.stringify(devpulseWaka) }}
/>
-
+
- {/* Hero Section */}
-
+
{/* Left text */}
-
+
Measure your
@@ -151,8 +150,7 @@ export default async function Home() {
Turn your daily coding activity into competitive, shareable
@@ -161,8 +159,7 @@ export default async function Home() {
-
-
-
Scroll to explore
-
-
-
-
- {/* Right abstract UI visual / Mockup */}
-
+ {/* Right abstract UI visual / Mockup — desktop only */}
+
{/* Card 1 */}
-
-
-
-
- Total Coding
-
-
- +18%
-
-
-
- 42h 15m
+
+
+
+ Total Coding
-
Last 7 days
-
+
+ 42h 15m
+
+
Last 7 days
+
{/* Card 2 */}
-
-
-
- Top Languages
-
-
-
-
- TS
+
+
+ Top Languages
+
+
+
+
+ TS
+
+
+
+
+ TypeScript
+
+
+ 28h 40m
+
-
-
-
- TypeScript
-
-
- 28h 40m
-
-
-
+
-
-
- Re
+
+
+
+ Re
+
+
+
+ React
+
+ 12h 10m
+
-
-
- React
-
- 12h 10m
-
-
-
+
@@ -264,7 +243,7 @@ export default async function Home() {
{/* Card 3 (Code terminal) */}
-
+
@@ -293,6 +272,12 @@ export default async function Home() {
+
+ {/* Scroll indicator */}
+
+ Scroll to explore
+
+
{/* Features Divider */}
@@ -379,16 +364,14 @@ function FeatureCard({
delay: string;
}) {
return (
-
-
- {icon}
+
+
+
+ {icon}
+
+
{title}
+
{description}
-
{title}
-
{description}
);
}