openvibers/openvibe.games Commits

New worlds: the menu card says when each world was published (#368)

OP OpenVibers committed 2 days ago · 3c78b914a3 · 2 files, +30 −8

Changes

ddiff --git a/apps/server/src/net/menuCard.test.ts b/apps/server/src/net/menuCard.test.ts
iindex 9e6e971..2f778f7 100644
---- a/apps/server/src/net/menuCard.test.ts
++++ b/apps/server/src/net/menuCard.test.ts
@@@ -78,8 +78,8 @@ describe('the menu network card (frame.menu-card@1)', () => {
})
expect(card.more).toEqual({ label: 'All worlds', url: 'https://openvibe.games/worlds' })
expect(card.items).toEqual([
-- { title: 'World a', meta: 'by Builder', url: 'https://openvibe.games/worlds/a' },
-- { title: 'Moon base', meta: 'by Builder', url: 'https://openvibe.games/worlds/b' },
++ { title: 'World a', meta: 'by Builder · just now', url: 'https://openvibe.games/worlds/a' },
++ { title: 'Moon base', meta: 'by Builder · just now', url: 'https://openvibe.games/worlds/b' },
])
expect(card.title.length).toBeLessThanOrEqual(60)
for (const item of card.items) {
@@@ -93,6 +93,13 @@ describe('the menu network card (frame.menu-card@1)', () => {
expect(contracts.validate('frame.menu-cards@1', [card]).valid).toBe(true)
})
++ it('says when each world was published, in the same short shape as the other cards', () => {
++ expect(cardFrom([world('a', { publishedAt: NOW - 2 * 86_400_000 })], NOW).items[0]!.meta).toBe('by Builder · 2d ago')
++ expect(cardFrom([world('a', { publishedAt: NOW - 3 * 3_600_000 })], NOW).items[0]!.meta).toBe('by Builder · 3h ago')
++ // An old row with no published stamp still says when it was made rather than nothing.
++ expect(cardFrom([world('a', { publishedAt: null, createdAt: NOW - 5 * 86_400_000 })], NOW).items[0]!.meta).toBe('by Builder · 5d ago')
++ })
++
it('sends at most six, and never a draft or a hidden world', () => {
const many = Array.from({ length: 8 }, (_, i) => world(`w${i}`))
expect(cardFrom(many, NOW).items).toHaveLength(6)
ddiff --git a/apps/server/src/net/menuCard.ts b/apps/server/src/net/menuCard.ts
iindex f990b7e..1d06401 100644
---- a/apps/server/src/net/menuCard.ts
++++ b/apps/server/src/net/menuCard.ts
@@@ -29,16 +29,31 @@ export function plain(value: unknown, max: number): string {
.slice(0, max)
}
--/** The card itself, newest published world first (the store's order). */
++/** A short age for the card's one meta line ("2d ago"), the same shape the other sites' cards print. */
++function shortAgo(ms: number, now: number): string {
++ const min = Math.max(0, Math.round((now - ms) / 60000))
++ if (min < 1) return 'just now'
++ if (min < 60) return `${min}m ago`
++ const h = Math.round(min / 60)
++ if (h < 24) return `${h}h ago`
++ return `${Math.round(h / 24)}d ago`
++}
++
++/** The card itself, newest published world first (the store's order), each saying when it was published. */
export function cardFrom(worlds: CreatorWorld[], at = Date.now()): MenuCard {
const items = (Array.isArray(worlds) ? worlds : [])
.filter((w) => w && w.id && w.status === 'published')
.slice(0, 6)
-- .map((w) => ({
-- title: plain(w.title, 80),
-- meta: `by ${plain(w.ownerName, 110)}`,
-- url: `${BASE}/worlds/${encodeURIComponent(w.id)}`,
-- }))
++ .map((w) => {
++ // A published world's own time; an old row with no published stamp falls back to when it was made.
++ const published = w.publishedAt ?? w.createdAt
++ const when = Number.isFinite(published) ? ` · ${shortAgo(published, at)}` : ''
++ return {
++ title: plain(w.title, 80),
++ meta: `by ${plain(w.ownerName, 100)}${when}`,
++ url: `${BASE}/worlds/${encodeURIComponent(w.id)}`,
++ }
++ })
return menuCard({
id: CARD_ID,
site: SITE,