Skip to content

Commit 5ca565d

Browse files
melvincarvalhoCharlie
andauthored
feat: add Car premium listing card layout (#313)
Bespoke renderTypeSpecific for Car type — premium car listing with photo hero, brand badge overlay, bold title with gradient banner, spec grid of labeled chips (Year, Fuel, Colour, Model), description, and View Advert CTA. Class .card.car-listing. Gate passes (324 apps). Co-authored-by: Charlie <charlie@solid-apps.local>
1 parent 753b91a commit 5ca565d

2 files changed

Lines changed: 187 additions & 0 deletions

File tree

‎app.css‎

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4441,3 +4441,108 @@ footer a:hover { color: var(--accent-2); }
44414441
.fp-standfirst { padding: 0 1rem .6rem; }
44424442
.fp-masthead { padding: 1rem 1rem 0; }
44434443
}
4444+
4445+
/* ── CAR (premium car listing) ── */
4446+
.card.car-listing {
4447+
background: var(--card);
4448+
border-radius: var(--radius);
4449+
overflow: hidden;
4450+
}
4451+
.card.car-listing .hd.hidden { display: none; }
4452+
4453+
.car-hero {
4454+
position: relative;
4455+
width: 100%;
4456+
aspect-ratio: 16/9;
4457+
overflow: hidden;
4458+
background: #1a1a1e;
4459+
}
4460+
.car-hero-img {
4461+
width: 100%;
4462+
height: 100%;
4463+
object-fit: cover;
4464+
display: block;
4465+
}
4466+
.car-brand-badge {
4467+
position: absolute;
4468+
top: .8rem;
4469+
left: .8rem;
4470+
background: rgba(255,255,255,.92);
4471+
backdrop-filter: blur(8px);
4472+
color: var(--ink);
4473+
font-size: .78rem;
4474+
font-weight: 700;
4475+
letter-spacing: .06em;
4476+
text-transform: uppercase;
4477+
padding: .3rem .7rem;
4478+
border-radius: 6px;
4479+
}
4480+
4481+
.car-title {
4482+
font-size: 1.25rem;
4483+
font-weight: 700;
4484+
color: var(--ink);
4485+
padding: 1rem 1.5rem .6rem;
4486+
line-height: 1.25;
4487+
background: linear-gradient(180deg, rgba(30,64,175,.06) 0%, transparent 100%);
4488+
}
4489+
4490+
.car-spec-grid {
4491+
display: grid;
4492+
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
4493+
gap: .6rem;
4494+
padding: 0 1.5rem .8rem;
4495+
}
4496+
4497+
.car-spec-chip {
4498+
background: var(--surface);
4499+
border: 1px solid var(--line);
4500+
border-radius: 8px;
4501+
padding: .55rem .7rem;
4502+
text-align: center;
4503+
}
4504+
.car-spec-label {
4505+
font-size: .68rem;
4506+
text-transform: uppercase;
4507+
letter-spacing: .07em;
4508+
color: var(--muted-2);
4509+
font-weight: 600;
4510+
margin-bottom: .15rem;
4511+
}
4512+
.car-spec-value {
4513+
font-size: .85rem;
4514+
font-weight: 600;
4515+
color: var(--ink);
4516+
}
4517+
4518+
.car-desc {
4519+
font-size: .84rem;
4520+
line-height: 1.6;
4521+
color: var(--muted);
4522+
padding: 0 1.5rem .8rem;
4523+
}
4524+
4525+
.car-cta {
4526+
display: block;
4527+
text-align: center;
4528+
margin: .4rem 1.5rem 1.2rem;
4529+
padding: .7rem;
4530+
background: var(--accent);
4531+
color: #fff;
4532+
font-weight: 600;
4533+
font-size: .9rem;
4534+
border-radius: 10px;
4535+
text-decoration: none;
4536+
transition: filter .15s, transform .1s;
4537+
}
4538+
.car-cta:hover {
4539+
filter: brightness(1.1);
4540+
transform: translateY(-1px);
4541+
}
4542+
4543+
@media (max-width: 480px) {
4544+
.car-spec-grid { grid-template-columns: 1fr 1fr; padding: 0 1rem .6rem; }
4545+
.car-title { padding: .8rem 1rem .5rem; font-size: 1.1rem; }
4546+
.car-desc { padding: 0 1rem .6rem; }
4547+
.car-cta { margin: .4rem 1rem 1rem; }
4548+
}

