🛒

嫁から頼まれた買い物リストを忘れないwebアプリ作った

2024/11/02に公開

今回のwebアプリは自分のために作成したアプリです。
俺得っていうやつです。

完成品の紹介

テキストフィールドに嫁さんからきたラインをコピーした文章を
テキストフィールドにペーストをします。

その後にボタンを押してチェックリストが表示されるだけのアプリです。
買い物かごにぶち込んだ後はチェックするだけです。

実物は以下を参照してください

https://shopping-checklist-ruby.vercel.app/

プロジェクトの作成

作成したいディレクトリに移動してから

npx create-next-app@latest shopping-checklist

設定は以下のような感じです。
ほぼほぼデフォルトを選択しました。

✔ Would you like to use TypeScript? … No / Yes #ここはYes
✔ Would you like to use ESLint? … No / Yes #ここはYes
✔ Would you like to use Tailwind CSS? … No / Yes #ここはYes
✔ Would you like your code inside a `src/` directory? … No / Yes #ここはYes
✔ Would you like to use App Router? (recommended) … No / Yes #ここはYes
✔ Would you like to use Turbopack for next dev? … No / Yes #ここはNo
✔ Would you like to customize the import alias (@/* by default)? … No / Yes #ここはNo

作成後は色々フォルダがありますが
プロジェクト名/src/app/page.tsxにコードを貼り付けるだけです。

コード

// src/app/page.tsx

"use client";

import React, { useState } from "react";

// チェックリスト用のメインコンポーネント
const ClipboardCheckList: React.FC = () => {
  // `items` はチェックリストの項目を保持する状態
  const [items, setItems] = useState<string[]>([]);
  // `manualInput` はテキストエリアに入力される文字列を保持する状態
  const [manualInput, setManualInput] = useState<string>("");

  // `handlePaste` はテキストエリアの内容を分割してリストに追加する関数
  const handlePaste = () => {
    // テキストエリアから各行を取得し、空行を削除してリスト化
    const lines = manualInput.split("\n").filter((line) => line.trim() !== "");
    // `items` 状態に行ごとに分割されたリストをセット
    setItems(lines);
    // テキストエリアをクリア
    setManualInput("");
  };

  // `handleClear` はチェックリストをクリアする関数
  const handleClear = () => {
    // `items` 状態と `checkedItems` 状態をリセット
    setItems([]);
    setCheckedItems({});
  };

  // `checkedItems` は各チェックボックスの選択状態を保持する状態
  const [checkedItems, setCheckedItems] = useState<{ [key: number]: boolean }>(
    {}
  );

  // `handleCheckboxChange` は特定の項目のチェック状態を切り替える関数
  const handleCheckboxChange = (index: number) => {
    // `checkedItems` 状態の指定インデックスを反転させる
    setCheckedItems((prev) => ({
      ...prev,
      [index]: !prev[index],
    }));
  };

  return (
    <div className="p-4 max-w-md mx-auto">
      <h1 className="text-2xl font-bold mb-4">Shopping Checklist</h1>
      {/* 手動で内容を貼り付けるためのテキストエリア */}
      <textarea
        value={manualInput}
        onChange={(e) => setManualInput(e.target.value)}
        placeholder="ここにリストを貼り付けてください"
        className="w-full p-2 border rounded-md mb-2 text-black"
        rows={4}
      />
      {/* ペーストとクリアのアクションボタン */}
      <div className="flex space-x-2 mb-4">
        <button
          onClick={handlePaste}
          className="px-4 py-2 bg-blue-500 text-white rounded-md"
        >
          Add to List
        </button>
        <button
          onClick={handleClear}
          className="px-4 py-2 bg-red-500 text-white rounded-md"
        >
          Clear List
        </button>
      </div>
      {/* チェックリストの項目一覧 */}
      <ul className="space-y-2">
        {items.map((item, index) => (
          <li key={index} className="flex items-center">
            {/* チェックボックスとテキストをラベルで囲み、クリックでチェックをトグル */}
            <label className="flex items-center cursor-pointer">
              <input
                type="checkbox"
                checked={!!checkedItems[index]}
                onChange={() => handleCheckboxChange(index)}
                className="mr-2"
              />
              {/* チェック済み項目は打消し線と灰色に */}
              <span
                className={`${
                  checkedItems[index] ? "line-through text-gray-500" : ""
                }`}
              >
                {item}
              </span>
            </label>
          </li>
        ))}
      </ul>
    </div>
  );
};

// ページ全体のエクスポート用関数
export default function Home() {
  return <ClipboardCheckList />;
}

終わりに

今回は完全に個人的なwebアプリを作成しました。
Next.jsを勉強中でデプロイをしてみたかったのもあって今回のものを作りました。

それにしてNext.jsやtailwindは楽ですね…
もっと勉強して理解を深めていきます。

Discussion