← back to Malden House
browse.js
75 lines
// browse.js — public rental directory, card grid from localStorage
(function () {
function load() {
try { return JSON.parse(localStorage.getItem("htg.rentals") || "{}"); }
catch (e) { return {}; }
}
function escapeHtml(s) {
return String(s ?? "")
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
const escapeAttr = escapeHtml;
function formatMoney(v) {
return v === null || v === undefined || v === "" ? "—" : escapeHtml(v.toLocaleString());
}
const all = Object.values(load());
const venues = [...new Set(all.flatMap(r => (r.nearest || []).slice(0,1).map(v => v.name)))].sort();
const sel = document.getElementById("br-venue");
venues.forEach(v => {
const o = document.createElement("option");
o.value = v; o.textContent = v.replace(/· .*$/, "").trim();
sel.appendChild(o);
});
const budget = document.getElementById("br-budget");
const bv = document.getElementById("br-bv");
budget.addEventListener("input", () => { bv.textContent = "$" + (+budget.value).toLocaleString(); render(); });
sel.addEventListener("change", render);
function render() {
const maxP = +budget.value;
const venueFilter = sel.value;
const rows = all.filter(r => {
const n0 = (r.nearest || [])[0];
if (!n0) return false;
if (r.price && r.price.mid > maxP) return false;
if (venueFilter && n0.name !== venueFilter) return false;
return true;
});
const grid = document.getElementById("br-grid");
const empty = document.getElementById("br-empty");
if (!rows.length) { grid.innerHTML = ""; empty.hidden = false; return; }
empty.hidden = true;
grid.innerHTML = rows.map(r => {
const n0 = r.nearest[0];
const photo = (r.photos && r.photos[0]) || null;
const street = r.address.street || "";
const cityLine = [r.address.city, r.address.state].filter(Boolean).join(", ");
const chip = `${n0.mi.toFixed(1)} mi · ${n0.headline || (n0.sports || "").split("·")[0]}`;
const sat = `https://maps.google.com/maps?q=${encodeURIComponent(`${r.address.lat},${r.address.lng}`)}&t=k&z=18&output=embed`;
return `
<a class="br-card" href="rental.html?id=${encodeURIComponent(r.slug)}">
<div class="br-img">
${photo
? `<img src="${escapeAttr(photo)}" alt="${escapeAttr(street)}">`
: `<iframe src="${escapeAttr(sat)}" loading="lazy"></iframe>`}
<span class="br-chip">${escapeHtml(chip)}</span>
</div>
<div class="br-body">
<div class="br-addr">${escapeHtml(street)}</div>
<div class="br-city">${escapeHtml(cityLine)}</div>
<div class="br-row">
<span><b>$${formatMoney(r.price && r.price.mid)}</b><em>/ night</em></span>
<span class="br-host">by ${escapeHtml(r.host)}</span>
</div>
</div>
</a>`;
}).join("");
}
render();
})();