Compare commits

...

17 Commits

Author SHA1 Message Date
500c2c64f4 chore: release 2.2.77
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 30s
Build & Deploy / 🏗️ Build (push) Successful in 3m42s
Build & Deploy / 🧪 QA (push) Successful in 1m46s
Build & Deploy / 🚀 Deploy (push) Successful in 34s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m15s
Build & Deploy / 🔔 Notify (push) Successful in 4s
2026-06-27 08:09:37 +02:00
e13ce8bcec fix: resolve ssr:false in Server Component build error by creating Client Component wrappers 2026-06-27 08:09:26 +02:00
feb8372a7c chore: release 2.2.76
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 29s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 3s
Build & Deploy / 🧪 QA (push) Successful in 1m49s
Build & Deploy / 🏗️ Build (push) Failing after 2m28s
2026-06-27 08:01:31 +02:00
c190a4f67e perf: dynamically import InitialLoader and MobileBottomNav to remove framer-motion from main JS bundle 2026-06-27 08:01:27 +02:00
6717b32d44 chore: release 2.2.75
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 29s
Build & Deploy / 🚀 Deploy (push) Successful in 35s
Build & Deploy / 🧪 QA (push) Successful in 1m46s
Build & Deploy / 🏗️ Build (push) Successful in 3m34s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m12s
Build & Deploy / 🔔 Notify (push) Successful in 4s
2026-06-27 07:20:55 +02:00
f1732917bc perf: enable experimental.inlineCss to eliminate 380ms render-blocking CSS waterfall 2026-06-27 07:20:50 +02:00
1f666d1b34 chore: release 2.2.74
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 28s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m12s
Build & Deploy / 🧪 QA (push) Successful in 1m46s
Build & Deploy / 🏗️ Build (push) Successful in 3m35s
Build & Deploy / 🚀 Deploy (push) Successful in 34s
Build & Deploy / 🔔 Notify (push) Successful in 4s
2026-06-27 06:14:39 +02:00
ab42590206 test: fix gatekeeper bypass logic in pagespeed-sitemap.ts by passing TARGET_URL 2026-06-27 06:14:33 +02:00
7d4ff03806 chore: release 2.2.73
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 29s
Build & Deploy / 🏗️ Build (push) Successful in 3m34s
Build & Deploy / 🧪 QA (push) Successful in 1m52s
Build & Deploy / 🚀 Deploy (push) Successful in 35s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m15s
Build & Deploy / 🔔 Notify (push) Successful in 4s
2026-06-26 21:22:51 +02:00
26ed3e3f1f fix(perf): remove animate-fade-in from main and force sync decode on logo to eliminate 2s Element Render Delay and align LCP with FCP 2026-06-26 21:22:38 +02:00
eaf40dec7c chore: release 2.2.72
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 28s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m17s
Build & Deploy / 🧪 QA (push) Successful in 1m52s
Build & Deploy / 🏗️ Build (push) Successful in 3m34s
Build & Deploy / 🚀 Deploy (push) Successful in 34s
Build & Deploy / 🔔 Notify (push) Successful in 4s
2026-06-26 19:22:17 +02:00
d56ce045c3 fix(perf): replace framer-motion with pure css animations in HeroSection to eliminate JS-induced 4.5s LCP delay 2026-06-26 19:22:17 +02:00
586b6cdee8 chore: release 2.2.71
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 31s
Build & Deploy / 🧪 QA (push) Successful in 1m50s
Build & Deploy / 🏗️ Build (push) Successful in 3m40s
Build & Deploy / 🚀 Deploy (push) Successful in 35s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m17s
Build & Deploy / 🔔 Notify (push) Successful in 4s
2026-06-26 13:00:33 +02:00
f1b8ee1188 fix(perf): completely disable Sentry client-side auto-instrumentation to save 556KB of JS
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 1m18s
Build & Deploy / 🧪 QA (push) Successful in 1m46s
Build & Deploy / 🏗️ Build (push) Successful in 3m41s
Build & Deploy / 🚀 Deploy (push) Successful in 35s
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-06-26 12:24:07 +02:00
88cc214ddb fix(ci): use correct auth cookie name for e-tib gatekeeper bypass
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 1m17s
Build & Deploy / 🧪 QA (push) Successful in 1m47s
Build & Deploy / 🏗️ Build (push) Successful in 3m29s
Build & Deploy / 🚀 Deploy (push) Successful in 35s
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-06-26 11:21:24 +02:00
25facb995f chore: bump version for fix
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 30s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m12s
Build & Deploy / 🧪 QA (push) Successful in 1m44s
Build & Deploy / 🏗️ Build (push) Successful in 3m32s
Build & Deploy / 🚀 Deploy (push) Successful in 33s
Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-06-26 10:22:03 +02:00
7b01924055 fix: revert optimizeCss to fix LCP/FCP regression caused by critters with Tailwind v4 2026-06-26 10:21:57 +02:00
10 changed files with 80 additions and 53 deletions

View File

