-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
merge : post 부분
- Loading branch information
Showing
19 changed files
with
3,718 additions
and
123 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import React from "react"; | ||
import ReactMarkdown from "react-markdown"; | ||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; | ||
import { vscDarkPlus } from "react-syntax-highlighter/dist/esm/styles/prism"; | ||
import remarkGfm from "remark-gfm"; | ||
import styled from "styled-components"; | ||
|
||
const StyledCodeBlock = styled(SyntaxHighlighter)` | ||
border-radius: 8px; | ||
span { | ||
font-size: 15px; | ||
} | ||
`; | ||
|
||
const Wrapper = styled.div` | ||
color: ${(props) => props.theme.textColor}; | ||
font-size: 16px; | ||
margin-top: 16px; | ||
font-weight: 400; | ||
line-height: 2; | ||
p { | ||
font-size: 16px; | ||
margin-top: 16px; | ||
font-weight: 400; | ||
line-height: 2; | ||
} | ||
h1 { | ||
font-size: 36px; | ||
line-height: 1.2; | ||
font-weight: 500; | ||
} | ||
h2 { | ||
font-size: 32px; | ||
line-height: 1.2; | ||
font-weight: 500; | ||
margin-top: 80px; | ||
margin-bottom: 40px; | ||
} | ||
img { | ||
max-width: 800px; | ||
margin: 25px 0px; | ||
} | ||
`; | ||
|
||
function MarkdownRender(props) { | ||
const { markdownContent } = props; | ||
return ( | ||
<Wrapper> | ||
<ReactMarkdown | ||
remarkPlugins={[remarkGfm]} | ||
components={{ | ||
code({ node, inline, className, children, ...props }) { | ||
const match = /language-(\w+)/.exec(className || ""); | ||
return !inline && match ? ( | ||
// !inline && match 조건에 맞으면 하이라이팅 | ||
<StyledCodeBlock | ||
{...props} | ||
style={vscDarkPlus} | ||
language={match[1]} | ||
PreTag="div" | ||
> | ||
{String(children).replace(/\n$/, "")} | ||
</StyledCodeBlock> | ||
) : ( | ||
// 안 맞다면 문자열 형태로 반환 | ||
<code {...props} className={className}> | ||
{children} | ||
</code> | ||
); | ||
}, | ||
}} | ||
> | ||
{markdownContent} | ||
</ReactMarkdown> | ||
</Wrapper> | ||
); | ||
} | ||
|
||
export default MarkdownRender; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import React from "react"; | ||
import styled from "styled-components"; | ||
import fm from "front-matter"; | ||
import { useNavigate } from "react-router-dom"; | ||
|
||
const Wrapper = styled.div` | ||
width: 100%; | ||
display: flex; | ||
flex-direction: column; | ||
padding: 15px; | ||
border-radius: 10px; | ||
background-color: ${(props) => props.theme.boxBgColor}; | ||
`; | ||
|
||
const Thumbnail = styled.img` | ||
width: 100%; | ||
border-radius: 10px; | ||
height: 316px; | ||
object-fit: cover; | ||
`; | ||
|
||
const Date = styled.div` | ||
margin-top: 20px; | ||
font-size: 18px; | ||
`; | ||
|
||
const Title = styled.p` | ||
margin-top: 20px; | ||
overflow-wrap: break-word; | ||
font-size: 30px; | ||
font-weight: 500; | ||
line-height: 1.2; | ||
`; | ||
|
||
function PostCard(props) { | ||
const navigate = useNavigate(); | ||
const { post } = props; | ||
|
||
const getFileNameWithoutExtension = (filename) => { | ||
// 파일명을 점(.)을 기준으로 분할하여 배열로 만듭니다. | ||
const parts = filename.split("."); | ||
|
||
// 배열의 마지막 요소를 제거하여 파일의 확장자를 제거합니다. | ||
parts.pop(); | ||
|
||
// 배열의 나머지 요소를 다시 합쳐서 파일명으로 반환합니다. | ||
const filenameWithoutExtension = parts.join("."); | ||
|
||
return filenameWithoutExtension; | ||
}; | ||
|
||
const filename = getFileNameWithoutExtension(post.filename); | ||
|
||
const postData = fm(post.content).attributes; | ||
return ( | ||
<Wrapper | ||
onClick={() => { | ||
navigate(`/post/${filename}`); | ||
}} | ||
> | ||
<Thumbnail src={`${process.env.PUBLIC_URL}${postData.imgpath}`} /> | ||
<Date>{postData.date}</Date> | ||
<Title>{postData.title}</Title> | ||
</Wrapper> | ||
); | ||
} | ||
|
||
export default PostCard; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import React, { useEffect, useState } from "react"; | ||
import styled from "styled-components"; | ||
import fm from "front-matter"; | ||
import axios from "axios"; | ||
import { useParams } from "react-router-dom"; | ||
import Header from "../Header/Header"; | ||
import MarkdownRender from "../../common/MarkdownRender"; | ||
|
||
const Wrapper = styled.div` | ||
width: 100%; | ||
height: 100%; | ||
padding: 0 10rem; | ||
display: flex; | ||
flex-direction: column; | ||
background-color: ${(props) => props.theme.bgColor}; | ||
color: ${(props) => props.theme.textColor}; | ||
`; | ||
|
||
const Preview = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: center; | ||
align-items: center; | ||
gap: 20px; | ||
`; | ||
|
||
const Date = styled.p` | ||
color: #d9d9d9; | ||
font-weight: 500; | ||
`; | ||
|
||
const Title = styled.h1` | ||
font-size: 40px; | ||
line-height: 1.2; | ||
font-weight: 700; | ||
`; | ||
|
||
const Thumbnail = styled.img` | ||
width: 100%; | ||
height: 400px; | ||
border-radius: 20px; | ||
object-fit: cover; | ||
`; | ||
|
||
const ContentBox = styled.div` | ||
width: 100%; | ||
height: 100%; | ||
display: flex; | ||
flex-direction: column; | ||
margin-top: 15px; | ||
gap: 15px; | ||
`; | ||
|
||
function PostPage() { | ||
const { failename } = useParams(); | ||
|
||
const [markdownContent, setMarkdownContent] = useState(""); | ||
const [markdownData, setMarkdownData] = useState(); | ||
// markdown 파일을 가져와서 text로 변환 | ||
useEffect(() => { | ||
const getMarkdown = async (failename) => { | ||
try { | ||
const response = await axios.get( | ||
`https://nodestudy-34u2.onrender.com/post/${failename}` | ||
); | ||
const parsedMarkdown = fm(response.data); | ||
setMarkdownContent(parsedMarkdown.body); | ||
setMarkdownData(parsedMarkdown.attributes); | ||
} catch (err) { | ||
console.log("err", err); | ||
} | ||
}; | ||
getMarkdown(failename); | ||
}, [failename]); | ||
|
||
return ( | ||
<> | ||
<Header /> | ||
<Wrapper> | ||
<Preview> | ||
<Date>{markdownData?.date}</Date> | ||
<Title>{markdownData?.title}</Title> | ||
<Thumbnail src={markdownData?.imgpath} /> | ||
</Preview> | ||
<ContentBox> | ||
<MarkdownRender markdownContent={markdownContent} /> | ||
</ContentBox> | ||
</Wrapper> | ||
</> | ||
); | ||
} | ||
|
||
export default PostPage; |
Oops, something went wrong.