Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified .github/pull_request_template.md
100644 β†’ 100755
Empty file.
Empty file modified .gitignore
100644 β†’ 100755
Empty file.
Empty file modified .gitmessage.txt
100644 β†’ 100755
Empty file.
Empty file modified README.md
100644 β†’ 100755
Empty file.
Empty file modified package-lock.json
100644 β†’ 100755
Copy link

@charijyard charijyard Apr 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 18,256κ°œλ‚˜ μžˆλŠ”λ° pull requestν•˜λŠ” 데 문제 μ—†μ—ˆλ‹ˆ? .. μ‹ κΈ°ν•˜λ‹€

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

γ…‹γ…‹γ…‹λΈŒλžœμΉ˜ ν—·κ°ˆλ €μ„œ 초기 λΈŒλžœμΉ˜μ— λ³‘ν•©ν•˜λŠλΌ 컀밋이 λ§Žμ•„μ§„κ±° κ°™μ•„

Empty file.
Empty file modified package.json
100644 β†’ 100755
Empty file.
Empty file modified public/favicon.ico
100644 β†’ 100755
Empty file.
Empty file modified public/index.html
100644 β†’ 100755
Empty file.
Empty file modified public/logo192.png
100644 β†’ 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified public/logo512.png
100644 β†’ 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified public/manifest.json
100644 β†’ 100755
Empty file.
Empty file modified public/robots.txt
100644 β†’ 100755
Empty file.
Empty file modified src/App.css
100644 β†’ 100755
Empty file.
Empty file modified src/App.js
100644 β†’ 100755
Empty file.
Empty file modified src/App.test.js
100644 β†’ 100755
Empty file.
Empty file modified src/assets/images/lion.jpeg
100644 β†’ 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified src/assets/images/logo.png
100644 β†’ 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified src/components/Footer/index.jsx
100644 β†’ 100755
Empty file.
28 changes: 22 additions & 6 deletions src/components/Header/index.jsx
100644 β†’ 100755
Original file line number Diff line number Diff line change
@@ -1,21 +1,37 @@
import { Link } from "react-router-dom";
import { useEffect, useState } from "react";

import lion from "../../assets/images/lion.jpeg";

const Header = () => {
const [isUserLoggedIn, setIsUserLoggedIn] = useState(false); // 둜그인 μ—¬λΆ€ μƒνƒœ, μš°μ„  false둜 μ΄ˆκΈ°ν™”

useEffect(() => {
// TODO: 이후 api μ—°κ²° μ‹œ μœ νš¨ν•œ token이 μžˆλ‹€λ©΄ setIsUserLoggedIn(true)둜 μƒνƒœ λ³€κ²½ν•˜λŠ” μ½”λ“œ μž‘μ„±
}, []);

const handleSignOut = () => {
// TODO: 이후 api μ—°κ²° μ‹œ token 제거
};
return (
<div className="flex items-center justify-between w-full gap-5 bg-black px-5 py-2.5 h-20">
<Link to="/" className="flex flex-row items-center gap-5">
<img src={lion} alt="lion" className="max-h-16 rounded-full" />
<div className="text-white text-xl">SNULION BLOG</div>
</Link>
<div className="flex">
<Link to="/signin" className="mr-10 p-3 uppercase text-lg">
sign in
</Link>
<Link to="/signup" className="mr-10 p-3 uppercase text-lg">
sign up
</Link>
{isUserLoggedIn ?
<Link to="/" className="mr-10 p-3 uppercase text-lg">sign out</Link>
:
<>
<Link to="/signin" className="mr-10 p-3 uppercase text-lg">
sign in
</Link>
<Link to="/signup" className="mr-10 p-3 uppercase text-lg">
sign up
</Link>
</>
}
</div>
</div>
);
Expand Down
15 changes: 13 additions & 2 deletions src/components/Posts/index.jsx
100644 β†’ 100755
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { Link } from "react-router-dom";

export const SmallPost = ({ post }) => {
const onClickLike = (e) => {
e.preventDefault();
alert("λ‚˜λ„ μ’‹μ•„!");
// add api call for liking post here
};

return (
<Link
to={`/${post.id}`}
Expand All @@ -15,14 +21,19 @@ export const SmallPost = ({ post }) => {
</span>
))}
</div>
<span className="cursor-pointer">
<span onClick={onClickLike} className="cursor-pointer">
{post.like_users.length > 0 && `❀️ ${post.like_users.length}`}
</span>
</Link>
);
};

