Skip to content

Commit ae9c952

Browse files
feat(docs): add breadcrumb navigation to blog post pages (#7306)
1 parent 4c0d78d commit ae9c952

4 files changed

Lines changed: 187 additions & 7 deletions

File tree

documentation/src/components/blog/common/date.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import React from "react";
2+
import clsx from "clsx";
23

3-
export function Date({ date, formattedDate }) {
4+
export function Date({ date, formattedDate, className }) {
45
return (
5-
<time dateTime={date} itemProp="datePublished" className="uppercase">
6+
<time
7+
dateTime={date}
8+
itemProp="datePublished"
9+
className={clsx("uppercase", className)}
10+
>
611
{formattedDate}
712
</time>
813
);

documentation/src/components/blog/post-paginator/index.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ export const PostPaginator = ({ posts, title }) => {
2121
"blog-md:max-w-[672px]",
2222
"blog-lg:max-w-[720px]",
2323
"pt-16",
24-
"pb-12",
25-
"blog-md:pt-[72px] blog-md:pb-[120px]",
24+
"blog-md:pt-[72px]",
2625
)}
2726
>
2827
<div className={clsx("w-full")}>
@@ -57,7 +56,7 @@ export const PostPaginator = ({ posts, title }) => {
5756
"blog-md:flex-row",
5857
"w-full",
5958
"items-start",
60-
"blog-md:items-center",
59+
"blog-md:items-start",
6160
"gap-2",
6261
"py-3",
6362
"blog-md:py-4",
@@ -95,7 +94,7 @@ export const PostPaginator = ({ posts, title }) => {
9594
"w-[120px]",
9695
"blog-md:text-right",
9796
"text-[10px]",
98-
"leading-4",
97+
"leading-6",
9998
"font-semibold",
10099
"uppercase",
101100
"tracking-[0.01em]",
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import React from "react";
2+
import Link from "@docusaurus/Link";
3+
import clsx from "clsx";
4+
5+
type BlogCategory = {
6+
label?: string;
7+
permalink?: string;
8+
} | null;
9+
10+
type BreadcrumbItem = {
11+
label: string;
12+
href?: string;
13+
};
14+
15+
type BlogBreadcrumbsProps = {
16+
permalink?: string;
17+
title?: string;
18+
category?: BlogCategory;
19+
className?: string;
20+
};
21+
22+
const getBreadcrumbItems = ({
23+
permalink,
24+
title,
25+
category,
26+
}: {
27+
permalink: string;
28+
title: string;
29+
category?: BlogCategory;
30+
}): BreadcrumbItem[] => [
31+
{ label: "Blog", href: "/blog" },
32+
...(category?.label && category?.permalink
33+
? [{ label: category.label, href: category.permalink }]
34+
: []),
35+
{ label: title, href: permalink },
36+
];
37+
38+
export const BlogBreadcrumbs = ({
39+
permalink,
40+
title,
41+
category,
42+
className,
43+
}: BlogBreadcrumbsProps) => {
44+
if (!title || !permalink) {
45+
return null;
46+
}
47+
48+
const items = getBreadcrumbItems({ permalink, title, category });
49+
50+
return (
51+
<nav
52+
className={clsx("not-prose", "w-full", "min-w-0", className)}
53+
aria-label="Blog breadcrumbs"
54+
>
55+
<ol
56+
className={clsx(
57+
"m-0",
58+
"p-0",
59+
"list-none",
60+
"flex",
61+
"w-full",
62+
"min-w-0",
63+
"flex-col",
64+
"items-start",
65+
"gap-1",
66+
"blog-sm:flex-row",
67+
"blog-sm:flex-wrap",
68+
"blog-sm:items-center",
69+
"blog-sm:gap-0",
70+
"text-sm",
71+
"leading-5",
72+
"font-normal",
73+
"tracking-[-0.007em]",
74+
)}
75+
>
76+
{items.map((item, index) => {
77+
const isLast = index === items.length - 1;
78+
const itemTextClass = isLast
79+
? "text-zinc-400 dark:text-zinc-400"
80+
: "text-zinc-700 dark:text-zinc-300";
81+
const itemContainerClass = isLast
82+
? "blog-sm:flex-1"
83+
: "blog-sm:w-auto blog-sm:shrink-0";
84+
const itemLabelClass = clsx(
85+
"block",
86+
"min-w-0",
87+
"max-w-full",
88+
"break-words",
89+
isLast ? "blog-sm:truncate" : "blog-sm:whitespace-nowrap",
90+
);
91+
92+
return (
93+
<li
94+
key={`${item.label}-${item.href ?? "current"}`}
95+
className={clsx(
96+
"flex",
97+
"items-center",
98+
"min-w-0",
99+
"max-w-full",
100+
"w-full",
101+
itemContainerClass,
102+
)}
103+
>
104+
{index > 0 && (
105+
<span
106+
className={clsx(
107+
"hidden",
108+
"blog-sm:inline",
109+
"blog-sm:mx-2",
110+
"text-zinc-300",
111+
"dark:text-zinc-700",
112+
)}
113+
aria-hidden="true"
114+
>
115+
/
116+
</span>
117+
)}
118+
{item.href && !isLast ? (
119+
<Link
120+
to={item.href}
121+
className={clsx(
122+
"no-underline",
123+
"hover:no-underline",
124+
itemLabelClass,
125+
itemTextClass,
126+
"hover:text-zinc-700",
127+
"dark:hover:text-zinc-300",
128+
)}
129+
>
130+
{item.label}
131+
</Link>
132+
) : (
133+
<span
134+
className={clsx(itemLabelClass, itemTextClass)}
135+
aria-current={isLast ? "page" : undefined}
136+
>
137+
{item.label}
138+
</span>
139+
)}
140+
<span
141+
className={clsx(
142+
"ml-2",
143+
"text-zinc-300",
144+
"dark:text-zinc-700",
145+
"blog-sm:hidden",
146+
)}
147+
aria-hidden="true"
148+
>
149+
/
150+
</span>
151+
</li>
152+
);
153+
})}
154+
</ol>
155+
</nav>
156+
);
157+
};

documentation/src/theme/BlogPostPage/index.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,37 @@ import {
1010
} from "@docusaurus/theme-common/internal";
1111
import BlogLayout from "@theme/BlogLayout";
1212
import BlogPostPageMetadata from "@theme/BlogPostPage/Metadata";
13+
import { BlogBreadcrumbs } from "../../refine-theme/blog-breadcrumbs";
1314
import { BlogTOC } from "../../refine-theme/blog-toc";
1415

1516
import { BlogPostPageView, PostPaginator } from "../../components/blog";
1617

1718
function BlogPostPageContent({ children }) {
1819
const { metadata, toc } = useBlogPost();
19-
const { relatedPosts } = metadata;
20+
const { relatedPosts, permalink, title, category } = metadata;
2021

2122
return (
2223
<BlogLayout toc={<BlogTOC toc={toc} />}>
2324
<BlogPostPageView>{children}</BlogPostPageView>
2425
<PostPaginator title="Related Articles" posts={relatedPosts} />
26+
<BlogBreadcrumbs
27+
permalink={permalink}
28+
title={title}
29+
category={category}
30+
className={clsx(
31+
"w-full",
32+
"mx-auto",
33+
"px-4",
34+
"blog-md:px-0",
35+
"blog-max:px-4",
36+
"max-w-[320px]",
37+
"blog-md:max-w-[672px]",
38+
"blog-lg:max-w-[720px]",
39+
"mt-10",
40+
"pb-16",
41+
"blog-md:pb-[120px]",
42+
)}
43+
/>
2544
</BlogLayout>
2645
);
2746
}

0 commit comments

Comments
 (0)