diff --git a/frontend/app/[topic]/TopicLayout.tsx b/frontend/app/[topic]/TopicLayout.tsx index f02ae13..d44d173 100644 --- a/frontend/app/[topic]/TopicLayout.tsx +++ b/frontend/app/[topic]/TopicLayout.tsx @@ -10,6 +10,7 @@ import { useEffect, useMemo, useState, useRef, useCallback } from "react"; import { useTheme } from "../../src/context/ThemeContext"; +import { useGitHubStats } from "../../src/hooks/useGitHubStats"; import { useRouter } from "next/navigation"; import { FaGithub, FaLinkedin } from "react-icons/fa"; import toast, { Toaster } from "react-hot-toast"; @@ -55,7 +56,8 @@ export default function TopicLayout({ prevTopic?: { id: string; title?: string } | null; nextTopic?: { id: string; title?: string } | null; }) { - const { darkMode, toggleTheme } = useTheme(); + // Removed `darkMode` - we only need toggleTheme for the button! + const { toggleTheme } = useTheme(); const router = useRouter(); const [domHeadings, setDomHeadings] = useState>([]); @@ -68,17 +70,7 @@ export default function TopicLayout({ const [expandedOutline, setExpandedOutline] = useState>({}); const [activeOutlineId, setActiveOutlineId] = useState(null); - - const [githubStats, setGithubStats] = useState({ - stars: "-", - openIssues: "-", - openPrs: "-", - mergedPrs: "-", - lastPush: "", - contributors: [] as any[], - loading: true - }); - + const githubStats = useGitHubStats(); const progressBarRef = useRef(null); const scrollTopBtnRef = useRef(null); @@ -110,40 +102,6 @@ export default function TopicLayout({ }; }, [isMobileMenuOpen, cmdOpen]); - useEffect(() => { - const fetchGitHubStats = async () => { - try { - const [repoRes, openPrsRes, mergedPrsRes, issuesRes, contributorsRes] = await Promise.all([ - fetch('https://api.github.com/repos/yash-pluto/refme').catch(() => null), - fetch('https://api.github.com/search/issues?q=repo:yash-pluto/refme+is:pr+is:open').catch(() => null), - fetch('https://api.github.com/search/issues?q=repo:yash-pluto/refme+is:pr+is:merged').catch(() => null), - fetch('https://api.github.com/search/issues?q=repo:yash-pluto/refme+is:issue+is:open').catch(() => null), - fetch('https://api.github.com/repos/yash-pluto/refme/contributors').catch(() => null) - ]); - - const repoData = repoRes && repoRes.ok ? await repoRes.json() : {}; - const openPrsData = openPrsRes && openPrsRes.ok ? await openPrsRes.json() : {}; - const mergedPrsData = mergedPrsRes && mergedPrsRes.ok ? await mergedPrsRes.json() : {}; - const issuesData = issuesRes && issuesRes.ok ? await issuesRes.json() : {}; - const contributorsData = contributorsRes && contributorsRes.ok ? await contributorsRes.json() : []; - - setGithubStats({ - stars: repoData.stargazers_count !== undefined ? repoData.stargazers_count.toString() : "-", - openIssues: issuesData.total_count !== undefined ? issuesData.total_count.toString() : "-", - openPrs: openPrsData.total_count !== undefined ? openPrsData.total_count.toString() : "-", - mergedPrs: mergedPrsData.total_count !== undefined ? mergedPrsData.total_count.toString() : "-", - lastPush: repoData.pushed_at || repoData.updated_at || "", - contributors: Array.isArray(contributorsData) ? contributorsData : [], - loading: false - }); - } catch (error) { - setGithubStats(prev => ({ ...prev, loading: false })); - } - }; - - fetchGitHubStats(); - }, []); - useEffect(() => { const article = document.querySelector("article"); const headingNodes = article ? Array.from(article.querySelectorAll("h2[id], h3[id]")) : []; @@ -257,15 +215,16 @@ export default function TopicLayout({ }); }, [outlineGroups]); + // REFACTORED: Converted all JS logic to pure Tailwind `dark:` classes const themeClasses = { - page: darkMode ? "bg-[#050505] text-[#F5F5F5]" : "bg-[#FFFFFF] text-[#111111]", - sidebar: darkMode ? "bg-[#101010]" : "bg-[#F7F7F7]", - header: darkMode ? "bg-[#050505]/90" : "bg-[#FFFFFF]/90", - border: darkMode ? "border-[#222222]" : "border-[#E5E5E5]", - muted: darkMode ? "text-zinc-400" : "text-zinc-500", - hoverAccent: darkMode ? "hover:text-[#C699FF]" : "hover:text-[#6f45d6]", - activeNavBg: darkMode ? "bg-[#C699FF]/15 text-[#C699FF]" : "bg-[#6f45d6]/10 text-[#6f45d6]", - inputBg: darkMode ? "bg-[#101010]" : "bg-[#F4F4F4]", + page: "bg-[#FFFFFF] text-[#111111] dark:bg-[#050505] dark:text-[#F5F5F5]", + sidebar: "bg-[#F7F7F7] dark:bg-[#101010]", + header: "bg-[#FFFFFF]/90 dark:bg-[#050505]/90", + border: "border-[#E5E5E5] dark:border-[#222222]", + muted: "text-zinc-500 dark:text-zinc-400", + hoverAccent: "hover:text-[#6f45d6] dark:hover:text-[#C699FF]", + activeNavBg: "bg-[#6f45d6]/10 text-[#6f45d6] dark:bg-[#C699FF]/15 dark:text-[#C699FF]", + inputBg: "bg-[#F4F4F4] dark:bg-[#101010]", }; const getTopicIcon = (topicId: string) => { @@ -330,10 +289,23 @@ export default function TopicLayout({
- - - setCmdOpen(false)} searchData={searchData} onSelect={handleSearchSelect} placeholder="Search documentation or type a command..." /> - + {/* REFACTORED: Used !important classes to override react-hot-toast defaults via Tailwind instead of JS styles */} + + + setCmdOpen(false)} + onToggle={() => setCmdOpen((prev) => !prev)} + searchData={searchData} + onSelect={handleSearchSelect} + placeholder="Search documentation or type a command..." + /> + {isMobileMenuOpen &&
setIsMobileMenuOpen(false)} />}
@@ -386,8 +358,10 @@ export default function TopicLayout({
-
@@ -439,7 +413,7 @@ export default function TopicLayout({ @@ -449,7 +423,7 @@ export default function TopicLayout({ @@ -461,7 +435,7 @@ export default function TopicLayout({ @@ -482,13 +456,13 @@ export default function TopicLayout({
{outlineGroups.map((group) => (
- { e.preventDefault(); scrollToSection(group.id); setIsMobileTocOpen(false); }} className={`block text-[14px] font-medium ${activeOutlineId === group.id ? (darkMode ? "text-[#C699FF]" : "text-[#6f45d6]") : themeClasses.muted}`}> + { e.preventDefault(); scrollToSection(group.id); setIsMobileTocOpen(false); }} className={`block text-[14px] font-medium ${activeOutlineId === group.id ? "text-[#6f45d6] dark:text-[#C699FF]" : themeClasses.muted}`}> {group.title} {group.items.length > 0 && (
{group.items.map((item) => ( - { e.preventDefault(); scrollToSection(item.id); setIsMobileTocOpen(false); }} className={`block text-[13px] font-medium ${activeOutlineId === item.id ? (darkMode ? "text-[#C699FF]" : "text-[#6f45d6]") : themeClasses.muted}`}> + { e.preventDefault(); scrollToSection(item.id); setIsMobileTocOpen(false); }} className={`block text-[13px] font-medium ${activeOutlineId === item.id ? "text-[#6f45d6] dark:text-[#C699FF]" : themeClasses.muted}`}> {item.title} ))} @@ -508,10 +482,8 @@ export default function TopicLayout({ {children} - {/* Combined Bottom Section */}
- {/* Center Aligned Feedback Section */}
Was this page helpful? @@ -537,19 +509,19 @@ export default function TopicLayout({
- {/* Updated Dynamic GitHub Widget */} -
-
+ {/* REFACTORED: Completely eliminated JS conditional rendering for the GitHub widget */} +
+
Yash Vardhan
- + Yash-Pluto @@ -558,58 +530,58 @@ export default function TopicLayout({
- +
-

+

Join the community building the ultimate quick-reference. Contributions are welcome for all categories and languages.

-
+
✓ - Open Source Architecture + Open Source Architecture
-
+
✓ - Community Driven Updates + Community Driven Updates
-
+
Open PRs
- {githubStats.openPrs} + {githubStats.openPrs}
-
+
Merged
- {githubStats.mergedPrs} + {githubStats.mergedPrs}
-
+
Issues
- {githubStats.openIssues} + {githubStats.openIssues}
-
+
Stars
- {githubStats.stars} + {githubStats.stars}
@@ -624,7 +596,7 @@ export default function TopicLayout({ src={user.avatar_url} alt={user.login} title={user.login} - className={`h-10 w-10 rounded-full border-[3px] ${darkMode ? 'border-[#0a0a0a]' : 'border-white'} shadow-md`} + className={`h-10 w-10 rounded-full border-[3px] border-white dark:border-[#0a0a0a] shadow-md`} style={{ zIndex: 10 - idx, opacity: 1 - (idx * 0.12) }} /> ))} @@ -641,7 +613,7 @@ export default function TopicLayout({ href={`https://github.com/yash-pluto/refme/edit/main/frontend/content/${topicKey}.mdx`} target="_blank" rel="noopener noreferrer" - className={`flex flex-1 sm:flex-none justify-center items-center gap-2 rounded-xl px-4 py-3 text-[13px] font-bold border transition-colors ${darkMode ? "border-[#333] hover:bg-white/5 text-zinc-300" : "border-[#E5E5E5] hover:bg-black/5 text-zinc-700"}`} + className={`flex flex-1 sm:flex-none justify-center items-center gap-2 rounded-xl px-4 py-3 text-[13px] font-bold border transition-colors border-[#E5E5E5] hover:bg-black/5 text-zinc-700 dark:border-[#333] dark:hover:bg-white/5 dark:text-zinc-300`} > Edit Page @@ -649,7 +621,7 @@ export default function TopicLayout({ href="https://github.com/yash-pluto/refme" target="_blank" rel="noopener noreferrer" - className={`flex flex-1 sm:flex-none justify-center items-center gap-2 rounded-xl px-5 py-3 text-[13px] font-bold transition-all active:scale-[0.98] ${darkMode ? "bg-white text-black hover:bg-zinc-200" : "bg-black text-white hover:bg-zinc-800"}`} + className={`flex flex-1 sm:flex-none justify-center items-center gap-2 rounded-xl px-5 py-3 text-[13px] font-bold transition-all active:scale-[0.98] bg-black text-white hover:bg-zinc-800 dark:bg-white dark:text-black dark:hover:bg-zinc-200`} > Contribute @@ -693,13 +665,13 @@ export default function TopicLayout({ const isActiveGroup = activeOutlineId === group.id; return (
- { e.preventDefault(); scrollToSection(group.id); }} className={`block text-[13px] tracking-tight font-semibold leading-snug transition-colors mb-2 ${isActiveGroup ? (darkMode ? "text-[#C699FF] drop-shadow-[0_0_8px_rgba(198,153,255,0.4)]" : "text-[#6f45d6] drop-shadow-[0_0_8px_rgba(111,69,214,0.4)]") : `${themeClasses.muted} hover:text-current`}`}> + { e.preventDefault(); scrollToSection(group.id); }} className={`block text-[13px] tracking-tight font-semibold leading-snug transition-colors mb-2 ${isActiveGroup ? "text-[#6f45d6] drop-shadow-[0_0_8px_rgba(111,69,214,0.4)] dark:text-[#C699FF] dark:drop-shadow-[0_0_8px_rgba(198,153,255,0.4)]" : `${themeClasses.muted} hover:text-current`}`}> {group.title} {group.items.length > 0 && (
{group.items.map((item) => ( - { e.preventDefault(); scrollToSection(item.id); }} className={`block text-[12px] font-medium leading-snug transition-colors ${activeOutlineId === item.id ? (darkMode ? "text-[#C699FF] drop-shadow-[0_0_8px_rgba(198,153,255,0.4)]" : "text-[#6f45d6] drop-shadow-[0_0_8px_rgba(111,69,214,0.4)]") : `${themeClasses.muted} hover:text-current`}`}> + { e.preventDefault(); scrollToSection(item.id); }} className={`block text-[12px] font-medium leading-snug transition-colors ${activeOutlineId === item.id ? "text-[#6f45d6] drop-shadow-[0_0_8px_rgba(111,69,214,0.4)] dark:text-[#C699FF] dark:drop-shadow-[0_0_8px_rgba(198,153,255,0.4)]" : `${themeClasses.muted} hover:text-current`}`}> {item.title} ))} @@ -719,7 +691,7 @@ export default function TopicLayout({
-
- { - const isHighlighted = highlightLines.includes(lineNumber); - return { - style: { - display: "block", - minWidth: "fit-content", // Ensures highlights stretch across scrollable container - backgroundColor: isHighlighted - ? (darkMode ? "rgba(198, 153, 255, 0.1)" : "rgba(111, 69, 214, 0.1)") - : "transparent", - borderLeft: isHighlighted - ? (darkMode ? "3px solid #C699FF" : "3px solid #6f45d6") - : "3px solid transparent", - paddingLeft: "13px", - paddingRight: "16px", - } - }; - }} - customStyle={{ - background: "transparent", - padding: 0, - margin: 0, - fontSize: "0.9rem", - lineHeight: "1.7", - overflowX: "auto", - }} - > - {code} - +
+ {/* Render a height-preserving invisible block before hydration, then swap to real highlighter */} + {!mounted ? ( + + ) : ( + { + const isHighlighted = highlightLines.includes(lineNumber); + return { + style: { + display: "block", + minWidth: "fit-content", + backgroundColor: isHighlighted + ? (darkMode ? "rgba(198, 153, 255, 0.1)" : "rgba(111, 69, 214, 0.1)") + : "transparent", + borderLeft: isHighlighted + ? (darkMode ? "3px solid #C699FF" : "3px solid #6f45d6") + : "3px solid transparent", + paddingLeft: "13px", + paddingRight: "16px", + } + }; + }} + customStyle={{ + background: "transparent", + padding: 0, + margin: 0, + fontSize: "0.9rem", + lineHeight: "1.7", + overflowX: "auto", + }} + > + {code} + + )}
); diff --git a/frontend/app/components/DirectoryList.tsx b/frontend/app/components/DirectoryList.tsx deleted file mode 100644 index 2b67965..0000000 --- a/frontend/app/components/DirectoryList.tsx +++ /dev/null @@ -1,90 +0,0 @@ -// app/components/DirectoryList.tsx -"use client"; - -import Link from "next/link"; -import { cloneElement } from "react"; -import { REFERENCE_DATA } from "../page"; -import { ArrowRight } from "lucide-react"; - -interface DirectoryListProps { - darkMode: boolean; - searchQuery: string; -} - -export default function DirectoryList({ - darkMode, - searchQuery, -}: DirectoryListProps) { - const filteredData = REFERENCE_DATA.map((section) => ({ - ...section, - items: section.items.filter((item) => - item.name.toLowerCase().includes(searchQuery.toLowerCase()), - ), - })).filter((section) => section.items.length > 0); - - if (filteredData.length === 0) { - return ( -
- No matching entries found. -
- ); - } - - return ( -
- {filteredData.map((section) => ( -
-
-
- {cloneElement(section.icon, { - className: "block", - style: { color: darkMode ? "#f4f4f5" : "#111111" }, - })} -
-

- {section.category} -

-
- -
- {section.items.map((item) => { - const iconNode = cloneElement(item.icon, { - className: "block", - style: { - color: darkMode ? "#f4f4f5" : "#111111", - opacity: 1, - }, - }); - - return ( - -
-
- {iconNode} -
- -
- Open - -
-
- -
-

{item.name}

-

- {item.desc} -

-
- - ); - })} -
-
- ))} -
- ); -} diff --git a/frontend/app/components/Footer.tsx b/frontend/app/components/Footer.tsx index 98830eb..bcf6a26 100644 --- a/frontend/app/components/Footer.tsx +++ b/frontend/app/components/Footer.tsx @@ -1,40 +1,23 @@ -// Footer.tsx "use client"; import Link from "next/link"; -import { useTheme } from "../../src/context/ThemeContext"; import { FaGithub, FaLinkedin, FaYoutube, FaTwitter } from "react-icons/fa"; export default function Footer() { - const { darkMode } = useTheme(); - - const themeClasses = { - bg: darkMode ? "bg-[#050505]" : "bg-zinc-50", - border: darkMode ? "border-[#333]" : "border-[#E5E5E5]", - text: darkMode ? "text-zinc-400" : "text-zinc-500", - hover: darkMode ? "hover:text-white" : "hover:text-black", - heading: darkMode ? "text-white" : "text-black", - iconBtn: darkMode ? "border-[#333] hover:bg-[#1a1a1a]" : "border-[#E5E5E5] hover:bg-zinc-200", - }; - - const watermarkStroke = darkMode - ? "rgba(255, 255, 255, 0.82)" - : "rgba(0, 0, 0, 0.72)"; - return ( -