// Smelebrity — "Smell like your favourite celebrity"
// Two screens (Home, Celebrity review), all data from CELEBRITIES array.
const { useState, useEffect, useMemo } = React;
const CELEBRITIES = window.CELEBRITIES;
const GUIDES = window.GUIDES || [];
const SITE_PAGES = window.SITE_PAGES || {};
const FEATURED = CELEBRITIES[0];
const WEEKLY = CELEBRITIES.slice(1, 5);
const STANDING = CELEBRITIES.slice(5, 11);
// Static multi-page routing (set by each HTML file at build time).
const SM_PAGE = window.__SM_PAGE__ || 'home';
function homeUrl() {
return '/';
}
function celebUrl(slug) {
return `/celebrities/${slug}/`;
}
function guidesIndexUrl() {
return '/guides/';
}
function guideUrl(slug) {
return `/guides/${slug}/`;
}
function celebIndexUrl() {
return '/celebrities/';
}
function celebCategoryUrl(segment) {
return `/celebrities/${segment}/`;
}
function sitePageUrl(page) {
return `/${page}/`;
}
function celebProfession(c) {
return c.profession || 'actor';
}
function shuffleArray(items) {
const list = items.slice();
for (let i = list.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[list[i], list[j]] = [list[j], list[i]];
}
return list;
}
function relatedCelebritiesFor(currentSlug) {
const baked = window.__RELATED_SLUGS__;
if (Array.isArray(baked) && baked.length) {
return baked
.map((slug) => CELEBRITIES.find((c) => c.slug === slug))
.filter(Boolean);
}
return shuffleArray(CELEBRITIES.filter((c) => c.slug !== currentSlug)).slice(0, 3);
}
function formatGuideDate(iso) {
if (!iso) return '';
const d = new Date(iso + 'T12:00:00');
return d.toLocaleDateString('en-GB', { day: 'numeric', month: 'long', year: 'numeric' });
}
function resolveImageUrl(imageUrl) {
if (!imageUrl) return null;
if (/^https?:\/\//i.test(imageUrl)) return imageUrl;
if (imageUrl.startsWith('images/')) {
return `/${imageUrl}`;
}
return imageUrl;
}
function initialRoute() {
if (SM_PAGE === 'guide' && window.__INITIAL_GUIDE_SLUG__) {
const slug = window.__INITIAL_GUIDE_SLUG__;
if (GUIDES.some((g) => g.slug === slug)) {
return { route: 'guide', slug };
}
}
if (SM_PAGE === 'guides-index') {
return { route: 'guides', slug: null };
}
if (SM_PAGE === 'celebrities-index') {
return { route: 'celebrities-index', slug: null };
}
if (SM_PAGE === 'celebrities-a-list') {
return { route: 'celebrities-a-list', slug: null };
}
if (SM_PAGE === 'celebrities-athletes') {
return { route: 'celebrities-athletes', slug: null };
}
if (SM_PAGE === 'celebrities-musicians') {
return { route: 'celebrities-musicians', slug: null };
}
if (SITE_PAGES[SM_PAGE]) {
return { route: SM_PAGE, slug: null };
}
if (SM_PAGE === 'celebrity' && window.__INITIAL_SLUG__) {
const slug = window.__INITIAL_SLUG__;
if (CELEBRITIES.some((c) => c.slug === slug)) {
return { route: 'review', slug };
}
}
return { route: 'home', slug: FEATURED.slug };
}
// Design tweaks panel — off in production unless explicitly enabled in HTML.
const ENABLE_TWEAKS = window.__ENABLE_TWEAKS__ === true;
// ── Tweak defaults ──────────────────────────────────────────────────────────
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
"palette": "noir",
"typePair": "editorial",
"heroLayout": "full",
"density": "regular",
"ctaStyle": "solid",
"ctaCopy": "Buy on Amazon →"
}/*EDITMODE-END*/;
// ── Design tokens (driven by tweaks) ────────────────────────────────────────
const PALETTES = {
noir: { bg:'#0b0a08', surface:'#141210', line:'rgba(214,182,108,0.14)', ink:'#efe6d3', mute:'rgba(239,230,211,0.58)', dim:'rgba(239,230,211,0.32)', accent:'#d6b66c', accentDeep:'#a8864a', tint:'rgba(214,182,108,0.08)' },
cognac: { bg:'#1a120b', surface:'#22180f', line:'rgba(220,150,90,0.16)', ink:'#f3e6d1', mute:'rgba(243,230,209,0.6)', dim:'rgba(243,230,209,0.32)', accent:'#dc965a', accentDeep:'#a86a39', tint:'rgba(220,150,90,0.08)' },
onyx: { bg:'#0a0d12', surface:'#11151b', line:'rgba(180,196,220,0.14)', ink:'#eaeef5', mute:'rgba(234,238,245,0.6)', dim:'rgba(234,238,245,0.32)', accent:'#b8c7d9', accentDeep:'#7d8ea2', tint:'rgba(180,196,220,0.06)' },
};
const TYPE_PAIRS = {
editorial: { display:'"DM Serif Display", "Cormorant Garamond", serif', body:'"Manrope", system-ui, sans-serif', mono:'"JetBrains Mono", ui-monospace, monospace', displayWeight:400, italicDisplay:true },
modern: { display:'"Syne", system-ui, sans-serif', body:'"Manrope", system-ui, sans-serif', mono:'"JetBrains Mono", ui-monospace, monospace', displayWeight:700, italicDisplay:false },
classic: { display:'"Bodoni Moda", "Didot", serif', body:'"Work Sans", system-ui, sans-serif', mono:'"JetBrains Mono", ui-monospace, monospace', displayWeight:500, italicDisplay:false },
};
const DENSITY = {
compact: { sectionY: 64, cardGap: 16, blockGap: 28 },
regular: { sectionY: 96, cardGap: 24, blockGap: 40 },
roomy: { sectionY: 140, cardGap: 32, blockGap: 56 },
};
// ── Small atoms ─────────────────────────────────────────────────────────────
function Kicker({ children, style }) {
return
{children}
;
}
function CTA({ children, style, variant, size = 'md', href, onClick, disabled }) {
const cls = `cta cta-${variant} cta-${size}${disabled ? ' cta-disabled' : ''}`;
if (disabled) {
return {children} ;
}
if (href) return {children} ;
return {children} ;
}
// ── Buy logic ──────────────────────────────────────────────────────────────
// One source of truth for routing a celeb's purchase intent:
// • amazonUrl present → "Buy on Amazon →" to amazonUrl
// • amazonUrl null, altRetailerUrl set → "Shop on →" to altRetailerUrl
// • amazonUrl + altRetailerUrl both set → Amazon primary, alt as secondary link
// • neither → disabled "Coming soon"
function BuyButton({ celeb, ctaCopy, size = 'lg', variant = 'primary' }) {
const hasAmazon = !!celeb.amazonUrl;
const hasAlt = !!celeb.altRetailerUrl;
if (!hasAmazon && !hasAlt) {
return Coming soon ;
}
const href = hasAmazon ? celeb.amazonUrl : celeb.altRetailerUrl;
const label = hasAmazon ? ctaCopy : `Shop on ${celeb.altRetailerName} \u2192`;
return {label} ;
}
function SecondaryRetailerLink({ celeb }) {
if (!celeb.amazonUrl || !celeb.altRetailerUrl) return null;
return (
Also at {celeb.altRetailerName} →
);
}
function buyTrustLabels(celeb) {
if (celeb.amazonUrl) {
return ['Secure checkout', 'Shop with confidence on Amazon'];
}
if (celeb.altRetailerUrl) {
return ['Secure checkout', 'Official retailer site'];
}
return null;
}
// Bottle: real image if imageUrl is set, otherwise the abstract SVG placeholder.
function BottleSlot({ tall = false, label = 'product shot', accent = '#d6b66c', imageUrl }) {
const aspect = tall ? '3/4.6' : '1/1.1';
const src = resolveImageUrl(imageUrl);
if (src) {
return (
);
}
return (
);
}
// ── Navigation ──────────────────────────────────────────────────────────────
function TopNav({ route, navigate }) {
const [menuOpen, setMenuOpen] = useState(false);
// Close the mobile menu whenever route changes.
useEffect(() => { setMenuOpen(false); }, [route]);
// Lock body scroll when the mobile menu is open.
useEffect(() => {
if (menuOpen) {
const prev = document.body.style.overflow;
document.body.style.overflow = 'hidden';
return () => { document.body.style.overflow = prev; };
}
}, [menuOpen]);
const go = (view, slug) => (e) => {
e.preventDefault();
setMenuOpen(false);
navigate(view, slug);
};
const guidesActive = route === 'guides' || route === 'guide';
return (
);
}
// ── HOME PAGE ───────────────────────────────────────────────────────────────
function Home({ navigate, ctaCopy, heroLayout }) {
return (
{heroLayout === 'full' ?
: }
);
}
function HeroFullBleed({ navigate, ctaCopy }) {
const c = FEATURED;
const [first, ...rest] = c.celebrity.split(' ');
const last = rest.join(' ');
return (
The Smelebrity No. 01 · Researched
Smell like {first} {last} .
{c.lead}
Score
{c.score.toFixed(1)}/10
{c.price != null && c.price !== '' && (
Amazon price today
{c.was != null && c.was !== '' && {c.was} } {c.price}
)}
His signature since
{c.sinceYear}
navigate('review', c.slug)}>Read the full breakdown →
{c.score.toFixed(1)}
Smelebrity Score
);
}
function HeroEditorial({ navigate, ctaCopy }) {
const c = FEATURED;
return (
Issue 14 · The Celebrity Signature Edition · May 2026
The {CELEBRITIES.length} celebrity scents
worth your money this year.
No. 01
{c.celebrity} wears
{c.fragrance}
{c.verdict}
{c.score.toFixed(1)} Score
{c.price != null && c.price !== '' && (
{c.price} Amazon
)}
{c.sinceYear} Since
navigate('review', c.slug)}>Full breakdown →
);
}
function WeeklySection({ navigate }) {
return (
{WEEKLY.map((r, i) => (
navigate('review', r.slug)}>
{String(i+1).padStart(2,'0')}
Smell like {r.celebShort}
{r.brand} {r.fragrance}
{r.blurb}
{r.score.toFixed(1)}/10
{r.price != null && r.price !== '' && (
{r.price}
)}
))}
);
}
function ResearchBar() {
return (
How we research
We research every celebrity. You shop with confidence.
Every celebrity scent on Smelebrity is sourced from on-the-record interviews, press campaigns, brand archives, and documented historical records. Source confidence is noted on every page — from confirmed brand endorsements to historical community records.
{CELEBRITIES.length}
Celebs tracked
);
}
function CelebrityPickCard({ celeb, ctaCopy, navigate }) {
return (
navigate('review', celeb.slug)}
style={{ cursor: 'pointer' }}
>
{celeb.tag}
Smell like {celeb.celebShort}
{celeb.brand} {celeb.fragrance}
{celeb.why}
{celeb.score.toFixed(1)}
{celeb.price != null && celeb.price !== '' && (
{celeb.price}
)}
);
}
function CelebrityPicksGrid({ celebrities, ctaCopy, navigate }) {
return (
{celebrities.map((c) => (
))}
);
}
function CelebritiesCategoryHero({ kicker, title, lead }) {
return (
{kicker &&
{kicker} }
{title}
{lead &&
{lead}
}
);
}
function CelebritiesIndexPage({ navigate, ctaCopy }) {
const trending = CELEBRITIES.filter((c) => c.category === 'trending');
const oldHollywood = CELEBRITIES.filter((c) => c.category === 'old-hollywood');
return (
);
}
function CelebritiesAListPage({ navigate, ctaCopy }) {
return (
);
}
function CelebritiesProfessionPage({ navigate, ctaCopy, profession, kicker, title, lead, footnote }) {
const list = CELEBRITIES.filter((c) => celebProfession(c) === profession);
return (
);
}
function StaticSitePage({ pageId, navigate }) {
const page = SITE_PAGES[pageId];
if (!page) return null;
return (
{page.sections.map((section, i) => (
{section.heading && (
{section.heading}
)}
{section.type === 'cards' && section.items && (
{section.items.map((card) => (
{card.title}
{card.body}
{card.examples}
))}
)}
{section.type === 'list' && section.items && (
{section.items.map((item) => (
{item}
))}
)}
{section.type === 'email' && (
)}
{section.paragraphs &&
section.paragraphs.map((para, j) => (
{para}
))}
))}
);
}
function StandingPicks({ ctaCopy, navigate }) {
return (
);
}
function FooterCta({ ctaCopy }) {
const c = FEATURED;
return (
One last thing
You came here to smell like a star.
Here's where to start.
{c.celebrity}'s signature: {c.brand} {c.fragrance}{c.size ? `, ${c.size}` : ''}.
{c.price != null && c.price !== '' ? (
<> {c.was != null && c.was !== '' ? <>{c.was} → > : null}{c.price} on Amazon today.>
) : null}{' '}
{c.score.toFixed(1)}/10, his confirmed pick since {c.sinceYear}.
Smelebrity earns a commission on Amazon purchases via the links above. The picks are unaffected.
);
}
function SectionHeader({ kicker, title, rightLink }) {
return (
);
}
function SiteFooter({ navigate }) {
const footGo = (view, slug) => (e) => {
e.preventDefault();
navigate(view, slug);
};
return (
);
}
// ── GUIDES ──────────────────────────────────────────────────────────────────
function GuidesIndex({ navigate }) {
return (
Journal
Fragrance, confidence,and how to show up.
Essays on scent, first impressions, and the quiet rituals that help you walk into any room like you belong there.
{GUIDES.map((g) => (
navigate('guide', g.slug)}
style={{ cursor: 'pointer' }}
>
{g.category}
{g.title}
{g.heroText}
{formatGuideDate(g.publishDate)}
Read article →
))}
);
}
function GuideArticle({ navigate, current: g }) {
const others = GUIDES.filter((x) => x.slug !== g.slug);
return (
{g.category} · {formatGuideDate(g.publishDate)}
{g.title}
{g.heroText}
{g.sections.map((section, i) => (
{section.heading}
{section.paragraphs.map((para, j) => (
{para}
))}
))}
{others.length > 0 && (
Keep reading
More from the journal.
{others.map((o) => (
navigate('guide', o.slug)}
style={{ cursor: 'pointer' }}
>
{o.category}
{o.title}
{o.heroText}
))}
)}
);
}
// ── REVIEW PAGE ─────────────────────────────────────────────────────────────
function Review({ navigate, ctaCopy, current }) {
return (
);
}
function ReviewHero({ ctaCopy, current: c }) {
return (
Smell like {c.celebrity} · Researched · His signature since {c.sinceYear}
{c.celebrity} wears
{c.brand} {c.fragrance}
{c.oneLiner}
{c.score.toFixed(1)}
/10
Smelebrity verdict
{c.verdict}
{c.price != null && c.price !== '' && (
{c.was != null && c.was !== '' && {c.was} }
{c.price}
on Amazon
Verified May 23, 2026
)}
);
}
function ReviewVerdict({ current: c }) {
return (
The verdict
{c.lead}
{c.story1}
);
}
function NotesPyramid({ current: c }) {
return (
The notes
What you'll actually smell.
{[
{ tier:'Top', when:'0–30 min', notes: c.notes.top },
{ tier:'Heart', when:'30 min – 4 hr', notes: c.notes.heart },
{ tier:'Base', when:'4 hr +', notes: c.notes.base },
].map((n) => (
{n.tier}
{n.when}
{n.notes.map((x) => {x} )}
))}
);
}
function Performance({ current: c }) {
const bars = [
{ k:'Longevity', v: c.perf.longevity, note: `${c.perf.longevity*1+1}–${c.perf.longevity*1+3} hours on skin` },
{ k:'Sillage', v: c.perf.sillage, note: c.perf.sillage >= 8 ? 'Strong — fills a room within an hour' : c.perf.sillage >= 6 ? 'Moderate — arm\'s length projection' : 'Light — close-skin only' },
{ k:'Projection', v: c.perf.projection, note: c.perf.projection >= 8 ? 'Arm\'s length for first 3 hours' : 'Modest, within personal space' },
{ k:'Versatility', v: c.perf.versatility, note: c.perf.versatility >= 8 ? 'Works from boardroom to bar' : 'Best in its lane — don\'t force it' },
{ k:'Value', v: c.perf.value, note: c.perf.value >= 8 ? 'Genuinely a steal at this price' : 'Pricey — but the ml/compliment ratio works' },
];
return (
The performance
How it actually behaves.
{bars.map((b) => (
{b.k}
{Array.from({length:10}).map((_,i)=> )}
{b.v}/10
{b.note}
))}
);
}
function Wearability({ current: c }) {
return (
When to wear it
The occasion calculator.
Wear it for
{c.wearFor.map((w) => (
{w.when} — {w.why}
))}
Skip it for
{c.skipFor.map((w) => (
{w.when} — {w.why}
))}
);
}
function BuyBox({ ctaCopy, current: c }) {
const sizeSuffix = c.size ? ` — ${c.size}` : '';
const listing = `${c.brand} ${c.fragrance}${sizeSuffix}`;
const retailerTag = c.amazonUrl
? 'Amazon'
: c.altRetailerUrl
? 'Official retailer'
: null;
const trustLabels = buyTrustLabels(c);
return (
Where to buy
{listing}
{retailerTag &&
{retailerTag}
}
{trustLabels && (
{trustLabels.map((label) => (
✓ {label}
))}
)}
Smelebrity is an Amazon Associate — we earn commission on these links.
);
}
function ProsCons({ current: c }) {
return (
The honest bit
What's right — and what isn't.
Pros
{c.prosCons.pros.map((p)=>{p} )}
Cons
{c.prosCons.cons.map((p)=>{p} )}
);
}
function RelatedCelebs({ navigate, ctaCopy, current }) {
const others = useMemo(
() => relatedCelebritiesFor(current.slug),
[current.slug]
);
return (
Keep reading
If you want to smell like {current.celebShort}, you'll want these too.
{others.map((r) => (
navigate('review', r.slug)}>
Smell like {r.celebShort}
{r.brand} {r.fragrance}
{r.blurb}
{r.score.toFixed(1)}
))}
);
}
// ── App shell + Tweaks ──────────────────────────────────────────────────────
function App() {
const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
const initial = useMemo(initialRoute, []);
const [route, setRoute] = useState(initial.route);
const [currentSlug, setCurrentSlug] = useState(initial.slug);
const current = useMemo(
() => CELEBRITIES.find((c) => c.slug === currentSlug) || FEATURED,
[currentSlug]
);
const currentGuide = useMemo(
() => GUIDES.find((g) => g.slug === currentSlug) || GUIDES[0],
[currentSlug]
);
const navigate = (view, slug) => {
if (view === 'home') {
window.location.href = homeUrl();
return;
}
if (view === 'guides') {
window.location.href = guidesIndexUrl();
return;
}
if (view === 'guide') {
window.location.href = guideUrl(slug || currentSlug);
return;
}
if (view === 'celebrities-index') {
window.location.href = celebIndexUrl();
return;
}
if (view === 'celebrities-a-list') {
window.location.href = celebCategoryUrl('a-list');
return;
}
if (view === 'celebrities-athletes') {
window.location.href = celebCategoryUrl('athletes');
return;
}
if (view === 'celebrities-musicians') {
window.location.href = celebCategoryUrl('musicians');
return;
}
if (view === 'about') {
window.location.href = sitePageUrl('about');
return;
}
if (view === 'research-methodology') {
window.location.href = sitePageUrl('research-methodology');
return;
}
if (view === 'amazon-disclosure') {
window.location.href = sitePageUrl('amazon-disclosure');
return;
}
if (view === 'contact') {
window.location.href = sitePageUrl('contact');
return;
}
const targetSlug = slug || currentSlug;
window.location.href = celebUrl(targetSlug);
};
const palette = PALETTES[t.palette] || PALETTES.noir;
const type = TYPE_PAIRS[t.typePair] || TYPE_PAIRS.editorial;
const density = DENSITY[t.density] || DENSITY.regular;
useEffect(() => { window.scrollTo({ top: 0, behavior: 'instant' }); }, [route, currentSlug]);
const cssVars = {
'--bg': palette.bg,
'--surface': palette.surface,
'--line': palette.line,
'--ink': palette.ink,
'--mute': palette.mute,
'--dim': palette.dim,
'--accent': palette.accent,
'--accent-deep': palette.accentDeep,
'--tint': palette.tint,
'--font-display': type.display,
'--font-body': type.body,
'--font-mono': type.mono,
'--display-weight': type.displayWeight,
'--display-italic': type.italicDisplay ? 'italic' : 'normal',
'--section-y': density.sectionY + 'px',
'--card-gap': density.cardGap + 'px',
'--block-gap': density.blockGap + 'px',
};
// Apply vars to documentElement too, so body resolves them.
useEffect(() => {
const el = document.documentElement;
Object.entries(cssVars).forEach(([k, v]) => el.style.setProperty(k, String(v)));
});
return (
{route === 'home' && (
)}
{route === 'review' && (
)}
{route === 'guides' && (
)}
{route === 'guide' && currentGuide && (
)}
{route === 'celebrities-index' && (
)}
{route === 'celebrities-a-list' && (
)}
{route === 'celebrities-athletes' && (
)}
{route === 'celebrities-musicians' && (
)}
{route === 'about' &&
}
{route === 'research-methodology' && (
)}
{route === 'amazon-disclosure' && (
)}
{route === 'contact' &&
}
{ENABLE_TWEAKS && (
setTweak('palette', v)} />
setTweak('typePair', v)} />
setTweak('heroLayout', v)} />
setTweak('density', v)} />
setTweak('ctaStyle', v)} />
setTweak('ctaCopy', v)} />
navigate('home')} secondary={route!=='home'} />
navigate('review', currentSlug)} secondary={route!=='review'} />
({ value: c.slug, label: c.celebrity }))}
onChange={(v)=>navigate('review', v)} />
)}
);
}
function PaletteChips({ current, onChange }) {
const opts = [
{ id:'noir', label:'Noir', bg:'#0b0a08', accent:'#d6b66c' },
{ id:'cognac', label:'Cognac', bg:'#1a120b', accent:'#dc965a' },
{ id:'onyx', label:'Onyx', bg:'#0a0d12', accent:'#b8c7d9' },
];
return (
{opts.map((o) => (
onChange(o.id)} title={o.label}>
{o.label}
))}
);
}
ReactDOM.createRoot(document.getElementById('root')).render( );