diff --git a/src/components/ComponentUsage.astro b/src/components/ComponentUsage.astro index fb4cf15c63c7b33..c61b5a83b52400d 100644 --- a/src/components/ComponentUsage.astro +++ b/src/components/ComponentUsage.astro @@ -1,8 +1,8 @@ --- import { z } from "astro:schema"; import { getComponentsUsage } from "~/util/components"; -import { slug } from "github-slugger"; +import UsageList from "./UsageList.astro"; import Details from "./Details.astro"; type Props = z.infer; @@ -22,70 +22,6 @@ const usage = await getComponentsUsage(component); {usage.pages.size} pages.

-

Pages

- -

Partials

- +
diff --git a/src/components/Details.astro b/src/components/Details.astro index 2ac10fee8c83bb3..94be66c3bd4ece4 100644 --- a/src/components/Details.astro +++ b/src/components/Details.astro @@ -7,12 +7,13 @@ type Props = z.infer; const props = z.object({ header: z.string(), open: z.boolean().optional(), + id: z.string().optional(), }); -const { header, open } = props.parse(Astro.props); +const { header, open, id } = props.parse(Astro.props); --- -
+
diff --git a/src/components/PartialsUsage.astro b/src/components/PartialsUsage.astro new file mode 100644 index 000000000000000..c4d6d4435eacba9 --- /dev/null +++ b/src/components/PartialsUsage.astro @@ -0,0 +1,41 @@ +--- +import { getPartialsUsage } from "~/util/components"; + +import Details from "./Details.astro"; +import UsageList from "./UsageList.astro"; + +const partials = await getPartialsUsage(); +--- + +
+ { + [...Object.entries(partials)] + .sort((a, b) => a[0].localeCompare(b[0])) + .map(([name, usage]) => ( +
+ +
+ )) + } +
+ + diff --git a/src/components/UsageList.astro b/src/components/UsageList.astro new file mode 100644 index 000000000000000..4fb06cb78e45205 --- /dev/null +++ b/src/components/UsageList.astro @@ -0,0 +1,93 @@ +--- +import { z } from "astro:schema"; +import { slug } from "github-slugger"; + +const props = z.object({ + usage: z.object({ + count: z.number(), + pages: z.set(z.string()), + }), +}); + +const { usage } = props.parse(Astro.props); +--- + +<> +

+ Used {usage.count} times. +

+

+ Pages +

+
    + { + [...usage.pages] + .filter((path) => path.startsWith("src/content/docs/")) + .sort() + .map((path) => { + const slugified = + "/" + + path + .replace("src/content/docs/", "") + .replace(".mdx", "") + .split("/") + .map((segment) => { + if (segment === "1.1.1.1") { + return segment; + } + return slug(segment); + }) + .join("/") + + "/"; + + return ( +
  • + + {slugified} + + + - + + Source + + +
  • + ); + }) + } +
+

+ Partials +

+
    + { + [...usage.pages] + .filter((path) => path.startsWith("src/content/partials/")) + .sort() + .map((path) => { + return ( +
  • + + {path} + +
  • + ); + }) + } +
