@koishi-ce/client 1.0.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/app/assets/logo.png +0 -0
- package/app/home/home.vue +51 -0
- package/app/home/index.ts +18 -0
- package/app/home/welcome.en-US.yml +9 -0
- package/app/home/welcome.vue +111 -0
- package/app/home/welcome.zh-CN.yml +9 -0
- package/app/index.html +13 -0
- package/app/index.scss +64 -0
- package/app/index.ts +32 -0
- package/app/layout/header.vue +187 -0
- package/app/layout/index.ts +15 -0
- package/app/layout/layout.vue +194 -0
- package/app/layout/menu-item.vue +60 -0
- package/app/settings/index.ts +39 -0
- package/app/settings/settings.vue +82 -0
- package/app/settings/theme.vue +123 -0
- package/app/shims.d.ts +1 -0
- package/app/status/index.ts +21 -0
- package/app/status/loading.vue +23 -0
- package/app/status/status.vue +56 -0
- package/app/styles/element.scss +217 -0
- package/app/styles/hc.scss +35 -0
- package/app/styles/index.scss +140 -0
- package/app/styles/index.ts +30 -0
- package/app/styles/layout.scss +92 -0
- package/app/theme/activity/button.vue +97 -0
- package/app/theme/activity/index.vue +119 -0
- package/app/theme/activity/item.vue +185 -0
- package/app/theme/activity/separator.vue +163 -0
- package/app/theme/activity/utils.ts +27 -0
- package/app/theme/blank.vue +24 -0
- package/app/theme/index.ts +37 -0
- package/app/theme/index.vue +34 -0
- package/app/theme/menu/index.vue +26 -0
- package/app/theme/menu/menu-item.vue +58 -0
- package/app/theme/menu/menu.vue +45 -0
- package/app/theme/status.vue +45 -0
- package/app/tsconfig.json +15 -0
- package/client/components/chat/image.vue +20 -0
- package/client/components/chat/overlay.vue +231 -0
- package/client/components/chat/utils.ts +6 -0
- package/client/components/common/index.ts +11 -0
- package/client/components/common/k-button.vue +127 -0
- package/client/components/common/k-hint.vue +62 -0
- package/client/components/common/k-tab.vue +50 -0
- package/client/components/dynamic.vue +61 -0
- package/client/components/icons/activity/default.vue +6 -0
- package/client/components/icons/activity/ellipsis.vue +6 -0
- package/client/components/icons/activity/home.vue +13 -0
- package/client/components/icons/activity/moon.vue +6 -0
- package/client/components/icons/activity/settings.vue +6 -0
- package/client/components/icons/activity/sun.vue +6 -0
- package/client/components/icons/index.ts +133 -0
- package/client/components/icons/style.scss +3 -0
- package/client/components/icons/svg/arrow-left.vue +6 -0
- package/client/components/icons/svg/arrow-right.vue +6 -0
- package/client/components/icons/svg/box-open.vue +6 -0
- package/client/components/icons/svg/check-full.vue +6 -0
- package/client/components/icons/svg/chevron-down.vue +6 -0
- package/client/components/icons/svg/chevron-left.vue +6 -0
- package/client/components/icons/svg/chevron-right.vue +6 -0
- package/client/components/icons/svg/chevron-up.vue +6 -0
- package/client/components/icons/svg/clipboard-list.vue +6 -0
- package/client/components/icons/svg/edit.vue +6 -0
- package/client/components/icons/svg/exclamation-full.vue +6 -0
- package/client/components/icons/svg/expand.vue +6 -0
- package/client/components/icons/svg/file-archive.vue +6 -0
- package/client/components/icons/svg/filter.vue +6 -0
- package/client/components/icons/svg/github.vue +6 -0
- package/client/components/icons/svg/gitlab.vue +6 -0
- package/client/components/icons/svg/info-full.vue +6 -0
- package/client/components/icons/svg/koishi.vue +6 -0
- package/client/components/icons/svg/link.vue +6 -0
- package/client/components/icons/svg/paper-plane.vue +6 -0
- package/client/components/icons/svg/question-empty.vue +6 -0
- package/client/components/icons/svg/redo.vue +6 -0
- package/client/components/icons/svg/search-minus.vue +6 -0
- package/client/components/icons/svg/search-plus.vue +6 -0
- package/client/components/icons/svg/search.vue +6 -0
- package/client/components/icons/svg/star-empty.vue +6 -0
- package/client/components/icons/svg/star-full.vue +6 -0
- package/client/components/icons/svg/start.vue +6 -0
- package/client/components/icons/svg/tag.vue +6 -0
- package/client/components/icons/svg/times-full.vue +6 -0
- package/client/components/icons/svg/tools.vue +6 -0
- package/client/components/icons/svg/undo.vue +6 -0
- package/client/components/icons/svg/user.vue +6 -0
- package/client/components/index.ts +75 -0
- package/client/components/layout/card.vue +69 -0
- package/client/components/layout/content.vue +37 -0
- package/client/components/layout/empty.vue +41 -0
- package/client/components/layout/index.ts +15 -0
- package/client/components/layout/tab-group.vue +45 -0
- package/client/components/layout/tab-item.vue +35 -0
- package/client/components/link.ts +39 -0
- package/client/components/perms.vue +73 -0
- package/client/components/slot.ts +95 -0
- package/client/context.ts +143 -0
- package/client/data.ts +178 -0
- package/client/index.ts +76 -0
- package/client/plugins/action.ts +251 -0
- package/client/plugins/i18n.ts +43 -0
- package/client/plugins/loader.ts +154 -0
- package/client/plugins/router.ts +278 -0
- package/client/plugins/setting.ts +217 -0
- package/client/plugins/theme.ts +134 -0
- package/client/shims.d.ts +55 -0
- package/client/tsconfig.json +15 -0
- package/client/utils.ts +36 -0
- package/global.d.ts +24 -0
- package/lib/bin.d.ts +1 -0
- package/lib/bin.mjs +112 -0
- package/lib/client-CaTn_gVG.mjs +125 -0
- package/lib/index.d.ts +20 -0
- package/lib/index.mjs +2 -0
- package/lib/src-Bxzzi1Rx.mjs +160 -0
- package/lib/yaml-UzQbvquH.mjs +23 -0
- package/package.json +66 -0
- package/src/bin.ts +61 -0
- package/src/index.ts +280 -0
- package/src/yaml.ts +22 -0
|
Binary file
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
控制台首页:WebSocket 就绪后渲染 "home" 插槽内容(默认为欢迎卡片),
|
|
3
|
+
未连接时显示连接提示卡片。
|
|
4
|
+
-->
|
|
5
|
+
<template>
|
|
6
|
+
<k-layout :main="`darker page-home${socket ? '' : ' loading'}`">
|
|
7
|
+
<el-scrollbar v-if="socket">
|
|
8
|
+
<k-slot name="home">
|
|
9
|
+
<k-slot-item :order="1000">
|
|
10
|
+
<welcome></welcome>
|
|
11
|
+
</k-slot-item>
|
|
12
|
+
</k-slot>
|
|
13
|
+
</el-scrollbar>
|
|
14
|
+
<div v-else>
|
|
15
|
+
<k-card class="connect">正在连接到 Koishi 服务器……</k-card>
|
|
16
|
+
</div>
|
|
17
|
+
</k-layout>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script lang="ts" setup>
|
|
21
|
+
import { global, socket } from "@koishi-ce/client";
|
|
22
|
+
import Welcome from "./welcome.vue";
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<style lang="scss">
|
|
26
|
+
|
|
27
|
+
.page-home {
|
|
28
|
+
&.loading {
|
|
29
|
+
display: flex;
|
|
30
|
+
flex-direction: column;
|
|
31
|
+
align-items: center;
|
|
32
|
+
justify-content: center;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.k-card.welcome {
|
|
36
|
+
margin: var(--card-margin);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.k-card.connect {
|
|
40
|
+
width: 400px;
|
|
41
|
+
max-width: 400px;
|
|
42
|
+
text-align: center;
|
|
43
|
+
line-height: 2;
|
|
44
|
+
|
|
45
|
+
p {
|
|
46
|
+
margin: 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
</style>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 首页插件:将 welcome 欢迎页注册为根路由 "/"。
|
|
3
|
+
* order 取极大值(活动栏 top 组渲染时按 order 逆序输出,故首页位于最顶部)。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Context } from "@koishi-ce/client";
|
|
7
|
+
import Home from "./home.vue";
|
|
8
|
+
|
|
9
|
+
export default function (ctx: Context) {
|
|
10
|
+
ctx.page({
|
|
11
|
+
id: "home",
|
|
12
|
+
path: "/",
|
|
13
|
+
name: "欢迎",
|
|
14
|
+
icon: "activity:home",
|
|
15
|
+
order: 1000,
|
|
16
|
+
component: Home,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
title: Welcome to Koishi!
|
|
2
|
+
description: Your chatbot is ready to go. 点击下面的任一选项,开启你的 Koishi 之旅吧。
|
|
3
|
+
action:
|
|
4
|
+
docs:
|
|
5
|
+
title: Documentation
|
|
6
|
+
description: The official documentation contains everything you want to know.
|
|
7
|
+
forum:
|
|
8
|
+
title: Forum
|
|
9
|
+
description: If you run into problems, you can always ask for help on the forum.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
欢迎卡片:文档 / 社区论坛等入口链接。
|
|
3
|
+
自带 zh-CN 与 en-US 两套文案(局部 vue-i18n 实例,独立于全局语言包),
|
|
4
|
+
其余扩展可通过 "welcome-choice" 插槽追加自定义入口。
|
|
5
|
+
-->
|
|
6
|
+
<template>
|
|
7
|
+
<div class="k-card welcome">
|
|
8
|
+
<h1>{{ t('title') }}</h1>
|
|
9
|
+
<p>{{ t('description') }}</p>
|
|
10
|
+
<div class="choices">
|
|
11
|
+
<k-slot name="welcome-choice">
|
|
12
|
+
<k-slot-item :order="1000">
|
|
13
|
+
<a class="choice" href="https://koishi.chat" rel="noopener noreferer" target="_blank">
|
|
14
|
+
<h2>{{ t('action.docs.title') }}</h2>
|
|
15
|
+
<p>{{ t('action.docs.description') }}</p>
|
|
16
|
+
</a>
|
|
17
|
+
</k-slot-item>
|
|
18
|
+
<k-slot-item :order="500">
|
|
19
|
+
<a class="choice" href="https://k.ilharp.cc" rel="noopener noreferer" target="_blank">
|
|
20
|
+
<h2>{{ t('action.forum.title') }}</h2>
|
|
21
|
+
<p>{{ t('action.forum.description') }}</p>
|
|
22
|
+
</a>
|
|
23
|
+
</k-slot-item>
|
|
24
|
+
</k-slot>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script lang="ts" setup>
|
|
30
|
+
import { useI18n } from "vue-i18n";
|
|
31
|
+
import enUS from "./welcome.en-US.yml";
|
|
32
|
+
import zhCN from "./welcome.zh-CN.yml";
|
|
33
|
+
|
|
34
|
+
// 组件私有的双语文案:不依赖全局 i18n,确保欢迎页在任何语言环境下可用
|
|
35
|
+
const { t, setLocaleMessage } = useI18n({
|
|
36
|
+
messages: {
|
|
37
|
+
"zh-CN": zhCN,
|
|
38
|
+
"en-US": enUS,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// 开发模式下 yml 文案改动即时热替换,无需整页刷新
|
|
43
|
+
if (import.meta.hot) {
|
|
44
|
+
import.meta.hot.accept("./welcome.zh-CN.yml", (module) => {
|
|
45
|
+
setLocaleMessage("zh-CN", module.default);
|
|
46
|
+
});
|
|
47
|
+
import.meta.hot.accept("./welcome.en-US.yml", (module) => {
|
|
48
|
+
setLocaleMessage("en-US", module.default);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<style lang="scss">
|
|
54
|
+
|
|
55
|
+
.page-home .welcome {
|
|
56
|
+
--welcome-title: 2.5rem;
|
|
57
|
+
--welcome-padding: 3rem 3rem;
|
|
58
|
+
--welcome-choice-padding: 0.5rem 1.5rem;
|
|
59
|
+
--welcome-gap: 2rem;
|
|
60
|
+
|
|
61
|
+
padding: var(--welcome-padding);
|
|
62
|
+
|
|
63
|
+
h1 {
|
|
64
|
+
font-size: var(--welcome-title);
|
|
65
|
+
margin-top: 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
h1 + p {
|
|
69
|
+
margin: var(--welcome-gap) 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.choices {
|
|
73
|
+
display: flex;
|
|
74
|
+
flex-flow: row wrap;
|
|
75
|
+
gap: var(--welcome-gap);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.choice {
|
|
79
|
+
flex: 1 0 auto;
|
|
80
|
+
display: inline-block;
|
|
81
|
+
width: 280px;
|
|
82
|
+
box-sizing: border-box;
|
|
83
|
+
padding: var(--welcome-choice-padding);
|
|
84
|
+
border: 1px solid var(--k-color-divider);
|
|
85
|
+
border-radius: 6px;
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
transition: var(--color-transition);
|
|
88
|
+
|
|
89
|
+
&:hover {
|
|
90
|
+
background-color: var(--k-side-color);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
h2 {
|
|
94
|
+
font-size: 1.25rem;
|
|
95
|
+
margin-top: 1rem;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
p {
|
|
99
|
+
font-size: 0.9375rem;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@media screen and (max-width: 768px) {
|
|
104
|
+
--welcome-title: 2rem;
|
|
105
|
+
--welcome-padding: 1.5rem 1.5rem;
|
|
106
|
+
--welcome-gap: 1.5rem;
|
|
107
|
+
--welcome-choice-padding: 0.5rem 1.5rem;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
</style>
|
package/app/index.html
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Koishi 控制台</title>
|
|
7
|
+
<link rel="icon" href="/assets/logo.png" />
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/index.ts"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
package/app/index.scss
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
body {
|
|
2
|
+
margin: 0;
|
|
3
|
+
min-height: 100vh;
|
|
4
|
+
font-family: var(--font-family);
|
|
5
|
+
-webkit-font-smoothing: antialiased;
|
|
6
|
+
-moz-osx-font-smoothing: grayscale;
|
|
7
|
+
color: var(--fg1);
|
|
8
|
+
background-color: var(--k-page-bg);
|
|
9
|
+
position: relative;
|
|
10
|
+
transition: color 0.3s ease, background-color 0.3s ease;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
code {
|
|
14
|
+
font-family: var(--font-family-code);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
a {
|
|
18
|
+
color: inherit;
|
|
19
|
+
text-decoration: none;
|
|
20
|
+
transition: color 0.3s ease;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
p, ul {
|
|
24
|
+
margin: 1em 0;
|
|
25
|
+
line-height: 1.7;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
table {
|
|
29
|
+
text-align: center;
|
|
30
|
+
width: 100%;
|
|
31
|
+
border-collapse: collapse;
|
|
32
|
+
|
|
33
|
+
td, th {
|
|
34
|
+
padding: .5em 1em;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
tr {
|
|
38
|
+
border-top: 1px solid var(--k-color-divider);
|
|
39
|
+
transition: border-color 0.3s ease;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
tr:last-child {
|
|
43
|
+
border-bottom: 1px solid var(--k-color-divider);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.markdown {
|
|
48
|
+
a, code a {
|
|
49
|
+
color: var(--k-text-active);
|
|
50
|
+
|
|
51
|
+
&:hover {
|
|
52
|
+
text-decoration: underline;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
code {
|
|
57
|
+
color: var(--k-text-normal);
|
|
58
|
+
padding: 0.25rem 0.5rem;
|
|
59
|
+
background-color: var(--k-page-bg);
|
|
60
|
+
border-radius: 3px;
|
|
61
|
+
overflow-wrap: break-word;
|
|
62
|
+
transition: background-color 0.3s ease, color 0.3s ease;
|
|
63
|
+
}
|
|
64
|
+
}
|
package/app/index.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 控制台前端宿主应用入口(scripts/client.ts 总装构建的主入口)。
|
|
3
|
+
*
|
|
4
|
+
* 依次注册内置的功能插件(首页 / 布局 / 设置 / 状态栏 / 全局样式 / 主题),
|
|
5
|
+
* 启动应用根上下文后,在非静态模式下与 Koishi 服务端建立 WebSocket 连接。
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { connect, global, root } from "@koishi-ce/client";
|
|
9
|
+
import home from "./home";
|
|
10
|
+
import layout from "./layout";
|
|
11
|
+
import settings from "./settings";
|
|
12
|
+
import status from "./status";
|
|
13
|
+
import styles from "./styles";
|
|
14
|
+
import theme from "./theme";
|
|
15
|
+
|
|
16
|
+
import "virtual:uno.css";
|
|
17
|
+
import "./index.scss";
|
|
18
|
+
|
|
19
|
+
root.plugin(home);
|
|
20
|
+
root.plugin(layout);
|
|
21
|
+
root.plugin(settings);
|
|
22
|
+
root.plugin(status);
|
|
23
|
+
root.plugin(styles);
|
|
24
|
+
root.plugin(theme);
|
|
25
|
+
|
|
26
|
+
root.start();
|
|
27
|
+
|
|
28
|
+
if (!global.static) {
|
|
29
|
+
// global.static 为真表示纯静态构建(无后端),跳过连接
|
|
30
|
+
const endpoint = new URL(global.endpoint, location.origin).toString();
|
|
31
|
+
connect(root, () => new WebSocket(endpoint.replace(/^http/, "ws")));
|
|
32
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
布局顶栏:左侧标题(默认取当前路由名)、右侧菜单区,
|
|
3
|
+
移动端额外提供侧栏开关按钮与溢出菜单("...")按钮。
|
|
4
|
+
-->
|
|
5
|
+
<template>
|
|
6
|
+
<div class="layout-header" :class="{ 'has-menu': menuKey }">
|
|
7
|
+
<div
|
|
8
|
+
class="toggle-sidebar-button"
|
|
9
|
+
role="button"
|
|
10
|
+
tabindex="0"
|
|
11
|
+
@click="$emit('update:isLeftAsideOpen', !isLeftAsideOpen)"
|
|
12
|
+
>
|
|
13
|
+
<div class="icon">
|
|
14
|
+
<span></span>
|
|
15
|
+
<span></span>
|
|
16
|
+
<span></span>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="left">
|
|
20
|
+
<slot name="left">{{ route.name }}</slot>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="right">
|
|
23
|
+
<slot name="right"></slot>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="toggle-menu-button"
|
|
26
|
+
v-if="menuKey"
|
|
27
|
+
role="button"
|
|
28
|
+
tabindex="1"
|
|
29
|
+
@click.stop="trigger($event, menuData)"
|
|
30
|
+
>
|
|
31
|
+
<k-icon name="ellipsis"></k-icon>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<script lang="ts" setup>
|
|
37
|
+
import { type ActionContext, useMenu } from "@koishi-ce/client";
|
|
38
|
+
import { useRoute } from "vue-router";
|
|
39
|
+
|
|
40
|
+
const props = defineProps<{
|
|
41
|
+
isLeftAsideOpen: boolean;
|
|
42
|
+
isRightAsideOpen: boolean;
|
|
43
|
+
menuKey?: string;
|
|
44
|
+
menuData?: unknown;
|
|
45
|
+
}>();
|
|
46
|
+
|
|
47
|
+
// 溢出菜单按钮的点击触发器:打开 menuKey 对应的上下文菜单
|
|
48
|
+
// (menuKey 为运行期字符串,这里断言为菜单键类型以复用字面量重载)
|
|
49
|
+
const trigger = useMenu(props.menuKey as keyof ActionContext);
|
|
50
|
+
|
|
51
|
+
defineEmits(["update:isLeftAsideOpen", "update:isRightAsideOpen"]);
|
|
52
|
+
|
|
53
|
+
const route = useRoute();
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<style lang="scss">
|
|
57
|
+
|
|
58
|
+
.toggle-sidebar-button {
|
|
59
|
+
position: absolute;
|
|
60
|
+
top: 0;
|
|
61
|
+
height: 100%;
|
|
62
|
+
left: 1rem;
|
|
63
|
+
display: none;
|
|
64
|
+
cursor: pointer;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.toggle-sidebar-button .icon {
|
|
68
|
+
display: flex;
|
|
69
|
+
flex-direction: column;
|
|
70
|
+
justify-content: center;
|
|
71
|
+
align-items: center;
|
|
72
|
+
width: 1.25rem;
|
|
73
|
+
height: 100%;
|
|
74
|
+
cursor: inherit;
|
|
75
|
+
|
|
76
|
+
span {
|
|
77
|
+
display: inline-block;
|
|
78
|
+
width: 100%;
|
|
79
|
+
height: 2px;
|
|
80
|
+
border-radius: 2px;
|
|
81
|
+
background-color: var(--fg1);
|
|
82
|
+
transition: transform 0.3s ease;
|
|
83
|
+
|
|
84
|
+
&:nth-child(2) {
|
|
85
|
+
margin: 6px 0;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.toggle-menu-button {
|
|
91
|
+
display: none;
|
|
92
|
+
height: 100%;
|
|
93
|
+
width: var(--header-height);
|
|
94
|
+
align-items: center;
|
|
95
|
+
justify-content: center;
|
|
96
|
+
|
|
97
|
+
.k-icon {
|
|
98
|
+
height: 1.25rem;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@media screen and (max-width: 768px) {
|
|
103
|
+
.toggle-sidebar-button {
|
|
104
|
+
display: block;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.toggle-menu-button {
|
|
108
|
+
display: flex;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.layout-header.has-menu .right {
|
|
112
|
+
display: none;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.layout-header {
|
|
117
|
+
position: relative;
|
|
118
|
+
box-sizing: border-box;
|
|
119
|
+
height: var(--header-height);
|
|
120
|
+
flex: 0 0 auto;
|
|
121
|
+
background-color: inherit;
|
|
122
|
+
display: flex;
|
|
123
|
+
flex-direction: row;
|
|
124
|
+
align-items: center;
|
|
125
|
+
justify-content: space-between;
|
|
126
|
+
border-bottom: var(--k-color-divider-dark) 1px solid;
|
|
127
|
+
transition: var(--color-transition);
|
|
128
|
+
font-weight: bolder;
|
|
129
|
+
|
|
130
|
+
.left {
|
|
131
|
+
margin-left: var(--header-height);
|
|
132
|
+
padding-left: 0.5rem;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.right {
|
|
136
|
+
margin-right: 0.5rem;
|
|
137
|
+
flex: 0 0 auto;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.menu-item {
|
|
141
|
+
position: relative;
|
|
142
|
+
width: 4rem;
|
|
143
|
+
height: var(--header-height);
|
|
144
|
+
display: inline-flex;
|
|
145
|
+
flex-direction: column;
|
|
146
|
+
align-items: center;
|
|
147
|
+
justify-content: center;
|
|
148
|
+
cursor: pointer;
|
|
149
|
+
transition: var(--color-transition);
|
|
150
|
+
|
|
151
|
+
&.active {
|
|
152
|
+
color: var(--k-color-primary);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
&.spin {
|
|
156
|
+
animation: spin 1s linear infinite;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@keyframes spin {
|
|
160
|
+
0% {
|
|
161
|
+
transform: rotate(0deg);
|
|
162
|
+
}
|
|
163
|
+
100% {
|
|
164
|
+
transform: rotate(360deg);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
&.disabled {
|
|
169
|
+
opacity: 0.3;
|
|
170
|
+
pointer-events: none;
|
|
171
|
+
|
|
172
|
+
@media screen and (max-width: 768px) {
|
|
173
|
+
display: none;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.menu-icon {
|
|
178
|
+
height: 1.125rem;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
@media screen and (max-width: 768px) {
|
|
182
|
+
width: 3rem;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 布局插件:向全局 "layout" 插槽注册三栏布局组件。
|
|
3
|
+
* order 取极小值保证它先于其它同插槽内容排序(作为页面骨架)。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Context } from "@koishi-ce/client";
|
|
7
|
+
import Layout from "./layout.vue";
|
|
8
|
+
|
|
9
|
+
export default function (ctx: Context) {
|
|
10
|
+
ctx.slot({
|
|
11
|
+
type: "layout",
|
|
12
|
+
component: Layout,
|
|
13
|
+
order: -1000,
|
|
14
|
+
});
|
|
15
|
+
}
|