深呼吸アプリを作ってみたので振り返ります

# こちらの動画をもとに勉強させてもらいました</summary>

とにもかくにもこちらをご覧ください。

https://www.youtube.com/watch?v=jce9sb5EYco


# そして、出来上がったものがこちらです

文言を日本語にして、エステに来たみたいな
セリフにした以外は、ほぼ動画で作成されたもののままです。

https://webthevoice.net/breathmedication/

# まずはHTMLから

```html
<!DOCTYPE html>
<html lang="ja">

<head>
	<meta charset="UTF-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<link rel="stylesheet" href="./style.css">
	<title>は～い、深呼吸しましょうね～</title>
</head>

<body>
	<div class="input">
		<label>何回、深呼吸しますか～？</label>
		<select class="breath-input">
			<option value="3">3 回 深呼吸する</option>
			<option value="5">5 回 深呼吸する</option>
			<option value="7">7 回 深呼吸する</option>
		</select>
	</div>
	<div class="circle-wrap">
		<div class="circle-outline"></div>
		<div class="circle-progress"></div>
	</div>
	<p class="instructions">は～い、深呼吸する準備はできましたか～？<br>
		できましたらですね、下のボタンを押して下さいませ～</p>
	<button class="start">始めます</button>
	<p class="breaths">深呼吸をあと：<span class="breaths-text">3</span> 回しますね～
	</p>

	<script type="text/javascript" src="./app.js"></script>
</body>

</html>
```

:::note
良かった所
日本語にすることで、ユーザーにどういった工程を踏んでもらいたいのかより理解出来ました。
背景画像に黒く薄い膜をしく、という技を知り、体験できたのは良かったです。
:::

:::note warn
これから直してみたい所
深呼吸をあと：0 回しますね～ という表記が不自然なので、言葉でなんとかできたらしたいところです。
:::

# 続いてCSSです

```css
@import url("https://fonts.googleapis.com/css2?family=Sawarabi+Mincho&display=swap");

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  font-family: "Sawarabi Mincho", sans-serif;
}

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  color: #fff;
  background: url("./img/bg.jpg");
  background-size: cover;
}

body::after {
  content: "";
  position: absolute;
  height: 100%;
  width: 100%;
  background-color: rgba(0, 0, 0, 0.6);
  z-index: -1;
}

.input {
  display: flex;
  flex-direction: column;
  margin-bottom: 40px;
}

.input label {
  text-align: center;
  font-size: 80%;
  margin-bottom: 8px;
}

.input select {
  border: none;
  border-radius: 8px;
  min-width: 300px;
  font-size: 75%;
  padding: 8px 4px;
  background-color: #6236ff;
  color: #fff;
}

.input select:focus {
  outline: none;
}

.circle-wrap {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  position: relative;
  margin-bottom: 40px;
}

.circle-outline {
  width: 300px;
  height: 300px;
  border-radius: 50%;
  background-color: transparent;
  border: 15px solid #f1f1f1;
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
    0 4px 6px -2px rgba(0, 0, 0, 0.05);
}

.circle-progress {
  width: 50px;
  height: 50px;
  position: absolute;
  background-color: #6236ff;
  border-radius: 50%;
  transition: 4s ease all;
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
    0 4px 6px -2px rgba(0, 0, 0, 0.05);
}

.circle-grow {
  transform: scale(5.3);
}

.breaths {
  text-align: center;
  margin-top: 24px;
}

.breaths-text {
  font-size: 24px;
}

.instructions {
  text-align: center;
  margin-bottom: 32px;
}

button {
  padding: 8px 20px;
  border-radius: 8px;
  background-color: #6236ff;
  color: #fff;
  border: none;
  cursor: pointer;
  transition: 0.3s ease all;
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
    0 4px 6px -2px rgba(0, 0, 0, 0.05);
}

button:hover {
  background-color: #f1f1f1;
  color: #6236ff;
}

.button-inactive {
  pointer-events: none;
  background-color: #969696;
}
```

:::note
良かった所
"* {" ですべてを包括する、ということを知りました。
:::

:::note warn
これから直してみたい所
スマホ（GooglePixel3 Chrome）で確認すると、画面上下に若干、上レイヤーの隙間が見えるのでなんとかしたいところです。
body::after のコロンは一つで良かった気がします。
:::

# 最後にJSです

```javascript
const circleProgress = document.querySelector('.circle-progress');
const numberOfBreaths = document.querySelector('.breath-input');
const start = document.querySelector('.start');
const instructions = document.querySelector('.instructions');
const breathsText = document.querySelector('.breaths-text');
let breathsLeft = 3;

// ユーザーの呼吸回数選択を変更表示
numberOfBreaths.addEventListener('change', () => {
  breathsLeft = numberOfBreaths.value;
  breathsText.innerText = breathsLeft;
});

// 中央の円を拡大縮小させる
const growCircle = () => {
  circleProgress.classList.add('circle-grow');
  setTimeout(() => {
    circleProgress.classList.remove('circle-grow')
  }, 8000);
};

// 呼吸法の説明
const breathTextUpdate = () => {
  breathsLeft--;
  breathsText.innerText = breathsLeft;
  instructions.innerText = "はい、鼻から大きく吸って～";
  setTimeout(() => {
    instructions.innerText = "はい、ちょっと止めて～、まだよ～まだよ～";
    setTimeout(() => {
      instructions.innerText = "はい、口からゆっくり吐いて～"
    }, 4000);
  }, 4000)
}

// 呼吸に使用する関数
const breathingApp = () => {
  const breathingAnimation = setInterval(() => {
    if (breathsLeft === 0) {
      clearInterval(breathingAnimation);
      instructions.innerText = "は～い、お疲れさまでした～、温か～いお紅茶飲んでくださいね～";
      start.classList.remove('button-inactive');
      breathsLeft = numberOfBreaths.value;
      breathsText.innerText = breathsLeft;
      return;
    }
    growCircle();
    breathTextUpdate();
  }, 12000)
}

// 深呼吸開始ボタン
start.addEventListener('click', () => {
  start.classList.add("button-inactive");
  instructions.innerText = "リラ～ックス";
  setTimeout(() => {
    instructions.innerText = "は～い、始めますよ～";
    setTimeout(() => {
      breathingApp();
      growCircle();
      breathTextUpdate();
    }, 2000);
  }, 2000);
});
```

:::note
良かった所
とにかく、初心者でもできる範囲のスクリプト郡だったのがありがたかったです。
DOM操作を体験できたのは良かったです。
:::

:::note warn
これから直してみたい所
アロー関数がいまだに馴染め（記憶に定着し）てないので、ひきつづき使ってみたいところです。
", 12000" や "--;" や "const の入れ子構造" など、改めて見返すと、まだ馴染め（記憶に定着し）てないので、ひきつづき使ってみたいところです。
:::

# まとめ

Javascriptを勉強するに当たって、アウトプットするにはちょうどよい動画でしたので、
HTMLやCSSはある程度わかっていて、その上でJavascriptを初めてみたい方は
見てみてはいかがでしょうか？

英語ですが、Youtube内の設定で日本語自動翻訳ができます。
翻訳とコードでなんとかすすめることはできます。

深呼吸をさせるという、仕組みがとてもおもしろく、またデザインも洗練されていて、
丸の拡大縮小で深呼吸を促すのか！　その手があったか！　と、
とても楽しんで作ることができました。