feat: Initialize SvelteKit project, add tsconfig.json, and introduce a new Calculator.svelte component.
This commit is contained in:
37
hdyc-svelte/src/routes/+layout.svelte
Normal file
37
hdyc-svelte/src/routes/+layout.svelte
Normal file
@@ -0,0 +1,37 @@
|
||||
<script lang="ts">
|
||||
import '../app.css';
|
||||
import Sidebar from '$lib/components/Sidebar.svelte';
|
||||
import SearchBar from '$lib/components/SearchBar.svelte';
|
||||
|
||||
let sidebarOpen = false;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" href="/favicon.png" />
|
||||
</svelte:head>
|
||||
|
||||
<header class="site-header">
|
||||
<div style="display:flex;align-items:center;gap:0.75rem;">
|
||||
<button class="hamburger" on:click={() => (sidebarOpen = !sidebarOpen)} aria-label="Toggle menu">
|
||||
☰
|
||||
</button>
|
||||
<a href="/" class="site-logo">
|
||||
<span>How Do You</span><span class="logo-accent">Convert</span><span style="opacity:0.4;font-weight:400">.com</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<SearchBar />
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="site-body">
|
||||
<Sidebar bind:open={sidebarOpen} />
|
||||
<main class="main-content">
|
||||
<slot />
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<footer class="site-footer">
|
||||
© {new Date().getFullYear()} HowDoYouConvert.com — Free unit conversion calculators. All rights reserved.
|
||||
</footer>
|
||||
44
hdyc-svelte/src/routes/+page.svelte
Normal file
44
hdyc-svelte/src/routes/+page.svelte
Normal file
@@ -0,0 +1,44 @@
|
||||
<script lang="ts">
|
||||
import { getCategoriesWithCounts, calculators } from '$lib/data/calculators';
|
||||
import CategoryCard from '$lib/components/CategoryCard.svelte';
|
||||
import SearchBar from '$lib/components/SearchBar.svelte';
|
||||
|
||||
const cats = getCategoriesWithCounts();
|
||||
const totalCalculators = calculators.length;
|
||||
const totalCategories = cats.length;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>HowDoYouConvert.com — Free Unit Conversion Calculators</title>
|
||||
<meta name="description" content="Convert between hundreds of units instantly. Free online calculators for length, weight, temperature, volume, area, speed, energy, power, data and more." />
|
||||
</svelte:head>
|
||||
|
||||
<section class="hero">
|
||||
<h1>How Do You Convert?</h1>
|
||||
<p>Instant, bidirectional unit conversions — no ads, no clutter, just answers.</p>
|
||||
<div class="search-center">
|
||||
<SearchBar />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="stats-row">
|
||||
<div class="stat">
|
||||
<div class="stat-num">{totalCalculators}</div>
|
||||
<div class="stat-label">Converters</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-num">{totalCategories}</div>
|
||||
<div class="stat-label">Categories</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-num">0ms</div>
|
||||
<div class="stat-label">Load Time</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="section-heading">Browse by Category</h2>
|
||||
<div class="category-grid">
|
||||
{#each cats as cat}
|
||||
<CategoryCard icon={cat.icon} label={cat.label} href="/category/{cat.key}" />
|
||||
{/each}
|
||||
</div>
|
||||
27
hdyc-svelte/src/routes/[slug]/+page.server.ts
Normal file
27
hdyc-svelte/src/routes/[slug]/+page.server.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { error } from '@sveltejs/kit';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { getCalculatorBySlug, getCalculatorsByCategory, categories } from '$lib/data/calculators';
|
||||
|
||||
export const load: PageServerLoad = ({ params }) => {
|
||||
const calc = getCalculatorBySlug(params.slug);
|
||||
|
||||
if (!calc) {
|
||||
throw error(404, {
|
||||
message: `Calculator "${params.slug}" not found`
|
||||
});
|
||||
}
|
||||
|
||||
// Get related calculators from the same category (excluding this one)
|
||||
const related = getCalculatorsByCategory(calc.category)
|
||||
.filter(c => c.slug !== calc.slug)
|
||||
.slice(0, 8);
|
||||
|
||||
const categoryMeta = categories[calc.category];
|
||||
|
||||
return {
|
||||
calculator: calc,
|
||||
related,
|
||||
categoryLabel: categoryMeta?.label ?? calc.category,
|
||||
categoryIcon: categoryMeta?.icon ?? '🔢'
|
||||
};
|
||||
};
|
||||
73
hdyc-svelte/src/routes/[slug]/+page.svelte
Normal file
73
hdyc-svelte/src/routes/[slug]/+page.svelte
Normal file
@@ -0,0 +1,73 @@
|
||||
<script lang="ts">
|
||||
import Calculator from '$lib/components/Calculator.svelte';
|
||||
import type { PageData } from './$types';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
$: calc = data.calculator;
|
||||
$: related = data.related;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{calc.name} — HowDoYouConvert.com</title>
|
||||
<meta name="description" content="Convert {calc.labels.in1} to {calc.labels.in2} instantly with our free online calculator. Accurate bidirectional conversion with the exact formula shown." />
|
||||
</svelte:head>
|
||||
|
||||
<nav class="breadcrumbs">
|
||||
<a href="/">Home</a>
|
||||
<span class="sep">›</span>
|
||||
<a href="/category/{calc.category}">{data.categoryIcon} {data.categoryLabel}</a>
|
||||
<span class="sep">›</span>
|
||||
<span>{calc.name}</span>
|
||||
</nav>
|
||||
|
||||
<Calculator config={calc} />
|
||||
|
||||
<div class="seo-content">
|
||||
{#if calc.descriptionHTML}
|
||||
{@html calc.descriptionHTML}
|
||||
{:else}
|
||||
<h3>How to convert {calc.labels.in1} to {calc.labels.in2}</h3>
|
||||
{#if calc.type === 'standard' && calc.factor}
|
||||
<p>
|
||||
The conversion between {calc.labels.in1.toLowerCase()} and {calc.labels.in2.toLowerCase()}
|
||||
uses a fixed multiplication factor. One {calc.labels.in1.toLowerCase().replace(/s$/, '')} equals
|
||||
{calc.factor}{calc.offset ? ` plus an offset of ${calc.offset}` : ''} {calc.labels.in2.toLowerCase()}.
|
||||
{#if calc.offset}
|
||||
This offset is common in temperature conversions, where scales differ not just in magnitude but also in their zero point.
|
||||
{/if}
|
||||
</p>
|
||||
<p>
|
||||
To convert, multiply the value in {calc.labels.in1.toLowerCase()} by {calc.factor}{calc.offset ? `, then add ${calc.offset}` : ''}.
|
||||
To convert in the opposite direction, {calc.offset ? `subtract ${calc.offset}, then ` : ''}divide by {calc.factor}.
|
||||
</p>
|
||||
{:else if calc.type === '3col' || calc.type === '3col-mul'}
|
||||
<p>
|
||||
This is a three-variable conversion. Enter any two of the three values
|
||||
— {calc.labels.in1}, {calc.labels.in2}, and {calc.labels.in3} — and the third
|
||||
will be calculated automatically.
|
||||
</p>
|
||||
{:else if calc.type === 'base'}
|
||||
<p>
|
||||
Number system conversion between base-{calc.fromBase} ({calc.labels.in1.toLowerCase()}) and
|
||||
base-{calc.toBase} ({calc.labels.in2.toLowerCase()}). Enter a value in either field and the
|
||||
equivalent representation will appear in the other.
|
||||
</p>
|
||||
{:else}
|
||||
<p>
|
||||
Enter a value in the field for {calc.labels.in1.toLowerCase()} and the equivalent
|
||||
in {calc.labels.in2.toLowerCase()} will be calculated instantly. The conversion
|
||||
works bidirectionally — modify either field and the other updates in real time.
|
||||
</p>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if related.length > 0}
|
||||
<h3 class="section-heading">Related Converters</h3>
|
||||
<div class="related-grid">
|
||||
{#each related as rel}
|
||||
<a href="/{rel.slug}" class="related-chip">{rel.name}</a>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
21
hdyc-svelte/src/routes/category/[category]/+page.server.ts
Normal file
21
hdyc-svelte/src/routes/category/[category]/+page.server.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { error } from '@sveltejs/kit';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { getCalculatorsByCategory, categories } from '$lib/data/calculators';
|
||||
|
||||
export const load: PageServerLoad = ({ params }) => {
|
||||
const cat = params.category;
|
||||
const meta = categories[cat];
|
||||
|
||||
if (!meta) {
|
||||
throw error(404, { message: `Category "${cat}" not found` });
|
||||
}
|
||||
|
||||
const calcs = getCalculatorsByCategory(cat);
|
||||
|
||||
return {
|
||||
category: cat,
|
||||
label: meta.label,
|
||||
icon: meta.icon,
|
||||
calculators: calcs
|
||||
};
|
||||
};
|
||||
30
hdyc-svelte/src/routes/category/[category]/+page.svelte
Normal file
30
hdyc-svelte/src/routes/category/[category]/+page.svelte
Normal file
@@ -0,0 +1,30 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
|
||||
export let data: PageData;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{data.label} Converters — HowDoYouConvert.com</title>
|
||||
<meta name="description" content="Browse all {data.label.toLowerCase()} unit converters. Free online calculators for converting between {data.label.toLowerCase()} units." />
|
||||
</svelte:head>
|
||||
|
||||
<nav class="breadcrumbs">
|
||||
<a href="/">Home</a>
|
||||
<span class="sep">›</span>
|
||||
<span>{data.icon} {data.label}</span>
|
||||
</nav>
|
||||
|
||||
<h1 class="page-title">{data.icon} {data.label} Converters</h1>
|
||||
<p class="page-subtitle">
|
||||
{data.calculators.length} converter{data.calculators.length !== 1 ? 's' : ''} available in this category.
|
||||
Select any conversion below to get started.
|
||||
</p>
|
||||
|
||||
<div class="calc-list">
|
||||
{#each data.calculators as calc}
|
||||
<a href="/{calc.slug}" class="calc-list-item">
|
||||
{calc.name}
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
30
hdyc-svelte/src/routes/sitemap.xml/+server.ts
Normal file
30
hdyc-svelte/src/routes/sitemap.xml/+server.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import type { RequestHandler } from './$types';
|
||||
import { calculators } from '$lib/data/calculators';
|
||||
|
||||
export const GET: RequestHandler = async () => {
|
||||
const urls = calculators.map(
|
||||
(calc) => `
|
||||
<url>
|
||||
<loc>https://howdoyouconvert.com/${calc.slug}</loc>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>`
|
||||
);
|
||||
|
||||
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>https://howdoyouconvert.com/</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
${urls.join('')}
|
||||
</urlset>`;
|
||||
|
||||
return new Response(sitemap, {
|
||||
headers: {
|
||||
'Content-Type': 'application/xml',
|
||||
'Cache-Control': 'max-age=0, s-maxage=3600'
|
||||
}
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user