Как добавить интерактивный туториал на сайт используя React
Вступление или для чего вообще нужен интерактивный туториал
Привет, опять. В этой статье ты узнаешь как быстро и просто создать интерактивный туториал по вашему инструменту на Реакте. И первый вопрос который бы я задал, был бы такой: а нужен ли он вообще?
И действительно, если функционал инструмента максимально простой и интуитивно понятный, то заморачиваться над туториалом не стоит. В идеале, к этому и нужно стремиться чтобы пользователь без всякой лишней мысли приступал к использованию твоего инструмента.
Но как это бывает в реальной жизни, не все инструменты одно кнопочные и у многих большой и сложный функционал. Взять к примеру следующие веб-инструменты:
- Topvisor
- Google Analytics
Нельзя так просто взять и пользоваться ими. Сначала, ты должен научиться ими пользоваться. В моём случае получился не очень интуитивно понятный инструмент. По этому будем делать встроенный туториал на сайт.
Создание собственного ивента для запуска туториала
У нас уже есть кнопка для вызова цепочки подсказок
Нужно теперь её настроить так, чтобы эта цепочка работала. Сделаем мы это через создание собственного события.
В файле Header.js замени:
export default function Header() {
const header_buttons = document.getElementById('meta-header')
const btns = []
for ( const btn of header_buttons.children){
const ref = btn.firstElementChild.getAttribute('href')
if (btn.dataset.type == 'inner-link'){
btns.push()
}
else if (btn.dataset.type == 'tutorial' ){
btns.push()
}
export default function Header() {
const header_buttons = document.getElementById('meta-header')
const btns = []
for ( const btn of header_buttons.children){
const ref = btn.firstElementChild.getAttribute('href')
if (btn.dataset.type == 'inner-link'){
btns.push()
}
else if (btn.dataset.type == 'tutorial' ){
btns.push()
}
Мы добавили к кнопке айдишник + собственное событие на клик.
Создание нового компонента Tutorial.js
Теперь создадим новый компонент. В директории src/components создай файл Tutorial.js. После чего добавь туда следующий код:
import * as React from 'react';
import { createRoot } from 'react-dom/client';
import Popover from '@mui/material/Popover';
export default function Hint({children, anchor}) {
const [anchorEl, setAnchorEl] = React.useState(null);
const [counter, setCounter] = React.useState(1);
const [message, setMessage] = React.useState('');
const clearAllHints = () => {
const hints = document.querySelectorAll('.tutorial_hint')
hints.forEach( (hint_target) => {
hint_target.style = ''
if (hint_target.classList.contains('to_be_hidden')){
hint_target.classList.add('hidden')
hint_target.classList.remove('to_be_hidden')
}
})
}
const displayNextHint = () => {
const hints = document.querySelectorAll('.tutorial_hint')
hints.forEach( (hint_target) => {
if (parseInt(hint_target.dataset.queue) == counter){
hint_target.style = 'background-color: orange'
if (hint_target.classList.contains('hidden')){
hint_target.classList.remove('hidden')
hint_target.classList.add('to_be_hidden')
}
var hint_msg = document.getElementById(`tutorial_hint_${hint_target.dataset.queue}`)
setMessage(hint_msg.innerText)
setAnchorEl(hint_target)
}
})
setCounter(counter + 1)
}
const handleClick = (event) => {
clearAllHints()
displayNextHint()
};
let tutorial_button = document.getElementById('onTutorial')
tutorial_button.addEventListener('onTutorial', handleClick, {once: true})
const handleClose = () => {
const hints = document.querySelectorAll('.tutorial_hint')
if (hints.length < counter){
setMessage('')
setCounter(1)
setAnchorEl(null);
clearAllHints()
}
else{
clearAllHints()
displayNextHint()
}
};
const open = Boolean(anchorEl);
const id = open ? 'simple-popover' : undefined;
return (
{message}
);
}
const popover = document.getElementById('popover-tutorial');
const root = createRoot(popover);
root.render( );
Суть данного кода сводиться к тому, чтобы искать помеченные элементы с классом tutorial_hint и отрендерить подсказку рядом с этим элементом. Функцию на которую стоит обратить внимание это displayNextHint. Найдя все помеченные элементы, она находит элемент с ней связанный и берёт от туда текст подсказки. После чего выделяет элемент подсказки и показывает саму подсказку.
Чтобы компонент смог отрендериться добавим ещё один элемент в app.html, прямо перед app_settings элементом.
И подключим новый компонент в index.js
Помечаем элементы для подсказок
Осталось только пометить необходимые элементы для подсказок.
export default function AppActions(){
const [isModal, setModal] = React.useState(false);
const req = {'setModal': setModal}
return (
Optional: Then you can save all of your configurations
{setModal(true); waitTillModalIsUp(SaveRequest, req)}} className='w-fit tutorial_hint' data-queue="4">
{setModal(false)}}
>
Step 3: And now you can gather all informatino from SERP results
{StartParsingRequest(req)}} className='w-fit tutorial_hint'>
)
}
export default function AppQueries(){
…
return (
{engine_list}
Step 2: Choose an required engine to parse. And then type your query
handleClick(ev,engine_list)} className='w-fit tutorial_hint' data-queue="2">
)
}
export default function AppSettings(){
...
return (
Step 1: Check at least one checkbox, to choose what to save
{/* Icon button is gonna be changed */}
{ isSettings ?
: }
)
}
export default function AppUtils(){
...
return (
Here you can find the most popular and ready-to-use presets
Here you will find your own presets
Here you will see the actual proccess of gathering information
It is a link to a results of parsing proccess
...
}
Выводы или то как это выглядит
По итогу всё это будет выглядеть как-то так:
Если ты пропустил всё что было выше и хочешь просто получить проект в текущем состоянии, то ты можешь скачать его здесь
В следующей статье мы создадим возможность пользователям, входить и регистрироваться на нашем сайте.
0