‎app.js‎

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2506,6 +2506,88 @@
25062506
handled.add("hasMenuSection"); handled.add("provider"); handled.add("url");
25072507
}
25082508

2509+
// ── CAR (premium car listing) ──
2510+
if (cfg.type === "Car") {
2511+
const card = document.querySelector(".card");
2512+
if (card) card.classList.add("car-listing");
2513+
2514+
// Hide normal header
2515+
const hd = document.querySelector(".hd");
2516+
if (hd) hd.classList.add("hidden");
2517+
2518+
// Remove generic hero if present, we'll build our own
2519+
const heroMount = document.getElementById("hero-mount");
2520+
if (heroMount) heroMount.querySelector('.hero')?.remove();
2521+
2522+
// ── Photo hero ──
2523+
const img = data["image"];
2524+
if (img) {
2525+
const hero = document.createElement("div"); hero.className = "car-hero";
2526+
const imgEl = document.createElement("img"); imgEl.className = "car-hero-img";
2527+
imgEl.src = img; imgEl.alt = data[cfg.titleProp] || "Car photo";
2528+
imgEl.loading = "lazy";
2529+
hero.appendChild(imgEl);
2530+
// Brand badge overlay
2531+
const brand = data["brand"];
2532+
if (brand) {
2533+
const badge = document.createElement("div"); badge.className = "car-brand-badge";
2534+
badge.textContent = brand;
2535+
hero.appendChild(badge);
2536+
}
2537+
view.appendChild(hero);
2538+
}
2539+
2540+
// ── Name big over price-style banner ──
2541+
const title = data[cfg.titleProp];
2542+
if (title) {
2543+
const nameEl = document.createElement("div"); nameEl.className = "car-title";
2544+
nameEl.textContent = title;
2545+
view.appendChild(nameEl);
2546+
}
2547+
2548+
// ── Spec grid of labeled boxes ──
2549+
const specItems = [];
2550+
const year = data["vehicleModelDate"];
2551+
if (year) specItems.push({ label: "Year", value: year });
2552+
const fuel = data["fuelType"];
2553+
if (fuel) specItems.push({ label: "Fuel", value: fuel });
2554+
const colour = data["color"];
2555+
if (colour) specItems.push({ label: "Colour", value: colour });
2556+
const model = data["model"];
2557+
if (model) specItems.push({ label: "Model", value: model });
2558+
2559+
if (specItems.length) {
2560+
const grid = document.createElement("div"); grid.className = "car-spec-grid";
2561+
specItems.forEach(s => {
2562+
const chip = document.createElement("div"); chip.className = "car-spec-chip";
2563+
chip.innerHTML = "<div class=\"car-spec-label\">" + s.label + "</div><div class=\"car-spec-value\">" + s.value + "</div>";
2564+
grid.appendChild(chip);
2565+
});
2566+
view.appendChild(grid);
2567+
}
2568+
2569+
// ── Description ──
2570+
const desc = data["description"];
2571+
if (desc) {
2572+
const descEl = document.createElement("div"); descEl.className = "car-desc";
2573+
descEl.textContent = desc;
2574+
view.appendChild(descEl);
2575+
}
2576+
2577+
// ── View Advert CTA ──
2578+
const url = data["url"];
2579+
if (url) {
2580+
const cta = document.createElement("a"); cta.className = "car-cta";
2581+
cta.href = url; cta.target = "_blank"; cta.rel = "noopener";
2582+
cta.textContent = "View Advert →";
2583+
view.appendChild(cta);
2584+
}
2585+
2586+
handled.add("name"); handled.add("image"); handled.add("description");
2587+
handled.add("brand"); handled.add("model"); handled.add("vehicleModelDate");
2588+
handled.add("fuelType"); handled.add("color"); handled.add("url");
2589+
}
2590+
25092591
// ── NEWSARTICLE (newspaper front page) ──
25102592
if (cfg.type === "NewsArticle") {
25112593
const card = document.querySelector(".card");

0 commit comments

Comments
 (0)