@@ -19,13 +19,14 @@ import DocBreadcrumbs from "@theme/DocBreadcrumbs";
1919import Layout from "@docusaurus/core/lib/client/theme-fallback/Layout" ;
2020import Head from "@docusaurus/Head" ;
2121import MDXContent from "@theme/MDXContent" ;
22+ import useDocusaurusContext from "@docusaurus/useDocusaurusContext" ;
2223import { KeployCloud } from "@site/src/components/KeployCloud" ;
2324
2425export default function DocItem ( props ) {
2526 const { content : DocContent } = props ;
2627 const { metadata, frontMatter, assets} = DocContent ;
2728 const {
28- keywords,
29+ keywords : frontMatterKeywords ,
2930 hide_title : hideTitle ,
3031 hide_table_of_contents : hideTableOfContents ,
3132 toc_min_heading_level : tocMinHeadingLevel ,
@@ -43,19 +44,138 @@ export default function DocItem(props) {
4344 ! hideTableOfContents && DocContent . toc && DocContent . toc . length > 0 ;
4445 const renderTocDesktop =
4546 canRenderTOC && ( windowSize === "desktop" || windowSize === "ssr" ) ;
46-
47+ const { siteConfig} = useDocusaurusContext ( ) ;
48+ const toIsoDate = ( value ) => {
49+ if ( ! value ) {
50+ return null ;
51+ }
52+ const isEpochSeconds = Number . isFinite ( value ) && value < 1e12 ;
53+ const date = new Date ( isEpochSeconds ? value * 1000 : value ) ;
54+ if ( Number . isNaN ( date . getTime ( ) ) ) {
55+ return null ;
56+ }
57+ return date . toISOString ( ) ;
58+ } ;
59+ const toAbsoluteUrl = ( baseUrl , url ) => {
60+ if ( ! url ) {
61+ return null ;
62+ }
63+ if ( url . startsWith ( "http://" ) || url . startsWith ( "https://" ) ) {
64+ return url ;
65+ }
66+ const trimmedBase = baseUrl ?. replace ( / \/ $ / , "" ) ?? "" ;
67+ const normalizedPath = url . startsWith ( "/" ) ? url : `/${ url } ` ;
68+ return `${ trimmedBase } ${ normalizedPath } ` ;
69+ } ;
70+ const toArray = ( value ) => {
71+ if ( ! value ) {
72+ return [ ] ;
73+ }
74+ return Array . isArray ( value ) ? value : [ value ] ;
75+ } ;
76+ const toPersonList = ( value ) => {
77+ return toArray ( value )
78+ . map ( ( item ) => {
79+ if ( ! item ) {
80+ return null ;
81+ }
82+ if ( typeof item === "string" ) {
83+ return { [ "@type" ] : "Person" , name : item } ;
84+ }
85+ if ( item . name ) {
86+ return {
87+ "@type" : "Person" ,
88+ name : item . name ,
89+ ...( item . url ? { url : item . url } : { } ) ,
90+ } ;
91+ }
92+ return null ;
93+ } )
94+ . filter ( Boolean ) ;
95+ } ;
96+ const pageUrl = toAbsoluteUrl ( siteConfig ?. url , metadata ?. permalink ) ;
97+ const modifiedTime = toIsoDate (
98+ metadata ?. lastUpdatedAt || frontMatter ?. lastUpdatedAt
99+ ) ;
100+ const publishedTime = toIsoDate ( frontMatter ?. date || frontMatter ?. publishedAt ) ;
101+ const schemaTypeFromFrontMatter =
102+ frontMatter ?. schemaType || frontMatter ?. schema_type ;
103+ const isApi =
104+ frontMatter ?. apiReference === true ||
105+ frontMatter ?. type === "api" ||
106+ ( frontMatter ?. tags || [ ] ) . includes ?. ( "api" ) ;
107+ const isBlog =
108+ frontMatter ?. type === "blog" ||
109+ frontMatter ?. blog === true ||
110+ ( frontMatter ?. tags || [ ] ) . includes ?. ( "blog" ) ;
111+ const schemaType = schemaTypeFromFrontMatter
112+ ? schemaTypeFromFrontMatter
113+ : isApi
114+ ? "APIReference"
115+ : isBlog
116+ ? "BlogPosting"
117+ : "Article" ;
118+ const authorList = toPersonList ( frontMatter ?. author || frontMatter ?. authors ) ;
119+ const maintainerList = toPersonList ( frontMatter ?. maintainer ) ;
120+ const contributorList = toPersonList ( frontMatter ?. contributor ) ;
121+ const combinedContributors = [ ...maintainerList , ...contributorList ] ;
122+ const keywords = frontMatter ?. keywords || metadata ?. keywords ;
123+ const metaKeywords = frontMatterKeywords ?? metadata ?. keywords ;
124+ const programmingLanguage =
125+ frontMatter ?. programmingLanguage || frontMatter ?. programmingLanguages ;
126+ const targetPlatform = frontMatter ?. targetPlatform ;
127+ const proficiencyLevel = frontMatter ?. proficiencyLevel ;
128+ const articleSchema =
129+ pageUrl && title
130+ ? {
131+ "@context" : "https://schema.org" ,
132+ "@type" : schemaType ,
133+ headline : title ,
134+ description,
135+ ...( modifiedTime ? { dateModified : modifiedTime } : { } ) ,
136+ ...( publishedTime ? { datePublished : publishedTime } : { } ) ,
137+ ...( keywords ? { keywords} : { } ) ,
138+ ...( authorList . length ? { author : authorList } : { } ) ,
139+ ...( combinedContributors . length
140+ ? { contributor : combinedContributors }
141+ : { } ) ,
142+ ...( proficiencyLevel ? { proficiencyLevel} : { } ) ,
143+ ...( programmingLanguage ? { programmingLanguage} : { } ) ,
144+ ...( targetPlatform ? { targetPlatform} : { } ) ,
145+ mainEntityOfPage : {
146+ "@type" : "WebPage" ,
147+ "@id" : pageUrl ,
148+ } ,
149+ publisher : {
150+ "@type" : "Organization" ,
151+ name : "Keploy" ,
152+ logo : {
153+ "@type" : "ImageObject" ,
154+ url : "https://keploy.io/docs/img/favicon.png" ,
155+ } ,
156+ } ,
157+ }
158+ : null ;
47159 const MDXComponent = props . content ;
48160 return (
49161 < >
50162 < Head >
51163 < title > { title } </ title >
52164 { description && < meta name = "description" content = { description } /> }
165+ { modifiedTime && (
166+ < meta property = "article:modified_time" content = { modifiedTime } />
167+ ) }
168+ { articleSchema && (
169+ < script type = "application/ld+json" >
170+ { JSON . stringify ( articleSchema ) }
171+ </ script >
172+ ) }
53173 </ Head >
54174 < Layout
55175 { ...{
56176 title,
57177 description,
58- keywords,
178+ keywords : metaKeywords ,
59179 image,
60180 } }
61181 />
0 commit comments