Files
awesome-copilot/website/src/components/brand/PlaybookArticleBody.tsx
T
Aaron Powell 31f586489e fix(website): show real contributor count on every page shell
The contributor badge rendered 0 on Playbook, Cookbook, home and custom
pages, and reverted to 0 on hydration everywhere else.

Two causes:
- Shells that bypass PageShell (LearningArticleLayout, PlaybookIndex,
  PlaybookArticleBody, CookbookIndex, HomePage, TopNav, Custom) defaulted
  contributorsTotal to 0 instead of the site-data value.
- site-data read .all-contributorsrc with node:fs at module scope. Those
  shells are client:load hydrated, so the read threw in the browser and
  the count reset to 0 after hydration.

The count is now read once in astro.config.mjs and inlined through
vite.define as __CONTRIBUTORS_TOTAL__, so it is a literal in both the
server render and the client bundle.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 80686fef-efe3-4cdd-8cd6-bfa61a5d0af6
2026-08-17 12:31:25 +10:00

101 lines
2.7 KiB
TypeScript

import { AlertIcon, MarkGithubIcon } from "@primer/octicons-react";
import {
LearningArticleLayout,
type TocSection,
} from "./LearningArticleLayout";
import type {
ArticleBlock,
ArticleSection,
CalloutKind,
} from "../../lib/playbook-article";
import { pageHref } from "./pageHref";
import type { SearchItem } from "./searchIndex";
import { contributorsTotal as siteContributorsTotal } from "../../lib/site-data";
import styles from "./styles/github-copilot-app.module.css";
const CALLOUT_TITLES: Record<CalloutKind, string> = {
note: "Note",
tip: "Pro tip",
caution: "Caution",
};
/**
* Static sibling of `ProTip`. Article bodies are prerendered, so this variant
* reuses the same prototype classes and drops the dismiss control that would
* require client state.
*/
function Callout({ kind, html }: { kind: CalloutKind; html: string }) {
return (
<aside className={styles.proTip}>
<div className={styles.proTipHeader}>
<span className={styles.proTipMark}>
{kind === "caution" ? (
<AlertIcon size={20} />
) : (
<MarkGithubIcon size={20} />
)}
</span>
<span className={styles.proTipTitle}>{CALLOUT_TITLES[kind]}</span>
</div>
<div
className={styles.proTipBody}
dangerouslySetInnerHTML={{ __html: html }}
/>
</aside>
);
}
function Block({ block, index }: { block: ArticleBlock; index: number }) {
if (block.type === "callout") {
return <Callout key={index} kind={block.kind} html={block.html} />;
}
return <div key={index} dangerouslySetInnerHTML={{ __html: block.html }} />;
}
export function PlaybookArticleBody({
slug,
breadcrumbLabel,
title,
description,
sections,
tocSections,
searchIndex = [],
contributorsTotal = siteContributorsTotal,
}: {
/** Site path of this article, e.g. `learning-hub/agentic-workflows`. */
slug: string;
breadcrumbLabel: string;
title: string;
description: string;
sections: ArticleSection[];
tocSections: TocSection[];
searchIndex?: SearchItem[];
contributorsTotal?: number;
}) {
return (
<LearningArticleLayout
pageHref={pageHref}
currentPage={slug}
breadcrumbLabel={breadcrumbLabel}
heroTitle={title}
heroSubtitle={description}
tocSections={tocSections}
searchIndex={searchIndex}
contributorsTotal={contributorsTotal}
>
{sections.map((section) => (
<section
key={section.id}
id={section.id}
className={styles.articleSection}
>
{section.blocks.map((block, index) => (
<Block key={index} block={block} index={index} />
))}
</section>
))}
</LearningArticleLayout>
);
}