cars: brand logos everywhere (search cards, brand grid, model headers), stricter logo matching + curated fixes, logo refresh in cars-photos
All checks were successful
Deploy production / deploy (push) Successful in 2m24s
All checks were successful
Deploy production / deploy (push) Successful in 2m24s
This commit is contained in:
@@ -15,6 +15,7 @@ const staticPaths = [
|
||||
'/lists',
|
||||
'/trackers/books',
|
||||
'/trackers/cars',
|
||||
'/trackers/cars/brands',
|
||||
'/trackers/music',
|
||||
'/projects/game-tracker',
|
||||
'/projects/game-tracker/pokemon',
|
||||
|
||||
@@ -9,7 +9,10 @@ export const load: PageServerLoad = async ({ url }) => {
|
||||
cars,
|
||||
total,
|
||||
pageSize: PAGE_SIZE,
|
||||
brands: overview.brands,
|
||||
brands: overview.brands.map(({ slug, name, models }) => ({ slug, name, models })),
|
||||
topBrands: overview.byNl
|
||||
.slice(0, 16)
|
||||
.map(({ slug, name, models, nlCount, logo }) => ({ slug, name, models, nlCount, logo })),
|
||||
stats: overview.stats,
|
||||
currentYear: new Date().getFullYear(),
|
||||
seo: {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import BrandTile from '#lib/cars/BrandTile.svelte';
|
||||
import CarCard from '#lib/cars/CarCard.svelte';
|
||||
import {
|
||||
BODIES,
|
||||
@@ -10,6 +11,7 @@
|
||||
fuelLabel,
|
||||
fmtCompact,
|
||||
fmtNumber,
|
||||
LOGO_NOTE,
|
||||
SORTS
|
||||
} from '#lib/cars/shared.js';
|
||||
import { Input } from '#lib/components/ui/input/index.js';
|
||||
@@ -92,6 +94,22 @@
|
||||
</div>
|
||||
</dl>
|
||||
|
||||
{#if !filtering && f.page === 1}
|
||||
<section class="mb-8" aria-labelledby="brands-heading">
|
||||
<div class="mb-3 flex items-baseline justify-between gap-3">
|
||||
<h2 id="brands-heading" class="text-lg font-semibold">brands</h2>
|
||||
<a href="/trackers/cars/brands" class="text-sm text-[var(--site-muted)] hover:underline"
|
||||
>all {fmtNumber(data.stats.brands)} brands →</a
|
||||
>
|
||||
</div>
|
||||
<ul class="brands">
|
||||
{#each data.topBrands as brand (brand.slug)}
|
||||
<li><BrandTile {brand} compact /></li>
|
||||
{/each}
|
||||
</ul>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
<form
|
||||
bind:this={form}
|
||||
method="GET"
|
||||
@@ -213,11 +231,17 @@
|
||||
register, CC0) and
|
||||
<a href="https://www.fueleconomy.gov/feg/download.shtml" class="underline">fueleconomy.gov</a>
|
||||
(US EPA/DOE). Models are grouped from registered trade names, so a few odd splits remain. Prices are
|
||||
average catalogue prices of new cars when first registered in NL. Blank means unknown.
|
||||
average catalogue prices of new cars when first registered in NL. Blank means unknown. Photos from
|
||||
Wikimedia Commons, credited on each car's page. {LOGO_NOTE}
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.brands {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr));
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
<script lang="ts">
|
||||
import BrandBadge from '#lib/cars/BrandBadge.svelte';
|
||||
import CarCard from '#lib/cars/CarCard.svelte';
|
||||
import { commonsPage, flag, fmtNumber, thumbAt, thumbSrcset, years } from '#lib/cars/shared.js';
|
||||
import {
|
||||
commonsPage,
|
||||
flag,
|
||||
fmtNumber,
|
||||
LOGO_NOTE,
|
||||
thumbAt,
|
||||
thumbSrcset,
|
||||
years
|
||||
} from '#lib/cars/shared.js';
|
||||
import ArrowLeft from 'lucide-svelte/icons/arrow-left';
|
||||
import type { PageProps } from './$types';
|
||||
|
||||
@@ -74,7 +82,9 @@
|
||||
>{/if}{#if b.logoFile}
|
||||
· Logo: <a href={commonsPage(b.logoFile)} rel="noopener"
|
||||
>{b.logoAuthor ?? 'Wikimedia Commons'}</a
|
||||
>{#if b.logoLicense}, {b.logoLicense}{/if}{/if}. Photos from Wikimedia Commons.
|
||||
>{#if b.logoLicense}, {b.logoLicense}{/if}{/if}. Photos from Wikimedia Commons.{#if b.logo}
|
||||
{LOGO_NOTE}{/if}
|
||||
<a href="/trackers/cars/brands" class="underline">All brands</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||
const { model, brand, variants, photos, prev, next } = found;
|
||||
return {
|
||||
car: publicCar(model),
|
||||
brand: { slug: brand.slug, name: brand.name, country: brand.country },
|
||||
brand: { slug: brand.slug, name: brand.name, country: brand.country, logo: brand.logo },
|
||||
variants: variants.map(publicVariant),
|
||||
photos,
|
||||
prev,
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
<header class="hero">
|
||||
<div class="flex items-center gap-4">
|
||||
<a href="/trackers/cars/{data.brand.slug}" aria-label="{data.brand.name} models"
|
||||
><BrandBadge name={data.brand.name} size="lg" /></a
|
||||
><BrandBadge name={data.brand.name} logo={data.brand.logo} size="lg" /></a
|
||||
>
|
||||
<div class="min-w-0">
|
||||
<p class="dex">{dexLabel(car.dex)}</p>
|
||||
|
||||
20
src/routes/trackers/cars/brands/+page.server.ts
Normal file
20
src/routes/trackers/cars/brands/+page.server.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { carOverview } from '#lib/server/cars.js';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
const { byNl, stats } = await carOverview();
|
||||
return {
|
||||
brands: byNl.map(({ slug, name, models, nlCount, logo }) => ({
|
||||
slug,
|
||||
name,
|
||||
models,
|
||||
nlCount,
|
||||
logo
|
||||
})),
|
||||
stats,
|
||||
seo: {
|
||||
title: 'Car brands',
|
||||
description: `All ${stats.brands} car brands in the pokedex with their logos, most common on Dutch roads first.`
|
||||
}
|
||||
};
|
||||
};
|
||||
49
src/routes/trackers/cars/brands/+page.svelte
Normal file
49
src/routes/trackers/cars/brands/+page.svelte
Normal file
@@ -0,0 +1,49 @@
|
||||
<script lang="ts">
|
||||
import BrandTile from '#lib/cars/BrandTile.svelte';
|
||||
import { LOGO_NOTE, fmtNumber } from '#lib/cars/shared.js';
|
||||
import ArrowLeft from 'lucide-svelte/icons/arrow-left';
|
||||
import type { PageProps } from './$types';
|
||||
|
||||
let { data }: PageProps = $props();
|
||||
const withLogo = $derived(data.brands.filter((b) => b.logo).length);
|
||||
</script>
|
||||
|
||||
<div class="mx-auto max-w-6xl px-4 py-12 sm:px-6 sm:py-16">
|
||||
<a href="/trackers/cars" class="back"><ArrowLeft size={15} /> all cars</a>
|
||||
<header class="mt-6 mb-8">
|
||||
<h1 class="text-4xl font-semibold tracking-tight sm:text-5xl">brands</h1>
|
||||
<p class="mt-3 max-w-2xl text-[var(--site-muted)]">
|
||||
All {fmtNumber(data.brands.length)} brands in the pokedex, the ones you see most on Dutch roads
|
||||
first. Tap one for its models.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<ul class="grid">
|
||||
{#each data.brands as brand (brand.slug)}
|
||||
<li><BrandTile {brand} /></li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
<p class="mt-10 text-xs leading-relaxed text-[var(--site-muted)]">
|
||||
{withLogo} of {data.brands.length} brands have a logo; the rest get a coloured monogram.
|
||||
{LOGO_NOTE} Each brand page credits its logo's author and licence.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.back {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
font-size: 0.85rem;
|
||||
color: var(--site-muted);
|
||||
}
|
||||
.back:hover {
|
||||
color: var(--site-text);
|
||||
}
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
|
||||
gap: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user