diff --git a/sidebars.ts b/sidebars.ts index 1e9b510c..11ec70b3 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -124,7 +124,7 @@ const sidebars: SidebarsConfig = { "Pandas/pd_intro", "Pandas/pd_dataframes", "Pandas/pd_input_output", - "Pandas/pd_data_analysis", + "Pandas/pd_data_analysis", ], }, { diff --git a/src/components/Community/LandingCommunity.css b/src/components/Community/LandingCommunity.css index 3067bf13..9f568573 100644 --- a/src/components/Community/LandingCommunity.css +++ b/src/components/Community/LandingCommunity.css @@ -47,7 +47,10 @@ gap: 1rem; } -.landing-community .landing-community__content .landing-community__stats .landing-community__stat-item { +.landing-community + .landing-community__content + .landing-community__stats + .landing-community__stat-item { display: flex; flex-direction: column; justify-content: center; @@ -60,28 +63,47 @@ position: relative; } -.landing-community .landing-community__content .landing-community__stats .landing-community__stat-item.clickable { +.landing-community + .landing-community__content + .landing-community__stats + .landing-community__stat-item.clickable { cursor: pointer; } -.landing-community .landing-community__content .landing-community__stats .landing-community__stat-item.clickable:hover, -.landing-community .landing-community__content .landing-community__stats .landing-community__stat-item.clickable:focus { +.landing-community + .landing-community__content + .landing-community__stats + .landing-community__stat-item.clickable:hover, +.landing-community + .landing-community__content + .landing-community__stats + .landing-community__stat-item.clickable:focus { transform: scale(1.02); box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); outline: none; } -.landing-community .landing-community__content .landing-community__stats .landing-community__stat-item.loading { +.landing-community + .landing-community__content + .landing-community__stats + .landing-community__stat-item.loading { opacity: 0.7; } -.landing-community .landing-community__content .landing-community__stats .landing-community__stat-item:hover { +.landing-community + .landing-community__content + .landing-community__stats + .landing-community__stat-item:hover { cursor: pointer; transform: scale(1.01); box-shadow: 0 8px 16px rgba(0, 0, 0, 0.4); } -.landing-community .landing-community__content .landing-community__stats .landing-community__stat-item .landing-community__stat-value { +.landing-community + .landing-community__content + .landing-community__stats + .landing-community__stat-item + .landing-community__stat-value { font-size: 3.5rem; font-weight: 600; color: var(--ifm-color-primary); @@ -105,7 +127,11 @@ text-shadow: inherit; } -.landing-community .landing-community__content .landing-community__stats .landing-community__stat-item .landing-community__loading { +.landing-community + .landing-community__content + .landing-community__stats + .landing-community__stat-item + .landing-community__loading { display: flex; align-items: center; justify-content: center; @@ -133,11 +159,19 @@ transition: opacity 0.2s ease; } -.landing-community .landing-community__content .landing-community__stats .landing-community__stat-item.clickable:hover .external-link-icon { +.landing-community + .landing-community__content + .landing-community__stats + .landing-community__stat-item.clickable:hover + .external-link-icon { opacity: 1; } -.landing-community .landing-community__content .landing-community__stats .landing-community__stat-item .landing-community__stat-description { +.landing-community + .landing-community__content + .landing-community__stats + .landing-community__stat-item + .landing-community__stat-description { font-size: 1rem; text-shadow: 0 0 1px var(--ifm-color-primary); } @@ -152,38 +186,58 @@ position: relative; } -.landing-community .landing-community__content .landing-community__info.clickable { +.landing-community + .landing-community__content + .landing-community__info.clickable { cursor: pointer; } -.landing-community .landing-community__content .landing-community__info.clickable:hover, -.landing-community .landing-community__content .landing-community__info.clickable:focus { +.landing-community + .landing-community__content + .landing-community__info.clickable:hover, +.landing-community + .landing-community__content + .landing-community__info.clickable:focus { transform: scale(1.01); box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); outline: none; } -.landing-community .landing-community__content .landing-community__info .landing-community__image { +.landing-community + .landing-community__content + .landing-community__info + .landing-community__image { width: 100%; object-fit: cover; border-radius: 1rem; } -.landing-community .landing-community__content .landing-community__info .landing-community__info-text { +.landing-community + .landing-community__content + .landing-community__info + .landing-community__info-text { margin-top: 1rem; padding: 0; font-size: 1rem; text-shadow: 0 0 1px var(--ifm-color-primary); } -.landing-community .landing-community__content .landing-community__info .landing-community__info-text .landing-community__link { +.landing-community + .landing-community__content + .landing-community__info + .landing-community__info-text + .landing-community__link { color: var(--ifm-color-primary); text-shadow: 0 0 1px var(--ifm-color-primary); text-decoration: none; font-weight: 600; } -.landing-community .landing-community__content .landing-community__info .landing-community__info-text .landing-community__link:hover { +.landing-community + .landing-community__content + .landing-community__info + .landing-community__info-text + .landing-community__link:hover { text-decoration: underline; } @@ -197,7 +251,10 @@ transition: opacity 0.2s ease; } -.landing-community .landing-community__content .landing-community__info.clickable:hover .external-link-indicator { +.landing-community + .landing-community__content + .landing-community__info.clickable:hover + .external-link-indicator { opacity: 1; } @@ -214,14 +271,20 @@ width: 100%; } - .landing-community .landing-community__content .landing-community__info .landing-community__image { + .landing-community + .landing-community__content + .landing-community__info + .landing-community__image { width: 100%; } - .landing-community .landing-community__content .landing-community__info .landing-community__info-text { + .landing-community + .landing-community__content + .landing-community__info + .landing-community__info-text { margin-top: 1rem; padding: 0; font-size: 1rem; text-shadow: 0 0 1px var(--ifm-color-primary); } -} \ No newline at end of file +} diff --git a/src/components/HomepageFeatures/styles.module.css b/src/components/HomepageFeatures/styles.module.css index 036cd579..69126a23 100644 --- a/src/components/HomepageFeatures/styles.module.css +++ b/src/components/HomepageFeatures/styles.module.css @@ -9,4 +9,4 @@ .featureSvg { height: 200px; width: 200px; -} \ No newline at end of file +} diff --git a/src/components/StatsSection/styles.module.css b/src/components/StatsSection/styles.module.css index 6c565622..0bc3745e 100644 --- a/src/components/StatsSection/styles.module.css +++ b/src/components/StatsSection/styles.module.css @@ -144,7 +144,6 @@ /* Animation keyframes */ @keyframes float { - 0%, 100% { transform: translateY(0); @@ -156,7 +155,6 @@ } @keyframes pulse { - 0%, 100% { transform: scale(1); @@ -181,4 +179,4 @@ 100% { box-shadow: 0 0 5px rgba(79, 70, 229, 0.5); } -} \ No newline at end of file +} diff --git a/src/components/dashboard/LeaderBoard/BadgeModal.tsx b/src/components/dashboard/LeaderBoard/BadgeModal.tsx new file mode 100644 index 00000000..42f74008 --- /dev/null +++ b/src/components/dashboard/LeaderBoard/BadgeModal.tsx @@ -0,0 +1,190 @@ +// src/components/dashboard/LeaderBoard/BadgeModal.tsx +import React, { useEffect } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { FaTimes } from "react-icons/fa"; +import { useSafeColorMode } from "@site/src/utils/useSafeColorMode"; + +interface BadgeConfig { + image: string; + name: string; + criteria: (prs: number, points: number) => boolean; +} + +interface BadgeModalProps { + isOpen: boolean; + onClose: () => void; + earnedBadges: string[]; + allBadges: BadgeConfig[]; + contributorName?: string; +} + +export default function BadgeModal({ + isOpen, + onClose, + earnedBadges, + allBadges, + contributorName, +}: BadgeModalProps): JSX.Element | null { + const { isDark } = useSafeColorMode(); + + // Close modal on Escape key press + useEffect(() => { + if (!isOpen) return; + const handleEsc = (event: KeyboardEvent) => { + if (event.key === "Escape") { + onClose(); + } + }; + + window.addEventListener("keydown", handleEsc); + return () => { + window.removeEventListener("keydown", handleEsc); + }; + }, [isOpen, onClose]); + + const handleBackdropClick = (e: React.MouseEvent) => { + if (e.target === e.currentTarget) { + onClose(); + } + }; + + if (!isOpen) return null; + + return ( + + {isOpen && ( + + e.stopPropagation()} + > + {/* Modal Header */} +
+
+

+ {contributorName + ? `${contributorName}'s Badges` + : "Achievement Badges"} +

+

+ {earnedBadges.length} of {allBadges.length} badges earned +

+
+ +
+ + {/* Modal Body */} +
+
+ {allBadges.map((badge, index) => { + const isEarned = earnedBadges.includes(badge.image); + return ( + +
+ {badge.name} + {!isEarned && ( +
+ + + + +
+ )} + {isEarned && ( +
+ + + +
+ )} +
+
+

+ {badge.name} +

+ {!isEarned && ( +

+ Locked +

+ )} + {isEarned && ( +

+ Earned +

+ )} +
+
+ ); + })} +
+
+
+
+ )} +
+ ); +} + diff --git a/src/components/dashboard/LeaderBoard/PRListModal.tsx b/src/components/dashboard/LeaderBoard/PRListModal.tsx index 2d15fa2e..f86c0a1f 100644 --- a/src/components/dashboard/LeaderBoard/PRListModal.tsx +++ b/src/components/dashboard/LeaderBoard/PRListModal.tsx @@ -1,8 +1,8 @@ // src/components/dashboard/LeaderBoard/PRListModal.tsx -import React, { useEffect } from "react"; +import React, { useEffect, useMemo } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { FaTimes, FaExternalLinkAlt, FaGithub } from "react-icons/fa"; -import { useColorMode } from "@docusaurus/theme-common"; +import { useSafeColorMode } from "@site/src/utils/useSafeColorMode"; import { useCommunityStatsContext } from "../../../lib/statsProvider"; interface PRDetails { @@ -34,20 +34,43 @@ export default function PRListModal({ isOpen, onClose, }: PRListModalProps): JSX.Element | null { - const { colorMode } = useColorMode(); - const isDark = colorMode === "dark"; + const { isDark } = useSafeColorMode(); // Get filtered PRs from context const { getFilteredPRsForContributor, currentTimeFilter } = useCommunityStatsContext(); - if (!contributor) return null; - // Get filtered PRs instead of using contributor.prDetails - const filteredPRs = getFilteredPRsForContributor(contributor.username); + // Use useMemo to prevent infinite loops + // IMPORTANT: All hooks must be called before any early returns + const filteredPRs = useMemo(() => { + if (!contributor) return []; + return getFilteredPRsForContributor(contributor.username); + }, [contributor?.username, getFilteredPRsForContributor, currentTimeFilter]); // Calculate total points from filtered PRs - const totalPoints = filteredPRs.reduce((sum, pr) => sum + pr.points, 0); + const totalPoints = useMemo(() => { + return filteredPRs.reduce((sum, pr) => sum + pr.points, 0); + }, [filteredPRs]); + + // Close modal on Escape key press + useEffect(() => { + if (!isOpen) return; + const handleEsc = (event: KeyboardEvent) => { + if (event.key === "Escape") { + onClose(); + } + }; + + window.addEventListener("keydown", handleEsc); + return () => { + window.removeEventListener("keydown", handleEsc); + }; + }, [isOpen, onClose]); + + // Early return AFTER all hooks + // Only return null if contributor is missing (not if isOpen is false, to allow exit animations) + if (!contributor) return null; const formatDate = (dateString: string) => { const date = new Date(dateString); @@ -88,21 +111,6 @@ export default function PRListModal({ return "#6b7280"; // Gray for no points }; - // Close modal on Escape key press - useEffect(() => { - if (!isOpen) return; - const handleEsc = (event: KeyboardEvent) => { - if (event.key === "Escape") { - onClose(); - } - }; - - window.addEventListener("keydown", handleEsc); - return () => { - window.removeEventListener("keydown", handleEsc); - }; - }, [isOpen]); - return ( {isOpen && ( diff --git a/src/components/dashboard/LeaderBoard/leaderboard.css b/src/components/dashboard/LeaderBoard/leaderboard.css index 1e53a997..d05cbcc7 100644 --- a/src/components/dashboard/LeaderBoard/leaderboard.css +++ b/src/components/dashboard/LeaderBoard/leaderboard.css @@ -92,7 +92,10 @@ padding: 20px; border-radius: 16px; width: 200px; - transition: transform 0.3s ease-in-out, box-shadow 0.3s ease-in-out, border 0.3s; + transition: + transform 0.3s ease-in-out, + box-shadow 0.3s ease-in-out, + border 0.3s; position: relative; cursor: pointer; display: flex; @@ -120,7 +123,7 @@ /* Reflection Effect */ .podium-card::after { - content: ''; + content: ""; position: absolute; top: 100%; left: 0; @@ -132,7 +135,7 @@ rgba(255, 255, 255, 0.4) 0%, rgba(255, 255, 255, 0.3) 25%, rgba(255, 255, 255, 0.1) 75%, - rgba(255, 255, 255, 0.0) 100% + rgba(255, 255, 255, 0) 100% ); transform: scaleY(-1); z-index: 1; @@ -145,14 +148,20 @@ rgba(43, 48, 59, 0.4) 0%, rgba(43, 48, 59, 0.3) 25%, rgba(43, 48, 59, 0.1) 75%, - rgba(43, 48, 59, 0.0) 100% + rgba(43, 48, 59, 0) 100% ); } /* Reflection box-shadows */ -.first-place::after { box-shadow: 0 2px 6px rgba(255, 215, 0, 0.1); } -.second-place::after { box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05); } -.third-place::after { box-shadow: 0 2px 6px rgba(205, 127, 50, 0.1); } +.first-place::after { + box-shadow: 0 2px 6px rgba(255, 215, 0, 0.1); +} +.second-place::after { + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05); +} +.third-place::after { + box-shadow: 0 2px 6px rgba(205, 127, 50, 0.1); +} /* User Photo */ .podium-card .user-photo { @@ -192,9 +201,15 @@ border-color: #2b303b; } -.first-place .rank-badge { background-color: #FFD700; } -.second-place .rank-badge { background-color: #555; } -.third-place .rank-badge { background-color: #CD7F32; } +.first-place .rank-badge { + background-color: #ffd700; +} +.second-place .rank-badge { + background-color: #555; +} +.third-place .rank-badge { + background-color: #cd7f32; +} /* User Details */ .podium-card .details { @@ -255,28 +270,38 @@ } .second-place:hover { - transform: translateY(-5px); - border-color: #C0C0C0; - box-shadow: 0 0 15px rgba(192, 192, 192, 0.7), 0 10px 30px rgba(0, 0, 0, 0.15); + transform: translateY(-35px); + border-color: #c0c0c0; + box-shadow: + 0 0 15px rgba(192, 192, 192, 0.7), + 0 10px 30px rgba(0, 0, 0, 0.15); } .third-place:hover { transform: translateY(-5px); - border-color: #CD7F32; - box-shadow: 0 0 15px rgba(205, 127, 50, 0.7), 0 10px 30px rgba(0, 0, 0, 0.15); + border-color: #cd7f32; + box-shadow: + 0 0 15px rgba(205, 127, 50, 0.7), + 0 10px 30px rgba(0, 0, 0, 0.15); } /* Dark Mode Hover Effects */ .dark .first-place:hover { - box-shadow: 0 0 15px rgba(255, 215, 0, 0.3), 0 10px 30px rgba(0, 0, 0, 0.3); + box-shadow: + 0 0 15px rgba(255, 215, 0, 0.3), + 0 10px 30px rgba(0, 0, 0, 0.3); } .dark .second-place:hover { - box-shadow: 0 0 15px rgba(192, 192, 192, 0.3), 0 10px 30px rgba(0, 0, 0, 0.3); + box-shadow: + 0 0 15px rgba(192, 192, 192, 0.3), + 0 10px 30px rgba(0, 0, 0, 0.3); } .dark .third-place:hover { - box-shadow: 0 0 15px rgba(205, 127, 50, 0.3), 0 10px 30px rgba(0, 0, 0, 0.3); + box-shadow: + 0 0 15px rgba(205, 127, 50, 0.3), + 0 10px 30px rgba(0, 0, 0, 0.3); } /* Stats Grid */ @@ -546,7 +571,7 @@ .contributors-header { display: grid; - grid-template-columns: 0.5fr 0.5fr 2fr 1fr 1fr; + grid-template-columns: 0.5fr 0.5fr 2fr 1fr 1fr 1.5fr; padding: 16px 24px; font-weight: bold; font-size: 14px; @@ -569,7 +594,7 @@ .contributor-row { display: grid; - grid-template-columns: 0.5fr 0.5fr 2fr 1fr 1fr; + grid-template-columns: 0.5fr 0.5fr 2fr 1fr 1fr 1.5fr; align-items: center; padding: 16px 24px; transition: background-color 0.2s ease; @@ -615,6 +640,84 @@ padding: 8px; } +/* Badge display styles */ +.contributor-badges { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; + cursor: pointer; + transition: all 0.2s ease; +} + +.contributor-badges:hover { + transform: translateY(-2px); +} + +.contributor-badge-icon { + width: 44px; + height: 44px; + object-fit: contain; + border-radius: 8px; + transition: + transform 0.2s ease, + box-shadow 0.2s ease; + cursor: pointer; + background: rgba(255, 255, 255, 0.1); + padding: 2px; +} + +.contributor-badge-icon:hover { + transform: scale(1.15); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); + z-index: 10; + position: relative; +} + +.username-with-badges { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 4px; +} + +/* Badges column styling */ +.contributor-cell.badges-cell { + display: flex; + align-items: center; + justify-content: flex-start; + padding: 8px; +} + +/* Badge display in top performer cards */ +.top-performer-card .contributor-badges { + margin-top: 8px; + justify-content: center; +} + +.top-performer-card .contributor-badge-icon { + width: 36px; + height: 36px; +} + +/* Badge display in podium cards */ +.podium-card .details { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; +} + +.podium-card .contributor-badges { + margin-top: 4px; + justify-content: center; +} + +.podium-card .contributor-badge-icon { + width: 32px; + height: 32px; +} + /* Position the badge inside the cell */ .rank-badge { position: absolute; @@ -1636,3 +1739,386 @@ gap: 12px; } } + +/* Badge Modal Styles */ +.badge-modal-backdrop { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 1000; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; + backdrop-filter: blur(4px); +} + +.badge-modal-backdrop.light { + background: rgba(0, 0, 0, 0.5); +} + +.badge-modal-backdrop.dark { + background: rgba(0, 0, 0, 0.7); +} + +.badge-modal-container { + width: 100%; + max-width: 900px; + max-height: 85vh; + border-radius: 20px; + box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); + overflow: hidden; + display: flex; + flex-direction: column; +} + +.badge-modal-container.light { + background: white; + border: 1px solid #e5e7eb; +} + +.badge-modal-container.dark { + background: #1f2937; + border: 1px solid #374151; +} + +/* Badge Modal Header */ +.badge-modal-header { + padding: 24px 28px 20px; + border-bottom: 1px solid; + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + background: linear-gradient(135deg, rgba(99, 102, 241, 0.1) 0%, rgba(139, 92, 246, 0.1) 100%); +} + +.badge-modal-header.light { + border-color: #e5e7eb; + background: linear-gradient(135deg, rgba(99, 102, 241, 0.05) 0%, rgba(139, 92, 246, 0.05) 100%); +} + +.badge-modal-header.dark { + border-color: #374151; + background: linear-gradient(135deg, rgba(99, 102, 241, 0.15) 0%, rgba(139, 92, 246, 0.15) 100%); +} + +.badge-modal-title { + font-size: 24px; + font-weight: 700; + margin: 0 0 4px 0; + background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.badge-modal-title.dark { + background: linear-gradient(135deg, #818cf8 0%, #a78bfa 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.badge-modal-subtitle { + font-size: 14px; + margin: 0; + opacity: 0.7; + font-weight: 500; +} + +.badge-modal-subtitle.light { + color: #6b7280; +} + +.badge-modal-subtitle.dark { + color: #9ca3af; +} + +.badge-modal-close { + width: 40px; + height: 40px; + border-radius: 10px; + border: none; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.2s ease; + flex-shrink: 0; + font-size: 18px; +} + +.badge-modal-close.light { + background: #f3f4f6; + color: #6b7280; +} + +.badge-modal-close.light:hover { + background: #e5e7eb; + color: #374151; + transform: rotate(90deg); +} + +.badge-modal-close.dark { + background: #374151; + color: #9ca3af; +} + +.badge-modal-close.dark:hover { + background: #4b5563; + color: #f3f4f6; + transform: rotate(90deg); +} + +/* Badge Modal Body */ +.badge-modal-body { + flex: 1; + overflow-y: auto; + padding: 28px; +} + +.badge-modal-body.light { + background: #fafafa; +} + +.badge-modal-body.dark { + background: #111827; +} + +.badge-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); + gap: 20px; + padding: 8px 0; +} + +/* Badge Item */ +.badge-item { + display: flex; + flex-direction: column; + align-items: center; + padding: 20px; + border-radius: 16px; + transition: all 0.3s ease; + cursor: pointer; + border: 2px solid transparent; + position: relative; + overflow: hidden; +} + +.badge-item.light { + background: #ffffff; + border-color: #e5e7eb; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); +} + +.badge-item.light:hover { + border-color: #6366f1; + box-shadow: 0 8px 24px rgba(99, 102, 241, 0.15); + transform: translateY(-4px); +} + +.badge-item.dark { + background: #1f2937; + border-color: #374151; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); +} + +.badge-item.dark:hover { + border-color: #8b5cf6; + box-shadow: 0 8px 24px rgba(139, 92, 246, 0.2); + transform: translateY(-4px); +} + +.badge-item.locked { + opacity: 0.6; +} + +.badge-item.earned { + opacity: 1; +} + +.badge-item.earned.light { + background: linear-gradient(135deg, rgba(99, 102, 241, 0.05) 0%, rgba(139, 92, 246, 0.05) 100%); + border-color: #6366f1; +} + +.badge-item.earned.dark { + background: linear-gradient(135deg, rgba(139, 92, 246, 0.1) 0%, rgba(99, 102, 241, 0.1) 100%); + border-color: #8b5cf6; +} + +.badge-item-image-wrapper { + position: relative; + width: 120px; + height: 120px; + margin-bottom: 16px; + display: flex; + align-items: center; + justify-content: center; +} + +.badge-item-image { + width: 100%; + height: 100%; + object-fit: contain; + border-radius: 12px; + transition: all 0.3s ease; + filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.1)); +} + +.badge-item-image.locked { + filter: grayscale(100%) brightness(0.5) drop-shadow(0 4px 8px rgba(0, 0, 0, 0.1)); +} + +.badge-item.earned .badge-item-image { + filter: drop-shadow(0 4px 12px rgba(99, 102, 241, 0.3)); +} + +.badge-item.dark.earned .badge-item-image { + filter: drop-shadow(0 4px 12px rgba(139, 92, 246, 0.4)); +} + +.badge-lock-overlay { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 48px; + height: 48px; + background: rgba(0, 0, 0, 0.7); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + color: white; + z-index: 2; + backdrop-filter: blur(4px); +} + +.badge-earned-indicator { + position: absolute; + top: 8px; + right: 8px; + width: 32px; + height: 32px; + background: linear-gradient(135deg, #10b981 0%, #059669 100%); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + color: white; + z-index: 2; + box-shadow: 0 2px 8px rgba(16, 185, 129, 0.4); + animation: pulse 2s infinite; +} + +@keyframes pulse { + 0%, 100% { + transform: scale(1); + box-shadow: 0 2px 8px rgba(16, 185, 129, 0.4); + } + 50% { + transform: scale(1.1); + box-shadow: 0 4px 12px rgba(16, 185, 129, 0.6); + } +} + +.badge-item-info { + text-align: center; + width: 100%; +} + +.badge-item-name { + font-size: 16px; + font-weight: 600; + margin: 0 0 8px 0; + line-height: 1.3; +} + +.badge-item-name.light { + color: #111827; +} + +.badge-item-name.dark { + color: #f9fafb; +} + +.badge-item-status { + font-size: 12px; + font-weight: 500; + margin: 0; + padding: 4px 12px; + border-radius: 12px; + display: inline-block; +} + +.badge-item-status.light { + background: #f3f4f6; + color: #6b7280; +} + +.badge-item-status.dark { + background: #374151; + color: #9ca3af; +} + +.badge-item-status.earned.light { + background: linear-gradient(135deg, #10b981 0%, #059669 100%); + color: white; +} + +.badge-item-status.earned.dark { + background: linear-gradient(135deg, #10b981 0%, #059669 100%); + color: white; +} + +/* Responsive Design for Badge Modal */ +@media (max-width: 768px) { + .badge-modal-container { + max-width: 95vw; + max-height: 90vh; + margin: 10px; + } + + .badge-modal-header { + padding: 20px 20px 16px; + } + + .badge-modal-body { + padding: 20px; + } + + .badge-grid { + grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); + gap: 16px; + } + + .badge-item-image-wrapper { + width: 100px; + height: 100px; + } +} + +@media (max-width: 480px) { + .badge-grid { + grid-template-columns: repeat(2, 1fr); + gap: 12px; + } + + .badge-item { + padding: 16px; + } + + .badge-item-image-wrapper { + width: 80px; + height: 80px; + } + + .badge-item-name { + font-size: 14px; + } +} diff --git a/src/components/dashboard/LeaderBoard/leaderboard.tsx b/src/components/dashboard/LeaderBoard/leaderboard.tsx index ea24970c..8994390c 100644 --- a/src/components/dashboard/LeaderBoard/leaderboard.tsx +++ b/src/components/dashboard/LeaderBoard/leaderboard.tsx @@ -1,11 +1,12 @@ // src/components/dashboard/LeaderBoard/leaderboard.tsx -import React, { JSX, useState } from "react"; +import React, { JSX, useState, useCallback } from "react"; import { motion } from "framer-motion"; import { FaStar, FaCode, FaUsers, FaGithub, FaSearch } from "react-icons/fa"; import { ChevronRight, ChevronLeft } from "lucide-react"; -import { useColorMode } from "@docusaurus/theme-common"; +import { useSafeColorMode } from "@site/src/utils/useSafeColorMode"; import { useCommunityStatsContext } from "@site/src/lib/statsProvider"; import PRListModal from "./PRListModal"; +import BadgeModal from "./BadgeModal"; import { mockContributors } from "./mockData"; import "./leaderboard.css"; @@ -20,6 +21,7 @@ interface PRDetails { mergedAt: string; repoName: string; number: number; + points: number; } interface Contributor { @@ -29,6 +31,7 @@ interface Contributor { points: number; prs: number; prDetails?: PRDetails[]; + badges?: string[]; // Array of badge image paths } interface Stats { @@ -37,6 +40,121 @@ interface Stats { flooredTotalPoints: number; } +// Badge configuration - maps badge numbers to achievement criteria +const BADGE_CONFIG = [ + { + image: "/badges/1.png", + name: "First Contribution", + criteria: (prs: number) => prs >= 1, + }, + { + image: "/badges/2.png", + name: "Bronze Contributor", + criteria: (prs: number) => prs >= 5, + }, + { + image: "/badges/3.png", + name: "Silver Contributor", + criteria: (prs: number) => prs >= 10, + }, + { + image: "/badges/4.png", + name: "Gold Contributor", + criteria: (prs: number) => prs >= 25, + }, + { + image: "/badges/5.png", + name: "Platinum Contributor", + criteria: (prs: number) => prs >= 50, + }, + { + image: "/badges/6.png", + name: "Diamond Contributor", + criteria: (prs: number) => prs >= 100, + }, + { + image: "/badges/7.png", + name: "Points Master", + criteria: (_: number, points: number) => points >= 500, + }, + { + image: "/badges/8.png", + name: "Elite Contributor", + criteria: (prs: number) => prs >= 200, + }, + { + image: "/badges/9.png", + name: "Legendary Contributor", + criteria: (prs: number) => prs >= 500, + }, + { + image: "/badges/10.png", + name: "Hall of Fame", + criteria: (prs: number, points: number) => prs >= 1000 || points >= 5000, + }, +]; + +/** + * Determines which badges a contributor should have based on their stats + */ +function getContributorBadges( + contributor: Contributor, + rank: number, +): string[] { + const badges: string[] = []; + + // Special rank-based badges + if (rank === 1) { + badges.push("/badges/10.png"); // Hall of Fame for #1 + } else if (rank === 2) { + badges.push("/badges/9.png"); // Legendary for #2 + } else if (rank === 3) { + badges.push("/badges/8.png"); // Elite for #3 + } + + // Achievement-based badges + BADGE_CONFIG.forEach((badge) => { + if (badge.criteria(contributor.prs, contributor.points)) { + // Avoid duplicates + if (!badges.includes(badge.image)) { + badges.push(badge.image); + } + } + }); + + return badges; +} + +/** + * Badge display component + */ +function ContributorBadges({ + badges, + onClick, +}: { + badges: string[]; + onClick?: () => void; +}) { + if (!badges || badges.length === 0) return null; + + return ( +
+ {badges.map((badge, index) => ( + {`Badge b.image === badge)?.name || + "Achievement Badge" + } + /> + ))} +
+ ); +} + function Badge({ count, label, @@ -88,14 +206,16 @@ function TopPerformerCard({ contributor, rank, onPRClick, + onBadgeClick, }: { contributor: Contributor; rank: number; onPRClick: (contributor: Contributor) => void; + onBadgeClick?: (contributor: Contributor) => void; }) { - const { colorMode } = useColorMode(); - const isDark = colorMode === "dark"; + const { isDark } = useSafeColorMode(); const rankClass = rank === 1 ? "top-1" : rank === 2 ? "top-2" : "top-3"; + const badges = getContributorBadges(contributor, rank); return (
@@ -116,6 +236,10 @@ function TopPerformerCard({ > {contributor.username} + onBadgeClick?.(contributor)} + />
(null); const [isModalOpen, setIsModalOpen] = useState(false); + const [badgeModalContributor, setBadgeModalContributor] = + useState(null); + const [isBadgeModalOpen, setIsBadgeModalOpen] = useState(false); const [isSelectChanged, setIsSelectChanged] = useState(false); const itemsPerPage = 20; @@ -163,10 +289,24 @@ export default function LeaderBoard(): JSX.Element { setIsModalOpen(true); }; - const handleCloseModal = () => { + const handleCloseModal = useCallback(() => { setIsModalOpen(false); setSelectedContributor(null); - }; + }, []); + + // Badge modal handlers + const handleBadgeClick = useCallback( + (contributor: Contributor) => { + setBadgeModalContributor(contributor); + setIsBadgeModalOpen(true); + }, + [], + ); + + const handleCloseBadgeModal = useCallback(() => { + setIsBadgeModalOpen(false); + setBadgeModalContributor(null); + }, []); // Use mock data only in development mode when there's an error or no contributors const displayContributors = @@ -376,7 +516,16 @@ export default function LeaderBoard(): JSX.Element { className="user-photo" />
-

{filteredContributors[1].username}

+

+ {filteredContributors[1].username} +

+ handleBadgeClick(filteredContributors[1])} + />
- {filteredContributors[1].points} Points + + {filteredContributors[1].points} Points +
@@ -401,7 +552,16 @@ export default function LeaderBoard(): JSX.Element { className="user-photo" />
-

{filteredContributors[0].username}

+

+ {filteredContributors[0].username} +

+ handleBadgeClick(filteredContributors[0])} + />
- {filteredContributors[0].points} Points + + {filteredContributors[0].points} Points +
@@ -426,7 +588,16 @@ export default function LeaderBoard(): JSX.Element { className="user-photo" />
-

{filteredContributors[2].username}

+

+ {filteredContributors[2].username} +

+ handleBadgeClick(filteredContributors[2])} + />
- {filteredContributors[2].points} Points + + {filteredContributors[2].points} Points +
@@ -574,6 +747,7 @@ export default function LeaderBoard(): JSX.Element {
User
PRs
Points
+
Badges
{currentItems.map((contributor, index) => ( +
+ handleBadgeClick(contributor)} + /> +
))} @@ -682,6 +865,22 @@ export default function LeaderBoard(): JSX.Element { isOpen={isModalOpen} onClose={handleCloseModal} /> + + {/* Badge Modal */} + {badgeModalContributor && ( + c.username === badgeModalContributor.username, + ) + 1, + )} + allBadges={BADGE_CONFIG} + contributorName={badgeModalContributor.username} + /> + )} ); } diff --git a/src/components/faqs/faqs.tsx b/src/components/faqs/faqs.tsx index ed7d8582..5b3465c4 100644 --- a/src/components/faqs/faqs.tsx +++ b/src/components/faqs/faqs.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; import { FiChevronDown } from "react-icons/fi"; import { motion } from "framer-motion"; -import { useColorMode } from "@docusaurus/theme-common"; // Docusaurus theme detection +import { useSafeColorMode } from "../../utils/useSafeColorMode"; const faqData = [ { @@ -44,8 +44,7 @@ const faqData = [ const FAQs: React.FC = () => { const [activeIndex, setActiveIndex] = useState(null); - const { colorMode } = useColorMode(); - const isDark = colorMode === "dark"; + const { colorMode, isDark } = useSafeColorMode(); const toggleAccordion = (index: number) => { setActiveIndex(activeIndex === index ? null : index); diff --git a/src/components/ourProjects.tsx b/src/components/ourProjects.tsx index 6511da4d..a52e79fa 100644 --- a/src/components/ourProjects.tsx +++ b/src/components/ourProjects.tsx @@ -4,7 +4,7 @@ import { ChevronRight } from "lucide-react"; import { useState } from "react"; import { motion } from "framer-motion"; import React from "react"; -import { useColorMode } from "@docusaurus/theme-common"; +import { useSafeColorMode } from "../utils/useSafeColorMode"; // Mobile-specific overrides for very small screens (<768px and <320px) import "./ourProjects.mobile.css"; // Import projects data and types @@ -51,8 +51,7 @@ export interface OurProjectsProps { const OurProjects: React.FC = ({ OurProjectsData: legacyData, }) => { - const { colorMode } = useColorMode(); // light or dark - const isDark = colorMode === "dark"; + const { colorMode, isDark } = useSafeColorMode(); // Use JSON data by default, fallback to legacy props for backward compatibility // Convert legacy data to new format if needed diff --git a/src/components/testimonials/TestimonialCard.tsx b/src/components/testimonials/TestimonialCard.tsx index 4ee4f2aa..7c378a85 100644 --- a/src/components/testimonials/TestimonialCard.tsx +++ b/src/components/testimonials/TestimonialCard.tsx @@ -1,7 +1,7 @@ import React from "react"; import { motion } from "framer-motion"; import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar"; -import { useColorMode } from "@docusaurus/theme-common"; +import { useSafeColorMode } from "../../utils/useSafeColorMode"; interface TestimonialCardProps { name: string; @@ -20,8 +20,7 @@ const TestimonialCard: React.FC = ({ avatar, link, }) => { - const { colorMode } = useColorMode(); - const isDark = colorMode === "dark"; + const { colorMode, isDark } = useSafeColorMode(); // Function to format the link display const formatLinkDisplay = (url: string) => { diff --git a/src/components/topmate/TopMateCard.tsx b/src/components/topmate/TopMateCard.tsx index 616e569d..faba360b 100644 --- a/src/components/topmate/TopMateCard.tsx +++ b/src/components/topmate/TopMateCard.tsx @@ -1,7 +1,7 @@ import React from "react"; import { motion } from "framer-motion"; import { ArrowUpRight, Clock } from "lucide-react"; -import { useColorMode } from "@docusaurus/theme-common"; +import { useSafeColorMode } from "../../utils/useSafeColorMode"; interface TopMateCardProps { title: string; @@ -20,8 +20,7 @@ const TopMateCard: React.FC = ({ username, setShowTopmate, }) => { - const { colorMode } = useColorMode(); - const isDark = colorMode === "dark"; + const { colorMode, isDark } = useSafeColorMode(); return ( { - const { colorMode } = useColorMode(); // Get current theme: 'light' or 'dark' + const { colorMode } = useSafeColorMode(); // Get current theme: 'light' or 'dark' const profileData = { title: "1:1 Mentorship Call", diff --git a/src/css/custom.css b/src/css/custom.css index f4e2be12..be920687 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -121,7 +121,7 @@ a.menu__link.menu__link--active div span:first-child { /* ================= SECTION 4: CUSTOM SIDEBAR CATEGORY THEMES ================= */ /* GitHub theme */ -.custom-sidebar-github>.menu__list-item-collapsible>.menu__link { +.custom-sidebar-github > .menu__list-item-collapsible > .menu__link { background: linear-gradient(135deg, #24292e, #586069); color: white; border-radius: 8px; @@ -130,7 +130,7 @@ a.menu__link.menu__link--active div span:first-child { } /* Python theme */ -.custom-sidebar-python>.menu__list-item-collapsible>.menu__link { +.custom-sidebar-python > .menu__list-item-collapsible > .menu__link { background: linear-gradient(135deg, #3776ab, #ffd43b); color: white; border-radius: 8px; @@ -139,7 +139,7 @@ a.menu__link.menu__link--active div span:first-child { } /* SQL theme */ -.custom-sidebar-sql>.menu__list-item-collapsible>.menu__link { +.custom-sidebar-sql > .menu__list-item-collapsible > .menu__link { background: linear-gradient(135deg, #336791, #4479a1); color: white; border-radius: 8px; @@ -148,7 +148,7 @@ a.menu__link.menu__link--active div span:first-child { } /* Next.js theme */ -.custom-sidebar-nextjs>.menu__list-item-collapsible>.menu__link { +.custom-sidebar-nextjs > .menu__list-item-collapsible > .menu__link { background: linear-gradient(135deg, #000000, #333333); color: white; border-radius: 8px; @@ -157,7 +157,7 @@ a.menu__link.menu__link--active div span:first-child { } /* Google Student Ambassador theme */ -.custom-sidebar-gsa>.menu__list-item-collapsible>.menu__link { +.custom-sidebar-gsa > .menu__list-item-collapsible > .menu__link { background: linear-gradient(135deg, #4285f4, #34a853); color: white; border-radius: 8px; @@ -166,7 +166,7 @@ a.menu__link.menu__link--active div span:first-child { } /* Technical theme */ -.custom-sidebar-technical>.menu__list-item-collapsible>.menu__link { +.custom-sidebar-technical > .menu__list-item-collapsible > .menu__link { background: linear-gradient(135deg, #ff6b6b, #ee5a24); color: white; border-radius: 8px; @@ -175,9 +175,9 @@ a.menu__link.menu__link--active div span:first-child { } /* Custom subcategory styling */ -.custom-sidebar-setup>.menu__list-item-collapsible>.menu__link, -.custom-sidebar-basics>.menu__list-item-collapsible>.menu__link, -.custom-sidebar-maintainer>.menu__list-item-collapsible>.menu__link { +.custom-sidebar-setup > .menu__list-item-collapsible > .menu__link, +.custom-sidebar-basics > .menu__list-item-collapsible > .menu__link, +.custom-sidebar-maintainer > .menu__list-item-collapsible > .menu__link { background: rgba(36, 41, 46, 0.1); border-left: 3px solid #24292e; padding-left: 16px; @@ -185,12 +185,12 @@ a.menu__link.menu__link--active div span:first-child { } /* Hover effects for all custom categories */ -.custom-sidebar-github>.menu__list-item-collapsible>.menu__link:hover, -.custom-sidebar-python>.menu__list-item-collapsible>.menu__link:hover, -.custom-sidebar-sql>.menu__list-item-collapsible>.menu__link:hover, -.custom-sidebar-nextjs>.menu__list-item-collapsible>.menu__link:hover, -.custom-sidebar-gsa>.menu__list-item-collapsible>.menu__link:hover, -.custom-sidebar-technical>.menu__list-item-collapsible>.menu__link:hover { +.custom-sidebar-github > .menu__list-item-collapsible > .menu__link:hover, +.custom-sidebar-python > .menu__list-item-collapsible > .menu__link:hover, +.custom-sidebar-sql > .menu__list-item-collapsible > .menu__link:hover, +.custom-sidebar-nextjs > .menu__list-item-collapsible > .menu__link:hover, +.custom-sidebar-gsa > .menu__list-item-collapsible > .menu__link:hover, +.custom-sidebar-technical > .menu__list-item-collapsible > .menu__link:hover { transform: translateX(4px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); transition: all 0.3s ease; @@ -269,7 +269,7 @@ html[data-theme="dark"] .menu__link--active::after { } /* ======== SECTION 7 : Adjust individual navbar items ==========*/ -.navbar__items>.navbar__item { +.navbar__items > .navbar__item { padding: 0.2rem 0.3rem !important; margin: 0 !important; } @@ -300,7 +300,6 @@ html[data-theme="dark"] .menu__link--active::after { /* Ensure dropdowns are visible on big screens */ @media (min-width: 1300px) { - .navbar__item.dropdown, .navbar__item:has(.dropdown-content) { position: relative !important; @@ -456,7 +455,6 @@ body { /* ===== SECTION 10: DESKTOP NAVBAR ENHANCEMENTS ===== */ @media (min-width: 1300px) { - /* Better spacing for desktop navbar */ .navbar__inner { max-width: 1400px; @@ -481,7 +479,10 @@ body { * This hides all navbar items on small screens, *except* for the * toggle, brand, and the item :has() the GitHub auth button. */ - .navbar__items .navbar__item:not(.navbar__toggle):not(.navbar__brand):not(:has(#firebase-auth-github-navbar)) { + .navbar__items + .navbar__item:not(.navbar__toggle):not(.navbar__brand):not( + :has(#firebase-auth-github-navbar) + ) { display: none !important; } @@ -686,8 +687,8 @@ body { } /* Prevent grid content from forcing overflow in the dropdown rows */ -.dropdown__menu .grid>.col-span-2, -.dropdown-content .grid>.col-span-2 { +.dropdown__menu .grid > .col-span-2, +.dropdown-content .grid > .col-span-2 { min-width: 0 !important; /* allow the icon column to shrink inside the 3-col grid */ } @@ -710,8 +711,8 @@ body { } /* Add breathing room between the left label and the vertical separator */ -.dropdown__menu .grid>.border-r.col-span-1, -.dropdown-content .grid>.border-r.col-span-1 { +.dropdown__menu .grid > .border-r.col-span-1, +.dropdown-content .grid > .border-r.col-span-1 { padding-right: 0.5rem !important; } @@ -872,7 +873,11 @@ html.theme-light .text-gray-900 { /* Ensure the specific block is forced light in light mode */ html[data-theme="light"] .interview-prep-page .technical-outer { - background-image: linear-gradient(135deg, #eff6ff 0%, #f8fafc 100%) !important; + background-image: linear-gradient( + 135deg, + #eff6ff 0%, + #f8fafc 100% + ) !important; background-color: #ffffff !important; -webkit-backdrop-filter: none !important; backdrop-filter: none !important; @@ -883,7 +888,11 @@ html[data-theme="light"] .interview-prep-page .technical-outer { /* Companies tab: use white gradients in light mode and remove overlays */ [data-theme="light"] .company-outer { - background-image: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%) !important; + background-image: linear-gradient( + 135deg, + #ffffff 0%, + #f8fafc 100% + ) !important; background-color: #ffffff !important; color: #0f172a !important; isolation: isolate !important; @@ -893,7 +902,7 @@ html[data-theme="light"] .interview-prep-page .technical-outer { } /* hide the subtle pattern overlay added inside the component */ -[data-theme="light"] .company-outer>.absolute.inset-0, +[data-theme="light"] .company-outer > .absolute.inset-0, [data-theme="light"] .company-outer .absolute.inset-0.opacity-5 { display: none !important; background: none !important; @@ -977,12 +986,14 @@ html { /* ===== FOOTER BACKGROUND PROTECTION ===== */ /* Ensure footer maintains its gradient background in dark mode */ [data-theme="dark"] .enhanced-footer { - background: linear-gradient(135deg, - #0f0f23 0%, - #1a1a2e 25%, - #16213e 50%, - #0f3460 75%, - #533483 100%) !important; + background: linear-gradient( + 135deg, + #0f0f23 0%, + #1a1a2e 25%, + #16213e 50%, + #0f3460 75%, + #533483 100% + ) !important; color: #e2e8f0 !important; } @@ -998,17 +1009,22 @@ html { /* ===== STEP 6: MAXIMUM SPECIFICITY PROTECTION ===== */ /* Override the exact problematic global rule with same specificity */ -[data-theme="dark"] body:not(:has(.community-page)) .enhanced-footer .container { +[data-theme="dark"] + body:not(:has(.community-page)) + .enhanced-footer + .container { background-color: transparent !important; } [data-theme="dark"] body:not(:has(.community-page)) .enhanced-footer { - background: linear-gradient(135deg, - #0f0f23 0%, - #1a1a2e 25%, - #16213e 50%, - #0f3460 75%, - #533483 100%) !important; + background: linear-gradient( + 135deg, + #0f0f23 0%, + #1a1a2e 25%, + #16213e 50%, + #0f3460 75%, + #533483 100% + ) !important; color: #e2e8f0 !important; } @@ -1030,14 +1046,15 @@ html { /* ===== REMOVE THEME TOGGLE FROM MOBILE SIDEBAR AS THERE IS ONE ON THE NAVBAR ===== */ @media (max-width: 1200px) { - /* Aggressively hide theme toggle in mobile sidebar */ - .navbar-sidebar__brand button:not(.navbar-sidebar__close):not([class*="close"]), + .navbar-sidebar__brand + button:not(.navbar-sidebar__close):not([class*="close"]), .navbar-sidebar__brand .colorModeToggle, .navbar-sidebar .colorModeToggle, .navbar-sidebar__brand button[class*="colorModeToggle"], .navbar-sidebar button[class*="colorModeToggle"], - .navbar-sidebar__brand .clean-btn[class*="toggle"]:not(.navbar-sidebar__close), + .navbar-sidebar__brand + .clean-btn[class*="toggle"]:not(.navbar-sidebar__close), .navbar-sidebar .clean-btn[class*="toggle"]:not(.navbar-sidebar__close), .navbar-sidebar__brand [class*="toggle_"]:not(.navbar-sidebar__close), .navbar-sidebar [class*="toggle_"]:not(.navbar-sidebar__close), @@ -1109,7 +1126,6 @@ html { /* Mobile-only visibility & spacing fixes for Tutorials icons (320–768px) */ @media screen and (max-width: 768px) { - /* Ensure the label + icons row inside Docs dropdown uses the full width */ .navbar-sidebar .grid, .navbar-sidebar .dropdown__menu .grid, @@ -1122,12 +1138,12 @@ html { } /* So the icon column doesn't get clipped in the 3-col layout */ - .navbar-sidebar .grid>.col-span-2 { + .navbar-sidebar .grid > .col-span-2 { min-width: 0 !important; } /* Tighten label space and drop the border on very small screens */ - .navbar-sidebar .grid>.border-r.col-span-1 { + .navbar-sidebar .grid > .border-r.col-span-1 { border-right: 0 !important; padding-right: 0.25rem !important; font-weight: 600; @@ -1172,7 +1188,7 @@ html { } /* Add vertical space between Tutorials, Courses, Interview Prep blocks */ - .navbar-sidebar .dropdown__menu>.grid { + .navbar-sidebar .dropdown__menu > .grid { padding: 1rem 0 !important; margin: 1rem 0 !important; } @@ -1498,8 +1514,8 @@ html { padding-right: var(--ifm-navbar-padding-horizontal) !important; } -.navbar>.container, -.navbar>.container-fluid { +.navbar > .container, +.navbar > .container-fluid { max-width: none !important; width: 100% !important; padding: 0 !important; @@ -1545,12 +1561,16 @@ main { right: 0; bottom: 0; background: - radial-gradient(circle at 20% 30%, + radial-gradient( + circle at 20% 30%, rgba(99, 102, 241, 0.08) 0%, - transparent 40%), - radial-gradient(circle at 80% 70%, + transparent 40% + ), + radial-gradient( + circle at 80% 70%, rgba(168, 85, 247, 0.06) 0%, - transparent 45%); + transparent 45% + ); pointer-events: none; } @@ -1602,74 +1622,74 @@ a { /* ================= MISCELLANEOUS ================= */ /* Fix Home icon alignment with text in breadcrumbs [Docs] */ -.theme-doc-breadcrumbs a.breadcrumbs__link>svg { +.theme-doc-breadcrumbs a.breadcrumbs__link > svg { display: inline-block; } /* Fix difficulty and topic pill backgrounds in light/dark mode */ -[data-theme='light'] .rounded.bg-gray-100, -[data-theme='light'] .rounded-full.bg-green-100, -[data-theme='light'] .rounded-full.bg-yellow-100, -[data-theme='light'] .rounded-full.bg-red-100, -[data-theme='light'] .rounded-full.bg-blue-100 { +[data-theme="light"] .rounded.bg-gray-100, +[data-theme="light"] .rounded-full.bg-green-100, +[data-theme="light"] .rounded-full.bg-yellow-100, +[data-theme="light"] .rounded-full.bg-red-100, +[data-theme="light"] .rounded-full.bg-blue-100 { background-color: var(--ifm-color-emphasis-100) !important; } -[data-theme='light'] .rounded-full.bg-green-100 { +[data-theme="light"] .rounded-full.bg-green-100 { background-color: #dcfce7 !important; /* green-100 */ } -[data-theme='light'] .rounded-full.bg-yellow-100 { +[data-theme="light"] .rounded-full.bg-yellow-100 { background-color: #fef9c3 !important; /* yellow-100 */ } -[data-theme='light'] .rounded-full.bg-red-100 { +[data-theme="light"] .rounded-full.bg-red-100 { background-color: #fee2e2 !important; /* red-100 */ } -[data-theme='light'] .rounded-full.bg-blue-100 { +[data-theme="light"] .rounded-full.bg-blue-100 { background-color: #dbeafe !important; /* blue-100 */ } -[data-theme='light'] .rounded.bg-gray-100 { +[data-theme="light"] .rounded.bg-gray-100 { background-color: #f3f4f6 !important; /* gray-100 */ } /* Dark mode overrides */ -[data-theme='dark'] .rounded.dark\:bg-gray-700, -[data-theme='dark'] .rounded-full.dark\:bg-green-900, -[data-theme='dark'] .rounded-full.dark\:bg-yellow-900, -[data-theme='dark'] .rounded-full.dark\:bg-red-900, -[data-theme='dark'] .rounded-full.dark\:bg-blue-900 { +[data-theme="dark"] .rounded.dark\:bg-gray-700, +[data-theme="dark"] .rounded-full.dark\:bg-green-900, +[data-theme="dark"] .rounded-full.dark\:bg-yellow-900, +[data-theme="dark"] .rounded-full.dark\:bg-red-900, +[data-theme="dark"] .rounded-full.dark\:bg-blue-900 { opacity: 1 !important; } -[data-theme='dark'] .rounded-full.dark\:bg-green-900 { +[data-theme="dark"] .rounded-full.dark\:bg-green-900 { background-color: #14532d !important; /* green-900 */ } -[data-theme='dark'] .rounded-full.dark\:bg-yellow-900 { +[data-theme="dark"] .rounded-full.dark\:bg-yellow-900 { background-color: #713f12 !important; /* yellow-900 */ } -[data-theme='dark'] .rounded-full.dark\:bg-red-900 { +[data-theme="dark"] .rounded-full.dark\:bg-red-900 { background-color: #7f1d1d !important; /* red-900 */ } -[data-theme='dark'] .rounded-full.dark\:bg-blue-900 { +[data-theme="dark"] .rounded-full.dark\:bg-blue-900 { background-color: #1e3a8a !important; /* blue-900 */ } -[data-theme='dark'] .rounded.dark\:bg-gray-700 { +[data-theme="dark"] .rounded.dark\:bg-gray-700 { background-color: #374151 !important; /* gray-700 */ } @@ -1683,21 +1703,21 @@ a { /* Light mode: explicit background + text for each variant */ [data-theme="light"] .interview-prep-page .difficulty-badge.bg-green-200 { - background-color: #DCFCE7 !important; + background-color: #dcfce7 !important; /* green-200 -> higher contrast */ - color: #14532D !important; + color: #14532d !important; } [data-theme="light"] .interview-prep-page .difficulty-badge.bg-yellow-200 { - background-color: #FEF3C7 !important; + background-color: #fef3c7 !important; /* yellow-200 */ - color: #78350F !important; + color: #78350f !important; } [data-theme="light"] .interview-prep-page .difficulty-badge.bg-red-200 { - background-color: #FEE2E2 !important; + background-color: #fee2e2 !important; /* red-200 */ - color: #7F1D1D !important; + color: #7f1d1d !important; } /* Keep all duration badges grey in light mode */ @@ -1717,7 +1737,11 @@ html[data-theme="light"] .bg-gradient-to-r.from-blue-50.to-purple-50 { /* Companies: force white/near-white surface in light mode for .company-outer */ html[data-theme="light"] .company-outer { - background-image: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%) !important; + background-image: linear-gradient( + 135deg, + #ffffff 0%, + #f8fafc 100% + ) !important; background-color: #ffffff !important; -webkit-backdrop-filter: none !important; backdrop-filter: none !important; @@ -1761,7 +1785,11 @@ html[data-theme="light"] a.company-tab-link { /* If any Tailwind gradient utility still applies, remove it for these containers in light mode */ html[data-theme="light"] .company-outer.bg-gradient-to-br, html[data-theme="light"] [data-slot="card-header"].bg-gradient-to-br { - background-image: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%) !important; + background-image: linear-gradient( + 135deg, + #ffffff 0%, + #f8fafc 100% + ) !important; background-color: #ffffff !important; -webkit-backdrop-filter: none !important; backdrop-filter: none !important; @@ -1782,14 +1810,12 @@ html[data-theme="light"] [data-slot="card-header"].bg-gradient-to-br { border: none !important; } - .avatar.margin-bottom--sm { width: auto !important; height: auto !important; border: none !important; } - .blog-page .margin-bottom--xl { margin-bottom: 0rem !important; } @@ -1798,7 +1824,7 @@ html[data-theme="light"] [data-slot="card-header"].bg-gradient-to-br { /* Issue #980: Fix inconsistent padding and margins across sections */ /* Standard section spacing: 2rem vertical, 1.5rem horizontal on smaller screens */ -main>div:not(.m-0) { +main > div:not(.m-0) { margin-top: 2rem; margin-bottom: 2rem; } @@ -1810,7 +1836,7 @@ main>div:not(.m-0) { /* Responsive: reduce spacing on mobile devices */ @media (max-width: 768px) { - main>div:not(.m-0) { + main > div:not(.m-0) { margin-top: 1.5rem; margin-bottom: 1.5rem; } @@ -1841,4 +1867,4 @@ h2:first-child, h3:first-child { margin-top: 0; margin-bottom: 1rem; -} \ No newline at end of file +} diff --git a/src/pages/badges/github-badges.module.css b/src/pages/badges/github-badges.module.css index 5b78c1ff..e83e4e96 100644 --- a/src/pages/badges/github-badges.module.css +++ b/src/pages/badges/github-badges.module.css @@ -1519,7 +1519,6 @@ table tr:last-child td:last-child { 0 1px 2px rgba(0, 0, 0, 0.04); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); cursor: pointer; - } .skinToneTable .levelImages img:hover { diff --git a/src/pages/badges/github-badges.tsx b/src/pages/badges/github-badges.tsx index 2aaad04c..b10d257f 100644 --- a/src/pages/badges/github-badges.tsx +++ b/src/pages/badges/github-badges.tsx @@ -254,7 +254,7 @@ const GithubBadgesContent = (): React.ReactElement => { src="https://github.githubassets.com/images/modules/profile/achievements/starstruck-default.png" alt="Starstruck" className={styles.badgeImgSmall} - whileHover={{ scale: 1.13}} + whileHover={{ scale: 1.13 }} transition={{ type: "spring", stiffness: 300 }} /> @@ -331,7 +331,7 @@ const GithubBadgesContent = (): React.ReactElement => { src="https://github.githubassets.com/images/modules/profile/achievements/quickdraw-default.png" alt="Quickdraw" className={styles.badgeImgSmall} - whileHover={{ scale: 1.13}} + whileHover={{ scale: 1.13 }} transition={{ type: "spring", stiffness: 300 }} /> @@ -344,16 +344,14 @@ const GithubBadgesContent = (): React.ReactElement => {
-
- Level: Default -
+
Level: Default
- Quickdraw Default + Quickdraw Default
Needed: 1
@@ -373,7 +371,7 @@ const GithubBadgesContent = (): React.ReactElement => { src="https://github.githubassets.com/images/modules/profile/achievements/pair-extraordinaire-default.png" alt="Pair Extraordinaire" className={styles.badgeImgSmall} - whileHover={{ scale: 1.13}} + whileHover={{ scale: 1.13 }} transition={{ type: "spring", stiffness: 300 }} /> @@ -408,33 +406,35 @@ const GithubBadgesContent = (): React.ReactElement => { Levels: Default, Bronze, Silver, Gold
- Pair Extraordinarie Default - Pair Extraordinarie Bronze - Pair Extraordinarie Silver - Pair Extraordinarie Gold + Pair Extraordinarie Default + Pair Extraordinarie Bronze + Pair Extraordinarie Silver + Pair Extraordinarie Gold +
+
+ Needed: 1, 10, 24, 48 +
-
Needed: 1, 10, 24, 48
- {/* Pull Shark */} @@ -451,7 +451,7 @@ const GithubBadgesContent = (): React.ReactElement => { src="https://github.githubassets.com/images/modules/profile/achievements/pull-shark-default.png" alt="Pull Shark" className={styles.badgeImgSmall} - whileHover={{ scale: 1.13}} + whileHover={{ scale: 1.13 }} transition={{ type: "spring", stiffness: 300 }} /> @@ -483,33 +483,35 @@ const GithubBadgesContent = (): React.ReactElement => { Levels: Default, Bronze, Silver, Gold
- Pull Shark Default - Pull Shark Bronze - Pull Shark Silver - Pull Shark Gold + Pull Shark Default + Pull Shark Bronze + Pull Shark Silver + Pull Shark Gold +
+
+ Needed: 2, 16, 128, 1024 +
-
Needed: 2, 16, 128, 1024
- {/* Galaxy Brain */} @@ -526,7 +528,7 @@ const GithubBadgesContent = (): React.ReactElement => { src="https://github.githubassets.com/images/modules/profile/achievements/galaxy-brain-default.png" alt="Galaxy Brain" className={styles.badgeImgSmall} - whileHover={{ scale: 1.13}} + whileHover={{ scale: 1.13 }} transition={{ type: "spring", stiffness: 300 }} /> @@ -558,33 +560,35 @@ const GithubBadgesContent = (): React.ReactElement => { Levels: Default, Bronze, Silver, Gold
- Galaxy Brain Default - Galaxy Brain Bronze - Galaxy Brain Silver - Galaxy Brain Gold + Galaxy Brain Default + Galaxy Brain Bronze + Galaxy Brain Silver + Galaxy Brain Gold +
+
+ Needed: 2, 8, 16, 32 +
-
Needed: 2, 8, 16, 32
- {/* YOLO */} diff --git a/src/pages/broadcasts/video.css b/src/pages/broadcasts/video.css index 382ded74..90979220 100644 --- a/src/pages/broadcasts/video.css +++ b/src/pages/broadcasts/video.css @@ -14,24 +14,32 @@ right: 0; bottom: 0; background: - radial-gradient(circle at 20% 30%, + radial-gradient( + circle at 20% 30%, rgba(99, 102, 241, 0.05) 0%, - transparent 40%), - radial-gradient(circle at 80% 70%, + transparent 40% + ), + radial-gradient( + circle at 80% 70%, rgba(168, 85, 247, 0.04) 0%, - transparent 45%); + transparent 45% + ); pointer-events: none; z-index: -1; } [data-theme="dark"] .video-container::before { background: - radial-gradient(circle at 20% 30%, + radial-gradient( + circle at 20% 30%, rgba(99, 102, 241, 0.08) 0%, - transparent 40%), - radial-gradient(circle at 80% 70%, + transparent 40% + ), + radial-gradient( + circle at 80% 70%, rgba(168, 85, 247, 0.06) 0%, - transparent 45%); + transparent 45% + ); } /* Header and title styling */ @@ -83,9 +91,11 @@ position: relative; font-weight: 700; text-align: center; - background: linear-gradient(135deg, - var(--ifm-color-primary) 0%, - var(--ifm-color-primary-light) 100%); + background: linear-gradient( + 135deg, + var(--ifm-color-primary) 0%, + var(--ifm-color-primary-light) 100% + ); background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; @@ -100,9 +110,11 @@ transform: translateX(-50%); width: 80px; height: 4px; - background: linear-gradient(135deg, - var(--ifm-color-primary) 0%, - var(--ifm-color-primary-light) 100%); + background: linear-gradient( + 135deg, + var(--ifm-color-primary) 0%, + var(--ifm-color-primary-light) 100% + ); border-radius: 2px; } @@ -138,10 +150,12 @@ left: 0; right: 0; bottom: 0; - background: linear-gradient(135deg, - rgba(99, 102, 241, 0.02) 0%, - rgba(168, 85, 247, 0.02) 50%, - rgba(59, 130, 246, 0.02) 100%); + background: linear-gradient( + 135deg, + rgba(99, 102, 241, 0.02) 0%, + rgba(168, 85, 247, 0.02) 50%, + rgba(59, 130, 246, 0.02) 100% + ); border-radius: 24px; z-index: -1; opacity: 0; @@ -161,10 +175,12 @@ } [data-theme="dark"] .video-card::before { - background: linear-gradient(135deg, - rgba(99, 102, 241, 0.08) 0%, - rgba(168, 85, 247, 0.06) 50%, - rgba(59, 130, 246, 0.08) 100%); + background: linear-gradient( + 135deg, + rgba(99, 102, 241, 0.08) 0%, + rgba(168, 85, 247, 0.06) 50%, + rgba(59, 130, 246, 0.08) 100% + ); } .video-card:hover { @@ -205,24 +221,30 @@ left: 0; right: 0; bottom: 0; - background: linear-gradient(135deg, - rgba(99, 102, 241, 0.03) 0%, - rgba(168, 85, 247, 0.02) 100%); + background: linear-gradient( + 135deg, + rgba(99, 102, 241, 0.03) 0%, + rgba(168, 85, 247, 0.02) 100% + ); border-radius: 20px; z-index: -1; } [data-theme="dark"] .video-info { - background: linear-gradient(145deg, - var(--dark-bg-secondary) 0%, - #0f1419 100%); + background: linear-gradient( + 145deg, + var(--dark-bg-secondary) 0%, + #0f1419 100% + ); border-color: var(--dark-border); } [data-theme="dark"] .video-info::before { - background: linear-gradient(135deg, - rgba(99, 102, 241, 0.06) 0%, - rgba(168, 85, 247, 0.04) 100%); + background: linear-gradient( + 135deg, + rgba(99, 102, 241, 0.06) 0%, + rgba(168, 85, 247, 0.04) 100% + ); } .video-title { @@ -382,7 +404,6 @@ } @keyframes pulse { - 0%, 100% { opacity: 0.7; @@ -429,9 +450,11 @@ gap: 1.5rem; margin-bottom: 3rem; padding: 0.5rem; - background: linear-gradient(145deg, - rgba(255, 255, 255, 0.8) 0%, - rgba(248, 250, 252, 0.8) 100%); + background: linear-gradient( + 145deg, + rgba(255, 255, 255, 0.8) 0%, + rgba(248, 250, 252, 0.8) 100% + ); border-radius: 20px; backdrop-filter: blur(10px); border: 1px solid rgba(226, 232, 240, 0.6); @@ -443,9 +466,11 @@ } [data-theme="dark"] .video-tabs { - background: linear-gradient(145deg, - rgba(17, 24, 39, 0.8) 0%, - rgba(15, 23, 42, 0.8) 100%); + background: linear-gradient( + 145deg, + rgba(17, 24, 39, 0.8) 0%, + rgba(15, 23, 42, 0.8) 100% + ); border-color: var(--dark-border); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); } @@ -472,9 +497,11 @@ left: 0; right: 0; bottom: 0; - background: linear-gradient(135deg, - rgba(99, 102, 241, 0.1) 0%, - rgba(168, 85, 247, 0.1) 100%); + background: linear-gradient( + 135deg, + rgba(99, 102, 241, 0.1) 0%, + rgba(168, 85, 247, 0.1) 100% + ); opacity: 0; transition: opacity 0.3s ease; border-radius: 16px; @@ -498,9 +525,11 @@ } .tab-button.active { - background: linear-gradient(135deg, - var(--ifm-color-primary) 0%, - var(--ifm-color-primary-light) 100%); + background: linear-gradient( + 135deg, + var(--ifm-color-primary) 0%, + var(--ifm-color-primary-light) 100% + ); color: white; transform: translateY(-2px); box-shadow: @@ -600,9 +629,11 @@ left: 0; right: 0; bottom: 0; - background: linear-gradient(135deg, - rgba(99, 102, 241, 0.1) 0%, - rgba(168, 85, 247, 0.1) 100%); + background: linear-gradient( + 135deg, + rgba(99, 102, 241, 0.1) 0%, + rgba(168, 85, 247, 0.1) 100% + ); opacity: 0; transition: opacity 0.3s ease; } @@ -635,9 +666,11 @@ font-weight: 600; color: var(--ifm-color-emphasis-700); padding: 0.75rem 1rem; - background: linear-gradient(145deg, - rgba(99, 102, 241, 0.1) 0%, - rgba(168, 85, 247, 0.1) 100%); + background: linear-gradient( + 145deg, + rgba(99, 102, 241, 0.1) 0%, + rgba(168, 85, 247, 0.1) 100% + ); border-radius: 12px; border: 1px solid rgba(99, 102, 241, 0.2); min-width: 120px; @@ -645,9 +678,11 @@ } [data-theme="dark"] .pagination button { - background: linear-gradient(145deg, - var(--dark-bg-secondary) 0%, - #0f172a 100%); + background: linear-gradient( + 145deg, + var(--dark-bg-secondary) 0%, + #0f172a 100% + ); color: var(--dark-text-primary); border-color: var(--dark-border); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); @@ -667,8 +702,10 @@ [data-theme="dark"] .pagination span { color: var(--dark-text-primary); - background: linear-gradient(145deg, - rgba(59, 130, 246, 0.1) 0%, - rgba(168, 85, 247, 0.1) 100%); + background: linear-gradient( + 145deg, + rgba(59, 130, 246, 0.1) 0%, + rgba(168, 85, 247, 0.1) 100% + ); border-color: rgba(59, 130, 246, 0.3); -} \ No newline at end of file +} diff --git a/src/pages/code-of-conduct/index.css b/src/pages/code-of-conduct/index.css index b3064658..5dc8afc7 100644 --- a/src/pages/code-of-conduct/index.css +++ b/src/pages/code-of-conduct/index.css @@ -412,4 +412,4 @@ html[data-theme="light"] { .coc-content-card { padding: 1.5rem 1rem; } -} \ No newline at end of file +} diff --git a/src/pages/community/index.tsx b/src/pages/community/index.tsx index b082b0a4..14ed37f4 100644 --- a/src/pages/community/index.tsx +++ b/src/pages/community/index.tsx @@ -273,14 +273,15 @@ export default function CommunityPage(): React.ReactElement { div:last-child { +.dashboard-mobile-menu > div:last-child { position: absolute; top: 0; left: 0; @@ -76,7 +76,7 @@ transition: transform 0.3s ease; } -.dashboard-mobile-menu.show>div:last-child { +.dashboard-mobile-menu.show > div:last-child { transform: translateX(0); } @@ -295,9 +295,11 @@ left: 0; right: 0; height: 4px; - background: linear-gradient(90deg, - var(--ifm-color-primary), - var(--ifm-color-primary-light)); + background: linear-gradient( + 90deg, + var(--ifm-color-primary), + var(--ifm-color-primary-light) + ); } .dashboard-stat-card:hover { @@ -713,4 +715,4 @@ [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 3eafe977..bf06f244 100644 --- a/src/pages/dashboard/index.tsx +++ b/src/pages/dashboard/index.tsx @@ -559,22 +559,25 @@ const DashboardContent: React.FC = () => {
diff --git a/src/pages/ebooks/index.tsx b/src/pages/ebooks/index.tsx index 16ce2ec7..e44be744 100644 --- a/src/pages/ebooks/index.tsx +++ b/src/pages/ebooks/index.tsx @@ -18,7 +18,11 @@ interface EbookData { const getCategory = (title: string): string => { if (title.toLowerCase().includes("python")) return "Programming"; if (title.toLowerCase().includes("java")) return "Programming"; - if (title.toLowerCase().includes("c++") || title.toLowerCase().includes("cpp")) return "Programming"; + if ( + title.toLowerCase().includes("c++") || + title.toLowerCase().includes("cpp") + ) + return "Programming"; if (title.toLowerCase().includes("c ")) return "Programming"; return "Programming"; }; @@ -163,7 +167,7 @@ export default function Ebooks(): ReactElement {

Explore Ebooks

- Read high-quality ebooks on programming, tools, and development. + Read high-quality ebooks on programming, tools, and development. Dive into comprehensive guides that inspire, educate, and help you master new skills.

@@ -210,7 +214,8 @@ export default function Ebooks(): ReactElement { onClick={() => setSelectedFilter(category as any)} > 📚 - {category} ({ebooks.filter((e) => e.category === category).length}) + {category} ( + {ebooks.filter((e) => e.category === category).length}) ))} @@ -219,7 +224,7 @@ export default function Ebooks(): ReactElement {
{currentEbooks.length > 0 ? ( <> -
+
{currentEbooks.map((ebook, index) => (
- +
{ diff --git a/src/pages/index.module.css b/src/pages/index.module.css index a7253402..2b7f7664 100644 --- a/src/pages/index.module.css +++ b/src/pages/index.module.css @@ -21,4 +21,4 @@ display: flex; align-items: center; justify-content: center; -} \ No newline at end of file +} diff --git a/src/pages/interview-prep/CompaniesTab.tsx b/src/pages/interview-prep/CompaniesTab.tsx index 26f5e412..a0823d23 100644 --- a/src/pages/interview-prep/CompaniesTab.tsx +++ b/src/pages/interview-prep/CompaniesTab.tsx @@ -273,7 +273,7 @@ const CompaniesTab: React.FC = ({ companyTips = [] }) => { >
- + = ({ companyTips = [] }) => { alt={`${company.company} logo`} className="h-20 w-20 rounded-2xl border border-gray-100 bg-white object-contain p-3 shadow-lg" /> -
+
@@ -362,7 +362,7 @@ const CompaniesTab: React.FC = ({ companyTips = [] }) => {
-

+

Focus: {company.focus}

@@ -503,7 +503,7 @@ const CompaniesTab: React.FC = ({ companyTips = [] }) => { whileTap={{ scale: 0.98 }} >
-

+

"{item.question}"

= ({ companyTips = [] }) => { transition={{ duration: 0.5, delay: 0.3 }} >
-
+
🚀
@@ -631,7 +631,7 @@ const CompaniesTab: React.FC = ({ companyTips = [] }) => { className="relative overflow-hidden rounded-3xl border-2 border-indigo-200 bg-gradient-to-br from-indigo-50 via-purple-50 to-pink-50 p-12 dark:border-indigo-800 dark:from-indigo-900/20 dark:via-purple-900/20 dark:to-pink-900/20" variants={fadeIn} > -
🤝
+
🤝
💡
@@ -717,10 +717,7 @@ const CompaniesTab: React.FC = ({ companyTips = [] }) => {
- +