import color from "picocolors"; import { initKeypress, onKey, stopKeypress } from "../keyboard.js"; import { createStepUI } from "../utils/stepui.js"; import { frontendSteps } from "./config.js"; function clearScreen() { process.stdout.write('\x1Bc'); } function strWidth(str) { let width = 0; for (const char of str) { width += char.charCodeAt(0) > 127 ? 2 : 1; } return width; } function padEnd(str, width) { return str + " ".repeat(Math.max(0, width - strWidth(str))); } // 网格选择器 export async function gridSelect(items, title) { let current = 0; let resolved = false; const termWidth = process.stdout.columns || 80; const cols = Math.min(3, items.length); const colWidth = 20; const rows = Math.ceil(items.length / cols); const totalWidth = cols * colWidth; const pad = " ".repeat(Math.max(0, Math.floor((termWidth - totalWidth) / 2))); function render() { clearScreen(); console.log(""); const titlePad = " ".repeat(Math.max(0, Math.floor((termWidth - strWidth(title) - 4) / 2))); console.log(titlePad + color.bgMagenta(color.white(` ${title} `))); console.log(""); console.log(pad + color.dim("↑ ↓ ← → 选择 | Enter 确认 | Esc 返回")); console.log("\n"); for (let row = 0; row < rows; row++) { let line = ""; let descLine = ""; for (let col = 0; col < cols; col++) { const idx = row * cols + col; if (idx < items.length) { const item = items[idx]; const isSelected = idx === current; if (isSelected) { line += color.cyan("[" + item.name + "]"); } else { line += " " + item.name + " "; } line += " ".repeat(colWidth - strWidth(item.name) - 2); descLine += padEnd(item.desc || "", colWidth); } } console.log(pad + line); console.log(pad + color.dim(descLine)); console.log("\n"); } } return new Promise(resolve => { initKeypress(); render(); onKey((str, key) => { if (!key || resolved) return; const row = Math.floor(current / cols); const col = current % cols; switch (key.name) { case "up": if (row > 0) { current -= cols; render(); } break; case "down": if (row < rows - 1 && current + cols < items.length) { current += cols; render(); } break; case "left": if (col > 0) { current--; render(); } break; case "right": if (col < cols - 1 && current < items.length - 1) { current++; render(); } break; case "return": resolved = true; stopKeypress(); setImmediate(() => resolve({ action: "select", item: items[current] })); break; case "escape": resolved = true; stopKeypress(); setImmediate(() => resolve({ action: "back" })); break; } }); }); } // 创建组件配置UI export function createComponentUI(frameworkName) { return createStepUI({ title: `${frameworkName} - 组件配置`, getSteps: () => frontendSteps }); } // 解析配置结果 export function formatResults(results) { const stepNames = frontendSteps.map(s => s.name); const summary = []; results.forEach((val, i) => { if (Array.isArray(val) && val.length > 0) { summary.push(`${stepNames[i]}: ${val.join(", ")}`); } else if (val && val !== "none") { summary.push(`${stepNames[i]}: ${val}`); } }); return summary.length ? summary : ["未选择任何组件"]; } // 等待按键 export async function waitKey(message = "按任意键返回") { console.log(color.dim(`\n${message}`)); return new Promise(resolve => { initKeypress(); onKey(() => { stopKeypress(); resolve(); }); }); } // 显示占位信息 export function showPlaceholder(framework) { clearScreen(); console.log(""); console.log(color.bgGreen(color.black(" 配置完成 "))); console.log(""); console.log(color.cyan("框架: ") + framework.name); console.log(""); console.log(color.yellow("功能开发中,敬请期待...")); }