You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
4.9 KiB
184 lines
4.9 KiB
|
1 day ago
|
import { GmBuiltinPanelId, GmKind, type IGmCommand, type IGmConfirmData, type IGmNumberStepperData, type IGmTextAreaData } from './GmTypes';
|
||
|
|
import { GmRegistry } from './GmRegistry';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 极简 GM 注册器:链式写几行即可挂命令,不必手拼 IGmCommand。
|
||
|
|
*
|
||
|
|
* @example
|
||
|
|
* ```ts
|
||
|
|
* new GmEasy()
|
||
|
|
* .tab('常用')
|
||
|
|
* .btn('复制存档', () => copy())
|
||
|
|
* .sw('显示广告', () => on, v => set(v))
|
||
|
|
* .num('金钱', () => get(), v => set(v))
|
||
|
|
* .page('道具', 'itemPicker', () => '点选')
|
||
|
|
* .commit();
|
||
|
|
* ```
|
||
|
|
*/
|
||
|
|
export class GmEasy {
|
||
|
|
private readonly _cmds: IGmCommand[] = [];
|
||
|
|
private _group = '常用';
|
||
|
|
private _order = 0;
|
||
|
|
private _seq = 0;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 切换 Tab 分组(后续命令都进这个分组)。
|
||
|
|
*/
|
||
|
|
tab(name: string): this {
|
||
|
|
if (!name) {
|
||
|
|
console.warn('[GmEasy] tab 名为空');
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
this._group = name;
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 快捷按钮:点一下执行。
|
||
|
|
*/
|
||
|
|
btn(title: string, run: () => void | Promise<void>): this {
|
||
|
|
this._push({
|
||
|
|
id: this._id('btn'),
|
||
|
|
title,
|
||
|
|
group: this._group,
|
||
|
|
kind: GmKind.Quick,
|
||
|
|
order: ++this._order,
|
||
|
|
run,
|
||
|
|
});
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 滑动开关。
|
||
|
|
*/
|
||
|
|
sw(title: string, get: () => boolean, set: (on: boolean) => void): this {
|
||
|
|
this._push({
|
||
|
|
id: this._id('sw'),
|
||
|
|
title,
|
||
|
|
group: this._group,
|
||
|
|
kind: GmKind.Toggle,
|
||
|
|
order: ++this._order,
|
||
|
|
get,
|
||
|
|
set,
|
||
|
|
});
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 数值:列表内「设为」覆盖 + ± 增减。
|
||
|
|
* @param setValue 写入绝对值(增减由壳层算好再传入)
|
||
|
|
*/
|
||
|
|
num(title: string, getValue: () => number, setValue: (v: number) => void, min = 0): this {
|
||
|
|
const panelData: IGmNumberStepperData = {
|
||
|
|
getValue,
|
||
|
|
apply: (v) => setValue(v),
|
||
|
|
min,
|
||
|
|
defaultMode: 'set',
|
||
|
|
};
|
||
|
|
this._push({
|
||
|
|
id: this._id('num'),
|
||
|
|
title,
|
||
|
|
group: this._group,
|
||
|
|
kind: GmKind.Content,
|
||
|
|
order: ++this._order,
|
||
|
|
panelId: GmBuiltinPanelId.numberStepper,
|
||
|
|
panelData,
|
||
|
|
summary: () => `${Math.floor(Number(getValue()) || 0)}`,
|
||
|
|
});
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 打开已注册的内容面板(如道具点选)。
|
||
|
|
*/
|
||
|
|
page(title: string, panelId: string, summary?: () => string, panelData?: unknown): this {
|
||
|
|
this._push({
|
||
|
|
id: this._id('page'),
|
||
|
|
title,
|
||
|
|
group: this._group,
|
||
|
|
kind: GmKind.Content,
|
||
|
|
order: ++this._order,
|
||
|
|
panelId,
|
||
|
|
panelData,
|
||
|
|
summary: summary ?? (() => '›'),
|
||
|
|
});
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 危险操作(二次确认)。
|
||
|
|
*/
|
||
|
|
danger(title: string, message: string, onConfirm: () => void): this {
|
||
|
|
const panelData: IGmConfirmData = { message, onConfirm };
|
||
|
|
this._push({
|
||
|
|
id: this._id('danger'),
|
||
|
|
title,
|
||
|
|
group: this._group,
|
||
|
|
kind: GmKind.Content,
|
||
|
|
order: ++this._order,
|
||
|
|
panelId: GmBuiltinPanelId.confirmQuick,
|
||
|
|
panelData,
|
||
|
|
summary: () => '危险',
|
||
|
|
});
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 大段文本(如粘贴存档 JSON)。
|
||
|
|
*/
|
||
|
|
text(title: string, apply: (raw: string) => void, placeholder = '粘贴内容'): this {
|
||
|
|
const panelData: IGmTextAreaData = { placeholder, apply };
|
||
|
|
this._push({
|
||
|
|
id: this._id('text'),
|
||
|
|
title,
|
||
|
|
group: this._group,
|
||
|
|
kind: GmKind.Content,
|
||
|
|
order: ++this._order,
|
||
|
|
panelId: GmBuiltinPanelId.textArea,
|
||
|
|
panelData,
|
||
|
|
summary: () => '粘贴',
|
||
|
|
});
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 当前 Tab 直接嵌入内容面板(整页展示,无列表入口)。
|
||
|
|
*/
|
||
|
|
embed(panelId: string): this {
|
||
|
|
this._push({
|
||
|
|
id: this._id('embed'),
|
||
|
|
title: this._group,
|
||
|
|
group: this._group,
|
||
|
|
kind: GmKind.Content,
|
||
|
|
order: ++this._order,
|
||
|
|
panelId,
|
||
|
|
embed: true,
|
||
|
|
});
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 提交注册到 Registry。
|
||
|
|
*/
|
||
|
|
commit(): void {
|
||
|
|
if (this._cmds.length <= 0) {
|
||
|
|
console.warn('[GmEasy] commit 时没有任何命令');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
GmRegistry.register(this._cmds);
|
||
|
|
}
|
||
|
|
|
||
|
|
private _id(prefix: string): string {
|
||
|
|
this._seq++;
|
||
|
|
return `easy.${prefix}.${this._seq}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
private _push(cmd: IGmCommand): void {
|
||
|
|
if (!cmd.title) {
|
||
|
|
console.warn('[GmEasy] 跳过无标题命令');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
this._cmds.push(cmd);
|
||
|
|
}
|
||
|
|
}
|