1+ import type { MouseEvent } from 'react'
2+ import { useRouter } from 'next/router'
13import cx from 'classnames'
4+ import { Breadcrumbs as BrandBreadcrumbs } from '@primer/react-brand'
25
36import { useMainContext } from '../context/MainContext'
4- import { Link } from '@/frame/components/Link'
5-
6- import styles from './Breadcrumbs.module.scss'
77
88type Props = {
99 inHeader ?: boolean
@@ -16,55 +16,64 @@ export type BreadcrumbT = {
1616
1717export const Breadcrumbs = ( { inHeader } : Props ) => {
1818 const { breadcrumbs } = useMainContext ( )
19+ const router = useRouter ( )
20+
21+ // BrandBreadcrumbs.Item renders a plain <a>, so intercept clicks to restore
22+ // next/link-style client-side navigation. Modifier/middle clicks fall through
23+ // to the browser so open-in-new-tab still works, and the <a href> keeps the
24+ // links crawlable for SSR.
25+ const handleClick = ( event : MouseEvent < HTMLAnchorElement > , href : string ) => {
26+ if (
27+ event . defaultPrevented ||
28+ event . button !== 0 ||
29+ event . metaKey ||
30+ event . ctrlKey ||
31+ event . shiftKey ||
32+ event . altKey ||
33+ ! href . startsWith ( '/' )
34+ ) {
35+ return
36+ }
37+ event . preventDefault ( )
38+ // hrefs already include the locale prefix (e.g. /en/...), so disable
39+ // Next.js locale handling to avoid double-prefixing.
40+ router . push ( href , undefined , { locale : false } )
41+ }
1942
2043 return (
21- /*
22- NOTE: The breadcrumbs class and the nav tag are used by the
23- Lunr search scripts. The a tag generated by the Link is also used.
24- If these change, please also change
25- updating src/search/scripts/parse-page-sections-into-records.ts.
26- */
27- < nav
44+ < BrandBreadcrumbs
2845 data-testid = { inHeader ? 'breadcrumbs-header' : 'breadcrumbs-in-article' }
29- className = { cx ( 'f5 breadcrumbs' , styles . breadcrumbs ) }
3046 aria-label = "Breadcrumb"
3147 data-container = "breadcrumbs"
3248 >
33- < ul >
34- { Object . values ( breadcrumbs )
35- . filter ( Boolean )
36- . map ( ( breadcrumb , i , arr ) => {
37- const title = `${ breadcrumb . title } `
38- return [
39- ! breadcrumb . href ? (
40- < span data-testid = "breadcrumb-title" key = { title } className = "px-2" >
41- { breadcrumb . title }
42- </ span >
43- ) : (
44- < li className = "d-inline-block" key = { title } >
45- < Link
46- data-testid = "breadcrumb-link"
47- href = { breadcrumb . href }
48- title = { title }
49- className = { cx (
50- 'Link--primary mr-2 color-fg-muted' ,
51- // Show the last breadcrumb if it's in the header, but not if it's in the article
52- // If there's only 1 breadcrumb, show it
53- ! inHeader && i === arr . length - 1 && arr . length !== 1 && 'd-none' ,
54- ) }
55- >
56- { breadcrumb . title }
57- </ Link >
58- { i !== arr . length - 1 ? (
59- < span className = "color-fg-muted pr-2" key = { `${ i } -slash` } >
60- /
61- </ span >
62- ) : null }
63- </ li >
64- ) ,
65- ]
66- } ) }
67- </ ul >
68- </ nav >
49+ { Object . values ( breadcrumbs )
50+ . filter ( Boolean )
51+ . map ( ( breadcrumb , i , arr ) => {
52+ const title = `${ breadcrumb . title } `
53+ if ( ! breadcrumb . href ) {
54+ return (
55+ < li key = { title } >
56+ < span data-testid = "breadcrumb-title" > { breadcrumb . title } </ span >
57+ </ li >
58+ )
59+ }
60+ return (
61+ < BrandBreadcrumbs . Item
62+ data-testid = "breadcrumb-link"
63+ key = { title }
64+ href = { breadcrumb . href }
65+ title = { title }
66+ onClick = { ( event ) => handleClick ( event , breadcrumb . href ! ) }
67+ className = { cx (
68+ // Show the last breadcrumb if it's in the header, but not if it's in the article.
69+ // If there's only 1 breadcrumb, show it.
70+ ! inHeader && i === arr . length - 1 && arr . length !== 1 && 'd-none' ,
71+ ) }
72+ >
73+ { breadcrumb . title }
74+ </ BrandBreadcrumbs . Item >
75+ )
76+ } ) }
77+ </ BrandBreadcrumbs >
6978 )
7079}
0 commit comments