diff --git a/.gitignore b/.gitignore index af5f0247e..81d7bf8f8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .idea .temp +.astro # build output dist/ diff --git a/src/components/Guide/GuideContent.astro b/src/components/Guide/GuideContent.astro index 3eeb4db1e..ed51c19a8 100644 --- a/src/components/Guide/GuideContent.astro +++ b/src/components/Guide/GuideContent.astro @@ -3,6 +3,7 @@ import { getGuideTableOfContent, type GuideFileType } from '../../lib/guide'; import MarkdownFile from '../MarkdownFile.astro'; import { TableOfContent } from '../TableOfContent/TableOfContent'; import { replaceVariables } from '../../lib/markdown'; +import { RelatedGuides } from './RelatedGuides'; interface Props { guide: GuideFileType; @@ -14,13 +15,21 @@ const allHeadings = guide.getHeadings(); const tableOfContent = getGuideTableOfContent(allHeadings); const showTableOfContent = tableOfContent.length > 0; +const showRelatedGuides = + guide?.frontmatter?.relatedGuides && + Object.keys(guide?.frontmatter?.relatedGuides).length > 0; const { frontmatter: guideFrontmatter, author } = guide; ---
{ - showTableOfContent && ( + (showTableOfContent || showRelatedGuides) && (
+
) diff --git a/src/components/Guide/RelatedGuides.tsx b/src/components/Guide/RelatedGuides.tsx new file mode 100644 index 000000000..85e121b65 --- /dev/null +++ b/src/components/Guide/RelatedGuides.tsx @@ -0,0 +1,70 @@ +import { useState } from 'react'; +import { cn } from '../../lib/classname'; +import { ChevronDown } from 'lucide-react'; + +type RelatedGuidesProps = { + relatedTitle?: string; + relatedGuides: Record; +}; + +export function RelatedGuides(props: RelatedGuidesProps) { + const { relatedTitle = 'Other Guides', relatedGuides } = props; + + const [isOpen, setIsOpen] = useState(false); + + const relatedGuidesArray = Object.entries(relatedGuides).map( + ([title, url]) => ({ + title, + url, + }), + ); + + return ( +
+

{relatedTitle}

+ + +
    + {relatedGuidesArray.map((relatedGuide) => ( +
  1. + { + if (!isOpen) { + return; + } + + setIsOpen(false); + }} + > + {relatedGuide.title} + +
  2. + ))} +
+
+ ); +} diff --git a/src/lib/guide.ts b/src/lib/guide.ts index a83b1aa84..809b02950 100644 --- a/src/lib/guide.ts +++ b/src/lib/guide.ts @@ -20,6 +20,8 @@ export interface GuideFrontmatter { priority: number; changefreq: 'daily' | 'weekly' | 'monthly' | 'yearly'; }; + relatedTitle?: string; + relatedGuides?: Record; tags: string[]; } @@ -116,5 +118,11 @@ export function getGuideTableOfContent(headings: HeadingType[]) { } }); + if (tableOfContents.length > 5) { + tableOfContents.forEach((group) => { + group.children = []; + }); + } + return tableOfContents; } diff --git a/src/lib/markdown.ts b/src/lib/markdown.ts index af0a1c2ae..3cc2a7f84 100644 --- a/src/lib/markdown.ts +++ b/src/lib/markdown.ts @@ -11,7 +11,7 @@ export function replaceVariables( currentYear: new Date().getFullYear().toString(), }; - return markdown.replace(/@([^@]+)@/g, (match, p1) => { + return markdown?.replace(/@([^@]+)@/g, (match, p1) => { return allVariables[p1] || match; }); } diff --git a/src/pages/frontend/job-description.astro b/src/pages/frontend/job-description.astro index c4ab5fb27..7022e25a5 100644 --- a/src/pages/frontend/job-description.astro +++ b/src/pages/frontend/job-description.astro @@ -12,7 +12,7 @@ const guide = await getGuideById(guideId); const { frontmatter: guideData } = guide!; const ogImageUrl = - guideData.seo.ogImageUrl || + guideData.seo?.ogImageUrl || getOpenGraphImageUrl({ group: 'guide', resourceId: guideId, @@ -20,9 +20,9 @@ const ogImageUrl = ---