163 lines
4.6 KiB
JavaScript
163 lines
4.6 KiB
JavaScript
import color from "picocolors";
|
||
import readline from "readline";
|
||
import { steps } from "./config.js";
|
||
|
||
// 存储结果和状态
|
||
let results = [];
|
||
let completed = new Set();
|
||
let currentStep = 0;
|
||
let currentOption = 0;
|
||
|
||
// 初始化结果
|
||
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(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(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`);
|
||
}
|