fix: resolve HTML hierarchy, accessibility and PDF link issues
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 7s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m19s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 11m30s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 12s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 2m45s
🚀 Build & Deploy / 🔔 Notify (push) Successful in 2s
Nightly QA (Inlined) / 🏗️ Prepare & Install (push) Successful in 6m54s
Nightly QA (Inlined) / 🔍 Static Analysis (push) Failing after 1m29s
Nightly QA (Inlined) / 🧪 Maintenance & Links (push) Failing after 1m38s
Nightly QA (Inlined) / ♿ Accessibility (push) Successful in 2m0s
Nightly QA (Inlined) / 🎭 Lighthouse (push) Failing after 2m2s
Nightly QA (Inlined) / 🔔 Notify (push) Successful in 1s
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 7s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m19s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 11m30s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 12s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 2m45s
🚀 Build & Deploy / 🔔 Notify (push) Successful in 2s
Nightly QA (Inlined) / 🏗️ Prepare & Install (push) Successful in 6m54s
Nightly QA (Inlined) / 🔍 Static Analysis (push) Failing after 1m29s
Nightly QA (Inlined) / 🧪 Maintenance & Links (push) Failing after 1m38s
Nightly QA (Inlined) / ♿ Accessibility (push) Successful in 2m0s
Nightly QA (Inlined) / 🎭 Lighthouse (push) Failing after 2m2s
Nightly QA (Inlined) / 🔔 Notify (push) Successful in 1s
- Fix heading level skip in ContactContent success state (H3 -> H2) - Clean up deprecated iframe attributes in ContactContent - Add aria-label to footer logo link for WCAG compliance - Rename PDF assets to hyphenated filenames to fix link checks - Update AGB page with new PDF link format
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -13,22 +13,27 @@ export default function AVB() {
|
||||
.filter((b) => b !== "");
|
||||
|
||||
// Extract title and stand more robustly
|
||||
const title = rawBlocks.find(b => b.startsWith("# "))?.replace(/^#\s+/, "") || "Allgemeine Verkaufsbedingungen";
|
||||
const stand = rawBlocks.find(b => b.toLowerCase().startsWith("stand:")) || "Stand: April 2026";
|
||||
const title =
|
||||
rawBlocks.find((b) => b.startsWith("# "))?.replace(/^#\s+/, "") ||
|
||||
"Allgemeine Verkaufsbedingungen";
|
||||
const stand =
|
||||
rawBlocks.find((b) => b.toLowerCase().startsWith("stand:")) ||
|
||||
"Stand: April 2026";
|
||||
|
||||
const sections: { title: string; content: string[] }[] = [];
|
||||
let currentSection: { title: string; content: string[] } | null = null;
|
||||
|
||||
// Process sections, skipping title and stand blocks
|
||||
rawBlocks.forEach((block) => {
|
||||
if (block.startsWith("# ") || block.toLowerCase().startsWith("stand:")) return;
|
||||
if (block.startsWith("# ") || block.toLowerCase().startsWith("stand:"))
|
||||
return;
|
||||
|
||||
if (block.startsWith("##")) {
|
||||
// New section header: e.g. "## 1. Geltungsbereich"
|
||||
if (currentSection) sections.push(currentSection);
|
||||
currentSection = {
|
||||
title: block.replace(/^##\s+/, "").trim(),
|
||||
content: []
|
||||
currentSection = {
|
||||
title: block.replace(/^##\s+/, "").trim(),
|
||||
content: [],
|
||||
};
|
||||
} else if (currentSection) {
|
||||
// Clean up bold markers for better display
|
||||
@@ -39,7 +44,7 @@ export default function AVB() {
|
||||
if (currentSection) sections.push(currentSection);
|
||||
|
||||
// The very last block might be a footer/schlussbestimmung if it's not in a section
|
||||
// In our MD, everything is in a section, so we just use the last block of the last section as potential footer if we want,
|
||||
// In our MD, everything is in a section, so we just use the last block of the last section as potential footer if we want,
|
||||
// but the current UI expects a separate 'footer' variable.
|
||||
const footer = "MB Grid Solutions & Services";
|
||||
|
||||
@@ -55,7 +60,7 @@ export default function AVB() {
|
||||
<p className="text-slate-500 font-medium">{stand}</p>
|
||||
</div>
|
||||
<a
|
||||
href="/assets/AVB MB Grid 4-2026.pdf"
|
||||
href="/assets/avb-mb-grid-4-2026.pdf"
|
||||
download
|
||||
className="btn-primary !py-3 !px-6 flex items-center gap-2"
|
||||
>
|
||||
|
||||
@@ -162,13 +162,8 @@ export default function Contact() {
|
||||
<div className="w-full h-[300px] rounded-[2.5rem] overflow-hidden border border-white/10 shadow-sm grayscale hover:grayscale-0 transition-all duration-700 relative group">
|
||||
<div className="absolute inset-0 border-2 border-accent/0 group-hover:border-accent/20 transition-all duration-500 z-10 pointer-events-none rounded-[2.5rem]" />
|
||||
<iframe
|
||||
width="100%"
|
||||
height="100%"
|
||||
frameBorder="0"
|
||||
scrolling="no"
|
||||
marginHeight={0}
|
||||
marginWidth={0}
|
||||
title="Location Map"
|
||||
className="w-full h-full border-0"
|
||||
title={t("info.mapTitle") || "Location Map"}
|
||||
src="https://www.openstreetmap.org/export/embed.html?bbox=9.445,48.815,9.465,48.825&layer=mapnik&marker=48.8198,9.4552"
|
||||
></iframe>
|
||||
</div>
|
||||
@@ -185,9 +180,9 @@ export default function Contact() {
|
||||
<div className="w-20 h-20 rounded-full bg-accent/10 text-accent flex items-center justify-center mx-auto mb-8">
|
||||
<CheckCircle size={40} />
|
||||
</div>
|
||||
<h3 className="text-3xl font-bold text-primary mb-4">
|
||||
<h2 className="text-3xl font-bold text-primary mb-4">
|
||||
{t("form.successTitle")}
|
||||
</h3>
|
||||
</h2>
|
||||
<p className="text-slate-600 text-lg mb-10">
|
||||
{t("form.successMessage")}
|
||||
</p>
|
||||
|
||||
@@ -184,7 +184,11 @@ const Layout = ({ children }: { children: React.ReactNode }) => {
|
||||
<div className="container-custom relative z-10">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-10 md:gap-12 mb-12 md:mb-16">
|
||||
<div className="lg:col-span-2">
|
||||
<Link href="/" className="inline-block mb-6 md:mb-8 group">
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-block mb-6 md:mb-8 group"
|
||||
aria-label={t("nav.home")}
|
||||
>
|
||||
<div className="relative h-16 md:h-20 w-48 brightness-0 invert opacity-80 group-hover:opacity-100 transition-opacity">
|
||||
<Image
|
||||
src="/assets/logo.png"
|
||||
|
||||
@@ -75,9 +75,9 @@ export const StatusModal = ({
|
||||
)}
|
||||
</div>
|
||||
|
||||
<h3 className="text-3xl font-extrabold text-primary mb-4 leading-tight">
|
||||
<h2 className="text-3xl font-extrabold text-primary mb-4 leading-tight">
|
||||
{title}
|
||||
</h3>
|
||||
</h2>
|
||||
<p className="text-slate-600 text-lg mb-10 leading-relaxed">
|
||||
{message}
|
||||
</p>
|
||||
|
||||
14
scripts/find-empty-anchors.ts
Normal file
14
scripts/find-empty-anchors.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import * as cheerio from "cheerio";
|
||||
import * as fs from "fs";
|
||||
|
||||
const file = process.argv[2];
|
||||
const html = fs.readFileSync(file, "utf8");
|
||||
const $ = cheerio.load(html);
|
||||
|
||||
$("a").each((i, el) => {
|
||||
const text = $(el).text().trim();
|
||||
const label = $(el).attr("aria-label");
|
||||
if (!text && !label) {
|
||||
console.log(`Empty anchor found: ${$(el).toString()}`);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user