Entry screen is the app: phone frame with a live deck inside
The homepage was a marketing brochure -- a hero paragraph, a "three steps" explainer and a tag list. It described the gesture in prose while the actual Tinder deck sat behind /deck/[jobId], reachable only after signing in AND posting a job. Nobody opening the app ever saw the product. Now / renders a phone illustration with the real app running inside it: the same <Deck>, the same drag physics, real verified pros. On a phone the bezel collapses and the deck simply fills the viewport -- drawing a picture of a phone on a phone is absurd, and it would eat the width the cards need. - Removed the fixed app bar and bottom tab bar. AppShell now renders the screen title as an in-flow h1; the bar owned the only h1 on every screen, so dropping it silently would have left every page headingless. The /jobs "post" action moved from bar chrome into the content, since the tab bar was its only other route there. - getShowcaseDeck(): a deck with no job behind it. getDeck is job-scoped (joins jobs for category and location, anti-joins swipes), which an anonymous visitor has none of, so this centres on the launch city. Eligibility rules are copied verbatim -- nobody may appear in the shop window who could not appear on a real deck. - deck.showcase: the only public procedure in the router. list and swipe stay behind clientProcedure. It reads nothing about the caller and writes nothing, so a right swipe on the entry screen is purely local. No real tradesperson is contacted until a job is posted. - <Deck> filled a hardcoded 560px desktop box; it now fills its container. The card counter moved out from between the two action buttons so the thumb zone holds nothing but the two controls. Verified against the seeded database: 22 eligible pros returned, and all three seeded traps excluded for the right reason -- Pau Ribas (22km out, 5km radius), Unverified Ulla (pending), Away Arnau (not accepting). 7 new integration tests cover exactly that. Also corrects a label I had written as "Plumbers near you" -- the showcase deck is not category-filtered and shows every trade. Includes concurrent edits to the mobile shell, ui/ primitives and DESIGN.md made outside this session. typecheck, lint, build clean; 141 tests pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -34,8 +34,8 @@ export function Deck({ cards, onDecide }: DeckProps) {
|
||||
const visible = remaining.slice(0, 3);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-6">
|
||||
<div className="relative h-[560px] w-full max-w-sm">
|
||||
<div className="flex h-full min-h-0 flex-col items-center gap-5">
|
||||
<div className="relative w-full min-h-0 flex-1">
|
||||
<AnimatePresence initial={false}>
|
||||
{visible
|
||||
.map((card, i) => (
|
||||
@@ -50,15 +50,12 @@ export function Deck({ cards, onDecide }: DeckProps) {
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex shrink-0 items-center gap-12 pb-2">
|
||||
<ActionButton
|
||||
label="Not this one"
|
||||
variant="pass"
|
||||
onClick={() => visible[0] && decide(visible[0].proId, 'left')}
|
||||
/>
|
||||
<p className="w-28 text-center text-sm text-[var(--muted)] tabular-nums">
|
||||
{remaining.length} left
|
||||
</p>
|
||||
<ActionButton
|
||||
label="Send this job"
|
||||
variant="hire"
|
||||
@@ -204,7 +201,7 @@ function ActionButton({
|
||||
|
||||
function EmptyDeck() {
|
||||
return (
|
||||
<div className="mx-auto flex h-[560px] max-w-sm flex-col items-center justify-center gap-3 rounded-3xl border border-dashed border-[var(--border)] p-8 text-center">
|
||||
<div className="mx-auto flex h-full flex-col items-center justify-center gap-3 rounded-deck border border-dashed border-hairline p-8 text-center">
|
||||
<h2 className="text-lg font-semibold">That’s everyone nearby</h2>
|
||||
<p className="text-sm text-[var(--muted)]">
|
||||
You’ve seen every verified pro who covers your area for this trade. We’ll notify
|
||||
|
||||
Reference in New Issue
Block a user