Skip to content

Commit 638eec7

Browse files
authored
Improve wrapper handling for how-to links (#330)
1 parent 3f1626b commit 638eec7

File tree

3 files changed

+40
-65
lines changed

3 files changed

+40
-65
lines changed
Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
---
2-
import { z, type CollectionEntry } from "astro:content";
2+
import { type CollectionEntry } from "astro:content";
33
44
import { computeTitle } from "@/lib/guidelines";
5-
import { renderAndValidate } from "@/lib/zod";
65
import { getEntry } from "astro:content";
6+
import { load } from "cheerio";
77
88
interface Props {
99
entry: CollectionEntry<"guidelines"> | CollectionEntry<"requirements">;
@@ -20,40 +20,44 @@ const howtoPath = parentHowto
2020
? `${parentHowto === true ? idParts[1] : parentHowto}/${howtoSlug}/`
2121
: `${howtoSlug}/`;
2222
const baseUrl = "https://w3c.github.io/wcag3/how-to/";
23-
const { Content, remarkPluginFrontmatter } = await renderAndValidate(
24-
entry,
25-
z.object({
26-
description: z.string(),
27-
})
28-
);
29-
---
3023
31-
{
32-
howtoSlug ? (
33-
<div class="body-wrapper">
34-
<Fragment set:html={remarkPluginFrontmatter.description} />
35-
<aside class="doclinks">
36-
<p>
37-
<a href={`${baseUrl}${howtoPath}`}>
38-
<svg aria-hidden="true" class="i-info">
39-
<use xlink:href="img/icons.svg#i-info" />
40-
</svg>{" "}
41-
{entry.collection === "guidelines"
24+
function processHtml() {
25+
const entryHtml = entry.rendered!.html;
26+
if (!howtoSlug) return entryHtml;
27+
28+
const $ = load(entryHtml, null, false);
29+
const $wrappableElement = $("p, ul, ol")
30+
// Exclude nested elements (e.g. inside of a Note)
31+
.filter((_, el) => !$(el).parent().length)
32+
.first();
33+
if (!$wrappableElement.length)
34+
throw new Error(`${entry.id}: Can't find element to wrap with link to how-tos`);
35+
36+
$wrappableElement.wrap(`<div class="body-wrapper"></div>`).after(`
37+
<aside class="doclinks">
38+
<p>
39+
<a href="${baseUrl}${howtoPath}">
40+
<svg aria-hidden="true" class="i-info">
41+
<use xlink:href="img/icons.svg#i-info" />
42+
</svg>
43+
${
44+
entry.collection === "guidelines"
4245
? `How to meet ${computeTitle(entry)}`
43-
: `${computeTitle(entry)} methods`}
44-
</a>
45-
</p>
46-
</aside>
47-
</div>
48-
) : (
49-
<Fragment set:html={remarkPluginFrontmatter.description} />
50-
)
46+
: `${computeTitle(entry)} methods`
47+
}
48+
</a>
49+
</p>
50+
</aside>
51+
`);
52+
return $.html();
5153
}
54+
---
55+
5256
{
5357
entry.collection === "requirements" && entry.data.needsAdditionalResearch && (
5458
<p class="ednote">
5559
Needs <a href="#additional_research">additional research</a>
5660
</p>
5761
)
5862
}
59-
<Content />
63+
<Fragment set:html={processHtml()} />

src/lib/markdown/guidelines.ts

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
import type { RehypePlugin, RemarkPlugin } from "@astrojs/markdown-remark";
2-
import type { RootContent } from "hast";
1+
import type { RemarkPlugin } from "@astrojs/markdown-remark";
32

4-
import { toHtml } from "hast-util-to-html";
53
import { visit } from "unist-util-visit";
64
import type { VFile } from "vfile";
75

@@ -76,33 +74,5 @@ const customDirectives: RemarkPlugin = () => (tree, file) => {
7674
});
7775
};
7876

79-
/** Extracts leading paragraphs/lists' HTML to a separate value. */
80-
const extractLeadingContent: RehypePlugin = () => (tree, file) => {
81-
if (!isGuidelineFile(file)) return;
82-
const contentTags = ["p", "ul", "ol"];
83-
const leadingElements: RootContent[] = [];
84-
const textClass = `${getGuidelineFileType(file)}-text`;
85-
86-
for (
87-
let child = tree.children[0];
88-
child?.type === "text" || (child?.type === "element" && contentTags.includes(child.tagName));
89-
tree.children.shift() && (child = tree.children[0])
90-
) {
91-
if (child.type === "element") {
92-
const existingClass = child.properties.class;
93-
if (existingClass) child.properties.class += ` ${textClass}`;
94-
else child.properties.class = textClass;
95-
}
96-
leadingElements.push(child);
97-
}
98-
if (!leadingElements.length) file.fail("Leading content expected but not found.");
99-
100-
const html = toHtml(leadingElements, {
101-
allowDangerousCharacters: true,
102-
allowDangerousHtml: true,
103-
});
104-
getFrontmatter(file).description = html;
105-
};
106-
10777
export const guidelinesRemarkPlugins = [addEmptyTermNote, customDirectives];
108-
export const guidelinesRehypePlugins = [extractLeadingContent];
78+
export const guidelinesRehypePlugins = [];

src/styles/guidelines.css

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ a.internalDFN[title]:hover, .internalDFN[title]:active, a.internalDFN[title]:foc
6363
color: #404040;
6464
}
6565

66+
:is(.guideline, .requirement, .body-wrapper) > :is(p, ul, ol) {
67+
font-size: 110%;
68+
margin-top: 0;
69+
}
70+
6671
.guideline {
6772
margin-left: 4em;
6873
position: relative;
@@ -73,10 +78,6 @@ a.internalDFN[title]:hover, .internalDFN[title]:active, a.internalDFN[title]:foc
7378
position: relative;
7479
}
7580

76-
.guideline-text, .requirement-text {
77-
font-size: 110%;
78-
margin-top: 0;
79-
}
8081
.guideline h3, .requirement h4, .requirement h5 {
8182
width: 100%;
8283
margin-bottom: 0;

0 commit comments

Comments
 (0)