Files
Siteforge/src/components/Breadcrumbs.tsx
T
nmemmert c4645e3475 Add cross-site improvements across three phases
Phase 1 — Quick wins:
- Image lazy-loading on series/resource cards
- Newsletter signup added to Episodes page (before highlights)
- Per-route meta tags via usePageMeta hook (title, og:title, og:description)
- Breadcrumbs on study index, section, and notes pages
- SVG completion checkmark badges on study section list
- Analytics time-range filter (7d / 30d / 90d) in admin panel

Phase 2 — Medium features:
- Related episodes on archived series detail pages
- Resource library two-tier filter (type + tag chips)
- Global search (Fuse.js) moved below sticky header as full-width bar
- Q&A anonymous upvoting with localStorage dedup + admin pin/unpin
- Study enrollment funnel tracking (firstVisitAt, firstCompletionAt) with funnel chart in analytics

Phase 3 — Larger features:
- Study section comments (auto-approve for enrolled users, admin moderation panel)
- Study completion certificate (canvas render, PNG download, shareable public URL)
- Episode script full-text search (mammoth docx extraction, server-side search, admin upload UI)
- Reflection questions renamed from Discussion Questions; quiz answers can be shared to section discussion
- Public certificate route at /certificate/:token with og meta tags
- Comment moderation panel added to admin under Manage > Study Comments

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 09:10:29 -04:00

37 lines
1.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Link } from 'react-router-dom'
export interface BreadcrumbItem {
label: string
href?: string
}
export function Breadcrumbs({ items }: { items: BreadcrumbItem[] }) {
if (items.length === 0) return null
return (
<nav aria-label="Breadcrumb" className="study-breadcrumbs">
<ol className="study-breadcrumbs-list">
{items.map((item, idx) => {
const isLast = idx === items.length - 1
return (
<li key={idx} className="study-breadcrumbs-item">
{!isLast && item.href ? (
<Link to={item.href} className="study-breadcrumbs-link">
{item.label}
</Link>
) : (
<span className="study-breadcrumbs-current" aria-current={isLast ? 'page' : undefined}>
{item.label}
</span>
)}
{!isLast && (
<span className="study-breadcrumbs-sep" aria-hidden="true"> </span>
)}
</li>
)
})}
</ol>
</nav>
)
}