First
CI / scan_ruby (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled

This commit is contained in:
2026-04-29 00:06:36 +01:00
commit 6f64e1a530
97 changed files with 3179 additions and 0 deletions
+240
View File
@@ -0,0 +1,240 @@
<% content_for :title, "#{@listing[:title]} | Forecourt" %>
<div data-controller="listing-puzzle" class="min-h-screen bg-zinc-50 text-zinc-900">
<!-- Forecourt QA: local review tools still live at /admin. -->
<div data-listing-puzzle-target="hintPanel" class="fixed bottom-5 right-5 z-50 hidden w-[22rem] rounded-3xl border border-zinc-200 bg-white p-5 shadow-2xl shadow-zinc-900/15">
<div class="flex items-start justify-between gap-4">
<div>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-zinc-500">QA Drawer</p>
<h2 class="mt-1 text-lg font-semibold text-zinc-950">Subtle nudge unlocked</h2>
</div>
<button type="button" data-action="listing-puzzle#dismissHint" class="rounded-full border border-zinc-200 px-2.5 py-1 text-sm text-zinc-500 transition hover:border-zinc-300 hover:text-zinc-700">Close</button>
</div>
<p class="mt-3 text-sm leading-6 text-zinc-600">
The advert has clues in captions, checklists, page data, and repeating IDs. Devtools will help, and the local-only review screen still answers at <span class="font-mono text-xs text-zinc-900">/admin</span>.
</p>
<p class="mt-3 text-xs text-zinc-500">Logo taps tracked: <span data-listing-puzzle-target="progress">0/5</span></p>
</div>
<header class="border-b border-zinc-200 bg-white/90 backdrop-blur">
<div class="mx-auto flex max-w-7xl items-center justify-between px-6 py-4 lg:px-8">
<button type="button" data-action="listing-puzzle#tapLogo" class="inline-flex items-center gap-3 rounded-full border border-zinc-200 px-4 py-2 text-left transition hover:border-zinc-300 hover:bg-zinc-50">
<span class="flex h-9 w-9 items-center justify-center rounded-full bg-zinc-950 text-sm font-semibold text-white">M</span>
<span>
<span class="block text-sm font-semibold text-zinc-950">Forecourt</span>
<span class="block text-xs text-zinc-500">Curated enthusiast adverts</span>
</span>
</button>
<div class="hidden items-center gap-3 md:flex">
<span class="rounded-full border border-emerald-200 bg-emerald-50 px-3 py-1 text-xs font-medium text-emerald-700">Verified seller</span>
<span class="rounded-full border border-zinc-200 px-3 py-1 text-xs font-medium text-zinc-600">Price reduced this week</span>
</div>
</div>
</header>
<main class="mx-auto max-w-7xl px-6 py-8 lg:px-8 lg:py-10">
<section class="border-b border-zinc-200 pb-10">
<div class="flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">
<div>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-zinc-500">Advert FC-718-421</p>
<h1 class="mt-2 text-4xl font-semibold tracking-tight text-zinc-950"><%= @listing[:title] %></h1>
<p class="mt-3 max-w-3xl text-sm leading-6 text-zinc-600"><%= @listing[:subtitle] %></p>
</div>
<div class="flex flex-wrap gap-3">
<div class="rounded-2xl border border-zinc-200 bg-white px-4 py-3">
<p class="text-xs font-medium uppercase tracking-[0.2em] text-zinc-500">Mileage</p>
<p class="mt-1 text-sm font-semibold text-zinc-900"><%= @listing[:mileage] %></p>
</div>
<div class="rounded-2xl border border-zinc-200 bg-white px-4 py-3">
<p class="text-xs font-medium uppercase tracking-[0.2em] text-zinc-500">Location</p>
<p class="mt-1 text-sm font-semibold text-zinc-900"><%= @listing[:location] %></p>
</div>
<div class="rounded-2xl border border-zinc-200 bg-white px-4 py-3">
<p class="text-xs font-medium uppercase tracking-[0.2em] text-zinc-500">MOT</p>
<p class="mt-1 text-sm font-semibold text-zinc-900"><%= @listing[:mot_status] %></p>
</div>
</div>
</div>
<div class="mt-8 grid gap-10 lg:grid-cols-[minmax(0,1.6fr)_minmax(18rem,0.95fr)]">
<div>
<figure>
<img
src="<%= @listing[:hero_image] %>"
alt="Front three-quarter studio view of the graphite blue 2021 Porsche 718 Cayman S"
class="aspect-[16/10] w-full rounded-3xl object-cover shadow-xl shadow-zinc-900/10"
>
<figcaption class="mt-3 text-sm text-zinc-500"><%= @listing[:image_caption] %></figcaption>
</figure>
<div class="mt-4 grid gap-3 sm:grid-cols-3">
<% @listing[:gallery].each_with_index do |image, index| %>
<img
src="<%= image %>"
alt="Gallery photo <%= index + 1 %> of the 2021 Porsche 718 Cayman S"
loading="lazy"
class="aspect-[4/3] w-full rounded-2xl object-cover"
>
<% end %>
</div>
</div>
<aside class="lg:pl-4">
<div class="sticky top-6 rounded-3xl border border-zinc-200 bg-white p-6 shadow-xl shadow-zinc-900/5">
<div class="flex items-baseline justify-between gap-4">
<div>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-zinc-500">Price</p>
<p class="mt-2 text-4xl font-semibold tracking-tight text-zinc-950"><%= @listing[:price] %></p>
</div>
<p class="text-sm font-medium text-zinc-500"><%= @listing[:payment] %></p>
</div>
<div class="mt-6 space-y-3">
<button class="inline-flex w-full items-center justify-center rounded-full bg-zinc-950 px-5 py-3 text-sm font-semibold text-white transition hover:bg-zinc-800">Reserve for 24 hours</button>
<button class="inline-flex w-full items-center justify-center rounded-full border border-zinc-200 px-5 py-3 text-sm font-semibold text-zinc-900 transition hover:border-zinc-300 hover:bg-zinc-50">Message seller</button>
</div>
<dl class="mt-6 grid gap-4 border-t border-zinc-200 pt-6 text-sm text-zinc-600">
<div class="flex items-center justify-between gap-4">
<dt>VIN</dt>
<dd class="font-medium text-zinc-900"><%= @listing[:vin] %></dd>
</div>
<div class="flex items-center justify-between gap-4">
<dt>Stock</dt>
<dd class="font-medium text-zinc-900"><%= @listing[:stock_number] %></dd>
</div>
<div class="flex items-center justify-between gap-4">
<dt>Exterior</dt>
<dd class="font-medium text-zinc-900"><%= @listing[:exterior] %></dd>
</div>
<div class="flex items-center justify-between gap-4">
<dt>Interior</dt>
<dd class="font-medium text-zinc-900"><%= @listing[:interior] %></dd>
</div>
</dl>
<div class="mt-6 border-t border-zinc-200 pt-6">
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-zinc-500">Seller</p>
<p class="mt-2 text-lg font-semibold text-zinc-950"><%= @listing[:seller_name] %></p>
<p class="mt-1 text-sm text-zinc-600"><%= @listing[:seller_role] %></p>
<div class="mt-4 space-y-2 text-sm text-zinc-600">
<p><%= @listing[:seller_since] %></p>
<p><%= @listing[:response_time] %></p>
</div>
</div>
</div>
</aside>
</div>
</section>
<section class="grid gap-12 border-b border-zinc-200 py-10 lg:grid-cols-[minmax(0,1.25fr)_minmax(18rem,0.75fr)]">
<div>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-zinc-500">Overview</p>
<div class="mt-4 space-y-4 text-sm leading-7 text-zinc-700">
<% @listing[:overview].each do |paragraph| %>
<p><%= paragraph %></p>
<% end %>
</div>
</div>
<div>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-zinc-500">Highlights</p>
<ul class="mt-4 space-y-3 text-sm leading-6 text-zinc-700">
<% @listing[:highlights].each do |highlight| %>
<li class="rounded-2xl border border-zinc-200 bg-white px-4 py-3"><%= highlight %></li>
<% end %>
</ul>
</div>
</section>
<section class="grid gap-12 border-b border-zinc-200 py-10 lg:grid-cols-[minmax(0,1fr)_minmax(18rem,0.9fr)]">
<div>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-zinc-500">Specifications</p>
<div class="mt-4 divide-y divide-zinc-200 rounded-3xl border border-zinc-200 bg-white">
<% @listing[:specs].each do |label, value| %>
<div class="flex items-start justify-between gap-6 px-5 py-4 text-sm">
<p class="text-zinc-500"><%= label %></p>
<p class="text-right font-medium text-zinc-900"><%= value %></p>
</div>
<% end %>
</div>
</div>
<div>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-zinc-500">Document packet</p>
<p class="mt-3 text-sm leading-6 text-zinc-600">The seller uploaded the original paperwork bundle and a few newer scans. Check the details carefully.</p>
<div class="mt-4 overflow-hidden rounded-3xl border border-zinc-200 bg-white">
<div class="grid grid-cols-[minmax(0,0.9fr)_minmax(0,1.3fr)_5.5rem] gap-4 border-b border-zinc-200 px-5 py-3 text-xs font-semibold uppercase tracking-[0.18em] text-zinc-500">
<p>Source</p>
<p>Detail</p>
<p class="text-right">File</p>
</div>
<% @listing[:document_packet].each do |entry| %>
<div class="grid grid-cols-[minmax(0,0.9fr)_minmax(0,1.3fr)_5.5rem] gap-4 border-b border-zinc-100 px-5 py-4 text-sm last:border-b-0">
<p class="font-medium text-zinc-900"><%= entry[:source] %></p>
<p class="text-zinc-700"><%= entry[:detail] %></p>
<div class="flex justify-end">
<span class="rounded-full border border-zinc-200 bg-zinc-50 px-3 py-1 text-xs font-medium text-zinc-600"><%= entry[:file_type] %></span>
</div>
</div>
<% end %>
</div>
</div>
</section>
<section class="grid gap-12 border-b border-zinc-200 py-10 lg:grid-cols-[minmax(0,1fr)_minmax(18rem,0.9fr)]">
<div>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-zinc-500">Inspection notes</p>
<div class="mt-4 grid gap-3 sm:grid-cols-2">
<% @listing[:condition_notes].each do |note| %>
<div class="rounded-2xl border border-zinc-200 bg-white px-4 py-4 text-sm text-zinc-700"><%= note %></div>
<% end %>
</div>
<p class="mt-8 text-xs font-semibold uppercase tracking-[0.24em] text-zinc-500">Seller notes</p>
<div class="mt-4 space-y-3 text-sm leading-6 text-zinc-700">
<% @listing[:seller_notes].each do |note| %>
<p><%= note %></p>
<% end %>
</div>
</div>
<div>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-zinc-500">Pre-sale prep tickets</p>
<p class="mt-3 text-sm leading-6 text-zinc-600">The prep desk export is still sorted by latest activity. Closed tickets all share the same base code, and only one part changes.</p>
<div class="mt-4 divide-y divide-zinc-200 rounded-3xl border border-zinc-200 bg-white">
<% @listing[:prep_tickets].each do |entry| %>
<div class="flex items-center justify-between gap-4 px-5 py-4">
<div>
<p class="text-sm font-medium text-zinc-900"><%= entry[:task] %></p>
<p class="mt-1 text-sm text-zinc-500"><%= entry[:stamp] %></p>
</div>
<div class="flex items-center gap-3">
<span class="<%= entry[:status] == 'Closed' ? 'border-emerald-200 bg-emerald-50 text-emerald-700' : 'border-amber-200 bg-amber-50 text-amber-700' %> rounded-full border px-3 py-1 text-xs font-medium"><%= entry[:status] %></span>
<code class="rounded-full bg-zinc-950 px-3 py-1.5 text-xs text-zinc-100"><%= entry[:code] %></code>
</div>
</div>
<% end %>
</div>
</div>
</section>
<section class="py-10">
<div class="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
<div>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-zinc-500">Forecourt promise</p>
<p class="mt-2 max-w-3xl text-sm leading-6 text-zinc-600">
Every enthusiast advert includes verified vehicle-history data, recent visual documentation, and just enough intake weirdness to remind you a human touched it somewhere along the way.
</p>
</div>
<div class="text-sm text-zinc-500">
Build tag <span class="font-mono text-xs text-zinc-700">preview-2026.04.28+qa</span>
</div>
</div>
</section>
</main>
<script id="forecourt-media-manifest" type="application/json"><%= raw json_escape(@page_blob) %></script>
</div>