Commit 0ea37b6
feat(mdk-checkout): rebrand checkout UI to match DESIGN.md (MDK-891) (#792)
* feat(mdk-checkout): rebrand checkout UI to match DESIGN.md (MDK-891)
Restyles the hosted checkout component (all states: unconfirmed,
pending payment, payment received, expired, error) to match the
moneydevkit.com landing-page brand defined in DESIGN.md: dark
teal-tinted Terminal Field background, square corners, italic
Source Serif display headings, Geist Mono uppercase labels with
prompt-mark prefixes, teal-edged QR frame, and ghost-style buttons
with leading "›".
Adds a /preview route in mdk-nextjs-demo that renders each
checkout state with mocked Checkout data so the rebrand can be
QA'd without MDK_ACCESS_TOKEN / MDK_MNEMONIC. Demo deps switched
to workspace:* and Source Serif 4 / Geist / Geist Mono are loaded
via next/font.
Inner state components (UnconfirmedCheckout, PendingPaymentCheckout,
PaymentReceivedCheckout, ExpiredCheckout) and the CheckoutLayout
chrome are exported from @moneydevkit/core/client so the preview
harness can render them directly.
* feat(mdk-checkout): show fiat headline for USD-priced checkouts (MDK-891)
PendingPaymentCheckout now reads checkout.currency: USD-priced
checkouts get a "$5.00"-style headline with the sats amount tucked
into View Details, while SAT-priced checkouts keep the sats headline
and gain a faint "≈ $5.00" subtitle.
Also hard-codes USD when formatting invoice.fiatAmount in View
Details (Intl.NumberFormat doesn't accept "SAT"), matching the
convention already used by PaymentReceivedCheckout.
Adds a "Pending QR (SAT)" tab to the demo preview route so both
modes can be verified side-by-side.
* feat(mdk-checkout): adopt BIP-177 ₿ prefix for sat amounts (MDK-891)
Display-only change. All user-facing sat values render as "₿6,487"
instead of "6,487 sats" -- the symbol hugs the number the same way
"$" hugs a USD amount. View Details labels become "Amount (₿)" and
the UNCONFIRMED state's custom-amount input switches its SAT marker
from a trailing "sats" suffix to a leading "₿" prefix to mirror the
USD "$" prefix.
No backend, API contract, or stored data changes -- formatSats and
the underlying sat values are untouched.
* chore(mdk-checkout): drop › prefix from View Details trigger (MDK-891)
* feat(mdk-checkout): inline fiat conversion next to ₿ headline (MDK-891)
For SAT-priced checkouts, render the fiat conversion on the same
baseline as the ₿ headline -- same italic Source Serif, same size,
weight 300, faint color, 1.5rem gap -- instead of stacking it
underneath as a ≈$x.xx mono subtitle.
Also tunes the demo preview mock so SAT-priced uses a round ₿6,000
with the odd $4.62 conversion that round sat amount actually
implies, mirroring the existing USD-priced mock ($5.00 / odd sats).
Loads Source Serif 4 weight 300 in next/font for the lighter fiat
treatment.
* feat(mdk-checkout): swap "Powered by moneydevkit" wordmark for SVG logo (MDK-891)
Replaces the underlined "moneydevkit" text in the checkout footer
with an inlined SVG of the moneydevkit wordmark. The SVG uses
currentColor on all fills (and the rotated half-circle gradient
stops), so it inherits the parent link's color and picks up the
existing .mdk-link hover-to-teal transition.
"Powered by" is now sentence-cased and rendered in Geist Sans
(--mdk-font-body) at 11px in mdk-faint, instead of mono uppercase
via the mdk-label class. Logo height is 1.25em of the surrounding
text. Applied to both CheckoutLayout and CheckoutError footers.
* feat(mdk-checkout): split logo hover so wordmark stays white (MDK-891)
Tags the symbol and wordmark groups with mdk-logo-symbol and
mdk-logo-wordmark classes. The symbol keeps inheriting the parent
link's currentColor (muted → teal on hover); the wordmark is pinned
to mdk-fg only while the link is hovered, so the moneydevkit text
reads in Signal White next to a teal symbol instead of the whole
logo turning teal.
* refactor(mdk-checkout): move title + description inside the panel (MDK-891)
Title and description now live inside the same mdk-panel as the
amount, QR, and View Details, rather than floating above it. Title
size dropped to clamp(1.15rem, 2.2vw, 1.45rem) so it doesn't tower
over the amount.
Demo preview mocks tweaked: title is now "Tip for Cindy" (no
em-dash amount suffix, since the amount renders elsewhere) and the
description is "Thanks for supporting my work" -- both USD and SAT
tabs use the same strings.
* feat(mdk-checkout): style QR with MDK teal gradient via qr-code-styling (MDK-891)
Swaps the qrcode.react SVG renderer for @liquid-js/qr-code-styling
in PendingPaymentCheckout. New StyledQRCode wrapper mounts the
library's QR into a sized div via useEffect and updates on prop
change.
Visual treatment:
- 240×240 (down from 320)
- small-square dot shape
- 45° linear gradient from Phosphor Teal → Deep Signal Teal on
dots, corner squares, and corner dots (sourced from DESIGN.md,
expressed as oklch)
- Black QR background to match the surrounding mdk-qr-frame
- Frame border now Phosphor Teal at 25% alpha with a 2px corner
radius; frame background also dropped to black so the QR has no
white halo
Layout: outer CheckoutLayout/CheckoutError wrapper changed from a
fixed 380px width to `width: 100%, max-width: 327px` so the panel
fits a 375px iPhone SE viewport with 24px gutters on each side and
scales down on narrower viewports.
* feat(mdk-checkout): add Cash App + Strike pay-with buttons (MDK-891)
Below the invoice copy field, the pending-payment screen now offers
two deep-link launchers:
- Pay with Cash App -> https://cash.app/launch/lightning/<invoice>
- Pay with Strike -> strike:<invoice>
Icon glyphs (Cash App "$" mark, Strike lightning mark) inlined as
React components in WalletIcons.tsx, extracted from the Money Dev
Kit Figma design system. Both use currentColor so the parent button
text color drives the fill.
Brand buttons share a new .mdk-wallet-button base (Geist Sans 14px
medium, sentence case, 2px radius, subtle hover lift) with two
brand modifiers: Cash App green (#00E013) bg with white text, and
Strike black bg with the MDK hard-line border + white text.
In preview mode the buttons resolve to a placeholder invoice string
so demo clicks won't try to launch real wallets with a bad payload.
* feat(mdk-checkout): chunked teal/gray invoice display (MDK-891)
Replaces the truncated single-line invoice string in the copy field
with a five-segment display: first 4 chars in teal, next 4 muted,
a four-period divider, then the final 8 chars split into two more
4-char chunks (muted + teal). The trailing chunks are sliced from
the end (.slice(-8, -4) and .slice(-4)) so each is always exactly
four characters regardless of total invoice length.
The <code> element is now a flexbox with justify-content:
space-between so the five segments distribute evenly across the
copy field instead of clustering on the left. The four-period
divider is rendered as four individual spans inside an inline-flex
container with a 0.25em gap, giving consistent visual spacing
between the dots that doesn't depend on font kerning. Falls back
to the raw string for any invoice shorter than 16 characters
(real Lightning invoices are always well over that).
* refactor(mdk-checkout): move View Details below pay-with buttons (MDK-891)
The View Details collapsible (line items, fiat/sat conversion,
exchange rate, expires-in) used to sit between the amount headline
and the QR code. It now lives beneath the Pay with Strike button,
so the primary flow above the fold reads amount -> QR -> invoice
copy -> pay-with buttons, and the breakdown stays one tap away
without breaking up the scan-and-pay path.
* fix(mdk-checkout): align QR frame width with sibling controls (MDK-891)
The QR frame was shrink-wrapping the 240px QR, ending up narrower
than the copy field and pay-with buttons that use w-full inside the
same panel. The frame now stretches to w-full and StyledQRCode's
wrapper is width:100% / aspect-ratio 1/1 so the QR scales up to
fill it. The SVG is still rendered at the library's native 240px
resolution and CSS scales the vector to fit, which keeps the QR
crisp and scannable while making the left/right edges line up
across the QR frame, invoice copy field, and both pay-with buttons.
* feat(mdk-checkout): flash QR on copy tap (MDK-891)
Adds a brief white flash overlay on the QR frame each time the
invoice is copied to clipboard. A copyFlashKey state increments on
every successful copy and is used as the React key on the .mdk-qr-flash
overlay, so the element re-mounts and the 520ms ease-out keyframe
(peak 45% opacity at ~18%, fade back to 0) re-fires on every
consecutive tap without waiting for the previous flash to clear.
* style(mdk-checkout): tighten checkout rhythm and shrink details affordance (MDK-891)
A handful of small visual tunings on the pending payment screen:
- Invoice copy field now sits below the Pay with Strike button
instead of above Cash App. Its padding switches from p-3 to a
flat 0.75rem / 1rem so it renders at the same height as the
pay-with buttons, and the elements align edge-to-edge top to
bottom.
- "View Details" trigger text drops from 13px to 11px and its
ChevronDown caret shrinks from w-3/h-3 to w-2.5/h-2.5, with the
gap between them tightened from gap-2 to gap-1.5 so the smaller
pieces stay visually paired.
- Vertical rhythm around the amount headline tightens: the
title/description block (CheckoutLayout) and the amount wrapper
(PendingPaymentCheckout) both drop from mb-6 to mb-3, halving
the gap above and below the amount.
- Checkout description copy goes from font-weight 400 to 300, a
hair lighter so the title carries the visual weight.
* feat(mdk-checkout): add light-mode theme variant (MDK-891)
Adds a light-mode variant to the checkout component, controlled by
a new `theme` prop on MdkCheckoutProvider and the public Checkout
component. The provider now exposes MdkTheme ('dark' | 'light'),
sets data-theme on its .mdk-checkout wrapper, and ships a
useMdkTheme hook for child components.
CSS tokens get a [data-theme="light"] override block in
mdk-styles.css that flips neutrals (bg, fg, muted, faint, line)
toward a teal-tinted paper palette and drops the teal hues from
oklch(0.88 / 0.74) down to oklch(0.55 / 0.42) so the brand color
keeps AA contrast on white. The QR frame's hardcoded #000
background is now a --mdk-qr-bg token; teal borders use color-mix
so they re-tint per theme.
StyledQRCode is theme-aware via useMdkTheme: dark mode keeps the
bright Phosphor->Deep teal gradient on black; light mode swaps to
a darker teal gradient on white, applied through the library's
.update() so the QR re-renders cleanly on toggle.
Glow effects (the teal text-shadow on the title/amount/"Payment
received" headlines, and the soft 25%-alpha QR frame border) read
as a luminous glow on the dark canvas but as a smudgy drop-shadow
against white. In light mode the text-shadow is removed entirely
and the QR frame border alpha bumps from 25% to 70% so it lands
as a crisp teal hairline.
The demo preview page gains a Dark / Light toggle row underneath
the state tabs that swaps the MdkCheckoutProvider's theme prop in
state, so reviewers can flip between the two variants on the same
URL.
* feat(mdk-checkout): polish Received, Unconfirmed, Expired states (MDK-891)
Tightens copy and microtypography across the non-pending checkout
states:
Unconfirmed
- Drop the leading "›" from the customer-data form labels and
collapse the space before the required-asterisk, so labels read
"EMAIL*" / "NAME*" instead of "› EMAIL *".
Received
- Drop the leading "›" from the "Thank you for your business"
footer, bump its line-height to 1.6, and bind "your" + "business"
with a non-breaking space so they wrap together.
- Strip trailing colons from Amount and Checkout ID labels.
- Consolidate the two separate "Amount Fiat" + "Amount (₿)" rows
into a single "Amount" row that places the sats amount (muted)
to the left of the USD amount (fg), baseline-aligned.
- Replace the long full-id span with a chunked checkout ID: first
4 chars + four-period divider + last 4 chars at 11px in
mdk-text-muted, preceded by a 14px white copy-to-clipboard icon
button that flips teal on copy.
Expired
- Drop the "This checkout session has expired." sentence to
font-weight 300 so the headline restart copy carries more visual
weight than the explanation.
* style(mdk-checkout): drop status-icon frame border to 25% alpha (MDK-891)
The teal-on-Received and amber-on-Expired status icon containers
had full-opacity borders that competed with the icon glyph for
attention. Switching both border-colors to color-mix(... 25%,
transparent) leaves a soft halo so the icon inside reads as the
focal element. Picks up both themes automatically via the existing
--mdk-teal and --mdk-amber tokens.
* chore(mdk-nextjs-demo): redesign preview chrome with sticky control bar (MDK-891)
The preview page now puts the checkout component at center stage:
- Controls move from the top of the page to a sticky full-width
bar at the bottom, backed by var(--mdk-bg-2) with a
var(--mdk-line-soft) top divider so it reads as a separate
surface from the simulated host page.
- Buttons in the bar are roughly half their previous height
(0.3rem / 0.65rem padding, 11px Geist Mono uppercase) and group
under tiny 10px faint labels (STATE / THEME / BG), separated by
thin vertical line dividers.
- A new BG cluster lets reviewers preview the checkout against
three host-page surfaces, theme-scoped so dark themes get three
dark surfaces and light themes get three light surfaces. The
selected slot id (1 / 2 / 3) is preserved when the theme toggles
so the same slot can be compared across themes.
Dark surface slots:
1. MDK Terminal Field (default teal-tinted dark)
2. Purple -> red 135deg gradient (saturated brand)
3. Deep navy (developer-tool brand pages)
Light surface slots:
1. MDK Paper (default teal-tinted near-white)
2. White -> cyan 135deg gradient (soft consumer-app brand)
3. Warm cream (publication / content-app surfaces)
The control bar itself keeps using var(--mdk-bg-2) regardless of
the BG override so it remains a stable preview-tool affordance and
doesn't blend into the simulated host surface.
* refactor(mdk-checkout): move Powered by footer inside the panel (MDK-891)
"Powered by [moneydevkit logo]" used to sit in its own div under
the mdk-panel container. It now lives inside the panel, after
{children} with mt-4 breathing room. Applied to both
CheckoutLayout and CheckoutError so the chrome stays consistent.
* feat(mdk-checkout): self-host brand fonts via Fontsource (MDK-891)
Bundles the checkout's brand typography directly into the SDK so a
consumer dropping in <Checkout /> gets the correct fonts without
having to wire up next/font (or anything else) themselves.
Adds three runtime deps to @moneydevkit/core:
- @fontsource-variable/geist
- @fontsource-variable/geist-mono
- @fontsource/source-serif-4 (italic 300/500/700)
mdk-styles.css now @imports those packages at the top so consumer
bundlers (Next.js / Vite / webpack) resolve the woff2 files from
node_modules. The font-family fallback strings in --mdk-font-body
and --mdk-font-mono switch from "Geist Sans" / "Geist Mono" to
the Fontsource family names "Geist Variable" / "Geist Mono
Variable" so the bundled fonts actually take effect.
Consumers who prefer to load fonts themselves (e.g. via next/font
for SSR optimization) can still override by setting
--font-source-serif / --font-geist-sans / --font-geist-mono on a
parent element -- the var() lookups are unchanged so user-set
variables win over the bundled fonts.
The demo's app/layout.tsx drops its Source Serif / Geist /
Geist Mono next/font loaders since the SDK now ships them
itself; Space Grotesk stays for the demo's marketing pages.
* fix(e2e): update selectors for rebranded checkout component
Rebrand renamed post-payment text to "Payment received" and dropped the
"Checkout ID:" label, breaking the workspace e2e scripts. Accept both old
and new payment-confirmed phrasing, and read the checkout id from the URL
instead of scraping the success screen.
Also drop the demo /preview page when building against the legacy pinned
SDK - it imports rebrand-era exports (CheckoutLayout, MdkCheckoutProvider,
...) absent from @moneydevkit/core@0.15.0, which broke the legacy build.
* revert(mdk-nextjs-demo): restore demo to published SDK pins
The rebrand lives in @moneydevkit/core, not the demo. The demo's switch to
workspace:* and the new /preview QA harness broke vercel-deploy: Vercel runs
pnpm install on the demo folder standalone, where workspace:* cannot resolve,
and /preview imports rebrand-era /client exports absent from any published
SDK. Revert the demo to staging's 0.10.0 pins and drop /preview. e2e still
exercises the rebrand SDK via its own npm pkg set workspace:* override.
---------
Co-authored-by: Martin Saposnic <martinsaposnic@gmail.com>1 parent be18dbc commit 0ea37b6
13 files changed
Lines changed: 1461 additions & 492 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
54 | 57 | | |
| 58 | + | |
55 | 59 | | |
56 | 60 | | |
57 | 61 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
2 | 6 | | |
3 | 7 | | |
4 | 8 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
| 8 | + | |
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| 19 | + | |
18 | 20 | | |
19 | 21 | | |
20 | | - | |
| 22 | + | |
21 | 23 | | |
22 | 24 | | |
23 | 25 | | |
24 | 26 | | |
25 | | - | |
| 27 | + | |
26 | 28 | | |
27 | 29 | | |
28 | 30 | | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | | - | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
41 | | - | |
42 | | - | |
43 | | - | |
44 | | - | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | | - | |
49 | | - | |
50 | | - | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
51 | 66 | | |
52 | | - | |
53 | | - | |
54 | | - | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
55 | 80 | | |
56 | 81 | | |
57 | 82 | | |
| |||
64 | 89 | | |
65 | 90 | | |
66 | 91 | | |
67 | | - | |
| 92 | + | |
68 | 93 | | |
69 | | - | |
70 | | - | |
| 94 | + | |
| 95 | + | |
71 | 96 | | |
72 | | - | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
73 | 101 | | |
74 | | - | |
| 102 | + | |
75 | 103 | | |
76 | 104 | | |
77 | 105 | | |
| |||
84 | 112 | | |
85 | 113 | | |
86 | 114 | | |
87 | | - | |
88 | | - | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
89 | 119 | | |
90 | | - | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
95 | | - | |
96 | | - | |
97 | | - | |
98 | | - | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
99 | 132 | | |
100 | | - | |
101 | | - | |
102 | | - | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
103 | 146 | | |
104 | 147 | | |
105 | 148 | | |
| |||
263 | 306 | | |
264 | 307 | | |
265 | 308 | | |
266 | | - | |
267 | | - | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
268 | 314 | | |
269 | 315 | | |
270 | 316 | | |
271 | 317 | | |
272 | 318 | | |
273 | | - | |
| 319 | + | |
274 | 320 | | |
275 | 321 | | |
276 | 322 | | |
| |||
292 | 338 | | |
293 | 339 | | |
294 | 340 | | |
295 | | - | |
296 | | - | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
297 | 346 | | |
298 | 347 | | |
299 | 348 | | |
| |||
322 | 371 | | |
323 | 372 | | |
324 | 373 | | |
325 | | - | |
| 374 | + | |
326 | 375 | | |
327 | | - | |
| 376 | + | |
328 | 377 | | |
329 | 378 | | |
330 | 379 | | |
| |||
0 commit comments