payments/credit-card.ex
Payment card
A generic payment card with a chip, a masked number, the holder's name and the expiry.
# in the module that renders the template
use EHVisuals
<div class="h-96 rounded-xl border border-border">
<.payments_credit_card animated />
</div>
Props
| Prop | Type | Default | What it does |
|---|---|---|---|
kind |
string | "Company card" |
|
issuer |
string | "Northwind" |
The name on the top left. Up to 22 characters. |
holder |
string | "Marta Nowak" |
Up to 20 characters. |
last4 |
string | "4471" |
The four digits left readable. |
expiry |
string | "08/29" |
|
mark |
boolean | true |
Shows the EmpoweredHouse mark where a card brand would stand. |
Frame props, shared by every composition
| Prop | Type | Default | What it does |
|---|---|---|---|
animated |
boolean | false |
Turns motion on. Without it the composition renders in its final, still state. |
trigger |
"mount" | "in-view" | "in-view-repeat" | "in-view" |
When the entrance plays: on page load, once when scrolled into view, or every time it comes back into view. |
hover |
boolean | false |
Enables the hover micro-interactions the composition supports. |
glow |
boolean | true |
The warm incandescent halo behind the composition. |
fade_out |
boolean | false |
Fades the bottom edge into the surface underneath. |
isometric |
boolean | false |
Tilts the composition into the isometric plane of the platform stack. |
theme |
"dark" | "light" | "dark" |
`dark` for the site canvas, `light` for the cream reversed surface. |
class |
string | nil |
Extra classes for the frame. |
rest |
global | — |
Any other HTML attribute, set on the frame. |
Source
Two files. Copy them into your app if you would rather own the code than depend on the library.
lib/eh_visuals/payments/credit-card.ex
defmodule EHVisuals.Payments.CreditCard do
@moduledoc """
A payment card: a chip, a masked number, the holder and the expiry. It
carries no card brand; the EmpoweredHouse mark may stand where one would.
"""
use EHVisuals.Composition,
name: "payments/credit-card",
title: "Payment card",
description:
"A generic payment card with a chip, a masked number, the holder's name and the expiry."
attr(:kind, :string, default: "Company card")
attr(:issuer, :string,
default: "Northwind",
doc: "The name on the top left. Up to 22 characters."
)
attr(:holder, :string, default: "Marta Nowak", doc: "Up to 20 characters.")
attr(:last4, :string, default: "4471", doc: "The four digits left readable.")
attr(:expiry, :string, default: "08/29")
attr(:mark, :boolean,
default: true,
doc: "Shows the EmpoweredHouse mark where a card brand would stand."
)
attr(:label, :string, default: "A payment card for Marta Nowak ending in 4471")
frame_attrs()
@spec payments_credit_card(map()) :: Phoenix.LiveView.Rendered.t()
def payments_credit_card(assigns) do
dots =
for group <- 0..2, dot <- 0..3 do
%{cx: 27 + group * 56 + dot * 10, stagger: 5 + group * 2}
end
assigns = assign(assigns, :dots, dots)
~H"""
<.frame name="payments/credit-card" label={@label} {frame_opts(assigns)}>
<svg viewBox="0 0 340 214">
<g class="ehv-h-lift">
<rect
class="ehv-payments-credit-card__body ehv-a-rise"
x="0.5"
y="0.5"
width="339"
height="213"
rx="16"
/>
<g class="ehv-a-fade ehv-i-1">
<text class="ehv-mono" x="24" y="33" font-size="8.5">{String.upcase(@kind)}</text>
<text class="ehv-t-strong" x="24" y="52" font-size="14">{@issuer}</text>
</g>
<g :if={@mark} class="ehv-a-pop ehv-i-2">
<.mark x="279" y="9" size="50" />
</g>
<g class="ehv-a-pop ehv-i-3">
<rect
class="ehv-payments-credit-card__chip"
x="24.5"
y="82.5"
width="42"
height="31"
rx="7"
/>
<path class="ehv-line" d="M38.5 83 V113 M52.5 83 V113 M25 98 H38.5 M52.5 98 H66" />
</g>
<path
class="ehv-line-ink ehv-round ehv-a-fade ehv-i-4"
d="M80 92 a8.5 8.5 0 0 1 0 12 M85.5 87.5 a14.5 14.5 0 0 1 0 21 M91 83 a20.5 20.5 0 0 1 0 30"
/>
<g :for={dot <- @dots} class={"ehv-a-pop ehv-i-#{dot.stagger}"}>
<circle class="ehv-fill-2" cx={dot.cx} cy="149" r="2.6" />
</g>
<text class="ehv-code ehv-a-fade ehv-i-11" x="192" y="155" font-size="17">{@last4}</text>
<g class="ehv-a-fade ehv-i-12">
<text class="ehv-mono ehv-t-4" x="24" y="180" font-size="7">CARDHOLDER</text>
<text x="24" y="196" font-size="12.5">{@holder}</text>
<text class="ehv-mono ehv-t-4" x="192" y="180" font-size="7">VALID THRU</text>
<text class="ehv-code" x="192" y="196" font-size="12">{@expiry}</text>
</g>
</g>
</svg>
</.frame>
"""
end
end
assets/css/payments/credit-card.css
/* payments/credit-card */
.ehv-payments-credit-card { --ehv-max-w: 370px; }
.ehv-payments-credit-card__body { fill: var(--ehv-surface-2); stroke: var(--ehv-border-strong); stroke-width: 1; }
.ehv-payments-credit-card__chip { fill: var(--ehv-surface-3); stroke: var(--ehv-ink-3); stroke-width: 1; }
.ehv--hover .ehv-payments-credit-card__chip { transition: stroke 200ms var(--ehv-ease); }
.ehv--hover:hover .ehv-payments-credit-card__chip { stroke: var(--ehv-lime); }