optimize for SEO
· 1 year ago
4dd2ba0e149e05ec3803a038efe5900e214ee483
Parent:
c5c4198c1
1 file changed +132 −46
- lifestyle-calculator.html +132 −46
Diff
--- a/lifestyle-calculator.html +++ b/lifestyle-calculator.html @@ -12,6 +12,7 @@ <meta content="https://cheatsheets.davidveksler.com/lifestyle-calculator.html" property="og:url"/> <meta content="Lifestyle Calculator: What Your Family's Income Really Buys" property="og:title"/> <meta content="Explore how different family income levels translate to real lifestyle choices, with a basic Cost of Living Adjustment. See what your household can afford from $20K to $25M+." property="og:description"/> + <meta content="images/lifestyle-calculator.png" property="og:image"/> <meta content="Interactive lifestyle calculator showing income to lifestyle progression " property="og:image:alt"/> <meta content="1200" property="og:image:width"/> <meta content="630" property="og:image:height"/> @@ -20,11 +21,32 @@ <meta content="https://cheatsheets.davidveksler.com/lifestyle-calculator.html" name="twitter:url"/> <meta content="Lifestyle Calculator: What Your Family's Income Really Buys" name="twitter:title"/> <meta content="Explore how different family income levels translate to real lifestyle choices, with a basic Cost of Living Adjustment. See what your household can afford from $20K to $25M+." name="twitter:description"/> - <link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" rel="stylesheet"/> + <meta content="images/lifestyle-calculator.png" name="twitter:image"/> + + <!-- SEO: JSON-LD Structured Data --> + <script type="application/ld+json"> + { + "@context": "https://schema.org", + "@type": "WebApplication", + "name": "Lifestyle Calculator: What Your Family's Income Really Buys", + "description": "An interactive tool to explore how family income levels from $20K to $25M+ translate to real-world lifestyle choices in housing, dining, travel, and more, with cost of living adjustments.", + "applicationCategory": "FinanceApplication", + "operatingSystem": "All", + "browserRequirements": "Requires a modern web browser with JavaScript enabled.", + "url": "https://cheatsheets.davidveksler.com/lifestyle-calculator.html", + "creator": { + "@type": "Person", + "name": "David Veksler" + }, + "keywords": "lifestyle calculator, income lifestyle, family budget, what can I afford, salary lifestyle, finance, cost of living, financial planning" + } + </script> + + <link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"/> <link href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css" rel="stylesheet"/> <link href="https://fonts.googleapis.com" rel="preconnect"/> <link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/> - <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Roboto+Slab:wght@700&display=swap" rel="stylesheet"/> + <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Roboto+Slab:wght@700&display=swap" rel="stylesheet"/> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <style> :root { @@ -253,7 +275,7 @@ <div id="background-layer-2"></div> </div> -<div class="container"> +<main class="container"> <div class="main-container"> <div class="text-center"> <h1 class="page-title">💰 Lifestyle Calculator</h1> @@ -267,7 +289,7 @@ <div class="row"> <div class="col-md-6 mb-3 mb-md-0"> <label class="form-label" for="colaSelector">Cost of Living Adjustment (COLA):</label> - <select class="form-select form-select-sm" id="colaSelector"><!-- Options populated by JS --></select> + <select class="form-select form-select-sm" id="colaSelector"></select> </div> <div class="col-md-6"> <label class="form-label" for="familySizeSelector">Household / Life Stage:</label> @@ -297,21 +319,32 @@ <div class="row"> <div class="col-lg-6"> - <div class="lifestyle-category dining fade-in"><div class="category-title"><i class="bi bi-egg-fried category-icon"></i> Dining & Food</div><div id="dining-content"></div></div> - <div class="lifestyle-category travel fade-in"><div class="category-title"><i class="bi bi-airplane category-icon"></i> Travel & Vacations</div><div id="travel-content"></div></div> - <div class="lifestyle-category housing fade-in"><div class="category-title"><i class="bi bi-house-door category-icon"></i> Housing & Living</div><div id="housing-content"></div></div> + <div class="lifestyle-category dining fade-in"><div class="category-title"><i class="bi bi-egg-fried category-icon"></i> Dining & Food</div><div id="dining-content"></div></div> + <div class="lifestyle-category travel fade-in"><div class="category-title"><i class="bi bi-airplane category-icon"></i> Travel & Vacations</div><div id="travel-content"></div></div> + <div class="lifestyle-category housing fade-in"><div class="category-title"><i class="bi bi-house-door category-icon"></i> Housing & Living</div><div id="housing-content"></div></div> <div class="lifestyle-category transportation fade-in"><div class="category-title"><i class="bi bi-car-front-fill category-icon"></i> Transportation</div><div id="transportation-content"></div></div> </div> <div class="col-lg-6"> - <div class="lifestyle-category entertainment fade-in"><div class="category-title"><i class="bi bi-dice-5-fill category-icon"></i> Entertainment & Hobbies</div><div id="entertainment-content"></div></div> - <div class="lifestyle-category education fade-in"><div class="category-title"><i class="bi bi-book-half category-icon"></i> Education & Growth</div><div id="education-content"></div></div> + <div class="lifestyle-category entertainment fade-in"><div class="category-title"><i class="bi bi-dice-5-fill category-icon"></i> Entertainment & Hobbies</div><div id="entertainment-content"></div></div> + <div class="lifestyle-category education fade-in"><div class="category-title"><i class="bi bi-book-half category-icon"></i> Education & Growth</div><div id="education-content"></div></div> <div class="lifestyle-category health-wellness fade-in"><div class="category-title"><i class="bi bi-heart-pulse-fill category-icon"></i> Health & Wellness</div><div id="health-wellness-content"></div></div> <div class="lifestyle-category services fade-in"><div class="category-title"><i class="bi bi-person-check-fill category-icon"></i> Personal Services</div><div id="services-content"></div></div> - <div class="lifestyle-category financial-planning fade-in"><div class="category-title"><i class="bi bi-piggy-bank category-icon"></i> Financial Planning & Investments</div><div id="financial-services-content"></div></div> + <div class="lifestyle-category financial-planning fade-in"><div class="category-title"><i class="bi bi-piggy-bank category-icon"></i> Financial Planning & Investments</div><div id="financial-services-content"></div></div> </div> </div> </div> -</div> +</main> + +<footer class="container text-center py-3"> + <div> + <a class="mx-2 link-secondary" href="https://www.linkedin.com/in/davidveksler/" target="_blank" title="David Veksler on LinkedIn"> + <i class="bi bi-linkedin"></i> LinkedIn + </a> + <a class="mx-2 link-secondary" href="https://cheatsheets.davidveksler.com/" title="Browse All Cheatsheets"> + <i class="bi bi-collection"></i> All Cheatsheets + </a> + </div> +</footer> <div id="milestone-popup"> <span id="milestone-emoji"></span> @@ -375,48 +408,101 @@ function updateBudgetChart(bracketIndex) { const labels = Object.keys(bracketData.budgetAllocation); const data = Object.values(bracketData.budgetAllocation); + + // A more sophisticated, financial-themed color palette + const colorPalette = [ + '#2d4059', // Deep Blue + '#ea5455', // Muted Red + '#f07b3f', // Orange + '#ffd460', // Yellow + '#7e9a9a', // Teal-Gray + '#4a6c6f', // Darker Teal + '#99a8b2', // Light Slate + '#596e79' // Medium Slate + ]; - if (budgetChart) { - budgetChart.data.labels = labels; - budgetChart.data.datasets[0].data = data; - budgetChart.update('none'); // Update without animation - } else { - const ctx = document.getElementById('budgetChart').getContext('2d'); - budgetChart = new Chart(ctx, { - type: 'doughnut', - data: { - labels: labels, - datasets: [{ - label: 'Budget Allocation', - data: data, - backgroundColor: ['#0d6efd', '#198754', '#ffc107', '#fd7e14', '#6f42c1', '#d63384', '#20c997', '#6c757d'], - borderColor: '#fff', - borderWidth: 2, - hoverOffset: 4 - }] + const chartConfig = { + type: 'doughnut', + data: { + labels: labels, + datasets: [{ + label: 'Budget Allocation', + data: data, + backgroundColor: colorPalette, + borderColor: '#ffffff', + borderWidth: 3, + hoverBorderColor: '#f8f9fa', + hoverBorderWidth: 1, + hoverOffset: 8 + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + cutout: '70%', // Makes the doughnut a bit thinner and more modern + animation: { + animateScale: true, + animateRotate: true }, - options: { - responsive: true, - maintainAspectRatio: false, - plugins: { - legend: { display: false }, - tooltip: { - callbacks: { - label: function(context) { - let label = context.label || ''; - if (label) { - label += ': '; - } - if (context.parsed !== null) { - label += context.parsed + '%'; - } - return label; + plugins: { + legend: { + display: true, + position: 'right', // Display labels in a legend + align: 'center', + labels: { + boxWidth: 12, + padding: 15, + font: { + size: 11, + family: "'Inter', sans-serif" + }, + color: '#495057' + } + }, + tooltip: { + enabled: true, + backgroundColor: 'rgba(0, 0, 0, 0.8)', + titleFont: { + size: 14, + weight: 'bold' + }, + bodyFont: { + size: 12 + }, + padding: 12, + cornerRadius: 8, + callbacks: { + label: function(context) { + let label = context.label || ''; + if (label) { + label += ': '; + } + if (context.parsed !== null) { + label += context.parsed + '%'; } + return label; } } } + }, + layout: { + padding: { + left: 0, + right: 10 // Add padding to ensure legend labels are not cut off + } } - }); + } + }; + + if (budgetChart) { + budgetChart.data.labels = labels; + budgetChart.data.datasets[0].data = data; + // Re-apply config on update to ensure settings persist + budgetChart.options = chartConfig.options; + budgetChart.update(); // Use default animation on update + } else { + const ctx = document.getElementById('budgetChart').getContext('2d'); + budgetChart = new Chart(ctx, chartConfig); } }