feat(ui): complete structural rewrite of content components to strict engineering blueprint aesthetic
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 5s
Build & Deploy / 🏗️ Build (push) Failing after 27s
Build & Deploy / 🧪 QA (push) Failing after 1m15s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s

This commit is contained in:
2026-02-22 02:35:06 +01:00
parent 3eccff42e4
commit 75c61f1436
6 changed files with 574 additions and 62 deletions

View File

@@ -0,0 +1,75 @@
'use client';
import React from 'react';
interface WebVitalsScoreProps {
values: {
/** Largest Contentful Paint in seconds (e.g. 2.5) */
lcp: number;
/** Interaction to Next Paint in milliseconds (e.g. 200) */
inp: number;
/** Cumulative Layout Shift (e.g. 0.1) */
cls: number;
};
description?: string;
showShare?: boolean;
}
export const WebVitalsScore: React.FC<WebVitalsScoreProps> = ({ values, description }) => {
const getStatus = (metric: 'lcp' | 'inp' | 'cls', value: number): 'good' | 'needs-improvement' | 'poor' => {
if (metric === 'lcp') return value <= 2.5 ? 'good' : value <= 4.0 ? 'needs-improvement' : 'poor';
if (metric === 'inp') return value <= 200 ? 'good' : value <= 500 ? 'needs-improvement' : 'poor';
if (metric === 'cls') return value <= 0.1 ? 'good' : value <= 0.25 ? 'needs-improvement' : 'poor';
return 'poor';
};
const metrics = [
{ id: 'lcp', label: 'Largest Contentful Paint', value: values.lcp, unit: 's', stat: getStatus('lcp', values.lcp), desc: 'Wann der Hauptinhalt geladen ist' },
{ id: 'inp', label: 'Interaction to Next Paint', value: values.inp, unit: 'ms', stat: getStatus('inp', values.inp), desc: 'Reaktionszeit auf Klicks' },
{ id: 'cls', label: 'Cumulative Layout Shift', value: values.cls, unit: '', stat: getStatus('cls', values.cls), desc: 'Visuelle Stabilität beim Laden' }
];
const getColors = (status: string) => {
if (status === 'good') return 'text-emerald-600 border-emerald-500';
if (status === 'needs-improvement') return 'text-amber-500 border-amber-400';
return 'text-red-500 border-red-500';
};
return (
<section className="my-16 not-prose border-[2px] border-slate-900 p-8 md:p-12 relative bg-white">
<div className="absolute -top-[14px] left-8 bg-white px-4">
<h3 className="text-xl font-bold text-slate-900 tracking-tight m-0 uppercase flex items-center gap-3">
<div className="w-3 h-3 bg-slate-900 rotate-45" />
Core Web Vitals
</h3>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 md:gap-12 mt-4">
{metrics.map((m) => {
const colors = getColors(m.stat);
return (
<div key={m.id} className="flex flex-col">
<span className="text-[10px] font-mono text-slate-500 uppercase tracking-widest mb-1">{m.label}</span>
<div className={`text-4xl md:text-5xl font-black tracking-tighter tabular-nums ${colors.split(' ')[0]} border-b-[3px] ${colors.split(' ')[1]} pb-2 mb-2`}>
{m.value}<span className="text-lg ml-1 font-bold">{m.unit}</span>
</div>
<div className="flex justify-between items-start gap-2">
<span className={`text-[10px] font-mono font-bold uppercase ${colors.split(' ')[0]}`}>{m.stat.replace('-', ' ')}</span>
<span className="text-[10px] text-slate-500 leading-snug text-right max-w-[120px]">{m.desc}</span>
</div>
</div>
);
})}
</div>
{description && (
<div className="mt-10 p-5 bg-slate-50 border-l-2 border-slate-900">
<p className="text-sm text-slate-800 m-0 leading-relaxed font-serif">
<span className="font-mono text-[10px] font-bold uppercase text-slate-900 tracking-widest block mb-2">Analyse</span>
{description}
</p>
</div>
)}
</section>
);
};