【Rails7+TourGuide JS】Railsでアプリにチュートリアルを実装する

# TourGuide JSめっちゃすごい

https://tourguidejs.com/

[![Image from Gyazo](https://i.gyazo.com/38d151be4acc89851c53e9a0c39c0bd6.gif)](https://gyazo.com/38d151be4acc89851c53e9a0c39c0bd6)

動画の挙動を実際に触ってみたい方は[こちら](https://boozefolio.herokuapp.com/)

https://boozefolio.herokuapp.com/

しかもめっちゃ簡単です。

# Railsでの使用方法
※当方の環境はRails7系+Ruby3系＋esbuild＋Tailwindです

### 1.TourGuide JSを読み込む
npmでインストールする方法とCDNで読み込む方法があります。
私はyarnでパッケージ管理していたので、今回はCDNで読み込む方法を選択

下記をコピペして```<head>```タグの間に追加

```app/views/layouts/application.html.erb
<script src="https://unpkg.com/@sjmc11/tourguidejs/dist/tour.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<link rel="stylesheet" href="https://unpkg.com/@sjmc11/tourguidejs/dist/css/tour.min.css">
```

※CDN(Content Delivery Network)

https://developer.mozilla.org/ja/docs/Glossary/CDN

### 2.説明を入れたい箇所のタグに```data-tg-tour="メッセージ"```を入れる

```index.html.erbなど該当ファイル
<div data-tg-tour="こんにちは！">
```
って書くと、「こんにちは」とメッセージの入った吹き出しが現れます。これを起動させるためのJavascryptを追加します。

### 3.Javascryptで起動させる

```app/javascript/custom/tourguide.js　※ファイル名は任意
const tg = new tourguide.TourGuideClient(); // npmで導入している場合は new TourGuideClient();
tg.start();
```
```app/javascript/application.js
import "./custom/tourguide"
```

これで完成！吹き出しが現れるはずです。やってみてください。

## チュートリアルをカスタマイズする

### 説明文を加える、順番を指定する、色を変える、画像を挿入する
チュートリアルを実装する際、大体は何STEPかの説明を加えたいと思います。
その順番や文言を変えるのも簡単です。

```index.html.erbなど
<div data-tg-tour="今から便利な機能について説明します！" 
     data-tg-title="ようこそ✨"
     data-tg-order="1">Hi!</div>

<div data-tg-tour="<style='color:red;'>ここから投稿します</style>" 
     data-tg-title="ステップ１"
     data-tg-order="2">投稿</div>

<div data-tg-tour="お得なクーポンはこちら！<br>重要ポイント" 
     data-tg-title="ステップ２"
     data-tg-order="3">Finish!</div>
```

```data-tg-tour```がチュートリアル本文
```data-tg-title```が吹き出しタイトル
```data-tg-order```が表示順
です。また、data-tg-tourやdata-tg-title内ではHTMLが使えますので、色や文字サイズを変えたり、画像を挿入することも可能です。

また、別の書き方としてjavascryptファイルにまとめて定義する方法もあります。
私はこちらを使用しました。
```app/javascript/custom/tourguide.js
const steps = [
  {
    title: "登録有難うございます🌈",
    content: "BoozePediaへようこそ！<p>まずは飲みましょう🍺乾杯！</p>",
    target: "#one",
    order: 1,
  },{
    title: "記録する📷",
    content: "お酒はここから記録します。<p>初めての種類であればBoozePediaにページが追加されます✨</p>",
    target: "#two",
    order: 2,
  },{
    title: "なんてお呼びしましょうか？🐈‍⬛",
    content: "初期設定はGoogleで登録した氏名になっています。「ユーザー名前を変更する」から変更してください📝",
    target: "#three",
    order: 3,
  },{
    title: "<img src='https://boozepedia.s3.ap-northeast-3.amazonaws.com/material/icon80.png' alt='アイコン画像'>",
    content: "スマートフォンの方は「ホーム画面に追加」を押すとアイコンがホーム画面に追加されます。🏠",
    target: "#four",
    order: 4,
  },{
    title: "最後にお願い🌱",
    content: "マイページの「お問い合わせ」からエラーのご報告・ご意見ご要望をお願いします。🙏</p>",
    target: "#five",
    order: 5,
  }
]

const tg = new tourguide.TourGuideClient({steps: steps}); //{steps: steps}を引数に
tg.start();
```
HTML側はどうなるかというと、先ほどの```data-tg-tour```などは全て削除し、```id="one"```のようにtarget:部分と同一のidをつければOK.該当タグを探す必要がないので、何ステップかある場合やチーム開発の場合はこちらが便利だと思います。

### その他オプション
TourGuide JSにはオプションが用意されています
```
autoScroll: boolean = true// 要素への自動スクロール
autoScrollSmooth: boolean = true // 自動スムーズスクロール
autoScrollOffset: number = 20// スムーズスクロールのための端からのオフセット
backdropClass: string = ""// ツアー背景用の追加CSSクラス
backdropColor: string = "rgba(20,20,21,0.84)"// RGBAのサポートのみ
targetPadding: number = 30// px単位でハイライトされたターゲットの周りのスペース。
backdropAnimate: boolean = true// 背景の位置とサイズをアニメートする。
dialogClass: string = ""// ツアーダイアログの追加CSSクラス
dialogZ: number = 999// ダイアログのzインデックス
dialogWidth: number = 0// ダイアログの幅を指定します。
dialogMaxWidth: number = 340// ダイアログの最大幅スタイルプロパティ
dialogAnimate: boolean = true// ダイアログの位置とサイズをアニメートします。
closeButton: boolean = true// 閉じるボタンを表示する。
nextLabel: string = "Next"// 次のボタンのテキスト
prevLabel: string = "Back"// 前へ進むボタンのテキスト
finishLabel: string = "Finish"// 終了ボタンのテキスト
hidePrev: boolean = false// 前のボタンを隠す
hideNext: boolean = false// 次のボタンを隠す
completeOnFinish: boolean = true// 終了時にツアーを終了としてlocalStorageに設定する。
showStepDots: boolean = true// ツアーの進行状況を表示する。
stepDotsPlacement: 'footer' | 'body' = "footer"// ダイアログボディ/フッターにドットを表示する
showButtons: boolean = true// next/prev ボタンを表示する。
showStepProgress: boolean = true// `1/5`ステップの進捗を表示する。
progressBar: string = ""// ダイアログヘッダーの下にプログレスバーを表示 - 有効にするには色文字列を渡す
keyboardControls: boolean =false// next & prev 矢印キー + esc キーを表示する。
exitOnEscape: boolean = true// エスケープキーでツアーを閉じる
exitOnClickOutside: boolean = true// バックドロップクリックでツアーを閉じる
rememberStep: boolean = true// 最後にアクティブになったステップでツアーを開く
debug: boolean = false// コンソールログを表示する。
ステップTourGuideStep[]// ツアーステップの事前定義
```
実際の使い方は
```app/javascript/custom/tourguide.js
const options = {
  completeOnFinish: boolean = true
};

const steps = [
...
const tg = new tourguide.TourGuideClient( {steps: steps, options: options }); // { steps: steps, options: options }に変更
tg.start();
```
このように定義するだけ。全部は試せていないので、説明はできません🙃

### オプションが効かないよぉ😇
私の認識違いかもしれないのですが、指定した
```completeOnFinish: boolean = true// 終了時にツアーを終了としてlocalStorageに設定する。```が効かず、画面遷移するたびにチュートリアルが出現。私の嫌いなポップアップ型広告のごとく消しても消しても現れる……最悪だ……🫠

そこで、finishを押したら現れないように関数を定義します。
※ここからはchatGPTを使用しているため、信頼度の低い情報であることをご留意ください。
```
const tourGuideCookieName = "tourGuideShown";
const tourGuideShown = Cookies.get(tourGuideCookieName);

if (!tourGuideShown) {
  const tg = new tourguide.TourGuideClient({ steps: steps, options: options });
  tg.start();
  tg.onFinish(() => {
    Cookies.set(tourGuideCookieName, true);
  });
}
```
①```Cookies.get(tourGuideCookieName)```でCookieからtourGuideCookieNameに対応する値を取得します。
②if文で```tourGuideShown```が偽であるかどうかをチェック
③tourGuideCookieNameが存在しない場合、または値が偽である場合に条件がtrueとなります。
④条件がtrueの場合、チュートリアルをスタートし、tourGuideCookieNameという名前のクッキーにtrueの値を設定します。これにより、次回以降のページ読み込み時にツアーガイドが表示されないようになります。

また、検証していないので今回は書かないのですが、jsが効かない原因としてRailsのTurbo Driveが原因の能性があります。下記記事でTurbo Driveを切る方法が載っているのでそちらを試すのもアリかもしれません。

https://zenn.dev/takeyuwebinc/articles/8ebe80bf442dc2

チュートリアルを実装したアプリで挙動も確認したい方は以下からどうぞ

https://boozefolio.herokuapp.com/

ご指摘等ありましたら、コメントよろしくお願いします。