Kanban Column
介绍
两列看板,点击卡片把它移到另一列。用 FLIP 记录前后位置,只用 transform 补间,列表重排不跳动。
纯 HTML、CSS 与少量原生 JS,没有框架依赖。复制提示词交给 Claude Code、Cursor、Trae 或 Codex,模型会把 Kanban Column 加进你的项目并换成你的配色。
适用场景
仪表盘、数据表格、图表卡片、对比表和状态面板。
安装
订阅 Builder 后,用 8pt CLI 装进项目,或在已接入 8pt MCP 的编辑器里直接调用。
$ npm i -g @8pt-dev/cli && 8pt add kanban-column
mcp › 使用 8pt MCP 调用 get_component("kanban-column")
代码
Kanban Column 的源码,动效只用 transform 与 opacity,并尊重减少动态效果设置。
<div class="x-kb">
<section class="x-kb__col" data-col="doing"><header>进行中 <em>3</em></header>
<button type="button" class="x-kb__card" data-tag="设计"><i></i>首页 Hero 改版</button>
<button type="button" class="x-kb__card" data-tag="前端"><i></i>定价页切换动效</button>
<button type="button" class="x-kb__card" data-tag="文档"><i></i>补充 MCP 示例</button>
</section>
<section class="x-kb__col" data-col="done"><header>已完成 <em>1</em></header>
<button type="button" class="x-kb__card" data-tag="前端"><i></i>深色模式变量</button>
</section>
</div>.x-kb{display:grid;grid-template-columns:1fr 1fr;gap:10px;width:min(340px,100%);color:var(--d-fg,#fff)}
.x-kb__col{display:flex;flex-direction:column;gap:6px;min-height:200px;padding:8px;border-radius:14px;background:color-mix(in srgb,var(--d-card,#14141c) 70%,transparent);border:1px solid var(--d-line,rgba(255,255,255,.1))}
.x-kb__col header{display:flex;align-items:center;justify-content:space-between;padding:2px 4px 6px;font:600 12px/1 var(--d-font,system-ui,sans-serif);color:var(--d-muted,#9b9ba8)}
.x-kb__col header em{font-style:normal;min-width:20px;padding:3px 6px;border-radius:999px;background:var(--d-line,rgba(255,255,255,.1));text-align:center;font-variant-numeric:tabular-nums}
.x-kb__card{position:relative;display:grid;gap:7px;padding:9px 10px;border-radius:10px;border:1px solid var(--d-line,rgba(255,255,255,.1));background:var(--d-card,#14141c);color:inherit;font:500 12.5px/1.35 var(--d-font,system-ui,sans-serif);text-align:left;cursor:pointer;box-shadow:0 6px 14px -10px rgba(0,0,0,.6);transition:box-shadow .2s;will-change:transform}
.x-kb__card::before{content:attr(data-tag);justify-self:start;padding:3px 6px;border-radius:5px;font:600 10px/1 var(--d-font,system-ui,sans-serif);color:var(--d-accent,#4D74FF);background:color-mix(in srgb,var(--d-accent,#4D74FF) 15%,transparent)}
.x-kb__card:hover{box-shadow:0 10px 22px -10px rgba(0,0,0,.7)}
.x-kb__card i{display:none}
[data-col=done] .x-kb__card{color:var(--d-muted,#9b9ba8);text-decoration:line-through;text-decoration-color:color-mix(in srgb,var(--d-muted,#9b9ba8) 60%,transparent)}
[data-col=done] .x-kb__card::before{color:#3dd68c;background:rgba(61,214,140,.14)}const init = (root) => {
const cols = [...root.querySelectorAll('.x-kb__col')];
const count = () => cols.forEach(c => c.querySelector('em').textContent = c.querySelectorAll('.x-kb__card').length);
const reduce = matchMedia('(prefers-reduced-motion: reduce)').matches;
const move = (card) => {
const cards = [...root.querySelectorAll('.x-kb__card')], first = new Map(cards.map(c => [c, c.getBoundingClientRect()]));
const to = card.closest('.x-kb__col') === cols[0] ? cols[1] : cols[0];
to.insertBefore(card, to.children[1] || null); count();
if (reduce) return;
cards.forEach(c => { const a = first.get(c), b = c.getBoundingClientRect(), dx = a.left - b.left, dy = a.top - b.top; if (!dx && !dy) return;
c.animate([{ transform: `translate(${dx}px, ${dy}px)` + (c === card ? ' rotate(-3deg) scale(1.04)' : '') }, { transform: 'none' }], { duration: 480, easing: 'cubic-bezier(.2,.8,.2,1)' }); });
};
…订阅 Builder 查看完整源码。查看价格