docs: add JSON-LD schemas to docs (#14007)
This commit is contained in:
@@ -7,6 +7,8 @@ import { useSidebar, useSiteConfig } from "../../providers"
|
||||
import { Button } from "../Button"
|
||||
import { TriangleRightMini } from "@medusajs/icons"
|
||||
import { Sidebar } from "types"
|
||||
import { getJsonLd } from "../../utils"
|
||||
import type { BreadcrumbList } from "schema-dts"
|
||||
|
||||
type BreadcrumbItems = {
|
||||
title: string
|
||||
@@ -16,7 +18,7 @@ type BreadcrumbItems = {
|
||||
export const Breadcrumbs = () => {
|
||||
const { sidebarHistory, getSidebarFirstLinkChild, getSidebar } = useSidebar()
|
||||
const {
|
||||
config: { breadcrumbOptions },
|
||||
config: { breadcrumbOptions, baseUrl, basePath },
|
||||
} = useSiteConfig()
|
||||
|
||||
const getLinkPath = (item: Sidebar.SidebarItemLink): string => {
|
||||
@@ -51,6 +53,24 @@ export const Breadcrumbs = () => {
|
||||
return items
|
||||
}, [sidebarHistory, breadcrumbOptions])
|
||||
|
||||
const jsonLd = useMemo(() => {
|
||||
const baseLink = `${baseUrl}${basePath}`.replace(/\/+$/, "")
|
||||
return getJsonLd<BreadcrumbList>({
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: breadcrumbItems.map((item, index) => ({
|
||||
"@type": "ListItem",
|
||||
position: index + 1,
|
||||
name: item.title,
|
||||
item: item.link.startsWith("#")
|
||||
? baseLink
|
||||
: item.link.startsWith("/")
|
||||
? `${baseLink}${item.link}`
|
||||
: item.link,
|
||||
})),
|
||||
})
|
||||
}, [breadcrumbItems, baseUrl, basePath])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
@@ -79,6 +99,12 @@ export const Breadcrumbs = () => {
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
))}
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: jsonLd,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
"use client"
|
||||
|
||||
import React, { useEffect, useState } from "react"
|
||||
import type { TechArticle } from "schema-dts"
|
||||
import { useIsBrowser, useSiteConfig } from "../../providers"
|
||||
import { getJsonLd } from "../../utils"
|
||||
import { usePathname } from "next/navigation"
|
||||
|
||||
export const TechArticleJsonLd = () => {
|
||||
const {
|
||||
config: { baseUrl, basePath, description: configDescription, titleSuffix },
|
||||
} = useSiteConfig()
|
||||
const pathname = usePathname()
|
||||
const { isBrowser } = useIsBrowser()
|
||||
const [jsonLdData, setJsonLdData] = useState("{}")
|
||||
|
||||
useEffect(() => {
|
||||
if (!isBrowser) {
|
||||
return
|
||||
}
|
||||
|
||||
// Use a small delay to ensure the document has been updated after navigation
|
||||
const updateJsonLd = () => {
|
||||
const baseLink = `${baseUrl}${basePath}`.replace(/\/+$/, "")
|
||||
const title = document.title.replace(` - ${titleSuffix}`, "")
|
||||
const description =
|
||||
document.querySelector("#main p")?.textContent ||
|
||||
configDescription ||
|
||||
""
|
||||
|
||||
const data = getJsonLd<TechArticle>({
|
||||
"@context": "https://schema.org",
|
||||
"@type": "TechArticle",
|
||||
headline: title,
|
||||
description,
|
||||
proficiencyLevel: "Expert",
|
||||
author: "Medusa",
|
||||
genre: "Documentation",
|
||||
keywords: "medusa, ecommerce, open-source",
|
||||
url: `${baseLink}${pathname}`,
|
||||
})
|
||||
|
||||
setJsonLdData(data)
|
||||
}
|
||||
|
||||
// Update immediately
|
||||
updateJsonLd()
|
||||
|
||||
// Also set up a MutationObserver to watch for title changes
|
||||
const titleObserver = new MutationObserver(() => {
|
||||
updateJsonLd()
|
||||
})
|
||||
|
||||
const titleElement = document.querySelector("title")
|
||||
if (titleElement) {
|
||||
titleObserver.observe(titleElement, {
|
||||
childList: true,
|
||||
characterData: true,
|
||||
subtree: true,
|
||||
})
|
||||
}
|
||||
|
||||
return () => {
|
||||
titleObserver.disconnect()
|
||||
}
|
||||
}, [isBrowser, pathname, baseUrl, basePath, configDescription, titleSuffix])
|
||||
|
||||
return (
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: jsonLdData }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import clsx from "clsx"
|
||||
import { RootProviders, Sidebar, SidebarProps } from "@/components"
|
||||
import { MainContentLayout, MainContentLayoutProps } from "./main-content"
|
||||
import { AiAssistantChatWindow } from "../components/AiAssistant/ChatWindow"
|
||||
import { TechArticleJsonLd } from "../components/TechArticleJsonLd"
|
||||
|
||||
export type RootLayoutProps = {
|
||||
bodyClassName?: string
|
||||
@@ -37,6 +38,7 @@ export const RootLayout = ({
|
||||
<MainContentLayout {...mainProps} />
|
||||
<AiAssistantChatWindow />
|
||||
</div>
|
||||
<TechArticleJsonLd />
|
||||
</ProvidersComponent>
|
||||
</RootProviders>
|
||||
</div>
|
||||
|
||||
5
www/packages/docs-ui/src/utils/get-json-ld.ts
Normal file
5
www/packages/docs-ui/src/utils/get-json-ld.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import type { Thing, WithContext } from "schema-dts"
|
||||
|
||||
export function getJsonLd<T extends Thing>(data: WithContext<T>): string {
|
||||
return JSON.stringify(data, null, 2).replace(/</g, "\\u003c")
|
||||
}
|
||||
@@ -4,6 +4,7 @@ export * from "./check-sidebar-item-visibility"
|
||||
export * from "./decode-str"
|
||||
export * from "./dom-utils"
|
||||
export * from "./event-parser"
|
||||
export * from "./get-json-ld"
|
||||
export * from "./get-link-with-base-path"
|
||||
export * from "./get-local-search"
|
||||
export * from "./get-navbar-items"
|
||||
|
||||
Reference in New Issue
Block a user