mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-19 12:49:25 +08:00
feat: 杂项工具栏
This commit is contained in:
parent
75acb376e2
commit
5c0a2a2318
@ -16,6 +16,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons-vue": "^6.1.0",
|
"@ant-design/icons-vue": "^6.1.0",
|
||||||
|
"@emotion/css": "^11.11.2",
|
||||||
"@vueuse/core": "^10.4.1",
|
"@vueuse/core": "^10.4.1",
|
||||||
"ant-design-vue": "^3.2.20",
|
"ant-design-vue": "^3.2.20",
|
||||||
"axios": "^1.5.0",
|
"axios": "^1.5.0",
|
||||||
@ -52,6 +53,7 @@
|
|||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"fs-extra": "^10.1.0",
|
"fs-extra": "^10.1.0",
|
||||||
"less": "^4.2.0",
|
"less": "^4.2.0",
|
||||||
|
"postcss-preset-env": "^9.5.9",
|
||||||
"rollup": "^3.28.1",
|
"rollup": "^3.28.1",
|
||||||
"terser": "^5.19.4",
|
"terser": "^5.19.4",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
|
1048
pnpm-lock.yaml
1048
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -165,7 +165,6 @@ function resize() {
|
|||||||
onUpdated(resize);
|
onUpdated(resize);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await sleep(50);
|
|
||||||
resize();
|
resize();
|
||||||
|
|
||||||
if (!main) return;
|
if (!main) return;
|
||||||
|
@ -22,11 +22,15 @@ interface DanmakuResponse extends ResponseBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface DanmakuInfo {
|
interface DanmakuInfo {
|
||||||
id: number;
|
id: string;
|
||||||
comment: string;
|
comment: string;
|
||||||
tags: string;
|
tags: string;
|
||||||
love: number;
|
love: string;
|
||||||
my_love_type: boolean;
|
my_love_type: boolean;
|
||||||
|
userid: string;
|
||||||
|
deler: string;
|
||||||
|
upload_time: string;
|
||||||
|
tower_name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DanmakuPostInfo extends Partial<DanmakuContentInfo> {
|
interface DanmakuPostInfo extends Partial<DanmakuContentInfo> {
|
||||||
@ -468,8 +472,8 @@ export class Danmaku extends EventEmitter<DanmakuEvent> {
|
|||||||
|
|
||||||
data.data.list.forEach(v => {
|
data.data.list.forEach(v => {
|
||||||
const dan = new Danmaku();
|
const dan = new Danmaku();
|
||||||
dan.id = v.id;
|
dan.id = parseInt(v.id);
|
||||||
dan.likedNum = v.love;
|
dan.likedNum = parseInt(v.love);
|
||||||
dan.liked = v.my_love_type;
|
dan.liked = v.my_love_type;
|
||||||
dan.decode(v);
|
dan.decode(v);
|
||||||
dan.posted = true;
|
dan.posted = true;
|
||||||
|
@ -1,21 +1,16 @@
|
|||||||
import { EmitableEvent, EventEmitter } from '@/core/common/eventEmitter';
|
import { EmitableEvent, EventEmitter } from '@/core/common/eventEmitter';
|
||||||
import { KeyCode } from '@/plugin/keyCodes';
|
import { deleteWith, has } from '@/plugin/utils';
|
||||||
import { deleteWith, flipBinary, has } from '@/plugin/utils';
|
import { Component, nextTick, reactive, shallowReactive } from 'vue';
|
||||||
import {
|
|
||||||
FunctionalComponent,
|
|
||||||
markRaw,
|
|
||||||
nextTick,
|
|
||||||
reactive,
|
|
||||||
shallowReactive
|
|
||||||
} from 'vue';
|
|
||||||
import {
|
|
||||||
createToolbarComponents,
|
|
||||||
createToolbarEditorComponents
|
|
||||||
} from '../init/toolbar';
|
|
||||||
import { gameKey } from '../init/hotkey';
|
|
||||||
import { unwarpBinary } from './hotkey';
|
|
||||||
import { fixedUi } from '../init/ui';
|
import { fixedUi } from '../init/ui';
|
||||||
import { GameStorage } from '../storage';
|
import { GameStorage } from '../storage';
|
||||||
|
import type {
|
||||||
|
CustomToolbarComponent,
|
||||||
|
MiscToolbar,
|
||||||
|
SettableItemData,
|
||||||
|
ToolbarItemBase,
|
||||||
|
ToolbarItemMap,
|
||||||
|
ToolbarItemType
|
||||||
|
} from '../init/toolbar';
|
||||||
|
|
||||||
interface CustomToolbarEvent extends EmitableEvent {
|
interface CustomToolbarEvent extends EmitableEvent {
|
||||||
add: (item: ValueOf<ToolbarItemMap>) => void;
|
add: (item: ValueOf<ToolbarItemMap>) => void;
|
||||||
@ -25,45 +20,6 @@ interface CustomToolbarEvent extends EmitableEvent {
|
|||||||
posChange: (bar: CustomToolbar) => void;
|
posChange: (bar: CustomToolbar) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ToolbarItemBase<T extends ToolbarItemType> {
|
|
||||||
type: T;
|
|
||||||
id: string;
|
|
||||||
noDefaultAction?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 快捷键
|
|
||||||
interface HotkeyToolbarItem extends ToolbarItemBase<'hotkey'> {
|
|
||||||
key: KeyCode;
|
|
||||||
assist: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用道具
|
|
||||||
interface ItemToolbarItem extends ToolbarItemBase<'item'> {
|
|
||||||
item: ItemIdOf<'tools' | 'constants'>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 切换辅助按键 ctrl alt shift
|
|
||||||
interface AssistKeyToolbarItem extends ToolbarItemBase<'assistKey'> {
|
|
||||||
assist: KeyCode.Ctrl | KeyCode.Shift | KeyCode.Alt;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MinimatToolbar extends ToolbarItemBase<'minimap'> {
|
|
||||||
action: boolean;
|
|
||||||
scale: number;
|
|
||||||
noBorder: boolean;
|
|
||||||
showInfo: boolean;
|
|
||||||
autoLocate: boolean;
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ToolbarItemMap {
|
|
||||||
hotkey: HotkeyToolbarItem;
|
|
||||||
item: ItemToolbarItem;
|
|
||||||
assistKey: AssistKeyToolbarItem;
|
|
||||||
minimap: MinimatToolbar;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ToolbarSaveData {
|
interface ToolbarSaveData {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
@ -72,21 +28,6 @@ interface ToolbarSaveData {
|
|||||||
items: ValueOf<ToolbarItemMap>[];
|
items: ValueOf<ToolbarItemMap>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ToolbarItemType = keyof ToolbarItemMap;
|
|
||||||
|
|
||||||
export type SettableItemData<T extends ToolbarItemType = ToolbarItemType> =
|
|
||||||
Omit<ToolbarItemMap[T], 'id' | 'type'>;
|
|
||||||
|
|
||||||
export interface CustomToolbarProps<
|
|
||||||
T extends ToolbarItemType = ToolbarItemType
|
|
||||||
> {
|
|
||||||
item: ToolbarItemMap[T];
|
|
||||||
toolbar: CustomToolbar;
|
|
||||||
}
|
|
||||||
export type CustomToolbarComponent<
|
|
||||||
T extends ToolbarItemType = ToolbarItemType
|
|
||||||
> = FunctionalComponent<CustomToolbarProps<T>>;
|
|
||||||
|
|
||||||
type ToolItemEmitFn<T extends ToolbarItemType> = (
|
type ToolItemEmitFn<T extends ToolbarItemType> = (
|
||||||
this: CustomToolbar,
|
this: CustomToolbar,
|
||||||
id: string,
|
id: string,
|
||||||
@ -101,18 +42,91 @@ interface RegisteredCustomToolInfo {
|
|||||||
onCreate: (item: any) => ToolbarItemBase<ToolbarItemType>;
|
onCreate: (item: any) => ToolbarItemBase<ToolbarItemType>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const COM = createToolbarComponents();
|
type MiscEmitFn = (
|
||||||
const EDITOR = createToolbarEditorComponents();
|
id: string,
|
||||||
|
toolbar: CustomToolbar,
|
||||||
|
item: MiscToolbar
|
||||||
|
) => void;
|
||||||
|
type ActivedFn = (info: MiscInfo) => boolean;
|
||||||
|
|
||||||
|
interface MiscInfo {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
emit: MiscEmitFn;
|
||||||
|
display: Component;
|
||||||
|
activable?: boolean;
|
||||||
|
actived?: ActivedFn;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Misc {
|
||||||
|
info: Record<string, MiscInfo>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册一个杂项工具
|
||||||
|
* @param id 杂项工具的id
|
||||||
|
* @param name 这个工具的名称
|
||||||
|
* @param emit 触发这个杂项工具时执行的函数
|
||||||
|
* @param display 这个工具的显示组件
|
||||||
|
* @param activable 是否是可以被激活的工具,例如打开小地图后显示为激活状态
|
||||||
|
*/
|
||||||
|
register(
|
||||||
|
this: Misc,
|
||||||
|
id: string,
|
||||||
|
name: string,
|
||||||
|
emit: MiscEmitFn,
|
||||||
|
display: Component
|
||||||
|
): void;
|
||||||
|
|
||||||
|
bindActivable(id: string, activable: boolean, actived?: ActivedFn): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新所有或指定的包含杂项工具的工具栏
|
||||||
|
* @param id 指定包含这个杂项工具的工具栏刷新,例如填drag,则只会刷新包含drag杂项工具的工具栏
|
||||||
|
*/
|
||||||
|
requestRefresh(id?: string): void;
|
||||||
|
}
|
||||||
|
|
||||||
const toolbarStorage = new GameStorage<Record<string, ToolbarSaveData>>(
|
const toolbarStorage = new GameStorage<Record<string, ToolbarSaveData>>(
|
||||||
GameStorage.fromAuthor('AncTe', 'toolbar')
|
GameStorage.fromAuthor('AncTe', 'toolbar')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const misc: Misc = {
|
||||||
|
info: {},
|
||||||
|
register(id, name, emit, display) {
|
||||||
|
this.info[id] = { id, name, emit, display };
|
||||||
|
},
|
||||||
|
bindActivable(id, activable, actived) {
|
||||||
|
this.info[id].activable = activable;
|
||||||
|
this.info[id].actived = actived;
|
||||||
|
},
|
||||||
|
requestRefresh(id) {
|
||||||
|
if (id) {
|
||||||
|
CustomToolbar.list.forEach(v => {
|
||||||
|
if (
|
||||||
|
v.items.some(v => {
|
||||||
|
return v.type === 'misc' && v.items?.includes(id);
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
v.refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
CustomToolbar.list.forEach(v => {
|
||||||
|
if (v.items.some(v => v.type === 'misc')) {
|
||||||
|
v.refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
||||||
static num: number = 0;
|
static num: number = 0;
|
||||||
static list: CustomToolbar[] = shallowReactive([]);
|
static list: CustomToolbar[] = shallowReactive([]);
|
||||||
static info: Record<string, RegisteredCustomToolInfo> = {};
|
static info: Record<string, RegisteredCustomToolInfo> = {};
|
||||||
|
|
||||||
|
static misc: Misc = misc;
|
||||||
|
|
||||||
items: ValueOf<ToolbarItemMap>[] = reactive([]);
|
items: ValueOf<ToolbarItemMap>[] = reactive([]);
|
||||||
num: number = CustomToolbar.num++;
|
num: number = CustomToolbar.num++;
|
||||||
id: string;
|
id: string;
|
||||||
@ -125,7 +139,7 @@ export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
|||||||
assistKey: number = 0;
|
assistKey: number = 0;
|
||||||
showIds: number[] = [];
|
showIds: number[] = [];
|
||||||
|
|
||||||
constructor(id: string) {
|
constructor(id: string, noshow: boolean = false) {
|
||||||
super();
|
super();
|
||||||
this.id = id;
|
this.id = id;
|
||||||
// 按比例设置初始大小
|
// 按比例设置初始大小
|
||||||
@ -136,7 +150,7 @@ export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
|||||||
this.x *= scale;
|
this.x *= scale;
|
||||||
this.y *= scale;
|
this.y *= scale;
|
||||||
|
|
||||||
this.show();
|
if (!noshow) this.show();
|
||||||
CustomToolbar.list.push(this);
|
CustomToolbar.list.push(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,8 +251,15 @@ export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 显示这个自定义工具栏,可以显示多个,且内容互通
|
* 显示这个自定义工具栏,可以显示多个,且内容互通
|
||||||
|
* @param multi 是否允许显示多个,不填时,如果已经存在这个工具栏,那么将不会显示
|
||||||
*/
|
*/
|
||||||
show() {
|
show(multi: boolean = false) {
|
||||||
|
if (
|
||||||
|
!multi &&
|
||||||
|
this.showIds.some(v => fixedUi.stack.some(vv => vv.num === v))
|
||||||
|
) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
const id = fixedUi.open('toolbar', { bar: this });
|
const id = fixedUi.open('toolbar', { bar: this });
|
||||||
this.showIds.push(id);
|
this.showIds.push(id);
|
||||||
return id;
|
return id;
|
||||||
@ -343,96 +364,6 @@ export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomToolbar.register(
|
|
||||||
'hotkey',
|
|
||||||
'快捷键',
|
|
||||||
function (id, item) {
|
|
||||||
// 按键
|
|
||||||
const assist = item.assist | this.assistKey;
|
|
||||||
const { ctrl, shift, alt } = unwarpBinary(assist);
|
|
||||||
const ev = new KeyboardEvent('keyup', {
|
|
||||||
ctrlKey: ctrl,
|
|
||||||
shiftKey: shift,
|
|
||||||
altKey: alt
|
|
||||||
});
|
|
||||||
|
|
||||||
// todo: Advanced KeyboardEvent simulate
|
|
||||||
gameKey.emitKey(item.key, assist, 'up', ev);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
COM.KeyTool,
|
|
||||||
EDITOR.KeyTool,
|
|
||||||
item => {
|
|
||||||
return {
|
|
||||||
key: KeyCode.Unknown,
|
|
||||||
assist: 0,
|
|
||||||
...item
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
CustomToolbar.register(
|
|
||||||
'item',
|
|
||||||
'使用道具',
|
|
||||||
function (id, item) {
|
|
||||||
// 道具
|
|
||||||
core.tryUseItem(item.item);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
COM.ItemTool,
|
|
||||||
EDITOR.ItemTool,
|
|
||||||
item => {
|
|
||||||
return {
|
|
||||||
item: 'book',
|
|
||||||
...item
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
CustomToolbar.register(
|
|
||||||
'assistKey',
|
|
||||||
'辅助按键',
|
|
||||||
function (id, item) {
|
|
||||||
// 辅助按键
|
|
||||||
if (item.assist === KeyCode.Ctrl) {
|
|
||||||
this.assistKey = flipBinary(this.assistKey, 0);
|
|
||||||
} else if (item.assist === KeyCode.Shift) {
|
|
||||||
this.assistKey = flipBinary(this.assistKey, 1);
|
|
||||||
} else if (item.assist === KeyCode.Alt) {
|
|
||||||
this.assistKey = flipBinary(this.assistKey, 2);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
COM.AssistKeyTool,
|
|
||||||
EDITOR.AssistKeyTool,
|
|
||||||
item => {
|
|
||||||
return {
|
|
||||||
assist: KeyCode.Ctrl,
|
|
||||||
...item
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
CustomToolbar.register(
|
|
||||||
'minimap',
|
|
||||||
'小地图',
|
|
||||||
function (id, item) {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
COM.MinimapTool,
|
|
||||||
EDITOR.MinimapTool,
|
|
||||||
item => {
|
|
||||||
return {
|
|
||||||
action: false,
|
|
||||||
scale: 5,
|
|
||||||
width: 300,
|
|
||||||
height: 300,
|
|
||||||
noBorder: false,
|
|
||||||
showInfo: false,
|
|
||||||
autoLocate: true,
|
|
||||||
...item,
|
|
||||||
noDefaultAction: true
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Mota.require('var', 'loading').once('coreInit', () => {
|
Mota.require('var', 'loading').once('coreInit', () => {
|
||||||
CustomToolbar.load();
|
CustomToolbar.load();
|
||||||
CustomToolbar.closeAll();
|
CustomToolbar.closeAll();
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import { KeyCode, KeyCodeUtils } from '@/plugin/keyCodes';
|
import { KeyCode, KeyCodeUtils } from '@/plugin/keyCodes';
|
||||||
import type {
|
import { CustomToolbar } from '../custom/toolbar';
|
||||||
CustomToolbarComponent,
|
|
||||||
CustomToolbarProps
|
|
||||||
} from '../custom/toolbar';
|
|
||||||
import BoxAnimate from '@/components/boxAnimate.vue';
|
import BoxAnimate from '@/components/boxAnimate.vue';
|
||||||
import { checkAssist } from '../custom/hotkey';
|
import { checkAssist, unwarpBinary } from '../custom/hotkey';
|
||||||
import { getVitualKeyOnce } from '@/plugin/utils';
|
import {
|
||||||
|
flipBinary,
|
||||||
|
getVitualKeyOnce,
|
||||||
|
openDanmakuPoster,
|
||||||
|
parseCss
|
||||||
|
} from '@/plugin/utils';
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@ -16,9 +18,76 @@ import {
|
|||||||
} from 'ant-design-vue';
|
} from 'ant-design-vue';
|
||||||
import { mainSetting } from '../setting';
|
import { mainSetting } from '../setting';
|
||||||
import Minimap from '@/components/minimap.vue';
|
import Minimap from '@/components/minimap.vue';
|
||||||
|
import { gameKey } from './hotkey';
|
||||||
|
import { FunctionalComponent, StyleValue, h } from 'vue';
|
||||||
|
import { mainUi } from './ui';
|
||||||
|
import { isMobile } from '@/plugin/use';
|
||||||
|
import { EllipsisOutlined } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
// todo: 新增更改设置的ToolItem
|
// todo: 新增更改设置的ToolItem
|
||||||
|
|
||||||
|
export interface ToolbarItemBase<T extends ToolbarItemType> {
|
||||||
|
type: T;
|
||||||
|
id: string;
|
||||||
|
noDefaultAction?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 快捷键
|
||||||
|
interface HotkeyToolbarItem extends ToolbarItemBase<'hotkey'> {
|
||||||
|
key: KeyCode;
|
||||||
|
assist: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用道具
|
||||||
|
interface ItemToolbarItem extends ToolbarItemBase<'item'> {
|
||||||
|
item: ItemIdOf<'tools' | 'constants'>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换辅助按键 ctrl alt shift
|
||||||
|
interface AssistKeyToolbarItem extends ToolbarItemBase<'assistKey'> {
|
||||||
|
assist: KeyCode.Ctrl | KeyCode.Shift | KeyCode.Alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 小地图
|
||||||
|
interface MinimapToolbar extends ToolbarItemBase<'minimap'> {
|
||||||
|
action: boolean;
|
||||||
|
scale: number;
|
||||||
|
noBorder: boolean;
|
||||||
|
showInfo: boolean;
|
||||||
|
autoLocate: boolean;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 杂项工具栏
|
||||||
|
export interface MiscToolbar extends ToolbarItemBase<'misc'> {
|
||||||
|
folded: boolean;
|
||||||
|
items: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ToolbarItemMap {
|
||||||
|
hotkey: HotkeyToolbarItem;
|
||||||
|
item: ItemToolbarItem;
|
||||||
|
assistKey: AssistKeyToolbarItem;
|
||||||
|
minimap: MinimapToolbar;
|
||||||
|
misc: MiscToolbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ToolbarItemType = keyof ToolbarItemMap;
|
||||||
|
|
||||||
|
export type SettableItemData<T extends ToolbarItemType = ToolbarItemType> =
|
||||||
|
Omit<ToolbarItemMap[T], 'id' | 'type'>;
|
||||||
|
|
||||||
|
export interface CustomToolbarProps<
|
||||||
|
T extends ToolbarItemType = ToolbarItemType
|
||||||
|
> {
|
||||||
|
item: ToolbarItemMap[T];
|
||||||
|
toolbar: CustomToolbar;
|
||||||
|
}
|
||||||
|
export type CustomToolbarComponent<
|
||||||
|
T extends ToolbarItemType = ToolbarItemType
|
||||||
|
> = FunctionalComponent<CustomToolbarProps<T>>;
|
||||||
|
|
||||||
interface Components {
|
interface Components {
|
||||||
DefaultTool: CustomToolbarComponent;
|
DefaultTool: CustomToolbarComponent;
|
||||||
KeyTool: CustomToolbarComponent<'hotkey'>;
|
KeyTool: CustomToolbarComponent<'hotkey'>;
|
||||||
@ -139,6 +208,98 @@ function MinimapTool(props: CustomToolbarProps<'minimap'>) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function MiscTool(props: CustomToolbarProps<'misc'>) {
|
||||||
|
const { item, toolbar } = props;
|
||||||
|
const scale = mainSetting.getValue('ui.toolbarScale', 100) / 100;
|
||||||
|
|
||||||
|
const triggerFold = () => {
|
||||||
|
item.folded = !item.folded;
|
||||||
|
toolbar.refresh();
|
||||||
|
};
|
||||||
|
|
||||||
|
const unfoldStyle = `
|
||||||
|
min-width: ${50 * scale}px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: ${18 * scale}px;
|
||||||
|
`;
|
||||||
|
const blockStyle = `
|
||||||
|
min-width: ${40 * scale}px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: ${40 * scale}px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
`;
|
||||||
|
const toolStyle = `
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: ${40 * scale}px;
|
||||||
|
height: ${40 * scale}px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
margin-left: ${5 * scale}px;
|
||||||
|
justify-content: center;
|
||||||
|
`;
|
||||||
|
const toolActivedStyle = `
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: ${40 * scale}px;
|
||||||
|
height: ${40 * scale}px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
margin-left: ${5 * scale}px;
|
||||||
|
justify-content: center;
|
||||||
|
color: aqua;
|
||||||
|
`;
|
||||||
|
const containerStyle = `
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 ${5 * scale}px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style="display: flex; align-items: center; justify-content: left">
|
||||||
|
{item.folded ? (
|
||||||
|
<div
|
||||||
|
class="button-text"
|
||||||
|
onClick={triggerFold}
|
||||||
|
style={unfoldStyle}
|
||||||
|
>
|
||||||
|
<EllipsisOutlined />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div style={containerStyle}>
|
||||||
|
<span
|
||||||
|
class="button-text"
|
||||||
|
onClick={triggerFold}
|
||||||
|
style={blockStyle}
|
||||||
|
>
|
||||||
|
折叠
|
||||||
|
</span>
|
||||||
|
{item.items.map(v => {
|
||||||
|
const info = CustomToolbar.misc.info[v];
|
||||||
|
const { actived } = info;
|
||||||
|
const style = actived?.(info)
|
||||||
|
? toolActivedStyle
|
||||||
|
: toolStyle;
|
||||||
|
if (!info) return <span></span>;
|
||||||
|
else
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
class="button-text"
|
||||||
|
style={style}
|
||||||
|
onClick={() => info.emit(v, toolbar, item)}
|
||||||
|
>
|
||||||
|
{info.display}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function DefaultToolEditor(props: CustomToolbarProps) {
|
function DefaultToolEditor(props: CustomToolbarProps) {
|
||||||
return <span></span>;
|
return <span></span>;
|
||||||
}
|
}
|
||||||
@ -407,3 +568,332 @@ function MinimapToolEditor(props: CustomToolbarProps<'minimap'>) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function MiscToolEditor(props: CustomToolbarProps<'misc'>) {
|
||||||
|
const { item, toolbar } = props;
|
||||||
|
|
||||||
|
const misc = CustomToolbar.misc.info;
|
||||||
|
const values = Object.values(misc);
|
||||||
|
|
||||||
|
const divStyle = `
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 5px 5%;
|
||||||
|
margin: 1%;
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: 1px solid #888;
|
||||||
|
`;
|
||||||
|
const addStyle = `
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 5%;
|
||||||
|
margin: 1%;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
const containerStyle = `
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={containerStyle}>
|
||||||
|
{item.items.map((v, i) => {
|
||||||
|
return (
|
||||||
|
<div style={divStyle}>
|
||||||
|
<span>第{i + 1}个工具</span>
|
||||||
|
<Select
|
||||||
|
style="width: 180px; font-size: 80%; height: 100%; background-color: #000"
|
||||||
|
value={v}
|
||||||
|
onChange={value =>
|
||||||
|
(item.items[i] = value as string)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{values.map(v => {
|
||||||
|
return (
|
||||||
|
<SelectOption value={v.id}>
|
||||||
|
{v.name}
|
||||||
|
</SelectOption>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<div style={addStyle}>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={() => item.items.push('danmaku')}
|
||||||
|
>
|
||||||
|
新增杂项工具
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomToolbar.register(
|
||||||
|
'hotkey',
|
||||||
|
'快捷键',
|
||||||
|
function (id, item) {
|
||||||
|
// 按键
|
||||||
|
const assist = item.assist | this.assistKey;
|
||||||
|
const { ctrl, shift, alt } = unwarpBinary(assist);
|
||||||
|
const ev = new KeyboardEvent('keyup', {
|
||||||
|
ctrlKey: ctrl,
|
||||||
|
shiftKey: shift,
|
||||||
|
altKey: alt
|
||||||
|
});
|
||||||
|
|
||||||
|
// todo: Advanced KeyboardEvent simulate
|
||||||
|
gameKey.emitKey(item.key, assist, 'up', ev);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
KeyTool,
|
||||||
|
KeyToolEdtior,
|
||||||
|
item => {
|
||||||
|
return {
|
||||||
|
key: KeyCode.Unknown,
|
||||||
|
assist: 0,
|
||||||
|
...item
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
CustomToolbar.register(
|
||||||
|
'item',
|
||||||
|
'使用道具',
|
||||||
|
function (id, item) {
|
||||||
|
// 道具
|
||||||
|
core.tryUseItem(item.item);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
ItemTool,
|
||||||
|
ItemToolEditor,
|
||||||
|
item => {
|
||||||
|
return {
|
||||||
|
item: 'book',
|
||||||
|
...item
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
CustomToolbar.register(
|
||||||
|
'assistKey',
|
||||||
|
'辅助按键',
|
||||||
|
function (id, item) {
|
||||||
|
// 辅助按键
|
||||||
|
if (item.assist === KeyCode.Ctrl) {
|
||||||
|
this.assistKey = flipBinary(this.assistKey, 0);
|
||||||
|
} else if (item.assist === KeyCode.Shift) {
|
||||||
|
this.assistKey = flipBinary(this.assistKey, 1);
|
||||||
|
} else if (item.assist === KeyCode.Alt) {
|
||||||
|
this.assistKey = flipBinary(this.assistKey, 2);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
AssistKeyTool,
|
||||||
|
AssistKeyToolEditor,
|
||||||
|
item => {
|
||||||
|
return {
|
||||||
|
assist: KeyCode.Ctrl,
|
||||||
|
...item
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
CustomToolbar.register(
|
||||||
|
'minimap',
|
||||||
|
'小地图',
|
||||||
|
function (id, item) {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
MinimapTool,
|
||||||
|
MinimapToolEditor,
|
||||||
|
item => {
|
||||||
|
return {
|
||||||
|
action: false,
|
||||||
|
scale: 5,
|
||||||
|
width: 300,
|
||||||
|
height: 300,
|
||||||
|
noBorder: false,
|
||||||
|
showInfo: false,
|
||||||
|
autoLocate: true,
|
||||||
|
...item,
|
||||||
|
noDefaultAction: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
CustomToolbar.register(
|
||||||
|
'misc',
|
||||||
|
'杂项',
|
||||||
|
function (id, item) {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
MiscTool,
|
||||||
|
MiscToolEditor,
|
||||||
|
item => {
|
||||||
|
return {
|
||||||
|
items: [],
|
||||||
|
folded: true,
|
||||||
|
...item,
|
||||||
|
noDefaultAction: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 杂项注册
|
||||||
|
Mota.require('var', 'hook').once('reset', () => {
|
||||||
|
// 小地图是否显示
|
||||||
|
let minimapTool = CustomToolbar.list.some(v => v.id === '@misc/minimap');
|
||||||
|
mainUi.on('close', () => {
|
||||||
|
let before = minimapTool;
|
||||||
|
minimapTool = CustomToolbar.list.some(v => v.id === '@misc/minimap');
|
||||||
|
if (before !== minimapTool) {
|
||||||
|
CustomToolbar.misc.requestRefresh('minimap');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
CustomToolbar.misc.register(
|
||||||
|
'danmaku',
|
||||||
|
'发弹幕',
|
||||||
|
openDanmakuPoster,
|
||||||
|
h('span', '发弹幕')
|
||||||
|
);
|
||||||
|
CustomToolbar.misc.register(
|
||||||
|
'toolbox',
|
||||||
|
'道具栏',
|
||||||
|
() => {
|
||||||
|
mainUi.open('toolbox');
|
||||||
|
},
|
||||||
|
<img
|
||||||
|
src={core.statusBar.icons.toolbox.src}
|
||||||
|
style="object-fit: contain"
|
||||||
|
></img>
|
||||||
|
);
|
||||||
|
CustomToolbar.misc.register(
|
||||||
|
'virtualKey',
|
||||||
|
'虚拟键盘',
|
||||||
|
() => {
|
||||||
|
getVitualKeyOnce();
|
||||||
|
},
|
||||||
|
<img
|
||||||
|
src={core.statusBar.icons.keyboard.src}
|
||||||
|
style="object-fit: contain"
|
||||||
|
></img>
|
||||||
|
);
|
||||||
|
CustomToolbar.misc.register(
|
||||||
|
'shop',
|
||||||
|
'快捷商店',
|
||||||
|
() => {
|
||||||
|
core.openQuickShop(true);
|
||||||
|
},
|
||||||
|
<img
|
||||||
|
src={core.statusBar.icons.shop.src}
|
||||||
|
style="object-fit: contain"
|
||||||
|
></img>
|
||||||
|
);
|
||||||
|
CustomToolbar.misc.register(
|
||||||
|
'save',
|
||||||
|
'存档',
|
||||||
|
() => {
|
||||||
|
core.save(true);
|
||||||
|
},
|
||||||
|
<img
|
||||||
|
src={core.statusBar.icons.save.src}
|
||||||
|
style="object-fit: contain"
|
||||||
|
></img>
|
||||||
|
);
|
||||||
|
CustomToolbar.misc.register(
|
||||||
|
'load',
|
||||||
|
'读档',
|
||||||
|
() => {
|
||||||
|
core.load(true);
|
||||||
|
},
|
||||||
|
<img
|
||||||
|
src={core.statusBar.icons.load.src}
|
||||||
|
style="object-fit: contain"
|
||||||
|
></img>
|
||||||
|
);
|
||||||
|
CustomToolbar.misc.register(
|
||||||
|
'redo',
|
||||||
|
'回退(自动存档)',
|
||||||
|
() => {
|
||||||
|
core.doSL('autoSave', 'load');
|
||||||
|
},
|
||||||
|
h('span', '回退')
|
||||||
|
);
|
||||||
|
CustomToolbar.misc.register(
|
||||||
|
'load',
|
||||||
|
'恢复(撤销自动存档)',
|
||||||
|
() => {
|
||||||
|
core.doSL('autoSave', 'reload');
|
||||||
|
},
|
||||||
|
h('span', '恢复')
|
||||||
|
);
|
||||||
|
CustomToolbar.misc.register(
|
||||||
|
'setting',
|
||||||
|
'系统设置',
|
||||||
|
() => {
|
||||||
|
core.openSettings(true);
|
||||||
|
},
|
||||||
|
<img
|
||||||
|
src={core.statusBar.icons.settings.src}
|
||||||
|
style="object-fit: contain"
|
||||||
|
></img>
|
||||||
|
);
|
||||||
|
CustomToolbar.misc.register(
|
||||||
|
'minimap',
|
||||||
|
'小地图',
|
||||||
|
(id, tool) => {
|
||||||
|
const index = CustomToolbar.list.findIndex(
|
||||||
|
v => v.id === '@misc/minimap'
|
||||||
|
);
|
||||||
|
minimapTool = index !== -1;
|
||||||
|
if (minimapTool) {
|
||||||
|
const tool = CustomToolbar.list[index];
|
||||||
|
tool.closeAll();
|
||||||
|
CustomToolbar.list.splice(index, 1);
|
||||||
|
minimapTool = false;
|
||||||
|
} else {
|
||||||
|
const tool = new CustomToolbar('@misc/minimap', true);
|
||||||
|
const info = CustomToolbar.info['minimap'].onCreate({
|
||||||
|
id: `minimap`,
|
||||||
|
type: 'minimap'
|
||||||
|
}) as MinimapToolbar;
|
||||||
|
info.noBorder = true;
|
||||||
|
info.action = true;
|
||||||
|
info.showInfo = true;
|
||||||
|
if (!isMobile) {
|
||||||
|
tool.x = window.innerWidth - 420;
|
||||||
|
tool.y = 100;
|
||||||
|
tool.width = 320;
|
||||||
|
tool.height = 320;
|
||||||
|
} else {
|
||||||
|
info.width = 150;
|
||||||
|
info.height = 150;
|
||||||
|
tool.x = window.innerWidth - 220;
|
||||||
|
tool.y = 50;
|
||||||
|
tool.width = 170;
|
||||||
|
tool.height = 170;
|
||||||
|
}
|
||||||
|
|
||||||
|
tool.add(info);
|
||||||
|
tool.show();
|
||||||
|
minimapTool = true;
|
||||||
|
}
|
||||||
|
tool.refresh();
|
||||||
|
},
|
||||||
|
h('span', '小地图')
|
||||||
|
);
|
||||||
|
// CustomToolbar.misc.register(
|
||||||
|
// 'drag',
|
||||||
|
// '地图拖动',
|
||||||
|
// () => {
|
||||||
|
// // todo
|
||||||
|
// },
|
||||||
|
// h('span', '拖动地图')
|
||||||
|
// );
|
||||||
|
|
||||||
|
CustomToolbar.misc.bindActivable('minimap', true, () => minimapTool);
|
||||||
|
});
|
||||||
|
@ -191,7 +191,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { CustomToolbar, ToolbarItemType } from '@/core/main/custom/toolbar';
|
import { CustomToolbar } from '@/core/main/custom/toolbar';
|
||||||
import { GameUi } from '@/core/main/custom/ui';
|
import { GameUi } from '@/core/main/custom/ui';
|
||||||
import { computed, onUnmounted, reactive, ref } from 'vue';
|
import { computed, onUnmounted, reactive, ref } from 'vue';
|
||||||
import {
|
import {
|
||||||
@ -205,6 +205,7 @@ import Scroll from '@/components/scroll.vue';
|
|||||||
import { deleteWith, tip } from '@/plugin/utils';
|
import { deleteWith, tip } from '@/plugin/utils';
|
||||||
import { Modal } from 'ant-design-vue';
|
import { Modal } from 'ant-design-vue';
|
||||||
import { mainSetting } from '@/core/main/setting';
|
import { mainSetting } from '@/core/main/setting';
|
||||||
|
import { ToolbarItemType } from '@/core/main/init/toolbar';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
ui: GameUi;
|
ui: GameUi;
|
||||||
|
@ -6,6 +6,7 @@ import vuejsx from '@vitejs/plugin-vue-jsx'
|
|||||||
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
|
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
|
||||||
import motaConfig from './mota.config';
|
import motaConfig from './mota.config';
|
||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
|
import postcssPresetEnv from 'postcss-preset-env';
|
||||||
|
|
||||||
const FSHOST = 'http://127.0.0.1:3000/';
|
const FSHOST = 'http://127.0.0.1:3000/';
|
||||||
|
|
||||||
@ -51,6 +52,9 @@ export default defineConfig({
|
|||||||
less: {
|
less: {
|
||||||
javascriptEnabled: true
|
javascriptEnabled: true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
postcss: {
|
||||||
|
plugins: [postcssPresetEnv()]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
|
Loading…
Reference in New Issue
Block a user