From fcaa941e9aeb404a410f632f5f64cda3d7ab561c Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Wed, 29 Sep 2021 17:32:37 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0intro=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E7=94=A8=E4=BA=8E=E6=96=B0=E4=BA=BA=E5=BC=95=E5=AF=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/plugins/com.msgbyte.intro/manifest.json | 9 + web/plugins/com.msgbyte.intro/package.json | 9 + web/plugins/com.msgbyte.intro/src/index.ts | 4 + web/plugins/com.msgbyte.intro/src/steps.ts | 77 ++++++++ web/plugins/com.msgbyte.intro/src/style.less | 176 +++++++++++++++++++ web/plugins/com.msgbyte.intro/src/tour.ts | 41 +++++ web/plugins/com.msgbyte.intro/tsconfig.json | 11 ++ web/plugins/com.msgbyte.intro/yarn.lock | 27 +++ 8 files changed, 354 insertions(+) create mode 100644 web/plugins/com.msgbyte.intro/manifest.json create mode 100644 web/plugins/com.msgbyte.intro/package.json create mode 100644 web/plugins/com.msgbyte.intro/src/index.ts create mode 100644 web/plugins/com.msgbyte.intro/src/steps.ts create mode 100644 web/plugins/com.msgbyte.intro/src/style.less create mode 100644 web/plugins/com.msgbyte.intro/src/tour.ts create mode 100644 web/plugins/com.msgbyte.intro/tsconfig.json create mode 100644 web/plugins/com.msgbyte.intro/yarn.lock diff --git a/web/plugins/com.msgbyte.intro/manifest.json b/web/plugins/com.msgbyte.intro/manifest.json new file mode 100644 index 00000000..5da1ed55 --- /dev/null +++ b/web/plugins/com.msgbyte.intro/manifest.json @@ -0,0 +1,9 @@ +{ + "label": "初始引导插件", + "name": "com.msgbyte.intro", + "url": "/plugins/com.msgbyte.intro/index.js", + "version": "0.0.0", + "author": "msgbyte", + "description": "为应用首次打开介绍应用的能力", + "requireRestart": true +} diff --git a/web/plugins/com.msgbyte.intro/package.json b/web/plugins/com.msgbyte.intro/package.json new file mode 100644 index 00000000..5a279985 --- /dev/null +++ b/web/plugins/com.msgbyte.intro/package.json @@ -0,0 +1,9 @@ +{ + "name": "@plugins/com.msgbyte.intro", + "main": "src/index.ts", + "version": "0.0.0", + "private": true, + "dependencies": { + "shepherd.js": "^8.3.1" + } +} diff --git a/web/plugins/com.msgbyte.intro/src/index.ts b/web/plugins/com.msgbyte.intro/src/index.ts new file mode 100644 index 00000000..05773b53 --- /dev/null +++ b/web/plugins/com.msgbyte.intro/src/index.ts @@ -0,0 +1,4 @@ +/** + * 异步加载 + */ +import('./tour'); diff --git a/web/plugins/com.msgbyte.intro/src/steps.ts b/web/plugins/com.msgbyte.intro/src/steps.ts new file mode 100644 index 00000000..ddd4aeb8 --- /dev/null +++ b/web/plugins/com.msgbyte.intro/src/steps.ts @@ -0,0 +1,77 @@ +import Shepherd from 'shepherd.js'; + +function buildWatchDom(selector: string) { + return () => { + return new Promise((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 ?? 'auto', + }, + canClickTarget: false, + beforeShowPromise: buildWatchDom(options.selector), + }; +} + +export const steps: Shepherd.Step.StepOptions[] = [ + buildStepOption({ + id: 'navbar', + text: '这是导航栏, 在这里可以切换tailchat的各个主要页面', + selector: '[data-tc-role=navbar]', + position: 'right', + }), + buildStepOption({ + id: 'personal', + text: '这是个人信息,在这里可以管理您的好友、插件、以及私信', + selector: '[data-tc-role=navbar-personal]', + position: 'right', + }), + buildStepOption({ + id: 'groups', + text: '这是群组列表, 会显示所有已加入的群组,您可以通过点击切换切换群组,也可以点击 + 号按钮来创建群组', + selector: '[data-tc-role=navbar-groups]', + position: 'right', + }), + buildStepOption({ + id: 'settings', + text: '这是设置按钮,可以通过此按钮来进行个人信息的变更、系统设置的变更、软件信息等内容', + selector: '[data-tc-role=navbar-settings]', + position: 'right', + }), + buildStepOption({ + id: 'sidebar', + text: '这是侧边栏,用于切换内容', + selector: '[data-tc-role^=sidebar-]', + position: 'right', + }), + buildStepOption({ + id: 'content', + text: '这是内容区,用于显示主要内容', + selector: '[data-tc-role^=content-]', + position: 'right', + }), +]; diff --git a/web/plugins/com.msgbyte.intro/src/style.less b/web/plugins/com.msgbyte.intro/src/style.less new file mode 100644 index 00000000..869cdecc --- /dev/null +++ b/web/plugins/com.msgbyte.intro/src/style.less @@ -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; +} diff --git a/web/plugins/com.msgbyte.intro/src/tour.ts b/web/plugins/com.msgbyte.intro/src/tour.ts new file mode 100644 index 00000000..10c0c4e0 --- /dev/null +++ b/web/plugins/com.msgbyte.intro/src/tour.ts @@ -0,0 +1,41 @@ +import Shepherd from 'shepherd.js'; +import { steps } from './steps'; +import './style.less'; + +const KEY = 'com.msgbyte.intro/hasRun'; + +if (!window.localStorage.getItem(KEY)) { + const tour = new Shepherd.Tour({ + useModalOverlay: true, + defaultStepOptions: { + classes: 'shadow-md', + scrollTo: true, + arrow: false, + modalOverlayOpeningRadius: 4, + modalOverlayOpeningPadding: 4, + buttons: [ + { + text: '跳过引导', + secondary: true, + action() { + this.complete(); + }, + }, + { + text: '下一步', + action() { + this.next(); + }, + }, + ], + }, + }); + + tour.on('complete', () => { + window.localStorage.setItem(KEY, 'true'); + }); + + tour.addSteps(steps); + + tour.start(); +} diff --git a/web/plugins/com.msgbyte.intro/tsconfig.json b/web/plugins/com.msgbyte.intro/tsconfig.json new file mode 100644 index 00000000..beb3c60f --- /dev/null +++ b/web/plugins/com.msgbyte.intro/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "rootDir": "./src", + "baseUrl": "./src", + "esModuleInterop": true, + "jsx": "react", + "paths": { + "@capital/*": ["../../../src/plugin/*"], + } + } +} diff --git a/web/plugins/com.msgbyte.intro/yarn.lock b/web/plugins/com.msgbyte.intro/yarn.lock new file mode 100644 index 00000000..8dc9749a --- /dev/null +++ b/web/plugins/com.msgbyte.intro/yarn.lock @@ -0,0 +1,27 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@popperjs/core@^2.9.2": + version "2.10.1" + resolved "https://registry.nlark.com/@popperjs/core/download/@popperjs/core-2.10.1.tgz#728ecd95ab207aab8a9a4e421f0422db329232be" + integrity sha1-co7NlasgequKmk5CHwQi2zKSMr4= + +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.npm.taobao.org/deepmerge/download/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha1-RNLqNnm49NT/ujPwPYZfwee/SVU= + +shepherd.js@^8.3.1: + version "8.3.1" + resolved "https://registry.nlark.com/shepherd.js/download/shepherd.js-8.3.1.tgz#131eeefc5eb2bc44c9e23d0da139db46b2b55339" + integrity sha1-Ex7u/F6yvETJ4j0NoTnbRrK1Uzk= + dependencies: + "@popperjs/core" "^2.9.2" + deepmerge "^4.2.2" + smoothscroll-polyfill "^0.4.4" + +smoothscroll-polyfill@^0.4.4: + version "0.4.4" + resolved "https://registry.nlark.com/smoothscroll-polyfill/download/smoothscroll-polyfill-0.4.4.tgz#3a259131dc6930e6ca80003e1cb03b603b69abf8" + integrity sha1-OiWRMdxpMObKgAA+HLA7YDtpq/g=