/** * @file Swizzled DocItemContent component. * * This component is a swizzled version of the original DocItemContent component. * * Similar to Docusaurus' default `DocItemContent`, this component renders * the content of a documentation page. However, it also adds support for * support badges, and Authentik version badges. */ import "./styles.css"; import { SupportBadge } from "#components/SupportBadge.tsx"; import { VersionBadge } from "#components/VersionBadge.tsx"; import { useSyntheticTitle } from "#hooks/title.ts"; import { PreReleaseAdmonition } from "#theme/DocItem/Content/PreReleaseAdmonition.tsx"; import { useDoc } from "@docusaurus/plugin-content-docs/client"; import { ThemeClassNames } from "@docusaurus/theme-common"; import type { Props } from "@theme/DocItem/Content"; import Heading from "@theme/Heading"; import MDXContent from "@theme/MDXContent"; import clsx from "clsx"; import React, { JSX, useEffect } from "react"; class MarkdownLintError extends Error { constructor(message: string) { super(message); this.name = "MarkdownLintError"; } } function useBadgeLinterEffect() { const { frontMatter, metadata } = useDoc(); const { hide_title } = frontMatter; const { id } = metadata; useEffect(() => { if (hide_title) { console.debug(`Skipping badge linting for ${id} because \`hide_title\` is set`); return; } const invalidBadges = document.querySelectorAll(`.theme-doc-markdown > header + .badge, .theme-doc-markdown .markdown > .badge `); const badgeCount = invalidBadges.length; if (!badgeCount) return; const badgeContent = Array.from(invalidBadges, (badge) => `"${badge.textContent}"`); const message = `${id}: ${badgeCount} Badge(s) defined in Markdown content instead of the frontmatter:\n ${badgeContent.join("\n")}`; console.error(message); console.error(`Found ${badgeCount} invalid badges on ${id}`, invalidBadges); throw new MarkdownLintError(message); }, [hide_title, id]); } interface BadgesProps { badges: JSX.Element[]; } const BadgeGroup: React.FC = ({ badges }) => { if (!badges.length) return null; return (

{badges.map((badge, index) => ( {badge} ))}

); }; const DocItemContent: React.FC = ({ children }) => { const syntheticTitle = useSyntheticTitle(); const { frontMatter, metadata, contentTitle } = useDoc(); const { id } = metadata; const { // --- support_level, authentik_version, authentik_enterprise, authentik_preview, } = frontMatter; const preReleaseDoc = frontMatter.beta && metadata.id.startsWith("releases"); useBadgeLinterEffect(); const badges: JSX.Element[] = []; if (authentik_version) { badges.push(); } if (support_level) { badges.push(); } if (authentik_preview) { badges.push(Preview); } if (authentik_enterprise) { badges.push(Enterprise); } if (badges.length && !syntheticTitle) { throw new MarkdownLintError( `${id}: ${badges.length} Badge(s) found with a missing synthetic title. Remove the page heading and set it via the frontmatter.`, ); } if (frontMatter.title && contentTitle && frontMatter.title === contentTitle) { throw new MarkdownLintError( `${id}: Synthetic title "${frontMatter.title}" and content title "${contentTitle}" are the same. Remove the first heading and let the frontmatter set the title.`, ); } return (
{syntheticTitle ? (
{syntheticTitle}
) : null} {preReleaseDoc ? : null} {children}
); }; export default DocItemContent;