-
Notifications
You must be signed in to change notification settings - Fork 65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[2팀 송창엽] [Chapter 1-2] 프레임워크 없이 SPA 만들기 #45
base: main
Are you sure you want to change the base?
Changes from all commits
bdaabee
73f0b4a
d75af23
cac4cb0
cd2c8cc
06d535c
a70c89d
6bf8db4
1a18137
3a21d5e
d643b9f
c0a30e3
d935185
f6766dd
3adeaeb
8777dbb
f438df7
086b589
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,36 @@ | ||
/** @jsx createVNode */ | ||
import { createVNode } from "../../lib"; | ||
import { globalStore, PostType } from "../../stores/globalStore.js"; | ||
import { toTimeFormat } from "../../utils/index.js"; | ||
|
||
interface PostProps extends PostType { | ||
activationLike?: boolean; | ||
} | ||
|
||
export const Post = ({ | ||
author, | ||
time, | ||
content, | ||
likeUsers, | ||
activationLike = false, | ||
}) => { | ||
id, | ||
}: PostProps) => { | ||
const { loggedIn } = globalStore.getState(); | ||
const { toggleLike } = globalStore.actions; | ||
Comment on lines
+18
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Post를 호출하는 곳에서 조회하면 더 좋을 것 같아요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 앗 그러네요 ! 원영님 말씀대로 생각하니 더 좋은 구조인 것 같습니다 |
||
|
||
const handleToggleLike = () => { | ||
if (!loggedIn) { | ||
window.alert("로그인 후 이용해주세요"); | ||
return; | ||
} | ||
|
||
if (!id) { | ||
return; | ||
} | ||
|
||
toggleLike(id); | ||
}; | ||
|
||
return ( | ||
<div className="bg-white rounded-lg shadow p-4 mb-4"> | ||
<div className="flex items-center mb-2"> | ||
|
@@ -21,8 +43,9 @@ export const Post = ({ | |
<div className="mt-2 flex justify-between text-gray-500"> | ||
<span | ||
className={`like-button cursor-pointer${activationLike ? " text-blue-500" : ""}`} | ||
onClick={handleToggleLike} | ||
> | ||
좋아요 {likeUsers.length} | ||
좋아요 {likeUsers?.length} | ||
</span> | ||
<span>댓글</span> | ||
<span>공유</span> | ||
|
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/** @jsx createVNode */ | ||
import { createVNode } from "../../lib"; | ||
import { globalStore } from "../../stores"; | ||
import { getCurrentTime } from "../../utils"; | ||
|
||
export const PostForm = () => { | ||
const { addPost } = globalStore.actions; | ||
const { currentUser } = globalStore.getState(); | ||
|
||
const handleSubmit = (event: SubmitEvent) => { | ||
event.preventDefault(); | ||
|
||
if (!currentUser) return; | ||
|
||
const postContent = document.getElementById( | ||
"post-content", | ||
) as HTMLTextAreaElement; | ||
|
||
const contentValue = postContent ? postContent.value : ""; | ||
|
||
addPost({ | ||
author: currentUser.username, | ||
content: contentValue, | ||
time: getCurrentTime(), | ||
}); | ||
}; | ||
|
||
return ( | ||
<form | ||
className="mb-4 bg-white rounded-lg shadow p-4" | ||
onSubmit={handleSubmit} | ||
> | ||
<textarea | ||
id="post-content" | ||
placeholder="무슨 생각을 하고 계신가요?" | ||
className="w-full p-2 border rounded" | ||
/> | ||
<button | ||
id="post-submit" | ||
className="mt-2 bg-blue-600 text-white px-4 py-2 rounded" | ||
> | ||
게시 | ||
</button> | ||
</form> | ||
); | ||
}; |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from "./Post.tsx"; | ||
export * from "./PostForm.tsx"; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/** @jsx createVNode */ | ||
import { createVNode } from "../../lib"; | ||
import { router } from "../../router"; | ||
|
||
interface LinkProps { | ||
onClick?: () => void; | ||
children?: unknown; | ||
href: string; | ||
className?: string; | ||
} | ||
Comment on lines
+5
to
+10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저는 타입스크립트를 많이 안 써봤습니다..ㅎㅎ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://yceffort.kr/2021/03/typescript-interface-vs-type There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 수연님 좋은 아티클 감사드립니다 ㅎㅎ 이건 별건 아니구 타입스크립트의 문제를 풀어보는 챌린지인데 한번 보셔도 될 것 같습니다 ! (저는 eazy도 어려웠어요) |
||
|
||
export function Link({ onClick, children, ...props }: LinkProps) { | ||
const handleClick = (e) => { | ||
e.preventDefault(); | ||
onClick?.(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저는 보통 |
||
router.get().push(e.target.href.replace(window.location.origin, "")); | ||
}; | ||
return ( | ||
<a onClick={handleClick} {...props}> | ||
{children} | ||
</a> | ||
); | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import { addEvent } from "./eventManager"; | ||
import { normalizeVNode } from "./normalizeVNode"; | ||
|
||
export interface VNode { | ||
type: string | Function; | ||
props: Record<string, any>; | ||
children?: Array<VNode | string | number>; | ||
} | ||
|
||
export function createElement(vNode: VNode) { | ||
if (vNode && typeof vNode.type === "function") { | ||
throw new Error("Function component is not supported"); | ||
} | ||
|
||
// vNode 정규화 | ||
let normalizedVNode = normalizeVNode(vNode); | ||
|
||
// null, undefined, boolean 빈 텍스트 노드 변환 | ||
if ( | ||
typeof normalizedVNode === "boolean" || | ||
normalizedVNode === null || | ||
normalizedVNode === undefined | ||
) { | ||
return document.createTextNode(""); | ||
} | ||
|
||
if ( | ||
typeof normalizedVNode === "string" || | ||
typeof normalizedVNode === "number" | ||
) { | ||
return document.createTextNode(String(normalizedVNode)); | ||
} | ||
|
||
if (Array.isArray(normalizedVNode)) { | ||
const fragment = document.createDocumentFragment(); | ||
|
||
normalizedVNode.forEach((child) => { | ||
fragment.appendChild(createElement(child)); | ||
}); | ||
|
||
return fragment; | ||
} | ||
|
||
// 일반 DOM 요소 생성 | ||
const { type, props = {}, children = [] } = normalizedVNode; | ||
const $element = document.createElement(type) as HTMLElement; | ||
|
||
// props 적용 | ||
updateAttributes($element, props); | ||
|
||
// children 추가 | ||
children.forEach((child) => { | ||
$element.appendChild(createElement(child)); | ||
}); | ||
|
||
return $element; | ||
} | ||
|
||
function updateAttributes($element: HTMLElement, props: Record<string, any>) { | ||
if (!props) return; | ||
|
||
Object.entries(props).forEach(([key, value]) => { | ||
// 이벤트 핸들러 등록 | ||
if (key.startsWith("on") && typeof value === "function") { | ||
const eventType = key.toLowerCase().substring(2); | ||
addEvent($element, eventType, value); | ||
return; | ||
} | ||
|
||
// className 등록 | ||
if (key === "className") { | ||
$element.setAttribute("class", value); | ||
return; | ||
} | ||
|
||
// 일반 속성 등록 | ||
$element.setAttribute(key, value); | ||
}); | ||
} |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
타입스크립트 사용하셨군요.. 저도 다음 과제에는 꼭 타입스크립트로 한번 해보겠습니다..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
22..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
333
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이번 과제부터 타입스크립트가 기본 적용이니 같이 타입지옥에 빠져보시지요 ㅎㅎㅎ