Skip to content

Commit 240c25f

Browse files
committed
fix: address PR #90 review comments
- workflows/a11y.yml, responsive.yaml: add permissions: contents: read (GitHub Advanced Security — GITHUB_TOKEN least-privilege) - .vscode/settings.json: remove chat.tools.terminal.autoApprove (security footgun — keep in local user settings only) - src/output.ts + output.test.ts: replace Markdown link syntax in <summary> with <a href> HTML (GFM does not render [text](url) inside HTML blocks) - ComparisonTable.vue: remove target=_blank / rel / ext-link SVG icon from internal doc links; also remove orphaned .ct-ext-icon CSS rules - scripts/responsive.pw.ts: only skip position:fixed in overflow detection; VitePress nav elements (.VPNav/.VPNavBar/.VPLocalNav/.VPFlyout) are now whitelisted by class instead of blanket-skipping all sticky elements — fixes potential false negatives for non-nav sticky content
1 parent 4dbb551 commit 240c25f

File tree

6 files changed

+26
-56
lines changed

6 files changed

+26
-56
lines changed

.github/workflows/a11y.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ concurrency:
4343
group: a11y-${{ github.ref }}
4444
cancel-in-progress: true
4545

46+
permissions:
47+
contents: read
48+
4649
jobs:
4750
audit:
4851
name: WCAG 2.1 AA pages audit

.vscode/settings.json

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1 @@
1-
{
2-
"chat.tools.terminal.autoApprove": {
3-
"/^git checkout -b feat/promotion-polish && git add -A && git diff --cached --stat$/": {
4-
"approve": true,
5-
"matchCommandLine": true
6-
}
7-
}
8-
}
1+
{}

