Skip to content

Commit

Permalink
merge : post 부분
Browse files Browse the repository at this point in the history
merge : post 부분
  • Loading branch information
sheepdog13 authored Feb 27, 2024
2 parents e74494d + 12289a6 commit 239668c
Show file tree
Hide file tree
Showing 19 changed files with 3,718 additions and 123 deletions.
3,051 changes: 3,051 additions & 0 deletions client/package-lock.json

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"proxy": "http://localhost:4000",
"name": "nodestudy",
"version": "0.1.0",
"private": true,
Expand All @@ -12,17 +11,22 @@
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.6.3",
"buffer": "^6.0.3",
"front-matter": "^4.0.2",
"http-proxy-middleware": "^2.0.6",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.49.2",
"react-markdown": "^9.0.1",
"react-query": "^3.39.3",
"react-redux": "^9.0.4",
"react-router-dom": "^6.21.1",
"react-scripts": "5.0.1",
"react-syntax-highlighter": "^15.5.0",
"redux": "^5.0.1",
"redux-promise": "^0.6.0",
"redux-thunk": "^3.1.0",
"remark-gfm": "^4.0.0",
"styled-components": "^6.1.8",
"web-vitals": "^2.1.4"
},
Expand Down
Binary file added client/public/img/ramen/cover.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added client/public/img/react/cover.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added client/public/img/yeonpotang/cover.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions client/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import RegisterPage from "./components/views/RegisterPage/RegisterPage";
import { ThemeProvider } from "styled-components";
import { dark, light } from "./styles/theme";
import { useSelector } from "react-redux";
import PostPage from "./components/views/PostPage/PostPage";

function App() {
const isDark = useSelector((state) => state.darkmode.isDark);
Expand All @@ -18,6 +19,7 @@ function App() {
<Route path="/" element={<LaindingPage />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/register" element={<RegisterPage />} />
<Route path="/post/:failename" element={<PostPage />} />
</Routes>
</ThemeProvider>
</>
Expand Down
79 changes: 79 additions & 0 deletions client/src/components/common/MarkdownRender.js
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;
57 changes: 29 additions & 28 deletions client/src/components/views/LandingPage/LandingPage.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
import React from "react";
import React, { useEffect, useState } from "react";
import Auth from "../../../hoc/auth";
import Header from "../Header/Header";
import styled from "styled-components";
import { useSelector } from "react-redux";
import AboutMe from "./AboutMe";
import PostCard from "./PostCard";
import axios from "axios";

const Wrapper = styled.div`
width: 100%;
height: 100vh;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
padding-bottom: 120px;
background-color: ${(props) => props.theme.bgColor};
color: ${(props) => props.theme.textColor};
`;

const H1 = styled.h1`
display: flex;
font-size: 30px;
font-weight: 500;
`;
const ContentBox = styled.div`
@media (max-width: 820px) {
flex-direction: column;
}
width: 100%;
height: 100%;
margin-top: 15px;
padding: 0 2rem;
gap: 15px;
Expand All @@ -34,42 +32,45 @@ const ContentBox = styled.div`
const LeftContentBox = styled.div`
display: flex;
width: 300px;
height: 100%;
@media (max-width: 820px) {
width: 100%;
}
`;
const RightContentBox = styled.div`
display: flex;
flex: 1;
justify-content: center;
align-items: center;
border-radius: 10px;
background-color: ${(props) => props.theme.boxBgColor};
width: 100%;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
`;

function LandingPage() {
// const logout = async () => {
// try {
// const res = await axios.get("/api/users/logout");
// console.log(res);
// } catch (err) {
// alert("로그아웃 실패");
// console.log(err);
// }
// };
const username = useSelector((state) => state.user.auth.name);
const isLogin = useSelector((state) => state.user.auth.isAuth);

const [postArray, setPostArray] = useState([]);
useEffect(() => {
const getMarkdown = async () => {
try {
const response = await axios.get(
"https://nodestudy-34u2.onrender.com/allmarkdown"
);
setPostArray(response.data);
} catch (err) {
console.log("err", err);
}
};
getMarkdown();
}, []);
return (
<>
<Header />
<Wrapper>
<Header />
<ContentBox>
<LeftContentBox>
<AboutMe />
</LeftContentBox>
<RightContentBox>
{isLogin && <H1>반갑습니다 {username}님!</H1>}
{postArray.map((post, i) => (
<PostCard key={i} post={post} />
))}
</RightContentBox>
</ContentBox>
</Wrapper>
Expand Down
68 changes: 68 additions & 0 deletions client/src/components/views/LandingPage/PostCard.js
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;
93 changes: 93 additions & 0 deletions client/src/components/views/PostPage/PostPage.js
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;
Loading

0 comments on commit 239668c

Please sign in to comment.