afe36fd347
Claude Design export for SD-0001 (login + create-storefront surfaces): wf-*/hf-* screens, design-system bundle, offline preview. First artifact in the ui/designs/ collection (ecomm#8). Also ignore .DS_Store. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
118 lines
6.1 KiB
React
118 lines
6.1 KiB
React
// wf-storefront.jsx — Screen 3: Create storefront (PUC-4/5/7). A/B + states.
|
|
const { Screen: FScreen, Wordmark: FWordmark, TopBar: FTopBar, AccountChip: FAccountChip,
|
|
Field: FField, Banner: FBanner, AuthCard: FAuthCard, StateBlock: FStateBlock,
|
|
WF_T: FT, WF_DS: FDS } = window;
|
|
const { Button: FButton, Soul: FSoul, Eyebrow: FEyebrow } = FDS;
|
|
|
|
function CreateForm({ s = {} }) {
|
|
return (
|
|
<>
|
|
<div>
|
|
<FEyebrow style={{ margin: '0 0 12px' }}>One storefront, fully yours</FEyebrow>
|
|
<h1 style={{ fontFamily: FT.disp, fontWeight: 700, letterSpacing: '-0.015em', fontSize: 26, color: FT.star, margin: '0 0 8px', lineHeight: 1.1 }}>Create your storefront</h1>
|
|
<p style={{ fontFamily: FT.body, fontSize: 14.5, lineHeight: 1.5, color: FT.soft, margin: 0 }}>
|
|
This is the one thing to do right now. Nothing here costs anything or commits you to anything.
|
|
</p>
|
|
</div>
|
|
{s.alreadyOwns && <FBanner title="Your account already has its storefront">
|
|
ecomm is one storefront per account today. <a href="#" style={{ color: FT.lilac, textDecoration: 'none' }}>Go to your admin →</a>
|
|
</FBanner>}
|
|
<FField label="Storefront name" optional
|
|
placeholder="e.g. Studio Fern" value={s.name}
|
|
helper="You can leave this blank — we'll pick a placeholder name you can change later." />
|
|
{s.blankPreview && (
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: 9, marginTop: -6, fontFamily: FT.body, fontSize: 13, color: FT.mute }}>
|
|
<span aria-hidden="true" style={{ color: FT.lilac }}>◇</span>
|
|
Saves as <span style={{ color: FT.soft, fontStyle: 'italic', fontFamily: FT.body }}>“mara's storefront”</span> — change it any time.
|
|
</div>
|
|
)}
|
|
<FButton variant="primary" href="#" disabled={s.creating}>
|
|
{s.creating ? 'Creating…' : 'Create storefront'}
|
|
</FButton>
|
|
</>
|
|
);
|
|
}
|
|
|
|
// ── Direction A — centered card ────────────────────────────────────────────
|
|
function CreateA({ device = 'desktop', s = {} }) {
|
|
const desktop = device === 'desktop';
|
|
return (
|
|
<FScreen starfield>
|
|
<FTopBar pad={desktop ? '0 32px' : '0 18px'} left={<FWordmark size={desktop ? 24 : 21} />}
|
|
right={desktop ? <FAccountChip /> : <SignOutMini />} />
|
|
<div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: desktop ? 32 : 18 }}>
|
|
<FAuthCard width={desktop ? 440 : '100%'}><CreateForm s={s} /></FAuthCard>
|
|
</div>
|
|
</FScreen>
|
|
);
|
|
}
|
|
|
|
// ── Direction B — split (the frame begins to form) ─────────────────────────
|
|
function CreateB({ device = 'desktop', s = {} }) {
|
|
const desktop = device === 'desktop';
|
|
if (!desktop) {
|
|
return (
|
|
<FScreen>
|
|
<div style={{ background: `${window.WF_STARFIELD}, var(--wv-night)`, borderBottom: `1px solid ${FT.hair}`, padding: '20px 22px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
|
<FWordmark size={21} />
|
|
<SignOutMini />
|
|
</div>
|
|
<div style={{ flex: 1, padding: '24px 22px', display: 'flex', flexDirection: 'column', gap: 20, justifyContent: 'center' }}>
|
|
<CreateForm s={s} />
|
|
</div>
|
|
</FScreen>
|
|
);
|
|
}
|
|
return (
|
|
<FScreen style={{ flexDirection: 'row' }}>
|
|
<aside style={{ flex: '0 0 44%', background: `${window.WF_STARFIELD}, var(--wv-night)`, borderRight: `1px solid ${FT.hair}`, padding: '40px 46px', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', overflow: 'hidden' }}>
|
|
<FWordmark size={26} />
|
|
<div style={{ maxWidth: 360 }}>
|
|
<FSoul size="lg" tone="gold" as="p">Build the<br />dictionary first.</FSoul>
|
|
<p style={{ fontFamily: FT.body, fontSize: 14.5, lineHeight: 1.6, color: FT.mute, marginTop: 20 }}>
|
|
One storefront, claimed by you. The frame you see now is the one your catalog, orders and settings will live in.
|
|
</p>
|
|
</div>
|
|
<FAccountChip />
|
|
</aside>
|
|
<div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '0 64px' }}>
|
|
<div style={{ width: '100%', maxWidth: 420, display: 'flex', flexDirection: 'column', gap: 20 }}>
|
|
<CreateForm s={s} />
|
|
</div>
|
|
</div>
|
|
</FScreen>
|
|
);
|
|
}
|
|
|
|
function SignOutMini() {
|
|
return <button style={{ fontFamily: FT.disp, fontWeight: 500, fontSize: 13, color: FT.star, background: 'transparent', border: 'none', cursor: 'pointer', padding: 0 }}>Sign out</button>;
|
|
}
|
|
|
|
// ── States stack ───────────────────────────────────────────────────────────
|
|
function CreateStates() {
|
|
return (
|
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 22 }}>
|
|
<FStateBlock label="Blank name" note="allowed → default generated">
|
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
|
|
<FField label="Storefront name" optional placeholder="e.g. Studio Fern"
|
|
helper="Leave blank and we'll name it for you." />
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: 9, fontFamily: FT.body, fontSize: 13, color: FT.mute }}>
|
|
<span aria-hidden="true" style={{ color: FT.lilac }}>◇</span>
|
|
Saves as <span style={{ color: FT.soft, fontStyle: 'italic' }}>“mara's storefront”</span>
|
|
</div>
|
|
</div>
|
|
</FStateBlock>
|
|
<FStateBlock label="Creating" note="button busy">
|
|
<FButton variant="primary" href="#" disabled>Creating…</FButton>
|
|
</FStateBlock>
|
|
<FStateBlock label="Already owns one" note="409 · defense in depth (PUC-7)">
|
|
<FBanner title="Your account already has its storefront">
|
|
ecomm is one storefront per account today. <a href="#" style={{ color: FT.lilac, textDecoration: 'none' }}>Go to your admin →</a>
|
|
</FBanner>
|
|
</FStateBlock>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
Object.assign(window, { CreateA, CreateB, CreateStates });
|