Help Improvement 6 — Prev/Next Navigation & Breadcrumbs
Status: [To Build]
Purpose: Help topic pages are currently isolated — no way to continue reading adjacent topics, and no breadcrumb trail back to the category. Both are pure UI additions to
HelpPagethat require passing the full page list at render time.
A — Breadcrumbs
What it looks like
Help Center › Content › Blog PostsThe breadcrumb lives in the HelpPage header, between the back-to-feature link and the title.
Implementation
HelpPage already knows data.category and data.categoryLabel. It needs to know the Help Center basePath to construct the first crumb link.
// packages/ui/src/HelpPage.tsx
// Add to props:
interface HelpPageProps {
data: HelpPageData;
inDrawer?: boolean;
basePath?: string; // default "/help"
onRate?: ...;
}
// Breadcrumb render (only when not inDrawer):
{!inDrawer && (
<nav className="flex items-center gap-1.5 text-sm text-muted-foreground mb-6" aria-label="Breadcrumb">
<Link href={basePath ?? "/help"} className="hover:text-foreground">
Help Center
</Link>
<ChevronRight className="w-3.5 h-3.5" />
<Link
href={`${basePath ?? "/help"}?category=${data.category}`}
className="hover:text-foreground"
>
{data.categoryLabel}
</Link>
<ChevronRight className="w-3.5 h-3.5" />
<span className="text-foreground font-medium">{data.title}</span>
</nav>
)}The category crumb links back to /help?category=content — the HelpCenter component already groups by category, so adding a ?category URL filter to it makes this link immediately useful (see below).
HelpCenter category filter from URL
// packages/ui/src/HelpCenter.tsx
// Read initial category from searchParams
const [activeCategory, setActiveCategory] = useState<string | null>(
() => typeof window !== "undefined"
? new URLSearchParams(window.location.search).get("category")
: null
);
// When activeCategory is set, only show pages for that category
const displayPages = useMemo(() => {
if (query.trim()) return null; // search overrides category filter
if (!activeCategory) return null; // show all
return pages.filter(p => p.category === activeCategory);
}, [pages, query, activeCategory]);B — Prev / Next Navigation
What it looks like
At the bottom of every help topic page, after all sections:
← Previous Next →
Activities Content CalendarImplementation
HelpPage receives the ordered list of all pages. The adjacent topics are computed by finding the current slug’s index.
// packages/ui/src/HelpPage.tsx
// Add to props:
interface HelpPageProps {
data: HelpPageData;
allPages?: HelpPageData[]; // full ordered list for prev/next
basePath?: string;
inDrawer?: boolean;
onRate?: ...;
}
// Derive prev/next:
const { prev, next } = useMemo(() => {
if (!allPages) return { prev: null, next: null };
const idx = allPages.findIndex(p => p.slug === data.slug);
return {
prev: idx > 0 ? allPages[idx - 1] : null,
next: idx < allPages.length - 1 ? allPages[idx + 1] : null,
};
}, [allPages, data.slug]);Render
{(prev || next) && !inDrawer && (
<nav className="flex items-center justify-between border-t pt-6 mt-10 gap-4">
{prev ? (
<Link
href={`${basePath ?? "/help"}/${prev.slug}`}
className="group flex flex-col items-start gap-0.5 max-w-[45%]"
>
<span className="text-xs text-muted-foreground flex items-center gap-1">
<ArrowLeft className="w-3 h-3" /> Previous
</span>
<span className="text-sm font-medium group-hover:text-violet-600 transition-colors line-clamp-1">
{prev.title}
</span>
</Link>
) : <div />}
{next ? (
<Link
href={`${basePath ?? "/help"}/${next.slug}`}
className="group flex flex-col items-end gap-0.5 max-w-[45%]"
>
<span className="text-xs text-muted-foreground flex items-center gap-1">
Next <ArrowRight className="w-3 h-3" />
</span>
<span className="text-sm font-medium group-hover:text-violet-600 transition-colors line-clamp-1">
{next.title}
</span>
</Link>
) : <div />}
</nav>
)}Passing allPages from the route
// apps/dashboard/src/app/(dashboard)/help/blog/page.tsx
import { dashboardHelpPages, dashboardHelpPageMap } from "../_data";
export default function HelpBlogPage() {
return (
<HelpPage
data={dashboardHelpPageMap.blog}
allPages={dashboardHelpPages} // full ordered list
/>
);
}Export both a map (keyed by slug) and an ordered array from _data/index.ts:
// apps/dashboard/src/app/(dashboard)/help/_data/index.ts
export const dashboardHelpPages: HelpPageData[] = [ ...all 26 topics ];
export const dashboardHelpPageMap: Record<string, HelpPageData> =
Object.fromEntries(dashboardHelpPages.map(p => [p.slug, p]));Ordering Strategy
Within each category, topics are ordered by logical reading sequence (not alphabetically). The global dashboardHelpPages array is ordered: pipeline → content → planning → seo → analytics → platform → (new categories).
Affected Files
| File | Change |
|---|---|
packages/ui/src/HelpPage.tsx | Add allPages, basePath props; render breadcrumbs + prev/next |
packages/ui/src/HelpCenter.tsx | Read ?category from URL; filter display by active category |
apps/dashboard/src/app/(dashboard)/help/_data/index.ts | Export both dashboardHelpPages array and dashboardHelpPageMap |
apps/dashboard/src/app/(dashboard)/help/[slug]/page.tsx | Pass allPages to <HelpPage> |
| All 26 topic page files | Pass allPages prop (or consolidate into a single dynamic [slug] route) |