feat: Extracted catSlug to shared utility; added category accent border…

- "frontend/src/utils/catSlug.ts"
- "frontend/src/pages/TopicsBrowse.tsx"
- "frontend/src/pages/SubTopicPage.tsx"
- "frontend/src/pages/SearchResults.tsx"
- "frontend/src/App.css"

GSD-Task: S03/T01
This commit is contained in:
jlightner 2026-03-31 06:26:06 +00:00
parent c481bafc7b
commit cf0205bd5c
6 changed files with 26 additions and 9 deletions

View file

@ -2334,6 +2334,8 @@ a.app-footer__repo:hover {
max-width: 56rem;
margin: 0 auto;
padding: 1rem 0;
border-left: 4px solid transparent;
padding-left: 1.25rem;
}
.subtopic-page__title {
@ -2347,6 +2349,13 @@ a.app-footer__repo:hover {
font-size: 0.95rem;
color: var(--color-text-secondary);
margin: 0 0 2rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.subtopic-page__subtitle-sep {
color: var(--color-text-muted);
}
.subtopic-groups {

View file

@ -9,6 +9,7 @@
import { useCallback, useEffect, useRef, useState } from "react";
import { Link, useSearchParams, useNavigate } from "react-router-dom";
import { searchApi, type SearchResultItem } from "../api/public-client";
import { catSlug } from "../utils/catSlug";
export default function SearchResults() {
const [searchParams] = useSearchParams();
@ -167,7 +168,7 @@ function SearchResultCard({ item }: { item: SearchResultItem }) {
{item.topic_category && (
<>
<span className="queue-card__separator">·</span>
<span>{item.topic_category}</span>
<span className={`badge badge--cat-${catSlug(item.topic_category)}`}>{item.topic_category}</span>
</>
)}
{item.topic_tags.length > 0 && (

View file

@ -11,6 +11,7 @@ import {
fetchSubTopicTechniques,
type TechniqueListItem,
} from "../api/public-client";
import { catSlug } from "../utils/catSlug";
/** Convert a URL slug to a display name: replace hyphens with spaces, title-case. */
function slugToDisplayName(slug: string): string {
@ -91,9 +92,13 @@ export default function SubTopicPage() {
}
const groups = groupByCreator(techniques);
const slug = category ? catSlug(categoryDisplay) : "";
return (
<div className="subtopic-page">
<div
className="subtopic-page"
style={slug ? { borderLeftColor: `var(--color-badge-cat-${slug}-text)` } : undefined}
>
{/* Breadcrumbs */}
<nav className="breadcrumbs" aria-label="Breadcrumb">
<Link to="/topics" className="breadcrumbs__link">Topics</Link>
@ -105,7 +110,9 @@ export default function SubTopicPage() {
<h2 className="subtopic-page__title">{subtopicDisplay}</h2>
<p className="subtopic-page__subtitle">
{techniques.length} technique{techniques.length !== 1 ? "s" : ""} in {categoryDisplay}
<span className={`badge badge--cat-${slug}`}>{categoryDisplay}</span>
<span className="subtopic-page__subtitle-sep">·</span>
{techniques.length} technique{techniques.length !== 1 ? "s" : ""}
</p>
{techniques.length === 0 ? (

View file

@ -13,11 +13,7 @@ import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { fetchTopics, type TopicCategory } from "../api/public-client";
import { CATEGORY_ICON } from "../components/CategoryIcons";
/** Derive the badge CSS slug from a category name. */
function catSlug(name: string): string {
return name.toLowerCase().replace(/\s+/g, "-");
}
import { catSlug } from "../utils/catSlug";

View file

@ -0,0 +1,4 @@
/** Derive the badge CSS slug from a category name. */
export function catSlug(name: string): string {
return name.toLowerCase().replace(/\s+/g, "-");
}

View file

@ -1 +1 @@
{"root":["./src/App.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/api/public-client.ts","./src/components/AdminDropdown.tsx","./src/components/AppFooter.tsx","./src/components/CategoryIcons.tsx","./src/components/CopyLinkButton.tsx","./src/components/CreatorAvatar.tsx","./src/components/ReportIssueModal.tsx","./src/pages/About.tsx","./src/pages/AdminPipeline.tsx","./src/pages/AdminReports.tsx","./src/pages/CreatorDetail.tsx","./src/pages/CreatorsBrowse.tsx","./src/pages/Home.tsx","./src/pages/SearchResults.tsx","./src/pages/SubTopicPage.tsx","./src/pages/TechniquePage.tsx","./src/pages/TopicsBrowse.tsx"],"version":"5.6.3"}
{"root":["./src/App.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/api/public-client.ts","./src/components/AdminDropdown.tsx","./src/components/AppFooter.tsx","./src/components/CategoryIcons.tsx","./src/components/CopyLinkButton.tsx","./src/components/CreatorAvatar.tsx","./src/components/ReportIssueModal.tsx","./src/pages/About.tsx","./src/pages/AdminPipeline.tsx","./src/pages/AdminReports.tsx","./src/pages/CreatorDetail.tsx","./src/pages/CreatorsBrowse.tsx","./src/pages/Home.tsx","./src/pages/SearchResults.tsx","./src/pages/SubTopicPage.tsx","./src/pages/TechniquePage.tsx","./src/pages/TopicsBrowse.tsx","./src/utils/catSlug.ts"],"version":"5.6.3"}