iTranslated by AI
I Built a Web App to Never Forget My Wife's Shopping List
This web app is an app I created for myself.
It's what you call a project for my own benefit.
Introduction of the Finished Product
You paste the text you copied from a LINE message sent by your wife
into the text field.
After that, it's just an app where the checklist is displayed when you press a button.
Once you've tossed the items into your shopping cart, you just check them off.

Please refer to the following for the actual app:
Creating the Project
After moving to the directory where you want to create the project:
npx create-next-app@latest shopping-checklist
The settings are something like this.
I selected almost all the defaults.
✔ Would you like to use TypeScript? … No / Yes #Select Yes
✔ Would you like to use ESLint? … No / Yes #Select Yes
✔ Would you like to use Tailwind CSS? … No / Yes #Select Yes
✔ Would you like your code inside a `src/` directory? … No / Yes #Select Yes
✔ Would you like to use App Router? (recommended) … No / Yes #Select Yes
✔ Would you like to use Turbopack for next dev? … No / Yes #Select No
✔ Would you like to customize the import alias (@/* by default)? … No / Yes #Select No
There are various folders after creation, but
you just need to paste the code into project-name/src/app/page.tsx.
Code
// src/app/page.tsx
"use client";
import React, { useState } from "react";
// Main component for the checklist
const ClipboardCheckList: React.FC = () => {
// `items` is the state that holds the checklist items
const [items, setItems] = useState<string[]>([]);
// `manualInput` is the state that holds the string entered in the textarea
const [manualInput, setManualInput] = useState<string>("");
// `handlePaste` is a function that splits the content of the textarea and adds it to the list
const handlePaste = () => {
// Get each line from the textarea, remove empty lines, and convert to a list
const lines = manualInput.split("\n").filter((line) => line.trim() !== "");
// Set the list split by line into the `items` state
setItems(lines);
// Clear the textarea
setManualInput("");
};
// `handleClear` is a function that clears the checklist
const handleClear = () => {
// Reset both `items` and `checkedItems` states
setItems([]);
setCheckedItems({});
};
// `checkedItems` is the state that holds the checked status of each checkbox
const [checkedItems, setCheckedItems] = useState<{ [key: number]: boolean }>(
{}
);
// `handleCheckboxChange` is a function that toggles the check status of a specific item
const handleCheckboxChange = (index: number) => {
// Invert the specified index in the `checkedItems` state
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 for manually pasting the content */}
<textarea
value={manualInput}
onChange={(e) => setManualInput(e.target.value)}
placeholder="Paste your list here"
className="w-full p-2 border rounded-md mb-2 text-black"
rows={4}
/>
{/* Action buttons for paste and clear */}
<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>
{/* List of checklist items */}
<ul className="space-y-2">
{items.map((item, index) => (
<li key={index} className="flex items-center">
{/* Wrap checkbox and text in a label to toggle check on click */}
<label className="flex items-center cursor-pointer">
<input
type="checkbox"
checked={!!checkedItems[index]}
onChange={() => handleCheckboxChange(index)}
className="mr-2"
/>
{/* Checked items are struck through and grayed out */}
<span
className={`${
checkedItems[index] ? "line-through text-gray-500" : ""
}`}
>
{item}
</span>
</label>
</li>
))}
</ul>
</div>
);
};
// Function for exporting the entire page
export default function Home() {
return <ClipboardCheckList />;
}
Closing
This time, I created a completely personal web app.
I created this because I am studying Next.js and wanted to try deploying something.
That being said, Next.js and Tailwind are so convenient...
I will continue to study and deepen my understanding.
Discussion