Skip to content

Commit 153556a

Browse files
kitfunsoclaude
andcommitted
Improve accessibility, add categories, and enhance SEO
Accessibility fixes (medium/low priority): - Add keyboard navigation to TipCalculator table rows - Add ARIA labels to MetricCard, Alert SVGs - Improve footer semantic structure (nav instead of h3) - Add aria-hidden to decorative breadcrumb icons Categories and navigation: - Create Automotive category (EV vs Gas, Buy vs Lease, CO2) - Update Health category with new calculators - Add Automotive to main calculators index - Add 3 new calculators to homepage SEO improvements: - Internal linking between related calculators - Optimize meta descriptions for loan and tip calculators - Update calculator counts in index Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent d0e5312 commit 153556a

14 files changed

Lines changed: 280 additions & 55 deletions

File tree

src/components/calculators/TipCalculator/TipCalculator.tsx

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,20 @@ export default function TipCalculator() {
109109
</div>
110110

111111
{/* Quick Tip Buttons */}
112-
<div>
113-
<p className="text-sm text-[var(--color-subtle)] mb-2">Quick select:</p>
114-
<div className="flex flex-wrap gap-2">
112+
<div role="group" aria-label="Quick tip percentage selection">
113+
<p id="quick-select-label" className="text-sm text-[var(--color-subtle)] mb-2">
114+
Quick select:
115+
</p>
116+
<div
117+
className="flex flex-wrap gap-2"
118+
role="radiogroup"
119+
aria-labelledby="quick-select-label"
120+
>
115121
{[15, 18, 20, 25].map((pct) => (
116122
<button
117123
key={pct}
124+
role="radio"
125+
aria-checked={Math.round(inputs.tipPercentage * 100) === pct}
118126
onClick={() => selectTipPercentage(pct / 100)}
119127
className={`px-4 py-2 rounded-lg text-sm font-medium transition-all ${
120128
Math.round(inputs.tipPercentage * 100) === pct
@@ -131,15 +139,20 @@ export default function TipCalculator() {
131139
{/* Split Count */}
132140
<div>
133141
<Label htmlFor="splitCount">Split Between</Label>
134-
<div className="flex items-center gap-4">
142+
<div
143+
className="flex items-center gap-4"
144+
role="group"
145+
aria-label="Number of people to split bill"
146+
>
135147
<button
136148
onClick={() => updateInput('splitCount', Math.max(1, inputs.splitCount - 1))}
137-
className="w-12 h-12 rounded-full bg-[var(--color-night)] hover:bg-white/10 text-xl font-bold text-[var(--color-cream)] transition-all"
149+
aria-label="Decrease number of people"
150+
className="w-12 h-12 rounded-full bg-[var(--color-night)] hover:bg-white/10 text-xl font-bold text-[var(--color-cream)] transition-all disabled:opacity-50"
138151
disabled={inputs.splitCount <= 1}
139152
>
140153
141154
</button>
142-
<div className="flex-1 text-center">
155+
<div className="flex-1 text-center" aria-live="polite">
143156
<span className="text-3xl font-bold text-[var(--color-cream)]">
144157
{inputs.splitCount}
145158
</span>
@@ -149,7 +162,8 @@ export default function TipCalculator() {
149162
</div>
150163
<button
151164
onClick={() => updateInput('splitCount', Math.min(20, inputs.splitCount + 1))}
152-
className="w-12 h-12 rounded-full bg-[var(--color-night)] hover:bg-white/10 text-xl font-bold text-[var(--color-cream)] transition-all"
165+
aria-label="Increase number of people"
166+
className="w-12 h-12 rounded-full bg-[var(--color-night)] hover:bg-white/10 text-xl font-bold text-[var(--color-cream)] transition-all disabled:opacity-50"
153167
disabled={inputs.splitCount >= 20}
154168
>
155169
+
@@ -223,24 +237,43 @@ export default function TipCalculator() {
223237
Quick Reference
224238
</h3>
225239
<div className="overflow-x-auto">
226-
<table className="w-full text-sm">
240+
<table className="w-full text-sm" aria-label="Compare tip percentages">
227241
<thead>
228242
<tr className="text-[var(--color-muted)] text-xs uppercase tracking-wider">
229-
<th className="text-left py-2">Tip %</th>
230-
<th className="text-right py-2">Tip</th>
231-
<th className="text-right py-2">Total</th>
232-
{inputs.splitCount > 1 && <th className="text-right py-2">Per Person</th>}
243+
<th scope="col" className="text-left py-2">
244+
Tip %
245+
</th>
246+
<th scope="col" className="text-right py-2">
247+
Tip
248+
</th>
249+
<th scope="col" className="text-right py-2">
250+
Total
251+
</th>
252+
{inputs.splitCount > 1 && (
253+
<th scope="col" className="text-right py-2">
254+
Per Person
255+
</th>
256+
)}
233257
</tr>
234258
</thead>
235259
<tbody className="divide-y divide-white/10">
236260
{result.suggestions.map((suggestion) => (
237261
<tr
238262
key={suggestion.percentage}
263+
tabIndex={0}
264+
role="button"
265+
aria-pressed={suggestion.percentage === inputs.tipPercentage}
266+
onKeyDown={(e) => {
267+
if (e.key === 'Enter' || e.key === ' ') {
268+
e.preventDefault();
269+
selectTipPercentage(suggestion.percentage);
270+
}
271+
}}
239272
className={`${
240273
suggestion.percentage === inputs.tipPercentage
241274
? 'bg-green-900/40 font-medium text-green-400'
242-
: 'hover:bg-white/5'
243-
} cursor-pointer transition-colors`}
275+
: 'hover:bg-white/5 focus:bg-white/5'
276+
} cursor-pointer transition-colors focus:outline-none focus:ring-2 focus:ring-green-500/50`}
244277
onClick={() => selectTipPercentage(suggestion.percentage)}
245278
>
246279
<td className="py-2">{Math.round(suggestion.percentage * 100)}%</td>

src/components/ui/calculator/Alert.tsx

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,13 @@ const VARIANT_STYLES = {
4141

4242
const VARIANT_ICONS = {
4343
info: (
44-
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
44+
<svg
45+
className="w-5 h-5"
46+
fill="none"
47+
stroke="currentColor"
48+
viewBox="0 0 24 24"
49+
aria-hidden="true"
50+
>
4551
<path
4652
strokeLinecap="round"
4753
strokeLinejoin="round"
@@ -51,7 +57,13 @@ const VARIANT_ICONS = {
5157
</svg>
5258
),
5359
warning: (
54-
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
60+
<svg
61+
className="w-5 h-5"
62+
fill="none"
63+
stroke="currentColor"
64+
viewBox="0 0 24 24"
65+
aria-hidden="true"
66+
>
5567
<path
5668
strokeLinecap="round"
5769
strokeLinejoin="round"
@@ -61,7 +73,13 @@ const VARIANT_ICONS = {
6173
</svg>
6274
),
6375
error: (
64-
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
76+
<svg
77+
className="w-5 h-5"
78+
fill="none"
79+
stroke="currentColor"
80+
viewBox="0 0 24 24"
81+
aria-hidden="true"
82+
>
6583
<path
6684
strokeLinecap="round"
6785
strokeLinejoin="round"
@@ -71,7 +89,13 @@ const VARIANT_ICONS = {
7189
</svg>
7290
),
7391
success: (
74-
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
92+
<svg
93+
className="w-5 h-5"
94+
fill="none"
95+
stroke="currentColor"
96+
viewBox="0 0 24 24"
97+
aria-hidden="true"
98+
>
7599
<path
76100
strokeLinecap="round"
77101
strokeLinejoin="round"
@@ -81,7 +105,13 @@ const VARIANT_ICONS = {
81105
</svg>
82106
),
83107
tip: (
84-
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
108+
<svg
109+
className="w-5 h-5"
110+
fill="none"
111+
stroke="currentColor"
112+
viewBox="0 0 24 24"
113+
aria-hidden="true"
114+
>
85115
<path
86116
strokeLinecap="round"
87117
strokeLinejoin="round"

src/components/ui/calculator/MetricCard.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,13 @@ export function MetricCard({
4343
hover:border-white/20 transition-all
4444
${className}
4545
`}
46+
role="group"
47+
aria-label={label}
4648
>
47-
<p className="text-xs font-medium text-[var(--color-muted)] uppercase tracking-wider mb-1">
49+
<p
50+
className="text-xs font-medium text-[var(--color-muted)] uppercase tracking-wider mb-1"
51+
aria-hidden="true"
52+
>
4853
{label}
4954
</p>
5055
<p className={`text-xl md:text-2xl font-bold tabular-nums ${valueColorClass}`}>{value}</p>

src/layouts/BaseLayout.astro

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,8 @@ const ogImageURL = ogImage
289289
</div>
290290

291291
<!-- Quick Links -->
292-
<div class="md:col-span-3">
293-
<h3 class="text-micro text-[var(--color-muted)] mb-6">Quick Links</h3>
292+
<nav class="md:col-span-3" aria-label="Quick Links">
293+
<p class="text-micro text-[var(--color-muted)] mb-6">Quick Links</p>
294294
<ul class="space-y-4">
295295
<li>
296296
<a
@@ -317,11 +317,11 @@ const ogImageURL = ogImage
317317
</a>
318318
</li>
319319
</ul>
320-
</div>
320+
</nav>
321321

322322
<!-- Popular Tools -->
323-
<div class="md:col-span-4">
324-
<h3 class="text-micro text-[var(--color-muted)] mb-6">Popular Calculators</h3>
323+
<nav class="md:col-span-4" aria-label="Popular Calculators">
324+
<p class="text-micro text-[var(--color-muted)] mb-6">Popular Calculators</p>
325325
<ul class="space-y-4">
326326
<li>
327327
<a
@@ -356,7 +356,7 @@ const ogImageURL = ogImage
356356
</a>
357357
</li>
358358
</ul>
359-
</div>
359+
</nav>
360360
</div>
361361

362362
<!-- Bottom Bar -->

src/layouts/CategoryLayout.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ const webPageSchema = {
176176
<a href="/" class="text-[var(--color-muted)] hover:text-[var(--color-cream)] transition-colors">
177177
Home
178178
</a>
179-
<svg class="w-4 h-4 text-[var(--color-muted)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
179+
<svg class="w-4 h-4 text-[var(--color-muted)]" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
180180
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
181181
</svg>
182182
<span class="text-[var(--color-cream)]">{category} Calculators</span>
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
---
2+
/**
3+
* Automotive Calculators Hub Page
4+
*
5+
* SEO-optimized category page for car and vehicle calculators.
6+
* Targets: "ev calculator", "car cost calculator", "ev vs gas calculator"
7+
*/
8+
9+
import CategoryLayout from '../../../layouts/CategoryLayout.astro';
10+
11+
const category = 'Automotive';
12+
const title = 'Automotive Calculators | EV vs Gas, Car Costs & More';
13+
const description =
14+
'Free automotive calculators to compare EV vs gas costs, calculate car expenses, and make smarter vehicle decisions. Save money on your next car purchase.';
15+
const keywords =
16+
'ev vs gas calculator, electric car cost calculator, car cost comparison, ev savings calculator, car buy vs lease, fuel cost calculator, automotive calculator';
17+
const canonicalURL = '/calculators/automotive/';
18+
19+
const calculators = [
20+
{
21+
title: 'EV vs Gas Calculator',
22+
description: 'Compare total cost of ownership between electric and gas vehicles over time.',
23+
href: '/calculators/ev-vs-gas-calculator',
24+
icon: 'bolt',
25+
color: 'green',
26+
},
27+
{
28+
title: 'Car Buy vs Lease Calculator',
29+
description: 'Decide whether buying or leasing makes more financial sense for you.',
30+
href: '/calculators/car-buy-vs-lease-calculator',
31+
icon: 'swap',
32+
color: 'blue',
33+
},
34+
{
35+
title: 'CO2 Calculator',
36+
description: 'Calculate your carbon footprint from driving and other activities.',
37+
href: '/calculators/co2-calculator',
38+
icon: 'leaf',
39+
color: 'green',
40+
},
41+
];
42+
---
43+
44+
<CategoryLayout
45+
category={category}
46+
title={title}
47+
description={description}
48+
keywords={keywords}
49+
canonicalURL={canonicalURL}
50+
icon="bolt"
51+
color="green"
52+
tagline="Make smarter vehicle decisions with data-driven calculations"
53+
calculators={calculators}
54+
>
55+
<p>
56+
Our automotive calculators help you make informed decisions about vehicle ownership. Whether
57+
you're considering an electric vehicle, deciding between buying or leasing, or tracking your
58+
carbon footprint, these tools provide the data you need.
59+
</p>
60+
<p>
61+
The EV vs Gas calculator accounts for purchase price, fuel/electricity costs, maintenance,
62+
insurance, and available tax credits to give you a complete picture of ownership costs over
63+
time.
64+
</p>
65+
<h3>Key Considerations When Comparing Vehicles</h3>
66+
<ul>
67+
<li>
68+
<strong>Total Cost of Ownership:</strong> Include purchase price, fuel, maintenance, insurance,
69+
and depreciation
70+
</li>
71+
<li>
72+
<strong>EV Tax Credits:</strong> Federal credits up to $7,500 (US) can significantly reduce EV purchase
73+
costs
74+
</li>
75+
<li>
76+
<strong>Electricity Rates:</strong> Home charging is typically 3-4x cheaper than public fast charging
77+
</li>
78+
<li>
79+
<strong>Maintenance Savings:</strong> EVs have fewer moving parts, resulting in lower maintenance
80+
costs
81+
</li>
82+
<li>
83+
<strong>Break-Even Point:</strong> The time it takes for an EV's lower operating costs to offset
84+
its higher purchase price
85+
</li>
86+
</ul>
87+
<p class="text-sm mt-4 text-[var(--color-muted)]">
88+
<em>
89+
Note: Actual costs vary based on your location, driving habits, electricity rates, and
90+
specific vehicle models. Use these calculators as a starting point for your research.
91+
</em>
92+
</p>
93+
</CategoryLayout>

src/pages/calculators/baby-cost-calculator.astro

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ const breadcrumbs = [
3030
3131
// Related calculators
3232
const relatedCalculators = [
33+
{
34+
title: 'Due Date Calculator',
35+
description: 'Calculate your pregnancy due date and track milestones.',
36+
href: '/calculators/due-date-calculator',
37+
icon: 'calculator' as const,
38+
color: 'coral' as const,
39+
},
3340
{
3441
title: 'Emergency Fund Calculator',
3542
description: 'Build your safety net before baby arrives.',
@@ -44,13 +51,6 @@ const relatedCalculators = [
4451
icon: 'calculator' as const,
4552
color: 'green' as const,
4653
},
47-
{
48-
title: 'Subscription Audit',
49-
description: 'Find money to redirect to baby fund.',
50-
href: '/calculators/subscription-audit-calculator',
51-
icon: 'chart' as const,
52-
color: 'purple' as const,
53-
},
5454
];
5555
5656
// FAQ data

src/pages/calculators/calorie-calculator.astro

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,18 @@ const relatedCalculators = [
3838
color: 'purple' as const,
3939
},
4040
{
41-
title: 'Percentage Calculator',
42-
description: 'Calculate percentages for tracking macros.',
43-
href: '/calculators/percentage-calculator',
44-
icon: 'percent' as const,
45-
color: 'violet' as const,
41+
title: 'Sleep Calculator',
42+
description: 'Optimize your sleep for better health and recovery.',
43+
href: '/calculators/sleep-calculator',
44+
icon: 'bolt' as const,
45+
color: 'ocean' as const,
4646
},
4747
{
48-
title: 'Unit Converter',
49-
description: 'Convert between lbs/kg and other units.',
50-
href: '/calculators/unit-converter',
51-
icon: 'swap' as const,
52-
color: 'blue' as const,
48+
title: 'Macro Calculator',
49+
description: 'Calculate your ideal protein, carbs, and fat intake.',
50+
href: '/calculators/macro-calculator',
51+
icon: 'heart' as const,
52+
color: 'coral' as const,
5353
},
5454
];
5555

0 commit comments

Comments
 (0)