@@ -1,6 +1,5 @@
import { Footer } from '@/components/layout/Footer';
import { Header } from '@/components/layout/Header';
import { MobileBottomNav } from '@/components/layout/MobileBottomNav';
import JsonLd from '@/components/JsonLd';
import SkipLink from '@/components/SkipLink';
import AnalyticsShell from '@/components/analytics/AnalyticsShell';
@@ -17,7 +16,10 @@ import { mapFileSlugToTranslated } from '@/lib/slugs';
import { cookies } from 'next/headers';
import { TransitionProvider } from '@/components/providers/TransitionProvider';
import { InitialLoader } from '@/components/providers/InitialLoader';
import { DynamicInitialLoader as InitialLoader } from '@/components/providers/DynamicInitialLoader';
import { DynamicMobileBottomNav as MobileBottomNav } from '@/components/layout/DynamicMobileBottomNav';
import { DynamicCorporateBackground as CorporateBackground } from '@/components/decorations/DynamicCorporateBackground';
import { DynamicPageTransitionShutter as PageTransitionShutter } from '@/components/providers/DynamicPageTransitionShutter';
@@ -197,7 +199,7 @@ export default async function Layout(props: {
<main
id="main-content"
className="flex-grow animate-fade-in overflow-visible"
className="flex-grow overflow-visible"
tabIndex={-1}
>
{children}

View File

@@ -87,3 +87,35 @@
}
}
/* trigger rebuild */
@layer utilities {
@keyframes hero-fade-in-up {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-hero-fade-in-up {
animation: hero-fade-in-up 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
}
@layer utilities {
@keyframes hero-zoom-out {
from {
transform: scale(1.05);
}
to {
transform: scale(1);
}
}
.animate-hero-zoom-out {
animation: hero-zoom-out 1.5s ease-out forwards;
}
}

View File

@@ -3,7 +3,6 @@
import React from 'react';
import Image from 'next/image';
import { usePathname } from 'next/navigation';
import { m } from 'framer-motion';
import { Badge, Container, Heading } from '@/components/ui';
import { Button } from '@/components/ui/Button';
@@ -17,25 +16,7 @@ export interface HeroSectionProps {
ctaHref?: string;
}
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.15,
delayChildren: 0.1,
},
},
};
const itemVariants = {
hidden: { opacity: 0, y: 30 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.8, ease: [0.16, 1, 0.3, 1] as const }
},
};
// CSS animations replace Framer Motion for better LCP
export const HeroSection: React.FC<HeroSectionProps> = (props) => {
const { title, badge, subtitle, backgroundImage, alignment, ctaLabel, ctaHref } = props;
@@ -47,12 +28,9 @@ export const HeroSection: React.FC<HeroSectionProps> = (props) => {
className={`relative min-h-[35vh] md:min-h-[50vh] flex items-center pt-28 pb-10 md:pt-36 md:pb-24 overflow-hidden bg-neutral-dark ${alignment === 'center' ? 'justify-center text-center' : ''}`}
>
{bgSrc && (
<m.div
<div
key={`hero-bg-${pathname}`}
className="absolute inset-0 z-0"
initial={{ scale: 1.05, opacity: 1 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ duration: 1.5, ease: "easeOut" }}
className="absolute inset-0 z-0 animate-hero-zoom-out"
>
<Image
src={bgSrc}
@@ -74,37 +52,34 @@ export const HeroSection: React.FC<HeroSectionProps> = (props) => {
{/* Top Fade for Header Navigation Readability */}
<div className="absolute top-0 left-0 w-full h-48 bg-gradient-to-b from-black/70 to-transparent z-[3] pointer-events-none" />
</m.div>
</div>
)}
<Container className={`relative z-10 ${alignment === 'center' ? 'max-w-5xl' : ''}`}>
<m.div
<div
key={`hero-content-${pathname}`}
className={`max-w-4xl ${alignment === 'center' ? 'mx-auto' : ''}`}
variants={containerVariants}
initial="hidden"
animate="visible"
>
{badge && (
<m.div variants={itemVariants}>
<div className="animate-hero-fade-in-up" style={{ animationDelay: '0.1s', opacity: 0, animationFillMode: 'forwards' }}>
<Badge variant="saturated" className="mb-4 md:mb-8 shadow-lg">
{badge}
</Badge>
</m.div>
</div>
)}
<m.div variants={itemVariants}>
<Heading level={1} size="section" variant="white" align={alignment || 'left'} className="mb-4 md:mb-8">
{title}
</Heading>
</m.div>
<div className="animate-hero-fade-in-up" style={{ animationDelay: badge ? '0.25s' : '0.1s', opacity: 0, animationFillMode: 'forwards' }}>
<Heading level={1} size="section" variant="white" align={alignment || 'left'} className="mb-4 md:mb-8">
{title}
</Heading>
</div>
{subtitle && (
<m.div variants={itemVariants}>
<div className="animate-hero-fade-in-up" style={{ animationDelay: badge ? '0.4s' : '0.25s', opacity: 0, animationFillMode: 'forwards' }}>
<p className={`text-lg md:text-2xl text-white/70 font-medium leading-relaxed max-w-2xl ${alignment === 'center' ? 'mx-auto' : ''}`}>
{subtitle}
</p>
</m.div>
</div>
)}
{ctaLabel && ctaHref && (
<m.div variants={itemVariants} className={`mt-8 ${alignment === 'center' ? 'flex flex-wrap justify-center gap-4' : 'flex flex-wrap gap-4'}`}>
<div className={`mt-8 animate-hero-fade-in-up ${alignment === 'center' ? 'flex flex-wrap justify-center gap-4' : 'flex flex-wrap gap-4'}`} style={{ animationDelay: badge ? '0.55s' : '0.4s', opacity: 0, animationFillMode: 'forwards' }}>
<Button
href={ctaHref}
variant="accent"
@@ -115,9 +90,9 @@ export const HeroSection: React.FC<HeroSectionProps> = (props) => {
&rarr;
</span>
</Button>
</m.div>
</div>
)}
</m.div>
</div>
</Container>
</section>
);

View File

@@ -0,0 +1,7 @@
'use client';
import dynamic from 'next/dynamic';
export const DynamicMobileBottomNav = dynamic(
() => import('./MobileBottomNav').then(mod => mod.MobileBottomNav),
{ ssr: false }
);

View File

@@ -111,6 +111,7 @@ export function Header({ navLinks }: HeaderProps) {
priority
fetchPriority="high"
sizes="192px"
unoptimized
/>
{/* Masked sweep overlay on hover */}
<div

View File

@@ -0,0 +1,7 @@
'use client';
import dynamic from 'next/dynamic';
export const DynamicInitialLoader = dynamic(
() => import('./InitialLoader').then(mod => mod.InitialLoader),
{ ssr: false }
);

View File

@@ -15,7 +15,7 @@ const nextConfig = {
pagesBufferLength: 2,
},
experimental: {
optimizeCss: true,
inlineCss: true,
staleTimes: {
dynamic: 0,
static: 30,
@@ -568,6 +568,7 @@ resolvedConfig = withSentryConfig(
disableClientWebpackPlugin: true,
autoInstrumentServerFunctions: false,
autoInstrumentMiddleware: false,
autoInstrumentAppDirectory: false,
}
);

View File

@@ -139,7 +139,7 @@
"prepare": "husky",
"preinstall": "npx only-allow pnpm"
},
"version": "2.2.69",
"version": "2.2.77",
"pnpm": {
"onlyBuiltDependencies": [
"@parcel/watcher",

View File

@@ -6,13 +6,14 @@ module.exports = async (browser, context) => {
const page = await browser.newPage();
// Using LHCI_URL or TARGET_URL if available
const targetUrl =
process.env.LHCI_URL || process.env.TARGET_URL || 'https://testing.klz-cables.com';
process.env.LHCI_URL || process.env.TARGET_URL || 'https://testing.e-tib.com';
const gatekeeperPassword = process.env.GATEKEEPER_PASSWORD || 'klz2026';
const authCookieName = process.env.AUTH_COOKIE_NAME || 'etib_gatekeeper_session';
console.log(`🔑 LHCI Auth: Setting gatekeeper cookie for ${new URL(targetUrl).hostname}...`);
console.log(`🔑 LHCI Auth: Setting gatekeeper cookie (${authCookieName}) for ${new URL(targetUrl).hostname}...`);
await page.setCookie({
name: 'klz_gatekeeper_session',
name: authCookieName,
value: gatekeeperPassword,
domain: new URL(targetUrl).hostname,
path: '/',

View File

@@ -19,6 +19,7 @@ const targetUrl =
'http://localhost:3000';
const limit = process.env.PAGESPEED_LIMIT ? parseInt(process.env.PAGESPEED_LIMIT) : 20; // Default limit to avoid infinite runs
const gatekeeperPassword = process.env.GATEKEEPER_PASSWORD || 'klz2026';
const authCookieName = process.env.AUTH_COOKIE_NAME || 'etib_gatekeeper_session';
async function main() {
console.log(`\n🚀 Starting PageSpeed test for: ${targetUrl}`);
@@ -32,7 +33,7 @@ async function main() {
// We might need to bypass gatekeeper for the sitemap fetch too
const response = await axios.get(sitemapUrl, {
headers: {
Cookie: `klz_gatekeeper_session=${gatekeeperPassword}`,
Cookie: `${authCookieName}=${gatekeeperPassword}`,
},
validateStatus: (status) => status < 400,
});
@@ -77,7 +78,7 @@ async function main() {
// Handle authentication for staging/testing
// Lighthouse can set cookies via --collect.settings.extraHeaders
const extraHeaders = JSON.stringify({
Cookie: `klz_gatekeeper_session=${gatekeeperPassword}`,
Cookie: `${authCookieName}=${gatekeeperPassword}`,
});
// Detect Chrome path from Puppeteer installation if not provided
@@ -147,7 +148,7 @@ async function main() {
execSync(lhciCommand, {
encoding: 'utf8',
stdio: 'inherit',
env: { ...process.env, CHROME_PATH: chromePath },
env: { ...process.env, CHROME_PATH: chromePath, TARGET_URL: targetUrl },
});
} catch (err: any) {
console.warn('⚠️ LHCI assertion finished with warnings or errors.');