docs: add ACCESSIBILITY_AUDIT, SECURITY_PRIVACY_AUDIT, PRODUCT_BRIEF with file-specific actions; a11y: add skip link, lang+hreflang, ARIA for menu/carousel/dialog/form; noValidate+honeypot

This commit is contained in:
2025-08-08 23:00:09 +02:00
parent 910253c8f4
commit 3c74d71e22
16 changed files with 501 additions and 43 deletions

View File

@@ -1,26 +1,34 @@
---
// src/layouts/BaseLayout.astro
import '../styles/global.css';
import '../styles/main.css';
export interface Props {
title?: string;
description?: string;
lang?: string;
}
const { title = "Omoluabi Association Netherlands", description = "Preserving Nigerian culture and heritage in the Netherlands" } = Astro.props;
---
<!DOCTYPE html>
<html lang="en">
<html lang={Astro.props.lang ?? 'en'}>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{title}</title>
<meta name="description" content={description} />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="alternate" hreflang="en" href="/en/" />
<link rel="alternate" hreflang="nl" href="/nl/" />
<link rel="alternate" hreflang="x-default" href="/" />
</head>
<body class="bg-gray-50">
<a href="#main" class="sr-only focus:not-sr-only focus:fixed focus:top-2 focus:left-2 focus:z-50 focus:bg-white focus:text-black focus:px-3 focus:py-2 focus:rounded">
Skip to main content
</a>
<!-- Navigation Header -->
<header class="bg-white shadow-sm sticky top-0 z-50">
<nav class="container mx-auto px-4 py-4">
@@ -58,7 +66,7 @@ const { title = "Omoluabi Association Netherlands", description = "Preserving Ni
</div>
<!-- Mobile menu button -->
<button class="md:hidden" id="mobile-menu-button">
<button class="md:hidden" id="mobile-menu-button" aria-controls="mobile-menu" aria-expanded="false">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
@@ -85,7 +93,7 @@ const { title = "Omoluabi Association Netherlands", description = "Preserving Ni
</header>
<!-- Main Content -->
<main>
<main id="main" tabindex="-1">
<slot />
</main>
@@ -136,34 +144,22 @@ const { title = "Omoluabi Association Netherlands", description = "Preserving Ni
<!-- Scripts -->
<script>
// Mobile menu toggle
document.addEventListener('DOMContentLoaded', () => {
const mobileMenuButton = document.getElementById('mobile-menu-button');
const mobileMenu = document.getElementById('mobile-menu');
if (mobileMenuButton && mobileMenu) {
mobileMenuButton.addEventListener('click', () => {
mobileMenu.classList.toggle('hidden');
const isHidden = mobileMenu.classList.toggle('hidden');
mobileMenuButton.setAttribute('aria-expanded', String(!isHidden));
});
}
// Intersection Observer for scroll animations
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
};
const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' };
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
}
});
entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('visible'); } });
}, observerOptions);
// Observe all elements with animation attributes
const animatedElements = document.querySelectorAll('[data-animate-on-scroll]');
animatedElements.forEach(el => observer.observe(el));
document.querySelectorAll('[data-animate-on-scroll]').forEach(el => observer.observe(el));
});
</script>
</body>