docs/.vitepress/theme/ComparisonTable.vue

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -108,31 +108,8 @@ const ROWS: Row[] = [
108108
<tbody>
109109
<tr v-for="row in ROWS" :key="row.feature" class="ct-row">
110110
<td class="ct-feature">
111-
<a
112-
v-if="row.docLink"
113-
:href="row.docLink"
114-
target="_blank"
115-
rel="noopener noreferrer"
116-
class="ct-feature-link"
117-
>
118-
<span class="ct-feature-title">
119-
{{ row.feature }}
120-
<svg
121-
class="ct-ext-icon"
122-
aria-hidden="true"
123-
width="11"
124-
height="11"
125-
viewBox="0 0 24 24"
126-
fill="none"
127-
stroke="currentColor"
128-
stroke-width="2"
129-
stroke-linecap="round"
130-
stroke-linejoin="round"
131-
>
132-
<line x1="7" y1="17" x2="17" y2="7" />
133-
<polyline points="7 7 17 7 17 17" />
134-
</svg>
135-
</span>
111+
<a v-if="row.docLink" :href="row.docLink" class="ct-feature-link">
112+
<span class="ct-feature-title">{{ row.feature }}</span>
136113
<span class="ct-feature-desc">{{ row.desc }}</span>
137114
</a>
138115
<span v-else class="ct-feature-plain">
@@ -350,16 +327,6 @@ thead tr {
350327
color: var(--vp-c-text-2);
351328
}
352329
353-
.ct-ext-icon {
354-
opacity: 0.35;
355-
flex-shrink: 0;
356-
transition: opacity 0.15s;
357-
}
358-
359-
.ct-feature-link:hover .ct-ext-icon {
360-
opacity: 0.75;
361-
}
362-
363330
.ct-cell {
364331
padding: 14px 12px;
365332
text-align: center;

scripts/responsive.pw.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,13 @@ interface OverflowHit {
7474
* the overflow is consumed inside that scroll container, not the page.
7575
* 2. Any ancestor is `position: fixed`: fixed containers are isolated from
7676
* the page scroll. Their children can overflow the container but NEVER add
77-
* to the document's horizontal scroll width (e.g. VitePress sticky navbar
78-
* flyout menus at narrow-tablet breakpoints).
77+
* to the document's horizontal scroll width.
7978
* 3. The element itself is `position: fixed` (same reasoning).
80-
* 4. The element is invisible (`visibility: hidden` covers closed VitePress
79+
* 4. The element (or an ancestor) matches a known VitePress nav class
80+
* (.VPNav, .VPNavBar, .VPLocalNav, .VPFlyout): these use `position: sticky`
81+
* and their flyout menus can temporarily exceed the viewport without
82+
* representing a real page-level overflow regression.
83+
* 5. The element is invisible (`visibility: hidden` covers closed VitePress
8184
* flyout panels that stay in the DOM but are not rendered).
8285
*/
8386
async function findOverflowingElements(page: Page): Promise<OverflowHit[]> {
@@ -92,19 +95,23 @@ async function findOverflowingElements(page: Page): Promise<OverflowHit[]> {
9295
const s = window.getComputedStyle(parent);
9396
// Non-visible overflow-x: overflow absorbed by this scroll container
9497
if (s.overflowX !== "visible") return true;
95-
// Fixed or sticky ancestor: children live in a separate layer and
98+
// Fixed ancestor: children live in a separate stacking context and
9699
// can never contribute to the document horizontal scroll width.
97-
// VitePress uses position:sticky (not fixed) for .VPNav/.VPNavBar.
98-
if (s.position === "fixed" || s.position === "sticky") return true;
100+
if (s.position === "fixed") return true;
101+
// VitePress nav elements (sticky) — flyout menus can temporarily
102+
// exceed the viewport; skip them by class to avoid false positives.
103+
if (parent.matches(".VPNav, .VPNavBar, .VPLocalNav, .VPFlyout")) return true;
99104
parent = parent.parentElement;
100105
}
101106
return false;
102107
}
103108

104109
for (const el of document.querySelectorAll("body *")) {
105110
const s = window.getComputedStyle(el);
106-
// Skip the element itself if fixed or sticky (same isolation rule)
107-
if (s.position === "fixed" || s.position === "sticky") continue;
111+
// Skip fixed elements (isolated stacking context)
112+
if (s.position === "fixed") continue;
113+
// Skip VitePress nav containers (sticky, known flyout false positives)
114+
if ((el as Element).closest(".VPNav, .VPNavBar, .VPLocalNav, .VPFlyout")) continue;
108115
// Skip invisible elements (closed VitePress flyout panels, etc.)
109116
if (s.visibility === "hidden" || s.display === "none") continue;
110117

src/output.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ describe("buildReplayDetails", () => {
190190
const out = buildReplayDetails(groups, QUERY, ORG, new Set(), new Set());
191191
expect(out).toContain("<details>");
192192
expect(out).toContain(
193-
"<summary>[github-code-search](https://fulll.github.io/github-code-search/) replay command</summary>",
193+
'<summary><a href="https://fulll.github.io/github-code-search/">github-code-search</a> replay command</summary>',
194194
);
195195
expect(out).toContain("```bash");
196196
expect(out).toContain("</details>");
@@ -296,7 +296,7 @@ describe("buildMarkdownOutput", () => {
296296
const out = buildMarkdownOutput(groups, QUERY, ORG, new Set(), new Set());
297297
expect(out).toContain("<details>");
298298
expect(out).toContain(
299-
"<summary>[github-code-search](https://fulll.github.io/github-code-search/) replay command</summary>",
299+
'<summary><a href="https://fulll.github.io/github-code-search/">github-code-search</a> replay command</summary>',
300300
);
301301
expect(out).toContain("```bash");
302302
expect(out).toContain("</details>");
@@ -314,7 +314,7 @@ describe("buildMarkdownOutput", () => {
314314
const out = buildMarkdownOutput(groups, QUERY, ORG, new Set(), new Set(), "repo-only");
315315
expect(out).toContain("<details>");
316316
expect(out).toContain(
317-
"<summary>[github-code-search](https://fulll.github.io/github-code-search/) replay command</summary>",
317+
'<summary><a href="https://fulll.github.io/github-code-search/">github-code-search</a> replay command</summary>',
318318
);
319319
});
320320

@@ -324,7 +324,7 @@ describe("buildMarkdownOutput", () => {
324324
expect(out).toContain("myorg/repoA\nmyorg/repoB\n");
325325
expect(out).toContain("<details>");
326326
expect(out).toContain(
327-
"<summary>[github-code-search](https://fulll.github.io/github-code-search/) replay command</summary>",
327+
'<summary><a href="https://fulll.github.io/github-code-search/">github-code-search</a> replay command</summary>',
328328
);
329329
});
330330

src/output.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export function buildReplayDetails(
108108
const shellCmd = raw.replace(/^# Replay:\n/, "");
109109
return [
110110
"<details>",
111-
"<summary>[github-code-search](https://fulll.github.io/github-code-search/) replay command</summary>",
111+
'<summary><a href="https://fulll.github.io/github-code-search/">github-code-search</a> replay command</summary>',
112112
"",
113113
"```bash",
114114
shellCmd,

0 commit comments

Comments
 (0)