@koishi-ce/client 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/app/home/home.vue +4 -1
- package/app/home/index.ts +2 -1
- package/app/home/welcome.vue +9 -26
- package/app/index.ts +8 -2
- package/app/layout/header.vue +12 -4
- package/app/layout/layout.vue +4 -1
- package/app/layout/menu-item.vue +3 -1
- package/app/settings/index.ts +3 -2
- package/app/settings/settings.vue +9 -7
- package/app/settings/theme.vue +4 -1
- package/app/status/loading.vue +7 -2
- package/app/theme/activity/button.vue +4 -1
- package/app/theme/activity/index.vue +12 -4
- package/app/theme/activity/item.vue +18 -4
- package/app/theme/activity/separator.vue +44 -12
- package/app/theme/blank.vue +7 -1
- package/app/theme/index.ts +7 -2
- package/app/theme/index.vue +6 -2
- package/app/theme/menu/menu-item.vue +10 -4
- package/app/theme/menu/menu.vue +9 -4
- package/client/components/chat/overlay.vue +38 -13
- package/client/components/common/k-hint.vue +3 -1
- package/client/components/dynamic.vue +2 -1
- package/client/components/icons/index.ts +7 -2
- package/client/components/index.ts +8 -2
- package/client/components/link.ts +5 -2
- package/client/components/perms.vue +22 -5
- package/client/components/slot.ts +19 -4
- package/client/context.ts +12 -4
- package/client/data.ts +57 -26
- package/client/index.ts +2 -1
- package/client/locales/de-DE.yml +47 -0
- package/client/locales/en-US.yml +47 -0
- package/client/locales/fr-FR.yml +47 -0
- package/client/locales/ja-JP.yml +47 -0
- package/client/locales/ru-RU.yml +47 -0
- package/client/locales/zh-CN.yml +47 -0
- package/client/locales/zh-TW.yml +47 -0
- package/client/plugins/action.ts +46 -13
- package/client/plugins/i18n.ts +118 -3
- package/client/plugins/loader.ts +67 -45
- package/client/plugins/router.ts +34 -11
- package/client/plugins/setting.ts +60 -16
- package/client/plugins/theme.ts +51 -11
- package/client/utils.ts +7 -2
- package/lib/bin.mjs +3 -3
- package/lib/{client-CaTn_gVG.mjs → client-C97iYPCr.mjs} +1 -1
- package/lib/index.d.ts +3 -4
- package/lib/index.mjs +1 -1
- package/lib/{src-DXaM1Kgh.mjs → src-BOakssV3.mjs} +2 -2
- package/package.json +3 -3
- package/src/bin.ts +10 -3
- package/src/index.ts +59 -15
- package/app/home/welcome.en-US.yml +0 -13
- package/app/home/welcome.zh-CN.yml +0 -13
|
@@ -18,19 +18,19 @@
|
|
|
18
18
|
<k-icon name="chevron-right"/>
|
|
19
19
|
</span>
|
|
20
20
|
<span class="button bottom" @click.stop>
|
|
21
|
-
<el-tooltip placement="top" content="
|
|
21
|
+
<el-tooltip placement="top" :content="t('overlay.zoomOut')" :offset="20">
|
|
22
22
|
<k-icon name="search-minus" @click="scale -= 0.2"/>
|
|
23
23
|
</el-tooltip>
|
|
24
|
-
<el-tooltip placement="top" content="
|
|
24
|
+
<el-tooltip placement="top" :content="t('overlay.zoomIn')" :offset="20">
|
|
25
25
|
<k-icon name="search-plus" @click="scale += 0.2"/>
|
|
26
26
|
</el-tooltip>
|
|
27
|
-
<el-tooltip placement="top" content="
|
|
27
|
+
<el-tooltip placement="top" :content="t('overlay.reset')" :offset="20">
|
|
28
28
|
<k-icon name="expand" @click="scale = 1, rotate = 0"/>
|
|
29
29
|
</el-tooltip>
|
|
30
|
-
<el-tooltip placement="top" content="
|
|
30
|
+
<el-tooltip placement="top" :content="t('overlay.rotateLeft')" :offset="20">
|
|
31
31
|
<k-icon name="undo" @click="rotate -= 90"/>
|
|
32
32
|
</el-tooltip>
|
|
33
|
-
<el-tooltip placement="top" content="
|
|
33
|
+
<el-tooltip placement="top" :content="t('overlay.rotateRight')" :offset="20">
|
|
34
34
|
<k-icon name="redo" @click="rotate += 90"/>
|
|
35
35
|
</el-tooltip>
|
|
36
36
|
</span>
|
|
@@ -42,9 +42,18 @@
|
|
|
42
42
|
</template>
|
|
43
43
|
|
|
44
44
|
<script lang="ts" setup>
|
|
45
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
computed,
|
|
47
|
+
onBeforeUnmount,
|
|
48
|
+
onMounted,
|
|
49
|
+
ref,
|
|
50
|
+
watch,
|
|
51
|
+
} from "vue";
|
|
52
|
+
import { useI18n } from "vue-i18n";
|
|
46
53
|
import { shared } from "./utils";
|
|
47
54
|
|
|
55
|
+
const { t } = useI18n();
|
|
56
|
+
|
|
48
57
|
// 用户手动调整的缩放与旋转量(复原即回到 1 / 0)
|
|
49
58
|
const scale = ref(1);
|
|
50
59
|
const rotate = ref(0);
|
|
@@ -58,7 +67,9 @@ const transform = computed(() => {
|
|
|
58
67
|
const siblings = computed(() => {
|
|
59
68
|
if (!shared.overlayImage) return;
|
|
60
69
|
const elements = Array.from(
|
|
61
|
-
document.querySelectorAll<HTMLImageElement>(
|
|
70
|
+
document.querySelectorAll<HTMLImageElement>(
|
|
71
|
+
".chat-image",
|
|
72
|
+
),
|
|
62
73
|
);
|
|
63
74
|
const index = elements.indexOf(shared.overlayImage);
|
|
64
75
|
return {
|
|
@@ -69,10 +80,15 @@ const siblings = computed(() => {
|
|
|
69
80
|
|
|
70
81
|
// 初始(适配屏幕)缩放比:按视口剩余空间把图片等比缩小,不放大
|
|
71
82
|
const defaultScale = computed(() => {
|
|
72
|
-
const { naturalHeight, naturalWidth } =
|
|
83
|
+
const { naturalHeight, naturalWidth } =
|
|
84
|
+
shared.overlayImage;
|
|
73
85
|
const maxHeight = innerHeight - paddingVertical * 2;
|
|
74
86
|
const maxWidth = innerWidth - paddingHorizontal * 2;
|
|
75
|
-
return Math.min(
|
|
87
|
+
return Math.min(
|
|
88
|
+
1,
|
|
89
|
+
maxHeight / naturalHeight,
|
|
90
|
+
maxWidth / naturalWidth,
|
|
91
|
+
);
|
|
76
92
|
});
|
|
77
93
|
|
|
78
94
|
// 切换/关闭查看器时重置手动缩放与旋转;
|
|
@@ -96,7 +112,10 @@ function setImage(el: HTMLImageElement) {
|
|
|
96
112
|
}
|
|
97
113
|
|
|
98
114
|
/** 把大图元素摆到原图片所在的位置与尺寸(关闭时的"飞回"动画终点) */
|
|
99
|
-
function moveToOrigin(
|
|
115
|
+
function moveToOrigin(
|
|
116
|
+
el: HTMLImageElement,
|
|
117
|
+
origin = shared.overlayImage,
|
|
118
|
+
) {
|
|
100
119
|
const { height, width } = origin;
|
|
101
120
|
const { left, top } = origin.getBoundingClientRect();
|
|
102
121
|
el.style.width = `${width}px`;
|
|
@@ -112,7 +131,8 @@ const paddingHorizontal = 0;
|
|
|
112
131
|
|
|
113
132
|
/** 把图片按适配缩放比居中摆放到视口中央 */
|
|
114
133
|
function moveToCenter(el: HTMLImageElement) {
|
|
115
|
-
const { naturalHeight, naturalWidth } =
|
|
134
|
+
const { naturalHeight, naturalWidth } =
|
|
135
|
+
shared.overlayImage;
|
|
116
136
|
const scale = defaultScale.value;
|
|
117
137
|
const width = naturalWidth * scale;
|
|
118
138
|
const height = naturalHeight * scale;
|
|
@@ -136,13 +156,18 @@ function onKeyDown(ev: KeyboardEvent) {
|
|
|
136
156
|
ev.preventDefault();
|
|
137
157
|
if (ev.key === "ArrowUp" || ev.key === "ArrowLeft") {
|
|
138
158
|
setImage(siblings.value.prev);
|
|
139
|
-
} else if (
|
|
159
|
+
} else if (
|
|
160
|
+
ev.key === "ArrowDown" ||
|
|
161
|
+
ev.key === "ArrowRight"
|
|
162
|
+
) {
|
|
140
163
|
setImage(siblings.value.next);
|
|
141
164
|
} else if (ev.key === "Escape") {
|
|
142
165
|
setImage(null);
|
|
143
166
|
} else if (ev.key === "Enter") {
|
|
144
167
|
// 关闭并把页面滚动到原图所在位置,便于继续浏览消息
|
|
145
|
-
shared.overlayImage.offsetParent.scrollIntoView({
|
|
168
|
+
shared.overlayImage.offsetParent.scrollIntoView({
|
|
169
|
+
behavior: "smooth",
|
|
170
|
+
});
|
|
146
171
|
setImage(null);
|
|
147
172
|
}
|
|
148
173
|
}
|
|
@@ -32,7 +32,9 @@ const props = defineProps({
|
|
|
32
32
|
const emit = defineEmits(["update:modelValue"]);
|
|
33
33
|
|
|
34
34
|
// modelValue 被显式传入时才呈现手型光标并响应点击(开关语义)
|
|
35
|
-
const pointer = computed(
|
|
35
|
+
const pointer = computed(
|
|
36
|
+
() => props.modelValue !== undefined,
|
|
37
|
+
);
|
|
36
38
|
|
|
37
39
|
function onClick() {
|
|
38
40
|
if (!pointer.value) return;
|
|
@@ -58,7 +58,8 @@ defineEmits(["update:modelValue"]);
|
|
|
58
58
|
// 按本地 schema 标注的名称,从服务端下发的 schema 仓库中取出完整定义;
|
|
59
59
|
// 元信息做一层合并,保留本地的 meta 覆盖权
|
|
60
60
|
const inner = computed(() => {
|
|
61
|
-
const hydrated =
|
|
61
|
+
const hydrated =
|
|
62
|
+
store.schema?.[props.schema?.meta.extra?.name];
|
|
62
63
|
return hydrated && new Schema(hydrated);
|
|
63
64
|
});
|
|
64
65
|
</script>
|
|
@@ -116,7 +116,10 @@ register("undo", Undo);
|
|
|
116
116
|
register("user", User);
|
|
117
117
|
|
|
118
118
|
/** 向注册表登记一个图标(markRaw 避免组件被响应式代理) */
|
|
119
|
-
export function register(
|
|
119
|
+
export function register(
|
|
120
|
+
name: string,
|
|
121
|
+
component: Component,
|
|
122
|
+
) {
|
|
120
123
|
registry[name] = markRaw(component);
|
|
121
124
|
}
|
|
122
125
|
|
|
@@ -129,7 +132,9 @@ export function install(app: App) {
|
|
|
129
132
|
name: String,
|
|
130
133
|
},
|
|
131
134
|
render(props: { name?: string }) {
|
|
132
|
-
const component = props.name
|
|
135
|
+
const component = props.name
|
|
136
|
+
? registry[props.name]
|
|
137
|
+
: undefined;
|
|
133
138
|
return component && h(component);
|
|
134
139
|
},
|
|
135
140
|
}),
|
|
@@ -15,10 +15,16 @@
|
|
|
15
15
|
// 无法解析(无 paths),故直接相对导入工作区内该包的浏览器端入口,
|
|
16
16
|
// 与构建器 collectWorkspaceAliases 的映射目标一致
|
|
17
17
|
|
|
18
|
-
import Element, {
|
|
18
|
+
import Element, {
|
|
19
|
+
ElLoading,
|
|
20
|
+
ElMessage,
|
|
21
|
+
ElMessageBox,
|
|
22
|
+
} from "element-plus";
|
|
19
23
|
import Markdown from "marked-vue";
|
|
20
24
|
import type { App } from "vue";
|
|
21
|
-
import components, {
|
|
25
|
+
import components, {
|
|
26
|
+
SchemaBase,
|
|
27
|
+
} from "../../../components/client/index.ts";
|
|
22
28
|
|
|
23
29
|
import { store } from "../data";
|
|
24
30
|
import ChatImage from "./chat/image.vue";
|
|
@@ -21,7 +21,9 @@ const KActivityLink = defineComponent({
|
|
|
21
21
|
setup(props, { slots }) {
|
|
22
22
|
const ctx = useContext();
|
|
23
23
|
return () => {
|
|
24
|
-
const activity = props.id
|
|
24
|
+
const activity = props.id
|
|
25
|
+
? ctx.$router.pages[props.id]
|
|
26
|
+
: undefined;
|
|
25
27
|
return h(
|
|
26
28
|
RouterLink,
|
|
27
29
|
{
|
|
@@ -30,7 +32,8 @@ const KActivityLink = defineComponent({
|
|
|
30
32
|
activity?.path.replace(/:.+/, "")) as string,
|
|
31
33
|
},
|
|
32
34
|
{
|
|
33
|
-
default: () =>
|
|
35
|
+
default: () =>
|
|
36
|
+
slots["default"]?.() ?? activity?.name,
|
|
34
37
|
},
|
|
35
38
|
);
|
|
36
39
|
};
|
|
@@ -32,7 +32,10 @@
|
|
|
32
32
|
// schemastery-vue 链接(它是 components 的依赖,Bun 隔离布局下不跨包可见)
|
|
33
33
|
|
|
34
34
|
import { store } from "@koishi-ce/client";
|
|
35
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
type Schema,
|
|
37
|
+
SchemaBase,
|
|
38
|
+
} from "@koishi-ce/components";
|
|
36
39
|
import type { CascaderOption } from "element-plus";
|
|
37
40
|
import { computed, type PropType } from "vue";
|
|
38
41
|
|
|
@@ -53,15 +56,29 @@ const config = SchemaBase.useModel();
|
|
|
53
56
|
* 逐段查找/创建级联节点;中间段(还有下级时)标记为 disabled,
|
|
54
57
|
* 因为 el-cascader 的父节点勾选会影响子级,而中间段并非真实权限。
|
|
55
58
|
*/
|
|
56
|
-
function addNode(
|
|
59
|
+
function addNode(
|
|
60
|
+
nodes: CascaderOption[],
|
|
61
|
+
path: string[],
|
|
62
|
+
prefix = "",
|
|
63
|
+
) {
|
|
57
64
|
const name = path.shift();
|
|
58
|
-
let node = nodes.find(
|
|
65
|
+
let node = nodes.find(
|
|
66
|
+
(node) => node.value === prefix + name,
|
|
67
|
+
);
|
|
59
68
|
if (!node) {
|
|
60
|
-
node = {
|
|
69
|
+
node = {
|
|
70
|
+
value: prefix + name,
|
|
71
|
+
label: name,
|
|
72
|
+
disabled: !!path.length,
|
|
73
|
+
};
|
|
61
74
|
nodes.push(node);
|
|
62
75
|
}
|
|
63
76
|
if (!path.length) return;
|
|
64
|
-
addNode(
|
|
77
|
+
addNode(
|
|
78
|
+
(node.children ||= []),
|
|
79
|
+
path,
|
|
80
|
+
`${prefix + name}:`,
|
|
81
|
+
);
|
|
65
82
|
}
|
|
66
83
|
|
|
67
84
|
// 由全部权限名构建级联选项树
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
// Copyright (c) 2019-present Shigma and Koishijs contributors.
|
|
3
3
|
// Copyright (c) 2026-present Koishi-CE contributors.
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
type App,
|
|
7
|
+
type Component,
|
|
8
|
+
defineComponent,
|
|
9
|
+
h,
|
|
10
|
+
} from "vue";
|
|
6
11
|
import { useContext } from "../context";
|
|
7
12
|
|
|
8
13
|
/** 插槽条目的基础形状:参与排序的组件 */
|
|
@@ -47,10 +52,15 @@ export const KSlot = defineComponent({
|
|
|
47
52
|
? []
|
|
48
53
|
: [...(slots["default"]?.() || [])]
|
|
49
54
|
.filter((node) => node.type === KSlotItem)
|
|
50
|
-
.map((node) => ({
|
|
55
|
+
.map((node) => ({
|
|
56
|
+
node,
|
|
57
|
+
order: node.props?.["order"] || 0,
|
|
58
|
+
}));
|
|
51
59
|
// external:ctx.slot() 注册的视图,disabled 的不渲染
|
|
52
60
|
const external = [
|
|
53
|
-
...(props.name
|
|
61
|
+
...(props.name
|
|
62
|
+
? ctx.$router.views[props.name] || []
|
|
63
|
+
: []),
|
|
54
64
|
]
|
|
55
65
|
.filter((item) => !item.disabled?.())
|
|
56
66
|
.map((item) => ({
|
|
@@ -85,7 +95,12 @@ function defineSlotComponent(name: string) {
|
|
|
85
95
|
return defineComponent({
|
|
86
96
|
inheritAttrs: false,
|
|
87
97
|
setup(_, { slots, attrs }) {
|
|
88
|
-
return () =>
|
|
98
|
+
return () =>
|
|
99
|
+
h(
|
|
100
|
+
KSlot,
|
|
101
|
+
{ name, data: attrs, single: true },
|
|
102
|
+
slots,
|
|
103
|
+
);
|
|
89
104
|
},
|
|
90
105
|
});
|
|
91
106
|
}
|
package/client/context.ts
CHANGED
|
@@ -26,7 +26,8 @@ import ThemeService from "./plugins/theme";
|
|
|
26
26
|
// —— 布局相关的 Context 类型扩展 ——
|
|
27
27
|
|
|
28
28
|
/** 前端侧事件表:在 cordis 事件的基础上扩展本库自定义事件 */
|
|
29
|
-
export interface Events<C extends Context = Context>
|
|
29
|
+
export interface Events<C extends Context = Context>
|
|
30
|
+
extends cordis.Events<C> {}
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* 前端 Context 接口:各服务插件通过 `declare module "../context"`
|
|
@@ -84,7 +85,10 @@ export class Context extends cordis.Context {
|
|
|
84
85
|
this.app = createApp(
|
|
85
86
|
defineComponent({
|
|
86
87
|
setup: () => () => [
|
|
87
|
-
h(resolveComponent("k-slot"), {
|
|
88
|
+
h(resolveComponent("k-slot"), {
|
|
89
|
+
name: "root",
|
|
90
|
+
single: true,
|
|
91
|
+
}),
|
|
88
92
|
h(resolveComponent("k-slot"), { name: "global" }),
|
|
89
93
|
],
|
|
90
94
|
}),
|
|
@@ -115,12 +119,16 @@ export class Context extends cordis.Context {
|
|
|
115
119
|
*/
|
|
116
120
|
addEventListener<K extends keyof WindowEventMap>(
|
|
117
121
|
type: K,
|
|
118
|
-
listener: (
|
|
122
|
+
listener: (
|
|
123
|
+
this: Window,
|
|
124
|
+
ev: WindowEventMap[K],
|
|
125
|
+
) => unknown,
|
|
119
126
|
options?: boolean | AddEventListenerOptions,
|
|
120
127
|
) {
|
|
121
128
|
return this.effect(() => {
|
|
122
129
|
window.addEventListener(type, listener, options);
|
|
123
|
-
return () =>
|
|
130
|
+
return () =>
|
|
131
|
+
window.removeEventListener(type, listener, options);
|
|
124
132
|
});
|
|
125
133
|
}
|
|
126
134
|
|
package/client/data.ts
CHANGED
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
// Copyright (c) 2026-present Koishi-CE contributors.
|
|
4
4
|
|
|
5
5
|
/// <reference path="./shims.d.ts" />
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
Promisify,
|
|
8
|
+
Universal,
|
|
9
|
+
} from "@koishi-ce/koishi";
|
|
7
10
|
import type {
|
|
8
11
|
ClientConfig,
|
|
9
12
|
Console,
|
|
@@ -43,7 +46,8 @@ export function withProxy(url: string) {
|
|
|
43
46
|
/** 当前与服务端的 WebSocket 连接(未连接时为 null) */
|
|
44
47
|
export const socket = ref<Universal.WebSocket | null>(null);
|
|
45
48
|
/** 按事件名登记的推送监听器(receive 注册) */
|
|
46
|
-
const listeners: Record<string, (data: unknown) => void> =
|
|
49
|
+
const listeners: Record<string, (data: unknown) => void> =
|
|
50
|
+
{};
|
|
47
51
|
/** 按报文 id 暂存的 RPC 应答钩子 [resolve, reject](send 写入) */
|
|
48
52
|
const responseHooks: Record<
|
|
49
53
|
string,
|
|
@@ -93,19 +97,26 @@ type StoreValue = Store[keyof Store];
|
|
|
93
97
|
|
|
94
98
|
// 服务端整表推送:直接覆盖 store 中对应键
|
|
95
99
|
// (key 为联合类型时直写 store[key] 会被要求交叉类型,故经 Record 视图写入)
|
|
96
|
-
receive<{ key: keyof Store; value: unknown }>(
|
|
97
|
-
|
|
98
|
-
})
|
|
100
|
+
receive<{ key: keyof Store; value: unknown }>(
|
|
101
|
+
"data",
|
|
102
|
+
({ key, value }) => {
|
|
103
|
+
(store as Record<keyof Store, StoreValue>)[key] =
|
|
104
|
+
value as StoreValue;
|
|
105
|
+
},
|
|
106
|
+
);
|
|
99
107
|
|
|
100
108
|
// 服务端增量推送:数组做追加,对象做浅合并
|
|
101
|
-
receive<{ key: keyof Store; value: unknown }>(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
receive<{ key: keyof Store; value: unknown }>(
|
|
110
|
+
"patch",
|
|
111
|
+
({ key, value }) => {
|
|
112
|
+
const current = store[key];
|
|
113
|
+
if (Array.isArray(current)) {
|
|
114
|
+
(current as unknown[]).push(...(value as unknown[]));
|
|
115
|
+
} else if (current) {
|
|
116
|
+
Object.assign(current, value);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
);
|
|
109
120
|
|
|
110
121
|
// RPC 应答分发:按报文 id 找到 send() 留下的 resolve/reject 并结算
|
|
111
122
|
receive<{ id: string; value?: unknown; error?: unknown }>(
|
|
@@ -131,7 +142,10 @@ receive<{ id: string; value?: unknown; error?: unknown }>(
|
|
|
131
142
|
* @param ctx 根 Context,用于把消息转发为 cordis 事件
|
|
132
143
|
* @param callback 创建 WebSocket 实例的工厂函数
|
|
133
144
|
*/
|
|
134
|
-
export function connect(
|
|
145
|
+
export function connect(
|
|
146
|
+
ctx: Context,
|
|
147
|
+
callback: () => Universal.WebSocket,
|
|
148
|
+
) {
|
|
135
149
|
const value = callback();
|
|
136
150
|
|
|
137
151
|
let sendTimer: number;
|
|
@@ -142,8 +156,14 @@ export function connect(ctx: Context, callback: () => Universal.WebSocket) {
|
|
|
142
156
|
if (!global.heartbeat) return;
|
|
143
157
|
clearTimeout(sendTimer);
|
|
144
158
|
clearTimeout(closeTimer);
|
|
145
|
-
sendTimer = +setTimeout(
|
|
146
|
-
|
|
159
|
+
sendTimer = +setTimeout(
|
|
160
|
+
() => send("ping"),
|
|
161
|
+
global.heartbeat.interval,
|
|
162
|
+
);
|
|
163
|
+
closeTimer = +setTimeout(
|
|
164
|
+
() => value?.close(),
|
|
165
|
+
global.heartbeat.timeout,
|
|
166
|
+
);
|
|
147
167
|
};
|
|
148
168
|
|
|
149
169
|
const reconnect = () => {
|
|
@@ -152,10 +172,14 @@ export function connect(ctx: Context, callback: () => Universal.WebSocket) {
|
|
|
152
172
|
for (const key in store) {
|
|
153
173
|
(store as Record<string, unknown>)[key] = undefined;
|
|
154
174
|
}
|
|
155
|
-
console.log(
|
|
175
|
+
console.log(
|
|
176
|
+
"[koishi] websocket disconnected, will retry in 1s...",
|
|
177
|
+
);
|
|
156
178
|
setTimeout(() => {
|
|
157
179
|
connect(ctx, callback).then(location.reload, () => {
|
|
158
|
-
console.log(
|
|
180
|
+
console.log(
|
|
181
|
+
"[koishi] websocket disconnected, will retry in 1s...",
|
|
182
|
+
);
|
|
159
183
|
});
|
|
160
184
|
}, 1000);
|
|
161
185
|
};
|
|
@@ -163,7 +187,12 @@ export function connect(ctx: Context, callback: () => Universal.WebSocket) {
|
|
|
163
187
|
value.addEventListener("message", (ev) => {
|
|
164
188
|
refresh();
|
|
165
189
|
const data = JSON.parse(ev.data);
|
|
166
|
-
console.debug(
|
|
190
|
+
console.debug(
|
|
191
|
+
"↓%c",
|
|
192
|
+
"color:purple",
|
|
193
|
+
data.type,
|
|
194
|
+
data.body,
|
|
195
|
+
);
|
|
167
196
|
if (data.type in listeners) {
|
|
168
197
|
listeners[data.type]?.(data.body);
|
|
169
198
|
}
|
|
@@ -172,11 +201,13 @@ export function connect(ctx: Context, callback: () => Universal.WebSocket) {
|
|
|
172
201
|
|
|
173
202
|
value.addEventListener("close", reconnect);
|
|
174
203
|
|
|
175
|
-
return new Promise<Universal.WebSocket.Event>(
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
204
|
+
return new Promise<Universal.WebSocket.Event>(
|
|
205
|
+
(resolve, reject) => {
|
|
206
|
+
value.addEventListener("open", (event) => {
|
|
207
|
+
socket.value = markRaw(value);
|
|
208
|
+
resolve(event);
|
|
209
|
+
});
|
|
210
|
+
value.addEventListener("error", reject);
|
|
211
|
+
},
|
|
212
|
+
);
|
|
182
213
|
}
|
package/client/index.ts
CHANGED
|
@@ -37,7 +37,8 @@ export const ScopeStatus = {
|
|
|
37
37
|
DISPOSED: 4,
|
|
38
38
|
} as const;
|
|
39
39
|
|
|
40
|
-
export type ScopeStatus =
|
|
40
|
+
export type ScopeStatus =
|
|
41
|
+
(typeof ScopeStatus)[keyof typeof ScopeStatus];
|
|
41
42
|
export * from "./components";
|
|
42
43
|
export * from "./context";
|
|
43
44
|
export * from "./data";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
# Copyright (c) 2019-present Shigma and Koishijs contributors.
|
|
3
|
+
# Copyright (c) 2026-present Koishi-CE contributors.
|
|
4
|
+
|
|
5
|
+
pages:
|
|
6
|
+
home: Willkommen
|
|
7
|
+
settings: Benutzereinstellungen
|
|
8
|
+
home:
|
|
9
|
+
connecting: Verbindung zum Koishi-Server wird hergestellt...
|
|
10
|
+
welcome:
|
|
11
|
+
title: Willkommen bei Koishi!
|
|
12
|
+
description: Ihr Chatbot ist einsatzbereit. Wählen Sie eine der Optionen unten, um Ihre Koishi-Reise zu beginnen.
|
|
13
|
+
docs:
|
|
14
|
+
title: Dokumentation
|
|
15
|
+
description: Lesen Sie die offizielle Dokumentation. Sie enthält alles, was Sie wissen möchten.
|
|
16
|
+
forum:
|
|
17
|
+
title: Forum
|
|
18
|
+
description: Tauschen Sie sich im Forum mit anderen Nutzern aus. Wenn Probleme auftreten, finden Sie dort Hilfe.
|
|
19
|
+
settings:
|
|
20
|
+
general: Allgemeine Einstellungen
|
|
21
|
+
appearance: Erscheinungsbild
|
|
22
|
+
status: Statusleisten-Einstellungen
|
|
23
|
+
loading:
|
|
24
|
+
page: Seitenkomponenten werden geladen
|
|
25
|
+
data: Daten werden geladen...
|
|
26
|
+
blank:
|
|
27
|
+
hint: Wenn Sie diese Seite sehen, wurde das Konsolen-Plugin erfolgreich geladen, aber es sind noch keine Konsolen-Erweiterungen installiert.
|
|
28
|
+
menu:
|
|
29
|
+
resetActivity: Aktivitätsleiste zurücksetzen
|
|
30
|
+
overlay:
|
|
31
|
+
zoomOut: Verkleinern
|
|
32
|
+
zoomIn: Vergrößern
|
|
33
|
+
reset: Zurücksetzen
|
|
34
|
+
rotateLeft: Gegen den Uhrzeigersinn drehen
|
|
35
|
+
rotateRight: Im Uhrzeigersinn drehen
|
|
36
|
+
schema:
|
|
37
|
+
settings:
|
|
38
|
+
$description: Allgemeine Einstellungen
|
|
39
|
+
locale: Spracheinstellungen.
|
|
40
|
+
theme:
|
|
41
|
+
$description: Design-Einstellungen
|
|
42
|
+
mode: Design-Präferenz.
|
|
43
|
+
mode-auto: System folgen
|
|
44
|
+
mode-dark: Dunkel
|
|
45
|
+
mode-light: Hell
|
|
46
|
+
dark: Dunkles Design.
|
|
47
|
+
light: Helles Design.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
# Copyright (c) 2019-present Shigma and Koishijs contributors.
|
|
3
|
+
# Copyright (c) 2026-present Koishi-CE contributors.
|
|
4
|
+
|
|
5
|
+
pages:
|
|
6
|
+
home: Welcome
|
|
7
|
+
settings: User Settings
|
|
8
|
+
home:
|
|
9
|
+
connecting: Connecting to the Koishi server...
|
|
10
|
+
welcome:
|
|
11
|
+
title: Welcome to Koishi!
|
|
12
|
+
description: Your chatbot is ready to go. Pick any option below to start your Koishi journey.
|
|
13
|
+
docs:
|
|
14
|
+
title: Documentation
|
|
15
|
+
description: Read the official documentation, which contains everything you want to know.
|
|
16
|
+
forum:
|
|
17
|
+
title: Forum
|
|
18
|
+
description: Talk with other users on the forum. If you run into problems, you can always ask for help there.
|
|
19
|
+
settings:
|
|
20
|
+
general: General Settings
|
|
21
|
+
appearance: Appearance
|
|
22
|
+
status: Status Bar Settings
|
|
23
|
+
loading:
|
|
24
|
+
page: Loading page components
|
|
25
|
+
data: Loading data...
|
|
26
|
+
blank:
|
|
27
|
+
hint: If you are seeing this page, the console plugin has loaded successfully, but no console extensions are installed yet.
|
|
28
|
+
menu:
|
|
29
|
+
resetActivity: Reset Activity Bar
|
|
30
|
+
overlay:
|
|
31
|
+
zoomOut: Zoom out
|
|
32
|
+
zoomIn: Zoom in
|
|
33
|
+
reset: Reset
|
|
34
|
+
rotateLeft: Rotate counterclockwise
|
|
35
|
+
rotateRight: Rotate clockwise
|
|
36
|
+
schema:
|
|
37
|
+
settings:
|
|
38
|
+
$description: General Settings
|
|
39
|
+
locale: Language settings.
|
|
40
|
+
theme:
|
|
41
|
+
$description: Theme Settings
|
|
42
|
+
mode: Theme preference.
|
|
43
|
+
mode-auto: Follow system
|
|
44
|
+
mode-dark: Dark
|
|
45
|
+
mode-light: Light
|
|
46
|
+
dark: Dark theme.
|
|
47
|
+
light: Light theme.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
# Copyright (c) 2019-present Shigma and Koishijs contributors.
|
|
3
|
+
# Copyright (c) 2026-present Koishi-CE contributors.
|
|
4
|
+
|
|
5
|
+
pages:
|
|
6
|
+
home: Accueil
|
|
7
|
+
settings: Paramètres utilisateur
|
|
8
|
+
home:
|
|
9
|
+
connecting: Connexion au serveur Koishi...
|
|
10
|
+
welcome:
|
|
11
|
+
title: Bienvenue sur Koishi !
|
|
12
|
+
description: Votre chatbot est prêt. Choisissez une option ci-dessous pour commencer votre aventure Koishi.
|
|
13
|
+
docs:
|
|
14
|
+
title: Documentation
|
|
15
|
+
description: "Lisez la documentation officielle : elle contient tout ce que vous voulez savoir."
|
|
16
|
+
forum:
|
|
17
|
+
title: Forum
|
|
18
|
+
description: Échangez avec d'autres utilisateurs sur le forum. Si vous rencontrez des problèmes, vous pouvez y demander de l'aide.
|
|
19
|
+
settings:
|
|
20
|
+
general: Paramètres généraux
|
|
21
|
+
appearance: Apparence
|
|
22
|
+
status: Paramètres de la barre d'état
|
|
23
|
+
loading:
|
|
24
|
+
page: Chargement des composants de la page
|
|
25
|
+
data: Chargement des données...
|
|
26
|
+
blank:
|
|
27
|
+
hint: Si vous voyez cette page, le plugin console s'est chargé avec succès, mais aucune extension de console n'est installée.
|
|
28
|
+
menu:
|
|
29
|
+
resetActivity: Réinitialiser la barre d'activités
|
|
30
|
+
overlay:
|
|
31
|
+
zoomOut: Réduire
|
|
32
|
+
zoomIn: Agrandir
|
|
33
|
+
reset: Réinitialiser
|
|
34
|
+
rotateLeft: Pivoter dans le sens antihoraire
|
|
35
|
+
rotateRight: Pivoter dans le sens horaire
|
|
36
|
+
schema:
|
|
37
|
+
settings:
|
|
38
|
+
$description: Paramètres généraux
|
|
39
|
+
locale: Paramètres de langue.
|
|
40
|
+
theme:
|
|
41
|
+
$description: Paramètres du thème
|
|
42
|
+
mode: Préférence de thème.
|
|
43
|
+
mode-auto: Suivre le système
|
|
44
|
+
mode-dark: Sombre
|
|
45
|
+
mode-light: Clair
|
|
46
|
+
dark: Thème sombre.
|
|
47
|
+
light: Thème clair.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
# Copyright (c) 2019-present Shigma and Koishijs contributors.
|
|
3
|
+
# Copyright (c) 2026-present Koishi-CE contributors.
|
|
4
|
+
|
|
5
|
+
pages:
|
|
6
|
+
home: ホーム
|
|
7
|
+
settings: ユーザー設定
|
|
8
|
+
home:
|
|
9
|
+
connecting: Koishi サーバーに接続しています……
|
|
10
|
+
welcome:
|
|
11
|
+
title: Koishi へようこそ!
|
|
12
|
+
description: ボットの準備が整いました。以下の選択肢からどれかを選んで、Koishi の旅を始めましょう。
|
|
13
|
+
docs:
|
|
14
|
+
title: ドキュメントを読む
|
|
15
|
+
description: 公式ドキュメントを読み始めましょう。知りたいことがすべて書かれています。
|
|
16
|
+
forum:
|
|
17
|
+
title: フォーラムへ
|
|
18
|
+
description: フォーラムで他のユーザーと交流しましょう。問題が起きたときは、ここで助けを求めることができます。
|
|
19
|
+
settings:
|
|
20
|
+
general: 一般設定
|
|
21
|
+
appearance: 外観設定
|
|
22
|
+
status: ステータスバー設定
|
|
23
|
+
loading:
|
|
24
|
+
page: ページコンポーネントを読み込み中
|
|
25
|
+
data: データを読み込み中……
|
|
26
|
+
blank:
|
|
27
|
+
hint: このページが表示されている場合、コンソールプラグインの読み込みには成功していますが、コンソール拡張がまだインストールされていません。
|
|
28
|
+
menu:
|
|
29
|
+
resetActivity: アクティビティバーをリセット
|
|
30
|
+
overlay:
|
|
31
|
+
zoomOut: 縮小
|
|
32
|
+
zoomIn: 拡大
|
|
33
|
+
reset: リセット
|
|
34
|
+
rotateLeft: 反時計回りに回転
|
|
35
|
+
rotateRight: 時計回りに回転
|
|
36
|
+
schema:
|
|
37
|
+
settings:
|
|
38
|
+
$description: 一般設定
|
|
39
|
+
locale: 言語設定。
|
|
40
|
+
theme:
|
|
41
|
+
$description: テーマ設定
|
|
42
|
+
mode: テーマの設定。
|
|
43
|
+
mode-auto: システムに従う
|
|
44
|
+
mode-dark: ダーク
|
|
45
|
+
mode-light: ライト
|
|
46
|
+
dark: ダークテーマ。
|
|
47
|
+
light: ライトテーマ。
|