diff --git a/docusaurus.config.ts b/docusaurus.config.ts index 33815a3d..96281b9a 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -3,15 +3,15 @@ import type { Config } from "@docusaurus/types"; import type * as Preset from "@docusaurus/preset-classic"; import remarkMath from "remark-math"; import rehypeKatex from "rehype-katex"; +import * as dotenv from "dotenv"; +dotenv.config(); // This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) - const config: Config = { title: "Recode Hive", tagline: "Dinosaurs are cool", favicon: "img/favicon.ico", - url: "https://recodehive.com", baseUrl: "/", @@ -25,18 +25,18 @@ const config: Config = { // Google Analytics and Theme Scripts scripts: [ { - src: '/instant-theme.js', + src: "/instant-theme.js", async: false, }, { - src: 'https://www.googletagmanager.com/gtag/js?id=G-W02Z2VJYCR', + src: "https://www.googletagmanager.com/gtag/js?id=G-W02Z2VJYCR", async: true, }, { - src: '/gtag-init.js', + src: "/gtag-init.js", }, { - src: '/pinterest-init.js', + src: "/pinterest-init.js", }, ], @@ -47,14 +47,14 @@ const config: Config = { presets: [ [ - 'classic', + "classic", { docs: { - path: "docs", + path: "docs", routeBasePath: "docs", sidebarPath: require.resolve("./sidebars.ts"), editUrl: ({ docPath }) => - `https://github.com/recodehive/recode-website/tree/main/docs/${docPath}`, + `https://github.com/recodehive/recode-website/tree/main/docs/${docPath}`, }, blog: { showReadingTime: true, @@ -62,8 +62,7 @@ const config: Config = { type: ["rss", "atom"], xslt: true, }, - editUrl: - "https://github.com/recodehive/recode-website/tree/main", + editUrl: "https://github.com/recodehive/recode-website/tree/main", onInlineTags: "warn", onInlineAuthors: "warn", onUntruncatedBlogPosts: "warn", @@ -72,7 +71,7 @@ const config: Config = { customCss: require.resolve("./src/css/custom.css"), }, gtag: { - trackingID: 'G-W02Z2VJYCR', + trackingID: "G-W02Z2VJYCR", anonymizeIP: false, }, } satisfies Preset.Options, @@ -82,14 +81,13 @@ const config: Config = { themeConfig: { image: "img/docusaurus-social-card.jpg", colorMode: { - defaultMode: 'light', + defaultMode: "light", disableSwitch: false, respectPrefersColorScheme: false, // Let users manually control theme }, navbar: { - title:"Recode Hive", + title: "Recode Hive", logo: { - alt: "RecodeHive Logo", src: "img/logo.png", }, @@ -102,14 +100,14 @@ const config: Config = { { type: "html", value: `
- Tutorials -
- SQL - Python - GitHub - Nextjs -
-
`, + Tutorials +
+ SQL + Python + GitHub + Nextjs +
+ `, }, { type: "html", @@ -118,13 +116,13 @@ const config: Config = { { type: "html", value: `
- Courses -
- git - Postman - Google -
-
`, + Courses +
+ git + Postman + Google +
+ `, }, { type: "html", @@ -133,12 +131,12 @@ const config: Config = { { type: "html", value: `
- Interview Prep -
- 🧩Technical - 💡Behavioral -
-
`, + Interview Prep +
+ 🧩Technical + 💡Behavioral +
+ `, }, ], }, @@ -169,7 +167,7 @@ const config: Config = { { label: "🎖️ GitHub Badges", to: "/badges/github-badges/", - }, + }, ], }, { @@ -213,47 +211,10 @@ const config: Config = { position: "right", value: '
', }, - // { - // type: "dropdown", - // html: '🏷️ Tags', - // position: "left", - // items: [ - // { - // label: "🏷️ Tutorial Tags 📚", - // to: "/docs/tags/", - // activeBaseRegex: "/docs/tags/", - // }, - // { - // label: "🏷️ Courses Tags 🎓", - // to: "/courses/tags/", - // activeBaseRegex: "/courses/tags/", - // }, - // { - // label: "🏷️ DSA Tags 🧠", - // to: "/dsa/tags/", - // activeBaseRegex: "/dsa/tags/", - // }, - // ], - // }, - - // { - // href: "https://github.com/codeharborhub/codeharborhub", - // position: "right", - // className: "header-github-link", - // "aria-label": "GitHub repository", - // }, - // { - // href: "https://www.codeharborhub.live/register", - // position: "right", - // className: "header-signup-link", - // "aria-label": "Auth", - // label: "Auth", - // }, ], - // hideOnScroll: true, }, footer: { - style: 'dark', + style: "dark", links: [], copyright: `Copyright © ${new Date().getFullYear()} recodehive. Built with Docusaurus.`, }, @@ -294,22 +255,12 @@ const config: Config = { disableInDev: false, }, ], - // Commented out to use TSX-based community page instead - // [ - // "@docusaurus/plugin-content-docs", - // { - // id: "community", - // path: "community", - // routeBasePath: "community", - // sidebarPath: require.resolve("./sidebarsCommunity.js"), - // remarkPlugins: [remarkMath], - // rehypePlugins: [rehypeKatex], - // showLastUpdateAuthor: true, - // showLastUpdateTime: true, - // }, - // ], ], - // scripts: [], + + // ✅ Add this customFields object to expose the token to the client-side + customFields: { + gitToken: process.env.DOCUSAURUS_GIT_TOKEN, + }, }; -export default config; +export default config; \ No newline at end of file diff --git a/package.json b/package.json index 20b30ee6..16603219 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", - "dotenv": "^16.5.0", + "dotenv": "^16.6.1", "embla-carousel-autoplay": "^8.6.0", "embla-carousel-react": "^8.6.0", "firebase": "^9.22.2", diff --git a/src/components/dashboard/LeaderBoard/leaderboard.css b/src/components/dashboard/LeaderBoard/leaderboard.css new file mode 100644 index 00000000..580d8216 --- /dev/null +++ b/src/components/dashboard/LeaderBoard/leaderboard.css @@ -0,0 +1,646 @@ +/* LeaderBoard.css */ + +.leaderboard-container { + min-height: 100vh; + padding: 32px 8px; + transition: background-color 0.3s ease; +} + +.leaderboard-container.light { + background: #f6f6f6; +} + +.leaderboard-container.dark { + background: #23272f; +} + +.leaderboard-content { + max-width: 1100px; + margin: 0 auto; +} + +/* Header */ +.header { + text-align: center; + margin-bottom: 48px; + padding: 0 8px; +} + +.title { + font-size: 32px; + font-weight: 700; + margin-bottom: 12px; + color: #6366f1; +} + +.subtitle { + font-size: 17px; + max-width: 600px; + margin: 0 auto; + line-height: 1.6; +} + +.light .subtitle { + color: #555; +} + +.dark .subtitle { + color: #b3b3b3; +} + +/* Top Performers Section */ +.top-performers-container { + text-align: center; + margin-bottom: 40px; +} + +.top-performers-title { + font-size: 24px; + font-weight: 700; + margin-bottom: 24px; +} + +.light .top-performers-title { + color: #333; +} + +.dark .top-performers-title { + color: #f1f1f1; +} + +.top-performers-grid { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 24px; + justify-items: center; + align-items: end; +} + +.top-performer-card { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + padding: 24px; + border-radius: 12px; + transition: all 0.3s ease; +} + +.light .top-performer-card { + background: #fff; + border: 1px solid #e2e8f0; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); +} + +.dark .top-performer-card { + background: #2b303b; + border: 1px solid #444; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2); +} + +.top-performer-card:hover { + transform: translateY(-5px); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1); +} + +.top-performer-card .avatar.large { + width: 96px; + height: 96px; + border-radius: 50%; + margin-bottom: 12px; + border: 4px solid #fff; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +.dark .top-performer-card .avatar.large { + border: 4px solid #23272f; +} + +.rank-overlay { + position: absolute; + top: 8px; + left: 8px; + display: flex; + justify-content: center; + align-items: center; + width: 40px; + height: 40px; + border-radius: 50%; + font-weight: bold; + color: #fff; + border: 2px solid #fff; +} + +.rank-overlay.top-1 { + background-color: #f59e0b; + border-color: #fde68a; + box-shadow: 0 0 10px #fde047; +} + +.rank-overlay.top-2 { + background-color: #6b7280; + border-color: #d1d5db; +} + +.rank-overlay.top-3 { + background-color: #964b00; + border-color: #fcd34d; +} + +.performer-info { + margin-top: 8px; +} + +.performer-info .username-link { + font-weight: bold; + font-size: 1.1rem; + color: #6366f1; + text-decoration: none; +} + +/* Stats Grid */ +.stats-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 24px; + margin-bottom: 40px; +} + +@media (max-width: 768px) { + .stats-grid { + grid-template-columns: 1fr; + } +} + +.stat-card { + padding: 24px; + border-radius: 12px; + transition: all 0.3s ease; +} + +.light .stat-card { + background: #fff; + border: 1px solid #e2e8f0; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); +} + +.dark .stat-card { + background: #2b303b; + border: 1px solid #444; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2); +} + +.stat-card:hover { + transform: translateY(-3px); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1); +} + +.stat-content { + display: flex; + align-items: center; + gap: 16px; +} + +.stat-icon { + display: flex; + justify-content: center; + align-items: center; + width: 48px; + height: 48px; + border-radius: 50%; + color: #fff; + font-size: 20px; +} + +.stat-icon.users { + background: #3b82f6; +} + +.stat-icon.prs { + background: #ef4444; +} + +.stat-icon.points { + background: #10b981; +} + +.stat-value { + font-size: 2rem; + font-weight: 800; + margin-bottom: 4px; +} + +.light .stat-value { + color: #333; +} + +.dark .stat-value { + color: #f1f1f1; +} + +.stat-label { + font-size: 14px; + text-transform: uppercase; + font-weight: bold; +} + +.light .stat-label { + color: #666; +} + +.dark .stat-label { + color: #aaa; +} + +/* Search */ +.search-container { + display: flex; + justify-content: center; + margin-bottom: 40px; +} + +.search-wrapper { + position: relative; + width: 100%; + max-width: 500px; +} + +.search-icon { + position: absolute; + top: 50%; + left: 16px; + transform: translateY(-50%); + font-size: 18px; +} + +.light .search-icon { + color: #666; +} + +.dark .search-icon { + color: #aaa; +} + +.search-input { + width: 100%; + padding: 12px 12px 12px 48px; + border-radius: 8px; + font-size: 16px; +} + +.light .search-input { + background: #fff; + border: 1px solid #e2e8f0; + color: #333; +} + +.dark .search-input { + background: #2b303b; + border: 1px solid #444; + color: #f1f1f1; +} + +/* Contributors List */ +.contributors-container { + border-radius: 12px; + overflow: hidden; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); +} + +.light .contributors-container { + background: #fff; + border: 1px solid #e2e8f0; +} + +.dark .contributors-container { + background: #2b303b; + border: 1px solid #444; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2); +} + +.contributors-header { + display: grid; + grid-template-columns: 0.5fr 0.5fr 2fr 1fr 1fr; + padding: 16px 24px; + font-weight: bold; + font-size: 14px; + text-transform: uppercase; + letter-spacing: 0.5px; + border-bottom: 1px solid #e2e8f0; +} + +.light .contributors-header { + background: #f8fafc; + color: #666; + border-bottom: 1px solid #e2e8f0; +} + +.dark .contributors-header { + background: #323742; + color: #b3b3b3; + border-bottom: 1px solid #444; +} + +.contributor-row { + display: grid; + grid-template-columns: 0.5fr 0.5fr 2fr 1fr 1fr; + align-items: center; + padding: 16px 24px; + transition: background-color 0.2s ease; +} + +.light .contributor-row.even { + background: #fff; +} + +.light .contributor-row.odd { + background: #f8fafc; +} + +.dark .contributor-row.even { + background: #2b303b; +} + +.dark .contributor-row.odd { + background: #323742; +} + +.contributor-row:hover { + background-color: #f1f5f9; +} + +.dark .contributor-row:hover { + background-color: #3b424f; +} + +.contributor-cell { + padding: 0 8px; +} + +.avatar { + width: 40px; + height: 40px; + border-radius: 50%; + border: 2px solid #fff; +} + +.dark .avatar { + border-color: #2b303b; +} + +.username-link { + font-weight: bold; + color: #6366f1; + text-decoration: none; + font-size: 1.1rem; +} + +.light .username-link { + color: #3b82f6; +} + +.dark .username-link { + color: #60a5fa; +} + +/* Badges */ +.badges-container { + display: flex; + gap: 8px; + margin-top: 8px; +} + +.badge { + display: inline-block; + padding: 4px 10px; + border-radius: 9999px; + font-size: 12px; + font-weight: bold; +} + +.rank-badge { + display: flex; + justify-content: center; + align-items: center; + width: 32px; + height: 32px; + border-radius: 50%; + font-weight: bold; + color: #fff; +} + +.rank-badge.top-1 { + background-color: #f59e0b; +} + +.rank-badge.top-2 { + background-color: #6b7280; +} + +.rank-badge.top-3 { + background-color: #964b00; +} + +.rank-badge.regular { + background: #e5e7eb; + color: #666; +} + +.dark .rank-badge.regular { + background: #444; + color: #ccc; +} + +/* Pagination */ +.pagination { + display: flex; + justify-content: center; + align-items: center; + gap: 8px; + padding: 24px 0; +} + +.pagination-btn { + display: flex; + justify-content: center; + align-items: center; + width: 40px; + height: 40px; + border-radius: 50%; + border: none; + cursor: pointer; + transition: all 0.2s ease; +} + +.light .pagination-btn { + background: #e5e7eb; + color: #6b7280; +} + +.dark .pagination-btn { + background: #374151; + color: #d1d5db; +} + +.pagination-btn:hover:not(.disabled) { + background: #d1d5db; +} + +.dark .pagination-btn:hover:not(.disabled) { + background: #4b5563; +} + +.pagination-btn.disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.page-btn { + display: flex; + justify-content: center; + align-items: center; + width: 36px; + height: 36px; + border-radius: 8px; + border: none; + cursor: pointer; + font-weight: bold; + transition: all 0.2s ease; +} + +.light .page-btn { + background: transparent; + color: #666; +} + +.dark .page-btn { + background: transparent; + color: #b3b3b3; +} + +.page-btn:hover { + background: #e5e7eb; +} + +.dark .page-btn:hover { + background: #374151; +} + +.page-btn.active { + background: #2563eb; + color: #fff; +} + +.dark .page-btn.active { + background: #3b82f6; + color: #fff; +} + +.page-numbers { + display: flex; + gap: 8px; +} + +/* CTA Footer */ +.cta-footer { + padding: 16px 24px; + text-align: center; +} + +.light .cta-footer { + border-top: 1px solid #eee; + background: #f6f6f6; +} + +.dark .cta-footer { + border-top: 1px solid #444; + background: #23272f; +} + +.cta-text { + font-size: 14px; + margin-bottom: 12px; +} + +.light .cta-text { + color: #555; +} + +.dark .cta-text { + color: #b3b3b3; +} + +.cta-button { + display: inline-flex; + align-items: center; + padding: 8px 16px; + border-radius: 9999px; + font-weight: bold; + text-decoration: none; + transition: all 0.3s ease; +} + +.light .cta-button { + background: #2563eb; + color: #fff; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); +} + +.dark .cta-button { + background: #3b82f6; + color: #fff; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2); +} + +.cta-button:hover { + transform: translateY(-2px); + background: #1d4ed8; + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15); +} + +.dark .cta-button:hover { + background: #1e40af; +} + +/* Responsive design */ +@media (max-width: 768px) { + .leaderboard-container { + padding: 24px 8px; + } + .top-performers-grid { + grid-template-columns: 1fr; + gap: 20px; + } + .stats-grid { + grid-template-columns: 1fr; + } + .contributors-header { + display: none; + } + .contributor-row { + grid-template-columns: 1fr; + gap: 16px; + padding: 16px; + margin-bottom: 12px; + border-radius: 8px; + } + .contributor-cell { + padding: 0; + } + .rank-cell { + position: absolute; + top: 8px; + left: 8px; + } + .avatar-cell { + justify-self: center; + } + .username-cell { + text-align: center; + } + .prs-cell, + .points-cell { + justify-self: center; + } +} \ No newline at end of file diff --git a/src/components/dashboard/LeaderBoard/leaderboard.tsx b/src/components/dashboard/LeaderBoard/leaderboard.tsx new file mode 100644 index 00000000..a58ddc96 --- /dev/null +++ b/src/components/dashboard/LeaderBoard/leaderboard.tsx @@ -0,0 +1,319 @@ +// src/pages/dashboard/LeaderBoard/leaderboard.tsx +import React, { JSX, useState } from "react"; +import { motion } from "framer-motion"; +import { + FaTrophy, + FaStar, + FaCode, + FaUsers, + FaGithub, + FaSearch, +} from "react-icons/fa"; +import { ChevronRight, ChevronLeft } from "lucide-react"; +import { useColorMode } from "@docusaurus/theme-common"; +import { useCommunityStatsContext } from "@site/src/lib/statsProvider"; +import "./leaderboard.css"; + +const GITHUB_ORG = "recodehive"; + +// Users to exclude from the leaderboard +const EXCLUDED_USERS = ["sanjay-kv", "allcontributors", "allcontributors[bot]"]; + +interface Contributor { + username: string; + avatar: string; + profile: string; + points: number; + prs: number; +} + +interface Stats { + flooredTotalPRs: number; + totalContributors: number; + flooredTotalPoints: number; +} + +function Badge({ count, label, color }: { count: number; label: string; color: { background: string; color: string } }) { + return ( + + {count} {label} + + ); +} + +function TopPerformerCard({ contributor, rank }: { contributor: Contributor; rank: number }) { + const { colorMode } = useColorMode(); + const isDark = colorMode === "dark"; + const rankClass = rank === 1 ? "top-1" : rank === 2 ? "top-2" : "top-3"; + + return ( +
+ {contributor.username} +
+ {rank} +
+
+ + {contributor.username} + +
+ + +
+
+
+ ); +} + +export default function LeaderBoard(): JSX.Element { + const { contributors, stats, loading, error } = useCommunityStatsContext(); + const { colorMode } = useColorMode(); + const isDark = colorMode === "dark"; + + const [searchQuery, setSearchQuery] = useState(""); + const [currentPage, setCurrentPage] = useState(1); + const itemsPerPage = 10; + + // Filter out excluded users and then apply search filter + const filteredContributors = contributors + .filter((contributor) => + !EXCLUDED_USERS.some(excludedUser => + contributor.username.toLowerCase() === excludedUser.toLowerCase() + ) + ) + .filter((contributor) => + contributor.username.toLowerCase().includes(searchQuery.toLowerCase()) + ); + + const totalPages = Math.ceil(filteredContributors.length / itemsPerPage); + const indexOfLast = currentPage * itemsPerPage; + const indexOfFirst = indexOfLast - itemsPerPage; + const currentItems = filteredContributors.slice(indexOfFirst, indexOfLast); + + const paginate = (pageNumber: number) => setCurrentPage(Math.max(1, Math.min(pageNumber, totalPages))); + + const renderPaginationButtons = () => { + const pages = []; + for (let i = 1; i <= totalPages; i++) { + pages.push( + + ); + } + return pages; + }; + + const getRankClass = (index: number) => { + if (index === 0) return "top-1"; + if (index === 1) return "top-2"; + if (index === 2) return "top-3"; + return "regular"; + }; + + return ( +
+
+ {/* Header */} + +

Recode Hive Leaderboard

+

+ Top contributors across the {GITHUB_ORG} organization +

+
+ + {/* Top 3 Performers Section */} + {!loading && !error && filteredContributors.length > 2 && ( +
+

RecodeHive Top Performers

+
+ + + +
+
+ )} + + {/* Stats */} + {stats && ( +
+
+
+
+ +
+
+
{stats.totalContributors}
+
Total Contributors
+
+
+
+
+
+
+ +
+
+
{stats.flooredTotalPRs}
+
Merged PRs
+
+
+
+
+
+
+ +
+
+
{stats.flooredTotalPoints}
+
Total Points
+
+
+
+
+ )} + + {/* Search */} +
+
+ + { + setSearchQuery(e.target.value); + setCurrentPage(1); + }} + className={`search-input ${isDark ? "dark" : "light"}`} + /> +
+
+ + {loading && ( +
+
+
#
+
Contributor
+
Contributions
+
+ {[...Array(itemsPerPage)].map((_, i) => ( +
+
+
+
+
+
+
+
+
+
+
+ ))} +
+ )} + + {error && ( +
+

Error: {error}

+
+ )} + + {!loading && !error && filteredContributors.length === 0 && ( +
+

No contributors found.

+
+ )} + + {!loading && !error && filteredContributors.length > 0 && ( +
+
+
Rank
+
Avatar
+
User
+
PRs
+
Points
+
+ {currentItems.map((contributor, index) => ( + +
+
+ {indexOfFirst + index + 1} +
+
+
+ {contributor.username} +
+ +
+ +
+
+ +
+
+ ))} + + {/* Pagination */} + {totalPages > 1 && ( +
+ +
{renderPaginationButtons()}
+ +
+ )} + + {/* CTA Footer */} +
+

Want to get on this leaderboard?

+ + + Contribute on GitHub + +
+
+ )} +
+
+ ); +} \ No newline at end of file diff --git a/src/components/navbar/NavbarIcon.tsx b/src/components/navbar/NavbarIcon.tsx index 1a06566f..df6cbd8e 100644 --- a/src/components/navbar/NavbarIcon.tsx +++ b/src/components/navbar/NavbarIcon.tsx @@ -1,11 +1,52 @@ import React from "react"; import { NAVBAR_CONFIG, type NavbarIconName } from "../../constants/navbarConfig"; -interface NavbarIconProps { +// Legacy interface for dashboard usage +interface DashboardNavbarIconProps { + icon: React.ReactNode; + text: string; + active: boolean; + onClick: () => void; +} + +// New interface for navbar usage +interface ConfigNavbarIconProps { name: NavbarIconName; } -export default function NavbarIcon({ name }: NavbarIconProps) { +type NavbarIconProps = DashboardNavbarIconProps | ConfigNavbarIconProps; + +// Type guard to check if props are for dashboard usage +function isDashboardProps(props: NavbarIconProps): props is DashboardNavbarIconProps { + return 'icon' in props && 'text' in props && 'active' in props && 'onClick' in props; +} + +export default function NavbarIcon(props: NavbarIconProps) { + // Handle dashboard usage + if (isDashboardProps(props)) { + const { icon, text, active, onClick } = props; + return ( +
{ + if (e.key === 'Enter' || e.key === ' ') { + onClick(); + } + }} + > + + {icon} + + {text} +
+ ); + } + + // Handle navbar config usage + const { name } = props; const IconComponent = NAVBAR_CONFIG[name]; if (!IconComponent) { diff --git a/src/lib/statsProvider.tsx b/src/lib/statsProvider.tsx index e5b8bfa9..7d23451d 100644 --- a/src/lib/statsProvider.tsx +++ b/src/lib/statsProvider.tsx @@ -1,64 +1,227 @@ +// src/lib/statsProvider.tsx + /** @jsxImportSource react */ import React, { - createContext, - useCallback, - useContext, - useEffect, - useMemo, - useState, - } from "react"; + createContext, + useCallback, + useContext, + useEffect, + useMemo, + useState, + ReactNode, +} from "react"; import { githubService, type GitHubOrgStats } from "../services/githubService"; +import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; + +interface ICommunityStatsContext { + githubStarCount: number; + githubStarCountText: string; + githubContributorsCount: number; + githubContributorsCountText: string; + githubForksCount: number; + githubForksCountText: string; + githubReposCount: number; + githubReposCountText: string; + githubDiscussionsCount: number; + githubDiscussionsCountText: string; + loading: boolean; + error: string | null; + lastUpdated: Date | null; + refetch: (signal: AbortSignal) => Promise; + clearCache: () => void; + // New properties for leaderboard + contributors: Contributor[]; + stats: Stats | null; +} + +// Define types for leaderboard data +interface Contributor { + username: string; + avatar: string; + profile: string; + points: number; + prs: number; +} + +interface Stats { + flooredTotalPRs: number; + totalContributors: number; + flooredTotalPoints: number; +} + +interface PullRequestItem { + user: { + login: string; + avatar_url: string; + html_url: string; + }; + merged_at?: string | null; +} + +export const CommunityStatsContext = createContext(undefined); + +interface CommunityStatsProviderProps { + children: ReactNode; +} + +const GITHUB_ORG = "recodehive"; +const POINTS_PER_PR = 10; +const MAX_CONCURRENT_REQUESTS = 5; // Limit concurrent requests to avoid rate limiting + +export function CommunityStatsProvider({ children }: CommunityStatsProviderProps) { + const { + siteConfig: { customFields }, + } = useDocusaurusContext(); + const token = customFields?.gitToken || ""; + + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [githubStarCount, setGithubStarCount] = useState(0); + const [githubContributorsCount, setGithubContributorsCount] = useState(0); + const [githubForksCount, setGithubForksCount] = useState(0); + const [githubReposCount, setGithubReposCount] = useState(0); + const [githubDiscussionsCount, setGithubDiscussionsCount] = useState(0); + const [lastUpdated, setLastUpdated] = useState(null); - interface ICommunityStatsContext { - githubStarCount: number; - githubStarCountText: string; - githubContributorsCount: number; - githubContributorsCountText: string; - githubForksCount: number; - githubForksCountText: string; - githubReposCount: number; - githubReposCountText: string; - githubDiscussionsCount: number; - githubDiscussionsCountText: string; - loading: boolean; - error: string | null; - lastUpdated: Date | null; - refetch: (signal: AbortSignal) => Promise; - clearCache: () => void; - } - - export const CommunityStatsContext = createContext(undefined); - - interface CommunityStatsProviderProps { - children: React.ReactNode; - } - - export function CommunityStatsProvider({ children }: CommunityStatsProviderProps) { - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - const [githubStarCount, setGithubStarCount] = useState(0); - const [githubContributorsCount, setGithubContributorsCount] = useState(0); - const [githubForksCount, setGithubForksCount] = useState(0); - const [githubReposCount, setGithubReposCount] = useState(0); - const [githubDiscussionsCount, setGithubDiscussionsCount] = useState(0); - const [lastUpdated, setLastUpdated] = useState(null); - - const fetchGithubStats = useCallback(async (signal: AbortSignal) => { - try { - setLoading(true); - setError(null); - - const stats: GitHubOrgStats = await githubService.fetchOrganizationStats(signal); + // New state for leaderboard data + const [contributors, setContributors] = useState([]); + const [stats, setStats] = useState(null); + + const fetchAllOrgRepos = useCallback(async (headers: Record) => { + const repos: any[] = []; + let page = 1; + while (true) { + const resp = await fetch(`https://api.github.com/orgs/${GITHUB_ORG}/repos?type=public&per_page=100&page=${page}`, { + headers, + }); + if (!resp.ok) { + throw new Error(`Failed to fetch org repos: ${resp.status} ${resp.statusText}`); + } + const data = await resp.json(); + repos.push(...data); + if (!Array.isArray(data) || data.length < 100) break; + page++; + } + return repos; + }, []); + + const fetchMergedPRsForRepo = useCallback(async (repoName: string, headers: Record) => { + const mergedPRs: PullRequestItem[] = []; + let page = 1; + while (true) { + const resp = await fetch( + `https://api.github.com/repos/${GITHUB_ORG}/${repoName}/pulls?state=closed&per_page=100&page=${page}`, + { headers } + ); + if (!resp.ok) { + console.warn(`Failed to fetch PRs for ${repoName}: ${resp.status} ${resp.statusText}`); + break; + } + const prs: PullRequestItem[] = await resp.json(); + if (!Array.isArray(prs) || prs.length === 0) break; + + const merged = prs.filter((pr) => Boolean(pr.merged_at)); + mergedPRs.push(...merged); + + if (prs.length < 100) break; + page++; + } + return mergedPRs; + }, []); + + // NEW: Concurrent processing function with controlled concurrency + const processBatch = useCallback(async ( + repos: any[], + headers: Record + ): Promise<{ contributorMap: Map; totalMergedPRs: number }> => { + const contributorMap = new Map(); + let totalMergedPRs = 0; + + // Process repos in batches to control concurrency + for (let i = 0; i < repos.length; i += MAX_CONCURRENT_REQUESTS) { + const batch = repos.slice(i, i + MAX_CONCURRENT_REQUESTS); + + const promises = batch.map(async (repo) => { + if (repo.archived) return { mergedPRs: [], repoName: repo.name }; - setGithubStarCount(stats.totalStars); - setGithubContributorsCount(stats.totalContributors); - setGithubForksCount(stats.totalForks); - setGithubReposCount(stats.publicRepositories); - setGithubDiscussionsCount(stats.discussionsCount); - setLastUpdated(new Date(stats.lastUpdated)); - - console.log("GitHub organization stats fetched successfully:", stats); - } catch (err) { + try { + const mergedPRs = await fetchMergedPRsForRepo(repo.name, headers); + return { mergedPRs, repoName: repo.name }; + } catch (error) { + console.warn(`Skipping repo ${repo.name} due to error:`, error); + return { mergedPRs: [], repoName: repo.name }; + } + }); + + // Wait for current batch to complete + const results = await Promise.all(promises); + + // Process results from this batch + results.forEach(({ mergedPRs }) => { + totalMergedPRs += mergedPRs.length; + + mergedPRs.forEach((pr) => { + const username = pr.user.login; + if (!contributorMap.has(username)) { + contributorMap.set(username, { + username, + avatar: pr.user.avatar_url, + profile: pr.user.html_url, + points: 0, + prs: 0, + }); + } + const contributor = contributorMap.get(username)!; + contributor.prs++; + contributor.points += POINTS_PER_PR; + }); + }); + } + + return { contributorMap, totalMergedPRs }; + }, [fetchMergedPRsForRepo]); + + const fetchAllStats = useCallback(async (signal: AbortSignal) => { + setLoading(true); + setError(null); + if (!token) { + setError("GitHub token not found. Please set customFields.gitToken in docusaurus.config.js."); + setLoading(false); + return; + } + + try { + const headers: Record = { + Authorization: `token ${token}`, + Accept: "application/vnd.github.v3+json", + }; + + // Fetch general organization stats (unchanged) + const orgStats: GitHubOrgStats = await githubService.fetchOrganizationStats(signal); + setGithubStarCount(orgStats.totalStars); + setGithubContributorsCount(orgStats.totalContributors); + setGithubForksCount(orgStats.totalForks); + setGithubReposCount(orgStats.publicRepositories); + setGithubDiscussionsCount(orgStats.discussionsCount); + setLastUpdated(new Date(orgStats.lastUpdated)); + + // Fetch leaderboard data with concurrent processing + const repos = await fetchAllOrgRepos(headers); + + // NEW: Use concurrent processing instead of sequential + const { contributorMap, totalMergedPRs } = await processBatch(repos, headers); + + const sortedContributors = Array.from(contributorMap.values()).sort( + (a, b) => b.points - a.points || b.prs - a.prs + ); + setContributors(sortedContributors); + setStats({ + flooredTotalPRs: totalMergedPRs, + totalContributors: sortedContributors.length, + flooredTotalPoints: sortedContributors.reduce((sum, c) => sum + c.points, 0), + }); + + } catch (err: any) { if (err.name !== 'AbortError') { console.error("Error fetching GitHub organization stats:", err); setError(err instanceof Error ? err.message : 'Failed to fetch GitHub stats'); @@ -73,90 +236,76 @@ import { githubService, type GitHubOrgStats } from "../services/githubService"; } finally { setLoading(false); } - }, []); - - const clearCache = useCallback(() => { - githubService.clearCache(); - // Optionally refetch after clearing cache - const abortController = new AbortController(); - fetchGithubStats(abortController.signal); - }, [fetchGithubStats]); - - useEffect(() => { - const abortController = new AbortController(); - fetchGithubStats(abortController.signal); - - return () => { - abortController.abort(); - }; - }, [fetchGithubStats]); - - const githubStarCountText = useMemo(() => { - return convertStatToText(githubStarCount); - }, [githubStarCount]); - - const githubContributorsCountText = useMemo(() => { - return convertStatToText(githubContributorsCount); - }, [githubContributorsCount]); - - const githubForksCountText = useMemo(() => { - return convertStatToText(githubForksCount); - }, [githubForksCount]); - - const githubReposCountText = useMemo(() => { - return convertStatToText(githubReposCount); - }, [githubReposCount]); - - const githubDiscussionsCountText = useMemo(() => { - return convertStatToText(githubDiscussionsCount); - }, [githubDiscussionsCount]); - - const value: ICommunityStatsContext = { - githubStarCount, - githubStarCountText, - githubContributorsCount, - githubContributorsCountText, - githubForksCount, - githubForksCountText, - githubReposCount, - githubReposCountText, - githubDiscussionsCount, - githubDiscussionsCountText, - loading, - error, - lastUpdated, - refetch: fetchGithubStats, - clearCache, + }, [token, fetchAllOrgRepos, processBatch]); + + const clearCache = useCallback(() => { + githubService.clearCache(); + const abortController = new AbortController(); + fetchAllStats(abortController.signal); + }, [fetchAllStats]); + + useEffect(() => { + const abortController = new AbortController(); + fetchAllStats(abortController.signal); + + return () => { + abortController.abort(); }; - - return ( - - {children} - - ); - } - - export const useCommunityStatsContext = (): ICommunityStatsContext => { - const context = useContext(CommunityStatsContext); - if (context === undefined) { - throw new Error("useCommunityStatsContext must be used within a CommunityStatsProvider"); - } - return context; - }; - - export const convertStatToText = (num: number): string => { - const hasIntlSupport = - typeof Intl === "object" && Intl && typeof Intl.NumberFormat === "function"; - - if (!hasIntlSupport) { - return `${(num / 1000).toFixed(1)}k`; - } - - const formatter = new Intl.NumberFormat("en-US", { - notation: "compact", - compactDisplay: "short", - maximumSignificantDigits: 3, - }); - return formatter.format(num); + }, [fetchAllStats]); + + const githubStarCountText = useMemo(() => convertStatToText(githubStarCount), [githubStarCount]); + const githubContributorsCountText = useMemo(() => convertStatToText(githubContributorsCount), [githubContributorsCount]); + const githubForksCountText = useMemo(() => convertStatToText(githubForksCount), [githubForksCount]); + const githubReposCountText = useMemo(() => convertStatToText(githubReposCount), [githubReposCount]); + const githubDiscussionsCountText = useMemo(() => convertStatToText(githubDiscussionsCount), [githubDiscussionsCount]); + + const value: ICommunityStatsContext = { + githubStarCount, + githubStarCountText, + githubContributorsCount, + githubContributorsCountText, + githubForksCount, + githubForksCountText, + githubReposCount, + githubReposCountText, + githubDiscussionsCount, + githubDiscussionsCountText, + loading, + error, + lastUpdated, + refetch: fetchAllStats, + clearCache, + contributors, + stats, }; - \ No newline at end of file + + return ( + + {children} + + ); +} + +export const useCommunityStatsContext = (): ICommunityStatsContext => { + const context = useContext(CommunityStatsContext); + if (context === undefined) { + throw new Error("useCommunityStatsContext must be used within a CommunityStatsProvider"); + } + return context; +}; + +export const convertStatToText = (num: number): string => { + const hasIntlSupport = + typeof Intl === "object" && Intl && typeof Intl.NumberFormat === "function"; + + if (!hasIntlSupport) { + return `${(num / 1000).toFixed(1)}k`; + } + + const formatter = new Intl.NumberFormat("en-US", { + notation: "compact", + compactDisplay: "short", + maximumSignificantDigits: 3, + }); + return formatter.format(num); +}; \ No newline at end of file diff --git a/src/pages/dashboard/dashboard.css b/src/pages/dashboard/dashboard.css index 2c600b7c..866f0e74 100644 --- a/src/pages/dashboard/dashboard.css +++ b/src/pages/dashboard/dashboard.css @@ -1,3803 +1,709 @@ -/* Dashboard Layout */ +/* Dashboard Layout Styles */ .dashboard-layout { display: flex; min-height: 100vh; - background-color: var(--ifm-background-color); - position: relative; + background: var(--ifm-background-color); + position:relative; } -/* Sidebar Styles */ -.dashboard-sidebar { - width: 260px; - background: var(--ifm-card-background-color); - border-right: 1px solid var(--ifm-toc-border-color); - padding: 1.5rem 0; +/* Dashboard Menu Button - Mobile Only */ +.dashboard-menu-btn { + display: none; position: fixed; - height: 100vh; - overflow-y: auto; - transition: width 0.3s ease, transform 0.3s ease; - /* z-index: 100; */ - display: flex; - flex-direction: column; -} - -.sidebar-header { - padding: 0 1.5rem; - margin-bottom: 1.5rem; - position: relative; - display: flex; - justify-content: space-between; - align-items: center; -} - -.sidebar-logo { - padding: 0 0 1.5rem 0; - border-bottom: 1px solid var(--ifm-toc-border-color); - margin-bottom: 0; - flex-grow: 1; - transition: opacity 0.2s ease; -} - -.sidebar-logo h2 { - margin: 0; - color: var(--ifm-color-primary); -} - -.sidebar-nav { - list-style: none; - padding: 0; - margin: 0; - flex-grow: 1; -} - -.sidebar-footer { - padding: 1rem 1.5rem 0; - margin-top: auto; - border-top: 1px solid var(--ifm-toc-border-color); - padding-top: 1.5rem; - transition: opacity 0.2s ease; -} - -.nav-item { - display: flex; - align-items: center; - padding: 0.75rem 1.5rem; - cursor: pointer; - transition: all 0.2s ease; - color: var(--ifm-font-color-base); - white-space: nowrap; -} - -.nav-item:hover { - background: var(--ifm-menu-color-background-active); - color: var(--ifm-color-primary); -} - -.nav-item.active { - background: var(--ifm-menu-color-background-active); - border-left: 3px solid var(--ifm-color-primary); - color: var(--ifm-color-primary); - font-weight: 600; -} - -.nav-icon { - margin-right: 0.75rem; - font-size: 1.25rem; -} - -/* Toggle Button */ -.sidebar-toggle { + top: 70px; + left: 20px; + z-index: 1100; background: var(--ifm-color-primary); color: white; border: none; - border-radius: 50%; - width: 30px; - height: 30px; - display: flex; - align-items: center; - justify-content: center; + border-radius: 8px; + width: 44px; + height: 44px; cursor: pointer; - margin-left: 1rem; - flex-shrink: 0; - transition: background-color 0.2s ease; - margin-bottom: 20px; + font-size: 18px; + font-weight: bold; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); + transition: all 0.3s ease; } -.sidebar-toggle:hover { +.dashboard-menu-btn:hover { background: var(--ifm-color-primary-dark); + transform: scale(1.05); } -.sidebar-toggle.bottom-toggle { - margin: 1.5rem auto 0; - display: block; -} - -/* Collapsed Sidebar */ -.dashboard-sidebar.collapsed { - width: 70px; - overflow: hidden; +.dashboard-menu-btn.open { + background: #dc3545; } -.dashboard-sidebar.collapsed .sidebar-logo h2, -.dashboard-sidebar.collapsed .nav-text, -.dashboard-sidebar.collapsed .sidebar-footer { - opacity: 0; +/* Mobile Menu */ +.dashboard-mobile-menu { + display: none; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 1050; pointer-events: none; - white-space: nowrap; -} - -.dashboard-sidebar.collapsed .sidebar-header { - justify-content: center; - padding: 0 1rem; -} - -.dashboard-sidebar.collapsed .sidebar-toggle { - position: absolute; - margin-right: 20px; - top: -1px; -} - -.dashboard-sidebar.collapsed .sidebar-toggle.bottom-toggle { - position: static; - margin: 1rem auto 0; -} - -.dashboard-sidebar.collapsed .nav-item { - padding: 0.75rem 1rem; -} - -.dashboard-sidebar.collapsed .nav-icon { - margin-right: 0; - font-size: 1.5rem; -} - -/* Main Content */ -.dashboard-main { - flex: 1; - margin-left: 300px; /* Match sidebar width */ - padding: 2rem; - max-width: calc(100% - 300px); - transition: margin-left 0.3s ease, max-width 0.3s ease; -} - -.dashboard-main.sidebar-collapsed { - margin-left: 70px; - max-width: calc(100% - 70px); -} - -.dashboard-main.discuss-view { - max-width: 100%; -} - -.dashboard-main.sidebar-collapsed.discuss-view { - margin-left: 0; - max-width: 100%; -} - -/* Discussion Section - Enhanced Modern UI */ -.discussion-container { - max-width: 1400px; - margin: 0 auto; - padding: 2rem 1rem; - color: var(--ifm-font-color-base); - position: relative; - overflow-x: hidden; - width: 100%; - box-sizing: border-box; } -/* Sidebar compatibility */ -.dashboard-main.discuss-view .discussion-container { - padding: 2rem 2rem; -} - -.dashboard-main.sidebar-collapsed.discuss-view .discussion-container { - padding: 2rem 1rem; +.dashboard-mobile-menu.show { + display: block; + pointer-events: all; } -/* Animated background particles */ -.discussion-container::before { - content: ""; +.dashboard-menu-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; - background: radial-gradient( - circle at 20% 50%, - var(--ifm-color-primary-lightest) 0%, - transparent 50% - ), - radial-gradient( - circle at 80% 20%, - var(--ifm-color-secondary-lightest) 0%, - transparent 50% - ), - radial-gradient( - circle at 40% 80%, - var(--ifm-color-primary-lightest) 0%, - transparent 50% - ); - opacity: 0.3; - pointer-events: none; - z-index: -1; -} - -.discussion-header { - text-align: center; - margin-bottom: 3rem; - position: relative; - z-index: 1; -} - -.discussion-header h1 { - font-size: 3.5rem; - font-weight: 800; - margin-bottom: 1rem; - color: var(--ifm-color-emphasis-900); - position: relative; - display: inline-block; + background: rgba(0, 0, 0, 0.5); + z-index: 1051; } -.discussion-header h1::after { - content: ""; +.dashboard-mobile-menu > div:last-child { position: absolute; - bottom: -10px; - left: 50%; - transform: translateX(-50%); - width: 60px; - height: 4px; - background: linear-gradient( - 135deg, - var(--ifm-color-primary), - var(--ifm-color-secondary) - ); - border-radius: 2px; - animation: pulse-glow 2s ease-in-out infinite alternate; -} - -@keyframes pulse-glow { - 0% { - box-shadow: 0 0 5px var(--ifm-color-primary); - width: 60px; - } - 100% { - box-shadow: 0 0 20px var(--ifm-color-primary), - 0 0 30px var(--ifm-color-primary-light); - width: 80px; - } -} - -.discussion-header h1 .highlight { - background: linear-gradient( - 135deg, - var(--ifm-color-primary), - #e74c3c, - var(--ifm-color-secondary) - ); - background-size: 200% 200%; - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - animation: gradient-shift 3s ease-in-out infinite; -} - -@keyframes gradient-shift { - 0%, - 100% { - background-position: 0% 50%; - } - 50% { - background-position: 100% 50%; - } + top: 0; + left: 0; + width: 280px; + height: 100vh; + background: var(--ifm-background-color); + border-right: 1px solid var(--ifm-color-emphasis-200); + z-index: 1052; + overflow-y: auto; + transform: translateX(-100%); + transition: transform 0.3s ease; } -.discussion-header p { - font-size: 1.2rem; - color: var(--ifm-color-emphasis-700); - max-width: 700px; - margin: 0 auto; - line-height: 1.6; - opacity: 0.9; +.dashboard-mobile-menu.show > div:last-child { + transform: translateX(0); } -/* Enhanced Toolbar */ -.discussion-toolbar { +.dashboard-menu-header { + padding: 20px; + border-bottom: 1px solid var(--ifm-color-emphasis-200); display: flex; justify-content: space-between; align-items: center; - margin-bottom: 2rem; - padding: 1rem 1.5rem; - background: var(--ifm-card-background-color); - border-radius: 20px; - border: 1px solid var(--ifm-color-border); - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08); - backdrop-filter: blur(10px); - /* background-color: rgba(255, 255, 255, 0.95); */ - position: relative; - overflow: hidden; } -[data-theme="dark"] .discussion-toolbar { - background: rgba(var(--ifm-card-background-color-rgb), 0.8); - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); +.dashboard-menu-header h3 { + margin: 0; + font-size: 18px; + font-weight: 600; } -.discussion-toolbar::before { - content: ""; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient( - 90deg, - transparent, - rgba(255, 255, 255, 0.1), - transparent - ); - transition: left 0.5s; +.close-menu-btn { + background: none; + border: none; + font-size: 24px; + cursor: pointer; + color: var(--ifm-color-content); + padding: 0; + width: 30px; + height: 30px; + display: flex; + align-items: center; + justify-content: center; } -.discussion-toolbar:hover::before { - left: 100%; +.dashboard-menu-items { + padding: 20px 0; } -.toolbar-left { +.menu-item { display: flex; align-items: center; - gap: 0.75rem; -} - -/* Enhanced Tab Buttons */ -.tab-btn { - padding: 0.875rem 1.5rem; - border: none; - background: transparent; - color: var(--ifm-color-emphasis-700); - font-size: 0.95rem; - font-weight: 600; + padding: 12px 20px; cursor: pointer; - border-radius: 12px; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - position: relative; - overflow: hidden; - display: flex; - align-items: center; - gap: 0.5rem; - white-space: nowrap; - flex-shrink: 0; + transition: all 0.2s ease; + color: var(--ifm-color-content); + font-weight: 500; } -.tab-btn::before { - content: ""; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: var(--ifm-color-primary); - opacity: 0; - transition: opacity 0.3s ease; - z-index: -1; +.menu-item:hover { + background: var(--ifm-color-emphasis-100); } -.tab-btn:hover { +.menu-item.active { background: var(--ifm-color-primary-lightest); color: var(--ifm-color-primary); - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); -} - -.tab-btn:hover::before { - opacity: 0.1; -} - -.tab-btn.active { - background: var(--ifm-color-primary); - color: white; - box-shadow: 0 4px 20px rgba(var(--ifm-color-primary-rgb), 0.4); - transform: translateY(-1px); -} - -.tab-btn.active::before { - opacity: 1; -} - -/* Enhanced Sort Dropdown */ -.sort-dropdown { - position: relative; -} - -.sort-dropdown select { - padding: 0.875rem 3rem 0.875rem 1.5rem; - border: 2px solid var(--ifm-color-border); - border-radius: 12px; - background: var(--ifm-card-background-color); - color: var(--ifm-color-emphasis-700); - font-size: 0.95rem; - font-weight: 600; - cursor: pointer; - appearance: none; - transition: all 0.3s ease; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); -} - -.sort-dropdown select:hover { - border-color: var(--ifm-color-primary); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); - transform: translateY(-1px); + border-right: 3px solid var(--ifm-color-primary); } -.sort-dropdown select:focus { - outline: none; - border-color: var(--ifm-color-primary); - box-shadow: 0 0 0 3px var(--ifm-color-primary-lightest); +.menu-icon { + margin-right: 12px; + display: flex; + align-items: center; } -.sort-dropdown::after { - content: "▼"; - position: absolute; - right: 1rem; - top: 50%; - transform: translateY(-50%); - color: var(--ifm-color-primary); - pointer-events: none; - transition: transform 0.3s ease; +/* Sidebar Styles */ +.dashboard-sidebar { + width: 280px; + background: var(--ifm-background-color); + border-right: 1px solid var(--ifm-color-emphasis-200); + padding: 20px; + flex-shrink: 0; + position: sticky; + top: 0; + height: 100vh; + overflow-y: auto; } -.sort-dropdown:hover::after { - transform: translateY(-50%) scale(1.1); +.sidebar-header { + margin-bottom: 30px; } -/* Enhanced New Discussion Button */ -.new-discussion-btn { +.back-button { display: flex; align-items: center; - gap: 0.75rem; - padding: 0.875rem 2rem; - background: linear-gradient( - 135deg, - var(--ifm-color-primary), - var(--ifm-color-primary-dark) - ); - color: white; + padding: 10px; + background: var(--ifm-color-emphasis-100); border: none; - border-radius: 25px; - font-size: 0.95rem; - font-weight: 700; + border-radius: 8px; cursor: pointer; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - position: relative; - overflow: hidden; - box-shadow: 0 4px 15px rgba(var(--ifm-color-primary-rgb), 0.3); - white-space: nowrap; + transition: all 0.2s ease; + color: var(--ifm-color-content); } -.new-discussion-btn:hover { - transform: translateY(-3px); - box-shadow: 0 8px 25px rgba(var(--ifm-color-primary-rgb), 0.4); +.back-button:hover { + background: var(--ifm-color-emphasis-200); + transform: translateX(-2px); } -/* Enhanced Categories Bar */ -.categories-bar { +.sidebar-nav { display: flex; - gap: 1rem; - margin-bottom: 2rem; - padding: 1rem 0; - overflow-x: auto; - scrollbar-width: none; - position: relative; -} - -.categories-bar::-webkit-scrollbar { - display: none; -} - -.category { - padding: 0.75rem 1.5rem; - border-radius: 25px; - background: var(--ifm-card-background-color); - border: 2px solid var(--ifm-color-border); - color: var(--ifm-color-emphasis-700); - font-size: 0.9rem; - font-weight: 600; - cursor: pointer; - white-space: nowrap; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); - flex-shrink: 0; -} - -.category:hover { - transform: translateY(-2px); - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); - border-color: var(--ifm-color-primary); - color: var(--ifm-color-primary); -} - -.category.active { - background: var(--ifm-color-primary); - color: white; - border-color: var(--ifm-color-primary); - font-weight: 700; - transform: translateY(-2px); - box-shadow: 0 4px 20px rgba(var(--ifm-color-primary-rgb), 0.3); + flex-direction: column; + gap: 8px; } -/* Enhanced Search Filters */ -.search-filters { +/* Navbar Icon Items for Dashboard */ +.navbar-icon-item { display: flex; - gap: 1.5rem; - margin-bottom: 2.5rem; align-items: center; -} - -.search-bar { - flex: 1; + padding: 12px 16px; + border-radius: 8px; + cursor: pointer; + transition: all 0.2s ease; + color: var(--ifm-color-content); + font-weight: 500; + text-decoration: none; position: relative; - min-width: 0; } -.search-bar input { - width: 100%; - padding: 1rem 1.5rem 1rem 3.5rem; - border: 2px solid var(--ifm-color-border); - border-radius: 15px; - background: var(--ifm-card-background-color); - color: var(--ifm-font-color-base); - font-size: 1rem; - font-weight: 500; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); -} - -.search-bar input:focus { - outline: none; - border-color: var(--ifm-color-primary); - box-shadow: 0 0 0 3px var(--ifm-color-primary-lightest), - 0 4px 12px rgba(0, 0, 0, 0.1); - transform: translateY(-1px); -} - -.searchbar-icon { - position: absolute; - top: 50%; - left: 1.25rem; - transform: translateY(-50%); - color: var(--ifm-color-primary); - font-size: 1.1rem; - transition: all 0.3s ease; - z-index: 1; -} - -.searchbar-icon::before { - content: "🔍"; - font-size: 1rem; -} - -/* Responsive Design */ -@media (max-width: 1200px) { - .dashboard-main.discuss-view .discussion-container { - padding: 2rem 1.5rem; - } -} - -@media (max-width: 992px) { - .dashboard-main { - margin-left: 0; - max-width: 100%; - padding: 1rem; - } - - .discussion-container { - padding: 1rem; - } - - .discussion-header h1 { - font-size: 2.5rem; - } -} - -@media (max-width: 768px) { - .discussion-header h1 { - font-size: 2rem; - } - - .discussion-header p { - font-size: 1rem; - } - - .discussion-toolbar { - flex-direction: column; - gap: 1rem; - padding: 1rem; - } - - .toolbar-left { - flex-wrap: wrap; - justify-content: center; - gap: 0.5rem; - } - - .tab-btn { - padding: 0.75rem 1rem; - font-size: 0.85rem; - } - - .new-discussion-btn { - width: 100%; - justify-content: center; - padding: 1rem; - } - - .categories-bar { - padding: 0.5rem 0; - gap: 0.75rem; - } - - .category { - padding: 0.6rem 1rem; - font-size: 0.85rem; - } - - .search-filters { - flex-direction: column; - gap: 1rem; - } - - .search-bar input { - padding: 0.875rem 1rem 0.875rem 3rem; - font-size: 0.9rem; - } - - .sort-dropdown select { - width: 100%; - padding: 0.875rem 2.5rem 0.875rem 1rem; - } -} - -@media (max-width: 480px) { - .discussion-container { - padding: 0.5rem; - } - - .discussion-header { - margin-bottom: 2rem; - } - - .discussion-header h1 { - font-size: 1.75rem; - } - - .discussion-header p { - font-size: 0.9rem; - } - - .discussion-toolbar { - padding: 0.75rem; - } - - .tab-btn { - padding: 0.6rem 0.8rem; - font-size: 0.8rem; - } - - .category { - padding: 0.5rem 0.8rem; - font-size: 0.8rem; - } - - .search-bar input { - padding: 0.75rem 0.875rem 0.75rem 2.75rem; - font-size: 0.85rem; - } - - .searchbar-icon { - left: 1rem; - } - - .sort-dropdown select { - padding: 0.75rem 2rem 0.75rem 0.875rem; - font-size: 0.85rem; - } -} - -/* Dashboard Mobile Menu Button */ -.dashboard-menu-btn { - display: none; - position: fixed; - top: 4rem; - right: 1rem; - z-index: 1001; - background: var(--ifm-color-primary); - color: white; - border: none; - border-radius: 8px; - width: 44px; - height: 44px; - align-items: center; - justify-content: center; - cursor: pointer; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); - transition: all 0.3s ease; - font-size: 1.2rem; -} - -.dashboard-menu-btn:hover { - background: var(--ifm-color-primary-dark); - transform: scale(1.05); -} - -/* Dashboard Mobile Menu */ -.dashboard-mobile-menu { - position: fixed; - top: 0; - right: -100%; - width: 280px; - height: 100vh; - background: var(--ifm-card-background-color); - border-left: 1px solid var(--ifm-color-border); - z-index: 1002; - transition: right 0.3s ease; - box-shadow: -2px 0 10px rgba(0, 0, 0, 0.1); - overflow-y: auto; -} - -.dashboard-mobile-menu.show { - right: 0; -} - -/* Mobile menu overlay */ -.dashboard-menu-overlay { - position: fixed; - top: 0; - left: 0; - right: 280px; - bottom: 0; - background: rgba(0, 0, 0, 0.5); - z-index: -1; - cursor: pointer; -} - -.dashboard-menu-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: 1.5rem; - border-bottom: 1px solid var(--ifm-color-border); - background: var(--ifm-color-primary); - color: white; -} - -.dashboard-menu-header h3 { - margin: 0; - font-size: 1.2rem; - font-weight: 600; - color: white; -} - -.close-menu-btn { - background: none; - border: none; - color: white; - font-size: 1.5rem; - cursor: pointer; - padding: 0.25rem; - border-radius: 4px; - transition: background-color 0.2s ease; -} - -.close-menu-btn:hover { - background: rgba(255, 255, 255, 0.1); -} - -.menu-divider { - height: 1px; - background: var(--ifm-color-border); - margin: 0.5rem 0; -} - -.dashboard-menu-items { - padding: 1rem 0; -} - -.menu-item { - display: flex; - align-items: center; - padding: 0.875rem 1.5rem; - cursor: pointer; - transition: all 0.2s ease; - color: var(--ifm-font-color-base); - border-left: 3px solid transparent; -} - -.menu-item:hover { - background: var(--ifm-menu-color-background-active); - color: var(--ifm-color-primary); -} - -.menu-item.active { - background: var(--ifm-menu-color-background-active); - border-left-color: var(--ifm-color-primary); - color: var(--ifm-color-primary); - font-weight: 600; -} - - - -.menu-icon { - margin-right: 0.75rem; - font-size: 1.1rem; - display: flex; - align-items: center; -} - -.menu-text { - font-size: 0.95rem; -} - -/* Mobile responsive styles */ -@media (max-width: 992px) { - .dashboard-menu-btn { - display: flex; - } - - .dashboard-sidebar { - display: none; - } - - .dashboard-layout::before { - content: ""; - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.5); - z-index: 999; - opacity: 0; - visibility: hidden; - transition: all 0.3s ease; - } - - .dashboard-mobile-menu.show ~ .dashboard-main::before { - content: ""; - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.5); - z-index: 999; - opacity: 1; - visibility: visible; - } - - .discussion-container { - padding-top: 4rem; - } - - .dashboard-main { - margin-left: 0; - max-width: 100%; - padding: 1rem; - } -} - -/* Sidebar collapsed states */ -@media (min-width: 993px) { - .dashboard-main.sidebar-collapsed.discuss-view .discussion-container { - padding: 2rem 1.5rem; - } -} - -/* Dark theme support for dashboard mobile menu */ -[data-theme="dark"] .dashboard-mobile-menu { - background: var(--ifm-background-surface-color); - border-left-color: var(--ifm-color-emphasis-300); - box-shadow: -2px 0 10px rgba(0, 0, 0, 0.3); -} - -[data-theme="dark"] .dashboard-menu-header { - background: var(--ifm-color-primary); -} - - - -/* Responsive adjustments for mobile menu */ - - -@media (max-width: 320px) { - .dashboard-menu-header { - padding: 1rem; - } - - .menu-item { - padding: 0.75rem 1rem; - } - - -} - -/* Enhanced New Discussion Button */ -.new-discussion-btn { - display: flex; - align-items: center; - gap: 0.75rem; - padding: 0.875rem 2rem; - background: linear-gradient( - 135deg, - var(--ifm-color-primary), - var(--ifm-color-primary-dark) - ); - color: white; - border: none; - border-radius: 25px; - font-size: 0.95rem; - font-weight: 700; - cursor: pointer; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - position: relative; - overflow: hidden; - box-shadow: 0 4px 15px rgba(var(--ifm-color-primary-rgb), 0.3); -} - -.new-discussion-btn::before { - content: ""; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient( - 90deg, - transparent, - rgba(255, 255, 255, 0.2), - transparent - ); - transition: left 0.5s; -} - -.new-discussion-btn:hover { - transform: translateY(-3px); - box-shadow: 0 8px 25px rgba(var(--ifm-color-primary-rgb), 0.4); -} - -.new-discussion-btn:hover::before { - left: 100%; -} - -.new-discussion-btn:active { - transform: translateY(-1px); -} - -/* Enhanced Categories Bar */ -.categories-bar { - display: flex; - gap: 1rem; - margin-bottom: 2rem; - padding: 1rem 0; - overflow-x: auto; - scrollbar-width: none; - position: relative; -} - -.categories-bar::-webkit-scrollbar { - display: none; -} - -.categories-bar::after { - content: ""; - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 2px; - background: linear-gradient( - 90deg, - var(--ifm-color-primary), - var(--ifm-color-secondary) - ); - border-radius: 1px; - opacity: 0.3; -} - -.category { - padding: 0.75rem 1.5rem; - border-radius: 25px; - background: var(--ifm-card-background-color); - border: 2px solid var(--ifm-color-border); - color: var(--ifm-color-emphasis-700); - font-size: 0.9rem; - font-weight: 600; - cursor: pointer; - white-space: nowrap; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - position: relative; - overflow: hidden; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); -} - -.category::before { - content: ""; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: var(--ifm-color-primary); - opacity: 0; - transition: opacity 0.3s ease; - z-index: -1; -} - -.category:hover { - transform: translateY(-2px); - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); - border-color: var(--ifm-color-primary); - color: var(--ifm-color-primary); -} - -.category:hover::before { - opacity: 0.1; -} - -.category.active { - background: var(--ifm-color-primary); - color: white; - border-color: var(--ifm-color-primary); - font-weight: 700; - transform: translateY(-2px); - box-shadow: 0 4px 20px rgba(var(--ifm-color-primary-rgb), 0.3); -} - -.category.active::before { - opacity: 1; -} - -/* Enhanced Search Filters */ -.search-filters { - display: flex; - gap: 1.5rem; - margin-bottom: 2.5rem; - align-items: center; -} - -.search-bar { - flex: 1; - position: relative; -} - -.search-bar input { - width: 100%; - padding: 1rem 1.5rem 1rem 3.5rem; - border: 2px solid var(--ifm-color-border); - border-radius: 15px; - background: var(--ifm-card-background-color); - color: var(--ifm-font-color-base); - font-size: 1rem; - font-weight: 500; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); -} - -.search-bar input:hover { - border-color: var(--ifm-color-primary-light); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); -} - -.search-bar input:focus { - outline: none; - border-color: var(--ifm-color-primary); - box-shadow: 0 0 0 3px var(--ifm-color-primary-lightest), - 0 4px 12px rgba(0, 0, 0, 0.1); - transform: translateY(-1px); -} - -.search-bar input::placeholder { - color: var(--ifm-color-emphasis-500); - font-style: italic; -} - -.searchbar-icon { - position: absolute; - top: 50%; - left: 1.25rem; - transform: translateY(-50%); - color: var(--ifm-color-primary); - font-size: 1.1rem; - transition: all 0.3s ease; - z-index: 1; -} - -.searchbar-icon::before { - content: "🔍"; - font-size: 1rem; -} - -.search-bar:hover .searchbar-icon { - color: var(--ifm-color-primary-dark); - transform: translateY(-50%) scale(1.1) lateY(-50%) scale(1.1); -} - -/* Enhanced New Discussion Button */ -.new-discussion-btn { - display: flex; - align-items: center; - gap: 0.75rem; - padding: 0.875rem 2rem; - background: linear-gradient( - 135deg, - var(--ifm-color-primary), - var(--ifm-color-primary-dark) - ); - color: white; - border: none; - border-radius: 25px; - font-size: 0.95rem; - font-weight: 700; - cursor: pointer; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - position: relative; - overflow: hidden; - box-shadow: 0 4px 15px rgba(var(--ifm-color-primary-rgb), 0.3); -} - -.new-discussion-btn::before { - content: ""; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient( - 90deg, - transparent, - rgba(255, 255, 255, 0.2), - transparent - ); - transition: left 0.5s; -} - -.new-discussion-btn:hover { - transform: translateY(-3px); - box-shadow: 0 8px 25px rgba(var(--ifm-color-primary-rgb), 0.4); -} - -.new-discussion-btn:hover::before { - left: 100%; -} - -.new-discussion-btn:active { - transform: translateY(-1px); -} - -/* Enhanced Categories Bar */ -.categories-bar { - display: flex; - gap: 1rem; - margin-bottom: 2rem; - padding: 1rem 0; - overflow-x: auto; - scrollbar-width: none; - position: relative; -} - -.categories-bar::-webkit-scrollbar { - display: none; -} - -.categories-bar::after { - content: ""; - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 2px; - background: linear-gradient( - 90deg, - var(--ifm-color-primary), - var(--ifm-color-secondary) - ); - border-radius: 1px; - opacity: 0.3; -} - -.category { - padding: 0.75rem 1.5rem; - border-radius: 25px; - background: var(--ifm-card-background-color); - border: 2px solid var(--ifm-color-border); - color: var(--ifm-color-emphasis-700); - font-size: 0.9rem; - font-weight: 600; - cursor: pointer; - white-space: nowrap; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - position: relative; - overflow: hidden; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); -} - -.category::before { - content: ""; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: var(--ifm-color-primary); - opacity: 0; - transition: opacity 0.3s ease; - z-index: -1; -} - -.category:hover { - transform: translateY(-2px); - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); - border-color: var(--ifm-color-primary); - color: var(--ifm-color-primary); -} - -.category:hover::before { - opacity: 0.1; -} - -.category.active { - background: var(--ifm-color-primary); - color: white; - border-color: var(--ifm-color-primary); - font-weight: 700; - transform: translateY(-2px); - box-shadow: 0 4px 20px rgba(var(--ifm-color-primary-rgb), 0.3); -} - -.category.active::before { - opacity: 1; -} - -/* Enhanced Search Filters */ -.search-filters { - display: flex; - gap: 1.5rem; - margin-bottom: 2.5rem; - align-items: center; -} - -.search-bar { - flex: 1; - position: relative; -} - -.search-bar input { - width: 100%; - padding: 1rem 1.5rem 1rem 3.5rem; - border: 2px solid var(--ifm-color-border); - border-radius: 15px; - background: var(--ifm-card-background-color); - color: var(--ifm-font-color-base); - font-size: 1rem; - font-weight: 500; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); -} - -.search-bar input:hover { - border-color: var(--ifm-color-primary-light); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); -} - -.search-bar input:focus { - outline: none; - border-color: var(--ifm-color-primary); - box-shadow: 0 0 0 3px var(--ifm-color-primary-lightest), - 0 4px 12px rgba(0, 0, 0, 0.1); - transform: translateY(-1px); -} - -.search-bar input::placeholder { - color: var(--ifm-color-emphasis-500); - font-style: italic; -} - -.searchbar-icon { - position: absolute; - top: 50%; - left: 1.25rem; - transform: translateY(-50%); - color: var(--ifm-color-primary); - font-size: 1.1rem; - transition: all 0.3s ease; -} - -.search-bar:hover .searchbar-icon { - color: var(--ifm-color-primary-dark); - transform: translateY(-50%) scale(1.1); -} - -/* Enhanced Discussions List */ -.discussions-list { - display: grid; - grid-template-columns: 1fr; - gap: 2rem; -} - -/* Enhanced Discussion Items */ -.discussion-item { - display: flex; - flex-direction: column; - padding: 1.5rem; - background: #ffffff; - border-radius: 16px; - border: 1px solid #e2e8f0; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - position: relative; - overflow: hidden; - box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), - 0 2px 4px -1px rgba(0, 0, 0, 0.06); - cursor: pointer; -} - -[data-theme="dark"] .discussion-item { - background: #1e293b; - border-color: #334155; - box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3), - 0 2px 4px -1px rgba(0, 0, 0, 0.2); -} - -[data-theme="dark"] .discussion-item { - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); -} - -.discussion-item::before { - content: ""; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 4px; - background: linear-gradient( - 90deg, - var(--ifm-color-primary), - var(--ifm-color-secondary) - ); - transform: scaleX(0); - transition: transform 0.3s ease; -} - -.discussion-item:hover { - box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), - 0 10px 10px -5px rgba(0, 0, 0, 0.04); - border-color: #10b981; -} - -[data-theme="dark"] .discussion-item:hover { - box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.4), - 0 10px 10px -5px rgba(0, 0, 0, 0.2); - border-color: #10b981; -} - -.discussion-item:hover::before { - transform: scaleX(1); -} - -/* Enhanced Avatar */ -.discussion-avatar { - width: 48px; - height: 48px; - border-radius: 50%; - overflow: hidden; - flex-shrink: 0; - position: relative; - border: 2px solid #e2e8f0; - transition: all 0.2s ease; - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1); -} - -[data-theme="dark"] .discussion-avatar { - border-color: #475569; -} - -.discussion-avatar img { - width: 100%; - height: 100%; - object-fit: cover; - border-radius: 50%; -} - -.discussion-avatar.verified::after { - content: "✓"; - position: absolute; - bottom: -2px; - right: -2px; - width: 16px; - height: 16px; - background: #2563eb; - color: white; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-size: 10px; - font-weight: bold; - border: 2px solid #ffffff; -} - -[data-theme="dark"] .discussion-avatar.verified::after { - border-color: #1e293b; -} - -.discussion-content { - flex: 1; - display: flex; - flex-direction: column; -} - -[data-theme="dark"] .discussion-content { - color: #f1f5f9; -} - -.discussion-content { - flex: 1; - display: flex; - flex-direction: column; -} - -.discussion-header { - display: flex; - align-items: center; - gap: 1rem; - margin-bottom: 1rem; -} - -.discussion-pinned-badge { - display: inline-flex; - align-items: center; - gap: 0.5rem; - background: #059669; - color: white; - padding: 0.5rem 1rem; - border-radius: 20px; - font-size: 0.875rem; - font-weight: 600; -} - -.discussion-pinned-badge::before { - content: "📌"; -} - -.discussion-title { - font-size: 1.5rem; - font-weight: 700; - margin: 0 0 1rem 0; - color: #1e293b; - line-height: 1.375; - transition: color 0.2s ease; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; -} - -.discussion-item:hover .discussion-title { - color: #2563eb; -} - -[data-theme="dark"] .discussion-title { - color: #f1f5f9; -} - -[data-theme="dark"] .discussion-item:hover .discussion-title { - color: #60a5fa; -} - -/* Enhanced Pinned Badge */ -.pinned-badge { - display: inline-flex; - align-items: center; - gap: 0.5rem; - padding: 0.5rem 1rem; - background: linear-gradient( - 135deg, - var(--ifm-color-primary), - var(--ifm-color-primary-dark) - ); - color: white; - border-radius: 25px; - font-size: 0.8rem; - font-weight: 700; - box-shadow: 0 2px 8px rgba(var(--ifm-color-primary-rgb), 0.3); - animation: glow-pulse 2s ease-in-out infinite alternate; -} - -@keyframes glow-pulse { - 0% { - box-shadow: 0 2px 8px rgba(var(--ifm-color-primary-rgb), 0.3); - } - 100% { - box-shadow: 0 4px 16px rgba(var(--ifm-color-primary-rgb), 0.5); - } -} - -.discussion-body p { - color: #475569; - font-size: 1rem; - line-height: 1.625; - margin: 0 0 1.5rem 0; - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; - overflow: hidden; -} - -[data-theme="dark"] .discussion-body p { - color: #cbd5e1; -} - -.discussion-meta { - display: flex; - justify-content: space-between; - align-items: center; - margin-top: 1rem; - padding-top: 1rem; - border-top: 1px solid #e2e8f0; -} - -[data-theme="dark"] .discussion-meta { - border-top-color: #334155; -} - -.discussion-author { - color: #64748b; - font-size: 0.875rem; -} - -[data-theme="dark"] .discussion-author { - color: #94a3b8; -} - -.discussion-stats { - display: flex; - gap: 1rem; - align-items: center; - color: #64748b; - font-size: 0.875rem; -} - -[data-theme="dark"] .discussion-stats { - color: #94a3b8; -} - -.discussion-stats span { - display: flex; - align-items: center; - gap: 0.25rem; -} - -/* Enhanced Meta Section */ -.discussion-meta { - display: flex; - justify-content: space-between; - align-items: center; - flex-wrap: wrap; - gap: 1.5rem; - padding-top: 1rem; - border-top: 1px solid var(--ifm-color-border); -} - -/* Enhanced Tags */ -.tags { - display: flex; - gap: 0.75rem; - flex-wrap: wrap; -} - -.tags { - display: flex; - gap: 0.5rem; - flex-wrap: wrap; - margin-bottom: 1rem; -} - -.tags .tag { - padding: 0.375rem 0.75rem; - background: linear-gradient(135deg, #dbeafe 0%, #e0e7ff 100%); - border-radius: 9999px; - color: #1e40af; - font-size: 0.75rem; - font-weight: 500; - transition: all 0.2s ease; - border: 1px solid #bfdbfe; - text-decoration: none; -} - -[data-theme="dark"] .tags .tag { - background: linear-gradient(135deg, #1e3a8a 0%, #3730a3 100%); - color: #dbeafe; - border-color: #3b82f6; -} - -.tags .tag:hover { - background: linear-gradient(135deg, #3b82f6 0%, #6366f1 100%); - color: white; - border-color: #2563eb; -} - -.tags .tag::before { - content: "#"; - opacity: 0.8; - margin-right: 0.125rem; -} - -/* Enhanced Meta Info */ -.meta-info { - display: flex; - align-items: center; - gap: 1.5rem; - color: var(--ifm-color-emphasis-600); - font-size: 0.9rem; - font-weight: 500; -} - -.meta-info span { - display: flex; - align-items: center; - gap: 0.5rem; - padding: 0.25rem 0.75rem; - border-radius: 15px; - background: var(--ifm-color-emphasis-100); - transition: all 0.3s ease; -} - -.meta-info span:hover { - background: var(--ifm-color-primary-lightest); - color: var(--ifm-color-primary); - transform: translateY(-1px); -} - -/* Enhanced Giscus Wrapper */ -.giscus-wrapper { - margin-top: 4rem; - padding-top: 3rem; - border-top: 2px solid var(--ifm-color-border); - position: relative; -} - -.giscus-wrapper::before { - content: ""; - position: absolute; - top: -1px; - left: 50%; - transform: translateX(-50%); - width: 100px; - height: 2px; - background: linear-gradient( - 90deg, - var(--ifm-color-primary), - var(--ifm-color-secondary) - ); - border-radius: 1px; -} - -/* Responsive Design */ -@media (max-width: 768px) { - .discussion-container { - padding: 1rem; - } - - .discussion-header h1 { - font-size: 2.5rem; - } - - .discussion-toolbar { - flex-direction: column; - gap: 1.5rem; - align-items: stretch; - padding: 1.5rem; - } - - .toolbar-left { - flex-wrap: wrap; - justify-content: center; - gap: 0.5rem; - } - - .tab-btn { - padding: 0.75rem 1rem; - font-size: 0.85rem; - } - - .new-discussion-btn { - justify-content: center; - padding: 1rem 1.5rem; - } - - .categories-bar { - gap: 0.75rem; - padding: 0.75rem 0; - } - - .category { - padding: 0.6rem 1rem; - font-size: 0.85rem; - } - - .search-filters { - flex-direction: column; - align-items: stretch; - gap: 1rem; - } - - .search-bar input { - padding: 0.875rem 1.25rem 0.875rem 3rem; - } - - .discussions-list { - gap: 1.5rem; - } - - .discussion-item { - flex-direction: column; - gap: 1rem; - padding: 1.5rem; - } - - .discussion-avatar { - width: 48px; - height: 48px; - align-self: flex-start; - } - - .discussion-meta { - flex-direction: column; - align-items: flex-start; - gap: 1rem; - } - - .meta-info { - gap: 1rem; - flex-wrap: wrap; - } -} - -@media (max-width: 480px) { - .discussion-header h1 { - font-size: 2rem; - } - - .discussion-header p { - font-size: 1rem; - } - - .discussion-item { - padding: 1rem; - } - - .discussion-header-content h3 { - font-size: 1.1rem; - } - - .tab-btn { - padding: 0.6rem 0.8rem; - font-size: 0.8rem; - } - - .category { - padding: 0.5rem 0.8rem; - font-size: 0.8rem; - } -} - -/* Dashboard Container */ -.dashboard-container { - max-width: 1200px; - margin: 0 auto; - padding: 0 1rem; -} - -/* Hero Section */ -.dashboard-hero { - text-align: center; - padding: 4rem 0 2rem; - margin-bottom: 3rem; -} - -.hero-content { - max-width: 800px; - margin: 0 auto; -} - -.dashboard-title { - font-size: 3.5rem; - font-weight: 700; - margin-bottom: 1.5rem; - color: var(--ifm-color-emphasis-900); - line-height: 1.1; -} - -.dashboard-title .highlight { - background: linear-gradient(135deg, var(--ifm-color-primary), #e74c3c); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.dashboard-subtitle { - font-size: 1.2rem; - color: var(--ifm-color-emphasis-700); - margin-bottom: 2rem; - line-height: 1.6; -} - -/* Stats Section */ -.dashboard-stats-section { - margin-bottom: 4rem; -} - -.dashboard-stats-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); - gap: 2rem; - margin-bottom: 3rem; -} - -.dashboard-stat-card { - background: linear-gradient( - 135deg, - var(--ifm-card-background-color) 0%, - rgba(var(--ifm-color-primary-rgb), 0.05) 100% - ); - border-radius: 2rem; - padding: 2.5rem; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08), 0 2px 8px rgba(0, 0, 0, 0.04); - border: 1px solid var(--ifm-color-border); - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); - display: flex; - align-items: center; - gap: 2rem; - position: relative; - overflow: hidden; - backdrop-filter: blur(10px); -} - -[data-theme="dark"] .dashboard-stat-card { - background: linear-gradient( - 135deg, - rgba(var(--ifm-card-background-color-rgb), 0.95) 0%, - rgba(var(--ifm-color-primary-rgb), 0.1) 100% - ); - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), 0 2px 8px rgba(0, 0, 0, 0.2); -} - -.dashboard-stat-card::before { - content: ""; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: linear-gradient( - 135deg, - rgba(var(--ifm-color-primary-rgb), 0.1) 0%, - transparent 50%, - rgba(var(--ifm-color-secondary-rgb), 0.05) 100% - ); - opacity: 0; - transition: opacity 0.4s ease; - pointer-events: none; -} - -.dashboard-stat-card:hover { - transform: translateY(-8px) scale(1.02); - box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15), 0 8px 24px rgba(0, 0, 0, 0.08); - border-color: var(--ifm-color-primary-light); -} - -[data-theme="dark"] .dashboard-stat-card:hover { - box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5), 0 8px 24px rgba(0, 0, 0, 0.3); -} - -.dashboard-stat-card:hover::before { - opacity: 1; -} - -.dashboard-stat-icon { - font-size: 3.5rem; - width: 5rem; - height: 5rem; - display: flex; - align-items: center; - justify-content: center; - background: linear-gradient( - 135deg, - var(--ifm-color-primary) 0%, - var(--ifm-color-primary-dark) 100% - ); - border-radius: 1.5rem; - flex-shrink: 0; - position: relative; - overflow: hidden; - box-shadow: 0 8px 24px rgba(var(--ifm-color-primary-rgb), 0.3); - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); -} - -.dashboard-stat-icon::before { - content: ""; - position: absolute; - top: -50%; - left: -50%; - width: 200%; - height: 200%; - background: linear-gradient( - 45deg, - transparent 30%, - rgba(255, 255, 255, 0.3) 50%, - transparent 70% - ); - transform: rotate(-45deg); - transition: transform 0.6s ease; -} - -.dashboard-stat-card:hover .dashboard-stat-icon { - transform: scale(1.1) rotate(5deg); - box-shadow: 0 12px 32px rgba(var(--ifm-color-primary-rgb), 0.4); -} - -.dashboard-stat-card:hover .dashboard-stat-icon::before { - transform: rotate(-45deg) translate(100%, 100%); -} - -.dashboard-stat-content { - flex: 1; -} - -.dashboard-stat-title { - font-size: 1.2rem; - font-weight: 700; - color: var(--ifm-color-emphasis-900); - margin-bottom: 0.75rem; - transition: all 0.3s ease; - position: relative; -} - -.dashboard-stat-title::after { - content: ""; - position: absolute; - bottom: -4px; - left: 0; - width: 0; - height: 2px; - background: linear-gradient( - 90deg, - var(--ifm-color-primary), - var(--ifm-color-secondary) - ); - transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1); - border-radius: 1px; -} - -.dashboard-stat-card:hover .dashboard-stat-title { - color: var(--ifm-color-primary); - transform: translateX(4px); -} - -.dashboard-stat-card:hover .dashboard-stat-title::after { - width: 100%; -} - -.dashboard-stat-value { - /* font-size: 3rem; - font-weight: 800; - - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - - margin-bottom: 0.5rem; - text-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); - transition: all 0.3s ease; - position: relative; */ - /* background: linear-gradient( - 135deg, - var(--ifm-color-primary) 0%, - var(--ifm-color-primary-dark) 100% - ); */ - /* not removed the properties as this can be used later on */ - background-clip: text; - font-size: 3rem; - font-weight: 800; - color: var(--ifm-color-primary); - margin-bottom: 0.5rem; - text-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); - transition: color 0.3s ease; - position: relative; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.dashboard-stat-card:hover .dashboard-stat-value { - transform: scale(1.05); - filter: drop-shadow(0 0 10px rgba(var(--ifm-color-primary-rgb), 0.3)); -} - -.dashboard-slot-counter { - font-size: inherit; - font-weight: inherit; - color: inherit; -} - -.dashboard-stat-description { - font-size: 0.95rem; - color: var(--ifm-color-emphasis-700); - margin: 0; - line-height: 1.5; - transition: all 0.3s ease; - opacity: 0.9; -} - -.dashboard-stat-card:hover .dashboard-stat-description { - color: var(--ifm-color-emphasis-800); - opacity: 1; - transform: translateY(-2px); -} - -.loading-spinner { - animation: spin 1s linear infinite; -} - -@keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} - -/* Leaderboard Section */ -.dashboard-leaderboard-section { - margin-bottom: 4rem; -} - -.leaderboard-header { - text-align: center; - margin-bottom: 3rem; -} - -.leaderboard-title { - font-size: 2.5rem; - font-weight: 700; - margin-bottom: 1rem; - color: var(--ifm-color-emphasis-900); -} - -.leaderboard-title .title-accent { - color: var(--ifm-color-primary); -} - -.leaderboard-description { - font-size: 1.1rem; - color: var(--ifm-color-emphasis-700); - max-width: 600px; - margin: 0 auto; - line-height: 1.6; -} - -.leaderboard-container { - display: flex; - flex-direction: column; - gap: 1.5rem; -} - -.leaderboard-card { - background: var(--ifm-color-background); - border-radius: 1.5rem; - padding: 2rem; - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); - border: 1px solid var(--ifm-color-border); - transition: all 0.3s ease; - display: grid; - grid-template-columns: auto auto 1fr auto; - gap: 1.5rem; - align-items: center; -} - -/* Center images in leaderboard when sidebar is collapsed */ -.dashboard-main.sidebar-collapsed .leaderboard-card { - grid-template-columns: 1fr; - text-align: center; - padding: 1.5rem; -} - -.dashboard-main.sidebar-collapsed .leaderboard-avatar { - margin: 0 auto; -} - -.dashboard-main.sidebar-collapsed .leaderboard-info { - grid-column: 1 / -1; -} - -.dashboard-main.sidebar-collapsed .leaderboard-actions { - grid-column: 1 / -1; - justify-self: center; -} - -.leaderboard-card:hover { - transform: translateY(-2px); - box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15); -} - -.leaderboard-rank { - display: flex; - align-items: center; - justify-content: center; -} - -.rank-badge { - font-size: 1.2rem; - font-weight: 700; - padding: 0.5rem 1rem; - border-radius: 50px; - color: white; - text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); -} - -.rank-badge.rank-1 { - background: linear-gradient(135deg, #ffd700, #ffb347); - box-shadow: 0 4px 15px rgba(255, 215, 0, 0.3); -} - -.rank-badge.rank-2 { - background: linear-gradient(135deg, #c0c0c0, #a8a8a8); - box-shadow: 0 4px 15px rgba(192, 192, 192, 0.3); -} - -.rank-badge.rank-3 { - background: linear-gradient(135deg, #cd7f32, #b8860b); - box-shadow: 0 4px 15px rgba(205, 127, 50, 0.3); -} - -.rank-badge.rank-4, -.rank-badge.rank-5 { - background: linear-gradient( - 135deg, - var(--ifm-color-primary), - var(--ifm-color-primary-darker) - ); - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); -} - -.leaderboard-avatar { - width: 4rem; - height: 4rem; - border-radius: 50%; - overflow: hidden; - border: 3px solid var(--ifm-color-primary-lightest); - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); -} - -.leaderboard-avatar img { - width: 100%; - height: 100%; - object-fit: cover; -} - -.leaderboard-info { - flex: 1; -} - -.leaderboard-name { - font-size: 1.4rem; - font-weight: 600; - color: var(--ifm-color-emphasis-900); - margin-bottom: 0.5rem; -} - -.leaderboard-stats { - display: flex; - gap: 1.5rem; - margin-bottom: 1rem; -} - -.stat-item { - font-size: 0.9rem; - color: var(--ifm-color-secondary-text); -} - -.stat-item strong { - color: var(--ifm-color-primary-text); - font-weight: 600; -} - -.leaderboard-achievements { - display: flex; - flex-wrap: wrap; - gap: 0.5rem; -} - -.achievement-badge { - font-size: 0.8rem; - padding: 0.25rem 0.75rem; - background: var(--ifm-color-primary-lightest); - color: var(--ifm-color-primary-text); - border-radius: 50px; - font-weight: 500; - border: 1px solid var(--ifm-color-primary-light); -} - -.leaderboard-actions { - display: flex; - align-items: center; -} - -.github-profile-btn { - background: var(--ifm-color-primary); - color: white; - text-decoration: none; - padding: 0.75rem 1.5rem; - border-radius: 50px; - font-weight: 600; - transition: all 0.3s ease; - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); -} - -.github-profile-btn:hover { - background: var(--ifm-color-primary-darker); - transform: translateY(-1px); - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); - text-decoration: none; - color: white; -} - -/* Call to Action */ -.dashboard-cta { - background: linear-gradient( - 135deg, - var(--ifm-color-primary), - var(--ifm-color-primary-darker) - ); - color: white; - padding: 4rem 2rem; - border-radius: 2rem; - text-align: center; - margin-bottom: 3rem; - box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); -} - -.cta-content h3 { - font-size: 2rem; - font-weight: 700; - margin-bottom: 1rem; - color: white; -} - -.cta-content p { - font-size: 1.1rem; - margin-bottom: 2rem; - opacity: 0.9; - line-height: 1.6; -} - -.cta-buttons { - display: flex; - gap: 1rem; - justify-content: center; - flex-wrap: wrap; -} - -.cta-primary, -.cta-secondary { - padding: 0.75rem 2rem; - border-radius: 50px; - text-decoration: none; - font-weight: 600; - transition: all 0.3s ease; - display: inline-block; -} - -.cta-primary { - background: white; - color: var(--ifm-color-primary); - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); -} - -.cta-primary:hover { - transform: translateY(-2px); - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); - text-decoration: none; - color: var(--ifm-color-primary); -} - -.cta-secondary { - background: transparent; - color: white; - border: 2px solid white; -} - -.cta-secondary:hover { - background: white; - color: var(--ifm-color-primary); - transform: translateY(-2px); - text-decoration: none; -} - -/* Leaderboard Page Styles */ -.leaderboard-page-container { - max-width: 1200px; - margin: 0 auto; - padding: 2rem 0; -} - -.leaderboard-page-header { - text-align: center; - margin-bottom: 3rem; -} - -.leaderboard-page-title { - font-size: 3rem; - font-weight: 700; - margin-bottom: 1rem; - color: var(--ifm-color-emphasis-900); -} - -/* Light theme page title */ -[data-theme="light"] .leaderboard-page-title { - color: #1a202c !important; -} - -[data-theme="light"] .leaderboard-page-subtitle { - color: #4a5568 !important; -} - -.leaderboard-page-title .highlight { - background: linear-gradient(135deg, #ffd700, #ff8c00); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.leaderboard-page-subtitle { - font-size: 1.2rem; - color: var(--ifm-color-emphasis-700); - margin-bottom: 2rem; -} - -.refresh-section { - margin-top: 2rem; -} - -.refresh-button { - background: var(--ifm-color-primary); - color: white; - border: none; - padding: 0.75rem 2rem; - border-radius: 50px; - font-weight: 600; - cursor: pointer; - transition: all 0.3s ease; - font-size: 1rem; -} - -.refresh-button:hover:not(:disabled) { - background: var(--ifm-color-primary-darker); - transform: translateY(-2px); - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); -} - -.refresh-button:disabled { - opacity: 0.6; - cursor: not-allowed; -} - -/* Loading and Error States */ -.loading-container { - text-align: center; - padding: 4rem 2rem; - background: var(--ifm-card-background-color); - border-radius: 1rem; - margin: 2rem 0; - border: 1px solid var(--ifm-color-border); -} - -.loading-spinner-large { - font-size: 3rem; - margin-bottom: 1rem; - animation: spin 2s linear infinite; -} - -.error-container { - text-align: center; - padding: 3rem 2rem; - background: var(--ifm-alert-background-color); - border: 1px solid var(--ifm-alert-border-color); - border-radius: 1rem; - margin: 2rem 0; -} - -.error-container h3 { - color: var(--ifm-color-danger); - margin-bottom: 1rem; -} - -.error-container p { - color: var(--ifm-font-color-base); - margin-bottom: 2rem; -} - -.error-help { - color: var(--ifm-font-color-base); -} - -/* Light theme loading and error states */ -[data-theme="light"] .loading-container { - background: #ffffff; - border: 1px solid #e2e8f0; - color: #1a202c; -} - -[data-theme="light"] .loading-text { - color: #4a5568 !important; -} - -[data-theme="light"] .error-container { - background: #fef2f2; - border: 1px solid #fecaca; - color: #1a202c; -} - -[data-theme="light"] .error-container h3 { - color: #dc2626 !important; -} - -[data-theme="light"] .error-container p, -[data-theme="light"] .error-help { - color: #374151 !important; -} - -.retry-button { - background: var(--ifm-color-danger); - color: white; - border: none; - padding: 0.75rem 2rem; - border-radius: 0.5rem; - font-weight: 600; - cursor: pointer; - transition: all 0.3s ease; - margin-top: 1rem; -} - -.retry-button:hover { - background: var(--ifm-color-danger-dark); - transform: translateY(-2px); -} - -/* Leaderboard Stats */ -.leaderboard-stats { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); - gap: 2rem; - margin-bottom: 3rem; - padding: 2rem; - background: var(--ifm-card-background-color); - border-radius: 1rem; - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); -} - -.leaderboard-stats .stat-item { - text-align: center; - padding: 1rem; -} - -.leaderboard-stats .stat-number { - display: block; - font-size: 2.5rem; - font-weight: 700; - color: var(--ifm-color-primary); - margin-bottom: 0.5rem; -} - -.leaderboard-stats .stat-label { - font-size: 0.9rem; - color: var(--ifm-color-emphasis-600); - font-weight: 500; -} - -/* Light theme leaderboard stats */ -[data-theme="light"] .leaderboard-stats { - background: #ffffff; - border: 1px solid #e2e8f0; - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); -} - -[data-theme="light"] .leaderboard-stats .stat-number { - color: var(--ifm-color-primary) !important; -} - -[data-theme="light"] .leaderboard-stats .stat-label { - color: #4a5568 !important; -} - -/* Leaderboard Grid */ -.leaderboard-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); - gap: 2rem; -} - -.leaderboard-item { - background: var(--ifm-card-background-color); - border-radius: 1.5rem; - padding: 2rem; - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); - border: 1px solid var(--ifm-color-border); - transition: all 0.3s ease; - position: relative; - overflow: hidden; - color: var(--ifm-font-color-base); -} - -/* Light theme specific styles */ -[data-theme="light"] .leaderboard-item { - background: #ffffff; - border: 1px solid #e2e8f0; - color: #1a202c; - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); -} - -[data-theme="light"] .leaderboard-item:hover { - box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12); - border-color: var(--ifm-color-primary); -} - -.leaderboard-item::before { - content: ""; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 4px; - background: var(--ifm-color-primary); -} - -.leaderboard-item.rank-1::before { - background: linear-gradient(135deg, #ffd700, #ffb347); -} - -.leaderboard-item.rank-2::before { - background: linear-gradient(135deg, #c0c0c0, #a8a8a8); -} - -.leaderboard-item.rank-3::before { - background: linear-gradient(135deg, #cd7f32, #b8860b); -} - -/* Rank Section */ -.rank-section { - text-align: center; - margin-bottom: 1.5rem; -} - -.rank-badge { - display: inline-block; - font-size: 1.2rem; - font-weight: 700; - padding: 0.75rem 1.5rem; - border-radius: 50px; - color: white; - text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); - min-width: 80px; -} - -.rank-badge.rank-1 { - background: linear-gradient(135deg, #ffd700, #ffb347); - box-shadow: 0 4px 15px rgba(255, 215, 0, 0.3); -} - -.rank-badge.rank-2 { - background: linear-gradient(135deg, #c0c0c0, #a8a8a8); - box-shadow: 0 4px 15px rgba(192, 192, 192, 0.3); -} - -.rank-badge.rank-3 { - background: linear-gradient(135deg, #cd7f32, #b8860b); - box-shadow: 0 4px 15px rgba(205, 127, 50, 0.3); -} - -.rank-badge.rank-other { - background: linear-gradient( - 135deg, - var(--ifm-color-primary), - var(--ifm-color-primary-darker) - ); - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); -} - -/* Avatar Section */ -.avatar-section { - text-align: center; - margin-bottom: 1.5rem; -} - -.user-avatar { - width: 80px; - height: 80px; - border-radius: 50%; - border: 4px solid var(--ifm-color-primary-lightest); - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); - object-fit: cover; -} - -/* User Info */ -.user-info { - text-align: center; - margin-bottom: 1.5rem; -} - -.user-name { - font-size: 1.4rem; - font-weight: 600; - color: var(--ifm-color-emphasis-900); - margin-bottom: 0.5rem; -} - -.user-username { - font-size: 0.9rem; - color: var(--ifm-color-emphasis-600); - margin-bottom: 1rem; - font-style: italic; -} - -/* Light theme text visibility fixes */ -[data-theme="light"] .user-name { - color: #1a202c !important; -} - -[data-theme="light"] .user-username { - color: #4a5568 !important; -} - -[data-theme="light"] .leaderboard-item .user-info { - color: #1a202c; -} - -/* Score Display */ -.score-display { - margin-bottom: 1.5rem; -} - -.score-number { - font-size: 2.5rem; - font-weight: 700; - color: var(--ifm-color-primary); - display: block; -} - -.score-label { - font-size: 0.9rem; - color: var(--ifm-color-emphasis-600); - text-transform: uppercase; - letter-spacing: 0.5px; -} - -/* Light theme score visibility */ -[data-theme="light"] .score-number { - color: var(--ifm-color-primary) !important; -} - -[data-theme="light"] .score-label { - color: #4a5568 !important; -} - -/* User Stats */ -.user-stats { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 1rem; - margin-bottom: 1.5rem; -} - -.user-stats .stat { - text-align: center; - padding: 0.75rem; - background: var(--ifm-color-background); - border-radius: 0.5rem; - border: 1px solid var(--ifm-color-border); -} - -.stat-value { - display: block; - font-size: 1.5rem; - font-weight: 600; - color: var(--ifm-color-primary); - margin-bottom: 0.25rem; -} - -.stat-text { - font-size: 0.8rem; - color: var(--ifm-color-emphasis-600); - text-transform: uppercase; - letter-spacing: 0.5px; -} - -/* Light theme stats visibility */ -[data-theme="light"] .user-stats .stat { - background: #f7fafc; - border: 1px solid #e2e8f0; -} - -[data-theme="light"] .stat-value { - color: var(--ifm-color-primary) !important; -} - -[data-theme="light"] .stat-text { - color: #4a5568 !important; -} - -/* Achievements */ -.achievements { - display: flex; - flex-wrap: wrap; - gap: 0.5rem; - justify-content: center; - margin-bottom: 1.5rem; -} - -.achievement-tag { - font-size: 0.75rem; - padding: 0.25rem 0.75rem; - background: var(--ifm-color-primary-lightest); - color: var(--ifm-color-primary-darker); - border-radius: 50px; - font-weight: 500; - border: 1px solid var(--ifm-color-primary-light); - white-space: nowrap; -} - -/* Light theme achievement tags */ -[data-theme="light"] .achievement-tag { - background: #e6fffa; - color: #234e52; - border: 1px solid #81e6d9; -} - -/* Actions Section */ -.actions-section { - text-align: center; -} - -.github-link { - display: inline-flex; - align-items: center; - gap: 0.5rem; - background: var(--ifm-color-primary); - color: white; - text-decoration: none; - padding: 0.75rem 1.5rem; - border-radius: 50px; - font-weight: 600; - transition: all 0.3s ease; - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); -} - -.github-link:hover { - background: var(--ifm-color-primary-darker); - transform: translateY(-1px); - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); - text-decoration: none; - color: white; -} - -/* Empty State */ -.empty-state { - text-align: center; - padding: 4rem 2rem; - background: var(--ifm-card-background-color); - border-radius: 1rem; - border: 1px solid var(--ifm-color-border); - color: var(--ifm-color-emphasis-700); -} - -.empty-state h3 { - margin-bottom: 1rem; - color: var(--ifm-color-emphasis-800); -} - -.empty-state p { - font-size: 1.1rem; - margin-bottom: 0; -} - -/* Light theme empty state */ -[data-theme="light"] .empty-state { - background: #ffffff; - border: 1px solid #e2e8f0; - color: #4a5568; -} - -[data-theme="light"] .empty-state h3 { - color: #1a202c !important; -} - -[data-theme="light"] .empty-state p { - color: #4a5568 !important; -} - -/* Responsive Design */ -@media (max-width: 768px) { - .leaderboard-page-title { - font-size: 2rem; - } - - .leaderboard-grid { - grid-template-columns: 1fr; - gap: 1.5rem; - } - - .leaderboard-item { - padding: 1.5rem; - } - - .leaderboard-stats { - grid-template-columns: repeat(3, 1fr); - gap: 1rem; - padding: 1.5rem; - } - - .user-avatar { - width: 60px; - height: 60px; - } - - .score-number { - font-size: 2rem; - } -} - -@media (max-width: 480px) { - .leaderboard-page-container { - padding: 1rem 0; - } - - .leaderboard-stats { - grid-template-columns: 1fr; - } - - .user-stats { - grid-template-columns: 1fr; - } -} - -/* Error Message */ -.error-message { - text-align: center; - padding: 1rem; - background: var(--ifm-color-warning-lightest); - border: 1px solid var(--ifm-color-warning-light); - border-radius: 0.5rem; - margin-bottom: 2rem; - color: var(--ifm-color-warning-darker); -} - -/* Responsive Design */ -@media (max-width: 768px) { - .dashboard-title { - font-size: 2.5rem; - } - - .dashboard-subtitle { - font-size: 1rem; - } - - .dashboard-stats-grid { - grid-template-columns: 1fr; - gap: 1rem; - } - - .dashboard-stat-card { - padding: 1.5rem; - flex-direction: column; - text-align: center; - } - - .dashboard-stat-icon { - font-size: 2.5rem; - width: 3rem; - height: 3rem; - } - - .dashboard-stat-value { - font-size: 2rem; - } - - .leaderboard-card { - grid-template-columns: 1fr; - gap: 1rem; - text-align: center; - } - - .leaderboard-stats { - justify-content: center; - } - - .leaderboard-achievements { - justify-content: center; - } - - .cta-buttons { - flex-direction: column; - align-items: center; - } - - .cta-primary, - .cta-secondary { - width: 100%; - max-width: 200px; - } -} - -@media (max-width: 480px) { - .dashboard-container { - padding: 0 0.5rem; - } - - .dashboard-hero { - padding: 2rem 0 1rem; - } - - .dashboard-title { - font-size: 2rem; - } - - .leaderboard-title { - font-size: 2rem; - } - - .dashboard-stat-card, - .leaderboard-card { - padding: 1rem; - } - - .dashboard-cta { - padding: 2rem 1rem; - } -} - -/* GSSoC-Style Enhancements */ -.leaderboard-page-container { - background: var(--ifm-background-color); - min-height: calc(100vh - 60px); -} - -.leaderboard-page-title { - background: linear-gradient( - 135deg, - var(--ifm-color-primary) 0%, - var(--ifm-color-primary-darker) 100% - ); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - text-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); -} - -/* Enhanced Leaderboard Item for GSSoC Style */ -.leaderboard-item { - background: var(--ifm-card-background-color); - border: 1px solid var(--ifm-color-border); - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(0, 0, 0, 0.15); - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); -} - -[data-theme="dark"] .leaderboard-item { - box-shadow: 0 8px 32px rgba(255, 255, 255, 0.05), - 0 1px 1px rgba(255, 255, 255, 0.1); -} - -.leaderboard-item:hover { - transform: translateY(-8px); - box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1); -} - -[data-theme="dark"] .leaderboard-item:hover { - box-shadow: 0 20px 40px rgba(255, 255, 255, 0.1), - 0 2px 4px rgba(255, 255, 255, 0.05); -} - -/* Gradient rank badges like GSSoC */ -.rank-badge.rank-1 { - background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 50%, #fecfef 100%); - animation: pulse-gold 2s ease-in-out infinite alternate; - color: #fff; -} - -.rank-badge.rank-2 { - background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%); - animation: pulse-silver 2s ease-in-out infinite alternate; - color: #333; -} - -.rank-badge.rank-3 { - background: linear-gradient(135deg, #ff9a56 0%, #ffad56 100%); - animation: pulse-bronze 2s ease-in-out infinite alternate; - color: #fff; -} - -@keyframes pulse-gold { - 0% { - box-shadow: 0 4px 15px rgba(255, 215, 0, 0.3); - } - 100% { - box-shadow: 0 6px 25px rgba(255, 215, 0, 0.5); - } -} - -@keyframes pulse-silver { - 0% { - box-shadow: 0 4px 15px rgba(192, 192, 192, 0.3); - } - 100% { - box-shadow: 0 6px 25px rgba(192, 192, 192, 0.5); - } -} - -@keyframes pulse-bronze { - 0% { - box-shadow: 0 4px 15px rgba(205, 127, 50, 0.3); - } - 100% { - box-shadow: 0 6px 25px rgba(205, 127, 50, 0.5); - } -} - -/* Special badges for GSSoC features */ -.achievement-tag { - font-size: 0.7rem; - padding: 0.3rem 0.8rem; - border-radius: 20px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.5px; - transition: all 0.3s ease; -} - -/* Postman badge styling */ -.achievement-tag:has-text("📮") { - background: linear-gradient(135deg, #ff6b35 0%, #f7931e 100%); - color: white; - border: none; -} - -/* Web3 badge styling */ -.achievement-tag:has-text("🌐") { - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - color: white; - border: none; -} - -/* Enhanced score display */ -.score-display { - position: relative; - background: linear-gradient( - 135deg, - var(--ifm-color-primary) 0%, - var(--ifm-color-primary-darker) 100% - ); - color: white; - padding: 1.5rem; - border-radius: 1rem; - margin-bottom: 1.5rem; - text-align: center; -} - -.score-number { - font-size: 3rem; - font-weight: 800; - color: white; - text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); - filter: drop-shadow(0 0 10px rgba(255, 255, 255, 0.3)); -} - -.score-label { - color: rgba(255, 255, 255, 0.9); - font-weight: 600; - text-transform: uppercase; - letter-spacing: 1px; -} - -/* Enhanced user avatar with ranking glow */ -.user-avatar { - transition: all 0.3s ease; - filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.15)); -} - -[data-theme="dark"] .user-avatar { - filter: drop-shadow(0 4px 12px rgba(255, 255, 255, 0.1)); -} - -.leaderboard-item:nth-child(1) .user-avatar { - border-color: #ffd700; - box-shadow: 0 0 20px rgba(255, 215, 0, 0.4); -} - -.leaderboard-item:nth-child(2) .user-avatar { - border-color: #c0c0c0; - box-shadow: 0 0 20px rgba(192, 192, 192, 0.4); -} - -.leaderboard-item:nth-child(3) .user-avatar { - border-color: #cd7f32; - box-shadow: 0 0 20px rgba(205, 127, 50, 0.4); -} - -/* Enhanced stats display */ -.user-stats .stat { - background: var(--ifm-color-background); - border: 1px solid var(--ifm-color-border); - box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.06); - transition: all 0.3s ease; -} - -[data-theme="dark"] .user-stats .stat { - box-shadow: inset 0 2px 4px rgba(255, 255, 255, 0.03); -} - -.user-stats .stat:hover { - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); -} - -[data-theme="dark"] .user-stats .stat:hover { - box-shadow: 0 4px 12px rgba(255, 255, 255, 0.05); -} - -/* Enhanced GitHub link */ -.github-link { - background: var(--ifm-color-emphasis-800); - color: var(--ifm-font-color-base-inverse); - padding: 0.75rem 1.5rem; - border-radius: 50px; - text-decoration: none; - transition: all 0.3s ease; - font-weight: 600; - gap: 0.5rem; - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); -} - -[data-theme="dark"] .github-link { - background: var(--ifm-color-emphasis-200); - color: var(--ifm-color-emphasis-900); - box-shadow: 0 4px 15px rgba(255, 255, 255, 0.1); -} - -.github-link:hover { - transform: translateY(-2px); - box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3); - color: var(--ifm-font-color-base-inverse); - text-decoration: none; -} - -[data-theme="dark"] .github-link:hover { - box-shadow: 0 8px 25px rgba(255, 255, 255, 0.2); - color: var(--ifm-color-emphasis-900); -} - -/* Top 3 special styling */ -.leaderboard-item:nth-child(1) { - background: var(--ifm-card-background-color); - border: 2px solid #ffd700; - position: relative; - overflow: hidden; -} - -.leaderboard-item:nth-child(1)::before { - content: ""; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: linear-gradient( - 135deg, - rgba(255, 215, 0, 0.1) 0%, - transparent 50% - ); - pointer-events: none; -} - -.leaderboard-item:nth-child(2) { - background: var(--ifm-card-background-color); - border: 2px solid #c0c0c0; - position: relative; - overflow: hidden; -} - -.leaderboard-item:nth-child(2)::before { - content: ""; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: linear-gradient( - 135deg, - rgba(192, 192, 192, 0.1) 0%, - transparent 50% - ); - pointer-events: none; -} - -.leaderboard-item:nth-child(3) { - background: var(--ifm-card-background-color); - border: 2px solid #cd7f32; - position: relative; - overflow: hidden; -} - -.leaderboard-item:nth-child(3)::before { - content: ""; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: linear-gradient( - 135deg, - rgba(205, 127, 50, 0.1) 0%, - transparent 50% - ); - pointer-events: none; -} - -/* Crown icons for top 3 */ -.leaderboard-item:nth-child(1)::after { - content: "👑"; - position: absolute; - top: -10px; - right: 20px; - font-size: 2rem; - filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2)); -} - -.leaderboard-item:nth-child(2)::after { - content: "🥈"; - position: absolute; - top: -10px; - right: 20px; - font-size: 2rem; - filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2)); -} - -.leaderboard-item:nth-child(3)::after { - content: "🥉"; - position: absolute; - top: -10px; - right: 20px; - font-size: 2rem; - filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2)); -} - -/* Leaderboard stats enhancement */ -.leaderboard-stats { - background: linear-gradient( - 135deg, - var(--ifm-color-primary) 0%, - var(--ifm-color-primary-darker) 100% - ); - color: white; - margin-bottom: 3rem; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); -} - -[data-theme="dark"] .leaderboard-stats { - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); -} - -.leaderboard-stats .stat-number { - color: white; - text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); -} - -.leaderboard-stats .stat-label { - color: rgba(255, 255, 255, 0.9); - font-weight: 600; -} - -/* Loading animation enhancement */ -.loading-spinner-large { - background: linear-gradient( - 135deg, - var(--ifm-color-primary), - var(--ifm-color-primary-darker) - ); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -/* Empty state enhancement */ -.empty-state { - text-align: center; - padding: 4rem 2rem; - background: var(--ifm-card-background-color); - border-radius: 2rem; - margin: 2rem 0; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); - border: 1px solid var(--ifm-color-border); -} - -[data-theme="dark"] .empty-state { - box-shadow: 0 8px 32px rgba(255, 255, 255, 0.05); -} - -/* Streak display */ -.streak-display { - position: absolute; - top: 1rem; - left: 1rem; - background: linear-gradient(135deg, #ff8a80, #ff5722); - color: white; - padding: 0.5rem 1rem; - border-radius: 50px; - font-size: 0.8rem; - font-weight: 600; - box-shadow: 0 4px 12px rgba(255, 87, 34, 0.3); - z-index: 10; -} - -.streak-display::before { - content: "🔥 "; -} - -/* Achievement tag enhancements for theme compatibility */ -.achievement-tag { - background: var(--ifm-color-primary-lightest); - color: var(--ifm-color-primary-darker); - border: 1px solid var(--ifm-color-primary-light); - transition: all 0.3s ease; -} - -[data-theme="dark"] .achievement-tag { - background: var(--ifm-color-primary-darkest); - color: var(--ifm-color-primary-lighter); - border: 1px solid var(--ifm-color-primary-dark); -} -.leaderboard-filters { - display: flex; - gap: 1rem; - margin: 1.5rem 0; - justify-content: flex-end; - align-items: center; - flex-wrap: wrap; -} -.leaderboard-header-controls { - display: flex; - justify-content: space-between; - align-items: center; - gap: 1rem; - margin-bottom: 2rem; - flex-wrap: wrap; -} -.refresh-section { - display: flex; - flex-direction: column; - gap: 0.5rem; -} -.filter-button { - padding: 0.75rem 1.5rem; - border: 2px solid var(--ifm-color-primary); - background: transparent; - color: var(--ifm-color-primary); - border-radius: 25px; - cursor: pointer; - font-size: 0.9rem; - font-weight: 600; - transition: all 0.3s ease; - position: relative; - overflow: hidden; - white-space: nowrap; -} - -.filter-button:hover { - background: var(--ifm-color-primary-lightest); - transform: translateY(-2px); +.navbar-icon-item:hover { + background: var(--ifm-color-emphasis-100); + color: var(--ifm-color-content); } -.filter-button.active { - background: var(--ifm-color-primary); - color: white; - box-shadow: 0 4px 15px rgba(var(--ifm-color-primary-rgb), 0.3); +.navbar-icon-item.active { + background: var(--ifm-color-primary-lightest); + color: var(--ifm-color-primary); + font-weight: 600; } -.filter-button.active::before { - content: ""; +.navbar-icon-item.active::before { + content: ''; position: absolute; - top: 0; left: 0; - right: 0; + top: 0; bottom: 0; - background: linear-gradient( - 45deg, - transparent 30%, - rgba(255, 255, 255, 0.2) 50%, - transparent 70% - ); - animation: shimmer 2s infinite; + width: 3px; + background: var(--ifm-color-primary); + border-radius: 0 2px 2px 0; } -.filter-button:disabled { - opacity: 0.6; - cursor: not-allowed; + +.navbar-icon { + margin-right: 12px; + display: flex; + align-items: center; + font-size: 18px; } -.filter-button .filter-icon { - margin-right: 0.5rem; - font-size: 1rem; +.navbar-text { + font-size: 14px; + line-height: 1.4; } -@keyframes shimmer { - 0% { - transform: translateX(-100%); - } - 100% { - transform: translateX(100%); - } +/* Main Content */ +.dashboard-main-content { + flex: 1; + padding: 40px; + overflow-x: hidden; } -.filter-button .filter-icon { - margin-right: 0.5rem; +/* Home Dashboard Styles */ +.dashboard-home-container { + max-width: 1200px; + margin: 0 auto; } -/* Rate limit warning */ -.rate-limit-warning { - background: linear-gradient(135deg, #fff3cd, #ffeaa7); - border: 1px solid #ffc107; - border-radius: 10px; - padding: 1.5rem; - margin: 1rem 0; +.dashboard-main-title { + font-size: 2.5rem; + font-weight: 800; + margin-bottom: 16px; + color: var(--ifm-color-content); text-align: center; } -.rate-limit-warning h4 { - color: #856404; - margin-bottom: 0.5rem; +.dashboard-description { + font-size: 1.1rem; + color: var(--ifm-color-content-secondary); + text-align: center; + margin-bottom: 60px; + max-width: 600px; + margin-left: auto; + margin-right: auto; } -.rate-limit-warning p { - color: #856404; - margin-bottom: 1rem; +.dashboard-stats-section { + margin-bottom: 60px; } -.rate-limit-timer { - font-size: 1.5rem; - font-weight: bold; - color: #dc3545; - margin: 1rem 0; +.section-title { + font-size: 1.8rem; + font-weight: 700; + margin-bottom: 30px; + text-align: center; + color: var(--ifm-color-content); } -/* Light theme rate limit warning */ -[data-theme="light"] .rate-limit-warning { - background: #fef3c7; - border: 1px solid #f59e0b; +.stat-cards-container { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 24px; + margin-bottom: 40px; } -[data-theme="light"] .rate-limit-warning h4, -[data-theme="light"] .rate-limit-warning p { - color: #92400e !important; +.dashboard-stat-card { + background: var(--ifm-background-surface-color); + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 16px; + padding: 32px 24px; + text-align: center; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); + transition: all 0.3s ease; + position: relative; + overflow: hidden; } -[data-theme="light"] .rate-limit-timer { - color: #dc2626 !important; +.dashboard-stat-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 4px; + background: linear-gradient(90deg, var(--ifm-color-primary), var(--ifm-color-primary-light)); } -@media (max-width: 768px) { - .leaderboard-header-controls { - flex-direction: column; - align-items: stretch; - } - .leaderboard-filters { - justify-content: center; - margin: 1rem 0; - } +.dashboard-stat-card:hover { + transform: translateY(-4px); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1); + border-color: var(--ifm-color-primary-lightest); +} - .filter-button { - padding: 0.6rem 1rem; - font-size: 0.8rem; - } +.dashboard-stat-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 64px; + height: 64px; + background: var(--ifm-color-primary-lightest); + color: var(--ifm-color-primary); + border-radius: 16px; + margin-bottom: 16px; + font-size: 24px; } -/* Filter loading state */ -.filter-loading { - opacity: 0.6; - pointer-events: none; +.dashboard-stat-title { + font-size: 1.1rem; + font-weight: 600; + margin-bottom: 8px; + color: var(--ifm-color-content-secondary); } -/* Light theme comprehensive fixes */ -[data-theme="light"] .leaderboard-page-container { - color: #1a202c; +.dashboard-stat-value { + font-size: 2.5rem; + font-weight: 800; + margin-bottom: 8px; + color: var(--ifm-color-content); + min-height: 60px; + display: flex; + align-items: center; + justify-content: center; +} + +.dashboard-stat-description { + font-size: 0.9rem; + color: var(--ifm-color-content-secondary); + line-height: 1.4; + margin: 0; } -[data-theme="light"] .leaderboard-content { - color: #1a202c; +.loading-spinner { + width: 32px; + height: 32px; + border: 3px solid var(--ifm-color-emphasis-200); + border-top: 3px solid var(--ifm-color-primary); + border-radius: 50%; + animation: spin 1s linear infinite; } -[data-theme="light"] .leaderboard-item * { - color: inherit; +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } } -[data-theme="light"] .leaderboard-item .user-info * { - color: inherit; +/* Discussions Section */ +.dashboard-discussions { + max-width: 1200px; + margin: 0 auto; } -/* Ensure all text in leaderboard is visible in light theme */ -[data-theme="light"] .leaderboard-item, -[data-theme="light"] .leaderboard-item .user-info, -[data-theme="light"] .leaderboard-item .user-stats, -[data-theme="light"] .leaderboard-item .achievements { - color: #1a202c !important; +.discussions-header { + text-align: center; + margin-bottom: 40px; } -[data-theme="light"] .leaderboard-item .user-name, -[data-theme="light"] .leaderboard-item .user-username, -[data-theme="light"] .leaderboard-item .stat-text { - color: inherit !important; +.discussions-header h1 { + font-size: 2.2rem; + font-weight: 700; + margin-bottom: 12px; + color: var(--ifm-color-content); } -/* Force visibility for all leaderboard text elements */ -[data-theme="light"] .leaderboard-page-container * { - color: inherit; +.discussions-header p { + font-size: 1.1rem; + color: var(--ifm-color-content-secondary); } -[data-theme="light"] .leaderboard-page-container h1, -[data-theme="light"] .leaderboard-page-container h2, -[data-theme="light"] .leaderboard-page-container h3, -[data-theme="light"] .leaderboard-page-container h4, -[data-theme="light"] .leaderboard-page-container p { - color: #1a202c !important; +.discussions-controls { + display: flex; + flex-direction: column; + gap: 20px; + margin-bottom: 30px; } -/* Keep giveaway page text white in light theme, but table text black */ -[data-theme="light"] - .min-h-screen.bg-gradient-to-br - *:not(table):not(th):not(td) { - color: white !important; +.discussion-tabs { + display: flex; + gap: 12px; + justify-content: center; + flex-wrap: wrap; } -[data-theme="light"] .min-h-screen.bg-gradient-to-br table th, -[data-theme="light"] .min-h-screen.bg-gradient-to-br table td { - color: black !important; + +.tab-button { + display: flex; + align-items: center; + gap: 8px; + padding: 12px 20px; + background: var(--ifm-background-surface-color); + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 8px; + cursor: pointer; + font-weight: 500; + transition: all 0.2s ease; + color: var(--ifm-color-content); } -/* ===== CONTRIBUTORS PAGE STYLING ===== */ +.tab-button:hover { + background: var(--ifm-color-emphasis-100); + border-color: var(--ifm-color-primary-lightest); +} -.contributors-page-container { - max-width: 1200px; - margin: 0 auto; - padding: 2rem; +.tab-button.active { + background: var(--ifm-color-primary); + color: white; + border-color: var(--ifm-color-primary); } -.contributors-hero .hero-content { - text-align: center; - margin-bottom: 3rem; +.search-and-sort { + display: flex; + gap: 16px; + align-items: center; + justify-content: center; + flex-wrap: wrap; } -.contributors-content { - margin-top: 3rem; +.search-bar { + display: flex; + align-items: center; + background: var(--ifm-background-surface-color); + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 8px; + padding: 0 12px; + min-width: 250px; } -.contributors-header { - text-align: center; - margin-bottom: 3rem; +.search-bar svg { + color: var(--ifm-color-content-secondary); + margin-right: 8px; } -.contributors-header h2 { - font-size: 2.5rem; - font-weight: 700; - color: var(--ifm-color-emphasis-900); - margin-bottom: 1rem; +.search-bar input { + border: none; + outline: none; + background: transparent; + padding: 12px 0; + flex: 1; + color: var(--ifm-color-content); } -.contributors-header p { - font-size: 1.2rem; - color: var(--ifm-color-emphasis-600); +.search-bar input::placeholder { + color: var(--ifm-color-content-secondary); } -.contributors-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); - gap: 2rem; - margin-top: 2rem; +.search-and-sort select { + padding: 12px 16px; + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 8px; + background: var(--ifm-background-surface-color); + color: var(--ifm-color-content); + cursor: pointer; +} + +.new-discussion-btn { + padding: 12px 20px; + background: var(--ifm-color-primary); + color: white; + border: none; + border-radius: 8px; + cursor: pointer; + font-weight: 500; + transition: all 0.2s ease; +} + +.new-discussion-btn:hover { + background: var(--ifm-color-primary-dark); + transform: translateY(-1px); +} + +.discussions-main-content { + display: flex; + gap: 30px; } -.contributor-card { - background: var(--ifm-card-background-color); +.category-sidebar { + min-width: 200px; + background: var(--ifm-background-surface-color); border: 1px solid var(--ifm-color-emphasis-200); border-radius: 12px; - padding: 2rem; - text-align: center; - transition: all 0.3s ease; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); + padding: 20px; + height: fit-content; + position: sticky; + top: 20px; } -.contributor-card:hover { - transform: translateY(-5px); - box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1); - border-color: var(--ifm-color-primary); +.category-sidebar h3 { + margin-bottom: 16px; + font-size: 1.1rem; + font-weight: 600; + color: var(--ifm-color-content); } -.contributor-avatar { - width: 80px; - height: 80px; - border-radius: 50%; - margin-bottom: 1rem; - border: 3px solid var(--ifm-color-primary-light); +.category-sidebar ul { + list-style: none; + padding: 0; + margin: 0; } -.contributor-avatar.placeholder { - background: var(--ifm-color-primary-lightest); +.category-sidebar li { display: flex; align-items: center; - justify-content: center; - font-size: 2rem; - color: var(--ifm-color-primary); - margin: 0 auto 1rem; + gap: 8px; + padding: 10px 12px; + border-radius: 6px; + cursor: pointer; + transition: all 0.2s ease; + color: var(--ifm-color-content-secondary); + font-weight: 500; +} + +.category-sidebar li:hover { + background: var(--ifm-color-emphasis-100); + color: var(--ifm-color-content); } -.contributor-card h3 { - font-size: 1.25rem; +.category-sidebar li.active { + background: var(--ifm-color-primary-lightest); + color: var(--ifm-color-primary); font-weight: 600; - color: var(--ifm-color-emphasis-900); - margin-bottom: 0.5rem; } -.contributor-card p { - color: var(--ifm-color-emphasis-600); - margin-bottom: 1rem; - font-size: 0.9rem; +.discussion-list { + flex: 1; } -.contributor-stats { +.loading-spinner-container { display: flex; justify-content: center; - flex-wrap: wrap; - gap: 0.5rem; + align-items: center; + padding: 60px; } -.contributor-stats span { - background: var(--ifm-color-primary-lightest); - color: var(--ifm-color-primary-darker); - padding: 0.25rem 0.75rem; - border-radius: 20px; - font-size: 0.8rem; - font-weight: 500; +.discussions-error-message, +.no-discussions-found { + text-align: center; + padding: 60px 20px; + color: var(--ifm-color-content-secondary); } -/* Dark theme support for contributors */ -[data-theme="dark"] .contributor-card { - background: var(--ifm-background-surface-color); - border-color: var(--ifm-color-emphasis-300); +/* Contributors Section */ +.dashboard-contributors { + max-width: 1200px; + margin: 0 auto; +} + +/* Giveaway Section */ +.giveaway-section { + text-align: center; + max-width: 600px; + margin: 0 auto; + padding: 60px 20px; } -[data-theme="dark"] .contributor-avatar.placeholder { - background: var(--ifm-color-primary-darkest); +.giveaway-section h1 { + font-size: 2.2rem; + font-weight: 700; + margin-bottom: 16px; + color: var(--ifm-color-content); } -[data-theme="dark"] .contributor-stats span { - background: var(--ifm-color-primary-darkest); - color: var(--ifm-color-primary-lighter); +.giveaway-content { + background: var(--ifm-background-surface-color); + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 12px; + padding: 40px; + margin-top: 30px; } -/* Responsive design for contributors */ -@media (max-width: 768px) { - .contributors-page-container { - padding: 1rem; +/* Mobile Responsive */ +@media (max-width: 996px) { + .dashboard-layout { + flex-direction: column; + } + + .dashboard-sidebar { + display: none; + } + + .dashboard-menu-btn { + display: block; + } + + .dashboard-main-content { + padding: 80px 20px 40px; + } + + .dashboard-main-title { + font-size: 2rem; + } + + .dashboard-description { + font-size: 1rem; + margin-bottom: 40px; } - .contributors-grid { + .stat-cards-container { grid-template-columns: 1fr; - gap: 1.5rem; + gap: 16px; } - .contributors-header h2 { + .dashboard-stat-card { + padding: 24px 20px; + } + + .dashboard-stat-value { font-size: 2rem; + min-height: 50px; } -} -/* Light theme github buttons */ -[data-theme="light"] .github-profile-btn, -[data-theme="light"] .github-link { - background: var(--ifm-color-primary); - color: white !important; -} + .discussions-main-content { + flex-direction: column; + gap: 20px; + } -[data-theme="light"] .github-profile-btn:hover, -[data-theme="light"] .github-link:hover { - background: var(--ifm-color-primary-darker); - color: white !important; - text-decoration: none; -} + .category-sidebar { + position: static; + min-width: auto; + } -/* Light theme refresh button */ -[data-theme="light"] .refresh-button { - background: var(--ifm-color-primary); - color: white !important; -} + .category-sidebar ul { + display: flex; + flex-wrap: wrap; + gap: 8px; + } -[data-theme="light"] .refresh-button:hover:not(:disabled) { - background: var(--ifm-color-primary-darker); - color: white !important; -} + .category-sidebar li { + white-space: nowrap; + } -/* Light theme rate limit status */ -[data-theme="light"] .rate-limit-status { - color: #4a5568 !important; -} + .search-and-sort { + flex-direction: column; + align-items: stretch; + } -/* ===== COMPREHENSIVE LIGHT THEME LEADERBOARD FIXES ===== */ + .search-bar { + min-width: auto; + } -/* Force all leaderboard text to be visible in light theme */ -[data-theme="light"] .leaderboard-page-container, -[data-theme="light"] .leaderboard-page-container *, -[data-theme="light"] .leaderboard-content, -[data-theme="light"] .leaderboard-content *, -[data-theme="light"] .leaderboard-grid, -[data-theme="light"] .leaderboard-grid *, -[data-theme="light"] .leaderboard-item, -[data-theme="light"] .leaderboard-item * { - color: #1a202c !important; -} + .discussion-tabs { + justify-content: flex-start; + overflow-x: auto; + padding-bottom: 8px; + } -/* Override specific elements that need different colors */ -[data-theme="light"] .score-display, -[data-theme="light"] .score-display * { - color: white !important; + .tab-button { + white-space: nowrap; + flex-shrink: 0; + } } -[data-theme="light"] .rank-badge, -[data-theme="light"] .rank-badge * { - color: white !important; -} +@media (max-width: 768px) { + .dashboard-main-content { + padding: 80px 16px 40px; + } -[data-theme="light"] .github-profile-btn, -[data-theme="light"] .github-profile-btn *, -[data-theme="light"] .github-link, -[data-theme="light"] .github-link * { - color: white !important; -} + .dashboard-stat-card { + padding: 20px 16px; + } -[data-theme="light"] .refresh-button, -[data-theme="light"] .refresh-button * { - color: white !important; -} + .dashboard-stat-icon { + width: 56px; + height: 56px; + font-size: 22px; + } -/* Ensure primary colored elements remain visible */ -[data-theme="light"] .stat-value, -[data-theme="light"] .score-number { - color: var(--ifm-color-primary) !important; -} + .dashboard-stat-value { + font-size: 1.8rem; + } -/* Fix any remaining invisible text */ -[data-theme="light"] .leaderboard-page-header *, -[data-theme="light"] .leaderboard-stats *, -[data-theme="light"] .user-info *, -[data-theme="light"] .user-stats *, -[data-theme="light"] .achievements * { - color: inherit !important; -} + .discussions-header h1 { + font-size: 1.8rem; + } -/* Ensure proper contrast for all interactive elements */ -[data-theme="light"] .filter-button { - color: var(--ifm-color-primary) !important; - border-color: var(--ifm-color-primary) !important; + .category-sidebar { + padding: 16px; + } } -[data-theme="light"] .filter-button.active { - background: var(--ifm-color-primary) !important; - color: white !important; +/* Dark mode enhancements */ +[data-theme="dark"] .dashboard-stat-card { + background: var(--ifm-color-emphasis-100); + border-color: var(--ifm-color-emphasis-300); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); } -/* Final fallback for any missed elements */ -[data-theme="light"] .dashboard-main * { - color: inherit; +[data-theme="dark"] .dashboard-stat-card:hover { + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4); } -[data-theme="light"] .dashboard-main { - color: #1a202c; +[data-theme="dark"] .dashboard-stat-icon { + background: rgba(99, 102, 241, 0.2); } + +[data-theme="dark"] .loading-spinner { + border-color: var(--ifm-color-emphasis-300); + border-top-color: var(--ifm-color-primary); +} \ No newline at end of file diff --git a/src/pages/dashboard/index.tsx b/src/pages/dashboard/index.tsx index c60fb34e..ab2e2a9e 100644 --- a/src/pages/dashboard/index.tsx +++ b/src/pages/dashboard/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { JSX, useEffect, useState } from "react"; import Layout from "@theme/Layout"; import Head from "@docusaurus/Head"; import BrowserOnly from "@docusaurus/BrowserOnly"; @@ -29,10 +29,12 @@ import { Calendar, BarChart3, ArrowLeft, + GitFork, } from "lucide-react"; import NavbarIcon from "@site/src/components/navbar/NavbarIcon"; import "@site/src/components/discussions/discussions.css"; import "./dashboard.css"; +import LeaderBoard from "@site/src/components/dashboard/LeaderBoard/leaderboard"; type DiscussionTab = "discussions" | "trending" | "unanswered"; type SortOption = "most_popular" | "latest" | "oldest"; @@ -44,38 +46,11 @@ type Category = | "show-and-tell" | "general"; -interface LeaderboardEntry { - rank: number; - name: string; - username?: string; - avatar: string; - contributions: number; - repositories: number; - achievements: string[]; - github_url: string; - score?: number; - streak?: number; - postManTag?: boolean; - web3hack?: boolean; - weeklyContributions?: number; - monthlyContributions?: number; -} - -type FilterPeriod = "weekly" | "monthly" | "overall"; - interface DashboardStats { totalContributors: number; totalRepositories: number; totalStars: number; totalForks: number; - topContributors: LeaderboardEntry[]; -} - -interface RateLimitInfo { - isLimited: boolean; - resetTime?: number; - remaining?: number; - limit?: number; } const categories: Category[] = [ @@ -103,8 +78,6 @@ const DashboardContent: React.FC = () => { const [discussions, setDiscussions] = useState([]); const [discussionsLoading, setDiscussionsLoading] = useState(true); const [discussionsError, setDiscussionsError] = useState(null); - const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false); - const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState(false); const [showDashboardMenu, setShowDashboardMenu] = useState(false); // Close dashboard menu when clicking outside @@ -126,19 +99,6 @@ const DashboardContent: React.FC = () => { document.removeEventListener('mousedown', handleClickOutside); }; }, [showDashboardMenu]); - const [leaderboardData, setLeaderboardData] = useState( - [] - ); - const [filteredLeaderboardData, setFilteredLeaderboardData] = useState< - LeaderboardEntry[] - >([]); - const [filterPeriod, setFilterPeriod] = useState("monthly"); - const [isLoadingLeaderboard, setIsLoadingLeaderboard] = useState(false); - const [leaderboardError, setLeaderboardError] = useState(null); - const [rateLimitInfo, setRateLimitInfo] = useState({ - isLimited: false, - }); - const [retryTimer, setRetryTimer] = useState(null); useEffect(() => { // Set active tab based on URL hash @@ -176,70 +136,6 @@ const DashboardContent: React.FC = () => { } }; - // Fetch leaderboard data when contributors tab is active or on initial load - useEffect(() => { - if (activeTab === "contributors") { - fetchLeaderboardData(); - } - }, [activeTab]); - - // Load initial demo data if no data exists - useEffect(() => { - if (leaderboardData.length === 0) { - const initialData: LeaderboardEntry[] = [ - { - rank: 1, - name: "sanjay-kv", - username: "sanjay-kv", - avatar: "https://avatars.githubusercontent.com/u/30715153?v=4", - contributions: 250, - repositories: 25, - score: 2500, - achievements: ["Top Contributor", "Founder", "Maintainer"], - github_url: "https://github.com/sanjay-kv", - streak: 15, - postManTag: false, - web3hack: false, - weeklyContributions: 35, - monthlyContributions: 120, - }, - { - rank: 2, - name: "vansh-codes", - username: "vansh-codes", - avatar: "https://avatars.githubusercontent.com/u/114163734?v=4", - contributions: 180, - repositories: 22, - score: 1800, - achievements: ["Rising Star", "Active Contributor", "Star Contributor"], - github_url: "https://github.com/vansh-codes", - streak: 8, - postManTag: false, - web3hack: false, - weeklyContributions: 25, - monthlyContributions: 85, - }, - { - rank: 3, - name: "Hemu21", - username: "Hemu21", - avatar: "https://avatars.githubusercontent.com/u/106808387?v=4", - contributions: 120, - repositories: 18, - score: 1200, - achievements: ["Power User", "Star Contributor", "Consistent"], - github_url: "https://github.com/Hemu21", - streak: 5, - postManTag: false, - web3hack: false, - weeklyContributions: 18, - monthlyContributions: 60, - }, - ]; - setLeaderboardData(initialData); - } - }, [leaderboardData.length]); - // Discussion handlers const handleDiscussionTabChange = (tab: DiscussionTab) => { setActiveDiscussionTab(tab); @@ -295,7 +191,7 @@ const DashboardContent: React.FC = () => { // First apply tab filter switch (activeDiscussionTab) { case "trending": - return discussion.reactions.total_count > 5; // Show discussions with more than 5 reactions + return discussion.reactions.total_count > 5; case "unanswered": return discussion.comments === 0; default: @@ -368,7 +264,7 @@ const DashboardContent: React.FC = () => { new Date(b.created_at).getTime() ); default: - return b.reactions.total_count - a.reactions.total_count; // most_popular + return b.reactions.total_count - a.reactions.total_count; } }); }; @@ -378,364 +274,11 @@ const DashboardContent: React.FC = () => { [discussions, activeDiscussionTab, selectedCategory, searchQuery, sortBy] ); - // Rate limit timer - useEffect(() => { - let interval: NodeJS.Timeout; - if (rateLimitInfo.isLimited && rateLimitInfo.resetTime) { - interval = setInterval(() => { - const now = Date.now(); - const resetTime = rateLimitInfo.resetTime * 1000; - const timeLeft = Math.max(0, resetTime - now); - - if (timeLeft <= 0) { - setRateLimitInfo({ isLimited: false }); - setRetryTimer(null); - } else { - setRetryTimer(Math.ceil(timeLeft / 1000)); - } - }, 1000); - } - - return () => { - if (interval) clearInterval(interval); - }; - }, [rateLimitInfo]); - - // Function to get GitHub headers with token if available - const getGitHubHeaders = () => { - return { - Accept: "application/vnd.github.v3+json", - "User-Agent": "RecodeHive-Dashboard/1.0", - }; - }; - - // Function to fetch data with rate limit handling - const fetchWithRateLimit = async (url: string): Promise => { - try { - const response = await fetch(url, { - headers: getGitHubHeaders(), - }); - - // Check rate limit headers - const rateLimitRemaining = response.headers.get("X-RateLimit-Remaining"); - const rateLimitReset = response.headers.get("X-RateLimit-Reset"); - const rateLimitLimit = response.headers.get("X-RateLimit-Limit"); - - // Handle rate limit more gracefully - if (response.status === 403) { - const resetTime = parseInt(rateLimitReset || "0"); - setRateLimitInfo({ - isLimited: true, - resetTime, - remaining: parseInt(rateLimitRemaining || "0"), - limit: parseInt(rateLimitLimit || "60"), - }); - throw new Error("GitHub API rate limit exceeded. Using cached data."); - } - - // Update rate limit info for display - if (rateLimitRemaining && rateLimitLimit) { - setRateLimitInfo({ - isLimited: false, - remaining: parseInt(rateLimitRemaining), - limit: parseInt(rateLimitLimit), - }); - } - - return response; - } catch (error) { - // More specific error handling - if (error.message.includes("rate limit")) { - throw error; - } - - // Generic network error - console.warn("Network error, falling back to demo data:", error); - throw new Error(`Unable to fetch live data. Showing demo data instead.`); - } - }; - - // Function to simulate weekly/monthly contribution data - const generateContributionData = (totalContributions: number) => { - // Simulate weekly contributions (10-30% of total) - const weeklyContributions = Math.floor( - totalContributions * (0.1 + Math.random() * 0.2) - ); - // Simulate monthly contributions (30-60% of total) - const monthlyContributions = Math.floor( - totalContributions * (0.3 + Math.random() * 0.3) - ); - - return { - weeklyContributions, - monthlyContributions, - }; - }; - - // Filter leaderboard data based on selected period - const filterLeaderboardData = ( - data: LeaderboardEntry[], - period: FilterPeriod - ) => { - let sortedData = [...data]; - - switch (period) { - case "weekly": - sortedData.sort( - (a, b) => (b.weeklyContributions || 0) - (a.weeklyContributions || 0) - ); - break; - case "monthly": - sortedData.sort( - (a, b) => - (b.monthlyContributions || 0) - (a.monthlyContributions || 0) - ); - break; - case "overall": - default: - sortedData.sort((a, b) => b.contributions - a.contributions); - break; - } - - // Update ranks based on filtered sorting - return sortedData.map((item, index) => ({ - ...item, - rank: index + 1, - })); - }; - - // Update filtered data when period or data changes - useEffect(() => { - const filtered = filterLeaderboardData(leaderboardData, filterPeriod); - setFilteredLeaderboardData(filtered); - }, [leaderboardData, filterPeriod]); - - const fetchLeaderboardData = async () => { - if (rateLimitInfo.isLimited) { - setLeaderboardError( - "Rate limit exceeded. Please wait before trying again." - ); - return; - } - - setIsLoadingLeaderboard(true); - setLeaderboardError(null); - - try { - console.log('Fetching leaderboard data from RecodeHive GitHub API...'); - - // Fetch all repositories from RecodeHive organization - const reposResponse = await fetch('https://api.github.com/orgs/recodehive/repos?type=public&per_page=100'); - - if (!reposResponse.ok) { - if (reposResponse.status === 403) { - throw new Error('GitHub API rate limit exceeded'); - } - throw new Error(`GitHub API request failed: ${reposResponse.status}`); - } - - const repos = await reposResponse.json(); - - if (!Array.isArray(repos)) { - throw new Error("Invalid GitHub API response format"); - } - - // Collect all contributors from all repositories (limit to avoid rate limits) - const contributorsMap = new Map< - string, - { - login: string; - avatar_url: string; - html_url: string; - contributions: number; - repositories: number; - weeklyContributions: number; - monthlyContributions: number; - } - >(); - - // Process only top repositories to avoid rate limits - const topRepos = repos - .sort((a, b) => b.stargazers_count - a.stargazers_count) - .slice(0, 10); // Limit to top 10 repos to reduce API calls - - // Fetch contributors for each repository with delay to avoid rate limits - for (let i = 0; i < topRepos.length; i++) { - const repo = topRepos[i]; - try { - // Add delay between requests to avoid hitting rate limits - if (i > 0) { - await new Promise((resolve) => setTimeout(resolve, 100)); - } - - const contributorsResponse = await fetchWithRateLimit( - `https://api.github.com/repos/${repo.full_name}/contributors?per_page=100` - ); - - if (contributorsResponse.ok) { - const contributors = await contributorsResponse.json(); - - if (Array.isArray(contributors)) { - contributors.forEach((contributor) => { - if (contributor.login && contributor.type === "User") { - const existing = contributorsMap.get(contributor.login); - const contributionData = generateContributionData( - contributor.contributions - ); - - if (existing) { - existing.contributions += contributor.contributions; - existing.repositories += 1; - existing.weeklyContributions += - contributionData.weeklyContributions; - existing.monthlyContributions += - contributionData.monthlyContributions; - } else { - contributorsMap.set(contributor.login, { - login: contributor.login, - avatar_url: contributor.avatar_url, - html_url: contributor.html_url, - contributions: contributor.contributions, - repositories: 1, - weeklyContributions: contributionData.weeklyContributions, - monthlyContributions: - contributionData.monthlyContributions, - }); - } - } - }); - } - } - } catch (error) { - console.warn(`Error fetching contributors for ${repo.name}:`, error); - if (error.message.includes("rate limit")) { - // Stop processing if we hit rate limit - break; - } - } - } - - // Transform contributors data to match our LeaderboardEntry interface - const transformedData: LeaderboardEntry[] = Array.from( - contributorsMap.values() - ) - .filter((contributor) => contributor.contributions > 0) - .map((contributor, index) => { - const score = contributor.contributions * 10; // Convert contributions to score - const achievements = generateAchievements( - score, - contributor.contributions - ); - - return { - rank: index + 1, - name: contributor.login, - username: contributor.login, - avatar: contributor.avatar_url, - contributions: contributor.contributions, - repositories: contributor.repositories, - score, - achievements, - github_url: contributor.html_url, - streak: Math.floor(Math.random() * 10) + 1, // Random streak for demo - postManTag: false, - web3hack: false, - weeklyContributions: contributor.weeklyContributions, - monthlyContributions: contributor.monthlyContributions, - }; - }) - .sort((a, b) => b.contributions - a.contributions) // Sort by contributions descending - .map((item, index) => ({ ...item, rank: index + 1 })); // Update ranks after sorting - - setLeaderboardData(transformedData); - } catch (error) { - console.error("Error fetching RecodeHive contributors data:", error); - setLeaderboardError(error.message); - - // Load fallback demo data - console.warn("Using fallback leaderboard data due to GitHub API limitations"); - setLeaderboardError("GitHub API rate limit reached. Showing demo data."); - const demoData: LeaderboardEntry[] = [ - { - rank: 1, - name: "sanjay-kv", - username: "sanjay-kv", - avatar: "https://avatars.githubusercontent.com/u/30715153?v=4", - contributions: 250, - repositories: 25, - score: 2500, - achievements: ["Top Contributor", "Founder", "Maintainer"], - github_url: "https://github.com/sanjay-kv", - streak: 15, - postManTag: false, - web3hack: false, - weeklyContributions: 35, - monthlyContributions: 120, - }, - { - rank: 2, - name: "vansh-codes", - username: "vansh-codes", - avatar: "https://avatars.githubusercontent.com/u/114163734?v=4", - contributions: 180, - repositories: 22, - score: 1800, - achievements: ["Rising Star", "Active Contributor", "Star Contributor"], - github_url: "https://github.com/vansh-codes", - streak: 8, - postManTag: false, - web3hack: false, - weeklyContributions: 25, - monthlyContributions: 85, - }, - { - rank: 3, - name: "Hemu21", - username: "Hemu21", - avatar: "https://avatars.githubusercontent.com/u/106808387?v=4", - contributions: 120, - repositories: 18, - score: 1200, - achievements: ["Power User", "Star Contributor", "Consistent"], - github_url: "https://github.com/Hemu21", - streak: 5, - postManTag: false, - web3hack: false, - weeklyContributions: 18, - monthlyContributions: 60, - }, - ]; - setLeaderboardData(demoData); - } finally { - setIsLoadingLeaderboard(false); - } - }; - - const generateAchievements = ( - score: number, - contributions: number - ): string[] => { - const achievements: string[] = []; - if (score >= 5000) achievements.push("Elite Contributor"); - if (score >= 3000) achievements.push("Master Contributor"); - if (score >= 1000) achievements.push("Advanced Contributor"); - if (score >= 500) achievements.push("Active Contributor"); - if (score >= 100) achievements.push("Rising Star"); - if (contributions >= 100) achievements.push("Century Club"); - if (contributions >= 50) achievements.push("Half Century"); - if (contributions >= 25) achievements.push("Quick Contributor"); - if (contributions >= 10) achievements.push("Consistent"); - if (score >= 7000) achievements.push("Legend"); - if (contributions >= 150) achievements.push("PR Master"); - return achievements.slice(0, 3); - }; - const handleTabChange = ( tab: "home" | "discuss" | "giveaway" | "contributors" ) => { setActiveTab(tab); - setIsMobileSidebarOpen(false); // Close mobile sidebar - setShowDashboardMenu(false); // Close dashboard menu + setShowDashboardMenu(false); if (tab === "discuss") { history.push("#discuss"); window.scrollTo(0, 0); @@ -749,122 +292,11 @@ const DashboardContent: React.FC = () => { } }; - // Filter functions - const handleFilterChange = (period: FilterPeriod) => { - setFilterPeriod(period); - }; - - const getContributionCount = ( - entry: LeaderboardEntry, - period: FilterPeriod - ) => { - switch (period) { - case "weekly": - return entry.weeklyContributions || 0; - case "monthly": - return entry.monthlyContributions || 0; - case "overall": - default: - return entry.contributions; - } - }; - - const FilterButtons = () => ( - - - - - - ); - - const RateLimitWarning = () => - rateLimitInfo.isLimited ? ( - -