export const BigPost = ({ post }) => {
const onClickLike = (e) => {
e.preventDefault();
alert("λ‚˜λ„ μ’‹μ•„!");
// add api call for liking post here
};
return (
<div className="flex flex-col px-8 py-5 w-full bg-orange-400 ring-4 ring-orange-300 rounded-xl gap-5">
<div className="flex flex-row items-center justify-between gap-3">
Expand All @@ -44,7 +55,7 @@ export const BigPost = ({ post }) => {
</span>
))}
</div>
<span className="flex flex-row text-black cursor-pointer">
<span onClick={onClickLike} className="flex flex-row text-black cursor-pointer">
❀️ {post.like_users.length > 0 ? post.like_users.length : "0"}
</span>
</div>
Expand Down
Empty file modified src/data/posts.js
100644 β†’ 100755
Empty file.
Empty file modified src/index.css
100644 β†’ 100755
Empty file.
Empty file modified src/index.js
100644 β†’ 100755
Empty file.
Empty file modified src/logo.svg
100644 β†’ 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified src/reportWebVitals.js
100644 β†’ 100755
Empty file.
52 changes: 50 additions & 2 deletions src/routes/HomePage.jsx
100644 β†’ 100755
Original file line number Diff line number Diff line change
@@ -1,11 +1,46 @@
import { SmallPost } from "../components/Posts";
import { Link } from "react-router-dom";
import posts from "../data/posts";
import { useEffect, useState } from "react";

