Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions components/Docs/DocsClient.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';

import { useDocsNavigation } from 'components/Docs/DocsNavigationContext';
import DocsBreadcrumbs from 'components/Docs/docsMain/docsBreadcrumbs';
import MainDocsBodyHeader from 'components/Docs/docsMain/docsMainBody';
import TocOverflowButton from 'components/Docs/docsMain/tocOverflowButton';
import ToC from 'components/Docs/toc';
Expand Down Expand Up @@ -82,6 +83,7 @@ export default function DocsClient({
!DocumentationData?.tocIsHidden ? 'xl:col-span-1' : ''
}`}
>
<DocsBreadcrumbs />
<MainDocsBodyHeader
DocumentTitle={DocumentationData?.title}
NavigationDocsItems={NavigationDocsData.data}
Expand Down
142 changes: 142 additions & 0 deletions components/Docs/docsMain/docsBreadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
'use client';

import { useNavigationData } from 'components/Docs/DocsLayoutClient';
import { useDocsNavigation } from 'components/Docs/DocsNavigationContext';
import React from 'react';

interface BreadcrumbItem {
title: string;
slug?: string;
}

const cleanPath = (path: string | undefined): string => {
return path ? path.replace(/\/+$/, '').replace(/^\/+/, '') : '';
};

const matchSlug = (
itemSlug: string | undefined,
currentPath: string,
): boolean => {
if (!itemSlug) return false;
return cleanPath(itemSlug) === cleanPath(currentPath);
};

const getFirstChildSlug = (item: any): string | undefined => {
if (!item) return undefined;
if (item.slug) return item.slug;
if (item.items && item.items.length > 0) {
for (const child of item.items) {
const slug = getFirstChildSlug(child);
if (slug) {
return slug;
}
}
}
return undefined;
};

const findNavigationPath = (
items: any[],
currentPath: string,
currentBreadcrumbs: BreadcrumbItem[] = [],
): BreadcrumbItem[] | null => {
if (!items) {
return null;
}
for (const item of items) {
if (!item) {
continue;
}
const isMatch = matchSlug(item.slug, currentPath);
const resolvedSlug = item.slug || getFirstChildSlug(item);
const newPath = [
...currentBreadcrumbs,
{ title: item.title || '', slug: resolvedSlug },
];

if (isMatch) return newPath;

if (item.items && item.items.length > 0) {
const childPath = findNavigationPath(item.items, currentPath, newPath);
if (childPath) {
return childPath;
}
}
}

return null;
};

const DocsBreadcrumbs = () => {
const { NavigationDocsData, NavigationLearnData } = useNavigationData();
const { learnActive } = useDocsNavigation();
const navigationItems = learnActive
? NavigationLearnData?.data
: NavigationDocsData?.data;

const currentPath =
typeof window !== 'undefined' ? window.location.pathname : '';
if (!navigationItems) return null;

const breadcrumbPath = findNavigationPath(navigationItems, currentPath);
if (!breadcrumbPath || breadcrumbPath.length < 1) return null;

return (
<nav
className="flex items-center text-sm text-neutral-text-secondary mb-1 flex-wrap"
aria-label="Breadcrumb"
>
<ol className="flex flex-wrap items-center max-w-full">
{breadcrumbPath.map((item, index) => {
const isLast = index === breadcrumbPath.length - 1;
const hasSlug = !!item.slug;

if (hasSlug && !isLast) {
return (
<li
key={index}
className="flex items-center whitespace-nowrap font-ibm-plex"
>
{index > 0 && (
<span className="text-neutral-text-secondary opacity-60 px-1.5">
{'>'}
</span>
)}
<a
href={item.slug}
className="text-neutral-text-secondary hover:text-brand-primary transition-colors"
>
{item.title}
</a>
</li>
);
}

return (
<li
key={index}
className="flex items-center whitespace-nowrap font-ibm-plex"
>
{index > 0 && (
<span className="text-neutral-text-secondary opacity-60 px-1.5">
{'>'}
</span>
)}
<span
className={
isLast
? 'text-neutral-text font-medium'
: 'text-neutral-text-secondary'
}
>
{item.title}
</span>
</li>
);
})}
</ol>
</nav>
);
};

export default DocsBreadcrumbs;