Fix listing sort order: order by pubDate, matching the date displayed
Deploy / build (push) Successful in 36s

Listings render `pubDate` but sorted by `updatedDate ?? pubDate`, so any
post carrying both dates sorted by a date it never displayed. After the
backdate commit the two diverged by years and the list read out of order
("January 7, 2026" above "September 13, 2026", "March 11, 2026" below
"December 10, 2025").

Replace `sortByUpdated` with `sortForListing`, which orders by `pubDate`
and uses `updatedDate` only as a tiebreak. This matches the RSS feed,
which already sorted by `pubDate`.

Verified all three listings (EN, EN homepage, ZH) are monotonically
non-increasing across the full 2024-09 -> 2026-09 span.
This commit is contained in:
2026-09-21 21:57:10 +08:00
parent ae2ccedaad
commit 2df67b6c50
6 changed files with 34 additions and 17 deletions
+24 -7
View File
@@ -2,16 +2,33 @@ import type { CollectionEntry } from 'astro:content';
type Post = CollectionEntry<'posts'>;
/**
* Newest-first ordering for listings.
*
* Ordered by `pubDate` — the date the listing actually *renders* — so the
* visible order always matches the visible dates. `updatedDate` is only a
* tiebreak, for stable ordering when two posts share a publish date.
*
* Do NOT sort by `updatedDate ?? pubDate` here: listings display `pubDate`,
* so a revised-and-backdated post would sort by a date it never shows and the
* list would read out of order (e.g. "January 7, 2026" appearing above
* "September 13, 2026").
*/
export function sortForListing(posts: Post[]): Post[] {
return [...posts].sort((a, b) => {
const byPub = b.data.pubDate.valueOf() - a.data.pubDate.valueOf();
if (byPub !== 0) return byPub;
const aUpd = a.data.updatedDate?.valueOf() ?? 0;
const bUpd = b.data.updatedDate?.valueOf() ?? 0;
return bUpd - aUpd;
});
}
/**
* Effective "last updated" timestamp for a post — `updatedDate` when present,
* else `pubDate`. Used to sort listings newest-first by *update time*, so a
* revised post resurfaces to the top.
* else `pubDate`. Used where *recency of editing* is what matters (e.g.
* deciding whether a post resurfaced), NOT for rendering order.
*/
export function updatedAt(post: Post): Date {
return post.data.updatedDate ?? post.data.pubDate;
}
/** Sort posts newest-first by update time (updatedDate ?? pubDate). */
export function sortByUpdated(posts: Post[]): Post[] {
return [...posts].sort((a, b) => updatedAt(b).valueOf() - updatedAt(a).valueOf());
}
+2 -2
View File
@@ -5,7 +5,7 @@ import PostList from '../../components/PostList.astro';
import CategoryArt from '../../components/CategoryArt.astro';
import { getCollection } from 'astro:content';
import { isEn } from '../../lib/lang';
import { sortByUpdated } from '../../lib/sort';
import { sortForListing } from '../../lib/sort';
import { categoryMeta } from '../../lib/categories';
export async function getStaticPaths() {
@@ -17,7 +17,7 @@ export async function getStaticPaths() {
const { category } = Astro.params;
const meta = categoryMeta(category as string);
const posts = sortByUpdated(
const posts = sortForListing(
(await getCollection('posts', isEn)).filter((p) => p.data.category === category),
);
+2 -2
View File
@@ -4,9 +4,9 @@ import PostList from '../components/PostList.astro';
import { getCollection } from 'astro:content';
import { isEn } from '../lib/lang';
import { SITE } from '../config';
import { sortByUpdated } from '../lib/sort';
import { sortForListing } from '../lib/sort';
const posts = sortByUpdated(await getCollection('posts', isEn));
const posts = sortForListing(await getCollection('posts', isEn));
---
<BaseLayout title={SITE.title} description={SITE.description} altLocaleUrl={`${SITE.url}/zh/`}>
+2 -2
View File
@@ -3,10 +3,10 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
import PostList from '../../components/PostList.astro';
import { getCollection } from 'astro:content';
import { isEn } from '../../lib/lang';
import { sortByUpdated } from '../../lib/sort';
import { sortForListing } from '../../lib/sort';
import { SITE } from '../../config';
const posts = sortByUpdated(await getCollection('posts', isEn));
const posts = sortForListing(await getCollection('posts', isEn));
---
<BaseLayout
+2 -2
View File
@@ -5,7 +5,7 @@ import PostList from '../../../components/PostList.astro';
import CategoryArt from '../../../components/CategoryArt.astro';
import { getCollection } from 'astro:content';
import { isZh } from '../../../lib/lang';
import { sortByUpdated } from '../../../lib/sort';
import { sortForListing } from '../../../lib/sort';
import { categoryMeta } from '../../../lib/categories';
export async function getStaticPaths() {
@@ -17,7 +17,7 @@ export async function getStaticPaths() {
const { category } = Astro.params;
const meta = categoryMeta(category as string);
const posts = sortByUpdated(
const posts = sortForListing(
(await getCollection('posts', isZh)).filter((p) => p.data.category === category),
);
+2 -2
View File
@@ -4,9 +4,9 @@ import PostList from '../../components/PostList.astro';
import { getCollection } from 'astro:content';
import { isZh } from '../../lib/lang';
import { SITE } from '../../config';
import { sortByUpdated } from '../../lib/sort';
import { sortForListing } from '../../lib/sort';
const posts = sortByUpdated(await getCollection('posts', isZh));
const posts = sortForListing(await getCollection('posts', isZh));
---
<BaseLayout