const HomePage = () => {
const postList = posts;
const [postList, setPostList] = useState(posts);

const handleChange = (e) => {};
const [tags, setTags] = useState([]);
const [searchTags, setSearchTags] = useState([]);
const [searchValue, setSearchValue] = useState("");

useEffect(() => {
const tagList = posts.reduce((acc, post) => {
for (let tag of post.tags) {
acc.add(tag.content);
}
return acc;
}, new Set());
setTags([...tagList]);
setSearchTags([...tagList]);
}, []);

const handleChange = (e) => {
const { value } = e.target;
const newTags = tags.filter((tag) => tag.includes(value));
setSearchTags(newTags);
};

const handleTagFilter = (e) => {
const { innerText } = e.target;
if (searchValue === innerText.substring(1)) {
setSearchValue("");
setPostList(posts);
} else {
const activeTag = innerText.substring(1);
setSearchValue(activeTag);
const newPosts = posts.filter((post) =>
post.tags.find((tag) => tag.content === activeTag)
);
setPostList(newPosts);
}
};

return (
<div>
Expand All @@ -20,6 +55,19 @@ const HomePage = () => {
className="border border-orange-400 outline-none rounded-2xl text-center py-2 px-20 text-orange-400 bg-transparent"
/>
</div>
<div className="flex mt-5 justify-center">
{searchTags.map((tag) => {
return (
<button
key={tag}
className={tag === searchValue ? "tag active mr-2" : "tag mr-2"}
onClick={handleTagFilter}
>
#{tag}
</button>
);
})}
</div>
<div className="grid grid-cols-3 px-10 mt-10">
{postList.map((post) => (
<SmallPost key={post.id} post={post} />
Expand Down
114 changes: 107 additions & 7 deletions src/routes/PostCreatePage.jsx
100644 β†’ 100755
Original file line number Diff line number Diff line change
@@ -1,22 +1,99 @@
import { useEffect, useState } from "react";
import posts from "../data/posts";
import { BigPost } from "../components/Posts";

const PostCreatePage = () => {
const post = {
const [isSubmitted, setIsSubmitted] = useState(false);
const [tags, setTags] = useState([]);
const [tagInputValue, setTagInputValue] = useState("");
const [autoCompletes, setAutoCompletes] = useState([]);
const [post, setPost] = useState({
id: posts.length,
title: "",
content: "",
author: { id: posts.length, username: "μ•„κΈ°μ‚¬μž" },
tags: [],
like_users: [],
created_at: "2024-02-04T07:42:50.658501Z",
});

const addTag = (e) => {
e.preventDefault();
if (post.tags.find((tag) => tag === tagInputValue)) return;
setPost({
...post,
tags: [...post.tags, tagInputValue],
});
setTagInputValue("");
setAutoCompletes([]);
};

const deleteTag = (tag) => {
setPost({
...post,
tags: post.tags.filter((t) => t !== tag),
});
};

const handleChange = (e) => {
setPost({ ...post, [e.target.id]: e.target.value });
};

const onSubmit = (e) => {
e.preventDefault();
const createdPost = {
...post,
like_users: [],
tags: post.tags.map((tag, idx) => {
return { id: idx + 1, content: tag };
}),
};
setPost(createdPost);
setIsSubmitted(true);

alert("κ²Œμ‹œκΈ€μ„ λ“±λ‘ν•©λ‹ˆλ‹€.");
//TODO : api connect(create post)
};

return (
useEffect(() => {
const duplicatedTagList = posts.reduce((acc, post) => {
for (let tag of post.tags) {
acc.add(tag.content);
}
return acc;
}, new Set());
const tagList = [...duplicatedTagList];
setTags([...tagList]);
}, []);

const handleAutoCompletes = (autoComplete) => {
const selectedTag = tags.find((tag) => tag === autoComplete);
if (post.tags.includes(selectedTag)) return; // μž…λ ₯ν•œ λ‚΄μš©μ΄ 이미 λ“±λ‘λœ νƒœκ·Έλ©΄ κ·Έλƒ₯ 등둝 μ•ˆλ¨
setPost({
...post,
tags: [...post.tags, selectedTag],
});
setTagInputValue("");
setAutoCompletes([]);
};

const handleTag = (e) => {
setTagInputValue(e.target.value);
if (e.target.value) {
const autoCompleteData = tags.filter((tag) =>
tag.includes(e.target.value)
);
setAutoCompletes(autoCompleteData);
} else {
setAutoCompletes([]);
}
};

return isSubmitted ? (
<div className="flex flex-col items-center w-[60%] p-8">
<BigPost post={post} />
</div>
) : (
<div className="flex flex-col items-center w-3/5">
<h3 className="font-bold text-4xl">κ²Œμ‹œκΈ€ μž‘μ„±</h3>
<form className="form" onSubmit={onSubmit}>
Expand All @@ -26,21 +103,23 @@ const PostCreatePage = () => {
<input
type="text"
placeholder="제λͺ©μ„ μž…λ ₯ν•˜μ„Έμš”"
defaultValue={post.title}
id="title"
className="input"
required
value={post.title}
onChange={handleChange}
/>
<label htmlFor="content" className="label">
λ‚΄μš©
</label>
<textarea
placeholder="λ‚΄μš©μ„ μž…λ ₯ν•˜μ„Έμš”"
id="content"
defaultValue={post.content}
value={post.content}
cols="30"
rows="10"
className="input"
onChange={handleChange}
required
></textarea>
<label htmlFor="tags" className="label">
Expand All @@ -53,20 +132,41 @@ const PostCreatePage = () => {
placeholder="νƒœκ·Έλ₯Ό μΆ”κ°€ν•˜μ„Έμš”"
id="tags"
className="input grow"
value={tagInputValue}
onChange={handleTag}
/>
<button type="button" className="small-button w-16">
<button
type="button"
className="small-button w-16"
onClick={addTag}
>
μΆ”κ°€
</button>
</div>
</div>
<div className="flex mt-2 bg-black border-gray-500 rounded-2xl w-full">
{autoCompletes &&
autoCompletes.map((autoComplete) => (
<button
className="tag rounded-2xl text-start border-gray-500 py-2 px-3 text-white focus:bg-gray"
key={autoComplete}
onClick={() => handleAutoCompletes(autoComplete)}
>
#{autoComplete}
</button>
))}
</div>
{post.tags && (
<div className="flex w-full mt-3 gap-x-1 flew-nowrap">
{post.tags.map((tag) => (
<div key={tag} className="flex">
<span className="tag active m-1 flex flex-row items-center gap-x-2">
<p>#{tag}</p>
</span>
<button className="after:content-['\00d7'] text-xl" />
<button
onClick={() => deleteTag(tag)}
className="after:content-['\00d7'] text-xl"
/>
</div>
))}
</div>
Expand All @@ -77,6 +177,6 @@ const PostCreatePage = () => {
</form>
</div>
);
};
};

export default PostCreatePage;
8 changes: 5 additions & 3 deletions src/routes/PostDetailPage.jsx
100644 β†’ 100755
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState, useEffect } from "react";
import { useParams, Link } from "react-router-dom";
import { useParams, Link, useNavigate } from "react-router-dom";
import { BigPost } from "../components/Posts";
import posts from "../data/posts";

Expand All @@ -11,9 +11,11 @@ const PostDetailPage = () => {
setPost(post);
}, [postId]);

const navigate = useNavigate();
const onClickDelete = () => {
alert("μ‚­μ œ");
//TODO : api connect(delete post)
alert("κ²Œμ‹œλ¬Όμ„ μ‚­μ œν•©λ‹ˆλ‹€.");
navigate("/");
// add api call for deleting post
};

return (
Expand Down
Loading