mirror of
https://github.com/cloudflare/cloudflare-docs.git
synced 2026-01-16 23:11:06 +00:00
[Docs Site] Add PartialsUsage component (#23608)
* [Docs Site] Add PartialsUsage component * naming and 1111 slugs
This commit is contained in:
parent
fb579fa3ab
commit
76069eb2ca
7 changed files with 228 additions and 88 deletions
|
|
@ -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<typeof props>;
|
||||
|
|
@ -22,70 +22,6 @@ const usage = await getComponentsUsage(component);
|
|||
<code>{usage.pages.size}</code> pages.
|
||||
</p>
|
||||
<Details header={`Pages which use ${component}`}>
|
||||
<p><strong>Pages</strong></p>
|
||||
<ul>
|
||||
{
|
||||
[...usage.pages]
|
||||
.filter((path) => path.startsWith("src/content/docs/"))
|
||||
.sort()
|
||||
.map((path) => {
|
||||
const slugified =
|
||||
"/" +
|
||||
path
|
||||
.replace("src/content/docs/", "")
|
||||
.replace(".mdx", "")
|
||||
.split("/")
|
||||
.map((segment) => slug(segment))
|
||||
.join("/") +
|
||||
"/";
|
||||
|
||||
return (
|
||||
<li>
|
||||
<a
|
||||
href={"https://developers.cloudflare.com" + slugified}
|
||||
target="_blank"
|
||||
>
|
||||
{slugified}
|
||||
</a>
|
||||
<span>
|
||||
-
|
||||
<a
|
||||
href={
|
||||
"https://github.com/cloudflare/cloudflare-docs/blob/production/" +
|
||||
path
|
||||
}
|
||||
target="_blank"
|
||||
>
|
||||
Source
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
<p><strong>Partials</strong></p>
|
||||
<ul>
|
||||
{
|
||||
[...usage.pages]
|
||||
.filter((path) => path.startsWith("src/content/partials/"))
|
||||
.sort()
|
||||
.map((path) => {
|
||||
return (
|
||||
<li>
|
||||
<a
|
||||
href={
|
||||
"https://github.com/cloudflare/cloudflare-docs/blob/production/" +
|
||||
path
|
||||
}
|
||||
target="_blank"
|
||||
>
|
||||
{path}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
<UsageList usage={usage} />
|
||||
</Details>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -7,12 +7,13 @@ type Props = z.infer<typeof props>;
|
|||
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);
|
||||
---
|
||||
|
||||
<details open={open}>
|
||||
<details open={open} id={id}>
|
||||
<summary set:html={marked.parse(header)} />
|
||||
<slot />
|
||||
</details>
|
||||
|
|
|
|||
41
src/components/PartialsUsage.astro
Normal file
41
src/components/PartialsUsage.astro
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
import { getPartialsUsage } from "~/util/components";
|
||||
|
||||
import Details from "./Details.astro";
|
||||
import UsageList from "./UsageList.astro";
|
||||
|
||||
const partials = await getPartialsUsage();
|
||||
---
|
||||
|
||||
<Details header="Usage" id="partials-container">
|
||||
{
|
||||
[...Object.entries(partials)]
|
||||
.sort((a, b) => a[0].localeCompare(b[0]))
|
||||
.map(([name, usage]) => (
|
||||
<Details header={name} id={name}>
|
||||
<UsageList usage={usage} />
|
||||
</Details>
|
||||
))
|
||||
}
|
||||
</Details>
|
||||
|
||||
<script>
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
console.log(params);
|
||||
const partial = params.get("partial");
|
||||
|
||||
if (partial) {
|
||||
const container = document.querySelector<HTMLDetailsElement>(
|
||||
"#partials-container",
|
||||
);
|
||||
const details = document.querySelector<HTMLDetailsElement>(
|
||||
`#${CSS.escape(partial)}`,
|
||||
);
|
||||
|
||||
if (container && details) {
|
||||
container.open = true;
|
||||
details.open = true;
|
||||
details.scrollIntoView();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
93
src/components/UsageList.astro
Normal file
93
src/components/UsageList.astro
Normal file
|
|
@ -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);
|
||||
---
|
||||
|
||||
<>
|
||||
<p>
|
||||
Used <strong>{usage.count}</strong> times.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Pages</strong>
|
||||
</p>
|
||||
<ul>
|
||||
{
|
||||
[...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 (
|
||||
<li>
|
||||
<a
|
||||
href={"https://developers.cloudflare.com" + slugified}
|
||||
target="_blank"
|
||||
>
|
||||
{slugified}
|
||||
</a>
|
||||
<span>
|
||||
-
|
||||
<a
|
||||
href={
|
||||
"https://github.com/cloudflare/cloudflare-docs/blob/production/" +
|
||||
path
|
||||
}
|
||||
target="_blank"
|
||||
>
|
||||
Source
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
<p>
|
||||
<strong>Partials</strong>
|
||||
</p>
|
||||
<ul>
|
||||
{
|
||||
[...usage.pages]
|
||||
.filter((path) => path.startsWith("src/content/partials/"))
|
||||
.sort()
|
||||
.map((path) => {
|
||||
return (
|
||||
<li>
|
||||
<a
|
||||
href={
|
||||
"https://github.com/cloudflare/cloudflare-docs/blob/production/" +
|
||||
path
|
||||
}
|
||||
target="_blank"
|
||||
>
|
||||
{path}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</>
|
||||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
<Render file="simple-props" params={{
|
||||
name: "world",
|
||||
}} />
|
||||
<Render
|
||||
file="simple-props"
|
||||
params={{
|
||||
name: "world",
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### Inputs
|
||||
|
||||
- `file` <Type text="string" />
|
||||
|
||||
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` <Type text="string" /> <MetaInfo text="optional" />
|
||||
|
||||
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 `<Render file="thing" product="dns" />`
|
||||
`docs/fundamentals/index.mdx` uses `<Render file="thing" product="dns" />`
|
||||
|
||||
`partials/dns/thing.mdx` must use `<Render file="thing2" product="dns" />` as `product` cannot be inferred.
|
||||
`partials/dns/thing.mdx` must use `<Render file="thing2" product="dns" />` as `product` cannot be inferred.
|
||||
|
||||
:::
|
||||
:::
|
||||
|
||||
- `params` <Type text="object" /> <MetaInfo text="optional" />
|
||||
|
||||
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";
|
||||
|
||||
<Render file="link-in-props" params={{
|
||||
link: "/style-guide/components/render/#links"
|
||||
}} />
|
||||
<Render
|
||||
file="link-in-props"
|
||||
params={{
|
||||
link: "/style-guide/components/render/#links",
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
#### Images
|
||||
|
|
@ -185,4 +191,8 @@ import { Render } from "~/components";
|
|||
<hr />
|
||||
|
||||
<Render file="optional-props" params={{ product: "Thing Three" }} />
|
||||
```
|
||||
```
|
||||
|
||||
## Partials
|
||||
|
||||
<PartialsUsage />
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { visit } from "unist-util-visit";
|
|||
type Usage = { count: number; pages: Set<string> };
|
||||
|
||||
let usages: Record<string, Usage>;
|
||||
let partials: Record<string, Usage>;
|
||||
|
||||
export function getComponentsUsage(): Promise<Record<string, Usage>>;
|
||||
export function getComponentsUsage(component: string): Promise<Usage>;
|
||||
|
|
@ -60,3 +61,60 @@ export async function getComponentsUsage(
|
|||
|
||||
return usages;
|
||||
}
|
||||
|
||||
export async function getPartialsUsage(): Promise<Record<string, Usage>> {
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue