Fix listing sort order: order by pubDate, matching the date displayed
Deploy / build (push) Successful in 36s
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:
+24
-7
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
);
|
||||
|
||||
|
||||
@@ -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/`}>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user