cars: keep MAZDA2/JAECOO7 names (no false typo strip), canonical upload.wikimedia.org thumbs, tidier gallery captions/credits
All checks were successful
Deploy production / deploy (push) Successful in 2m34s

This commit is contained in:
2026-10-24 16:54:14 +00:00
parent bf0a1e1d2a
commit 7636f0b2bc
3 changed files with 49 additions and 20 deletions

View File

@@ -391,12 +391,16 @@ function cleanTradeName(raw: string, make: string): string {
else if (s.startsWith(`${make} `) && s.length > make.length + 1) s = s.slice(make.length + 1); else if (s.startsWith(`${make} `) && s.length > make.length + 1) s = s.slice(make.length + 1);
else break; else break;
} }
// Make glued to a number ("MAZDA2 HYBRID" -> "2 HYBRID", "JAECOO7" -> "7").
const mk0 = make.replace(/[^A-Z]/g, '');
const glued = s.match(new RegExp(`^${mk0}(\\d+)\\b(.*)$`));
if (mk0.length >= 3 && glued) s = `${glued[1]}${glued[2]}`;
// Misspelt make as first word ("PEUGOT 205" under PEUGEOT). // Misspelt make as first word ("PEUGOT 205" under PEUGEOT).
const [w0, ...restW] = s.split(' '); const [w0, ...restW] = s.split(' ');
const mk0 = make.replace(/[^A-Z]/g, '');
if ( if (
restW.length && restW.length &&
mk0.length >= 5 && mk0.length >= 5 &&
/^[A-Z]+$/.test(w0) && // "MAZDA2 HYBRID" and "JAECOO7 PHEV" are names, not typos
w0 !== mk0 && w0 !== mk0 &&
w0.slice(0, 4) === mk0.slice(0, 4) && w0.slice(0, 4) === mk0.slice(0, 4) &&
Math.abs(w0.length - mk0.length) <= 1 Math.abs(w0.length - mk0.length) <= 1

View File

@@ -405,7 +405,10 @@ function toPhoto(
file, file,
kind, kind,
caption, caption,
thumb: info.thumburl, // Canonical host, no tracking query: https://upload.wikimedia.org/.../960px-<file>
thumb: info.thumburl
.replace(/\?.*$/, '')
.replace('//thumb.wikimedia.org/', '//upload.wikimedia.org/'),
width: info.width, width: info.width,
height: info.height, height: info.height,
author, author,

View File

@@ -14,8 +14,11 @@
let index = $state(0); let index = $state(0);
const current = $derived(photos[index]); const current = $derived(photos[index]);
const large = (p: CarPhoto) => thumbAt(p.thumb, p.width > 1280 ? 1280 : 960); const large = (p: CarPhoto) => thumbAt(p.thumb, p.width > 1280 ? 1280 : 960);
const norm = (s: string) => s.toLowerCase().replace(/[^a-z0-9]/g, '');
// Generation captions that just repeat the model name add nothing.
const caption = (p: CarPhoto) => (p.caption && norm(p.caption) !== norm(name) ? p.caption : null);
const alt = (p: CarPhoto, i: number) => const alt = (p: CarPhoto, i: number) =>
`${p.caption ?? name}, photo ${i + 1} of ${photos.length}`; `${caption(p) ?? name}, photo ${i + 1} of ${photos.length}`;
// Links go to the Commons file page; with JS they open the lightbox instead. // Links go to the Commons file page; with JS they open the lightbox instead.
function open(event: MouseEvent, i: number) { function open(event: MouseEvent, i: number) {
@@ -47,7 +50,7 @@
<ul class:single={photos.length === 1}> <ul class:single={photos.length === 1}>
{#each photos as p, i (p.file)} {#each photos as p, i (p.file)}
<li class:lead={i === 0}> <li class:lead={i === 0}>
<a href={commonsPage(p.file)} onclick={(e) => open(e, i)} title={p.caption ?? undefined}> <a href={commonsPage(p.file)} onclick={(e) => open(e, i)} title={caption(p) ?? undefined}>
<img <img
src={thumbAt(p.thumb, i === 0 ? 960 : 330)} src={thumbAt(p.thumb, i === 0 ? 960 : 330)}
srcset={i === 0 srcset={i === 0
@@ -61,24 +64,30 @@
width={p.width} width={p.width}
height={p.height} height={p.height}
/> />
{#if p.caption}<span class="cap">{p.caption}</span>{/if} {#if caption(p)}<span class="cap">{caption(p)}</span>{/if}
</a> </a>
</li> </li>
{/each} {/each}
</ul> </ul>
<div class="below">
<details class="credits"> <details class="credits">
<summary> <summary>
{photos.length} photo{photos.length === 1 ? '' : 's'} from Wikimedia Commons{#if wikipedia} {photos.length} photo{photos.length === 1 ? '' : 's'} from Wikimedia Commons · credits & licences
· <a href="https://en.wikipedia.org/wiki/{wikipedia.replace(/ /g, '_')}" rel="noopener"
>Wikipedia</a
>{/if} · credits
</summary> </summary>
<ol> <ol>
{#each photos as p, i (p.file)} {#each photos as p, i (p.file)}
<li>{i + 1}. {p.caption ?? p.file.replace(/\.\w+$/, '')}: {@render credit(p)}</li> <li>{i + 1}. {caption(p) ?? p.file.replace(/\.\w+$/, '')}: {@render credit(p)}</li>
{/each} {/each}
</ol> </ol>
</details> </details>
{#if wikipedia}
<a
class="wiki"
href="https://en.wikipedia.org/wiki/{wikipedia.replace(/ /g, '_')}"
rel="noopener">Read about it on Wikipedia ↗</a
>
{/if}
</div>
</section> </section>
<dialog bind:this={dialog} {onkeydown} {onclick} aria-label="{name} photos"> <dialog bind:this={dialog} {onkeydown} {onclick} aria-label="{name} photos">
@@ -89,8 +98,8 @@
{/key} {/key}
<figcaption> <figcaption>
<span <span
>{index + 1}/{photos.length}{#if current.caption} >{index + 1}/{photos.length}{#if caption(current)}
· {current.caption}{/if}</span · {caption(current)}{/if}</span
> >
<span class="credit">{@render credit(current)}</span> <span class="credit">{@render credit(current)}</span>
</figcaption> </figcaption>
@@ -178,6 +187,19 @@
font-size: 0.75rem; font-size: 0.75rem;
color: var(--site-muted); color: var(--site-muted);
} }
.below {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 1rem;
}
.wiki {
margin-top: 0.5rem;
flex: none;
font-size: 0.75rem;
color: var(--site-muted);
text-decoration: underline;
}
.credits summary { .credits summary {
cursor: pointer; cursor: pointer;
} }