spotters: brands, makers and operators with a logo first, activity order kept inside each group
All checks were successful
Deploy production / deploy (push) Successful in 1m6s

This commit is contained in:
2026-10-25 15:05:11 +00:00
parent 8045362852
commit 037a525f91
8 changed files with 25 additions and 15 deletions

View File

@@ -161,3 +161,8 @@ export function rankByActivity<T extends { id: number }>(tiles: T[], act: Map<nu
.sort((a, b) => b.s - a.s || a.i - b.i) .sort((a, b) => b.s - a.s || a.i - b.i)
.map((x) => x.t); .map((x) => x.t);
} }
/** Brands/makers/operators with a logo first; keeps the incoming order inside each group. */
export function logoFirst<T extends { logo: string | null }>(tiles: T[]) {
return [...tiles.filter((t) => t.logo), ...tiles.filter((t) => !t.logo)];
}

View File

@@ -3,6 +3,7 @@ import {
areasWithData, areasWithData,
groupActivity, groupActivity,
progress, progress,
logoFirst,
rankByActivity, rankByActivity,
seenByGroup seenByGroup
} from '#lib/server/spotting.js'; } from '#lib/server/spotting.js';
@@ -26,7 +27,7 @@ export const load: PageServerLoad = async ({ url }) => {
collected, collected,
areas, areas,
brands: overview.brands.map(({ slug, name, models }) => ({ slug, name, models })), brands: overview.brands.map(({ slug, name, models }) => ({ slug, name, models })),
topBrands: rankByActivity(overview.byNl, act) topBrands: logoFirst(rankByActivity(overview.byNl, act))
.slice(0, 16) .slice(0, 16)
.map(({ id, slug, name, models, nlCount, logo }) => ({ .map(({ id, slug, name, models, nlCount, logo }) => ({
slug, slug,

View File

@@ -1,11 +1,11 @@
import { carOverview } from '#lib/server/cars.js'; import { carOverview } from '#lib/server/cars.js';
import { seenByGroup } from '#lib/server/spotting.js'; import { logoFirst, seenByGroup } from '#lib/server/spotting.js';
import type { PageServerLoad } from './$types'; import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async () => { export const load: PageServerLoad = async () => {
const [{ byNl, stats }, seen] = await Promise.all([carOverview(), seenByGroup('cars')]); const [{ byNl, stats }, seen] = await Promise.all([carOverview(), seenByGroup('cars')]);
return { return {
brands: byNl.map(({ id, slug, name, models, nlCount, logo }) => ({ brands: logoFirst(byNl).map(({ id, slug, name, models, nlCount, logo }) => ({
seen: seen.get(id) ?? 0, seen: seen.get(id) ?? 0,
slug, slug,
name, name,

View File

@@ -3,6 +3,7 @@ import {
areasWithData, areasWithData,
groupActivity, groupActivity,
progress, progress,
logoFirst,
rankByActivity, rankByActivity,
seenByGroup seenByGroup
} from '#lib/server/spotting.js'; } from '#lib/server/spotting.js';
@@ -26,7 +27,7 @@ export const load: PageServerLoad = async ({ url }) => {
collected, collected,
areas, areas,
makers: overview.makers.map(({ slug, name, types }) => ({ slug, name, types })), makers: overview.makers.map(({ slug, name, types }) => ({ slug, name, types })),
topMakers: rankByActivity(overview.byBuilt, act) topMakers: logoFirst(rankByActivity(overview.byBuilt, act))
.slice(0, 16) .slice(0, 16)
.map(({ id, slug, name, types, built, logo }) => ({ .map(({ id, slug, name, types, built, logo }) => ({
slug, slug,

View File

@@ -1,11 +1,11 @@
import { planeOverview } from '#lib/server/planes.js'; import { planeOverview } from '#lib/server/planes.js';
import { seenByGroup } from '#lib/server/spotting.js'; import { logoFirst, seenByGroup } from '#lib/server/spotting.js';
import type { PageServerLoad } from './$types'; import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async () => { export const load: PageServerLoad = async () => {
const [{ byBuilt, stats }, seen] = await Promise.all([planeOverview(), seenByGroup('planes')]); const [{ byBuilt, stats }, seen] = await Promise.all([planeOverview(), seenByGroup('planes')]);
return { return {
makers: byBuilt.map(({ id, slug, name, types, built, logo }) => ({ makers: logoFirst(byBuilt).map(({ id, slug, name, types, built, logo }) => ({
seen: seen.get(id) ?? 0, seen: seen.get(id) ?? 0,
slug, slug,
name, name,

View File

@@ -3,6 +3,7 @@ import {
areasWithData, areasWithData,
groupActivity, groupActivity,
progress, progress,
logoFirst,
rankByActivity, rankByActivity,
seenByGroup seenByGroup
} from '#lib/server/spotting.js'; } from '#lib/server/spotting.js';
@@ -46,7 +47,7 @@ export const load: PageServerLoad = async ({ url }) => {
countries: overview.countries countries: overview.countries
.filter((c) => c.types >= 3 || c.name === filters.country) .filter((c) => c.types >= 3 || c.name === filters.country)
.map(({ name, types }) => ({ name, types })), .map(({ name, types }) => ({ name, types })),
topMakers: rankByActivity(overview.byBuilt, act) topMakers: logoFirst(rankByActivity(overview.byBuilt, act))
.slice(0, 16) .slice(0, 16)
.map(({ id, slug, name, types, built, logo }) => ({ .map(({ id, slug, name, types, built, logo }) => ({
slug, slug,
@@ -57,7 +58,8 @@ export const load: PageServerLoad = async ({ url }) => {
seen: seenMakers.get(id) ?? 0 seen: seenMakers.get(id) ?? 0
})), })),
// Operators from the chosen area first (the world region keeps the plain fleet-size order). // Operators from the chosen area first (the world region keeps the plain fleet-size order).
topOperators: (filters.area === 'world' topOperators: logoFirst(
filters.area === 'world'
? overview.operators ? overview.operators
: [...overview.operators].sort( : [...overview.operators].sort(
(a, b) => Number(home.has(b.country ?? '')) - Number(home.has(a.country ?? '')) (a, b) => Number(home.has(b.country ?? '')) - Number(home.has(a.country ?? ''))

View File

@@ -1,11 +1,11 @@
import { trainOverview } from '#lib/server/trains.js'; import { trainOverview } from '#lib/server/trains.js';
import { seenByGroup } from '#lib/server/spotting.js'; import { logoFirst, seenByGroup } from '#lib/server/spotting.js';
import type { PageServerLoad } from './$types'; import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async () => { export const load: PageServerLoad = async () => {
const [{ byBuilt, stats }, seen] = await Promise.all([trainOverview(), seenByGroup('trains')]); const [{ byBuilt, stats }, seen] = await Promise.all([trainOverview(), seenByGroup('trains')]);
return { return {
makers: byBuilt.map(({ id, slug, name, types, built, logo }) => ({ makers: logoFirst(byBuilt).map(({ id, slug, name, types, built, logo }) => ({
seen: seen.get(id) ?? 0, seen: seen.get(id) ?? 0,
slug, slug,
name, name,

View File

@@ -1,10 +1,11 @@
import { trainOverview } from '#lib/server/trains.js'; import { trainOverview } from '#lib/server/trains.js';
import { logoFirst } from '#lib/server/spotting.js';
import type { PageServerLoad } from './$types'; import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async () => { export const load: PageServerLoad = async () => {
const { operators, stats } = await trainOverview(); const { operators, stats } = await trainOverview();
return { return {
makers: operators.map(({ slug, name, types, logo }) => ({ makers: logoFirst(operators).map(({ slug, name, types, logo }) => ({
slug, slug,
name, name,
types, types,