Files
mypage/components/layout/Breadcrumbs.tsx
2025-12-03 16:33:43 +02:00

141 lines
4.0 KiB
TypeScript

'use client'
import {Link} from '@/i18n/navigation'
import { usePathname } from 'next/navigation'
import { useLocale, useTranslations } from 'next-intl'
import { Fragment } from 'react'
import { BreadcrumbsSchema } from './breadcrumbs-schema'
interface BreadcrumbItem {
label: string
href: string
current?: boolean
}
function HomeIcon({ className }: { className?: string }) {
return (
<svg
className={className}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"
/>
</svg>
)
}
function ChevronIcon({ className }: { className?: string }) {
return (
<svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
)
}
export function Breadcrumbs({ items }: { items?: BreadcrumbItem[] }) {
const pathname = usePathname()
const locale = useLocale()
const t = useTranslations('Breadcrumbs')
// Hide breadcrumbs on main page
const isMainPage = pathname === `/${locale}` || pathname === '/'
if (isMainPage) {
return null
}
const formatSegmentLabel = (segment: string): string => {
const specialCases: { [key: string]: string } = {
blog: t('blog'),
tags: t('tags'),
about: t('about'),
}
if (specialCases[segment]) {
return specialCases[segment]
}
return segment
.split('-')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ')
}
let breadcrumbs: BreadcrumbItem[] = items || []
if (!items) {
const segments = pathname.split('/').filter(Boolean)
breadcrumbs = segments.map((segment, index) => {
const href = '/' + segments.slice(0, index + 1).join('/')
const label = formatSegmentLabel(segment)
const current = index === segments.length - 1
return { label, href, current }
})
}
const schemaItems = [
{ position: 1, name: t('home'), item: '/' },
...breadcrumbs.map((item, index) => ({
position: index + 2,
name: item.label,
item: item.href,
})),
]
return (
<>
<nav
aria-label="Breadcrumb"
className="bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700"
>
<div className="container mx-auto px-4 py-3">
<ol className="flex items-center space-x-2 text-sm overflow-x-auto scrollbar-hide">
<li className="flex-shrink-0">
<Link
href="/"
className="flex items-center text-gray-500 hover:text-primary-600 transition"
aria-label={t('home')}
>
<HomeIcon className="w-4 h-4" />
</Link>
</li>
{breadcrumbs.map(item => (
<Fragment key={item.href}>
<li className="text-gray-400 flex-shrink-0">
<ChevronIcon className="w-4 h-4" />
</li>
<li className="flex-shrink-0">
{item.current ? (
<span
className="font-medium text-gray-700 dark:text-gray-300 truncate max-w-[150px] sm:max-w-none block"
aria-current="page"
>
{item.label}
</span>
) : (
<Link
href={item.href}
className="text-gray-500 hover:text-primary-600 transition truncate max-w-[150px] sm:max-w-none block"
>
{item.label}
</Link>
)}
</li>
</Fragment>
))}
</ol>
</div>
</nav>
<BreadcrumbsSchema items={schemaItems} />
</>
)
}