From 5f7a8a6f776786d9748837fdd01e03fd0088ebd3 Mon Sep 17 00:00:00 2001 From: jlightner Date: Tue, 31 Mar 2026 05:37:10 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20Added=20popular=20topics=20pill-link=20?= =?UTF-8?q?section=20to=20homepage=20that=20fetches=20f=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - "frontend/src/pages/Home.tsx" - "frontend/src/App.css" GSD-Task: S01/T02 --- frontend/src/App.css | 44 +++++++++++++++++++++++++++++++++++++ frontend/src/pages/Home.tsx | 39 ++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/frontend/src/App.css b/frontend/src/App.css index 21a64d2..4816e47 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -953,6 +953,50 @@ a.app-footer__repo:hover { transform: translateY(-1px); } +/* ── Popular topics quick-links ───────────────────────────────────────────── */ + +.home-popular-topics { + margin-top: 2.5rem; + text-align: center; +} + +.home-popular-topics__title { + font-size: 0.875rem; + font-weight: 600; + color: var(--color-text-secondary); + text-transform: uppercase; + letter-spacing: 0.05em; + margin-bottom: 0.75rem; +} + +.home-popular-topics__list { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 0.5rem; + max-width: 36rem; + margin: 0 auto; +} + +.pill--topic-quick { + display: inline-block; + padding: 0.375rem 0.875rem; + border-radius: 9999px; + font-size: 0.8125rem; + font-weight: 500; + background: var(--color-pill-bg); + color: var(--color-pill-text); + border: 1px solid var(--color-border); + text-decoration: none; + transition: border-color 0.15s, background 0.15s, color 0.15s; +} + +.pill--topic-quick:hover { + border-color: var(--color-accent); + background: var(--color-accent-subtle); + color: var(--color-accent); +} + /* ── Search form ──────────────────────────────────────────────────────────── */ .search-container { diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx index 0e85bba..1fc6ad5 100644 --- a/frontend/src/pages/Home.tsx +++ b/frontend/src/pages/Home.tsx @@ -11,6 +11,7 @@ import { Link, useNavigate } from "react-router-dom"; import { searchApi, fetchTechniques, + fetchTopics, type SearchResultItem, type TechniqueListItem, } from "../api/public-client"; @@ -21,6 +22,7 @@ export default function Home() { const [showDropdown, setShowDropdown] = useState(false); const [recent, setRecent] = useState([]); const [recentLoading, setRecentLoading] = useState(true); + const [popularTopics, setPopularTopics] = useState<{name: string; count: number}[]>([]); const navigate = useNavigate(); const inputRef = useRef(null); const debounceRef = useRef | null>(null); @@ -49,6 +51,26 @@ export default function Home() { }; }, []); + // Load popular topics + useEffect(() => { + let cancelled = false; + void (async () => { + try { + const categories = await fetchTopics(); + const all = categories.flatMap((cat) => + cat.sub_topics.map((st) => ({ name: st.name, count: st.technique_count })) + ); + all.sort((a, b) => b.count - a.count); + if (!cancelled) setPopularTopics(all.slice(0, 8)); + } catch { + // optional section — silently ignore + } + })(); + return () => { + cancelled = true; + }; + }, []); + // Close dropdown on outside click useEffect(() => { function handleClick(e: MouseEvent) { @@ -198,6 +220,23 @@ export default function Home() { Start Exploring + + {popularTopics.length > 0 && ( +
+

Popular Topics

+
+ {popularTopics.map((topic) => ( + + {topic.name} + + ))} +
+
+ )} {/* Navigation cards */}