+ diff --git a/src/components/index.ts b/src/components/index.ts index f401e399bbc8e96..ce408887cbbcf14 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -41,6 +41,7 @@ export { default as PagesBuildEnvironmentTools } from "./PagesBuildEnvironmentTo export { default as PagesBuildPreset } from "./PagesBuildPreset.astro"; export { default as PagesBuildPresetsTable } from "./PagesBuildPresetsTable.astro"; export { default as PagesLanguageSupport } from "./PagesLanguageSupport.astro"; +export { default as PartialsUsage } from "./PartialsUsage.astro"; export { default as Plan } from "./Plan.astro"; export { default as PlanInfo } from "./PlanInfo.astro"; export { default as ProductChangelog } from "./ProductChangelog.astro"; diff --git a/src/content/docs/style-guide/components/render.mdx b/src/content/docs/style-guide/components/render.mdx index 7cdb26fcce192cc..c3bbfc04e602ad0 100644 --- a/src/content/docs/style-guide/components/render.mdx +++ b/src/content/docs/style-guide/components/render.mdx @@ -4,7 +4,7 @@ styleGuide: component: Render --- -import { Code, Details, Type, MetaInfo } from "~/components"; +import { Code, Details, Type, MetaInfo, PartialsUsage } from "~/components"; The `Render` component allows us to include a "partial", a reusable Markdown snippet, onto a page. @@ -15,40 +15,43 @@ It also accepts parameters that can be used as variables within the partial, so ```mdx live import { Render } from "~/components"; - + ``` ### Inputs - `file` - This should be the name of the partial, without the containing directory or file extension. For example, `/partials/style-guide/hello.mdx` would be `file="hello"`. + This should be the name of the partial, without the containing directory or file extension. For example, `/partials/style-guide/hello.mdx` would be `file="hello"`. - `product` - By default, it will look for partials in the same product folder as the current page. You can use this to specify a different product. + By default, it will look for partials in the same product folder as the current page. You can use this to specify a different product. - :::caution + :::caution - When using the `Render` component inside partials, the original `product` is lost. + When using the `Render` component inside partials, the original `product` is lost. - For example, if there are three files: + For example, if there are three files: - 1. `docs/fundamentals/index.mdx` - 2. `partials/dns/thing.mdx` - 3. `partials/dns/thing2.mdx` + 1. `docs/fundamentals/index.mdx` + 2. `partials/dns/thing.mdx` + 3. `partials/dns/thing2.mdx` - `docs/fundamentals/index.mdx` uses `` + `docs/fundamentals/index.mdx` uses `` - `partials/dns/thing.mdx` must use `` as `product` cannot be inferred. + `partials/dns/thing.mdx` must use `` as `product` cannot be inferred. - ::: + ::: - `params` - If you wish to substitute values inside your partial, you can use pass params which can be referenced in your partial. Refer to [properties](#properties). + If you wish to substitute values inside your partial, you can use pass params which can be referenced in your partial. Refer to [properties](#properties). ## Properties @@ -128,9 +131,12 @@ import linkRaw from "~/content/partials/style-guide/link-in-props.mdx?raw"; ```mdx live import { Render } from "~/components"; - + ``` #### Images @@ -185,4 +191,8 @@ import { Render } from "~/components";
-``` \ No newline at end of file +``` + +## Partials + + diff --git a/src/util/components.ts b/src/util/components.ts index 7aac65ac48bf345..65d8063f8e06fd5 100644 --- a/src/util/components.ts +++ b/src/util/components.ts @@ -12,6 +12,7 @@ import { visit } from "unist-util-visit"; type Usage = { count: number; pages: Set }; let usages: Record; +let partials: Record; export function getComponentsUsage(): Promise>; export function getComponentsUsage(component: string): Promise; @@ -60,3 +61,60 @@ export async function getComponentsUsage( return usages; } + +export async function getPartialsUsage(): Promise> { + if (!partials) { + partials = {}; + + const entities = await readdir("./src/content/", { + recursive: true, + withFileTypes: true, + }); + + const files = entities.filter( + (entity) => entity.isFile() && entity.name.endsWith(".mdx"), + ); + + for (const file of files) { + const fullName = file.parentPath + "/" + file.name; + const content = await readFile(fullName, "utf8"); + + if (!content.includes("import")) continue; + + const tree = fromMarkdown(content, { + extensions: [mdxjs()], + mdastExtensions: [mdxFromMarkdown()], + }); + + visit(tree, ["mdxJsxFlowElement", "mdxJsxTextElement"], function (node) { + const typed = node as MdxJsxFlowElement | MdxJsxTextElement; + + if (!typed.name || typed.name[0] === typed.name[0].toLowerCase()) + return; + + if (typed.name === "Render") { + const file = typed.attributes.find( + (attr) => attr.type === "mdxJsxAttribute" && attr.name === "file", + )?.value; + + let product = typed.attributes.find( + (attr) => + attr.type === "mdxJsxAttribute" && attr.name === "product", + )?.value; + + if (!product) { + product = fullName.split("/")[3]; + } + + const partialName = `${product}/${file}`; + + partials[partialName] ||= { count: 0, pages: new Set() }; + partials[partialName].count++; + partials[partialName].pages.add(fullName); + } + }); + } + } + + return partials; +}