cars: Wikimedia Commons photos (cars.photos, card heroes, model gallery + lightbox, brand hero/logo), cars:photos + cars:refresh with --report-new, fold duplicate names (Golf VI, Peugot, Mustang Mach 1, Model 3/Y, i10/i30, Ceed, Lynk & Co)
All checks were successful
Deploy production / deploy (push) Successful in 3m0s
All checks were successful
Deploy production / deploy (push) Successful in 3m0s
This commit is contained in:
@@ -187,8 +187,8 @@
|
||||
|
||||
{#if data.cars.length}
|
||||
<ul class="grid">
|
||||
{#each data.cars as car (car.dex)}
|
||||
<li><CarCard {car} current={data.currentYear} /></li>
|
||||
{#each data.cars as car, i (car.dex)}
|
||||
<li><CarCard {car} current={data.currentYear} eager={i < 4} /></li>
|
||||
{/each}
|
||||
</ul>
|
||||
{:else}
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { PageServerLoad } from './$types';
|
||||
export const load: PageServerLoad = async ({ params }) => {
|
||||
const found = await getBrand(params.brand);
|
||||
if (!found) error(404, 'No such brand in the car pokedex');
|
||||
const { brand, models } = found;
|
||||
const { brand, models, hero } = found;
|
||||
return {
|
||||
brand: {
|
||||
slug: brand.slug,
|
||||
@@ -15,8 +15,15 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||
nlCount: brand.nlCount,
|
||||
firstYear: brand.firstYear,
|
||||
lastYear: brand.lastYear,
|
||||
sources: brand.sources
|
||||
sources: brand.sources,
|
||||
wikipedia: brand.wikipedia,
|
||||
logo: brand.logo,
|
||||
logoFile: brand.logoFile,
|
||||
logoAuthor: brand.logoAuthor,
|
||||
logoLicense: brand.logoLicense,
|
||||
photo: brand.photo
|
||||
},
|
||||
hero,
|
||||
models,
|
||||
currentYear: new Date().getFullYear(),
|
||||
seo: {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import BrandBadge from '#lib/cars/BrandBadge.svelte';
|
||||
import CarCard from '#lib/cars/CarCard.svelte';
|
||||
import { flag, fmtNumber, years } from '#lib/cars/shared.js';
|
||||
import { commonsPage, flag, fmtNumber, thumbAt, thumbSrcset, years } from '#lib/cars/shared.js';
|
||||
import ArrowLeft from 'lucide-svelte/icons/arrow-left';
|
||||
import type { PageProps } from './$types';
|
||||
|
||||
@@ -11,8 +11,46 @@
|
||||
|
||||
<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>
|
||||
{#if b.photo}
|
||||
<figure class="hero">
|
||||
<img
|
||||
src={thumbAt(b.photo, 960)}
|
||||
srcset={thumbSrcset(b.photo, [500, 960, 1280])}
|
||||
sizes="(min-width: 1152px) 1104px, 100vw"
|
||||
alt="{b.name} {data.hero?.model ?? ''}"
|
||||
fetchpriority="high"
|
||||
width="1280"
|
||||
height="480"
|
||||
/>
|
||||
{#if data.hero}
|
||||
<figcaption>
|
||||
{b.name}
|
||||
{data.hero.model} ·
|
||||
<a href={commonsPage(data.hero.file)} rel="noopener"
|
||||
>{data.hero.author ?? 'Wikimedia Commons'}</a
|
||||
>{#if data.hero.license}
|
||||
· {#if data.hero.licenseUrl}<a href={data.hero.licenseUrl} rel="noopener license"
|
||||
>{data.hero.license}</a
|
||||
>{:else}{data.hero.license}{/if}{/if}
|
||||
</figcaption>
|
||||
{/if}
|
||||
</figure>
|
||||
{/if}
|
||||
<header class="mt-6 mb-8 flex items-center gap-5">
|
||||
<BrandBadge name={b.name} size="lg" />
|
||||
{#if b.logo}
|
||||
<img
|
||||
class="logo"
|
||||
src={b.logo}
|
||||
alt="{b.name} logo"
|
||||
title="Logo: {b.logoAuthor ?? 'Wikimedia Commons'}{b.logoLicense
|
||||
? ` (${b.logoLicense})`
|
||||
: ''}"
|
||||
width="72"
|
||||
height="72"
|
||||
/>
|
||||
{:else}
|
||||
<BrandBadge name={b.name} size="lg" />
|
||||
{/if}
|
||||
<div>
|
||||
<h1 class="text-4xl font-semibold tracking-tight sm:text-5xl">{b.name}</h1>
|
||||
<p class="mt-2 text-[var(--site-muted)]">
|
||||
@@ -25,12 +63,18 @@
|
||||
</header>
|
||||
|
||||
<ul class="grid">
|
||||
{#each data.models as car (car.dex)}
|
||||
<li><CarCard {car} current={data.currentYear} /></li>
|
||||
{#each data.models as car, i (car.dex)}
|
||||
<li><CarCard {car} current={data.currentYear} eager={i < 4} /></li>
|
||||
{/each}
|
||||
</ul>
|
||||
<p class="mt-10 text-xs text-[var(--site-muted)]">
|
||||
Sorted by how many are registered in NL. Sources: {b.sources.join(', ')}.
|
||||
Sorted by how many are registered in NL. Sources: {b.sources.join(', ')}.{#if b.wikipedia}
|
||||
· <a href="https://en.wikipedia.org/wiki/{b.wikipedia.replace(/ /g, '_')}" rel="noopener"
|
||||
>{b.name} on Wikipedia</a
|
||||
>{/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.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -45,6 +89,46 @@
|
||||
.back:hover {
|
||||
color: var(--site-text);
|
||||
}
|
||||
.hero {
|
||||
position: relative;
|
||||
margin-top: 1.25rem;
|
||||
aspect-ratio: 8 / 3;
|
||||
overflow: hidden;
|
||||
border-radius: 1rem;
|
||||
border: 1px solid var(--site-border);
|
||||
background: var(--site-surface);
|
||||
}
|
||||
.hero img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
.hero figcaption {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
max-width: 100%;
|
||||
padding: 0.25rem 0.6rem;
|
||||
font-size: 0.7rem;
|
||||
color: rgb(255 255 255 / 0.85);
|
||||
background: rgb(0 0 0 / 0.5);
|
||||
border-top-left-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.hero figcaption a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.logo {
|
||||
width: 4.5rem;
|
||||
height: 4.5rem;
|
||||
object-fit: contain;
|
||||
padding: 0.5rem;
|
||||
border-radius: 1rem;
|
||||
background: #fff;
|
||||
border: 1px solid var(--site-border);
|
||||
}
|
||||
.grid {
|
||||
display: grid;
|
||||
gap: 0.75rem;
|
||||
|
||||
@@ -14,6 +14,7 @@ function publicCar(m: Model) {
|
||||
delete out.search;
|
||||
delete out.createdAt;
|
||||
delete out.updatedAt;
|
||||
delete out.photosCheckedAt;
|
||||
return {
|
||||
...(out as Omit<Model, 'id' | 'brandId' | 'search' | 'createdAt' | 'updatedAt'>),
|
||||
updatedAt: m.updatedAt?.toISOString() ?? null
|
||||
@@ -30,11 +31,12 @@ function publicVariant(v: Variant) {
|
||||
export const load: PageServerLoad = async ({ params }) => {
|
||||
const found = await getModel(params.brand, params.model);
|
||||
if (!found) error(404, 'No such car in the pokedex');
|
||||
const { model, brand, variants, prev, next } = found;
|
||||
const { model, brand, variants, photos, prev, next } = found;
|
||||
return {
|
||||
car: publicCar(model),
|
||||
brand: { slug: brand.slug, name: brand.name, country: brand.country },
|
||||
variants: variants.map(publicVariant),
|
||||
photos,
|
||||
prev,
|
||||
next,
|
||||
currentYear: new Date().getFullYear(),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import BrandBadge from '#lib/cars/BrandBadge.svelte';
|
||||
import FuelChip from '#lib/cars/FuelChip.svelte';
|
||||
import Gallery from '#lib/cars/Gallery.svelte';
|
||||
import {
|
||||
bodyLabel,
|
||||
dexLabel,
|
||||
@@ -174,6 +175,10 @@
|
||||
{/if}
|
||||
</header>
|
||||
|
||||
{#if data.photos.length}
|
||||
<Gallery photos={data.photos} name="{data.brand.name} {car.name}" wikipedia={car.wikipedia} />
|
||||
{/if}
|
||||
|
||||
{#if baseStats.length}
|
||||
<section class="card" aria-labelledby="stats">
|
||||
<h2 id="stats">base stats</h2>
|
||||
|
||||
Reference in New Issue
Block a user