← back to Interiordesignershowroom
refine: price-freshness trust chip on cards (price_checked_at) + PNG/apple-touch favicon fallbacks
1ead1ebaab5899b2d26d95a3b4179f15bba63dc5 · 2026-08-01 22:16:24 -0700 · Steve Abrams
Files touched
M lib/render.jsM public/css/site.cssA public/img/apple-touch-icon.pngA public/img/favicon-32.png
Diff
commit 1ead1ebaab5899b2d26d95a3b4179f15bba63dc5
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat Aug 1 22:16:24 2026 -0700
refine: price-freshness trust chip on cards (price_checked_at) + PNG/apple-touch favicon fallbacks
---
lib/render.js | 18 +++++++++++++++++-
public/css/site.css | 21 +++++++++++++++++++++
public/img/apple-touch-icon.png | Bin 0 -> 4465 bytes
public/img/favicon-32.png | Bin 0 -> 811 bytes
4 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/lib/render.js b/lib/render.js
index a848144..2d76703 100644
--- a/lib/render.js
+++ b/lib/render.js
@@ -16,6 +16,20 @@ const esc = (s = '') => String(s)
// Callers MUST check for empty string and hide the price element when blank.
const money = (n) => (n == null ? '' : '$' + Number(n).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }));
+// Price-freshness trust signal. Uses price_checked_at (NOT updated_at) — the
+// column that specifically records when we last confirmed the price against the
+// feed — so we never overstate how current a price is. Flags anything older than
+// two weeks as `stale` so a drifted feed price is visible rather than silent.
+function freshness(ts) {
+ if (!ts) return '';
+ const days = Math.floor((Date.now() - new Date(ts).getTime()) / 86400e3);
+ const label = days <= 0 ? 'today' : days === 1 ? 'yesterday'
+ : days < 30 ? `${days}d ago` : `${Math.floor(days / 30)}mo ago`;
+ const stale = days > 14;
+ return `<span class="price-fresh${stale ? ' stale' : ''}" title="Price last verified ${esc(new Date(ts).toISOString())}">`
+ + `Price verified ${label}</span>`;
+}
+
// FTC 16 CFR Part 255 requires a clear, conspicuous disclosure. This is not optional.
const DISCLOSURE_SHORT =
'This showroom is reader-supported. When you buy through links on our site, we may earn an affiliate commission at no extra cost to you.';
@@ -34,7 +48,7 @@ function productCard(p) {
}
// card-meta is only rendered when there is a price; empty div suppressed by CSS display:none
const metaHtml = priceHtml
- ? `<div class="card-meta">${priceHtml}</div>`
+ ? `<div class="card-meta">${priceHtml}${freshness(p.price_checked_at)}</div>`
: '';
// Image: use img with explicit width/height for aspect-ratio + graceful broken-img handling
@@ -84,6 +98,8 @@ function layout({ title, description, canonical, jsonld, body, activeNav }) {
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="${esc(SITE.url)}/img/og.png">
<link rel="icon" href="/img/favicon.svg" type="image/svg+xml">
+<link rel="icon" type="image/png" sizes="32x32" href="/img/favicon-32.png">
+<link rel="apple-touch-icon" href="/img/apple-touch-icon.png">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@300;400;500&family=DM+Serif+Display&display=swap">
diff --git a/public/css/site.css b/public/css/site.css
index a0419f4..777bb3b 100644
--- a/public/css/site.css
+++ b/public/css/site.css
@@ -442,6 +442,27 @@ h2.ruled::after {
font-size: .8rem;
margin-left: 4px;
}
+/* Price-freshness trust chip: its own subtle line under the price. A small
+ dot reads as "live/verified"; .stale flips it amber when the feed price is
+ older than two weeks so drift is visible, not hidden. */
+.price-fresh {
+ display: block;
+ margin-top: 3px;
+ font-size: .66rem;
+ letter-spacing: .02em;
+ color: var(--muted-lt);
+}
+.price-fresh::before {
+ content: "";
+ display: inline-block;
+ width: 5px; height: 5px;
+ margin-right: 5px;
+ border-radius: 50%;
+ background: #6f9f6f; /* verified-green dot */
+ vertical-align: middle;
+}
+.price-fresh.stale { color: #9a7b3a; }
+.price-fresh.stale::before { background: #d3a24a; }
.buy {
display: inline-block;
margin-top: 10px;
diff --git a/public/img/apple-touch-icon.png b/public/img/apple-touch-icon.png
new file mode 100644
index 0000000..b47c991
Binary files /dev/null and b/public/img/apple-touch-icon.png differ
diff --git a/public/img/favicon-32.png b/public/img/favicon-32.png
new file mode 100644
index 0000000..d923ebc
Binary files /dev/null and b/public/img/favicon-32.png differ
← 7f7de63 harden /api/render + admin: persistent restart-proof render
·
back to Interiordesignershowroom
·
refine: soften freshness chip to 'Price checked' + SEO struc 082c438 →