All files / packages/design-system-2-site/src/components MarkdownPage.tsx

100% Statements 7/7
95.23% Branches 20/21
100% Functions 1/1
100% Lines 7/7

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105                                                                                23x 23x 23x     23x                                   23x 1x                                         22x                                      
import { extractHeadings, extractLeadingHero, type RenderedMarkdown } from '@/lib/markdown';
import type { Crumb } from '@/components/Breadcrumbs';
import { DocShell } from '@/components/DocShell';
import { HeroSplit } from '@/components/HeroSplit';
import { PageFeedback } from '@/components/PageFeedback';
import { Pager, type PagerLink } from '@/components/Pager';
import { TabBar, type TabBarProps } from '@/components/TabBar';
import { ViewMarkdownButton } from '@/components/ViewMarkdownButton';
 
interface MarkdownPageProps extends RenderedMarkdown {
  tabs?: TabBarProps['tabs'];
  breadcrumbs?: Crumb[];
  /**
   * Raw markdown source for "Copy Markdown". Content pages pass it; the
   * page-bottom actions, divider and pager render only then.
   */
  markdown?: string;
  /** Subtitle under the title. */
  description?: string;
  prev?: PagerLink | null;
  next?: PagerLink | null;
  /** A category's landing page: a leading hero renders as the full-bleed compact banner. */
  isTopLevel?: boolean;
}
 
// Markdown source is trusted: authored in-repo, rendered at build time by the unified
// pipeline. No user-supplied HTML reaches this component.
export function MarkdownPage({
  frontmatter,
  html,
  tabs,
  breadcrumbs,
  markdown,
  description,
  prev,
  next,
  isTopLevel = false,
}: MarkdownPageProps) {
  // A leading hero carries the page title and background image; the layouts
  // below rebuild it as a compact banner or a side image.
  const { hero, rest, background } = extractLeadingHero(html);
  const title = frontmatter.title;
  const tabBar = tabs && tabs.length > 0 ? <TabBar tabs={tabs} /> : null;
 
  const body = (
    <>
      <article className="content-blocks" dangerouslySetInnerHTML={{ __html: rest }} />
      {markdown !== undefined && (
        <>
          {/* spacing-9 rhythm between content, actions, divider and pager. */}
          <div className="page-actions">
            <ViewMarkdownButton markdown={markdown} />
            <PageFeedback />
          </div>
          <hr className="page-divider" />
          <Pager prev={prev} next={next} />
        </>
      )}
    </>
  );
 
  // Top-level landing: full-bleed compact banner with only the title. These are
  // directory-style pages, so there's no in-page nav.
  if (isTopLevel && hero) {
    return (
      <>
        <div
          className="hero-banner hero-banner--compact markdown-page__banner"
          style={background ? { backgroundImage: background } : undefined}
        >
          {title && <h1>{title}</h1>}
        </div>
        <DocShell>
          {description && <p className="text-subtitle markdown-page__subtitle">{description}</p>}
          <div className="markdown-page__body">
            {tabBar}
            {body}
          </div>
        </DocShell>
      </>
    );
  }
 
  // Second level and below: breadcrumbs + title + subtitle, with the hero image
  // (if any) as a half-width side image.
  return (
    <DocShell
      toc={extractHeadings(rest)}
      heading={
        <>
          <HeroSplit
            breadcrumbs={breadcrumbs}
            title={title}
            description={description}
            image={hero && background ? background : undefined}
          />
          {tabBar}
        </>
      }
    >
      {body}
    </DocShell>
  );
}