diff --git a/components/Header.tsx b/components/Header.tsx index 7366116..fb342bf 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -1,27 +1,55 @@ import Image from "next/image"; -import { SingleMenu } from "./HeaderItem"; +import { WebMenuBar, MobileHeaderDropdown } from "./HeaderItem"; +import Link from "next/link"; +import { useState } from "react"; +import Hamburger from "hamburger-react"; const Header = () => { - return ( -
-
-
- devkor -
-
- - - - - - -
-
-
- profile -
-
- ); + const [isOpen, setOpen] = useState(false); + return ( +
+
+ {/* 헤더 로고 */} +
+ + devkor + +
+ {/* 메뉴 리스트 */} + +
+ {/* 마이페이지 아이콘 or 햄버거(모바일)*/} +
+
+ profile +
+
+ +
+
+ +
+ ); }; export default Header; diff --git a/components/HeaderItem.tsx b/components/HeaderItem.tsx index 4c1f728..fa6fc4a 100644 --- a/components/HeaderItem.tsx +++ b/components/HeaderItem.tsx @@ -2,18 +2,55 @@ import React from "react"; import { useRouter } from "next/router"; interface MenuProps { - title: string; + title: string; } +export const MenuList = [ + "Tech", + "Project", + "Study", + "Question", + "Members", + "Apply", +]; + export const SingleMenu = ({ title }: MenuProps) => { - const router = useRouter(); - const routerPath = title.toLowerCase(); - const handleClick = () => { - router.push(`/${routerPath}`); - }; - return ( -
- {title} -
- ); + const router = useRouter(); + const routerPath = title.toLowerCase(); + const handleClick = () => { + router.push(`/${routerPath}`); + }; + return ( +
+ {title} +
+ ); +}; + +export const WebMenuBar = () => { + return ( + <> + {MenuList.map((menu) => ( + + ))} + + ); +}; + +export const MobileHeaderDropdown = ({ isOpen }: { isOpen: boolean }) => { + return ( + + ); }; diff --git a/components/Icons.tsx b/components/Icons.tsx new file mode 100644 index 0000000..9a80ec8 --- /dev/null +++ b/components/Icons.tsx @@ -0,0 +1,30 @@ +import { FiHeart, FiDownload } from "react-icons/fi"; +import { FaHeart } from "react-icons/fa"; //꽉 찬 하트 +import { IoChatbox } from "react-icons/io5"; + +export const EmptyHeartIcon = () => { + return ( + + ); +}; + +export const DownloadIcon = () => { + return ( + + ); +}; + +export const ChatboxIcon = () => { + return ( + + ); +}; diff --git a/components/Layout.tsx b/components/Layout.tsx index 2e0e346..ea36ad0 100644 --- a/components/Layout.tsx +++ b/components/Layout.tsx @@ -2,10 +2,10 @@ import React from "react"; import Header from "./Header"; export const Layout = ({ children }: { children: React.ReactNode }) => { - return ( -
-
-
{children}
-
- ); + return ( +
+
+
{children}
+
+ ); }; diff --git a/components/PostCard.tsx b/components/PostCard.tsx index 5d2b628..768fbdf 100644 --- a/components/PostCard.tsx +++ b/components/PostCard.tsx @@ -5,18 +5,18 @@ import { FaComment, FaHeart } from "react-icons/fa"; const PostCard = () => { return ( -
+
BlogPost
-
+
Next.js의 Hydration 파헤치기

2022년 10월 7일

-
+
{ + return ( +
+
+
+ +
+
+ +
+
+ 안수진(OB) + + 2022년 12월 3일 + +
+
+
+ {children} +
+
+ ); +}; diff --git a/components/Tags.tsx b/components/Tags.tsx index 987c247..7e85fad 100644 --- a/components/Tags.tsx +++ b/components/Tags.tsx @@ -1,30 +1,39 @@ import React, { useState, SetStateAction } from "react"; // Tag Button Type Interface export interface TagButtonType { - name: string; - mapIdx: number; - sectionIdx: number; - setSectionIdx: React.Dispatch>; - } - - // Menu Button Component - export const TagButton = ({ - name, - mapIdx, - sectionIdx, - setSectionIdx, - }: TagButtonType) => { - return ( - - ); - }; - - // MenuList - export const TagList = ["전체", "Frontend", "Backend", "ML", "DevOps", "기타"]; + name: string; + mapIdx: number; + sectionIdx: number; + setSectionIdx: React.Dispatch>; +} + +// Tag Button Component +export const TagButton = ({ + name, + mapIdx, + sectionIdx, + setSectionIdx, +}: TagButtonType) => { + return ( + + ); +}; + +// PostView Tag +export const PostTag = ({ category }: { category: string }) => { + return ( + + {category} + + ); +}; + +// TagList +export const TagList = ["전체", "Frontend", "Backend", "ML", "DevOps", "기타"]; diff --git a/package-lock.json b/package-lock.json index 1a376d3..9cb9fd8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,15 +9,20 @@ "version": "0.1.0", "dependencies": { "@uiw/react-md-editor": "^3.19.8", + "hamburger-react": "^2.5.0", "next": "12.3.0", "next-remove-imports": "^1.0.8", "react": "18.2.0", "react-dom": "18.2.0", "react-icons": "^4.6.0", - "react-player": "^2.11.0" + "react-player": "^2.11.0", + "remark": "^14.0.2", + "remark-gfm": "^3.0.1", + "remark-html": "^15.0.1" }, "devDependencies": { "@svgr/webpack": "^6.5.0", + "@tailwindcss/typography": "^0.5.8", "@types/node": "18.7.17", "@types/react": "18.0.19", "@types/react-dom": "18.0.6", @@ -2553,6 +2558,21 @@ "tslib": "^2.4.0" } }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.8.tgz", + "integrity": "sha512-xGQEp8KXN8Sd8m6R4xYmwxghmswrd0cPnNI2Lc6fmrC3OojysTBJJGSIVwPV56q4t6THFUK3HJ0EaWwpglSxWw==", + "dev": true, + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -4970,6 +4990,14 @@ "dev": true, "license": "MIT" }, + "node_modules/hamburger-react": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/hamburger-react/-/hamburger-react-2.5.0.tgz", + "integrity": "sha512-5GSXe+ucxTPJ0SkhIsPQ/PRDweZPIKya1lfahAuExx31SdheeUA4uOPfQIAirbKona8hvo79VDr5LJQzPXsdpw==", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18" + } + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -5149,6 +5177,18 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-sanitize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-sanitize/-/hast-util-sanitize-4.0.0.tgz", + "integrity": "sha512-pw56+69jq+QSr/coADNvWTmBPDy+XsmwaF5KnUys4/wM1jt/fZdl7GPxhXXXYdXnz3Gj3qMkbUCH2uKjvX0MgQ==", + "dependencies": { + "@types/hast": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-select": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-5.0.2.tgz", @@ -5861,12 +5901,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "dev": true + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -7885,6 +7937,21 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/remark/-/remark-14.0.2.tgz", + "integrity": "sha512-A3ARm2V4BgiRXaUo5K0dRvJ1lbogrbXnhkJRmD0yw092/Yl0kOCZt1k9ZeElEwkZsWGsMumz6qL5MfNJH9nOBA==", + "dependencies": { + "@types/mdast": "^3.0.0", + "remark-parse": "^10.0.0", + "remark-stringify": "^10.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/remark-gfm": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz", @@ -7900,6 +7967,22 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark-html": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/remark-html/-/remark-html-15.0.1.tgz", + "integrity": "sha512-7ta5UPRqj8nP0GhGMYUAghZ/DRno7dgq7alcW90A7+9pgJsXzGJlFgwF8HOP1b1tMgT3WwbeANN+CaTimMfyNQ==", + "dependencies": { + "@types/mdast": "^3.0.0", + "hast-util-sanitize": "^4.0.0", + "hast-util-to-html": "^8.0.0", + "mdast-util-to-hast": "^12.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/remark-parse": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", @@ -7929,6 +8012,20 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark-stringify": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-10.0.2.tgz", + "integrity": "sha512-6wV3pvbPvHkbNnWB0wdDvVFHOe1hBRAx1Q/5g/EpH4RppAII6J8Gnwe7VbHuXaoKIF6LAg6ExTel/+kNqSQ7lw==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -10751,6 +10848,18 @@ "tslib": "^2.4.0" } }, + "@tailwindcss/typography": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.8.tgz", + "integrity": "sha512-xGQEp8KXN8Sd8m6R4xYmwxghmswrd0cPnNI2Lc6fmrC3OojysTBJJGSIVwPV56q4t6THFUK3HJ0EaWwpglSxWw==", + "dev": true, + "requires": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + } + }, "@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -12493,6 +12602,12 @@ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "dev": true }, + "hamburger-react": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/hamburger-react/-/hamburger-react-2.5.0.tgz", + "integrity": "sha512-5GSXe+ucxTPJ0SkhIsPQ/PRDweZPIKya1lfahAuExx31SdheeUA4uOPfQIAirbKona8hvo79VDr5LJQzPXsdpw==", + "requires": {} + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -12614,6 +12729,14 @@ "zwitch": "^2.0.0" } }, + "hast-util-sanitize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-sanitize/-/hast-util-sanitize-4.0.0.tgz", + "integrity": "sha512-pw56+69jq+QSr/coADNvWTmBPDy+XsmwaF5KnUys4/wM1jt/fZdl7GPxhXXXYdXnz3Gj3qMkbUCH2uKjvX0MgQ==", + "requires": { + "@types/hast": "^2.0.0" + } + }, "hast-util-select": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-5.0.2.tgz", @@ -13092,12 +13215,24 @@ "p-locate": "^5.0.0" } }, + "lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "dev": true + }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -14421,6 +14556,17 @@ "unified": "^10.0.0" } }, + "remark": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/remark/-/remark-14.0.2.tgz", + "integrity": "sha512-A3ARm2V4BgiRXaUo5K0dRvJ1lbogrbXnhkJRmD0yw092/Yl0kOCZt1k9ZeElEwkZsWGsMumz6qL5MfNJH9nOBA==", + "requires": { + "@types/mdast": "^3.0.0", + "remark-parse": "^10.0.0", + "remark-stringify": "^10.0.0", + "unified": "^10.0.0" + } + }, "remark-gfm": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz", @@ -14432,6 +14578,18 @@ "unified": "^10.0.0" } }, + "remark-html": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/remark-html/-/remark-html-15.0.1.tgz", + "integrity": "sha512-7ta5UPRqj8nP0GhGMYUAghZ/DRno7dgq7alcW90A7+9pgJsXzGJlFgwF8HOP1b1tMgT3WwbeANN+CaTimMfyNQ==", + "requires": { + "@types/mdast": "^3.0.0", + "hast-util-sanitize": "^4.0.0", + "hast-util-to-html": "^8.0.0", + "mdast-util-to-hast": "^12.0.0", + "unified": "^10.0.0" + } + }, "remark-parse": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", @@ -14453,6 +14611,16 @@ "unified": "^10.0.0" } }, + "remark-stringify": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-10.0.2.tgz", + "integrity": "sha512-6wV3pvbPvHkbNnWB0wdDvVFHOe1hBRAx1Q/5g/EpH4RppAII6J8Gnwe7VbHuXaoKIF6LAg6ExTel/+kNqSQ7lw==", + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.0.0", + "unified": "^10.0.0" + } + }, "resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", diff --git a/package.json b/package.json index 3521efa..ed2e97f 100644 --- a/package.json +++ b/package.json @@ -10,15 +10,20 @@ }, "dependencies": { "@uiw/react-md-editor": "^3.19.8", + "hamburger-react": "^2.5.0", "next": "12.3.0", "next-remove-imports": "^1.0.8", "react": "18.2.0", "react-dom": "18.2.0", "react-icons": "^4.6.0", - "react-player": "^2.11.0" + "react-player": "^2.11.0", + "remark": "^14.0.2", + "remark-gfm": "^3.0.1", + "remark-html": "^15.0.1" }, "devDependencies": { "@svgr/webpack": "^6.5.0", + "@tailwindcss/typography": "^0.5.8", "@types/node": "18.7.17", "@types/react": "18.0.19", "@types/react-dom": "18.0.6", diff --git a/pages/tech.tsx b/pages/tech/index.tsx similarity index 61% rename from pages/tech.tsx rename to pages/tech/index.tsx index a68e5d8..6bd9157 100644 --- a/pages/tech.tsx +++ b/pages/tech/index.tsx @@ -2,9 +2,9 @@ import type { NextPage } from "next"; import Head from "next/head"; import { useRouter } from "next/router"; import React, { useState, SetStateAction } from "react"; -import PostCard from "../components/PostCard"; +import PostCard from "../../components/PostCard"; import { GoSearch } from "react-icons/go"; -import { TagButtonType, TagButton, TagList } from "../components/Tags"; +import { TagButtonType, TagButton, TagList } from "../../components/Tags"; // Blog Page const Blog: NextPage = () => { @@ -18,15 +18,15 @@ const Blog: NextPage = () => { -
+
-

⚙️Tech Blog

-

대충 멋진 설명

+

⚙️Tech Blog

+

대충 멋진 설명

@@ -63,18 +63,34 @@ const Blog: NextPage = () => {
-
- - - - - - - - +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
-
+
); }; diff --git a/pages/tech/post/[postID].tsx b/pages/tech/post/[postID].tsx new file mode 100644 index 0000000..b9a966d --- /dev/null +++ b/pages/tech/post/[postID].tsx @@ -0,0 +1,165 @@ +import type { NextPage } from "next"; +import { useRouter } from "next/router"; +import Image from "next/image"; +import { PostTag } from "../../../components/Tags"; +import ReactMarkdown from "react-markdown"; +import remarkGfm from "remark-gfm"; +import React, { useState } from "react"; +import { PostComment } from "../../../components/PostComment"; +import PostCard from "../../../components/PostCard"; +import { + EmptyHeartIcon, + DownloadIcon, + ChatboxIcon, +} from "../../../components/Icons"; + +const PostView: NextPage = () => { + const router = useRouter(); + const { postID } = router.query; + /* content: 나중에 fetch해서 마크다운 내용 받을 state*/ + // const [content, setContent] = useState(''); + + const markdown = ` + # 제목이다. + ## 제목2이다. + + A paragraph with *emphasis* and **strong importance**. + +> A block quote with ~strikethrough~ and a URL: https://reactjs.org. + +\`code\` + +### 리스트들 +* Lists +* todo +* done + +|A|B| +|--|--| +|ghgh|hjh| + +`; + + return ( +
+
+ {/* 포스트 기본 정보(태그, 아이콘, 제목, 작성자, 수정/삭제 버튼) 섹션 */} +
+
+ +
+ + + +
+
+

+ Next.js의 Hydration 파헤치기 +

+
+
+ + by 노정훈회장님 + + + 2023년 1월 2일 + +
+ {/* TODO: 본인일 경우에만 수정 및 삭제 버튼 노출하기 */} +
+ + +
+
+
+ + {/* 포스트 본문 영역 */} +
+ , +
+ + {/* 작성자 프로필 영역 */} +
+
+ +
+
+ +
+
+ + 노정훈회장님 + +

+ 한 줄 소개 한 줄 소개 한 줄 소개 한 줄 소개 한 줄 소개 +

+
+
+ + {/* 하단 댓글정보 및 댓글작성 영역 */} +
+
+ 3 + 개의 댓글 +
+
+