diff --git a/index.html b/index.html
index d1d2eb5..bf94a79 100644
--- a/index.html
+++ b/index.html
@@ -107,13 +107,14 @@
}
}
- /* Font-Loading Optimierung */
+ /* Font-Loading Optimierung - Subset für Latin + German */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: swap;
- src: url('/fonts/inter-var.woff2') format('woff2-variations');
+ src: url('/fonts/inter-subset.woff2') format('woff2-variations');
+ unicode-range: U+0020-007E, U+00A0-00FF, U+0100-017F, U+2013-2014, U+2018-201A, U+201C-201E, U+2026, U+20AC;
}
body {
@@ -121,8 +122,8 @@
}
-
-
+
+
diff --git a/public/fonts/inter-subset.woff2 b/public/fonts/inter-subset.woff2
new file mode 100644
index 0000000..f7e7b8a
Binary files /dev/null and b/public/fonts/inter-subset.woff2 differ
diff --git a/public/fonts/inter-var.woff2 b/public/fonts/inter-var.woff2
deleted file mode 100644
index 5a8d3e7..0000000
Binary files a/public/fonts/inter-var.woff2 and /dev/null differ
diff --git a/scripts/pagespeed-check.js b/scripts/pagespeed-check.js
new file mode 100644
index 0000000..62c55e5
--- /dev/null
+++ b/scripts/pagespeed-check.js
@@ -0,0 +1,185 @@
+#!/usr/bin/env node
+/**
+ * PageSpeed Insights API Check
+ * Prüft die Performance einer URL mit der Google PageSpeed Insights API
+ */
+
+import https from 'https';
+
+// Disable SSL verification for local testing (network proxy issue)
+process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
+
+const API_KEY = 'AIzaSyA4qo0LfLy_ps-SyTQTQpFrFRjDnAUn_K4';
+const URL_TO_TEST = 'https://www.damjan-savic.com/';
+
+function httpsGet(url) {
+ return new Promise((resolve, reject) => {
+ https.get(url, (res) => {
+ let data = '';
+ res.on('data', chunk => data += chunk);
+ res.on('end', () => {
+ try {
+ resolve(JSON.parse(data));
+ } catch (e) {
+ reject(new Error(`JSON Parse Error: ${e.message}`));
+ }
+ });
+ }).on('error', reject);
+ });
+}
+
+async function runPageSpeedTest(url, strategy = 'mobile') {
+ const apiUrl = `https://www.pagespeedonline.googleapis.com/pagespeedonline/v5/runPagespeed?url=${encodeURIComponent(url)}&key=${API_KEY}&strategy=${strategy}&category=performance&category=accessibility&category=best-practices&category=seo`;
+
+ console.log(`\n🔍 Analysiere ${url} (${strategy})...\n`);
+ console.log('⏳ Bitte warten, die Analyse kann 30-60 Sekunden dauern...\n');
+
+ try {
+ const data = await httpsGet(apiUrl);
+
+ if (data.error) {
+ throw new Error(`API Error: ${data.error.message}`);
+ }
+
+ return data;
+ } catch (error) {
+ console.error('❌ Fehler bei der API-Anfrage:', error.message);
+ throw error;
+ }
+}
+
+function formatScore(score) {
+ const percentage = Math.round(score * 100);
+ if (percentage >= 90) return `\x1b[32m${percentage}\x1b[0m`; // Grün
+ if (percentage >= 50) return `\x1b[33m${percentage}\x1b[0m`; // Gelb
+ return `\x1b[31m${percentage}\x1b[0m`; // Rot
+}
+
+function formatTime(ms) {
+ if (ms < 1000) return `${Math.round(ms)}ms`;
+ return `${(ms / 1000).toFixed(1)}s`;
+}
+
+function displayResults(data, strategy) {
+ const lighthouse = data.lighthouseResult;
+ const categories = lighthouse.categories;
+ const audits = lighthouse.audits;
+
+ console.log('═'.repeat(60));
+ console.log(`📊 PageSpeed Insights Ergebnis (${strategy.toUpperCase()})`);
+ console.log('═'.repeat(60));
+
+ // Scores
+ console.log('\n📈 SCORES:');
+ console.log('─'.repeat(40));
+ console.log(` Performance: ${formatScore(categories.performance.score)}`);
+ console.log(` Barrierefreiheit: ${formatScore(categories.accessibility.score)}`);
+ console.log(` Best Practices: ${formatScore(categories['best-practices'].score)}`);
+ console.log(` SEO: ${formatScore(categories.seo.score)}`);
+
+ // Core Web Vitals
+ console.log('\n⚡ CORE WEB VITALS:');
+ console.log('─'.repeat(40));
+
+ const fcp = audits['first-contentful-paint'];
+ const lcp = audits['largest-contentful-paint'];
+ const tbt = audits['total-blocking-time'];
+ const cls = audits['cumulative-layout-shift'];
+ const si = audits['speed-index'];
+
+ console.log(` First Contentful Paint (FCP): ${formatTime(fcp.numericValue)}`);
+ console.log(` Largest Contentful Paint (LCP): ${formatTime(lcp.numericValue)}`);
+ console.log(` Total Blocking Time (TBT): ${formatTime(tbt.numericValue)}`);
+ console.log(` Cumulative Layout Shift (CLS): ${cls.displayValue}`);
+ console.log(` Speed Index: ${formatTime(si.numericValue)}`);
+
+ // Opportunities
+ const opportunities = Object.values(audits)
+ .filter(audit => audit.details?.type === 'opportunity' && audit.details?.overallSavingsMs > 0)
+ .sort((a, b) => (b.details?.overallSavingsMs || 0) - (a.details?.overallSavingsMs || 0))
+ .slice(0, 5);
+
+ if (opportunities.length > 0) {
+ console.log('\n💡 OPTIMIERUNGSMÖGLICHKEITEN:');
+ console.log('─'.repeat(40));
+ opportunities.forEach(opp => {
+ const savings = opp.details?.overallSavingsMs;
+ console.log(` • ${opp.title}`);
+ if (savings) {
+ console.log(` Potenzielle Einsparung: ${formatTime(savings)}`);
+ }
+ });
+ }
+
+ // Diagnostics
+ const diagnostics = Object.values(audits)
+ .filter(audit => audit.details?.type === 'table' && audit.score !== null && audit.score < 0.9)
+ .slice(0, 5);
+
+ if (diagnostics.length > 0) {
+ console.log('\n🔧 DIAGNOSE:');
+ console.log('─'.repeat(40));
+ diagnostics.forEach(diag => {
+ const scoreIcon = diag.score >= 0.5 ? '⚠️' : '❌';
+ console.log(` ${scoreIcon} ${diag.title}`);
+ });
+ }
+
+ // Passed Audits Count
+ const passedAudits = Object.values(audits).filter(a => a.score === 1).length;
+ const totalAudits = Object.values(audits).filter(a => a.score !== null).length;
+
+ console.log('\n✅ BESTANDENE PRÜFUNGEN:');
+ console.log('─'.repeat(40));
+ console.log(` ${passedAudits} von ${totalAudits} Prüfungen bestanden`);
+
+ console.log('\n' + '═'.repeat(60));
+
+ return {
+ performance: Math.round(categories.performance.score * 100),
+ accessibility: Math.round(categories.accessibility.score * 100),
+ bestPractices: Math.round(categories['best-practices'].score * 100),
+ seo: Math.round(categories.seo.score * 100),
+ lcp: lcp.numericValue,
+ fcp: fcp.numericValue,
+ tbt: tbt.numericValue,
+ cls: parseFloat(cls.displayValue)
+ };
+}
+
+async function main() {
+ console.log('\n🚀 PageSpeed Insights API Test');
+ console.log('================================\n');
+ console.log(`URL: ${URL_TO_TEST}`);
+ console.log(`API Key: ${API_KEY.substring(0, 10)}...`);
+
+ try {
+ // Mobile Test
+ const mobileData = await runPageSpeedTest(URL_TO_TEST, 'mobile');
+ const mobileResults = displayResults(mobileData, 'mobile');
+
+ // Desktop Test
+ console.log('\n\n');
+ const desktopData = await runPageSpeedTest(URL_TO_TEST, 'desktop');
+ const desktopResults = displayResults(desktopData, 'desktop');
+
+ // Summary
+ console.log('\n\n📋 ZUSAMMENFASSUNG:');
+ console.log('═'.repeat(60));
+ console.log(`\n 📱 Mobile:`);
+ console.log(` Performance: ${formatScore(mobileResults.performance / 100)}`);
+ console.log(` LCP: ${formatTime(mobileResults.lcp)}`);
+ console.log(` TBT: ${formatTime(mobileResults.tbt)}`);
+ console.log(`\n 🖥️ Desktop:`);
+ console.log(` Performance: ${formatScore(desktopResults.performance / 100)}`);
+ console.log(` LCP: ${formatTime(desktopResults.lcp)}`);
+ console.log(` TBT: ${formatTime(desktopResults.tbt)}`);
+ console.log('\n' + '═'.repeat(60));
+
+ } catch (error) {
+ console.error('\n❌ Test fehlgeschlagen:', error.message);
+ process.exit(1);
+ }
+}
+
+main();