GitHub API Rate Limit Reached

-

- We've temporarily reached the GitHub API rate limit. The contributors page - will automatically refresh when the limit resets. -

- {retryTimer && ( -
- Retry in: {Math.floor(retryTimer / 60)}: - {(retryTimer % 60).toString().padStart(2, "0")} -
- )} - -
- ) : rateLimitInfo.remaining && rateLimitInfo.remaining < 20 ? ( - -

API Rate Limit Low

-

- GitHub API requests remaining: {rateLimitInfo.remaining}/ - {rateLimitInfo.limit} -

-
- ) : null; - - // Rest of your component code remains the same... const { githubStarCount, - githubStarCountText, githubContributorsCount, - githubContributorsCountText, githubForksCount, - githubForksCountText, githubReposCount, - githubReposCountText, loading, error, } = useCommunityStatsContext(); @@ -874,7 +306,6 @@ const DashboardContent: React.FC = () => { totalRepositories: 0, totalStars: 0, totalForks: 0, - topContributors: [], }); useEffect(() => { @@ -883,18 +314,16 @@ const DashboardContent: React.FC = () => { totalRepositories: githubReposCount, totalStars: githubStarCount, totalForks: githubForksCount, - topContributors: leaderboardData.slice(0, 4), }); }, [ githubContributorsCount, githubReposCount, githubStarCount, githubForksCount, - leaderboardData, ]); const StatCard: React.FC<{ - icon: string; + icon: React.ReactNode; title: string; value: number; valueText: string; @@ -913,7 +342,7 @@ const DashboardContent: React.FC = () => {

