From cec16dbbca99f529835989f318fb7c7f2d8396a7 Mon Sep 17 00:00:00 2001 From: "JaeHyeon, Woo" Date: Fri, 29 Nov 2024 20:04:55 +0900 Subject: [PATCH 01/45] =?UTF-8?q?chore:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/ImageSafe.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/components/ImageSafe.tsx b/components/ImageSafe.tsx index dd2926ea7..58b6ff51b 100644 --- a/components/ImageSafe.tsx +++ b/components/ImageSafe.tsx @@ -13,16 +13,12 @@ export default function ImageSafe({ src, alt }: { src: string; alt: string }) { const res = await fetch( "/api/check-image?url=" + encodeURIComponent(src) ); - console.log(res); if (res.ok) { setImageSrc(src); } else { - console.error("Image source not configured in next.config.js"); - console.log(res); setImageSrc(IMAGE_PLACEHOLDER); } } catch (error) { - console.error("Error checking image configuration:", error); setImageSrc(IMAGE_PLACEHOLDER); } }; From 6db26166f88bfbae01a4d22c7bf9042ec2453d02 Mon Sep 17 00:00:00 2001 From: "JaeHyeon, Woo" Date: Fri, 29 Nov 2024 20:11:57 +0900 Subject: [PATCH 02/45] =?UTF-8?q?feat:=20=EB=B2=A0=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EA=B8=80=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/BestPostBoard.tsx | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/components/BestPostBoard.tsx b/components/BestPostBoard.tsx index 5d9b89989..1c7de9435 100644 --- a/components/BestPostBoard.tsx +++ b/components/BestPostBoard.tsx @@ -3,7 +3,7 @@ import styles from "./BestPostBoard.module.css"; import Image from "next/image"; import formatDate from "../lib/formatDate"; import { useDeviceType } from "@/contexts/DeviceTypeContext"; -import { useState } from "react"; +import ImageSafe from "./ImageSafe"; const PAGE_SIZE = { desktop: 3, @@ -11,8 +11,6 @@ const PAGE_SIZE = { mobile: 1, }; -const IMAGE_PLACEHOLDER = "/images/landscape-placeholder.svg"; - export default function BestPostBoard({ articles }: { articles: ArticleList }) { const deviceType = useDeviceType(); @@ -33,8 +31,6 @@ export default function BestPostBoard({ articles }: { articles: ArticleList }) { } function PostItem({ article }: { article: Article }) { - const [imgSrc, setImgSrc] = useState(article.image || IMAGE_PLACEHOLDER); - const createdAt = formatDate(article.createdAt); return ( @@ -48,15 +44,7 @@ function PostItem({ article }: { article: Article }) {

{article.title}

- {article.title} setImgSrc(IMAGE_PLACEHOLDER)} - /> +
From d689db9b257937c9c0e71997319ae1212ada6788 Mon Sep 17 00:00:00 2001 From: "JaeHyeon, Woo" Date: Fri, 29 Nov 2024 20:17:30 +0900 Subject: [PATCH 03/45] =?UTF-8?q?refactor:=20import=20=EA=B2=BD=EB=A1=9C?= =?UTF-8?q?=EB=A5=BC=20=EB=AA=A8=EB=91=90=20=EC=A0=88=EB=8C=80=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20impot=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/BestPostBoard.tsx | 2 +- components/ImageSafe.tsx | 1 - components/PostBoard.tsx | 4 ++-- contexts/DeviceTypeContext.tsx | 2 +- pages/_app.tsx | 2 +- pages/board.tsx | 2 +- 6 files changed, 6 insertions(+), 7 deletions(-) diff --git a/components/BestPostBoard.tsx b/components/BestPostBoard.tsx index 1c7de9435..ddf1ab628 100644 --- a/components/BestPostBoard.tsx +++ b/components/BestPostBoard.tsx @@ -1,7 +1,7 @@ import { Article, ArticleList } from "@/types/Article.type"; import styles from "./BestPostBoard.module.css"; import Image from "next/image"; -import formatDate from "../lib/formatDate"; +import formatDate from "@/lib/formatDate"; import { useDeviceType } from "@/contexts/DeviceTypeContext"; import ImageSafe from "./ImageSafe"; diff --git a/components/ImageSafe.tsx b/components/ImageSafe.tsx index 58b6ff51b..ca7f39aa3 100644 --- a/components/ImageSafe.tsx +++ b/components/ImageSafe.tsx @@ -1,4 +1,3 @@ -import getConfig from "next/config"; import Image from "next/image"; import { useState, useEffect } from "react"; diff --git a/components/PostBoard.tsx b/components/PostBoard.tsx index 15ae89ca8..4f383876f 100644 --- a/components/PostBoard.tsx +++ b/components/PostBoard.tsx @@ -1,13 +1,13 @@ import { Article, ArticleList } from "@/types/Article.type"; import Image from "next/image"; import styles from "./PostBoard.module.css"; -import { Suspense, useEffect, useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { getArticleList, GetArticleListParams, OrderBy, } from "@/api/article.api"; -import formatDate from "../lib/formatDate"; +import formatDate from "@/lib/formatDate"; import { useDeviceType } from "@/contexts/DeviceTypeContext"; import ImageSafe from "./ImageSafe"; diff --git a/contexts/DeviceTypeContext.tsx b/contexts/DeviceTypeContext.tsx index 902b123b1..57c417fc5 100644 --- a/contexts/DeviceTypeContext.tsx +++ b/contexts/DeviceTypeContext.tsx @@ -1,5 +1,5 @@ import { createContext, useContext, useEffect, useState } from "react"; -import useDebounce from "../hooks/useDebounce"; +import useDebounce from "@/hooks/useDebounce"; export type DeviceType = "desktop" | "tablet" | "mobile"; diff --git a/pages/_app.tsx b/pages/_app.tsx index b9f7a0dcc..a52da39cc 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,6 +1,6 @@ import type { AppProps } from "next/app"; import Head from "next/head"; -import "../styles/global.css"; +import "@/styles/global.css"; import { DeviceTypeProvider } from "@/contexts/DeviceTypeContext"; import Navigation from "@/components/Navigation"; diff --git a/pages/board.tsx b/pages/board.tsx index 921d3add6..3d507d496 100644 --- a/pages/board.tsx +++ b/pages/board.tsx @@ -2,7 +2,7 @@ import BestPostBoard from "@/components/BestPostBoard"; import PostBoard from "@/components/PostBoard"; import { getArticleList } from "@/api/article.api"; import { ArticleList } from "@/types/Article.type"; -import styles from "../styles/borad.module.css"; +import styles from "@/styles/borad.module.css"; export async function getServerSideProps() { const allArticles = await getArticleList({ From 1b4525c537aec490efb912e74b5f5062ad9e288e Mon Sep 17 00:00:00 2001 From: "JaeHyeon, Woo" Date: Fri, 29 Nov 2024 20:19:47 +0900 Subject: [PATCH 04/45] =?UTF-8?q?style:=20i=20=EB=AA=85=EC=B9=AD=20postInd?= =?UTF-8?q?ex=EB=A1=9C=20=EB=AA=85=ED=99=95=ED=95=98=EA=B2=8C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/BestPostBoard.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/BestPostBoard.tsx b/components/BestPostBoard.tsx index ddf1ab628..35d02352b 100644 --- a/components/BestPostBoard.tsx +++ b/components/BestPostBoard.tsx @@ -20,8 +20,8 @@ export default function BestPostBoard({ articles }: { articles: ArticleList }) {

베스트 게시글

- {articles.list.map((article, i) => { - if (i < PAGE_SIZE[deviceType]) { + {articles.list.map((article, postIndex) => { + if (postIndex < PAGE_SIZE[deviceType]) { return ; } })} From e5dc536631b48e61df58969e781d516830962adf Mon Sep 17 00:00:00 2001 From: "JaeHyeon, Woo" Date: Sat, 30 Nov 2024 00:58:09 +0900 Subject: [PATCH 05/45] =?UTF-8?q?feat:=20useAsync=20=EC=BB=A4=EC=8A=A4?= =?UTF-8?q?=ED=85=80=20=ED=9B=85=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/PostBoard.tsx | 2 -- hooks/useAsync.tsx | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 hooks/useAsync.tsx diff --git a/components/PostBoard.tsx b/components/PostBoard.tsx index 4f383876f..1ac950d78 100644 --- a/components/PostBoard.tsx +++ b/components/PostBoard.tsx @@ -17,8 +17,6 @@ const DEFAULT_PARAMS: GetArticleListParams = { orderBy: "recent", }; -const IMAGE_PLACEHOLDER = "/images/landscape-placeholder.svg"; - export default function PostBoard({ articles: initArticles, }: { diff --git a/hooks/useAsync.tsx b/hooks/useAsync.tsx new file mode 100644 index 000000000..355af4225 --- /dev/null +++ b/hooks/useAsync.tsx @@ -0,0 +1,22 @@ +import { useCallback, useState } from "react"; + +export default function useAsync( + asyncFunction: (parmas: T) => Promise +) { + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const excute = useCallback(async (params: T) => { + try { + setLoading(true); + setError(null); + return await asyncFunction(params); + } catch (err) { + setError(err as Error); + } finally { + setLoading(false); + } + }, []); + + return { excute, loading, error }; +} From cb60cfc04751b49daeee44c07b838d6fc5c033f8 Mon Sep 17 00:00:00 2001 From: WooLegend Date: Sat, 30 Nov 2024 03:43:01 +0900 Subject: [PATCH 06/45] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20useAsync=20=EC=BB=A4=EC=8A=A4?= =?UTF-8?q?=ED=85=80=20=ED=9B=85=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/PostBoard.tsx | 12 +++++++++--- hooks/useAsync.tsx | 25 ++++++++++++++----------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/components/PostBoard.tsx b/components/PostBoard.tsx index 1ac950d78..b4fd3ccd4 100644 --- a/components/PostBoard.tsx +++ b/components/PostBoard.tsx @@ -10,6 +10,7 @@ import { import formatDate from "@/lib/formatDate"; import { useDeviceType } from "@/contexts/DeviceTypeContext"; import ImageSafe from "./ImageSafe"; +import useAsync from "@/hooks/useAsync"; const DEFAULT_PARAMS: GetArticleListParams = { page: 1, @@ -28,6 +29,11 @@ export default function PostBoard({ const [selectedDropdown, setSelecedDropdown] = useState(false); const dropdownRef = useRef(null); const deviceType = useDeviceType(); + const { + excute: getArticleListAsync, + loading, + error, + } = useAsync(getArticleList); const handleClickDropdown = () => setSelecedDropdown((prev) => !prev); @@ -67,8 +73,8 @@ export default function PostBoard({ useEffect(() => { const fetchArticles = async () => { - const data = await getArticleList(params); - setArticles(data); + const data = await getArticleListAsync(params); + if (data) setArticles(data); }; fetchArticles(); @@ -76,7 +82,7 @@ export default function PostBoard({ return () => document.removeEventListener("click", handleClickDropdownOutside); - }, [params]); + }, [params, getArticleListAsync]); return (
diff --git a/hooks/useAsync.tsx b/hooks/useAsync.tsx index 355af4225..911c0bec0 100644 --- a/hooks/useAsync.tsx +++ b/hooks/useAsync.tsx @@ -6,17 +6,20 @@ export default function useAsync( const [loading, setLoading] = useState(false); const [error, setError] = useState(null); - const excute = useCallback(async (params: T) => { - try { - setLoading(true); - setError(null); - return await asyncFunction(params); - } catch (err) { - setError(err as Error); - } finally { - setLoading(false); - } - }, []); + const excute = useCallback( + async (params: T) => { + try { + setLoading(true); + setError(null); + return await asyncFunction(params); + } catch (err) { + setError(err as Error); + } finally { + setLoading(false); + } + }, + [asyncFunction] + ); return { excute, loading, error }; } From 73fcca3f37080da11e6750c620db6a270a1e65ac Mon Sep 17 00:00:00 2001 From: WooLegend Date: Sat, 30 Nov 2024 04:08:55 +0900 Subject: [PATCH 07/45] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A0=95=EB=A0=AC=20=EB=93=9C=EB=A1=AD=EB=8B=A4=EC=9A=B4=20?= =?UTF-8?q?=EC=99=B8=EB=B6=80=20=ED=81=B4=EB=A6=AD=20=EC=97=AC=EB=B6=80=20?= =?UTF-8?q?=ED=8C=90=EB=8B=A8=EC=9D=84=20=EC=9C=84=ED=95=9C=20=EC=BB=A4?= =?UTF-8?q?=EC=8A=A4=ED=85=80=20=ED=9B=85=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/PostBoard.tsx | 131 +++++++++++++++++++++----------------- hooks/useOutsideClick.tsx | 28 ++++++++ 2 files changed, 101 insertions(+), 58 deletions(-) create mode 100644 hooks/useOutsideClick.tsx diff --git a/components/PostBoard.tsx b/components/PostBoard.tsx index b4fd3ccd4..2f1794b3a 100644 --- a/components/PostBoard.tsx +++ b/components/PostBoard.tsx @@ -11,6 +11,7 @@ import formatDate from "@/lib/formatDate"; import { useDeviceType } from "@/contexts/DeviceTypeContext"; import ImageSafe from "./ImageSafe"; import useAsync from "@/hooks/useAsync"; +import useOutsideClick from "@/hooks/useOutsideClick"; const DEFAULT_PARAMS: GetArticleListParams = { page: 1, @@ -26,39 +27,24 @@ export default function PostBoard({ const [articles, setArticles] = useState(initArticles); const [params, setParams] = useState(DEFAULT_PARAMS); const [keyword, setKeyword] = useState(""); - const [selectedDropdown, setSelecedDropdown] = useState(false); - const dropdownRef = useRef(null); - const deviceType = useDeviceType(); const { excute: getArticleListAsync, loading, error, } = useAsync(getArticleList); - const handleClickDropdown = () => setSelecedDropdown((prev) => !prev); + const handleChangeKeyword = (event: React.ChangeEvent) => { + if (!(event.target instanceof HTMLElement)) return; + setKeyword(event.target.value.trim()); + }; - const handleClickOption = (event: React.MouseEvent) => { - const target = event.target; - if (!(target instanceof HTMLElement)) return; - if (!target.dataset.option) return; + const handleChangeOrderBy = (option: OrderBy) => setParams((prev) => { return { ...prev, - orderBy: target.dataset.option as OrderBy, + orderBy: option, }; }); - }; - - const handleClickDropdownOutside = (event: MouseEvent) => { - if (!dropdownRef.current) return; - if (dropdownRef.current.contains(event.target as Node)) return; - setSelecedDropdown(false); - }; - - const handleChangeKeyword = (event: React.ChangeEvent) => { - if (!(event.target instanceof HTMLElement)) return; - setKeyword(event.target.value.trim()); - }; const handleSubmitSearch = (event: React.FormEvent) => { event.preventDefault(); @@ -77,11 +63,6 @@ export default function PostBoard({ if (data) setArticles(data); }; fetchArticles(); - - document.addEventListener("click", handleClickDropdownOutside); - - return () => - document.removeEventListener("click", handleClickDropdownOutside); }, [params, getArticleListAsync]); return ( @@ -104,38 +85,10 @@ export default function PostBoard({ /> -
-
- {deviceType !== "mobile" && ( - {params.orderBy === "recent" ? "최신순" : "인기순"} - )} -
- 정렬 -
-
- {selectedDropdown && ( -
-
- 최신순 -
-
- 인기순 -
-
- )} -
+
{articles?.list.map((article) => ( @@ -185,3 +138,65 @@ function PostItem({ article }: { article: Article }) {
); } + +function Dropdown({ + orderBy, + onChange, +}: { + orderBy: OrderBy; + onChange: (option: OrderBy) => void; +}) { + const [selectedDropdown, setSelecedDropdown] = useState(false); + const dropdownRef = useRef(null); + const { flag } = useOutsideClick(dropdownRef); + const deviceType = useDeviceType(); + + const handleClickDropdown = () => setSelecedDropdown((prev) => !prev); + + const handleClickOption = (event: React.MouseEvent) => { + const target = event.target; + if (!(target instanceof HTMLElement)) return; + if (!target.dataset.option) return; + onChange(target.dataset.option as OrderBy); + }; + + useEffect(() => { + console.log(flag); + setSelecedDropdown(!flag); + }, [flag]); + + return ( +
+
+ {deviceType !== "mobile" && ( + {orderBy === "recent" ? "최신순" : "인기순"} + )} +
+ 정렬 +
+
+ {selectedDropdown && ( +
+
+ 최신순 +
+
+ 인기순 +
+
+ )} +
+ ); +} diff --git a/hooks/useOutsideClick.tsx b/hooks/useOutsideClick.tsx new file mode 100644 index 000000000..6e2c90734 --- /dev/null +++ b/hooks/useOutsideClick.tsx @@ -0,0 +1,28 @@ +import { RefObject, useCallback, useEffect, useState } from "react"; + +const useOutsideClick = (ref: RefObject) => { + const [flag, setFlag] = useState(false); + + const handler = useCallback( + (event: MouseEvent) => { + if (ref?.current && ref.current.contains(event.target as Node)) { + setFlag(false); + return; + } + setFlag(true); + }, + [ref] + ); + + useEffect(() => { + document.addEventListener("click", handler); + + return () => { + document.removeEventListener("click", handler); + }; + }, [handler]); + + return { flag }; +}; + +export default useOutsideClick; From 204ee6836bf0c5e20b6358540d3cdd839f1196c9 Mon Sep 17 00:00:00 2001 From: WooLegend Date: Sat, 30 Nov 2024 04:48:16 +0900 Subject: [PATCH 08/45] =?UTF-8?q?feat:=20container=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/Container.tsx | 5 +++++ pages/_app.tsx | 5 ++++- pages/board.tsx | 5 ++--- styles/borad.module.css | 19 ------------------- styles/global.css | 21 +++++++++++++++++++++ 5 files changed, 32 insertions(+), 23 deletions(-) create mode 100644 components/Container.tsx delete mode 100644 styles/borad.module.css diff --git a/components/Container.tsx b/components/Container.tsx new file mode 100644 index 000000000..f4eb3c591 --- /dev/null +++ b/components/Container.tsx @@ -0,0 +1,5 @@ +import { ReactNode } from "react"; + +export default function Container({ children }: { children: ReactNode }) { + return
{children}
; +} diff --git a/pages/_app.tsx b/pages/_app.tsx index a52da39cc..369d39dd6 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -3,6 +3,7 @@ import Head from "next/head"; import "@/styles/global.css"; import { DeviceTypeProvider } from "@/contexts/DeviceTypeContext"; import Navigation from "@/components/Navigation"; +import Container from "@/components/Container"; export default function App({ Component, pageProps }: AppProps) { return ( @@ -15,7 +16,9 @@ export default function App({ Component, pageProps }: AppProps) { - + + + ); diff --git a/pages/board.tsx b/pages/board.tsx index 3d507d496..d284141e4 100644 --- a/pages/board.tsx +++ b/pages/board.tsx @@ -2,7 +2,6 @@ import BestPostBoard from "@/components/BestPostBoard"; import PostBoard from "@/components/PostBoard"; import { getArticleList } from "@/api/article.api"; import { ArticleList } from "@/types/Article.type"; -import styles from "@/styles/borad.module.css"; export async function getServerSideProps() { const allArticles = await getArticleList({ @@ -32,9 +31,9 @@ export default function Board({ bestArticles: ArticleList; }) { return ( -
+ <> -
+ ); } diff --git a/styles/borad.module.css b/styles/borad.module.css deleted file mode 100644 index 6810244ee..000000000 --- a/styles/borad.module.css +++ /dev/null @@ -1,19 +0,0 @@ -.container { - display: flex; - flex-direction: column; - gap: 40px; - max-width: 1200px; - margin: 0 auto; -} - -@media screen and (max-width: 1199px) { - .container { - max-width: 696px; - } -} - -@media screen and (max-width: 767px) { - .container { - max-width: 343px; - } -} diff --git a/styles/global.css b/styles/global.css index 2e32cbe13..c39c7885a 100644 --- a/styles/global.css +++ b/styles/global.css @@ -36,6 +36,10 @@ --blue-active: #1251aa; --error: #f74747; --inactive: #9ca3af; + + --width-desktop: 1200px; + --width-tablet: 696px; + --width-mobile: 343px; } * { @@ -62,3 +66,20 @@ a { ul { list-style: none; } + +.container { + margin: 0 auto; + max-width: var(--width-desktop); +} + +@media screen and (max-width: 1199px) { + .container { + max-width: var(--width-tablet); + } +} + +@media screen and (max-width: 767px) { + .container { + max-width: var(--width-mobile); + } +} From a644810393dc9ea347225035928558070d7ed827 Mon Sep 17 00:00:00 2001 From: WooLegend Date: Sat, 30 Nov 2024 22:39:26 +0900 Subject: [PATCH 09/45] =?UTF-8?q?feat:=20=EA=B8=80=EC=93=B0=EA=B8=B0=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B5=AC=EC=A1=B0=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/PostBoard.tsx | 6 ++-- hooks/useOutsideClick.tsx | 2 +- pages/addboard.tsx | 70 ++++++++++++++++++++++++++++++++++++++ styles/addboard.module.css | 36 ++++++++++++++++++++ 4 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 pages/addboard.tsx create mode 100644 styles/addboard.module.css diff --git a/components/PostBoard.tsx b/components/PostBoard.tsx index 2f1794b3a..503908e4b 100644 --- a/components/PostBoard.tsx +++ b/components/PostBoard.tsx @@ -12,6 +12,7 @@ import { useDeviceType } from "@/contexts/DeviceTypeContext"; import ImageSafe from "./ImageSafe"; import useAsync from "@/hooks/useAsync"; import useOutsideClick from "@/hooks/useOutsideClick"; +import Link from "next/link"; const DEFAULT_PARAMS: GetArticleListParams = { page: 1, @@ -69,7 +70,9 @@ export default function PostBoard({

게시글

- + + 글쓰기 +
@@ -161,7 +164,6 @@ function Dropdown({ }; useEffect(() => { - console.log(flag); setSelecedDropdown(!flag); }, [flag]); diff --git a/hooks/useOutsideClick.tsx b/hooks/useOutsideClick.tsx index 6e2c90734..7f342b2fe 100644 --- a/hooks/useOutsideClick.tsx +++ b/hooks/useOutsideClick.tsx @@ -1,7 +1,7 @@ import { RefObject, useCallback, useEffect, useState } from "react"; const useOutsideClick = (ref: RefObject) => { - const [flag, setFlag] = useState(false); + const [flag, setFlag] = useState(true); const handler = useCallback( (event: MouseEvent) => { diff --git a/pages/addboard.tsx b/pages/addboard.tsx new file mode 100644 index 000000000..f263f2ca6 --- /dev/null +++ b/pages/addboard.tsx @@ -0,0 +1,70 @@ +import styles from "@/styles/addboard.module.css"; +import { ChangeEvent, useState } from "react"; + +const DEFAULT_VALUES: { + title: string; + content: string; + image: any; +} = { + title: "", + content: "", + image: undefined, +}; + +export default function AddBoard() { + const [values, setValues] = useState(DEFAULT_VALUES); + const [valid, setValid] = useState(false); + + const handleChangeValue = (name: string, value: any) => { + setValues((prev) => ({ + ...prev, + [name]: value, + })); + }; + + const handleChangeInput = ( + event: ChangeEvent + ) => { + if (!(event.target instanceof HTMLElement)) return; + const { name, value } = event.target; + handleChangeValue(name, value); + }; + + return ( + +
+

게시글 쓰기

+ +
+
+ + +
+
+ +