openvibers/openvibe.inventory Commits

Item pages describe the item (name, rarity, kind, its words, how many own it, how it is got) instead of its flavor text alone (#59)

OP OpenVibers committed 24 days ago · cd674e2dec · 2 files, +23 −1

Changes

ddiff --git a/server/http/pages.js b/server/http/pages.js
iindex c8a62cc..6d7a334 100644
---- a/server/http/pages.js
++++ b/server/http/pages.js
@@@ -56,6 +56,21 @@ function card(d, { href = `/items/${d.id}`, extra = '', owned = null, worn = fal
</li>`;
}
++/** An item page's meta description (≤ 160 characters): its name, rarity and kind, its own words, how many own it, how it is got. */
++function itemDescription(d, k) {
++ const what = `${d.name}, a ${RARITY_LABEL[d.rarity].toLowerCase()} ${k.name.toLowerCase()} on OpenVibe`;
++ const words = d.description ? ` "${String(d.description).replace(/\s+/g, ' ').trim().replace(/[.!?]+$/, '')}".` : '.';
++ const owned = Number(d.supply && d.supply.issued) || 0;
++ const supply = d.supply && d.supply.cap != null ? ` ${owned} of ${d.supply.cap} given.` : ` Owned by ${owned} ${owned === 1 ? 'person' : 'people'}.`;
++ const grantors = d.grantors || [];
++ const how = d.status !== 'published' ? ' No longer given.'
++ : grantors.includes('service:quest') ? ' Earned on OpenVibe.Quest.'
++ : grantors.includes('service:games') ? ' Earned on OpenVibe.Games.'
++ : ' Given by its issuer, never sold.';
++ const text = `${what}${words}${supply}${how}`;
++ return text.length <= 160 ? text : `${text.slice(0, 159).replace(/\s+\S*$/, '')}…`;
++}
++
function createPageRoutes(ctx) {
const { config, inv } = ctx;
const r = asyncRouter();
@@@ -145,7 +160,8 @@ ${shown.map((k) => html`<section class="inv-kind" aria-labelledby="k-${k.id.repl
page(req, res, {
index: d.status === 'published', cache: signedIn(req) ? null : PUBLIC_CACHE,
title: `${d.name} · ${RARITY_LABEL[d.rarity]} ${k.name.toLowerCase()}`,
-- description: d.description || `${d.name}, a ${RARITY_LABEL[d.rarity].toLowerCase()} ${k.name.toLowerCase()} on OpenVibe.`,
++ // What the item is, how many people own it and how it is got; its flavor text alone ("Angelic") said none of that.
++ description: itemDescription(d, k),
body: html`<p class="crumbs"><a href="/items">Every item</a> › <a href="/items?kind=${encodeURIComponent(k.id)}">${k.name}</a></p>
<div class="inv-detail r-${d.rarity}">
${art(d, { size: 'xl' })}
ddiff --git a/test/grantors.test.js b/test/grantors.test.js
iindex 6cc31b8..6179e69 100644
---- a/test/grantors.test.js
++++ b/test/grantors.test.js
@@@ -34,6 +34,12 @@ const { boot, check, done } = require('./helpers/boot');
const cap = await t.get(`/items/${(await inv.byAlias('service:live', 'hat_crown')).id}`);
assert.ok(!cap.text.includes('How to get it'), 'an item nobody else gives has no such section');
assert.ok(cap.text.includes('Only its issuer can give this item'));
++ // Each item page describes itself: name, rarity and kind, how many own it, how it is got (≤ 160 characters).
++ const descOf = (html) => ((html.match(/<meta name="description" content="([^"]*)">/) || [])[1] || '').replace(/&quot;/g, '"').replace(/&#39;/g, "'");
++ assert.match(descOf(page.text), /^.+, an? (common|uncommon|rare|epic|legendary) .+ on OpenVibe[.: ].* (Owned by \d+ (person|people)|\d+ of \d+ given)\. Earned on OpenVibe\.Quest\.$/);
++ assert.match(descOf(golden.text), /Earned on OpenVibe\.Games\.$/);
++ assert.match(descOf(cap.text), /Given by its issuer, never sold\.$|…$/);
++ for (const html of [page.text, golden.text, cap.text]) assert.ok(descOf(html).length <= 160, descOf(html));
const again = await require('../server/inventory/seed').seed(inv, { log: { log() {} } });
assert.strictEqual(again.grantors, 0, 'a second boot changes nothing');
});