{title}

{loading ? ( -
Loading...
+
) : ( { ); - const LeaderboardCard: React.FC<{ - entry: LeaderboardEntry; - index: number; - }> = ({ entry, index }) => ( - -
- #{entry.rank} -
-
- {entry.name} -
-
-

{entry.name}

-
- - {entry.contributions} Contributions - - - {entry.repositories} Repositories - -
-
- {entry.achievements.map((achievement, i) => ( - - {achievement} - - ))} -
-
- -
- ); - return (
{/* Dashboard Menu Button - Only visible on mobile */} @@ -996,817 +376,314 @@ const DashboardContent: React.FC = () => { onClick={() => setShowDashboardMenu(false)} /> )} -
-

Dashboard Menu

- -
- - - {/* Dashboard navigation items */} -
-
{ - handleTabChange("home"); - setShowDashboardMenu(false); - }} - > - - - - Home -
-
{ - handleTabChange("discuss"); - setShowDashboardMenu(false); - }} - > - - - - Discuss -
- -
{ - handleTabChange("giveaway"); - setShowDashboardMenu(false); - }} - > - - - - Giveaway -
-
{ - handleTabChange("contributors"); - setShowDashboardMenu(false); - }} - > - - - - Contributors -
-
-
- - {/* Sidebar Navigation - Hidden on mobile */} - - -
isSidebarCollapsed && setIsSidebarCollapsed(false)} - > - {activeTab === "home" ? ( - // Home tab content -
- +
{ + handleTabChange("home"); + setShowDashboardMenu(false); + }} > -
-

- Community Dashboard -

-

- Track our community's growth, celebrate top contributors, - and explore project statistics -

-
- - - {/* Stats Grid */} - Home +
+
{ + handleTabChange("discuss"); + setShowDashboardMenu(false); + }} > -
- - - - -
- - - {/* Leaderboard Section */} - Discussions +
+
{ + handleTabChange("contributors"); + setShowDashboardMenu(false); + }} > -
-

