perf(seo): image sizes, semantic HTML, X-Robots-Tag headers

- Add `sizes` prop to 8 <Image> components across news, heritage, and
  application pages — tells the browser which srcset variant to download,
  improving LCP and reducing bandwidth
- Replace date <span> with <time dateTime={ISO}> on news pages —
  Google uses datetime for article freshness signals
- Wrap news cards and article content in <article> tags — semantic
  boundary for crawlers
- Add X-Robots-Tag: noindex, nofollow header to all /hq-command
  responses in proxy.ts — defense-in-depth alongside meta robots

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-06 18:04:40 -05:00
parent 6b9a94490b
commit 8d80cbbc27
5 changed files with 25 additions and 17 deletions
@@ -904,7 +904,7 @@ function ExpandedCaseStudy({ node }: { node: any }) {
const fullImgSrc = `/cases/${nodeSlug}/${img}`;
return (
<div key={`g-${idx}`} className="relative w-full aspect-video rounded-2xl md:rounded-3xl overflow-hidden border border-black/10 dark:border-white/10 shadow-lg group bg-white">
<Image src={fullImgSrc} alt="Installation" fill className="object-cover group-hover:scale-105 transition-transform duration-700" />
<Image src={fullImgSrc} alt="Installation" fill sizes="(max-width: 768px) 100vw, 50vw" className="object-cover group-hover:scale-105 transition-transform duration-700" />
<button
onClick={() => openLightbox(fullImgSrc)}
className="absolute inset-0 w-full h-full bg-black/0 hover:bg-black/30 active:bg-black/40 transition-all flex items-center justify-center opacity-0 group-hover:opacity-100 backdrop-blur-[0px] hover:backdrop-blur-sm touch-manipulation"
@@ -1045,7 +1045,7 @@ export default function ApplicationClient({ data, realCases, images }: { data: a
<section className="relative w-full h-[50vh] md:h-[70vh] flex items-end justify-start overflow-hidden">
{heroImage ? (
<Image src={heroImage} alt={data.title} fill className="object-cover object-center scale-105 animate-slow-zoom" priority />
<Image src={heroImage} alt={data.title} fill sizes="100vw" className="object-cover object-center scale-105 animate-slow-zoom" priority />
) : (
<div className="absolute inset-0 bg-gradient-to-br from-[#0066CC]/20 to-black/80" />
)}
@@ -1149,7 +1149,7 @@ export default function ApplicationClient({ data, realCases, images }: { data: a
<div className="flex items-center gap-5 flex-1">
<div className="w-16 h-16 md:w-20 md:h-20 rounded-2xl md:rounded-3xl bg-black/5 dark:bg-black/50 border border-black/10 dark:border-white/5 flex items-center justify-center shrink-0 overflow-hidden relative shadow-inner">
{node.mediaFileName ? (
<Image src={`/cases/${nodeToSlug(node.title)}/${node.mediaFileName}`} alt={node.title} fill className="object-cover opacity-90 group-hover:scale-110 transition-transform duration-700" />
<Image src={`/cases/${nodeToSlug(node.title)}/${node.mediaFileName}`} alt={node.title} fill sizes="100px" className="object-cover opacity-90 group-hover:scale-110 transition-transform duration-700" />
) : (
<Cpu size={28} className="text-[#0066CC]/50 dark:text-[#00F0FF]/50" />
)}