From c16b9c1a5130469a76ec7fd33b7ec362319aab96 Mon Sep 17 00:00:00 2001 From: koreacomp5 Date: Thu, 9 Oct 2025 16:35:19 +0900 Subject: [PATCH] =?UTF-8?q?6.4=20=EA=B2=80=EC=83=89=20=EB=B0=94=20?= =?UTF-8?q?=EB=B0=8F=20=EA=B2=B0=EA=B3=BC=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EB=9D=BC=EC=9A=B0=ED=8C=85=20o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/components/AppHeader.tsx | 4 +++- src/app/components/PostList.tsx | 17 ++++++++++++++--- src/app/components/SearchBar.tsx | 28 ++++++++++++++++++++++++++++ src/app/search/page.tsx | 14 ++++++++++++++ todolist.txt | 2 +- 5 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 src/app/components/SearchBar.tsx create mode 100644 src/app/search/page.tsx diff --git a/src/app/components/AppHeader.tsx b/src/app/components/AppHeader.tsx index e81e371..d2686ee 100644 --- a/src/app/components/AppHeader.tsx +++ b/src/app/components/AppHeader.tsx @@ -1,12 +1,14 @@ import { ThemeToggle } from "@/app/components/ThemeToggle"; +import { SearchBar } from "@/app/components/SearchBar"; export function AppHeader() { return (
msg App
-
diff --git a/src/app/components/PostList.tsx b/src/app/components/PostList.tsx index 673d022..9367f0f 100644 --- a/src/app/components/PostList.tsx +++ b/src/app/components/PostList.tsx @@ -20,13 +20,14 @@ type Resp = { const fetcher = (url: string) => fetch(url).then((r) => r.json()); -export function PostList({ boardId, sort = "recent" }: { boardId?: string; sort?: "recent" | "popular" }) { +export function PostList({ boardId, sort = "recent", q }: { boardId?: string; sort?: "recent" | "popular"; q?: string }) { const pageSize = 10; const getKey = (index: number, prev: Resp | null) => { if (prev && prev.items.length === 0) return null; const page = index + 1; const sp = new URLSearchParams({ page: String(page), pageSize: String(pageSize), sort }); if (boardId) sp.set("boardId", boardId); + if (q) sp.set("q", q); return `/api/posts?${sp.toString()}`; }; const { data, size, setSize, isLoading } = useSWRInfinite(getKey, fetcher); @@ -37,8 +38,18 @@ export function PostList({ boardId, sort = "recent" }: { boardId?: string; sort?
정렬: - 최신 - 인기 + { const p = new URLSearchParams(); if (q) p.set("q", q); if (boardId) p.set("boardId", boardId); p.set("sort", "recent"); return p.toString(); })()}`} + style={{ textDecoration: sort === "recent" ? "underline" : "none" }} + > + 최신 + + { const p = new URLSearchParams(); if (q) p.set("q", q); if (boardId) p.set("boardId", boardId); p.set("sort", "popular"); return p.toString(); })()}`} + style={{ textDecoration: sort === "popular" ? "underline" : "none" }} + > + 인기 +
    {items.map((p) => ( diff --git a/src/app/components/SearchBar.tsx b/src/app/components/SearchBar.tsx new file mode 100644 index 0000000..ce4ce39 --- /dev/null +++ b/src/app/components/SearchBar.tsx @@ -0,0 +1,28 @@ +"use client"; +import { useRouter } from "next/navigation"; +import { useState } from "react"; + +export function SearchBar() { + const router = useRouter(); + const [term, setTerm] = useState(""); + return ( +
    { + e.preventDefault(); + const q = term.trim(); + router.push(q ? `/search?q=${encodeURIComponent(q)}` : "/search"); + }} + style={{ display: "flex", gap: 8, alignItems: "center" }} + > + setTerm(e.target.value)} + placeholder="검색어 입력" + style={{ padding: "6px 8px", border: "1px solid #ddd", borderRadius: 6 }} + /> + +
    + ); +} + + diff --git a/src/app/search/page.tsx b/src/app/search/page.tsx new file mode 100644 index 0000000..b373d6e --- /dev/null +++ b/src/app/search/page.tsx @@ -0,0 +1,14 @@ +import { PostList } from "@/app/components/PostList"; + +export default function SearchPage({ searchParams }: { searchParams?: { q?: string; sort?: "recent" | "popular" } }) { + const q = searchParams?.q ?? ""; + const sort = searchParams?.sort ?? "recent"; + return ( +
    +

    검색: {q || "전체"}

    + +
    + ); +} + + diff --git a/todolist.txt b/todolist.txt index 7298f26..8390d82 100644 --- a/todolist.txt +++ b/todolist.txt @@ -36,7 +36,7 @@ 6.1 Hero/공지 배너 컴포넌트(자동/수동 슬라이드) o 6.2 최근/인기 글 리스트 및 무한스크롤 연동 o 6.3 권한 기반 빠른 액션 노출 제어 o -6.4 검색 바 및 결과 페이지 라우팅 +6.4 검색 바 및 결과 페이지 라우팅 o 6.5 개인화 위젯(최근 본 글/알림 요약) [게시판/컨텐츠]