优化
This commit is contained in:
11
client/web/plugins/com.msgbyte.intro/manifest.json
Normal file
11
client/web/plugins/com.msgbyte.intro/manifest.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"label": "Intro plugin",
|
||||
"label.zh-CN": "初始引导插件",
|
||||
"name": "com.msgbyte.intro",
|
||||
"url": "/plugins/com.msgbyte.intro/index.js",
|
||||
"version": "0.0.0",
|
||||
"author": "msgbyte",
|
||||
"description": "Turn on the ability to introduce the app for the first time for the app",
|
||||
"description.zh-CN": "为应用首次打开介绍应用的能力",
|
||||
"requireRestart": true
|
||||
}
|
||||
9
client/web/plugins/com.msgbyte.intro/package.json
Normal file
9
client/web/plugins/com.msgbyte.intro/package.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "@plugins/com.msgbyte.intro",
|
||||
"main": "src/index.ts",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"shepherd.js": "^11.1.1"
|
||||
}
|
||||
}
|
||||
4
client/web/plugins/com.msgbyte.intro/src/index.ts
Normal file
4
client/web/plugins/com.msgbyte.intro/src/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 异步加载
|
||||
*/
|
||||
import('./tour');
|
||||
87
client/web/plugins/com.msgbyte.intro/src/steps.ts
Normal file
87
client/web/plugins/com.msgbyte.intro/src/steps.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import Shepherd from 'shepherd.js';
|
||||
import { Translate } from './translate';
|
||||
|
||||
function buildWatchDom(selector: string) {
|
||||
return () => {
|
||||
return new Promise<void>((resolve) => {
|
||||
const findDom = () => {
|
||||
if (document.querySelector(selector)) {
|
||||
resolve();
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
findDom();
|
||||
}, 200);
|
||||
}
|
||||
};
|
||||
|
||||
findDom();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function buildStepOption(options: {
|
||||
id: string;
|
||||
text: string;
|
||||
selector: string;
|
||||
position?: Shepherd.Step.StepOptions['attachTo']['on'];
|
||||
canClickTarget?: boolean;
|
||||
}): Shepherd.Step.StepOptions {
|
||||
return {
|
||||
id: options.id,
|
||||
text: options.text,
|
||||
attachTo: {
|
||||
element: options.selector,
|
||||
on: options.position,
|
||||
},
|
||||
canClickTarget: false,
|
||||
beforeShowPromise: buildWatchDom(options.selector),
|
||||
};
|
||||
}
|
||||
|
||||
export const steps: Shepherd.Step.StepOptions[] = [
|
||||
{
|
||||
id: 'start',
|
||||
text: Translate.step1,
|
||||
beforeShowPromise: buildWatchDom('[data-tc-role=navbar]'), // 仅当主界面出现后才显示欢迎
|
||||
},
|
||||
buildStepOption({
|
||||
id: 'navbar',
|
||||
text: Translate.step2,
|
||||
selector: '[data-tc-role=navbar]',
|
||||
position: 'right',
|
||||
}),
|
||||
buildStepOption({
|
||||
id: 'personal',
|
||||
text: Translate.step3,
|
||||
selector: '[data-tc-role=navbar-personal]',
|
||||
position: 'right',
|
||||
}),
|
||||
buildStepOption({
|
||||
id: 'groups',
|
||||
text: Translate.step4,
|
||||
selector: '[data-tc-role=navbar-groups]',
|
||||
position: 'right',
|
||||
}),
|
||||
buildStepOption({
|
||||
id: 'settings',
|
||||
text: Translate.step5,
|
||||
selector: '[data-tc-role=navbar-settings]',
|
||||
position: 'right',
|
||||
}),
|
||||
buildStepOption({
|
||||
id: 'sidebar',
|
||||
text: Translate.step6,
|
||||
selector: '[data-tc-role^=sidebar-]',
|
||||
position: 'right',
|
||||
}),
|
||||
buildStepOption({
|
||||
id: 'content',
|
||||
text: Translate.step7,
|
||||
selector: '[data-tc-role^=content-]',
|
||||
position: 'right',
|
||||
}),
|
||||
{
|
||||
id: 'end',
|
||||
text: Translate.step8,
|
||||
},
|
||||
];
|
||||
176
client/web/plugins/com.msgbyte.intro/src/style.less
Normal file
176
client/web/plugins/com.msgbyte.intro/src/style.less
Normal file
@@ -0,0 +1,176 @@
|
||||
.shepherd-button {
|
||||
background: #3288e6;
|
||||
border: 0;
|
||||
border-radius: 3px;
|
||||
color: hsla(0, 0%, 100%, 0.75);
|
||||
cursor: pointer;
|
||||
margin-right: 0.5rem;
|
||||
padding: 0.5rem 1.5rem;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
.shepherd-button:not(:disabled):hover {
|
||||
background: #196fcc;
|
||||
color: hsla(0, 0%, 100%, 0.75);
|
||||
}
|
||||
.shepherd-button.shepherd-button-secondary {
|
||||
background: #f1f2f3;
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
.shepherd-button.shepherd-button-secondary:not(:disabled):hover {
|
||||
background: #d6d9db;
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
.shepherd-button:disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.shepherd-footer {
|
||||
border-bottom-left-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 0 0.75rem 0.75rem;
|
||||
}
|
||||
.shepherd-footer .shepherd-button:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
.shepherd-cancel-icon {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: hsla(0, 0%, 50.2%, 0.75);
|
||||
font-size: 2em;
|
||||
cursor: pointer;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
transition: color 0.5s ease;
|
||||
}
|
||||
.shepherd-cancel-icon:hover {
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
.shepherd-has-title .shepherd-content .shepherd-cancel-icon {
|
||||
color: hsla(0, 0%, 50.2%, 0.75);
|
||||
}
|
||||
.shepherd-has-title .shepherd-content .shepherd-cancel-icon:hover {
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
.shepherd-title {
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
display: flex;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
flex: 1 0 auto;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.shepherd-header {
|
||||
align-items: center;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
line-height: 2em;
|
||||
padding: 0.75rem 0.75rem 0;
|
||||
}
|
||||
.shepherd-has-title .shepherd-content .shepherd-header {
|
||||
background: #e6e6e6;
|
||||
padding: 1em;
|
||||
}
|
||||
.shepherd-text {
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
font-size: 1rem;
|
||||
line-height: 1.3em;
|
||||
padding: 0.75em;
|
||||
}
|
||||
.shepherd-text p {
|
||||
margin-top: 0;
|
||||
}
|
||||
.shepherd-text p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.shepherd-content {
|
||||
border-radius: 5px;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
}
|
||||
.shepherd-element {
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
|
||||
max-width: 400px;
|
||||
opacity: 0;
|
||||
outline: none;
|
||||
transition: opacity 0.3s, visibility 0.3s;
|
||||
visibility: hidden;
|
||||
width: 100%;
|
||||
z-index: 9999;
|
||||
}
|
||||
.shepherd-enabled.shepherd-element {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
.shepherd-element[data-popper-reference-hidden]:not(.shepherd-centered) {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
.shepherd-element,
|
||||
.shepherd-element *,
|
||||
.shepherd-element :after,
|
||||
.shepherd-element :before {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.shepherd-arrow,
|
||||
.shepherd-arrow:before {
|
||||
position: absolute;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
z-index: -1;
|
||||
}
|
||||
.shepherd-arrow:before {
|
||||
content: '';
|
||||
transform: rotate(45deg);
|
||||
background: #fff;
|
||||
}
|
||||
.shepherd-element[data-popper-placement^='top'] > .shepherd-arrow {
|
||||
bottom: -8px;
|
||||
}
|
||||
.shepherd-element[data-popper-placement^='bottom'] > .shepherd-arrow {
|
||||
top: -8px;
|
||||
}
|
||||
.shepherd-element[data-popper-placement^='left'] > .shepherd-arrow {
|
||||
right: -8px;
|
||||
}
|
||||
.shepherd-element[data-popper-placement^='right'] > .shepherd-arrow {
|
||||
left: -8px;
|
||||
}
|
||||
.shepherd-element.shepherd-centered > .shepherd-arrow {
|
||||
opacity: 0;
|
||||
}
|
||||
.shepherd-element.shepherd-has-title[data-popper-placement^='bottom']
|
||||
> .shepherd-arrow:before {
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
.shepherd-target-click-disabled.shepherd-enabled.shepherd-target,
|
||||
.shepherd-target-click-disabled.shepherd-enabled.shepherd-target * {
|
||||
pointer-events: none;
|
||||
}
|
||||
.shepherd-modal-overlay-container {
|
||||
height: 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
transition: all 0.3s ease-out, height 0ms 0.3s, opacity 0.3s 0ms;
|
||||
width: 100vw;
|
||||
z-index: 9997;
|
||||
}
|
||||
.shepherd-modal-overlay-container.shepherd-modal-is-visible {
|
||||
height: 100vh;
|
||||
opacity: 0.5;
|
||||
transition: all 0.3s ease-out, height 0s 0s, opacity 0.3s 0s;
|
||||
}
|
||||
.shepherd-modal-overlay-container.shepherd-modal-is-visible path {
|
||||
pointer-events: all;
|
||||
}
|
||||
42
client/web/plugins/com.msgbyte.intro/src/tour.ts
Normal file
42
client/web/plugins/com.msgbyte.intro/src/tour.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import Shepherd from 'shepherd.js';
|
||||
import { Translate } from './translate';
|
||||
import { steps } from './steps';
|
||||
import './style.less';
|
||||
|
||||
const KEY = 'plugin:com.msgbyte.intro/hasRun';
|
||||
|
||||
if (!window.localStorage.getItem(KEY)) {
|
||||
const tour = new Shepherd.Tour({
|
||||
useModalOverlay: true,
|
||||
defaultStepOptions: {
|
||||
classes: 'shadow-md',
|
||||
scrollTo: true,
|
||||
arrow: true,
|
||||
modalOverlayOpeningRadius: 4,
|
||||
modalOverlayOpeningPadding: 4,
|
||||
buttons: [
|
||||
{
|
||||
text: Translate.skip,
|
||||
secondary: true,
|
||||
action() {
|
||||
this.complete();
|
||||
},
|
||||
},
|
||||
{
|
||||
text: Translate.next,
|
||||
action() {
|
||||
this.next();
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
tour.on('complete', () => {
|
||||
window.localStorage.setItem(KEY, 'true');
|
||||
});
|
||||
|
||||
tour.addSteps(steps);
|
||||
|
||||
tour.start();
|
||||
}
|
||||
54
client/web/plugins/com.msgbyte.intro/src/translate.ts
Normal file
54
client/web/plugins/com.msgbyte.intro/src/translate.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { localTrans } from '@capital/common';
|
||||
|
||||
export const Translate = {
|
||||
next: localTrans({
|
||||
'zh-CN': '下一步',
|
||||
'en-US': 'Next',
|
||||
}),
|
||||
skip: localTrans({
|
||||
'zh-CN': '跳过引导',
|
||||
'en-US': 'Skip Tour',
|
||||
}),
|
||||
step1: localTrans({
|
||||
'zh-CN': '欢迎使用 Tailchat, 一个插件化的开源IM应用!',
|
||||
'en-US': 'Welcome to Tailchat, a pluginify open source IM application!',
|
||||
}),
|
||||
step2: localTrans({
|
||||
'zh-CN': '这是导航栏, 在这里可以切换tailchat的各个主要页面。',
|
||||
'en-US':
|
||||
'This is the navigation bar, where you can switch between the main pages of tailchat.',
|
||||
}),
|
||||
step3: localTrans({
|
||||
'zh-CN': '这是个人信息入口,在这里可以访问您的好友、插件、以及私信等功能。',
|
||||
'en-US':
|
||||
'This is the personal information entry, where you can access functions such as your friends, plug-ins, and private messages.',
|
||||
}),
|
||||
step4: localTrans({
|
||||
'zh-CN':
|
||||
'这是群组列表, 会显示所有已加入的群组,您可以通过点击切换切换群组,也可以点击 + 号按钮来创建群组',
|
||||
'en-US':
|
||||
'This is a list of groups, which will display all the groups you have joined. You can click to switch between groups, or you can click the + button to create a group',
|
||||
}),
|
||||
step5: localTrans({
|
||||
'zh-CN':
|
||||
'这是设置按钮,可以通过此按钮来进行个人信息的变更、系统设置的变更、软件信息等内容',
|
||||
'en-US':
|
||||
'This is the setting button, through which you can change personal information, system settings, software information, etc.',
|
||||
}),
|
||||
step6: localTrans({
|
||||
'zh-CN': '这是侧边栏,用于切换内容。在未来会经常使用它来切换不同的面板。',
|
||||
'en-US':
|
||||
'This is the sidebar, used to toggle content. Will use it frequently in the future to switch between different panels.',
|
||||
}),
|
||||
step7: localTrans({
|
||||
'zh-CN': '这是内容区,用于显示主要内容,也是Tailchat展示内容的地方。',
|
||||
'en-US':
|
||||
'This is the content area, which is used to display the main content, and it is also where Tailchat displays the content.',
|
||||
}),
|
||||
step8: localTrans({
|
||||
'zh-CN':
|
||||
'如果有更多疑问, 欢迎访问官方文档了解更多: <br /><a href="https://tailchat.msgbyte.com/" target="_blank" style="text-decoration: underline;">点击此处打开官方文档</a>',
|
||||
'en-US':
|
||||
'If you have more questions, please visit the official document to learn more: <br /><a href="https://tailchat.msgbyte.com/" target="_blank" style="text-decoration: underline;">Click here to open the official documentation</a>',
|
||||
}),
|
||||
};
|
||||
9
client/web/plugins/com.msgbyte.intro/tsconfig.json
Normal file
9
client/web/plugins/com.msgbyte.intro/tsconfig.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true,
|
||||
"jsx": "react",
|
||||
"paths": {
|
||||
"@capital/*": ["../../src/plugin/*"],
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user