Files
yinx-cli/lib/ui.js
2025-12-16 16:21:26 +08:00

191 lines
5.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import color from "picocolors";
import readline from "readline";
import boxen from "boxen";
import { steps } from "./config.js";
// 存储结果和状态
let results = [];
let completed = new Set();
let currentStep = 0;
let currentOption = 0;
// 古诗配置
let poemLines = ["你我皆牛马", "生在人世间", "终日奔波苦", "一刻不得闲"];
let poemPerLine = 2;
// 设置古诗
export function setPoem(lines, perLine = 2) {
poemLines = lines;
poemPerLine = perLine;
}
// 渲染古诗
function renderPoem() {
const merged = [];
for (let i = 0; i < poemLines.length; i += poemPerLine) {
merged.push(poemLines.slice(i, i + poemPerLine).join(""));
}
return boxen(color.yellow(merged.join("\n")), {
padding: { top: 1, bottom: 1, left: 4, right: 4 },
borderStyle: "double",
borderColor: "cyan",
textAlignment: "center",
float: "center",
});
}
// 初始化结果
export function initResults() {
results = steps.map(s => s.type === "multiselect" ? [...s.default] : s.default);
completed = new Set();
currentStep = 0;
currentOption = 0;
}
// 渲染导航栏
function renderNav() {
const nav = steps.map((step, i) => {
if (completed.has(i)) {
return color.green(`${step.name}`);
} else if (i === currentStep) {
return color.bgCyan(color.black(` ${step.name} `));
} else {
return color.dim(`${step.name}`);
}
});
return `${nav.join(" ")} ${color.green("✓Submit")}`;
}
// 渲染选项列表
function renderOptions() {
const step = steps[currentStep];
const lines = [];
lines.push(color.cyan(step.message));
lines.push("");
step.options.forEach((opt, i) => {
const isCurrent = i === currentOption;
const isSelected = step.type === "multiselect"
? results[currentStep].includes(opt.value)
: results[currentStep] === opt.value;
let prefix;
if (step.type === "multiselect") {
prefix = isSelected ? color.green("◉ ") : "○ ";
} else {
prefix = isSelected ? color.green("● ") : "○ ";
}
const cursor = isCurrent ? color.cyan(" ") : " ";
const label = isCurrent ? color.cyan(opt.label) : opt.label;
const check = isSelected ? color.green(" ✓") : "";
lines.push(`${cursor}${prefix}${label}${check}`);
if (opt.hint) {
lines.push(` ${color.dim(opt.hint)}`);
}
});
return lines.join("\n");
}
// 渲染整个界面
function render() {
console.clear();
console.log(renderPoem());
console.log(color.bgCyan(color.black(" KTX2 纹理压缩工具 ")));
console.log("\n" + renderNav());
console.log(color.dim("\n← → 切换步骤 | ↑ ↓ 选择选项 | Space 选中 | Enter 确认 | Tab 提交\n"));
console.log(renderOptions());
}
// 主交互循环
export async function runInteractive() {
initResults();
readline.emitKeypressEvents(process.stdin);
if (process.stdin.isTTY) {
process.stdin.setRawMode(true);
}
return new Promise((resolve) => {
render();
const handler = (str, key) => {
if (!key) return;
const step = steps[currentStep];
const optCount = step.options.length;
if (key.name === "left") {
if (currentStep > 0) {
currentStep--;
currentOption = 0;
}
render();
} else if (key.name === "right") {
if (currentStep < steps.length - 1) {
currentStep++;
currentOption = 0;
}
render();
} else if (key.name === "up") {
currentOption = (currentOption - 1 + optCount) % optCount;
render();
} else if (key.name === "down") {
currentOption = (currentOption + 1) % optCount;
render();
} else if (key.name === "space") {
const opt = step.options[currentOption];
if (step.type === "multiselect") {
const idx = results[currentStep].indexOf(opt.value);
if (idx >= 0) {
results[currentStep].splice(idx, 1);
} else {
results[currentStep].push(opt.value);
}
} else {
results[currentStep] = opt.value;
}
completed.add(currentStep);
render();
} else if (key.name === "return") {
if (step.type === "select") {
results[currentStep] = step.options[currentOption].value;
}
completed.add(currentStep);
if (currentStep < steps.length - 1) {
currentStep++;
currentOption = 0;
}
render();
} else if (key.name === "tab") {
process.stdin.setRawMode(false);
process.stdin.removeListener("keypress", handler);
resolve(results);
} else if (key.name === "escape" || (key.ctrl && key.name === "c")) {
process.stdin.setRawMode(false);
console.clear();
console.log(color.yellow("操作已取消"));
process.exit(0);
}
};
process.stdin.on("keypress", handler);
});
}
// 显示配置摘要
export function showSummary(config) {
console.clear();
console.log(renderPoem());
console.log(color.bgCyan(color.black(" KTX2 纹理压缩工具 ")));
console.log("\n" + color.green("配置完成!当前设置:"));
console.log(` 文件格式: ${config.exts.join(", ")}`);
console.log(` 压缩程度: ${config.quality}`);
console.log(` 编码格式: ${config.encoding}`);
console.log(` Mipmap: ${config.mipmap}`);
console.log(` 输出选项: ${config.outputOpts.join(", ")}\n`);
}