- checker.js: checkSecurityHeaders() graded A+-F, checkSSL() via SSL Labs API - Both run in parallel with sitespeed.io to minimise wait time - DB: auto-migrate headers_json + ssl_json columns - Layout: coach scores + CWV side-by-side, headers + SSL below - Scorecard + CWV made compact Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
18 lines
1.2 KiB
Plaintext
18 lines
1.2 KiB
Plaintext
- function ms(v) { return v != null ? (v/1000).toFixed(2)+'s' : '—'; }
|
|
- function raw(v, unit) { return v != null ? v.toFixed(unit === 'ms' ? 0 : 3)+unit : '—'; }
|
|
- function cwvClass(metric, val) {
|
|
- if (val == null) return 'bg-gray-50 border-gray-200';
|
|
- const thresholds = { lcp: [2500, 4000], fcp: [1800, 3000], tbt: [200, 600], cls: [0.1, 0.25], ttfb: [800, 1800] };
|
|
- const t = thresholds[metric];
|
|
- if (!t) return 'bg-gray-50 border-gray-200';
|
|
- return val <= t[0] ? 'bg-green-50 border-green-300' : val <= t[1] ? 'bg-yellow-50 border-yellow-300' : 'bg-red-50 border-red-300';
|
|
- }
|
|
|
|
div(class='bg-white border border-gray-200 rounded-xl p-4 h-full')
|
|
h2(class='text-sm font-semibold mb-3 text-gray-600 uppercase tracking-wide') Core Web Vitals
|
|
div(class='grid grid-cols-3 sm:grid-cols-5 gap-2')
|
|
each item in [['LCP', 'lcp', ms(job.lcp)], ['FCP', 'fcp', ms(job.fcp)], ['TBT', 'tbt', raw(job.tbt,'ms')], ['CLS', 'cls', raw(job.cls,'')], ['TTFB', 'ttfb', ms(job.ttfb)]]
|
|
div(class=`border rounded-lg px-2 py-2 ${cwvClass(item[1], job[item[1]])} text-center`)
|
|
div(class='text-lg font-bold leading-tight')= item[2]
|
|
div(class='text-xs text-gray-500 mt-0.5')= item[0]
|