Skip to content
Open
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
296 changes: 170 additions & 126 deletions src/app/[locale]/ladder/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import {
PageActions,
} from "../../../components/index";
import { useTranslations } from "next-intl";
import { useState } from "react";

export default function MaintainerLadderPage() {
const t = useTranslations("ladderPage");
const [hoveredLevel, setHoveredLevel] = useState<number | null>(null);

const levels = [
{
Expand Down Expand Up @@ -259,185 +261,227 @@ export default function MaintainerLadderPage() {
<section className="py-8 sm:py-12 md:py-16 lg:py-20">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative">
{/* Mobile Layout */}
<div className="lg:hidden">
<div className="lg:hidden space-y-6">
{levels.map((level, index) => (
<div key={level.id} className="mb-4">
{/* Level Card */}
<div className="bg-gray-800/40 backdrop-blur-md rounded-lg p-6 border border-white/10 relative">
{/* Level Number */}
<div className="absolute -top-6 left-1/2 transform -translate-x-1/2">
<div
key={level.id}
className="relative group"
onMouseEnter={() => setHoveredLevel(level.id)}
onMouseLeave={() => setHoveredLevel(null)}
Comment on lines +268 to +270
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

The hover effects with onMouseEnter and onMouseLeave are not keyboard accessible. Users navigating with keyboard or screen readers won't be able to trigger these effects. Consider adding onFocus and onBlur event handlers, and ensuring the elements are keyboard-focusable with appropriate tabIndex values.

Suggested change
className="relative group"
onMouseEnter={() => setHoveredLevel(level.id)}
onMouseLeave={() => setHoveredLevel(null)}
className="relative group"
tabIndex={0}
onMouseEnter={() => setHoveredLevel(level.id)}
onMouseLeave={() => setHoveredLevel(null)}
onFocus={() => setHoveredLevel(level.id)}
onBlur={() => setHoveredLevel(null)}

Copilot uses AI. Check for mistakes.
>
{/* Glowing border effect */}
<div
className={`absolute -inset-[2px] bg-gradient-to-r ${level.gradient} rounded-xl opacity-0 group-hover:opacity-70 blur-sm transition-opacity duration-500`}
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

The glowing border effect uses a fixed blur-sm value. Consider using a larger blur value for the glow effect to be more visible and create a more pronounced shimmer effect. The current blur-sm (4px) may be too subtle for a noticeable glow.

Suggested change
className={`absolute -inset-[2px] bg-gradient-to-r ${level.gradient} rounded-xl opacity-0 group-hover:opacity-70 blur-sm transition-opacity duration-500`}
className={`absolute -inset-[2px] bg-gradient-to-r ${level.gradient} rounded-xl opacity-0 group-hover:opacity-70 blur-lg transition-opacity duration-500`}

Copilot uses AI. Check for mistakes.
></div>

<div className="relative bg-gradient-to-br from-gray-900/90 to-gray-800/90 backdrop-blur-xl rounded-xl p-5 border border-white/5 overflow-hidden">
{/* Animated background particles */}
<div className="absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity duration-700">
<div
className={`absolute top-0 left-0 w-32 h-32 bg-gradient-to-br ${level.gradient} rounded-full blur-3xl opacity-20`}
></div>
<div
className={`absolute bottom-0 right-0 w-32 h-32 bg-gradient-to-tl ${level.gradient} rounded-full blur-3xl opacity-20`}
Comment on lines +275 to +284
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

Performance concern: Each level item creates multiple animated blur effects that render on hover. With multiple levels on the page, this could cause performance issues, especially on lower-end devices. Consider using CSS containment properties or will-change hints to optimize rendering performance.

Suggested change
></div>
<div className="relative bg-gradient-to-br from-gray-900/90 to-gray-800/90 backdrop-blur-xl rounded-xl p-5 border border-white/5 overflow-hidden">
{/* Animated background particles */}
<div className="absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity duration-700">
<div
className={`absolute top-0 left-0 w-32 h-32 bg-gradient-to-br ${level.gradient} rounded-full blur-3xl opacity-20`}
></div>
<div
className={`absolute bottom-0 right-0 w-32 h-32 bg-gradient-to-tl ${level.gradient} rounded-full blur-3xl opacity-20`}
style={{ willChange: "opacity" }}
></div>
<div className="relative bg-gradient-to-br from-gray-900/90 to-gray-800/90 backdrop-blur-xl rounded-xl p-5 border border-white/5 overflow-hidden">
{/* Animated background particles */}
<div
className="absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity duration-700"
style={{ contain: "paint" }}
>
<div
className={`absolute top-0 left-0 w-32 h-32 bg-gradient-to-br ${level.gradient} rounded-full blur-3xl opacity-20`}
style={{ willChange: "opacity" }}
></div>
<div
className={`absolute bottom-0 right-0 w-32 h-32 bg-gradient-to-tl ${level.gradient} rounded-full blur-3xl opacity-20`}
style={{ willChange: "opacity" }}

Copilot uses AI. Check for mistakes.
></div>
</div>
Comment on lines +279 to +286
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

The shimmer and animation effects lack accessibility considerations. Users with vestibular disorders or motion sensitivity may experience discomfort. Consider adding a check for the prefers-reduced-motion media query to disable or reduce animations for users who have enabled this setting in their system preferences.

Copilot uses AI. Check for mistakes.

{/* Level badge */}
<div className="absolute -top-3 -right-3">
<div
className={`w-12 h-12 bg-gradient-to-br ${level.gradient} rounded-full flex items-center justify-center shadow-lg`}
className={`w-10 h-10 bg-gradient-to-br ${level.gradient} rounded-full flex items-center justify-center shadow-lg shadow-black/50 group-hover:scale-110 transition-transform duration-300`}
>
<span className="text-white font-bold text-lg">
<span className="text-white font-bold text-sm">
{level.id}
</span>
</div>
</div>

<div className="pt-4">
<div className="text-center mb-4">
<div
className={`inline-flex items-center justify-center w-16 h-16 bg-gradient-to-br ${level.gradient} rounded-full mb-3`}
>
<div className="text-white">{level.icon}</div>
</div>
<h3 className="text-xl font-bold text-white mb-2">
<div className="relative flex items-start gap-4">
{/* Icon */}
<div
className={`flex-shrink-0 w-12 h-12 bg-gradient-to-br ${level.gradient} rounded-lg flex items-center justify-center group-hover:rotate-6 transition-transform duration-300`}
>
<div className="text-white scale-90">{level.icon}</div>
</div>

{/* Content */}
<div className="flex-1 min-w-0">
<h3 className="text-lg font-bold text-white mb-1 group-hover:text-transparent group-hover:bg-clip-text group-hover:bg-gradient-to-r group-hover:from-white group-hover:to-gray-300 transition-all duration-300">
{level.title}
</h3>
{level.timeframe && (
<div className="inline-block bg-blue-900/50 rounded-full px-3 py-1 text-xs text-blue-200 mb-2">
<div className="inline-block bg-blue-500/20 rounded-full px-2 py-0.5 text-xs text-blue-300 mb-2">
{level.timeframe}
</div>
)}
<p className="text-gray-300 text-sm mb-4">
<p className="text-gray-400 text-sm mb-3 line-clamp-2">
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

The text truncation with line-clamp-2 on the description may hide important information without providing a way to expand or view the full content. Consider adding a tooltip or expandable section to ensure all content remains accessible to users.

Suggested change
<p className="text-gray-400 text-sm mb-3 line-clamp-2">
<p
className="text-gray-400 text-sm mb-3 line-clamp-2"
title={level.description}
>

Copilot uses AI. Check for mistakes.
{level.description}
</p>
</div>

<div className="space-y-2">
<h4 className="text-sm font-semibold text-white mb-2">
{t("requirementsLabel")}
</h4>
<ul className="space-y-1">
{level.requirements.map((req, reqIndex) => (
<li
key={reqIndex}
className="text-xs text-gray-300 flex items-start"
>
<span className="text-green-400 mr-2 mt-1">
β€’
</span>
<span>{req}</span>
</li>
{/* Compact requirements */}
<div className="space-y-1">
{level.requirements.slice(0, 2).map((req, reqIndex) => (
<div key={reqIndex} className="flex items-start gap-2">
<div
className={`w-1 h-1 rounded-full bg-gradient-to-r ${level.gradient} mt-1.5 flex-shrink-0`}
></div>
<p className="text-xs text-gray-400 line-clamp-1">
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

The text is truncated with line-clamp-1 which may hide important requirement details. Consider removing the truncation or providing a way to view the complete text to ensure all information is accessible.

Suggested change
<p className="text-xs text-gray-400 line-clamp-1">
<p
className="text-xs text-gray-400 line-clamp-1"
title={req}
aria-label={req}
>

Copilot uses AI. Check for mistakes.
{req}
</p>
</div>
))}
</ul>
</div>

{level.goodStanding && (
<div className="mt-4 p-3 bg-blue-900/20 border border-blue-500/30 rounded-lg">
<h4 className="text-sm font-semibold text-blue-300 mb-2">
{t("goodStandingLabel")}
</h4>
<p className="text-xs text-gray-300 leading-relaxed">
{level.goodStanding}
</p>
{level.requirements.length > 2 && (
<p className="text-xs text-gray-500 italic">
+{level.requirements.length - 2} more
</p>
)}
Comment on lines +323 to +337
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

The requirements are truncated to show only the first 2 items with a "+X more" indicator. This hides potentially critical information from users. Consider showing all requirements or providing an interactive way to expand and view the complete list.

Copilot uses AI. Check for mistakes.
</div>
)}
</div>
</div>

{index < levels.length - 1 && (
<div className="text-center mt-4">
<div className="text-xs text-gray-400">
{t("nextLevelLabel")}
</div>
<div className="text-sm font-semibold text-blue-400">
{/* Next level indicator */}
{index < levels.length - 1 && (
<div className="mt-3 pt-3 border-t border-white/5">
<div className="flex items-center justify-between">
<span className="text-xs text-gray-500">Next:</span>
<span
className={`text-xs font-semibold bg-gradient-to-r ${level.gradient} bg-clip-text text-transparent`}
>
{level.nextLevel}
</div>
</span>
</div>
)}
</div>
</div>
)}
</div>

{/* Connector */}
{index < levels.length - 1 && (
<div className="flex justify-center mt-2">
<div className="w-0.5 h-6 bg-gradient-to-b from-blue-500 to-purple-500"></div>
</div>
)}
</div>
))}
</div>

{/* Desktop Layout */}
<div className="hidden lg:block">
{/* Central Ladder Line */}
<div className="absolute left-1/2 top-0 bottom-0 w-1 bg-gradient-to-b from-blue-500 via-purple-500 to-red-500 transform -translate-x-1/2 z-5"></div>
{/* Central Ladder Line with pulse effect */}
<div className="absolute left-1/2 top-0 bottom-0 w-1 transform -translate-x-1/2 z-5">
<div className="absolute inset-0 bg-gradient-to-b from-blue-500 via-purple-500 to-red-500"></div>
<div className="absolute inset-0 bg-gradient-to-b from-blue-400 via-purple-400 to-red-400 animate-pulse opacity-50"></div>
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

The animate-pulse effect on the central ladder line runs continuously, which could be distracting and may cause issues for users with motion sensitivity. Consider making this animation respect the prefers-reduced-motion setting.

Suggested change
<div className="absolute inset-0 bg-gradient-to-b from-blue-400 via-purple-400 to-red-400 animate-pulse opacity-50"></div>
<div className="absolute inset-0 bg-gradient-to-b from-blue-400 via-purple-400 to-red-400 animate-pulse motion-reduce:animate-none opacity-50"></div>

Copilot uses AI. Check for mistakes.
</div>

{levels.map((level, index) => (
<div key={level.id} className="relative z-20">
<div
key={level.id}
className="relative z-20 mb-8"
onMouseEnter={() => setHoveredLevel(level.id)}
onMouseLeave={() => setHoveredLevel(null)}
Comment on lines +371 to +373
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

Same accessibility issue with keyboard navigation. The hover effects triggered by onMouseEnter and onMouseLeave are not accessible to keyboard users. Add onFocus and onBlur handlers and ensure keyboard accessibility.

Suggested change
className="relative z-20 mb-8"
onMouseEnter={() => setHoveredLevel(level.id)}
onMouseLeave={() => setHoveredLevel(null)}
className="relative z-20 mb-8"
tabIndex={0}
onMouseEnter={() => setHoveredLevel(level.id)}
onMouseLeave={() => setHoveredLevel(null)}
onFocus={() => setHoveredLevel(level.id)}
onBlur={() => setHoveredLevel(null)}

Copilot uses AI. Check for mistakes.
>
<div
className={`flex items-center ${index % 2 === 0 ? "flex-row" : "flex-row-reverse"}`}
className={`flex items-center ${
index % 2 === 0 ? "flex-row" : "flex-row-reverse"
}`}
>
{/* Content Side */}
<div
className={`w-5/12 ${index % 2 === 0 ? "pr-12" : "pl-12"}`}
className={`w-5/12 ${
index % 2 === 0 ? "pr-12" : "pl-12"
}`}
>
<div className="bg-gray-800/40 backdrop-blur-md rounded-lg p-8 border border-white/10 transition-all duration-300 hover:bg-gray-800/50 hover:border-white/20 hover:scale-105">
<div className="flex items-center mb-4">
<div
className={`w-12 h-12 bg-gradient-to-br ${level.gradient} rounded-full flex items-center justify-center mr-4`}
>
<div className="text-white">{level.icon}</div>
</div>
<div>
<h3 className="text-2xl font-bold text-white">
{level.title}
</h3>
{level.timeframe && (
<div className="inline-block bg-blue-900/50 rounded-full px-3 py-1 text-xs text-blue-200 mt-1">
{level.timeframe}
</div>
)}
</div>
</div>
<div className="relative group">
{/* Glowing border */}
<div
className={`absolute -inset-[2px] bg-gradient-to-r ${level.gradient} rounded-xl opacity-0 group-hover:opacity-70 blur transition-opacity duration-500`}
></div>

<p className="text-gray-300 mb-6 leading-relaxed">
{level.description}
</p>
<div className="relative bg-gradient-to-br from-gray-900/90 to-gray-800/90 backdrop-blur-xl rounded-xl p-6 border border-white/5 overflow-hidden">
{/* Animated corner accents */}
<div
className={`absolute top-0 ${
index % 2 === 0 ? "right-0" : "left-0"
} w-24 h-24 bg-gradient-to-br ${level.gradient} rounded-full blur-3xl opacity-0 group-hover:opacity-20 transition-opacity duration-700`}
></div>
Comment on lines +388 to +398
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

Duplicate code pattern: The glowing border effect and animated background particles are duplicated between mobile (lines 273-286) and desktop (lines 388-398) layouts. Consider extracting this into a reusable component to improve maintainability and reduce code duplication.

Copilot uses AI. Check for mistakes.

<div className="space-y-3">
<h4 className="text-lg font-semibold text-white">
{t("requirementsLabel")}
</h4>
<ul className="space-y-2">
{level.requirements.map((req, reqIndex) => (
<li
key={reqIndex}
className="text-gray-300 flex items-start"
<div className="relative">
{/* Header */}
<div className="flex items-center gap-3 mb-3">
<div
className={`w-10 h-10 bg-gradient-to-br ${level.gradient} rounded-lg flex items-center justify-center group-hover:rotate-12 transition-transform duration-300`}
>
<span className="text-green-400 mr-3 mt-1 text-lg">
β€’
</span>
<span className="text-sm leading-relaxed">
{req}
</span>
</li>
))}
</ul>
</div>
<div className="text-white scale-90">
{level.icon}
</div>
</div>
<div className="flex-1">
<h3 className="text-xl font-bold text-white group-hover:text-transparent group-hover:bg-clip-text group-hover:bg-gradient-to-r group-hover:from-white group-hover:to-gray-300 transition-all duration-300">
{level.title}
</h3>
{level.timeframe && (
<div className="inline-block bg-blue-500/20 rounded-full px-2 py-0.5 text-xs text-blue-300 mt-1">
{level.timeframe}
</div>
)}
</div>
</div>

{level.goodStanding && (
<div className="mt-6 p-4 bg-blue-900/20 border border-blue-500/30 rounded-lg">
<h4 className="text-base font-semibold text-blue-300 mb-2">
{t("goodStandingLabel")}
</h4>
<p className="text-sm text-gray-300 leading-relaxed">
{level.goodStanding}
{/* Description */}
<p className="text-gray-400 text-sm mb-4 leading-relaxed">
{level.description}
</p>
</div>
)}

{index < levels.length - 1 && (
<div className="mt-6 pt-4 border-t border-gray-700/50">
<div className="text-sm text-gray-400">
{t("nextLevelLabel")}
</div>
<div className="text-lg font-semibold text-blue-400">
{level.nextLevel}
{/* Requirements */}
<div className="space-y-2 mb-4">
{level.requirements.map((req, reqIndex) => (
<div
key={reqIndex}
className="flex items-start gap-2 group/item"
>
<div
className={`w-1.5 h-1.5 rounded-full bg-gradient-to-r ${level.gradient} mt-1.5 flex-shrink-0 group-hover/item:scale-150 transition-transform duration-200`}
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

The nested group classes (group and group/item) create a nested hover state system. However, the group-hover/item:scale-150 transition on the bullet point may be too aggressive and could cause layout shifts. Consider using a more subtle scale value like scale-125 to prevent visual jumping.

Suggested change
className={`w-1.5 h-1.5 rounded-full bg-gradient-to-r ${level.gradient} mt-1.5 flex-shrink-0 group-hover/item:scale-150 transition-transform duration-200`}
className={`w-1.5 h-1.5 rounded-full bg-gradient-to-r ${level.gradient} mt-1.5 flex-shrink-0 group-hover/item:scale-125 transition-transform duration-200`}

Copilot uses AI. Check for mistakes.
></div>
<p className="text-xs text-gray-400 leading-relaxed">
{req}
</p>
</div>
))}
</div>

{/* Good Standing */}
{level.goodStanding && (
<div className="p-3 bg-gradient-to-br from-blue-500/10 to-purple-500/10 border border-blue-500/20 rounded-lg">
<p className="text-xs text-gray-300 leading-relaxed">
{level.goodStanding}
</p>
</div>
)}

{/* Next Level */}
{index < levels.length - 1 && (
<div className="mt-4 pt-3 border-t border-white/5 flex items-center justify-between">
<span className="text-xs text-gray-500">Next Level:</span>
<span
className={`text-sm font-semibold bg-gradient-to-r ${level.gradient} bg-clip-text text-transparent`}
>
{level.nextLevel}
</span>
</div>
)}
</div>
)}
</div>
</div>
</div>

{/* Center Circle */}
<div className="w-2/12 flex justify-center">
<div
className={`w-20 h-20 bg-gradient-to-br ${level.gradient} rounded-full flex items-center justify-center shadow-2xl z-30 transition-all duration-300 hover:scale-110`}
className={`relative w-16 h-16 bg-gradient-to-br ${level.gradient} rounded-full flex items-center justify-center shadow-2xl z-30 transition-all duration-300 ${
hoveredLevel === level.id ? "scale-125" : "scale-100"
}`}
>
<span className="text-white font-bold text-2xl">
<span className="text-white font-bold text-xl">
{level.id}
</span>
{/* Ripple effect */}
{hoveredLevel === level.id && (
<div
className={`absolute inset-0 rounded-full bg-gradient-to-br ${level.gradient} animate-ping opacity-75`}
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

The animate-ping effect continuously animates, which could be distracting and cause performance issues. Additionally, this animation should respect the prefers-reduced-motion setting for users with motion sensitivity. Consider conditionally rendering this effect or using CSS to disable it based on the media query.

Suggested change
className={`absolute inset-0 rounded-full bg-gradient-to-br ${level.gradient} animate-ping opacity-75`}
className={`absolute inset-0 rounded-full bg-gradient-to-br ${level.gradient} motion-safe:animate-ping opacity-75`}

Copilot uses AI. Check for mistakes.
></div>
)}
</div>
</div>

Expand Down
Loading