- Top Contributors Board -

-

- Celebrating our most active community members who make - RecodeHive awesome! -

-
- -
- {error && ( -
-

Some data may be cached or incomplete

-
- )} - - {dashboardStats.topContributors.map((entry, index) => ( - - ))} -
- - - {/* Call to Action */} - LeaderBoard +
+
{ + handleTabChange("giveaway"); + setShowDashboardMenu(false); + }} > -
-

Want to see your name here?

-

- Join our community and start contributing to open source - projects! -

- -
- + Giveaways +
- ) : activeTab === "discuss" ? ( - -
-

- Community{" "} - - Discussions - -

-

- Join the conversation, ask questions, and share your thoughts - with the RecodeHive community. -

+
+
+ +
+
+ +
+
+ } + text="Home" + active={activeTab === "home"} + onClick={() => handleTabChange("home")} + /> + } + text="Discussions" + active={activeTab === "discuss"} + onClick={() => handleTabChange("discuss")} + /> + } + text="LeaderBoard +" + active={activeTab === "contributors"} + onClick={() => handleTabChange("contributors")} + /> + } + text="Giveaways" + active={activeTab === "giveaway"} + onClick={() => handleTabChange("giveaway")} + /> +
+
+ +
+ + Dashboard | Recode Hive + + + {activeTab === "home" && ( + +

Recode Hive Community Dashboard

+

+ Welcome to the Recode Hive community hub! Explore our stats, engage in discussions, and connect with fellow contributors. +

+ +
+

Community At a Glance

+
+ } + title="Total Stars" + value={dashboardStats.totalStars} + valueText={ + useCommunityStatsContext().githubStarCountText || "937" + } + description="Stars across all our public repositories" + /> + } + title="Contributors" + value={dashboardStats.totalContributors} + valueText={ + useCommunityStatsContext().githubContributorsCountText || "444" + } + description="Amazing community members" + /> + } + title="Repositories" + value={dashboardStats.totalRepositories} + valueText={ + useCommunityStatsContext().githubReposCountText || "10" + } + description="Open source projects" + /> + } + title="Forks" + value={dashboardStats.totalForks} + valueText={ + useCommunityStatsContext().githubForksCountText || "1.03K" + } + description="Community contributions" + />
+
+
+ )} + {activeTab === "discuss" && ( + +
+

Community Discussions

+

+ Engage with the community, ask questions, and share your projects. +

+
+
-
- - - -
+ > + All Discussions + -
- -
- {categories.map((category) => ( - - ))} + > + Unanswered +
- -
-
- +
+
+
-
- -
-
- -
- - {filteredDiscussions.length} discussion - {filteredDiscussions.length !== 1 ? "s" : ""} found - + +
- - {discussionsLoading ? ( -
-
-

Loading discussions...

-
- ) : discussionsError ? ( -
-
!
-

Unable to load discussions

-

{discussionsError}

- -
- ) : ( - <> -
- {filteredDiscussions.length > 0 ? ( - filteredDiscussions.map((discussion, index) => ( - - )) - ) : ( -
-
No discussions
-

No discussions found

-

- {searchQuery || selectedCategory !== "all" - ? "Try adjusting your filters or search terms." - : "Be the first to start a discussion!"} -

- - Start a Discussion - -
- )} -
- - {/* Community Engagement Section */} -
-

- 💬 Join the Conversation -

-

- Connect with our community! Share ideas, ask questions, and showcase your amazing work. -

-
- - ❓ Ask Question - - - 💡 Share Idea - - - 🎉 Show Work - -
-
- - )} - - ) : activeTab === "giveaway" ? ( - /* Giveaway Tab - Empty for now */ -
- -

- Giveaway -

-
- ) : activeTab === "contributors" ? ( - /* Contributors Tab - Shows the list of contributors */ -
- -

- RecodeHive Contributors -

-

- Live rankings from RecodeHive GitHub Organization • Updated - automatically -

- - {/* Header Controls: Refresh Button + Filter Buttons */} -
-
- - {rateLimitInfo.remaining && ( -

- API calls remaining: {rateLimitInfo.remaining}/ - {rateLimitInfo.limit} -

- )} + {getCategoryIcon(cat)} {getCategoryDisplayName(cat)} + + ))} + +
+
+ {discussionsLoading && ( +
+
- - {/* Filter Buttons positioned to the right */} - -
- - - {/* Rate Limit Warning */} - - - {/* Loading State */} - {isLoadingLeaderboard && ( - -
Loading...
-

- Fetching latest contributor data... -

-
- )} - - {/* Error State */} - {leaderboardError && !isLoadingLeaderboard && ( - -
!
-

Unable to Load Latest Data

-

{leaderboardError}

- {!rateLimitInfo.isLimited && ( - - )} -

- Showing cached data below. The contributors page will - automatically refresh when possible. -

-
- )} - - {/* Contributors Content */} - {!isLoadingLeaderboard && filteredLeaderboardData.length > 0 && ( - -
-
- - {filteredLeaderboardData.length} - - Contributors -
-
- - {getContributionCount( - filteredLeaderboardData[0], - filterPeriod - ) || 0} - - - Top{" "} - {filterPeriod.charAt(0).toUpperCase() + - filterPeriod.slice(1)} - -
-
- - {Math.round( - filteredLeaderboardData.reduce( - (acc, user) => - acc + getContributionCount(user, filterPeriod), - 0 - ) / filteredLeaderboardData.length - )} - - - Avg{" "} - {filterPeriod.charAt(0).toUpperCase() + - filterPeriod.slice(1)} - -
+ )} + {discussionsError && ( +
+

{discussionsError}

+ )} + {!discussionsLoading && + !discussionsError && + filteredDiscussions.length === 0 && ( +
+

No discussions found matching your criteria.

+
+ )} + {!discussionsLoading && + !discussionsError && + filteredDiscussions.map((discussion) => ( + + ))} +
+
+
+ )} -
- {filteredLeaderboardData.map((entry, index) => ( - - {/* Streak Display */} - {entry.streak && entry.streak > 1 && ( -
- {entry.streak} Day Streak -
- )} - -
-
- #{entry.rank} -
-
- -
- {entry.name} -
- -
-

{entry.name}

- {entry.username && entry.username !== entry.name && ( -

@{entry.username}

- )} - -
- - {getContributionCount(entry, filterPeriod)} - - - {filterPeriod === "weekly" - ? "this week" - : filterPeriod === "monthly" - ? "this month" - : "total"} - -
- -
-
- - {entry.contributions} - - Total PRs -
-
- - {entry.repositories} - - Repos -
-
- - {entry.achievements.length > 0 && ( -
- {entry.achievements.map((achievement, i) => ( - - {achievement} - - ))} -
- )} -
- - -
- ))} -
- - )} + {/* Contributors section with new LeaderBoard component */} + {activeTab === "contributors" && ( + + + + )} - {/* Empty State */} - {!isLoadingLeaderboard && - !leaderboardError && - filteredLeaderboardData.length === 0 && ( - -

No data available

-

No contributors found. Check back later!

-
- )} + {activeTab === "giveaway" && ( + +

Giveaways

+

+ Participate in our exciting giveaways for a chance to win awesome prizes! +

+
+

+ Stay tuned for our next giveaway. Follow our social media channels for updates! +

- ) : null} - +
+ )}
- ); +
+ ); }; const Dashboard: React.FC = () => { return ( - + - RecodeHive | Dashboard - + + + - Loading...
}> + Loading Dashboard...
}> {() => ( @@ -1817,4 +694,4 @@ const Dashboard: React.FC = () => { ); }; -export default Dashboard; +export default Dashboard; \ No newline at end of file