feat(hooks): Add useIntro hook

feat: Add guide demo
This commit is contained in:
陈凯龙 2022-01-25 17:43:53 +08:00
parent cb558f8af9
commit 0832194e61
15 changed files with 235 additions and 50 deletions

View File

@ -33,6 +33,7 @@
"echarts": "^5.2.2",
"echarts-wordcloud": "^2.0.0",
"element-plus": "1.3.0-beta.7",
"intro.js": "^4.3.0",
"lodash-es": "^4.17.21",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
@ -50,6 +51,7 @@
"@iconify/json": "^1.1.459",
"@intlify/vite-plugin-vue-i18n": "^3.2.1",
"@purge-icons/generated": "^0.7.0",
"@types/intro.js": "^3.0.2",
"@types/lodash-es": "^4.17.5",
"@types/node": "^17.0.10",
"@types/nprogress": "^0.2.0",

View File

@ -7,6 +7,7 @@ specifiers:
'@iconify/json': ^1.1.459
'@intlify/vite-plugin-vue-i18n': ^3.2.1
'@purge-icons/generated': ^0.7.0
'@types/intro.js': ^3.0.2
'@types/lodash-es': ^4.17.5
'@types/node': ^17.0.10
'@types/nprogress': ^0.2.0
@ -30,6 +31,7 @@ specifiers:
eslint-plugin-prettier: ^4.0.0
eslint-plugin-vue: ^8.3.0
husky: ^7.0.4
intro.js: ^4.3.0
less: ^4.1.2
lint-staged: ^12.2.2
lodash-es: ^4.17.21
@ -75,6 +77,7 @@ dependencies:
echarts: registry.npmmirror.com/echarts/5.2.2
echarts-wordcloud: registry.npmmirror.com/echarts-wordcloud/2.0.0_echarts@5.2.2
element-plus: registry.npmmirror.com/element-plus/1.3.0-beta.7_vue@3.2.26
intro.js: registry.npmmirror.com/intro.js/4.3.0
lodash-es: registry.nlark.com/lodash-es/4.17.21
mockjs: registry.npmmirror.com/mockjs/1.1.0
nprogress: registry.npmmirror.com/nprogress/0.2.0
@ -92,6 +95,7 @@ devDependencies:
'@iconify/json': registry.npmmirror.com/@iconify/json/1.1.459
'@intlify/vite-plugin-vue-i18n': registry.npmmirror.com/@intlify/vite-plugin-vue-i18n/3.2.1_vite@2.7.13+vue-i18n@9.1.9
'@purge-icons/generated': registry.nlark.com/@purge-icons/generated/0.7.0
'@types/intro.js': registry.npmmirror.com/@types/intro.js/3.0.2
'@types/lodash-es': registry.npmmirror.com/@types/lodash-es/4.17.5
'@types/node': registry.npmmirror.com/@types/node/17.0.10
'@types/nprogress': registry.npmmirror.com/@types/nprogress/0.2.0
@ -3910,25 +3914,6 @@ packages:
version: 1.4.0
dev: true
registry.nlark.com/needle/2.9.1:
resolution:
{
integrity: sha1-ItHf++NJDCuD4wH3cJtnNs2PJoQ=,
registry: https://registry.npm.taobao.org/,
tarball: https://registry.nlark.com/needle/download/needle-2.9.1.tgz
}
name: needle
version: 2.9.1
engines: { node: '>= 4.4.x' }
hasBin: true
requiresBuild: true
dependencies:
debug: registry.npmmirror.com/debug/3.2.7
iconv-lite: registry.nlark.com/iconv-lite/0.4.24
sax: registry.nlark.com/sax/1.2.4
dev: true
optional: true
registry.nlark.com/no-case/3.0.4:
resolution:
{
@ -7288,8 +7273,8 @@ packages:
vue-i18n:
optional: true
dependencies:
'@intlify/message-compiler': registry.npmmirror.com/@intlify/message-compiler/9.2.0-beta.28
'@intlify/shared': registry.npmmirror.com/@intlify/shared/9.2.0-beta.28
'@intlify/message-compiler': registry.npmmirror.com/@intlify/message-compiler/9.2.0-beta.29
'@intlify/shared': registry.npmmirror.com/@intlify/shared/9.2.0-beta.29
jsonc-eslint-parser: registry.npmmirror.com/jsonc-eslint-parser/1.4.1
source-map: registry.nlark.com/source-map/0.6.1
vue-i18n: registry.npmmirror.com/vue-i18n/9.1.9_vue@3.2.26
@ -7345,18 +7330,18 @@ packages:
source-map: registry.nlark.com/source-map/0.6.1
dev: false
registry.npmmirror.com/@intlify/message-compiler/9.2.0-beta.28:
registry.npmmirror.com/@intlify/message-compiler/9.2.0-beta.29:
resolution:
{
integrity: sha512-NBH9fZyitN2cijGt8bmU1W7ZPdhKbgW01L1RxJKFJW0cRaCmknJq63Aif1Q6xcxKt9ZhPbvIKHgPGzg1nWMfeA==,
integrity: sha512-FvMDwe57VvupujvNYUY90J8wv26wKu6j7I93dLwBOo/PTg7nQqFrmYQAF23UfDAdXO4FTdgHfFyb5ecYrN+n3g==,
registry: https://registry.npm.taobao.org/,
tarball: https://registry.npmmirror.com/@intlify/message-compiler/download/@intlify/message-compiler-9.2.0-beta.28.tgz
tarball: https://registry.npmmirror.com/@intlify/message-compiler/download/@intlify/message-compiler-9.2.0-beta.29.tgz
}
name: '@intlify/message-compiler'
version: 9.2.0-beta.28
version: 9.2.0-beta.29
engines: { node: '>= 12' }
dependencies:
'@intlify/shared': registry.npmmirror.com/@intlify/shared/9.2.0-beta.28
'@intlify/shared': registry.npmmirror.com/@intlify/shared/9.2.0-beta.29
source-map: registry.nlark.com/source-map/0.6.1
dev: true
@ -7400,15 +7385,15 @@ packages:
engines: { node: '>= 10' }
dev: false
registry.npmmirror.com/@intlify/shared/9.2.0-beta.28:
registry.npmmirror.com/@intlify/shared/9.2.0-beta.29:
resolution:
{
integrity: sha512-JBMcoj1D4kSAma7Vb0+d8z6lPLIn7hIdZJPxbU8bgeMMniwKLoIS/jGlEfrZihsB5+otckPeQp203z8skwVS0w==,
integrity: sha512-blMW14WBr3fiCEk/XO4IbSxM8WMAhQOzEgWzP1aqbkeXbIMiHeyFI0ZexwyTKsvDZz0wEWlhupQi+9udrJsozA==,
registry: https://registry.npm.taobao.org/,
tarball: https://registry.npmmirror.com/@intlify/shared/download/@intlify/shared-9.2.0-beta.28.tgz
tarball: https://registry.npmmirror.com/@intlify/shared/download/@intlify/shared-9.2.0-beta.29.tgz
}
name: '@intlify/shared'
version: 9.2.0-beta.28
version: 9.2.0-beta.29
engines: { node: '>= 12' }
dev: true
@ -7434,7 +7419,7 @@ packages:
optional: true
dependencies:
'@intlify/bundle-utils': registry.npmmirror.com/@intlify/bundle-utils/2.2.0_vue-i18n@9.1.9
'@intlify/shared': registry.npmmirror.com/@intlify/shared/9.2.0-beta.28
'@intlify/shared': registry.npmmirror.com/@intlify/shared/9.2.0-beta.29
'@rollup/pluginutils': registry.npmmirror.com/@rollup/pluginutils/4.1.2
debug: registry.npmmirror.com/debug/4.3.3
fast-glob: registry.nlark.com/fast-glob/3.2.7
@ -7572,6 +7557,17 @@ packages:
version: 0.0.39
dev: true
registry.npmmirror.com/@types/intro.js/3.0.2:
resolution:
{
integrity: sha1-y/m2nwVbd1gsws6+I26aQFsw770=,
registry: https://registry.npm.taobao.org/,
tarball: https://registry.npmmirror.com/@types/intro.js/download/@types/intro.js-3.0.2.tgz
}
name: '@types/intro.js'
version: 3.0.2
dev: true
registry.npmmirror.com/@types/json-schema/7.0.9:
resolution:
{
@ -10629,6 +10625,17 @@ packages:
through: registry.nlark.com/through/2.3.8
dev: true
registry.npmmirror.com/intro.js/4.3.0:
resolution:
{
integrity: sha512-F4LXM42QIXcO3/2myGBBFdbbUVUK0lBhK7pAxPLd082u+3HfvigFR+Rptqy05q3OzjG/O0vMFDedrnHdSPi2rQ==,
registry: https://registry.npm.taobao.org/,
tarball: https://registry.npmmirror.com/intro.js/download/intro.js-4.3.0.tgz
}
name: intro.js
version: 4.3.0
dev: false
registry.npmmirror.com/is-buffer/1.1.6:
resolution:
{
@ -10840,7 +10847,7 @@ packages:
image-size: registry.npmmirror.com/image-size/0.5.5
make-dir: registry.nlark.com/make-dir/2.1.0
mime: registry.npmmirror.com/mime/1.6.0
needle: registry.nlark.com/needle/2.9.1
needle: registry.npmmirror.com/needle/2.9.1
source-map: registry.nlark.com/source-map/0.6.1
dev: true
@ -11191,6 +11198,25 @@ packages:
engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 }
hasBin: true
registry.npmmirror.com/needle/2.9.1:
resolution:
{
integrity: sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==,
registry: https://registry.npm.taobao.org/,
tarball: https://registry.npmmirror.com/needle/download/needle-2.9.1.tgz
}
name: needle
version: 2.9.1
engines: { node: '>= 4.4.x' }
hasBin: true
requiresBuild: true
dependencies:
debug: registry.npmmirror.com/debug/3.2.7
iconv-lite: registry.nlark.com/iconv-lite/0.4.24
sax: registry.nlark.com/sax/1.2.4
dev: true
optional: true
registry.npmmirror.com/node-fetch/2.6.1:
resolution:
{

View File

@ -0,0 +1,3 @@
import ContentWrap from './src/ContentWrap.vue'
export { ContentWrap }

View File

@ -0,0 +1,35 @@
<script setup lang="ts">
import { ElCard, ElTooltip } from 'element-plus'
import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign'
const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('content-wrap')
defineProps({
title: propTypes.string.def(''),
message: propTypes.string.def('')
})
</script>
<template>
<ElCard :class="prefixCls" shadow="never">
<template v-if="title" #header>
<div class="flex items-center">
{{ title }}
<ElTooltip v-if="message" effect="dark" placement="right">
<template #content>
<div class="max-w-200px">{{ message }}</div>
</template>
<Icon class="ml-5px" icon="bi:question-circle-fill" :size="14" />
</ElTooltip>
</div>
</template>
<div>
<slot></slot>
</div>
</ElCard>
</template>
<style lang="less" scoped></style>

View File

@ -70,6 +70,7 @@ export default defineComponent({
return () => (
<div
id={prefixCls}
class={[
`${prefixCls} ${prefixCls}__${unref(menuMode)}`,
'h-[100%] overflow-hidden z-100 flex-col bg-[var(--left-menu-bg-color)]',

View File

@ -12,7 +12,7 @@ import { cloneDeep } from 'lodash-es'
import { filterMenusPath, initTabMap, tabPathMap } from './helper'
import { useDesign } from '@/hooks/web/useDesign'
const { getPrefixCls } = useDesign()
const { getPrefixCls, variables } = useDesign()
const prefixCls = getPrefixCls('tab-menu')
@ -106,6 +106,7 @@ export default defineComponent({
return () => (
<div
id={`${variables.namespace}-menu`}
class={[
prefixCls,
'relative bg-[var(--left-menu-bg-color)] top-1px',

View File

@ -148,7 +148,7 @@ watch(
</script>
<template>
<div :class="prefixCls" class="h-[var(--tags-view-height)] flex w-full relative">
<div :id="prefixCls" :class="prefixCls" class="h-[var(--tags-view-height)] flex w-full relative">
<span
:class="`${prefixCls}__tool`"
class="w-[var(--tags-view-height)] h-[var(--tags-view-height)] text-center leading-[var(--tags-view-height)] cursor-pointer"

41
src/hooks/web/useIntro.ts Normal file
View File

@ -0,0 +1,41 @@
import introJs from 'intro.js'
import { IntroJs, Step, Options } from 'intro.js'
import 'intro.js/introjs.css'
import { useI18n } from '@/hooks/web/useI18n'
import { useDesign } from '@/hooks/web/useDesign'
export const useIntro = (setps?: Step[], options?: Options) => {
const { t } = useI18n()
const { variables } = useDesign()
const defaultSetps: Step[] = setps || [
{
element: `#${variables.namespace}-menu`,
title: t('common.menu'),
intro: t('common.menuDes'),
position: 'right'
},
{
element: `#${variables.namespace}-tags-view`,
title: t('common.tagsView'),
intro: t('common.tagsViewDes'),
position: 'bottom'
}
]
const defaultOptions: Options = options || {
prevLabel: t('common.prevLabel'),
nextLabel: t('common.nextLabel'),
skipLabel: t('common.skipLabel'),
doneLabel: t('common.doneLabel')
}
const introRef: IntroJs = introJs()
introRef.addSteps(defaultSetps).setOptions(defaultOptions)
return {
introRef
}
}

View File

@ -11,7 +11,7 @@ import { useDesign } from '@/hooks/web/useDesign'
const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('layout-content')
const prefixCls = getPrefixCls('layout')
const appStore = useAppStore()
@ -54,7 +54,7 @@ export const useRenderLayout = () => {
</div>
<div
class={[
prefixCls,
`${prefixCls}-content`,
'absolute top-0 h-[100%]',
{
'w-[calc(100%-var(--left-menu-min-width))] left-[var(--left-menu-min-width)]':
@ -69,7 +69,7 @@ export const useRenderLayout = () => {
<ElScrollbar
v-loading={pageLoading.value}
class={[
`${prefixCls}-scrollbar`,
`${prefixCls}-content-scrollbar`,
{
'!h-[calc(100%-var(--top-tool-height)-var(--tags-view-height))] mt-[calc(var(--top-tool-height)+var(--tags-view-height))]':
fixedHeader.value
@ -115,7 +115,7 @@ export const useRenderLayout = () => {
<Menu class="!h-full"></Menu>
<div
class={[
prefixCls,
`${prefixCls}-content`,
'h-[100%]',
{
'w-[calc(100%-var(--left-menu-min-width))] left-[var(--left-menu-min-width)]':
@ -129,7 +129,7 @@ export const useRenderLayout = () => {
<ElScrollbar
v-loading={pageLoading.value}
class={[
`${prefixCls}-scrollbar`,
`${prefixCls}-content-scrollbar`,
{
'!h-[calc(100%-var(--tags-view-height))] mt-[calc(var(--tags-view-height))]':
fixedHeader.value && tagsView.value
@ -168,11 +168,11 @@ export const useRenderLayout = () => {
<Menu class="flex-1 px-10px h-[var(--top-tool-height)]"></Menu>
<ToolHeader></ToolHeader>
</div>
<div class={[prefixCls, 'v-content h-full w-full']}>
<div class={[`${prefixCls}-content`, 'h-full w-full']}>
<ElScrollbar
v-loading={pageLoading.value}
class={[
`${prefixCls}-scrollbar`,
`${prefixCls}-content-scrollbar`,
{
'mt-[var(--tags-view-height)]': fixedHeader.value
}
@ -207,10 +207,9 @@ export const useRenderLayout = () => {
</div>
<div class="absolute top-[var(--logo-height)] left-0 w-full h-[calc(100%-var(--logo-height))] flex">
<TabMenu></TabMenu>
{/* <Menu class="!h-full"></Menu> */}
<div
class={[
prefixCls,
`${prefixCls}-content`,
'h-[100%]',
{
'w-[calc(100%-var(--tab-menu-min-width))] left-[var(--tab-menu-min-width)]':
@ -224,7 +223,7 @@ export const useRenderLayout = () => {
<ElScrollbar
v-loading={pageLoading.value}
class={[
`${prefixCls}-scrollbar`,
`${prefixCls}-content-scrollbar`,
{
'!h-[calc(100%-var(--tags-view-height))] mt-[calc(var(--tags-view-height))]':
fixedHeader.value && tagsView.value

View File

@ -17,7 +17,17 @@ export default {
closeTheLeftTab: 'Close left',
closeTheRightTab: 'Close right',
closeOther: 'Close other',
closeAll: 'Close all'
closeAll: 'Close all',
prevLabel: 'Prev',
nextLabel: 'Next',
skipLabel: 'Jump',
doneLabel: 'End',
menu: 'Menu',
menuDes: 'Menu bar rendered in routed structure',
collapse: 'Collapse',
collapseDes: 'Expand and zoom the menu bar',
tagsView: 'Tags view',
tagsViewDes: 'Used to record routing history'
},
setting: {
projectSetting: 'Project setting',
@ -72,7 +82,8 @@ export default {
menu2: 'Menu2',
dashboard: 'Dashboard',
analysis: 'Analysis',
workplace: 'Workplace'
workplace: 'Workplace',
guide: 'Guide'
},
analysis: {
newUser: 'New user',
@ -173,5 +184,11 @@ export default {
timeSelect: 'Time Select',
inputPassword: 'input Password',
passwordStrength: 'Password Strength'
},
guideDemo: {
guide: 'Guide',
start: 'Start',
message:
'The guide page is very useful for some people who enter the project for the first time. You can briefly introduce the functions of the project. The boot page is based on intro js'
}
}

View File

@ -17,7 +17,17 @@ export default {
closeTheLeftTab: '关闭左侧标签页',
closeTheRightTab: '关闭右侧标签页',
closeOther: '关闭其他标签页',
closeAll: '关闭全部标签页'
closeAll: '关闭全部标签页',
prevLabel: '上一步',
nextLabel: '下一步',
skipLabel: '跳过',
doneLabel: '结束',
menu: '菜单',
menuDes: '以路由的结构渲染的菜单栏',
collapse: '展开缩收',
collapseDes: '展开和缩放菜单栏',
tagsView: '标签页',
tagsViewDes: '用于记录路由历史记录'
},
setting: {
projectSetting: '项目配置',
@ -72,7 +82,8 @@ export default {
menu2: '菜单2',
dashboard: '首页',
analysis: '分析页',
workplace: '工作台'
workplace: '工作台',
guide: '引导'
},
analysis: {
newUser: '新增用户',
@ -173,5 +184,11 @@ export default {
timeSelect: '时间选择',
inputPassword: '密码输入框',
passwordStrength: '密码强度'
},
guideDemo: {
guide: '引导页',
start: '开始',
message:
'引导页对于一些第一次进入项目的人很有用,你可以简单介绍下项目的功能。引导页基于 intro.js'
}
}

View File

@ -68,6 +68,23 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
}
]
},
{
path: '/guide',
component: Layout,
name: 'Guide',
meta: {},
children: [
{
path: 'index',
component: () => import('@/views/Guide/Guide.vue'),
name: 'GuideDemo',
meta: {
title: t('router.guide'),
icon: 'cib:telegram-plane'
}
}
]
},
{
path: '/level',
component: Layout,

20
src/views/Guide/Guide.vue Normal file
View File

@ -0,0 +1,20 @@
<script setup lang="ts">
import { ContentWrap } from '@/components/ContentWrap'
import { useI18n } from '@/hooks/web/useI18n'
import { useIntro } from '@/hooks/web/useIntro'
import { ElButton } from 'element-plus'
const { t } = useI18n()
const { introRef } = useIntro()
const guideStart = () => {
introRef.start()
}
</script>
<template>
<ContentWrap :title="t('guideDemo.guide')" :message="t('guideDemo.message')">
<ElButton type="primary" @click="guideStart">{{ t('guideDemo.start') }}</ElButton>
</ContentWrap>
</template>

View File

@ -23,7 +23,12 @@
"paths": {
"@/*": ["src/*"]
},
"types": ["@intlify/vite-plugin-vue-i18n/client", "vite/client", "element-plus/global"],
"types": [
"@intlify/vite-plugin-vue-i18n/client",
"vite/client",
"element-plus/global",
"@types/intro.js"
],
"typeRoots": ["./node_modules/@types/", "./types"]
},
"include": ["src/**/*", "types/**/*.d.ts", "mock/**/*.ts"],

View File

@ -132,7 +132,8 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
'axios',
'qs',
'echarts',
'echarts-wordcloud'
'echarts-wordcloud',
'intro.js'
]
}
}