iT邦幫忙

2025 iThome 鐵人賽

DAY 23
0
生成式 AI

30天用React打造AI工具箱系列 第 23

30天用React打造AI工具箱 Day23

  • 分享至 

  • xImage
  •  

30天用React打造AI工具箱 Day23

主題

Day23我們就來做筆記管理工具Note Manager」吧

功能介紹

  • 新增筆記(標題+內容)
  • 搜尋筆記(即時過濾)
  • 刪除筆記
  • 自動保存至 localStorage(重新整理不會消失)
  • 簡潔 UI + Tailwind CSS 樣式

程式碼

新增一個NoteManager

import { useState, useEffect } from "react"

export default function NoteManager() {
  const [notes, setNotes] = useState([])
  const [title, setTitle] = useState("")
  const [content, setContent] = useState("")
  const [search, setSearch] = useState("")

  // 讀取 localStorage
  useEffect(() => {
    const saved = JSON.parse(localStorage.getItem("notes") || "[]")
    setNotes(saved)
  }, [])

  // 自動儲存
  useEffect(() => {
    localStorage.setItem("notes", JSON.stringify(notes))
  }, [notes])

  const addNote = () => {
    if (!title.trim() || !content.trim()) return
    const newNote = {
      id: Date.now(),
      title,
      content,
      date: new Date().toLocaleString(),
    }
    setNotes([newNote, ...notes])
    setTitle("")
    setContent("")
  }

  const deleteNote = (id) => {
    setNotes(notes.filter((n) => n.id !== id))
  }

  const filteredNotes = notes.filter(
    (n) =>
      n.title.toLowerCase().includes(search.toLowerCase()) ||
      n.content.toLowerCase().includes(search.toLowerCase())
  )

  return (
    <div className="space-y-6">
      <h2 className="text-2xl font-bold">🗒️ 筆記管理工具</h2>

      {/* 新增筆記區 */}
      <div className="bg-white p-4 rounded shadow space-y-3">
        <input
          value={title}
          onChange={(e) => setTitle(e.target.value)}
          placeholder="筆記標題"
          className="w-full border px-3 py-2 rounded"
        />
        <textarea
          value={content}
          onChange={(e) => setContent(e.target.value)}
          placeholder="筆記內容..."
          rows="4"
          className="w-full border px-3 py-2 rounded"
        />
        <button
          onClick={addNote}
          className="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
        >
          新增筆記
        </button>
      </div>

      {/* 搜尋欄 */}
      <div>
        <input
          value={search}
          onChange={(e) => setSearch(e.target.value)}
          placeholder="搜尋筆記..."
          className="w-full border px-3 py-2 rounded"
        />
      </div>

      {/* 筆記列表 */}
      <div className="space-y-3">
        {filteredNotes.length === 0 ? (
          <p className="text-gray-500">目前沒有筆記。</p>
        ) : (
          filteredNotes.map((n) => (
            <div
              key={n.id}
              className="bg-white p-4 rounded shadow flex justify-between items-start"
            >
              <div>
                <h3 className="text-lg font-semibold">{n.title}</h3>
                <p className="text-gray-700 whitespace-pre-wrap">
                  {n.content}
                </p>
                <p className="text-xs text-gray-400 mt-1">{n.date}</p>
              </div>
              <button
                onClick={() => deleteNote(n.id)}
                className="text-red-600 hover:text-red-800 text-sm"
              >
                刪除
              </button>
            </div>
          ))
        )}
      </div>
    </div>
  )
}

然後接著在layout中加入筆記工具這個功能

import { useState } from "react"
import TodoApp from "./TodoApp"
import ChatBox from "./ChatBox"
import TranslationTool from "./TranslationTool"
import NoteManager from "./NoteManager" // ← 新增

export default function Layout() {
  const [active, setActive] = useState("todo")

  return (
    <div className="min-h-screen flex">
      <aside className="w-64 bg-gray-800 text-white p-6 space-y-4">
        <h2 className="text-xl font-bold mb-6">AI工具箱</h2>
        <nav className="space-y-2">
          {[
            ["todo", "待辦清單"],
            ["chat", "Chat工具"],
            ["translate", "翻譯工具"],
            ["notes", "筆記工具"], // ← 新增
          ].map(([key, label]) => (
            <button
              key={key}
              className={`block w-full text-left px-3 py-2 rounded ${
                active === key ? "bg-blue-600" : "hover:bg-gray-700"
              }`}
              onClick={() => setActive(key)}
            >
              {label}
            </button>
          ))}
        </nav>
      </aside>

      <main className="flex-1 bg-gray-50 p-6">
        {active === "todo" && <TodoApp />}
        {active === "chat" && <ChatBox />}
        {active === "translate" && <TranslationTool />}
        {active === "notes" && <NoteManager />} {/* ← 新增 */}
      </main>
    </div>
  )
}

上一篇
30天用React打造AI工具箱 Day22
系列文
30天用React打造AI工具箱23
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言