Skip to content

Commit cef1d52

Browse files
authored
Implement client-side filtering for previews (#351)
1 parent 3dc9018 commit cef1d52

File tree

5 files changed

+77
-22
lines changed

5 files changed

+77
-22
lines changed

src/components/guidelines/Guidelines.astro

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ const groups = await buildGuidelinesHierarchy();
1515
<h4>{computeTitle(guideline)}</h4>
1616
<EntryText entry={guideline} />
1717
{guideline.data.requirements.map((requirement) => (
18-
<section class="requirement" data-status={requirement.data.status} data-requirement-type={requirement.data.type}>
18+
<section
19+
class="requirement"
20+
data-status={requirement.data.status}
21+
data-requirement-type={requirement.data.type}
22+
data-skip={requirement.skippable}
23+
>
1924
<h5>{computeTitle(requirement)}</h5>
2025
<EntryText entry={requirement} />
2126
</section>

src/components/respec/GuidelinesRespec.astro

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
---
2+
import { isDevOrPreview } from "@/lib/constants";
3+
import GuidelinesRespecDev from "./GuidelinesRespecDev.astro";
4+
25
// ReSpec config and functions are defined in a component with an inline script to allow
36
// separating them in a way that will be conducive to sending to spec-generator, while
47
// avoiding Vite warnings which may occur when referencing scripts under public/
@@ -449,13 +452,15 @@
449452
href: "https://www.etsi.org/deliver/etsi_tr/101500_101599/101550/01.01.01_60/tr_101550v010101p.pdf",
450453
},
451454
"iso13066-1": {
452-
"href": "https://www.iso.org/standard/53770.html",
453-
"title": "Information technology — Interoperability with assistive technology (AT) - Part 1: Requirements and recommendations for interoperability",
454-
"status": "Published",
455-
"publisher": "ISO/IEC",
456-
"isoNumber": "ISO 13066-1:2011",
457-
"rawDate": "2011-05"
455+
href: "https://www.iso.org/standard/53770.html",
456+
title:
457+
"Information technology — Interoperability with assistive technology (AT) - Part 1: Requirements and recommendations for interoperability",
458+
status: "Published",
459+
publisher: "ISO/IEC",
460+
isoNumber: "ISO 13066-1:2011",
461+
rawDate: "2011-05",
458462
},
459463
},
460464
};
461465
</script>
466+
{isDevOrPreview && <GuidelinesRespecDev />}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<script is:inline>
2+
function filterSkippable() {
3+
const params = new URLSearchParams(location.search);
4+
if (params.get("skip")) document.querySelectorAll("[data-skip]").forEach((el) => el.remove());
5+
}
6+
respecConfig.preProcess.push(filterSkippable);
7+
8+
function addSkipUI() {
9+
const newUrl = new URL(location);
10+
if (newUrl.searchParams.get("skip")) newUrl.searchParams.delete("skip");
11+
else newUrl.searchParams.set("skip", "true");
12+
13+
const respecEl = document.getElementById("respec-ui");
14+
const el = document.createElement("a");
15+
el.href = "" + newUrl;
16+
el.style.position = "fixed";
17+
el.style.top = "60px";
18+
el.style.right = getComputedStyle(respecEl).right;
19+
el.textContent = newUrl.searchParams.get("skip")
20+
? "Preview without early-stage entries"
21+
: "Preview with all entries";
22+
respecEl.after(el);
23+
}
24+
respecConfig.postProcess.push(addSkipUI);
25+
</script>

src/lib/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/** Indicates that the build is running in a dev or PR preview environment. */
2+
export const isDevOrPreview = !!import.meta.env.DEV || !!import.meta.env.NETLIFY;

src/lib/guidelines.ts

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,49 @@
11
import { getCollection, getEntry, type CollectionEntry, type CollectionKey } from "astro:content";
22
import capitalize from "lodash-es/capitalize";
3+
import difference from "lodash-es/difference";
4+
5+
import { isDevOrPreview } from "./constants";
36

47
/**
5-
* Returns a filtered list of requirement/assertion slugs under the given group and guideline,
6-
* excluding any marked as needing additional research if WCAG_SKIP_WIP is set.
8+
* Returns a list of requirement/assertion slugs under the given group and guideline that would be
9+
* skipped for a major publication (i.e. exploratory/placeholder or needs additional research).
10+
* Note this returns an empty array when building for situations that do not allow for skipping
11+
* either at build time or client-side (e.g. Editor's Drafts).
712
*/
8-
async function getFilteredRequirements(groupId: string, guidelineSlug: string) {
13+
async function determineSkippableRequirements(groupId: string, guidelineSlug: string) {
14+
// Only populate when running a build that needs to skip at build time or client-side
15+
if (!import.meta.env.WCAG_SKIP_WIP && !isDevOrPreview) return [];
16+
917
const guideline = await getEntry("guidelines", `${groupId}/${guidelineSlug}`);
1018
if (!guideline) throw new Error(`Unresolvable guideline ID: ${guidelineSlug}`);
1119

12-
const filteredRequirements: string[] = [];
20+
const skippableRequirements: string[] = [];
1321
for (const requirementSlug of guideline.data.children) {
1422
const requirement = await getEntry(
1523
"requirements",
1624
`${groupId}/${guidelineSlug}/${requirementSlug}`
1725
);
1826
if (!requirement) throw new Error(`Unresolvable requirement ID: ${requirementSlug}`);
1927
if (
20-
import.meta.env.WCAG_SKIP_WIP &&
21-
(requirement.data.needsAdditionalResearch ||
22-
requirement.data.status === "placeholder" ||
23-
requirement.data.status === "exploratory")
24-
)
25-
continue;
26-
filteredRequirements.push(requirementSlug);
28+
requirement.data.needsAdditionalResearch ||
29+
requirement.data.status === "placeholder" ||
30+
requirement.data.status === "exploratory"
31+
) {
32+
skippableRequirements.push(requirementSlug);
33+
}
2734
}
28-
return filteredRequirements;
35+
return skippableRequirements;
36+
}
37+
38+
/** Extension of Requirement to facilitate client-side skipping in previews */
39+
interface SkippableRequirement extends CollectionEntry<"requirements"> {
40+
skippable?: boolean;
2941
}
3042

3143
let groupIds = (await getCollection("groupOrder")).map(({ id }) => id);
3244
let groups: Record<string, CollectionEntry<"groups">> = {};
3345
let guidelines: Record<string, CollectionEntry<"guidelines">> = {};
34-
let requirements: Record<string, CollectionEntry<"requirements">> = {};
46+
let requirements: Record<string, SkippableRequirement> = {};
3547

3648
export async function buildGuidelinesHierarchy() {
3749
// Cache collated collection data for subsequent calls
@@ -44,16 +56,22 @@ export async function buildGuidelinesHierarchy() {
4456
for (const guidelineSlug of group.data.children) {
4557
const guideline = await getEntry("guidelines", `${groupId}/${guidelineSlug}`);
4658
if (!guideline) throw new Error(`Unresolvable guideline ID: ${guidelineSlug}`);
47-
guideline.data.children = await getFilteredRequirements(groupId, guidelineSlug);
4859
guidelines[guideline.id] = guideline;
4960

61+
const skippableChildren = await determineSkippableRequirements(groupId, guidelineSlug);
62+
if (import.meta.env.WCAG_SKIP_WIP)
63+
// Filter children directly in case of build-time skip
64+
guideline.data.children = difference(guideline.data.children, skippableChildren);
65+
5066
for (const requirementSlug of guideline.data.children) {
5167
const requirement = await getEntry(
5268
"requirements",
5369
`${groupId}/${guidelineSlug}/${requirementSlug}`
5470
);
5571
if (!requirement) throw new Error(`Unresolvable requirement ID: ${requirementSlug}`);
56-
requirements[requirement.id] = requirement;
72+
requirements[requirement.id] = skippableChildren.includes(requirementSlug)
73+
? { ...requirement, skippable: true }
74+
: requirement;
5775
}
5876
}
5977
}

0 commit comments

Comments
 (0)