Ticket Pricing
介绍
像一张门票的买断价格卡:左边是产品规格,右边是撕线后的票根,上下各有一个半圆缺口。切换一台 / 两台授权,原价、现价和按钮金额一起变化。
拆自整页模板 Nook Mac 应用官网,可以单独使用,也能和同一模板拆出的其他组件拼回整页。
纯 HTML、CSS 与少量原生 JS,没有框架依赖。复制提示词交给 Claude Code、Cursor、Trae 或 Codex,模型会把 Ticket Pricing 加进你的项目并换成你的配色。
适用场景
SaaS 定价页、升级弹窗、方案对比和按月 / 按年切换。
安装
订阅 Builder 后,用 8pt CLI 装进项目,或在已接入 8pt MCP 的编辑器里直接调用。
$ npm i -g @8pt-dev/cli && 8pt add ticket-pricing
mcp › 使用 8pt MCP 调用 get_component("ticket-pricing")
代码
Ticket Pricing 的源码,动效只用 transform 与 opacity,并尊重减少动态效果设置。
<div class="x-tkt">
<div class="x-tkt__in" style="width:640px;height:300px">
<div class="x-tkt__pass">
<div class="x-tkt__main">
<span class="x-tkt__logo"><svg viewBox="0 0 64 64" aria-hidden="true"><rect x="2" y="2" width="60" height="60" rx="15" fill="#3D5BF0"/><path d="M14 23a4 4 0 0 1 4-4h9.5l4 4H46a4 4 0 0 1 4 4v14H14z" fill="#fff" fill-opacity=".42"/><rect x="12" y="28" width="40" height="21" rx="5.5" fill="#fff"/><rect x="19" y="35" width="15" height="3.2" rx="1.6" fill="#3D5BF0"/></svg>Nook<em>· 一次买断</em></span>
<h3>Mac 上的原生文件管理器。</h3>
<dl><dt>付款</dt><dd>一次付清,没有订阅</dd><dt>授权</dt><dd class="x-tkt__lic">一台 Mac</dd><dt>系统</dt><dd>macOS 15 或更新版本</dd><dt>更新</dt><dd>1.x 版本内持续更新</dd></dl>
<p class="x-tkt__ft">✓ 本页介绍的全部功能</p>
</div>
<div class="x-tkt__stub">
<div class="x-tkt__tog" role="radiogroup" aria-label="授权数量"><button type="button" role="radio" aria-checked="true" data-p="one">一台 Mac</button><button type="button" role="radio" aria-checked="false" data-p="two" tabindex="-1">两台 Mac</button></div>
<p class="x-tkt__was"><s>¥148</s><b>首发 6 折</b></p>
….x-tkt{position:relative;flex:none}
.x-tkt__in{position:absolute;left:0;top:0;transform-origin:0 0;filter:drop-shadow(0 24px 40px rgba(20,40,140,.22));font-family:var(--d-font,system-ui,sans-serif);color:var(--d-fg,#fff)}
.x-tkt__pass{display:grid;grid-template-columns:minmax(0,1fr) 240px;height:100%;border-radius:26px;
-webkit-mask:radial-gradient(circle 14px at calc(100% - 240px) 0,transparent 13.5px,#000 14px) top/100% 51% no-repeat,radial-gradient(circle 14px at calc(100% - 240px) 100%,transparent 13.5px,#000 14px) bottom/100% 51% no-repeat;
mask:radial-gradient(circle 14px at calc(100% - 240px) 0,transparent 13.5px,#000 14px) top/100% 51% no-repeat,radial-gradient(circle 14px at calc(100% - 240px) 100%,transparent 13.5px,#000 14px) bottom/100% 51% no-repeat}
.x-tkt__main{display:flex;flex-direction:column;gap:12px;padding:28px 30px;border-radius:26px 0 0 26px;background:var(--d-card,#14141c);box-shadow:inset 0 0 0 1px var(--d-line,rgba(255,255,255,.08))}
.x-tkt__logo{display:flex;align-items:center;gap:8px;font-weight:700;font-size:15px}.x-tkt__logo svg{width:24px;height:24px}.x-tkt__logo em{font-style:normal;font-weight:500;font-size:12.5px;color:var(--d-muted,#9b9ba8)}
.x-tkt__main h3{margin:0;font-size:22px;letter-spacing:-.02em;line-height:1.2}
.x-tkt__main dl{display:grid;grid-template-columns:60px 1fr;gap:7px 12px;margin:0;font-size:13.5px}.x-tkt__main dt{color:var(--d-muted,#9b9ba8)}.x-tkt__main dd{margin:0}
.x-tkt__ft{margin:auto 0 0;font-size:13px;font-weight:600;color:var(--d-accent,#4D74FF)}
.x-tkt__stub{position:relative;display:flex;flex-direction:column;justify-content:center;gap:12px;padding:24px 22px;border-radius:0 26px 26px 0;text-align:center;background:linear-gradient(170deg,color-mix(in srgb,var(--d-accent,#4D74FF) 14%,var(--d-card,#14141c)),var(--d-card,#14141c));box-shadow:inset 0 0 0 1px var(--d-line,rgba(255,255,255,.08))}
.x-tkt__stub::before{content:"";position:absolute;left:0;top:22px;bottom:22px;border-left:2px dashed var(--d-line,rgba(255,255,255,.14))}
…const init = (root) => {
const fit = (box, W, H) => {
const inner = box.firstElementChild;
const run = () => {
const cs = getComputedStyle(root);
const aw = root.clientWidth - parseFloat(cs.paddingLeft) - parseFloat(cs.paddingRight);
const ah = root.clientHeight - parseFloat(cs.paddingTop) - parseFloat(cs.paddingBottom);
if (aw <= 0 || ah <= 0) return;
const s = Math.max(0.2, Math.min(aw / W, ah / H, 1));
box.style.width = W * s + 'px'; box.style.height = H * s + 'px'; inner.style.transform = `scale(${s})`;
};
const ro = new ResizeObserver(run); ro.observe(root); run();
…订阅 Builder 查看完整源码。查看价格