Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add breadcrumbs and navigation structured data #410

Merged
merged 2 commits into from
Dec 8, 2023
Merged
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
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ NEXT_PUBLIC_GA_MEASUREMENT_ID=G-2D9VN5WR6Z
NEXT_PUBLIC_ALGOLIA_APP_ID=CQS6UA9C70
NEXT_PUBLIC_ALGOLIA_SEARCH_KEY=ef679b476514ba6905fc1140c7781f48
NEXT_PUBLIC_API_HOST=https://docs.icerpc.dev
NEXT_PUBLIC_BASE_URL=https://docs.icerpc.dev
57 changes: 57 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Analytics } from '@/components/analytics';
import { Inter } from 'next/font/google';
import clsx from 'clsx';
import { Metadata } from 'next';
import Script from 'next/script';

const inter = Inter({ subsets: ['latin', 'latin-ext'] });

Expand Down Expand Up @@ -53,6 +54,57 @@ export const metadata: Metadata = {
metadataBase: new URL('https://docs.icerpc.dev')
};

const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;
const schema = {
'@context': 'http://schema.org',
'@type': 'ItemList',
itemListElement: [
{
'@type': 'SiteNavigationElement',
position: 1,
name: 'Home',
description: 'Welcome to the IceRPC Docs.',
url: new URL('/', baseUrl).href
},
{
'@type': 'SiteNavigationElement',
position: 2,
name: 'Getting Started',
description: 'Quickly get up and running with IceRPC.',
url: new URL('/getting-started', baseUrl).href
},
{
'@type': 'SiteNavigationElement',
position: 3,
name: 'IceRPC',
description: 'A modular RPC framework built for QUIC.',
url: new URL('/icerpc', baseUrl).href
},
{
'@type': 'SiteNavigationElement',
position: 4,
name: 'Slice',
description: 'A modern IDL and serialization format.',
url: new URL('/slice2', baseUrl).href
},
{
'@type': 'SiteNavigationElement',
position: 5,
name: 'Protobuf',
description: 'Using Protocol Buffers with IceRPC.',
url: new URL('/protobuf', baseUrl).href
},
{
'@type': 'SiteNavigationElement',
position: 6,
name: 'IceRPC for Ice users',
description:
'How IceRPC relates to Ice, and how to use IceRPC and Ice together.',
url: new URL('/icerpc-for-ice-users', baseUrl).href
}
]
};

export default function RootLayout(props: any) {
return (
<html lang="en" suppressHydrationWarning>
Expand All @@ -76,6 +128,11 @@ export default function RootLayout(props: any) {
<Analytics />
</PathProvider>
</ThemeProvider>
<Script
id="navigation-structured-data"
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
{/* Fix for issue #368 - see discussion at https://github.com/algolia/docsearch/issues/1260 */}
<div className="fixed">
<input type="text" />
Expand Down
90 changes: 55 additions & 35 deletions components/breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,71 @@
import React from 'react';
import Link from 'next/link';
import clsx from 'clsx';
import Script from 'next/script';

export type Breadcrumb = {
name: string;
href: string;
};

type Props = { breadcrumbs: Breadcrumb[] };
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;

export const Breadcrumbs = ({ breadcrumbs }: Props) => {
const schema = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: breadcrumbs.map((crumb, index) => ({
'@type': 'ListItem',
position: index + 1, // Schema.org position is 1-based.
name: crumb.name,
item: new URL(crumb.href, baseUrl).href
}))
};

return (
<ol className="hidden justify-start p-0 text-sm md:flex">
{breadcrumbs.map((crumb, index) => {
const name = crumb.name;
const href = crumb.href;
const isLast = crumb === breadcrumbs[breadcrumbs.length - 1];
<>
<ol className="hidden justify-start p-0 text-sm md:flex">
{breadcrumbs.map((crumb, index) => {
const name = crumb.name;
const href = crumb.href;
const isLast = crumb === breadcrumbs[breadcrumbs.length - 1];

return (
<li
key={name}
className={clsx(
'mb-0 flex flex-row items-center gap-2',
index == 0 && 'pl-1'
)}
>
<Link href={href} className="dark:text-white/80">
{name}
</Link>
{!isLast ? (
<svg
fill="none"
height="22"
shapeRendering="geometricPrecision"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
viewBox="0 0 24 24"
className="-mx-2 text-[#64748b5b] dark:text-white/60"
>
<path d="M16.88 3.549L7.12 20.451"></path>
</svg>
) : null}
</li>
);
})}
</ol>
return (
<li
key={name}
className={clsx(
'mb-0 flex flex-row items-center gap-2',
index == 0 && 'pl-1'
)}
>
<Link href={href} className="dark:text-white/80">
{name}
</Link>
{!isLast ? (
<svg
fill="none"
height="22"
shapeRendering="geometricPrecision"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
viewBox="0 0 24 24"
className="-mx-2 text-[#64748b5b] dark:text-white/60"
>
<path d="M16.88 3.549L7.12 20.451"></path>
</svg>
) : null}
</li>
);
})}
</ol>
<Script
id="bread-crumb-structured-data"
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
</>
);
};