Repository navigation
fix: preserve card styling in heading hierarchy repair #23
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -21,21 +21,41 @@ const AFFECTED_PAGES = [ | |||||||||||
| "public/contact/index.html", | ||||||||||||
| "public/promptly/index.html", | ||||||||||||
| "public/promptly/privacy/index.html", | ||||||||||||
| "public/drishti/index.html" | ||||||||||||
| "public/drishti/index.html", | ||||||||||||
| "public/drishti/support/index.html", | ||||||||||||
| "public/privacy-choices/index.html" | ||||||||||||
| ] | ||||||||||||
|
|
||||||||||||
| // Heading levels in document order, e.g. [1, 2, 2, 3]. | ||||||||||||
| // Heading levels in document order, e.g. [1, 2, 2, 2, 2, 3, 3, 3]. | ||||||||||||
| const headingLevelsOf = (html) => | ||||||||||||
| [...html.matchAll(/<h([1-6])\b[^>]*>/gi)].map((m) => Number(m[1])) | ||||||||||||
|
|
||||||||||||
| console.log("test-public-heading-hierarchy: rendered heading outline on the four finding pages") | ||||||||||||
| // Count <h2> used as .info-card card titles (inside <article class="info-card">). | ||||||||||||
| const infoCardTitleCount = (html) => | ||||||||||||
| (html.match(/<article class="info-card[^"]*"[^>]*>[\s\S]*?<h2\b/gi) || []).length | ||||||||||||
|
Comment on lines
+33
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Scope each card match to its closing The current pattern is not bounded by an article end tag. If a card regresses to H3, the match can consume the next card’s or footer’s H2 and still count that card. The test can therefore pass with fewer than three card H2 headings. Match each article body separately and count articles that contain exactly one H2. Proposed fix const infoCardTitleCount = (html) =>
- (html.match(/<article class="info-card[^"]*"[^>]*>[\s\S]*?<h2\b/gi) || []).length
+ [...html.matchAll(
+ /<article\b[^>]*class="[^"]*\binfo-card\b[^"]*"[^>]*>([\s\S]*?)<\/article>/gi
+ )].filter(([, body]) => (body.match(/<h2\b/gi) || []).length === 1).lengthAlso applies to: 55-55 🤖 Prompt for AI Agents |
||||||||||||
|
|
||||||||||||
| // The CSS rule that keeps card headings at the former h3 card-title scale | ||||||||||||
| // regardless of h2 semantics, and lifts the global h2 12ch cap inside cards. | ||||||||||||
| const CARD_HEADING_RULE = ".info-card :is(h2, h3) {" | ||||||||||||
| const CARD_RULE_DECLARATIONS = [ | ||||||||||||
| "margin-top: 12px", // former .info-card h3 margin | ||||||||||||
| "font-size: clamp(1.65rem, 2vw, 2.35rem)", // former h3 card-title scale | ||||||||||||
| "max-width: none" // no 12ch cap inside cards | ||||||||||||
| ] | ||||||||||||
|
|
||||||||||||
| console.log("test-public-heading-hierarchy: card headings are semantic H2s with the former card scale") | ||||||||||||
|
|
||||||||||||
| for (const page of AFFECTED_PAGES) { | ||||||||||||
| const levels = headingLevelsOf(read(page)) | ||||||||||||
| const html = read(page) | ||||||||||||
| const levels = headingLevelsOf(html) | ||||||||||||
| console.log(`A. ${page}`) | ||||||||||||
| ok(levels.length > 0, "page contains at least one heading") | ||||||||||||
| ok(levels.filter((l) => l === 1).length === 1, "page has exactly one H1") | ||||||||||||
| ok(levels[0] === 1, "the H1 is the first heading in the outline") | ||||||||||||
| ok(infoCardTitleCount(html) === 3, "the three card headings are H2s inside .info-card articles") | ||||||||||||
| // Outline: H1 -> three H2 cards -> footer headings (footer H2 then H3s). | ||||||||||||
| const cardH2s = levels.filter((l) => l === 2).length | ||||||||||||
| ok(cardH2s >= 4, "card H2s plus the footer H2 keep a flat H2 band before the footer H3s") | ||||||||||||
| let jumps = 0 | ||||||||||||
| for (let i = 1; i < levels.length; i++) { | ||||||||||||
| if (levels[i] - levels[i - 1] > 1) { | ||||||||||||
|
|
@@ -46,7 +66,23 @@ for (const page of AFFECTED_PAGES) { | |||||||||||
| ok(jumps === 0, "no heading-level jump greater than one (no H1 -> H3 skip)") | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| console.log("B. npm test/ci wiring") | ||||||||||||
| console.log("B. card-heading CSS pairing") | ||||||||||||
| const css = read("public/styles.css") | ||||||||||||
| const ruleStart = css.indexOf(CARD_HEADING_RULE) | ||||||||||||
| ok(ruleStart !== -1, `styles.css defines ${CARD_HEADING_RULE}`) | ||||||||||||
| const ruleEnd = css.indexOf("}", ruleStart) | ||||||||||||
| const ruleBody = ruleStart === -1 ? "" : css.slice(ruleStart, ruleEnd) | ||||||||||||
| for (const decl of CARD_RULE_DECLARATIONS) { | ||||||||||||
| ok(ruleBody.includes(decl), `card rule keeps ${decl}`) | ||||||||||||
| } | ||||||||||||
| const globalH2 = css.match(/h2\s*{[^}]*}/)?.[0] ?? "" | ||||||||||||
| ok(globalH2.includes("max-width: 12ch"), "global h2 styling (12ch cap) is untouched") | ||||||||||||
|
Comment on lines
+78
to
+79
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Anchor the global H2 assertion to the global selector.
Anchor the match to a rule boundary or parse the selector list. Proposed fix-const globalH2 = css.match(/h2\s*{[^}]*}/)?.[0] ?? ""
+const globalH2 =
+ css.match(/(?:^|[}\n])\s*h2\s*{[^}]*}/)?.[0] ?? ""📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||
| ok( | ||||||||||||
| !/\.info-card\s+h3\s*{/.test(css), | ||||||||||||
| "the old .info-card h3-only rule is replaced by the shared :is(h2, h3) rule" | ||||||||||||
| ) | ||||||||||||
|
|
||||||||||||
| console.log("C. npm test/ci wiring") | ||||||||||||
| const pkg = JSON.parse(read("package.json")) | ||||||||||||
| ok( | ||||||||||||
| pkg.scripts.test.includes("test-public-heading-hierarchy.mjs"), | ||||||||||||
|
|
||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This regex can continue past the matching
</article>until it finds any later H2, so it does not establish the containment asserted by the test. For example, moving the third card title immediately after its closing article still produces a count of three, retains four total H2s and creates no level jump, causing every new hierarchy check to pass even though that card has no H2. Limit each match to the article body or inspect each article independently.Useful? React with 👍 / 👎.