1315 lines
65 KiB
JavaScript
1315 lines
65 KiB
JavaScript
// ============================================================
|
||
// atlas-pages.jsx — Atlas marketplace page bodies
|
||
// ------------------------------------------------------------
|
||
// Eight pages composing a coherent stays-marketplace product.
|
||
// All pages assume the .theme-atlas wrapper applied by the
|
||
// showcase. Built from vibn-ai-templates + vibn-marketplace
|
||
// components.
|
||
// ============================================================
|
||
|
||
// ─── Sample data — re-used across pages ─────────────────────
|
||
const sampleListings = [
|
||
{ id: "l1", title: "Cliffside cabin in the pines", subtitle: "Big Sur, California", price: { amount: 318, period: "/ night" }, rating: 4.94, reviews: 218, badges: ["superhost"], photo: { tone: "sand", label: "Big Sur · A-frame" } },
|
||
{ id: "l2", title: "Off-grid farmstead with hot pool", subtitle: "Mendocino, California", price: { amount: 246, period: "/ night" }, rating: 4.88, reviews: 176, badges: ["verified"], photo: { tone: "sage", label: "Off-grid farmstead" } },
|
||
{ id: "l3", title: "Modernist villa with quiet pool", subtitle: "Joshua Tree, California", price: { amount: 412, period: "/ night" }, rating: 4.97, reviews: 304, badges: ["superhost","instant"], photo: { tone: "warm", label: "Joshua Tree villa" } },
|
||
{ id: "l4", title: "Hillside cottage with garden", subtitle: "Sonoma, California", price: { amount: 184, period: "/ night" }, rating: 4.79, reviews: 92, badges: ["new"], photo: { tone: "blush", label: "Sonoma cottage" } },
|
||
{ id: "l5", title: "Loft above the harbor", subtitle: "Mendocino, California", price: { amount: 268, period: "/ night" }, rating: 4.91, reviews: 142, badges: ["verified"], photo: { tone: "ocean", label: "Harbor loft" } },
|
||
{ id: "l6", title: "Quiet ranch with grass paths", subtitle: "Carmel Valley, California", price: { amount: 295, period: "/ night" }, rating: 4.95, reviews: 256, badges: ["superhost"], photo: { tone: "sand", label: "Carmel Valley ranch" } },
|
||
{ id: "l7", title: "Painted barn with fields", subtitle: "Healdsburg, California", price: { amount: 220, period: "/ night" }, rating: 4.83, reviews: 78, badges: [], photo: { tone: "blush", label: "Painted barn" } },
|
||
{ id: "l8", title: "Bungalow with stone fireplace", subtitle: "Tahoe, California", price: { amount: 178, period: "/ night" }, rating: 4.86, reviews: 121, badges: ["instant"], photo: { tone: "night", label: "Tahoe bungalow" } },
|
||
];
|
||
|
||
const sampleCategories = [
|
||
{ id: "trending", label: "Trending", emoji: "🌅" },
|
||
{ id: "cabins", label: "Cabins", emoji: "🌲" },
|
||
{ id: "amazing", label: "Amazing views", emoji: "🏔" },
|
||
{ id: "tiny", label: "Tiny homes", emoji: "🏠" },
|
||
{ id: "design", label: "Design", emoji: "✦" },
|
||
{ id: "beach", label: "Beachfront", emoji: "🌊" },
|
||
{ id: "country", label: "Countryside", emoji: "🌾" },
|
||
{ id: "farms", label: "Farms", emoji: "🐎" },
|
||
{ id: "domes", label: "Domes", emoji: "◐" },
|
||
{ id: "creative", label: "Creative", emoji: "✎" },
|
||
{ id: "national", label: "National parks", emoji: "🌲" },
|
||
{ id: "ski", label: "Ski-in/out", emoji: "⛷" },
|
||
];
|
||
|
||
const userMira = { name: "Mira Reyes", color: "#d4b8a8" };
|
||
|
||
// ============================================================
|
||
// 1 · HOME / DISCOVERY
|
||
// ============================================================
|
||
const AtlasHome = () => {
|
||
const featured = sampleListings.slice(0, 8);
|
||
const cities = [
|
||
{ name: "Mendocino", sub: "5 hr drive", tone: "ocean" },
|
||
{ name: "Joshua Tree", sub: "Direct flight", tone: "warm" },
|
||
{ name: "Big Sur", sub: "3 hr drive", tone: "sand" },
|
||
{ name: "Tahoe", sub: "4 hr drive", tone: "night" },
|
||
];
|
||
|
||
return (
|
||
<MarketplaceTopShell user={userMira}>
|
||
{/* Hero — big editorial banner + inline search */}
|
||
<section style={{
|
||
padding: "60px 40px 30px", position: "relative",
|
||
background: "var(--surface-2)",
|
||
borderBottom: "1px solid var(--border)",
|
||
}}>
|
||
<div style={{ maxWidth: 1180, margin: "0 auto" }}>
|
||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 48, alignItems: "center" }}>
|
||
<div>
|
||
<Badge tone="accent" leadingIcon={<Icon name="spark" size={11}/>} style={{ marginBottom: 18 }}>
|
||
Atlas Originals · 2026
|
||
</Badge>
|
||
<h1 style={{
|
||
fontFamily: "var(--font-display)",
|
||
fontSize: 68, lineHeight: 1, margin: 0,
|
||
fontWeight: 500, letterSpacing: "-0.03em",
|
||
textWrap: "balance",
|
||
}}>
|
||
Stays that feel{" "}
|
||
<span className="accent-script" style={{ color: "var(--accent)" }}>
|
||
like the place
|
||
</span>.
|
||
</h1>
|
||
<p style={{
|
||
fontSize: 18, color: "var(--text-2)", lineHeight: 1.55,
|
||
margin: "20px 0 32px", maxWidth: 480,
|
||
}}>
|
||
4,820 homes hand-picked by the Atlas team — no chains,
|
||
no copy-paste. Hosted by people who actually live there.
|
||
</p>
|
||
<div style={{ display: "flex", gap: 12 }}>
|
||
<Button size="lg">Start browsing →</Button>
|
||
<Button size="lg" variant="secondary">How Atlas works</Button>
|
||
</div>
|
||
</div>
|
||
<PhotoSlot label="hero · stay photograph" tone="sand" aspect="4/5"
|
||
style={{ borderRadius: "var(--card-radius)", boxShadow: "var(--shadow-lg)" }}/>
|
||
</div>
|
||
|
||
{/* Inline search */}
|
||
<div style={{ marginTop: 56 }}>
|
||
<SearchBar destination="Northern California" dates={{ in: "Jun 14", out: "Jun 19" }} guests="2 adults · 1 dog"/>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Category rail */}
|
||
<section style={{
|
||
padding: "8px 40px 0", background: "var(--surface)",
|
||
borderBottom: "1px solid var(--border)", position: "sticky", top: 88, zIndex: 4,
|
||
}}>
|
||
<div style={{ maxWidth: 1180, margin: "0 auto" }}>
|
||
<CategoryRail categories={sampleCategories} active="cabins"/>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Featured listings */}
|
||
<section style={{ padding: "40px 40px 30px" }}>
|
||
<div style={{ maxWidth: 1180, margin: "0 auto" }}>
|
||
<div style={{
|
||
display: "flex", justifyContent: "space-between", alignItems: "baseline",
|
||
marginBottom: 22,
|
||
}}>
|
||
<div>
|
||
<div style={{
|
||
fontSize: "var(--text-xs)", color: "var(--text-3)",
|
||
textTransform: "uppercase", letterSpacing: "0.08em",
|
||
fontWeight: 500, marginBottom: 4,
|
||
}}>Editors' picks · Northern California</div>
|
||
<h2 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 32, margin: 0,
|
||
fontWeight: 500, letterSpacing: "-0.02em",
|
||
}}>This week's stays</h2>
|
||
</div>
|
||
<Button variant="ghost" trailingIcon={<Icon name="arrow" size={13}/>}>See all 184</Button>
|
||
</div>
|
||
|
||
<div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 28 }}>
|
||
{featured.map((l, i) => (
|
||
<ListingCard key={l.id} listing={{
|
||
...l,
|
||
tags: i === 0 ? ["Editor's pick"] : i === 2 ? ["Rare find"] : [],
|
||
favorite: i === 1,
|
||
}}/>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Inspiration row */}
|
||
<section style={{ padding: "40px 40px", background: "var(--surface-2)", borderTop: "1px solid var(--border)" }}>
|
||
<div style={{ maxWidth: 1180, margin: "0 auto" }}>
|
||
<h2 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 32, margin: "0 0 22px",
|
||
fontWeight: 500, letterSpacing: "-0.02em",
|
||
}}>Closer than you think</h2>
|
||
<div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 16 }}>
|
||
{cities.map(c => (
|
||
<div key={c.name} style={{
|
||
position: "relative", borderRadius: "var(--card-radius)", overflow: "hidden",
|
||
aspectRatio: "5/6", cursor: "pointer",
|
||
}}>
|
||
<PhotoSlot label={c.name} tone={c.tone} aspect="auto" style={{ height: "100%", aspectRatio: "auto" }}/>
|
||
<div style={{
|
||
position: "absolute", left: 18, bottom: 18, color: "#fff",
|
||
textShadow: "0 1px 3px rgba(0,0,0,0.4)",
|
||
}}>
|
||
<div style={{
|
||
fontFamily: "var(--font-display)", fontSize: 22,
|
||
fontWeight: 500, letterSpacing: "-0.01em",
|
||
}}>{c.name}</div>
|
||
<div style={{ fontSize: 13, opacity: 0.9 }}>{c.sub}</div>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* How Atlas works */}
|
||
<section style={{ padding: "60px 40px" }}>
|
||
<div style={{ maxWidth: 1180, margin: "0 auto" }}>
|
||
<div style={{ textAlign: "center", maxWidth: 540, margin: "0 auto 40px" }}>
|
||
<Badge tone="accent" style={{ marginBottom: 14 }}>How Atlas works</Badge>
|
||
<h2 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 38, margin: "0 0 14px",
|
||
fontWeight: 500, letterSpacing: "-0.02em",
|
||
}}>
|
||
Booking, but considered.
|
||
</h2>
|
||
<p style={{ fontSize: 16, color: "var(--text-2)", lineHeight: 1.55, margin: 0 }}>
|
||
Every host is interviewed. Every photo is real. Every refund is
|
||
easy. The way it should be.
|
||
</p>
|
||
</div>
|
||
<div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 24 }}>
|
||
{[
|
||
{ i: "people", t: "Hosted by humans", b: "Every Atlas host meets our team. No corporate brands, no auto-replies." },
|
||
{ i: "shield", t: "Vetted for the truth", b: "We visit and photograph each listing ourselves. What you see is what you sleep in." },
|
||
{ i: "spark", t: "Refund first", b: "Cancel up to 48 hours before for any reason. No questions, no fine print." },
|
||
].map(c => (
|
||
<Card key={c.t} padding={28}>
|
||
<div style={{
|
||
width: 44, height: 44, borderRadius: 12,
|
||
background: "var(--accent-soft)", color: "var(--accent)",
|
||
display: "flex", alignItems: "center", justifyContent: "center",
|
||
marginBottom: 16,
|
||
}}><Icon name={c.i} size={20}/></div>
|
||
<h3 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 22, margin: 0,
|
||
fontWeight: 500, letterSpacing: "-0.01em",
|
||
}}>{c.t}</h3>
|
||
<p style={{ margin: "8px 0 0", fontSize: 14, color: "var(--text-2)", lineHeight: 1.55 }}>{c.b}</p>
|
||
</Card>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</MarketplaceTopShell>
|
||
);
|
||
};
|
||
|
||
// ============================================================
|
||
// 2 · SEARCH RESULTS + MAP
|
||
// ============================================================
|
||
const AtlasSearch = () => {
|
||
return (
|
||
<MarketplaceTopShell user={userMira} compact showSearch
|
||
searchProps={{ destination: "Mendocino · Northern California", dates: { in: "Jun 14", out: "Jun 19" }, guests: "2 adults" }}>
|
||
{/* Filters strip */}
|
||
<section style={{
|
||
padding: "16px 40px", borderBottom: "1px solid var(--border)",
|
||
background: "var(--surface)", display: "flex",
|
||
justifyContent: "space-between", alignItems: "center", gap: 20,
|
||
}}>
|
||
<FilterChips filters={[
|
||
{ label: "Any type", active: true },
|
||
{ label: "Cabin", count: 84 },
|
||
{ label: "House" },
|
||
{ label: "Cottage" },
|
||
{ label: "Tiny home" },
|
||
{ label: "Yurt" },
|
||
{ label: "Filters", icon: "settings" },
|
||
]} onClear={() => {}}/>
|
||
<div style={{ display: "flex", alignItems: "center", gap: 12 }}>
|
||
<span style={{ fontSize: "var(--text-sm)", color: "var(--text-2)" }}>
|
||
<b style={{ color: "var(--text)" }}>184</b> stays
|
||
</span>
|
||
<Select value="Recommended"/>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Split: list + map */}
|
||
<section style={{
|
||
display: "grid", gridTemplateColumns: "minmax(0, 1.2fr) minmax(0, 1fr)",
|
||
height: "calc(100% - 145px)",
|
||
}}>
|
||
<div style={{ padding: "20px 40px", overflowY: "auto", display: "flex", flexDirection: "column", gap: 16 }}>
|
||
{sampleListings.slice(0, 5).map((l, i) => (
|
||
<ListingCardHorizontal key={l.id} listing={{
|
||
...l,
|
||
description: i === 0
|
||
? "A serene A-frame cabin with floor-to-ceiling windows, a sunken fireplace, and a wraparound deck overlooking the redwoods."
|
||
: "Sun-drenched home with thoughtful design, full kitchen, and outdoor soaking tub. Walk to the river in 5 minutes.",
|
||
amenities: ["Wifi","Kitchen","Hot tub","Fireplace","EV charger","Pet friendly"],
|
||
}}/>
|
||
))}
|
||
</div>
|
||
<div style={{ position: "sticky", top: 0, height: "100%", padding: 16 }}>
|
||
<MiniMap pins={[
|
||
{ x: 28, y: 36, price: 318, active: true },
|
||
{ x: 42, y: 28, price: 246 },
|
||
{ x: 56, y: 50, price: 412 },
|
||
{ x: 68, y: 32, price: 184 },
|
||
{ x: 38, y: 64, price: 268 },
|
||
{ x: 22, y: 58, price: 295 },
|
||
{ x: 76, y: 50, price: 220 },
|
||
{ x: 62, y: 18, price: 178 },
|
||
]}/>
|
||
</div>
|
||
</section>
|
||
</MarketplaceTopShell>
|
||
);
|
||
};
|
||
|
||
// ============================================================
|
||
// 3 · LISTING DETAIL
|
||
// ============================================================
|
||
const AtlasListing = () => {
|
||
const photos = [
|
||
{ label: "Photo 1 · exterior", tone: "sand" },
|
||
{ label: "Photo 2 · living", tone: "warm" },
|
||
{ label: "Photo 3 · kitchen", tone: "blush" },
|
||
{ label: "Photo 4 · bedroom", tone: "ocean" },
|
||
{ label: "Photo 5 · view", tone: "sage" },
|
||
];
|
||
const reviews = [
|
||
{ author: "Tomás Olivar", avatarColor: "#c8e8a8", rating: 5, date: "May 2026", location: "Berlin, DE", body: "We arrived after a long flight and the cabin felt like it had been waiting for us. Coffee already ground, fire laid in the stove. We extended a night." },
|
||
{ author: "Naila Choudhury", avatarColor: "#e8a87c", rating: 5, date: "April 2026", location: "Mumbai, IN", body: "Photos don't do it justice. The light at golden hour through those west-facing windows is something you should plan for. Bring a camera." },
|
||
{ author: "Henri Lamarck", avatarColor: "#a8c8e8", rating: 4.5, date: "March 2026", location: "Lyon, FR", body: "Beautiful design, very thoughtful. Wifi was a little patchy for video calls, but that's almost certainly a feature, not a bug." },
|
||
{ author: "Emi Hara", avatarColor: "#c8a8e8", rating: 5, date: "March 2026", location: "Kyoto, JP", body: "Mara is the kind of host who anticipates things. The local bakery list alone was worth the trip." },
|
||
];
|
||
|
||
return (
|
||
<MarketplaceTopShell user={userMira} compact>
|
||
<article style={{ padding: "28px 40px 60px", maxWidth: 1180, margin: "0 auto" }}>
|
||
{/* Title block */}
|
||
<header style={{ marginBottom: 18 }}>
|
||
<h1 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 36, margin: 0,
|
||
fontWeight: 500, letterSpacing: "-0.02em",
|
||
}}>Cliffside cabin in the pines</h1>
|
||
<div style={{
|
||
display: "flex", alignItems: "center", gap: 16, marginTop: 8,
|
||
fontSize: "var(--text-sm)", color: "var(--text-2)",
|
||
}}>
|
||
<RatingStars value={4.94} size={12}/>
|
||
<span>· 218 reviews</span>
|
||
<span>·</span>
|
||
<TrustBadge kind="superhost"/>
|
||
<span style={{ flex: 1 }}/>
|
||
<Button variant="ghost" size="sm" leadingIcon={<Icon name="link" size={13}/>}>Share</Button>
|
||
<Button variant="ghost" size="sm" leadingIcon={<Icon name="star" size={13}/>}>Save</Button>
|
||
</div>
|
||
</header>
|
||
|
||
{/* Gallery */}
|
||
<PhotoGallery photos={photos} style={{ marginBottom: 36 }}/>
|
||
|
||
{/* 2-column body + booking card */}
|
||
<div style={{ display: "grid", gridTemplateColumns: "1.5fr 1fr", gap: 56, alignItems: "start" }}>
|
||
<div>
|
||
{/* Summary */}
|
||
<div style={{ paddingBottom: 24, borderBottom: "1px solid var(--border)" }}>
|
||
<div style={{
|
||
display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 16,
|
||
marginBottom: 12,
|
||
}}>
|
||
<div>
|
||
<h2 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 24, margin: 0,
|
||
fontWeight: 500, letterSpacing: "-0.01em",
|
||
}}>Entire cabin in Big Sur · hosted by Mara</h2>
|
||
<div style={{ fontSize: "var(--text-sm)", color: "var(--text-2)", marginTop: 6 }}>
|
||
4 guests · 2 bedrooms · 2 beds · 1.5 baths
|
||
</div>
|
||
</div>
|
||
<Avatar name="Mara H" color="#e8a87c" size={56}/>
|
||
</div>
|
||
<p style={{
|
||
fontSize: 16, color: "var(--text)", lineHeight: 1.65,
|
||
margin: "10px 0 0", maxWidth: 540,
|
||
}}>
|
||
Set 80 feet above the Pacific, this A-frame is a quiet,
|
||
light-soaked retreat. Architecturally restored in 2024 with
|
||
radiant floors, a wood-burning stove, and a Furlong soaking tub
|
||
on the deck. Stargazing is the only TV.
|
||
</p>
|
||
<Button variant="ghost" size="sm" style={{ marginTop: 14, padding: 0 }}>
|
||
Show more →
|
||
</Button>
|
||
</div>
|
||
|
||
{/* Amenities */}
|
||
<div style={{ padding: "26px 0", borderBottom: "1px solid var(--border)" }}>
|
||
<h3 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 22, margin: "0 0 18px",
|
||
fontWeight: 500, letterSpacing: "-0.01em",
|
||
}}>What this place offers</h3>
|
||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "12px 32px" }}>
|
||
{[
|
||
["Pacific Ocean view", "home"], ["Wood-burning stove", "spark"],
|
||
["Soaking tub on deck", "home"], ["Fast wifi · 320Mbps", "bolt"],
|
||
["Equipped kitchen", "home"], ["Hairdryer + amenities", "shield"],
|
||
["EV charger · Level 2", "bolt"], ["Pet-friendly · 1 dog ok", "people"],
|
||
].map(([t, i]) => (
|
||
<div key={t} style={{ display: "flex", alignItems: "center", gap: 12, padding: "4px 0" }}>
|
||
<Icon name={i} size={18} style={{ color: "var(--text-2)" }}/>
|
||
<span style={{ fontSize: "var(--text-md)", color: "var(--text)" }}>{t}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
<Button variant="secondary" style={{ marginTop: 18 }}>Show all 28 amenities</Button>
|
||
</div>
|
||
|
||
{/* Calendar */}
|
||
<div style={{ padding: "26px 0", borderBottom: "1px solid var(--border)" }}>
|
||
<h3 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 22, margin: "0 0 4px",
|
||
fontWeight: 500, letterSpacing: "-0.01em",
|
||
}}>5 nights in Big Sur</h3>
|
||
<div style={{ fontSize: "var(--text-sm)", color: "var(--text-3)", marginBottom: 18 }}>
|
||
Jun 14 – Jun 19, 2026
|
||
</div>
|
||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 32 }}>
|
||
<CalendarMonth month="June 2026" firstWeekday={1} daysInMonth={30}
|
||
start={14} end={19} today={2} blocked={[7, 8, 21, 22, 23]}/>
|
||
<CalendarMonth month="July 2026" firstWeekday={3} daysInMonth={31}
|
||
blocked={[3, 4, 5, 11, 12, 19, 20, 27, 28]}/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Reviews */}
|
||
<div style={{ padding: "26px 0", borderBottom: "1px solid var(--border)" }}>
|
||
<RatingsSummary value={4.94} total={218} categories={[
|
||
{ label: "Cleanliness", value: 4.98 },
|
||
{ label: "Communication", value: 5.00 },
|
||
{ label: "Accuracy", value: 4.92 },
|
||
{ label: "Check-in", value: 5.00 },
|
||
{ label: "Value", value: 4.82 },
|
||
{ label: "Location", value: 4.96 },
|
||
]}/>
|
||
<div style={{
|
||
display: "grid", gridTemplateColumns: "1fr 1fr", gap: "32px 48px", marginTop: 32,
|
||
}}>
|
||
{reviews.map(r => <ReviewCard key={r.author} {...r}/>)}
|
||
</div>
|
||
<Button variant="secondary" style={{ marginTop: 26 }}>Show all 218 reviews</Button>
|
||
</div>
|
||
|
||
{/* Host */}
|
||
<div style={{ paddingTop: 26 }}>
|
||
<h3 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 22, margin: "0 0 18px",
|
||
fontWeight: 500, letterSpacing: "-0.01em",
|
||
}}>Meet your host</h3>
|
||
<HostHeader
|
||
name="Mara H" color="#e8a87c"
|
||
joined="2019" location="Big Sur, CA"
|
||
languages={["English", "Spanish"]}
|
||
kpis={[
|
||
{ label: "Reviews", value: "612" },
|
||
{ label: "Rating", value: "4.96" },
|
||
{ label: "Years hosting", value: "6" },
|
||
]}
|
||
blurb="I'm an architect by training and gardener by necessity. I share this cabin and a tiny cottage two ridges over. I'll send you a hand-drawn map of my favorite tide pools when you book."
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Sticky booking card */}
|
||
<aside style={{ position: "sticky", top: 100 }}>
|
||
<Card padding={28} variant="raised">
|
||
<div style={{
|
||
display: "flex", justifyContent: "space-between", alignItems: "baseline",
|
||
marginBottom: 18,
|
||
}}>
|
||
<PriceTag amount={318} period="/ night" size="lg" original={365}/>
|
||
<RatingStars value={4.94} size={12}/>
|
||
</div>
|
||
|
||
{/* Date + guests inputs */}
|
||
<div style={{
|
||
border: "1px solid var(--border-strong)", borderRadius: 10, overflow: "hidden",
|
||
marginBottom: 14,
|
||
}}>
|
||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", borderBottom: "1px solid var(--border-strong)" }}>
|
||
<div style={{ padding: "10px 14px", borderRight: "1px solid var(--border-strong)" }}>
|
||
<div style={{ fontSize: 10, fontWeight: 700, color: "var(--text)", letterSpacing: "0.05em", textTransform: "uppercase" }}>Check in</div>
|
||
<div style={{ fontSize: "var(--text-sm)", color: "var(--text)", marginTop: 2 }}>Jun 14, 2026</div>
|
||
</div>
|
||
<div style={{ padding: "10px 14px" }}>
|
||
<div style={{ fontSize: 10, fontWeight: 700, color: "var(--text)", letterSpacing: "0.05em", textTransform: "uppercase" }}>Check out</div>
|
||
<div style={{ fontSize: "var(--text-sm)", color: "var(--text)", marginTop: 2 }}>Jun 19, 2026</div>
|
||
</div>
|
||
</div>
|
||
<div style={{ padding: "10px 14px", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||
<div>
|
||
<div style={{ fontSize: 10, fontWeight: 700, color: "var(--text)", letterSpacing: "0.05em", textTransform: "uppercase" }}>Guests</div>
|
||
<div style={{ fontSize: "var(--text-sm)", color: "var(--text)", marginTop: 2 }}>2 adults · 1 dog</div>
|
||
</div>
|
||
<Icon name="chevDown" size={14} style={{ color: "var(--text-3)" }}/>
|
||
</div>
|
||
</div>
|
||
|
||
<Button full size="lg" leadingIcon={<Icon name="bolt" size={15}/>}>Reserve</Button>
|
||
<div style={{ textAlign: "center", fontSize: "var(--text-xs)", color: "var(--text-3)", margin: "10px 0 18px" }}>
|
||
You won't be charged yet
|
||
</div>
|
||
|
||
<PriceBreakdown items={[
|
||
{ label: "$318 × 5 nights", amount: 1590 },
|
||
{ label: "Atlas service fee", amount: 184 },
|
||
{ label: "Cleaning fee", amount: 95 },
|
||
{ label: "Local taxes (8%)", amount: 127 },
|
||
{ label: "First-time guest discount", amount: 150, note: "discount" },
|
||
]} total={1846}/>
|
||
|
||
<div style={{
|
||
marginTop: 18, padding: 14, borderRadius: 10,
|
||
background: "var(--accent-soft)", display: "flex", alignItems: "center", gap: 10,
|
||
}}>
|
||
<Icon name="info" size={14} style={{ color: "var(--accent)" }}/>
|
||
<span style={{ fontSize: "var(--text-sm)", color: "var(--text)" }}>
|
||
<b>Rare find</b> · this place is usually booked
|
||
</span>
|
||
</div>
|
||
</Card>
|
||
|
||
<div style={{
|
||
marginTop: 14, fontSize: "var(--text-xs)", color: "var(--text-3)",
|
||
textAlign: "center",
|
||
}}>Report this listing</div>
|
||
</aside>
|
||
</div>
|
||
</article>
|
||
</MarketplaceTopShell>
|
||
);
|
||
};
|
||
|
||
// ============================================================
|
||
// 4 · CHECKOUT
|
||
// ============================================================
|
||
const AtlasCheckout = () => (
|
||
<MarketplaceTopShell user={userMira} compact footer={false}>
|
||
<div style={{ padding: "32px 40px 60px", maxWidth: 1100, margin: "0 auto" }}>
|
||
<div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 18 }}>
|
||
<IconButton name="chevLeft" variant="secondary" label="Back"/>
|
||
<h1 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 30, margin: 0,
|
||
fontWeight: 500, letterSpacing: "-0.02em",
|
||
}}>Confirm and pay</h1>
|
||
</div>
|
||
|
||
<div style={{ display: "grid", gridTemplateColumns: "1.4fr 1fr", gap: 48, alignItems: "start" }}>
|
||
{/* Form */}
|
||
<div>
|
||
{/* Trip details */}
|
||
<section style={{ paddingBottom: 22, borderBottom: "1px solid var(--border)" }}>
|
||
<h2 style={{ fontFamily: "var(--font-display)", fontSize: 22, margin: "0 0 16px",
|
||
fontWeight: 500, letterSpacing: "-0.01em" }}>Your trip</h2>
|
||
{[
|
||
["Dates", "Jun 14 – 19, 2026"],
|
||
["Guests", "2 adults, 1 dog"],
|
||
].map(([k, v]) => (
|
||
<div key={k} style={{
|
||
display: "flex", justifyContent: "space-between", alignItems: "baseline",
|
||
padding: "10px 0",
|
||
}}>
|
||
<div>
|
||
<div style={{ fontSize: "var(--text-md)", fontWeight: 500 }}>{k}</div>
|
||
<div style={{ fontSize: "var(--text-sm)", color: "var(--text-2)" }}>{v}</div>
|
||
</div>
|
||
<Button variant="ghost" size="sm">Edit</Button>
|
||
</div>
|
||
))}
|
||
</section>
|
||
|
||
{/* Payment */}
|
||
<section style={{ padding: "26px 0", borderBottom: "1px solid var(--border)" }}>
|
||
<h2 style={{ fontFamily: "var(--font-display)", fontSize: 22, margin: "0 0 16px",
|
||
fontWeight: 500, letterSpacing: "-0.01em" }}>Pay with</h2>
|
||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 10, marginBottom: 18 }}>
|
||
{["Card","Apple Pay","Klarna"].map((p, i) => (
|
||
<div key={p} style={{
|
||
padding: "12px 16px", borderRadius: 10, cursor: "pointer", textAlign: "center",
|
||
background: i === 0 ? "var(--surface)" : "var(--surface)",
|
||
border: i === 0 ? "1.5px solid var(--text)" : "1px solid var(--border)",
|
||
fontSize: "var(--text-sm)", fontWeight: i === 0 ? 600 : 500,
|
||
color: "var(--text)",
|
||
}}>{p}</div>
|
||
))}
|
||
</div>
|
||
<Field label="Card number">
|
||
<Input value="4242 4242 4242 4242"/>
|
||
</Field>
|
||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
|
||
<Field label="Expiry"><Input value="08 / 28"/></Field>
|
||
<Field label="CVC"><Input value="123"/></Field>
|
||
</div>
|
||
<Field label="Country / region">
|
||
<Select value="United States"/>
|
||
</Field>
|
||
</section>
|
||
|
||
{/* Message host */}
|
||
<section style={{ padding: "26px 0", borderBottom: "1px solid var(--border)" }}>
|
||
<h2 style={{ fontFamily: "var(--font-display)", fontSize: 22, margin: "0 0 6px",
|
||
fontWeight: 500, letterSpacing: "-0.01em" }}>Message Mara</h2>
|
||
<p style={{ fontSize: "var(--text-sm)", color: "var(--text-2)", margin: "0 0 12px" }}>
|
||
Hosts often reply within an hour.
|
||
</p>
|
||
<Field>
|
||
<Textarea value="Hi Mara! We're looking forward to our trip. Any tips for the best spot to catch the sunset within walking distance?" rows={4}/>
|
||
</Field>
|
||
</section>
|
||
|
||
{/* Ground rules */}
|
||
<section style={{ padding: "26px 0" }}>
|
||
<h2 style={{ fontFamily: "var(--font-display)", fontSize: 22, margin: "0 0 12px",
|
||
fontWeight: 500, letterSpacing: "-0.01em" }}>Ground rules</h2>
|
||
<p style={{ fontSize: "var(--text-sm)", color: "var(--text-2)", lineHeight: 1.55 }}>
|
||
Atlas asks every guest to remember a few simple things. Treat
|
||
your host's home like your own. No parties or events. Follow the
|
||
house rules in your confirmation.
|
||
</p>
|
||
<Button size="lg" style={{ marginTop: 20 }}>Confirm and pay · $1,846</Button>
|
||
</section>
|
||
</div>
|
||
|
||
{/* Summary */}
|
||
<aside style={{ position: "sticky", top: 100 }}>
|
||
<Card padding={24} variant="raised">
|
||
<div style={{ display: "flex", gap: 14, marginBottom: 18 }}>
|
||
<div style={{ width: 100, borderRadius: 10, overflow: "hidden" }}>
|
||
<PhotoSlot label="Big Sur · A-frame" tone="sand" aspect="1/1"/>
|
||
</div>
|
||
<div style={{ flex: 1, minWidth: 0 }}>
|
||
<div style={{ fontSize: "var(--text-md)", fontWeight: 600, color: "var(--text)" }}>
|
||
Cliffside cabin in the pines
|
||
</div>
|
||
<div style={{ fontSize: "var(--text-xs)", color: "var(--text-3)", marginTop: 2 }}>
|
||
Entire cabin · 4 guests
|
||
</div>
|
||
<div style={{ marginTop: 6 }}>
|
||
<RatingStars value={4.94} size={11}/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<Divider/>
|
||
<h3 style={{ fontFamily: "var(--font-display)", fontSize: 18, margin: "8px 0 12px",
|
||
fontWeight: 500 }}>Price details</h3>
|
||
<PriceBreakdown items={[
|
||
{ label: "$318 × 5 nights", amount: 1590 },
|
||
{ label: "Atlas service fee", amount: 184 },
|
||
{ label: "Cleaning fee", amount: 95 },
|
||
{ label: "Local taxes (8%)", amount: 127 },
|
||
{ label: "First-time guest discount", amount: 150, note: "discount" },
|
||
]} total={1846}/>
|
||
</Card>
|
||
</aside>
|
||
</div>
|
||
</div>
|
||
</MarketplaceTopShell>
|
||
);
|
||
|
||
// ============================================================
|
||
// 5 · GUEST DASHBOARD · MY TRIPS
|
||
// ============================================================
|
||
const AtlasGuestDash = () => (
|
||
<MarketplaceDashboardShell role="guest" active="trips" user={userMira}>
|
||
<div style={{ padding: "28px 36px 40px", overflow: "auto" }}>
|
||
<div style={{
|
||
display: "flex", justifyContent: "space-between", alignItems: "baseline",
|
||
marginBottom: 22,
|
||
}}>
|
||
<div>
|
||
<div style={{
|
||
fontSize: "var(--text-xs)", color: "var(--text-3)",
|
||
textTransform: "uppercase", letterSpacing: "0.06em",
|
||
fontWeight: 500, marginBottom: 4,
|
||
}}>Welcome back, Mira</div>
|
||
<h1 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 32, margin: 0,
|
||
fontWeight: 500, letterSpacing: "-0.02em",
|
||
}}>Your trips</h1>
|
||
</div>
|
||
<Tabs items={[
|
||
{ label: "Upcoming", count: 1 }, { label: "Past", count: 12 },
|
||
{ label: "Cancelled" },
|
||
]} active="Upcoming"/>
|
||
</div>
|
||
|
||
{/* Upcoming hero */}
|
||
<Card padding={0} variant="raised" style={{
|
||
overflow: "hidden", marginBottom: 28,
|
||
}}>
|
||
<div style={{ display: "grid", gridTemplateColumns: "1.2fr 1fr" }}>
|
||
<div style={{ padding: 28 }}>
|
||
<Badge tone="accent" leadingIcon={<Icon name="bolt" size={11}/>} style={{ marginBottom: 14 }}>
|
||
Upcoming · in 19 days
|
||
</Badge>
|
||
<h2 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 30, margin: "0 0 4px",
|
||
fontWeight: 500, letterSpacing: "-0.02em",
|
||
}}>Cliffside cabin in the pines</h2>
|
||
<div style={{ fontSize: "var(--text-md)", color: "var(--text-2)" }}>
|
||
Big Sur, California · Hosted by Mara
|
||
</div>
|
||
|
||
<div style={{
|
||
display: "grid", gridTemplateColumns: "repeat(3, auto)", gap: "8px 36px",
|
||
margin: "22px 0", fontSize: "var(--text-sm)",
|
||
}}>
|
||
<div>
|
||
<div style={{ color: "var(--text-3)", fontSize: 11, textTransform: "uppercase", letterSpacing: "0.06em" }}>Check in</div>
|
||
<div style={{ fontWeight: 600, marginTop: 2 }}>Jun 14, 4:00pm</div>
|
||
</div>
|
||
<div>
|
||
<div style={{ color: "var(--text-3)", fontSize: 11, textTransform: "uppercase", letterSpacing: "0.06em" }}>Check out</div>
|
||
<div style={{ fontWeight: 600, marginTop: 2 }}>Jun 19, 11:00am</div>
|
||
</div>
|
||
<div>
|
||
<div style={{ color: "var(--text-3)", fontSize: 11, textTransform: "uppercase", letterSpacing: "0.06em" }}>Guests</div>
|
||
<div style={{ fontWeight: 600, marginTop: 2 }}>2 adults · 1 dog</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style={{ display: "flex", gap: 8 }}>
|
||
<Button leadingIcon={<Icon name="inbox" size={13}/>}>Message Mara</Button>
|
||
<Button variant="secondary">View itinerary</Button>
|
||
<Button variant="ghost">Get directions</Button>
|
||
</div>
|
||
|
||
<div style={{
|
||
marginTop: 18, padding: 12, borderRadius: 10,
|
||
background: "var(--surface-2)", display: "flex", alignItems: "center", gap: 10,
|
||
}}>
|
||
<Icon name="info" size={14} style={{ color: "var(--text-2)" }}/>
|
||
<span style={{ fontSize: "var(--text-sm)", color: "var(--text-2)" }}>
|
||
Free cancellation until <b style={{ color: "var(--text)" }}>Jun 12, 4:00pm</b>.
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div style={{ position: "relative" }}>
|
||
<PhotoSlot label="Big Sur · A-frame" tone="sand" aspect="auto"
|
||
style={{ height: "100%", aspectRatio: "auto" }}/>
|
||
</div>
|
||
</div>
|
||
</Card>
|
||
|
||
{/* Saved + past */}
|
||
<div style={{ display: "grid", gridTemplateColumns: "2fr 1fr", gap: 28 }}>
|
||
<div>
|
||
<h3 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 22, margin: "8px 0 14px",
|
||
fontWeight: 500, letterSpacing: "-0.01em",
|
||
}}>Past trips · 12</h3>
|
||
<div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
|
||
{[
|
||
{ i: "Mendocino, May 2025", l: "Off-grid farmstead", h: "Hosted by Jamal", rating: 5, tone: "sage" },
|
||
{ i: "Joshua Tree, Oct 2024", l: "Modernist villa", h: "Hosted by Sun", rating: 5, tone: "warm" },
|
||
{ i: "Sonoma, Aug 2024", l: "Hillside cottage", h: "Hosted by Lila", rating: 4.5, tone: "blush" },
|
||
].map(t => (
|
||
<Card key={t.i} padding={16} style={{ display: "grid", gridTemplateColumns: "100px 1fr auto", gap: 16, alignItems: "center" }}>
|
||
<div style={{ borderRadius: 10, overflow: "hidden", height: 80 }}>
|
||
<PhotoSlot label="" tone={t.tone} aspect="auto" style={{ height: "100%", aspectRatio: "auto" }}/>
|
||
</div>
|
||
<div>
|
||
<div style={{ fontSize: "var(--text-md)", fontWeight: 600 }}>{t.l}</div>
|
||
<div style={{ fontSize: "var(--text-sm)", color: "var(--text-2)" }}>{t.i} · {t.h}</div>
|
||
<div style={{ marginTop: 4 }}>
|
||
<RatingStars value={t.rating} size={11} showValue={false}/>
|
||
<span style={{ fontSize: "var(--text-xs)", color: "var(--text-3)", marginLeft: 6 }}>You left a review</span>
|
||
</div>
|
||
</div>
|
||
<Button variant="secondary" size="sm">Book again</Button>
|
||
</Card>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<h3 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 22, margin: "8px 0 14px",
|
||
fontWeight: 500, letterSpacing: "-0.01em",
|
||
}}>Wishlist · 8 saved</h3>
|
||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
|
||
{[
|
||
{ l: "Tahoe bungalow", tone: "night" },
|
||
{ l: "Painted barn", tone: "blush" },
|
||
{ l: "Carmel ranch", tone: "sand" },
|
||
{ l: "Harbor loft", tone: "ocean" },
|
||
].map(w => (
|
||
<div key={w.l} style={{ borderRadius: 10, overflow: "hidden", position: "relative" }}>
|
||
<PhotoSlot label={w.l} tone={w.tone} aspect="1/1"/>
|
||
</div>
|
||
))}
|
||
</div>
|
||
<Button variant="ghost" full style={{ marginTop: 10 }}>See all saved →</Button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</MarketplaceDashboardShell>
|
||
);
|
||
|
||
// ============================================================
|
||
// 6 · MESSAGES (Inbox + thread)
|
||
// ============================================================
|
||
const AtlasMessages = () => {
|
||
const threads = [
|
||
{ i: "Mara H", c: "#e8a87c", t: "Big Sur · A-frame", last: "We can leave the gate code in your message…", time: "10:42am", unread: 1, active: true },
|
||
{ i: "Theo Bly", c: "#c8e8a8", t: "Joshua Tree · Villa", last: "Glad you enjoyed! Hope to host you again.", time: "Tuesday", unread: 0 },
|
||
{ i: "Lila Munro", c: "#a8c8e8", t: "Sonoma · Cottage", last: "Yes, both dogs are welcome! Just send their…", time: "May 28", unread: 0 },
|
||
{ i: "Jamal Frost", c: "#c8a8e8", t: "Mendocino · Farmstead", last: "Thanks for the kind review, Mira.", time: "May 12", unread: 0 },
|
||
{ i: "Atlas Concierge", c: "#e8c8a8", t: "Trip planner", last: "Your trip details for Big Sur are ready →", time: "May 6", unread: 0 },
|
||
{ i: "Sun Ortiz", c: "#e8a8c8", t: "Tahoe · Bungalow", last: "We typically don't allow events but…", time: "April 22", unread: 0 },
|
||
];
|
||
|
||
return (
|
||
<MarketplaceDashboardShell role="guest" active="inbox" user={userMira}>
|
||
<div style={{ display: "grid", gridTemplateColumns: "360px 1fr", height: "100%", overflow: "hidden" }}>
|
||
{/* Inbox */}
|
||
<div style={{ borderRight: "1px solid var(--border)", display: "flex", flexDirection: "column" }}>
|
||
<div style={{ padding: "20px 20px 12px" }}>
|
||
<h2 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 24, margin: "0 0 10px",
|
||
fontWeight: 500, letterSpacing: "-0.01em",
|
||
}}>Messages</h2>
|
||
<Input placeholder="Search messages" leadingIcon={<Icon name="search" size={14}/>}/>
|
||
</div>
|
||
<div style={{ padding: "0 12px 4px", display: "flex", gap: 6 }}>
|
||
{["All", "Hosts", "Travelling", "Support"].map((t, i) => (
|
||
<span key={t} style={{
|
||
padding: "5px 10px", borderRadius: 999,
|
||
background: i === 0 ? "var(--text)" : "transparent",
|
||
color: i === 0 ? "var(--bg)" : "var(--text-2)",
|
||
fontSize: 12, fontWeight: 500, cursor: "pointer",
|
||
}}>{t}</span>
|
||
))}
|
||
</div>
|
||
<div style={{ flex: 1, overflowY: "auto", padding: "10px 8px" }}>
|
||
{threads.map(th => (
|
||
<div key={th.i + th.t} style={{
|
||
display: "flex", gap: 12, padding: 12, borderRadius: 10,
|
||
background: th.active ? "var(--surface)" : "transparent",
|
||
boxShadow: th.active ? "var(--shadow-sm)" : "none",
|
||
cursor: "pointer", marginBottom: 2,
|
||
}}>
|
||
<Avatar name={th.i} color={th.c} size={40}/>
|
||
<div style={{ flex: 1, minWidth: 0 }}>
|
||
<div style={{
|
||
display: "flex", justifyContent: "space-between", gap: 6,
|
||
}}>
|
||
<span style={{
|
||
fontSize: "var(--text-md)", fontWeight: th.unread ? 600 : 500,
|
||
color: "var(--text)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
|
||
}}>{th.i}</span>
|
||
<span style={{ fontSize: "var(--text-xs)", color: "var(--text-3)", whiteSpace: "nowrap" }}>{th.time}</span>
|
||
</div>
|
||
<div style={{ fontSize: "var(--text-xs)", color: "var(--accent)", marginTop: 1, fontWeight: 500 }}>
|
||
{th.t}
|
||
</div>
|
||
<div style={{
|
||
fontSize: "var(--text-sm)", color: th.unread ? "var(--text)" : "var(--text-2)",
|
||
marginTop: 2,
|
||
display: "-webkit-box", WebkitLineClamp: 1, WebkitBoxOrient: "vertical",
|
||
overflow: "hidden",
|
||
}}>{th.last}</div>
|
||
</div>
|
||
{th.unread > 0 && <span style={{
|
||
width: 8, height: 8, borderRadius: "50%", background: "var(--accent)",
|
||
alignSelf: "center", flexShrink: 0,
|
||
}}/>}
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Thread */}
|
||
<div style={{ display: "flex", flexDirection: "column", overflow: "hidden" }}>
|
||
{/* Thread header */}
|
||
<div style={{
|
||
padding: "18px 28px", borderBottom: "1px solid var(--border)",
|
||
display: "flex", justifyContent: "space-between", alignItems: "center", gap: 16,
|
||
}}>
|
||
<div style={{ display: "flex", alignItems: "center", gap: 14, minWidth: 0 }}>
|
||
<Avatar name="Mara H" color="#e8a87c" size={44}/>
|
||
<div style={{ minWidth: 0 }}>
|
||
<div style={{
|
||
fontFamily: "var(--font-display)", fontSize: 20,
|
||
fontWeight: 500, letterSpacing: "-0.01em",
|
||
}}>Mara H</div>
|
||
<div style={{ fontSize: "var(--text-xs)", color: "var(--text-3)" }}>
|
||
Host · responds in ~30 min · joined 2019
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div style={{ display: "flex", gap: 8 }}>
|
||
<Button variant="secondary" size="sm">View listing</Button>
|
||
<IconButton name="more" variant="secondary" label="More"/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Trip card */}
|
||
<div style={{ padding: "16px 28px 0" }}>
|
||
<div style={{
|
||
display: "flex", gap: 14, padding: 14,
|
||
borderRadius: 12, background: "var(--surface-2)",
|
||
border: "1px solid var(--border)",
|
||
}}>
|
||
<div style={{ width: 60, height: 60, borderRadius: 8, overflow: "hidden", flexShrink: 0 }}>
|
||
<PhotoSlot label="" tone="sand" aspect="1/1"/>
|
||
</div>
|
||
<div style={{ flex: 1 }}>
|
||
<div style={{ fontSize: "var(--text-sm)", fontWeight: 600 }}>Cliffside cabin in the pines</div>
|
||
<div style={{ fontSize: "var(--text-xs)", color: "var(--text-3)" }}>Big Sur · Jun 14 → 19 · 2 guests</div>
|
||
<div style={{ marginTop: 6, display: "flex", gap: 6 }}>
|
||
<Badge tone="success" dot>Confirmed</Badge>
|
||
<Badge>$1,846 total</Badge>
|
||
</div>
|
||
</div>
|
||
<Button variant="ghost" size="sm">Trip details →</Button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Messages */}
|
||
<div style={{ flex: 1, overflowY: "auto", padding: "20px 28px" }}>
|
||
<div style={{ textAlign: "center", fontSize: "var(--text-xs)", color: "var(--text-3)", margin: "8px 0 18px" }}>
|
||
May 22 · Booking confirmed
|
||
</div>
|
||
<MessageBubble name="Mara H" color="#e8a87c" mine={false} time="10:14am"
|
||
body="Hi Mira! So happy to host you and the pup in June. The roads are spectacular this time of year. Will let you know about the gate code closer to."/>
|
||
<MessageBubble mine time="10:21am"
|
||
body="Thank you Mara! Quick question — is there a good local bakery you'd recommend for sourdough?"/>
|
||
<MessageBubble name="Mara H" color="#e8a87c" mine={false} time="10:38am" attachment="Mara's local map.pdf · 2 pages"
|
||
body="Of course. Bigotti's is the obvious answer but I'll send you my whole list. The man who runs it remembers everyone's order."/>
|
||
<MessageBubble name="Mara H" color="#e8a87c" mine={false} time="10:42am"
|
||
body="We can leave the gate code in your message thread the morning of check-in. The cabin will be unlocked when you arrive — fire laid, coffee ground."/>
|
||
<div style={{ textAlign: "center", marginTop: 10 }}>
|
||
<span style={{
|
||
display: "inline-block", padding: "4px 10px", borderRadius: 999,
|
||
background: "var(--surface-2)", border: "1px solid var(--border)",
|
||
fontSize: "var(--text-xs)", color: "var(--text-3)",
|
||
}}>Mara is typing…</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Composer */}
|
||
<div style={{ padding: 16, borderTop: "1px solid var(--border)" }}>
|
||
<div style={{
|
||
display: "flex", alignItems: "flex-end", gap: 10,
|
||
padding: 8, borderRadius: 14,
|
||
background: "var(--surface)", border: "1px solid var(--border)",
|
||
}}>
|
||
<IconButton name="plus" size="sm" variant="ghost" label="Attach"/>
|
||
<textarea placeholder="Write a message…" rows="1" style={{
|
||
flex: 1, border: "none", outline: "none", background: "transparent",
|
||
fontFamily: "var(--font-sans)", fontSize: "var(--text-md)",
|
||
color: "var(--text)", resize: "none", padding: "6px 0",
|
||
}}/>
|
||
<Button size="sm">Send</Button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</MarketplaceDashboardShell>
|
||
);
|
||
};
|
||
|
||
// ============================================================
|
||
// 7 · HOST DASHBOARD · TODAY
|
||
// ============================================================
|
||
const AtlasHostDash = () => {
|
||
// Build 4 weeks of availability for the heatmap
|
||
const weeks = [
|
||
["booked","booked","booked","open","open","open","open"],
|
||
["booked","booked","booked","booked","booked","booked","booked"],
|
||
["open","open","open","blocked","blocked","blocked","blocked"],
|
||
["open","open","booked","booked","open","open","open"],
|
||
];
|
||
|
||
// SVG bar chart for monthly earnings
|
||
const earnings = [3200, 4100, 3850, 4900, 5400, 6200, 7100, 6800, 5900, 6400, 5200, 4800, 6900, 8200];
|
||
const maxE = Math.max(...earnings);
|
||
|
||
return (
|
||
<MarketplaceDashboardShell role="host" active="today" user={{ name: "Mara H", color: "#e8a87c" }}>
|
||
<div style={{ padding: "28px 36px 40px", overflow: "auto" }}>
|
||
<div style={{
|
||
display: "flex", justifyContent: "space-between", alignItems: "baseline",
|
||
marginBottom: 22, flexWrap: "wrap", gap: 16,
|
||
}}>
|
||
<div>
|
||
<div style={{
|
||
fontSize: "var(--text-xs)", color: "var(--text-3)",
|
||
textTransform: "uppercase", letterSpacing: "0.06em",
|
||
fontWeight: 500, marginBottom: 4,
|
||
}}>Hosting · Monday, May 25</div>
|
||
<h1 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 32, margin: 0,
|
||
fontWeight: 500, letterSpacing: "-0.02em",
|
||
}}>Good morning, Mara</h1>
|
||
<div style={{ fontSize: "var(--text-sm)", color: "var(--text-2)", marginTop: 4 }}>
|
||
You have 1 check-in this week and 2 messages waiting.
|
||
</div>
|
||
</div>
|
||
<div style={{ display: "flex", gap: 8 }}>
|
||
<Button variant="secondary">View as guest</Button>
|
||
<Button leadingIcon={<Icon name="plus" size={13}/>}>Create listing</Button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* KPI strip */}
|
||
<div style={{
|
||
display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 14, marginBottom: 24,
|
||
}}>
|
||
<StatTile label="Earnings · MTD" value="$8,240" sub="vs last month" trend={18} icon="bar"/>
|
||
<StatTile label="Upcoming bookings" value="6" sub="next 30 days" icon="briefcase"/>
|
||
<StatTile label="Rating · 90d" value="4.96" sub="218 reviews" icon="star"/>
|
||
<StatTile label="Response rate" value="98%" sub="avg. 30 min" icon="bolt"/>
|
||
</div>
|
||
|
||
<div style={{ display: "grid", gridTemplateColumns: "1.5fr 1fr", gap: 24 }}>
|
||
{/* Earnings chart */}
|
||
<Card padding={24}>
|
||
<div style={{
|
||
display: "flex", justifyContent: "space-between", alignItems: "baseline",
|
||
marginBottom: 18,
|
||
}}>
|
||
<div>
|
||
<h3 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 22, margin: 0,
|
||
fontWeight: 500, letterSpacing: "-0.01em",
|
||
}}>Earnings</h3>
|
||
<div style={{ fontSize: "var(--text-xs)", color: "var(--text-3)", marginTop: 2 }}>Last 14 days</div>
|
||
</div>
|
||
<Tabs variant="pill" items={[{ label: "Day" }, { label: "Week" }, { label: "Month" }]} active="Day"/>
|
||
</div>
|
||
<div style={{ position: "relative", height: 180 }}>
|
||
{[0, 0.25, 0.5, 0.75, 1].map(p => (
|
||
<div key={p} style={{
|
||
position: "absolute", left: 0, right: 0,
|
||
bottom: `${p * 100}%`, height: 1,
|
||
background: "var(--divider)",
|
||
}}/>
|
||
))}
|
||
<div style={{
|
||
position: "absolute", inset: 0,
|
||
display: "flex", alignItems: "flex-end", gap: 8, paddingRight: 4,
|
||
}}>
|
||
{earnings.map((v, i) => (
|
||
<div key={i} style={{ flex: 1, display: "flex", flexDirection: "column", justifyContent: "flex-end", height: "100%" }}>
|
||
<div style={{
|
||
width: "100%", height: `${(v / maxE) * 100}%`,
|
||
background: i === earnings.length - 1
|
||
? `linear-gradient(180deg, var(--accent), var(--accent-2))`
|
||
: "var(--surface-alt)",
|
||
borderRadius: 4,
|
||
}}/>
|
||
</div>
|
||
))}
|
||
</div>
|
||
<div style={{
|
||
position: "absolute", right: 0, top: -6,
|
||
background: "var(--text)", color: "var(--bg)",
|
||
padding: "3px 8px", borderRadius: 4,
|
||
fontSize: 11, fontWeight: 500,
|
||
}}>$820 · today</div>
|
||
</div>
|
||
<div style={{
|
||
display: "flex", justifyContent: "space-between", marginTop: 10,
|
||
fontSize: 10, color: "var(--text-3)", fontFamily: "var(--font-mono)",
|
||
}}>
|
||
{["May 12","M 13","T 14","W 15","T 16","F 17","S 18","S 19","M 20","T 21","W 22","T 23","F 24","Today"].map(d => (
|
||
<span key={d}>{d}</span>
|
||
))}
|
||
</div>
|
||
</Card>
|
||
|
||
{/* Upcoming bookings */}
|
||
<Card padding={24}>
|
||
<h3 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 22, margin: "0 0 16px",
|
||
fontWeight: 500, letterSpacing: "-0.01em",
|
||
}}>Upcoming check-ins</h3>
|
||
{[
|
||
{ g: "Mira Reyes", c: "#d4b8a8", date: "Jun 14 · 5 nights", note: "Welcome!" },
|
||
{ g: "Sun Ortiz", c: "#a8c8e8", date: "Jul 02 · 3 nights", note: "Repeat guest" },
|
||
{ g: "Henri Lamarck", c: "#c8e8a8", date: "Jul 15 · 7 nights", note: "Honeymoon" },
|
||
].map(g => (
|
||
<div key={g.g} style={{
|
||
display: "flex", alignItems: "center", gap: 12, padding: "10px 0",
|
||
borderTop: "1px solid var(--divider)",
|
||
}}>
|
||
<Avatar name={g.g} color={g.c} size={36}/>
|
||
<div style={{ flex: 1, minWidth: 0 }}>
|
||
<div style={{ fontSize: "var(--text-md)", fontWeight: 500 }}>{g.g}</div>
|
||
<div style={{ fontSize: "var(--text-xs)", color: "var(--text-3)" }}>
|
||
{g.date} · {g.note}
|
||
</div>
|
||
</div>
|
||
<Button size="sm" variant="ghost">Message</Button>
|
||
</div>
|
||
))}
|
||
</Card>
|
||
|
||
{/* Calendar heatmap */}
|
||
<Card padding={24}>
|
||
<div style={{
|
||
display: "flex", justifyContent: "space-between", alignItems: "baseline",
|
||
marginBottom: 16,
|
||
}}>
|
||
<h3 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 22, margin: 0,
|
||
fontWeight: 500, letterSpacing: "-0.01em",
|
||
}}>Calendar · June 2026</h3>
|
||
<Button size="sm" variant="ghost">Manage →</Button>
|
||
</div>
|
||
<AvailabilityHeatmap weeks={weeks}/>
|
||
<div style={{
|
||
display: "flex", gap: 16, marginTop: 14, fontSize: "var(--text-xs)", color: "var(--text-2)",
|
||
}}>
|
||
<span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
|
||
<span style={{ width: 10, height: 10, background: "var(--accent-soft)", border: "1px solid var(--accent)", borderRadius: 2 }}/>
|
||
Booked
|
||
</span>
|
||
<span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
|
||
<span style={{ width: 10, height: 10, background: "var(--success-soft)", border: "1px solid var(--success)", borderRadius: 2 }}/>
|
||
Open
|
||
</span>
|
||
<span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
|
||
<span style={{ width: 10, height: 10, background: "var(--surface-alt)", border: "1px solid var(--text-3)", borderRadius: 2 }}/>
|
||
Blocked
|
||
</span>
|
||
</div>
|
||
</Card>
|
||
|
||
{/* Recent reviews */}
|
||
<Card padding={24}>
|
||
<h3 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 22, margin: "0 0 16px",
|
||
fontWeight: 500, letterSpacing: "-0.01em",
|
||
}}>Recent reviews</h3>
|
||
<ReviewCard author="Naila Choudhury" avatarColor="#e8a87c" rating={5} date="April 2026"
|
||
body="Photos don't do it justice. The light at golden hour is something to plan for."/>
|
||
<Divider/>
|
||
<ReviewCard author="Henri Lamarck" avatarColor="#a8c8e8" rating={4.5} date="March 2026"
|
||
body="Beautiful design, very thoughtful. Wifi was patchy for video calls — probably a feature."/>
|
||
<Button variant="ghost" full style={{ marginTop: 4 }}>View all 218 →</Button>
|
||
</Card>
|
||
</div>
|
||
</div>
|
||
</MarketplaceDashboardShell>
|
||
);
|
||
};
|
||
|
||
// ============================================================
|
||
// 8 · NEW LISTING — step 3 of 6 ("Make it pop")
|
||
// ============================================================
|
||
const AtlasNewListing = () => {
|
||
return (
|
||
<MarketplaceDashboardShell role="host" active="listings" user={{ name: "Mara H", color: "#e8a87c" }}>
|
||
<div style={{ display: "flex", flexDirection: "column", height: "100%", overflow: "hidden" }}>
|
||
{/* Wizard header */}
|
||
<div style={{
|
||
padding: "18px 36px", borderBottom: "1px solid var(--border)",
|
||
display: "flex", justifyContent: "space-between", alignItems: "center",
|
||
}}>
|
||
<div>
|
||
<div style={{
|
||
fontSize: "var(--text-xs)", color: "var(--text-3)",
|
||
textTransform: "uppercase", letterSpacing: "0.06em",
|
||
fontWeight: 500, marginBottom: 2,
|
||
}}>Step 3 of 6 · Make it pop</div>
|
||
<h1 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 22, margin: 0,
|
||
fontWeight: 500, letterSpacing: "-0.01em",
|
||
}}>Add photos, title and description</h1>
|
||
</div>
|
||
<div style={{ display: "flex", gap: 8 }}>
|
||
<Button variant="ghost">Save & exit</Button>
|
||
<Button variant="secondary">Questions?</Button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Progress */}
|
||
<div style={{ padding: "12px 36px", borderBottom: "1px solid var(--border)" }}>
|
||
<div style={{ display: "grid", gridTemplateColumns: "repeat(6, 1fr)", gap: 8 }}>
|
||
{["About your place","Make it stand out","Make it pop","Set price","Publish","Welcome guests"].map((s, i) => (
|
||
<div key={s}>
|
||
<div style={{
|
||
height: 4, borderRadius: 2,
|
||
background: i < 2 ? "var(--text)" : i === 2 ? "var(--accent)" : "var(--surface-alt)",
|
||
}}/>
|
||
<div style={{
|
||
fontSize: 11, marginTop: 6,
|
||
color: i === 2 ? "var(--accent)" : i < 2 ? "var(--text)" : "var(--text-3)",
|
||
fontWeight: i === 2 ? 600 : 500,
|
||
}}>{s}</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Body */}
|
||
<div style={{ flex: 1, overflowY: "auto", padding: "28px 36px" }}>
|
||
<div style={{ display: "grid", gridTemplateColumns: "1.4fr 1fr", gap: 48, maxWidth: 1180, margin: "0 auto" }}>
|
||
<div>
|
||
{/* Photos */}
|
||
<section style={{ marginBottom: 32 }}>
|
||
<h2 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 26, margin: "0 0 6px",
|
||
fontWeight: 500, letterSpacing: "-0.02em",
|
||
}}>Photos · 12 of 5 required</h2>
|
||
<p style={{ fontSize: "var(--text-sm)", color: "var(--text-2)", margin: "0 0 18px" }}>
|
||
Drag to reorder. The first photo is your cover.
|
||
</p>
|
||
<div style={{
|
||
display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 12,
|
||
}}>
|
||
{[
|
||
{ l: "Cover · exterior", tone: "sand", primary: true },
|
||
{ l: "Living room", tone: "warm"},
|
||
{ l: "Kitchen", tone: "blush"},
|
||
{ l: "Bedroom", tone: "ocean"},
|
||
{ l: "Deck & view", tone: "sage"},
|
||
{ l: "Soaking tub", tone: "warm"},
|
||
].map(p => (
|
||
<div key={p.l} style={{
|
||
position: "relative", borderRadius: "var(--listing-radius)",
|
||
overflow: "hidden", border: p.primary ? "2px solid var(--accent)" : "1px solid var(--border)",
|
||
}}>
|
||
<PhotoSlot label={p.l} tone={p.tone} aspect="4/3"/>
|
||
{p.primary && <Badge tone="accent" leadingIcon={<Icon name="star" size={10}/>}
|
||
style={{ position: "absolute", top: 10, left: 10 }}>Cover</Badge>}
|
||
<IconButton name="more" size="sm" variant="secondary"
|
||
style={{ position: "absolute", top: 8, right: 8 }} label="Photo options"/>
|
||
</div>
|
||
))}
|
||
<div style={{
|
||
border: "1.5px dashed var(--border-strong)", borderRadius: "var(--listing-radius)",
|
||
aspectRatio: "4/3", display: "flex", flexDirection: "column",
|
||
alignItems: "center", justifyContent: "center", cursor: "pointer",
|
||
color: "var(--text-2)", background: "var(--surface-2)",
|
||
}}>
|
||
<div style={{
|
||
width: 44, height: 44, borderRadius: "50%", background: "var(--surface)",
|
||
border: "1px solid var(--border-strong)",
|
||
display: "flex", alignItems: "center", justifyContent: "center",
|
||
marginBottom: 10,
|
||
}}><Icon name="plus" size={20}/></div>
|
||
<span style={{ fontSize: "var(--text-sm)", fontWeight: 500 }}>Add more photos</span>
|
||
<span style={{ fontSize: "var(--text-xs)", color: "var(--text-3)" }}>or drop them here</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Title */}
|
||
<section style={{ marginBottom: 28 }}>
|
||
<h2 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 26, margin: "0 0 6px",
|
||
fontWeight: 500, letterSpacing: "-0.02em",
|
||
}}>Now, let's give it a title</h2>
|
||
<p style={{ fontSize: "var(--text-sm)", color: "var(--text-2)", margin: "0 0 14px" }}>
|
||
Short titles work best. Have fun with it — you can always change it later.
|
||
</p>
|
||
<Input value="Cliffside cabin in the pines"
|
||
style={{ fontSize: 22, fontFamily: "var(--font-display)", fontWeight: 500, padding: "16px 18px" }}/>
|
||
<div style={{ fontSize: "var(--text-xs)", color: "var(--text-3)", marginTop: 8 }}>
|
||
32 / 50 characters
|
||
</div>
|
||
</section>
|
||
|
||
{/* Description */}
|
||
<section>
|
||
<h2 style={{
|
||
fontFamily: "var(--font-display)", fontSize: 26, margin: "0 0 6px",
|
||
fontWeight: 500, letterSpacing: "-0.02em",
|
||
}}>Create your description</h2>
|
||
<p style={{ fontSize: "var(--text-sm)", color: "var(--text-2)", margin: "0 0 14px" }}>
|
||
Share what makes your place special. We'll suggest improvements as you write.
|
||
</p>
|
||
<Textarea rows={5}
|
||
value="Set 80 feet above the Pacific, this A-frame is a quiet, light-soaked retreat. Architecturally restored in 2024 with radiant floors, a wood-burning stove, and a Furlong soaking tub on the deck. Stargazing is the only TV."/>
|
||
<div style={{
|
||
marginTop: 10, padding: 14, borderRadius: 10,
|
||
background: "var(--accent-soft)", display: "flex", gap: 12, alignItems: "flex-start",
|
||
}}>
|
||
<Icon name="spark" size={16} style={{ color: "var(--accent)", marginTop: 2 }}/>
|
||
<div style={{ flex: 1 }}>
|
||
<div style={{ fontSize: "var(--text-sm)", fontWeight: 600, color: "var(--text)" }}>
|
||
Atlas suggests: lead with sensory details
|
||
</div>
|
||
<div style={{ fontSize: "var(--text-sm)", color: "var(--text-2)", marginTop: 2, lineHeight: 1.5 }}>
|
||
"Wake to ocean light through the redwoods…" tends to perform better than a list of features.
|
||
</div>
|
||
</div>
|
||
<Button size="sm" variant="ghost">Rewrite</Button>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
|
||
{/* Live preview */}
|
||
<aside style={{ position: "sticky", top: 0 }}>
|
||
<div style={{
|
||
fontSize: "var(--text-xs)", color: "var(--text-3)",
|
||
textTransform: "uppercase", letterSpacing: "0.08em",
|
||
fontWeight: 500, marginBottom: 12,
|
||
}}>Live preview</div>
|
||
<ListingCard listing={{
|
||
photo: { label: "Big Sur · A-frame", tone: "sand" },
|
||
title: "Cliffside cabin in the pines",
|
||
subtitle: "Big Sur, California",
|
||
price: { amount: 318, period: "/ night" },
|
||
rating: 4.94, reviews: 218,
|
||
badges: ["superhost"], tags: ["New"],
|
||
}}/>
|
||
<div style={{
|
||
marginTop: 16, padding: 14, borderRadius: 10,
|
||
background: "var(--surface)", border: "1px solid var(--border)",
|
||
fontSize: "var(--text-xs)", color: "var(--text-2)", lineHeight: 1.5,
|
||
}}>
|
||
This is how guests will see your listing in search results.
|
||
Don't worry — you'll be able to fine-tune everything after publishing.
|
||
</div>
|
||
</aside>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Bottom nav */}
|
||
<div style={{
|
||
padding: "16px 36px", borderTop: "1px solid var(--border)",
|
||
display: "flex", justifyContent: "space-between", alignItems: "center",
|
||
background: "var(--surface)",
|
||
}}>
|
||
<Button variant="ghost" leadingIcon={<Icon name="chevLeft" size={13}/>}>Back</Button>
|
||
<div style={{ display: "flex", gap: 12, fontSize: "var(--text-xs)", color: "var(--text-3)" }}>
|
||
<span>Auto-saved · just now</span>
|
||
</div>
|
||
<Button trailingIcon={<Icon name="arrow" size={13}/>}>Next · set your price</Button>
|
||
</div>
|
||
</div>
|
||
</MarketplaceDashboardShell>
|
||
);
|
||
};
|
||
|
||
// Export to window
|
||
Object.assign(window, {
|
||
AtlasHome, AtlasSearch, AtlasListing, AtlasCheckout,
|
||
AtlasMessages, AtlasGuestDash, AtlasHostDash, AtlasNewListing,
|
||
});
|