← back to Animals
yolo: Surface adoptable animals on pound/shelter detail pages
53b3de13ad5fae97ccdc0021cfbb6a4bfc827ae8 · 2026-05-08 01:32:14 -0700 · animal-yolo
Task: yolo.pound-detail-photos
Prompt: In ~/Projects/animals: on /clinic/:id pages where category in ('shelter','rescue','pound'), query shelter_animals table for that business_id and show available animals as cards (name, breed, photo if
Files touched
M agents/animal-yolo/state.jsonM src/server/index.jsM src/server/render.js
Diff
commit 53b3de13ad5fae97ccdc0021cfbb6a4bfc827ae8
Author: animal-yolo <steve@designerwallcoverings.com>
Date: Fri May 8 01:32:14 2026 -0700
yolo: Surface adoptable animals on pound/shelter detail pages
Task: yolo.pound-detail-photos
Prompt: In ~/Projects/animals: on /clinic/:id pages where category in ('shelter','rescue','pound'), query shelter_animals table for that business_id and show available animals as cards (name, breed, photo if
---
agents/animal-yolo/state.json | 4 ++--
src/server/index.js | 9 ++++++++-
src/server/render.js | 40 +++++++++++++++++++++++++++++++++++++++-
3 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/agents/animal-yolo/state.json b/agents/animal-yolo/state.json
index a1cbf4b..1b17582 100644
--- a/agents/animal-yolo/state.json
+++ b/agents/animal-yolo/state.json
@@ -1,5 +1,5 @@
{
- "cursor": 1,
- "runs": 1,
+ "cursor": 2,
+ "runs": 2,
"started_at": "2026-05-08T07:01:22.386Z"
}
\ No newline at end of file
diff --git a/src/server/index.js b/src/server/index.js
index 84d112e..0c65fd6 100644
--- a/src/server/index.js
+++ b/src/server/index.js
@@ -934,7 +934,14 @@ app.get('/clinic/:id', async (req, res) => {
if (!biz) return res.status(404).send(renderNotFound('Listing not found'));
const audit = await one('SELECT * FROM site_audits WHERE business_id=$1 ORDER BY audited_at DESC LIMIT 1', [biz.id]);
const ad = await pickAdForPage({ pagePath: req.path, keywords: [biz.category, biz.city], category: biz.category });
- res.send(renderBusiness({ biz, audit, ad }));
+ const animals = ['shelter','rescue','pound'].includes(biz.category)
+ ? await many(`SELECT id, name, breed_primary, breed_secondary, age_class, photo_urls, source_url
+ FROM shelter_animals
+ WHERE business_id=$1 AND status='available'
+ ORDER BY fetched_at DESC
+ LIMIT 60`, [biz.id])
+ : [];
+ res.send(renderBusiness({ biz, audit, ad, animals }));
});
// Owner pets gallery — /my-pets is a PRIVATE dashboard for the logged-in user.
diff --git a/src/server/render.js b/src/server/render.js
index bbae193..3131979 100644
--- a/src/server/render.js
+++ b/src/server/render.js
@@ -635,7 +635,44 @@ export function renderCategory({ category, dbCategory, businesses, ad }) {
</script>` + footer() + '</body></html>';
}
-export function renderBusiness({ biz, audit, ad }) {
+export function renderBusiness({ biz, audit, ad, animals = [] }) {
+ const animalsBlock = animals.length ? `
+ <section class="adoptable">
+ <h2>Adoptable animals <span class="muted small">(${animals.length})</span></h2>
+ <div class="adoptable-grid">
+ ${animals.map(a => {
+ const photo = Array.isArray(a.photo_urls) && a.photo_urls[0] ? a.photo_urls[0] : '';
+ const breed = [a.breed_primary, a.breed_secondary].filter(Boolean).join(' / ');
+ const card = `
+ <article class="adoptable-card">
+ ${photo
+ ? `<img src="${esc(photo)}" alt="${esc(a.name || 'Adoptable animal')}" loading="lazy">`
+ : `<div class="adoptable-noimg">🐾</div>`}
+ <div class="adoptable-meta">
+ <strong>${esc(a.name || 'Unnamed')}</strong>
+ ${breed ? `<span class="muted small">${esc(breed)}</span>` : ''}
+ ${a.age_class ? `<span class="age-tag">${esc(a.age_class)}</span>` : ''}
+ </div>
+ </article>`;
+ return a.source_url
+ ? `<a href="${esc(a.source_url)}" rel="nofollow noopener" target="_blank" class="adoptable-link">${card}</a>`
+ : card;
+ }).join('')}
+ </div>
+ </section>
+ <style>
+ .adoptable{margin:32px 0}
+ .adoptable h2{font-weight:400;margin-bottom:14px}
+ .adoptable-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:14px}
+ .adoptable-card{background:#fff;border:1px solid #d2dac8;border-radius:10px;overflow:hidden;display:flex;flex-direction:column}
+ .adoptable-card img{width:100%;aspect-ratio:1;object-fit:cover;background:#eef2eb;display:block}
+ .adoptable-noimg{width:100%;aspect-ratio:1;background:#eef2eb;display:flex;align-items:center;justify-content:center;font-size:42px;color:#9aa89a}
+ .adoptable-meta{padding:10px 12px;display:flex;flex-direction:column;gap:3px;font-size:13px}
+ .adoptable-meta strong{font-weight:500;color:#0f4d3a}
+ .age-tag{align-self:flex-start;background:#fdf5e6;border:1px solid #d4a04a;color:#5a4020;padding:1px 7px;border-radius:4px;font-size:11px;text-transform:capitalize;margin-top:2px}
+ .adoptable-link{text-decoration:none;color:inherit}
+ .adoptable-link:hover .adoptable-card{box-shadow:0 2px 8px rgba(15,77,58,.12)}
+ </style>` : '';
const auditBlock = audit ? `
<aside class="audit">
<h3>Website health: ${audit.marketing_score ?? '—'}/100</h3>
@@ -673,6 +710,7 @@ export function renderBusiness({ biz, audit, ad }) {
${adSlot(ad, 'sidebar', `/clinic/${biz.id}`)}
</div>
</div>
+ ${animalsBlock}
${leadForm()}
</main>` + footer() + '</body></html>';
}
← f22df9f rel=alternate JSON + HTTP Link header on /breeds and /photog
·
back to Animals
·
yolo: Breed page: nearest businesses that work with this bre e7e8d06 →