openvibers/openvibe.rent Commits
Home: a listing card says its city and kind under the title (kit.card sub), not as a badge and on hover; the rails wrap through the kit (#138)
Changes
@@@ -14,11 +14,7 @@.home-sec .ovk-fold { margin: 10px 0 0; }.home-sec .ovk-fold + .ovk-fold { margin-top: 8px; }.home-under { margin: 2px 0 12px; }--/* A computer sees every card at once: the rail wraps into a grid (a mouse has no ‹ › buttons without kit-web.js).-- Phones and touch tablets keep the rail they swipe. */--@media (min-width: 760px) and (hover: hover), (min-width: 1024px) {-- .home-sec .ovk-rail-track { grid-auto-flow: row; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); grid-auto-columns: auto; overflow: visible; margin: 0; padding: 2px 0 10px; }--}++/* From 760 px the rails wrap into a grid (kit.rail wrap, openvibe-shared 4.39.0); phones keep the rail they swipe. *//* The listings' kinds, as quick filters under their rail: one strip that scrolls sideways on a phone. */.home-kinds { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 0; }@@@ -169,10 +169,11 @@ ${notice(p && p.detail ? p.detail : 'You are over the limit for this.', 'warn')}const amount = Number.isFinite(n) ? n.toLocaleString('en-US', { maximumFractionDigits: Number.isInteger(n) ? 0 : 2 }) : String(row.price);return `${amount} ${row.currency}${PERIOD_SHORT[row.period] == null ? '' : PERIOD_SHORT[row.period]}`;};-- /** One listing in a rail: the city on the picture, the price in its corner, kind and place on hover. */++ /** One listing in a rail: the price in its corner, the city and kind on a line under the title (kit.card sub), the++ * full place on hover. */const listingCard = (row) => kit.card({href: `/listings/${row.id}`, title: row.title, type: 'listing', ratio: '4/3', share: false,-- badge: row.city, corner: priceShort(row), peek: [listings.KIND_TEXT[row.kind] || row.kind, whereOf(row)].filter(Boolean).join(' · '), when: row.created_at,++ sub: [row.city, listings.KIND_TEXT[row.kind] || row.kind].filter(Boolean).join(' · '), corner: priceShort(row), peek: whereOf(row), when: row.created_at,});r.get('/', async (req, res) => {const all = listings.normalizeFilters({});@@@ -217,7 +218,7 @@ ${home.stats([{ value: posted || null, label: posted === 1 ? 'listing posted here' : 'listings posted here', href: '/listings' },], { label: `${SITE_NAME} in numbers` })}--${latest.rows.length ? html`<section class="sc-sec home-sec home-latest">${raw(kit.rail({ id: 'latest', title: `Posted on ${SITE_NAME}`, more: { href: '/listings', label: `See all ${posted}` }, size: 's', items: latest.rows.map(listingCard) }))}++${latest.rows.length ? html`<section class="sc-sec home-sec home-latest">${raw(kit.rail({ id: 'latest', wrap: true, title: `Posted on ${SITE_NAME}`, more: { href: '/listings', label: `See all ${posted}` }, size: 's', items: latest.rows.map(listingCard) }))}<p class="home-kinds" aria-label="Listings by kind">${raw(kinds.map((k) => kit.button({ href: `/listings?${listings.filtersToQuery({ kind: k.value })}`, label: `${listings.KIND_TEXT[k.value] || k.value} ${k.count}`, kind: 'quiet', small: true })).join(' '))}</p></section>` : ''}<section class="sc-sec home-sec home-cities">${home.cityRail({ id: 'cities', title: 'What rent costs in the largest cities', more: { href: '/in', label: `All ${cityList.cities.length} cities` }, list: largest, pick: (c) => ({ corner: c.rent.b2 != null ? cityList.rentText(c.rent.b2) : null, peek: sizes(c) }) })}@@@ -29,7 +29,7 @@ const section = (id, title, lede, body) => (render(body).trim()*/function cityRail({ id, title, more, list, pick, href = (c) => c.path }) {return raw(kit.rail({-- id, title, more, size: 's',++ id, title, more, size: 's', wrap: true,items: (list || []).map((c) => {const p = pick(c);return kit.card({ href: href(c), title: c.name, type: 'map', ratio: '4/3', badge: c.state, corner: p.corner || 'not published', peek: p.peek || '', share: false });
@@ -14,11 +14,7 @@
@@ -14,11 +14,7 @@
.home-sec .ovk-fold { margin: 10px 0 0; }
.home-sec .ovk-fold { margin: 10px 0 0; }
.home-sec .ovk-fold + .ovk-fold { margin-top: 8px; }
.home-sec .ovk-fold + .ovk-fold { margin-top: 8px; }
.home-under { margin: 2px 0 12px; }
.home-under { margin: 2px 0 12px; }
-/* A computer sees every card at once: the rail wraps into a grid (a mouse has no ‹ › buttons without kit-web.js).
- Phones and touch tablets keep the rail they swipe. */
-@media (min-width: 760px) and (hover: hover), (min-width: 1024px) {
- .home-sec .ovk-rail-track { grid-auto-flow: row; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); grid-auto-columns: auto; overflow: visible; margin: 0; padding: 2px 0 10px; }
-}
+/* From 760 px the rails wrap into a grid (kit.rail wrap, openvibe-shared 4.39.0); phones keep the rail they swipe. */
/* The listings' kinds, as quick filters under their rail: one strip that scrolls sideways on a phone. */
/* The listings' kinds, as quick filters under their rail: one strip that scrolls sideways on a phone. */
.home-kinds { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 0; }
.home-kinds { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 0; }
@@ -169,10 +169,11 @@ ${notice(p && p.detail ? p.detail : 'You are over the limit for this.', 'warn')}
@@ -169,10 +169,11 @@ ${notice(p && p.detail ? p.detail : 'You are over the limit for this.', 'warn')}
const amount = Number.isFinite(n) ? n.toLocaleString('en-US', { maximumFractionDigits: Number.isInteger(n) ? 0 : 2 }) : String(row.price);
const amount = Number.isFinite(n) ? n.toLocaleString('en-US', { maximumFractionDigits: Number.isInteger(n) ? 0 : 2 }) : String(row.price);
return `${amount} ${row.currency}${PERIOD_SHORT[row.period] == null ? '' : PERIOD_SHORT[row.period]}`;
return `${amount} ${row.currency}${PERIOD_SHORT[row.period] == null ? '' : PERIOD_SHORT[row.period]}`;
};
};
- /** One listing in a rail: the city on the picture, the price in its corner, kind and place on hover. */
+ /** One listing in a rail: the price in its corner, the city and kind on a line under the title (kit.card sub), the
+ * full place on hover. */
const listingCard = (row) => kit.card({
const listingCard = (row) => kit.card({
href: `/listings/${row.id}`, title: row.title, type: 'listing', ratio: '4/3', share: false,
href: `/listings/${row.id}`, title: row.title, type: 'listing', ratio: '4/3', share: false,
- badge: row.city, corner: priceShort(row), peek: [listings.KIND_TEXT[row.kind] || row.kind, whereOf(row)].filter(Boolean).join(' · '), when: row.created_at,
+ sub: [row.city, listings.KIND_TEXT[row.kind] || row.kind].filter(Boolean).join(' · '), corner: priceShort(row), peek: whereOf(row), when: row.created_at,
});
});
r.get('/', async (req, res) => {
r.get('/', async (req, res) => {
const all = listings.normalizeFilters({});
const all = listings.normalizeFilters({});
@@ -217,7 +218,7 @@ ${home.stats([
@@ -217,7 +218,7 @@ ${home.stats([
{ value: posted || null, label: posted === 1 ? 'listing posted here' : 'listings posted here', href: '/listings' },
{ value: posted || null, label: posted === 1 ? 'listing posted here' : 'listings posted here', href: '/listings' },
], { label: `${SITE_NAME} in numbers` })}
], { label: `${SITE_NAME} in numbers` })}
-${latest.rows.length ? html`<section class="sc-sec home-sec home-latest">${raw(kit.rail({ id: 'latest', title: `Posted on ${SITE_NAME}`, more: { href: '/listings', label: `See all ${posted}` }, size: 's', items: latest.rows.map(listingCard) }))}
+${latest.rows.length ? html`<section class="sc-sec home-sec home-latest">${raw(kit.rail({ id: 'latest', wrap: true, title: `Posted on ${SITE_NAME}`, more: { href: '/listings', label: `See all ${posted}` }, size: 's', items: latest.rows.map(listingCard) }))}
<p class="home-kinds" aria-label="Listings by kind">${raw(kinds.map((k) => kit.button({ href: `/listings?${listings.filtersToQuery({ kind: k.value })}`, label: `${listings.KIND_TEXT[k.value] || k.value} ${k.count}`, kind: 'quiet', small: true })).join(' '))}</p></section>` : ''}
<p class="home-kinds" aria-label="Listings by kind">${raw(kinds.map((k) => kit.button({ href: `/listings?${listings.filtersToQuery({ kind: k.value })}`, label: `${listings.KIND_TEXT[k.value] || k.value} ${k.count}`, kind: 'quiet', small: true })).join(' '))}</p></section>` : ''}
<section class="sc-sec home-sec home-cities">${home.cityRail({ id: 'cities', title: 'What rent costs in the largest cities', more: { href: '/in', label: `All ${cityList.cities.length} cities` }, list: largest, pick: (c) => ({ corner: c.rent.b2 != null ? cityList.rentText(c.rent.b2) : null, peek: sizes(c) }) })}
<section class="sc-sec home-sec home-cities">${home.cityRail({ id: 'cities', title: 'What rent costs in the largest cities', more: { href: '/in', label: `All ${cityList.cities.length} cities` }, list: largest, pick: (c) => ({ corner: c.rent.b2 != null ? cityList.rentText(c.rent.b2) : null, peek: sizes(c) }) })}
@@ -29,7 +29,7 @@ const section = (id, title, lede, body) => (render(body).trim()
@@ -29,7 +29,7 @@ const section = (id, title, lede, body) => (render(body).trim()
*/
*/
function cityRail({ id, title, more, list, pick, href = (c) => c.path }) {
function cityRail({ id, title, more, list, pick, href = (c) => c.path }) {
return raw(kit.rail({
return raw(kit.rail({
- id, title, more, size: 's',
+ id, title, more, size: 's', wrap: true,
items: (list || []).map((c) => {
items: (list || []).map((c) => {
const p = pick(c);
const p = pick(c);
return kit.card({ href: href(c), title: c.name, type: 'map', ratio: '4/3', badge: c.state, corner: p.corner || 'not published', peek: p.peek || '', share: false });
return kit.card({ href: href(c), title: c.name, type: 'map', ratio: '4/3', badge: c.state, corner: p.corner || 'not published', peek: p.peek || '', share: false });