Command Palette
介绍
内联命令面板:输入即过滤,方向键移动高亮条,回车执行。高亮条用 transform 平移,不重排列表。
纯 HTML、CSS 与少量原生 JS,没有框架依赖。复制提示词交给 Claude Code、Cursor、Trae 或 Codex,模型会把 Command Palette 加进你的项目并换成你的配色。
适用场景
搜索框、AI 对话输入框、表单字段、文件上传和验证码等用户输入的地方。
安装
订阅 Builder 后,用 8pt CLI 装进项目,或在已接入 8pt MCP 的编辑器里直接调用。
$ npm i -g @8pt-dev/cli && 8pt add command-palette
mcp › 使用 8pt MCP 调用 get_component("command-palette")
代码
Command Palette 的源码,动效只用 transform 与 opacity,并尊重减少动态效果设置。
<div class="x-cmd" data-own-k>
<label class="x-cmd__in"><span aria-hidden="true"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg></span><input placeholder="输入命令…" aria-label="命令"><kbd>K</kbd></label>
<div class="x-cmd__list" role="listbox">
<span class="x-cmd__hl" aria-hidden="true"></span>
<button type="button" role="option" data-k="new 新建 项目"><i><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg></i>新建项目<em>N</em></button>
<button type="button" role="option" data-k="theme 切换 主题 深色"><i><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M20 14.5A8 8 0 1 1 9.5 4a6.5 6.5 0 0 0 10.5 10.5z"/></svg></i>切换深色主题<em>T</em></button>
<button type="button" role="option" data-k="invite 邀请 成员"><i><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="8" r="3.5"/><path d="M2.5 20a6.5 6.5 0 0 1 13 0M18 8v6M15 11h6"/></svg></i>邀请成员<em>I</em></button>
<button type="button" role="option" data-k="deploy 部署 发布"><i><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17L17 7M9 7h8v8"/></svg></i>部署到生产<em>D</em></button>
<button type="button" role="option" data-k="settings 设置"><i><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1.1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z"/></svg></i>打开设置<em>,</em></button>
</div>
<div class="x-cmd__toast" aria-live="polite"></div>
</div>.x-cmd{position:relative;width:min(320px,100%);border-radius:14px;background:var(--d-card,#14141c);border:1px solid var(--d-line,rgba(255,255,255,.12));box-shadow:0 24px 50px -28px rgba(0,0,0,.7);color:var(--d-fg,#fff);overflow:hidden}
.x-cmd__in{display:flex;align-items:center;gap:8px;height:42px;padding:0 12px;border-bottom:1px solid var(--d-line,rgba(255,255,255,.1))}
.x-cmd__in span{color:var(--d-muted,#9b9ba8);font-size:13px}
.x-cmd__in input{flex:1;min-width:0;border:0;outline:0;background:transparent;color:inherit;font:14px/1 var(--d-font,system-ui,sans-serif)}
.x-cmd__in input::placeholder{color:var(--d-muted,#9b9ba8)}
.x-cmd__in kbd{padding:3px 6px;border-radius:5px;border:1px solid var(--d-line,rgba(255,255,255,.14));font:600 10px/1 ui-monospace,monospace;color:var(--d-muted,#9b9ba8)}
.x-cmd__list{position:relative;display:grid;padding:6px}
.x-cmd__list button{position:relative;z-index:1;display:flex;align-items:center;gap:10px;height:34px;padding:0 10px;border:0;background:transparent;color:inherit;font:13px/1 var(--d-font,system-ui,sans-serif);text-align:left;cursor:pointer}
.x-cmd__list button[hidden]{display:none}
.x-cmd__list i{display:grid;place-items:center;width:18px;font-style:normal;color:var(--d-muted,#9b9ba8)}
.x-cmd__list em{margin-left:auto;font:600 10px/1 ui-monospace,monospace;font-style:normal;color:var(--d-muted,#9b9ba8)}
.x-cmd__hl{position:absolute;left:6px;right:6px;top:6px;height:34px;border-radius:8px;background:color-mix(in srgb,var(--d-accent,#4D74FF) 18%,transparent);transition:transform .22s cubic-bezier(.2,.8,.2,1),opacity .2s}
…const init = (root) => {
const input = root.querySelector('input'), hl = root.querySelector('.x-cmd__hl'), toast = root.querySelector('.x-cmd__toast');
const opts = [...root.querySelectorAll('[role=option]')];
let sel = 0, t, demo, di = 0;
const vis = () => opts.filter(o => !o.hidden);
const draw = () => { const v = vis(); hl.style.opacity = v.length ? 1 : 0; sel = Math.min(sel, Math.max(0, v.length - 1)); hl.style.transform = `translateY(${sel * 34}px)`; opts.forEach(o => o.setAttribute('aria-selected', String(o === v[sel]))); };
const run = (o) => { if (!o) return; toast.textContent = '✓ ' + o.childNodes[1].textContent.trim(); toast.classList.add('on'); clearTimeout(t); t = setTimeout(() => toast.classList.remove('on'), 1200); };
input.addEventListener('input', () => { const q = input.value.trim().toLowerCase(); opts.forEach(o => o.hidden = !!q && !(o.dataset.k + o.textContent).toLowerCase().includes(q)); sel = 0; draw(); });
input.addEventListener('keydown', e => { const v = vis(); if (!v.length) return;
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') { e.preventDefault(); sel = (sel + (e.key === 'ArrowDown' ? 1 : v.length - 1)) % v.length; draw(); }
if (e.key === 'Enter') { e.preventDefault(); run(v[sel]); } });
opts.forEach(o => { o.addEventListener('pointerenter', () => { sel = vis().indexOf(o); draw(); }); o.addEventListener('click', () => run(o)); });
…订阅 Builder 查看完整源码。查看价格