diff --git a/demo/docs/customization/doccard.mdx b/demo/docs/customization/doccard.mdx new file mode 100644 index 000000000..0a304bf02 --- /dev/null +++ b/demo/docs/customization/doccard.mdx @@ -0,0 +1,165 @@ +--- +id: doccard +hide_title: true +sidebar_label: DocCard Markdown +title: DocCard Markdown +description: Swizzle the DocCard component to render Markdown in card descriptions. +--- + +## Overview + +The default DocCard component used by Docusaurus displays the `description` field +as plain text. Any Markdown inside the description is escaped rather than +rendered. To support Markdown, you can swizzle the component and update it to use +`@theme/Markdown`. + +## Swizzling the component + +Run the swizzle command from your site directory and choose the **eject** option +when prompted: + +```bash +npx docusaurus swizzle @docusaurus/theme-classic DocCard +``` + +This will create `src/theme/DocCard/index.tsx` in your project. Replace its +contents with the following: + +```tsx title="src/theme/DocCard/index.tsx" +import React, { type ReactNode } from "react"; + +import isInternalUrl from "@docusaurus/isInternalUrl"; +import Link from "@docusaurus/Link"; +import type { + PropSidebarItemCategory, + PropSidebarItemLink, +} from "@docusaurus/plugin-content-docs"; +import { + useDocById, + findFirstSidebarItemLink, +} from "@docusaurus/plugin-content-docs/lib/client/docsUtils"; +import { usePluralForm } from "@docusaurus/theme-common"; +import { translate } from "@docusaurus/Translate"; +import type { Props } from "@theme/DocCard"; +import Heading from "@theme/Heading"; +import Markdown from "@theme/Markdown"; +import clsx from "clsx"; + +import styles from "./styles.module.css"; + +function useCategoryItemsPlural() { + const { selectMessage } = usePluralForm(); + return (count: number) => + selectMessage( + count, + translate( + { + message: "1 item|{count} items", + id: "theme.docs.DocCard.categoryDescription.plurals", + description: + "The default description for a category card in the generated index about how many items this category includes", + }, + { count } + ) + ); +} + +function CardContainer({ + className, + href, + children, +}: { + className?: string; + href: string; + children: ReactNode; +}): ReactNode { + return ( + + {children} + + ); +} + +function CardLayout({ + className, + href, + icon, + title, + description, +}: { + className?: string; + href: string; + icon: ReactNode; + title: string; + description?: string; +}): ReactNode { + return ( + + + {icon} {title} + + {description && ( + + {description} + + )} + + ); +} + +function CardCategory({ item }: { item: PropSidebarItemCategory }): ReactNode { + const href = findFirstSidebarItemLink(item); + const categoryItemsPlural = useCategoryItemsPlural(); + + // Unexpected: categories that don't have a link have been filtered upfront + if (!href) { + return null; + } + + return ( + + ); +} + +function CardLink({ item }: { item: PropSidebarItemLink }): ReactNode { + const icon = isInternalUrl(item.href) ? "📄️" : "🔗"; + const doc = useDocById(item.docId ?? undefined); + return ( + + ); +} + +export default function DocCard({ item }: Props): ReactNode { + switch (item.type) { + case "link": + return ; + case "category": + return ; + default: + throw new Error(`unknown item type ${JSON.stringify(item)}`); + } +} +``` +