Compare commits

...

2 Commits

Author SHA1 Message Date
089ce13c59 fix: mobile nav close button + CI Gatekeeper auth
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 6s
Build & Deploy / 🧪 QA (push) Successful in 2m25s
Build & Deploy / 🏗️ Build (push) Successful in 4m56s
Build & Deploy / 🚀 Deploy (push) Successful in 15s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 5m3s
Build & Deploy / 🔔 Notify (push) Successful in 3s
- Add explicit close (×) button inside mobile nav overlay
  - Was unreachable because header's hamburger was behind overlay z-index
  - New button lives inside the overlay at full z-index visibility
- Fix check-forms.ts: authenticate via Gatekeeper login form
  - Old approach: inject raw password as session cookie (didn't work)
  - New approach: navigate to protected page, detect Gatekeeper gate,
    fill password form and submit to get a real server-signed session cookie
  - Fixes E2E form tests that failed because pages returned Gatekeeper HTML
2026-02-28 19:25:53 +01:00
a2cf9791ae fix: optimize footer layout for mobile
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 7s
Build & Deploy / 🧪 QA (push) Successful in 2m8s
Build & Deploy / 🏗️ Build (push) Successful in 4m5s
Build & Deploy / 🚀 Deploy (push) Successful in 17s
Build & Deploy / 🧪 Post-Deploy Verification (push) Failing after 4m16s
Build & Deploy / 🔔 Notify (push) Successful in 4s
- Switch to grid-cols-2 on mobile (was grid-cols-1)
- Brand column: col-span-2 (full width on mobile)
- Legal + Company columns: col-span-1 each (side-by-side on mobile)
- Recent Posts column: col-span-2 (full width on mobile)
- Reduce footer padding: py-14 md:py-24 (was py-24)
- Tighten grid gap: gap-10 md:gap-16 (was gap-16)
- Bottom bar: flex-row always so copyright + language on one line
2026-02-28 10:53:00 +01:00
3 changed files with 60 additions and 23 deletions

View File

@@ -15,14 +15,14 @@ export default function Footer() {
const currentYear = new Date().getFullYear(); const currentYear = new Date().getFullYear();
return ( return (
<footer className="bg-primary text-white py-24 relative overflow-hidden content-visibility-auto"> <footer className="bg-primary text-white py-14 md:py-24 relative overflow-hidden content-visibility-auto">
<div className="absolute top-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-white/20 to-transparent" /> <div className="absolute top-0 left-0 w-full h-px bg-gradient-to-r from-transparent via-white/20 to-transparent" />
<Container> <Container>
<h2 className="sr-only">Footer Navigation</h2> <h2 className="sr-only">Footer Navigation</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-12 gap-16 mb-20"> <div className="grid grid-cols-2 md:grid-cols-2 lg:grid-cols-12 gap-10 md:gap-16 mb-12 md:mb-20">
{/* Brand Column */} {/* Brand Column full width on mobile */}
<div className="lg:col-span-4 space-y-8"> <div className="col-span-2 md:col-span-2 lg:col-span-4 space-y-6 md:space-y-8">
<Link <Link
href={`/${locale}`} href={`/${locale}`}
className="inline-block group" className="inline-block group"
@@ -67,9 +67,9 @@ export default function Footer() {
</div> </div>
</div> </div>
{/* Links Columns */} {/* Legal Column */}
<div className="lg:col-span-2"> <div className="col-span-1 lg:col-span-2">
<h3 className="text-accent font-bold uppercase tracking-widest text-xs md:text-sm mb-8"> <h3 className="text-accent font-bold uppercase tracking-widest text-xs mb-5 md:mb-8">
{t('legal')} {t('legal')}
</h3> </h3>
<ul className="space-y-4 text-white/70 list-none m-0 p-0"> <ul className="space-y-4 text-white/70 list-none m-0 p-0">
@@ -121,8 +121,9 @@ export default function Footer() {
</ul> </ul>
</div> </div>
<div className="lg:col-span-2"> {/* Company Column */}
<h3 className="text-accent font-bold uppercase tracking-widest text-xs md:text-sm mb-8"> <div className="col-span-1 lg:col-span-2">
<h3 className="text-accent font-bold uppercase tracking-widest text-xs mb-5 md:mb-8">
{t('company')} {t('company')}
</h3> </h3>
<ul className="space-y-4 text-white/70 list-none m-0 p-0"> <ul className="space-y-4 text-white/70 list-none m-0 p-0">
@@ -189,9 +190,9 @@ export default function Footer() {
</ul> </ul>
</div> </div>
{/* Recent Posts Column */} {/* Recent Posts Column full width on mobile */}
<div className="lg:col-span-4"> <div className="col-span-2 md:col-span-2 lg:col-span-4">
<h3 className="text-accent font-bold uppercase tracking-widest text-xs md:text-sm mb-8"> <h3 className="text-accent font-bold uppercase tracking-widest text-xs mb-5 md:mb-8">
{t('recentPosts')} {t('recentPosts')}
</h3> </h3>
<ul className="space-y-6 list-none m-0 p-0"> <ul className="space-y-6 list-none m-0 p-0">
@@ -242,7 +243,7 @@ export default function Footer() {
</div> </div>
</div> </div>
<div className="pt-12 border-t border-white/10 flex flex-col md:flex-row justify-between items-center gap-8 text-white/70 text-xs md:text-sm font-medium"> <div className="pt-8 md:pt-12 border-t border-white/10 flex flex-row justify-between items-center gap-4 text-white/70 text-xs md:text-sm font-medium">
<p>{t('copyright', { year: currentYear })}</p> <p>{t('copyright', { year: currentYear })}</p>
<div className="flex gap-8"> <div className="flex gap-8">
<Link <Link

View File

@@ -352,6 +352,29 @@ export default function Header() {
ref={mobileMenuRef} ref={mobileMenuRef}
inert={isMobileMenuOpen ? undefined : true} inert={isMobileMenuOpen ? undefined : true}
> >
{/* Close Button inside overlay */}
<div className="flex justify-end p-6 pt-8">
<button
className="touch-target p-2 rounded-xl bg-white/10 border border-white/20 text-white hover:bg-white/20 transition-all duration-300"
aria-label={t('toggleMenu')}
onClick={() => {
setIsMobileMenuOpen(false);
trackEvent(AnalyticsEvents.BUTTON_CLICK, {
type: 'mobile_menu',
action: 'close',
});
}}
>
<svg className="w-7 h-7" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
<nav className="flex-grow flex flex-col justify-center items-center p-8 space-y-8"> <nav className="flex-grow flex flex-col justify-center items-center p-8 space-y-8">
{menuItems.map((item, idx) => ( {menuItems.map((item, idx) => (
<div <div

View File

@@ -66,16 +66,29 @@ async function main() {
const page = await browser.newPage(); const page = await browser.newPage();
// 3. Inject Gatekeeper session bypassing auth screens // 3. Authenticate through Gatekeeper login form
console.log(`\n🛡 Injecting Gatekeeper Session...`); console.log(`\n🛡 Authenticating through Gatekeeper...`);
await page.setCookie({ try {
name: 'klz_gatekeeper_session', // Navigate to a protected page so Gatekeeper redirects us to the login screen
value: gatekeeperPassword, await page.goto(contactUrl, { waitUntil: 'networkidle0', timeout: 30000 });
domain: new URL(targetUrl).hostname,
path: '/', // Check if we landed on the Gatekeeper login page
httpOnly: true, const isGatekeeperPage = await page.$('input[name="password"]');
secure: targetUrl.startsWith('https://'), if (isGatekeeperPage) {
}); await page.type('input[name="password"]', gatekeeperPassword);
await Promise.all([
page.waitForNavigation({ waitUntil: 'networkidle0', timeout: 30000 }),
page.click('button[type="submit"]'),
]);
console.log(`✅ Gatekeeper authentication successful!`);
} else {
console.log(`✅ Already authenticated (no Gatekeeper gate detected).`);
}
} catch (err: any) {
console.error(`❌ Gatekeeper authentication failed: ${err.message}`);
await browser.close();
process.exit(1);
}
let hasErrors = false; let hasErrors = false;