-
Notifications
You must be signed in to change notification settings - Fork 93
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
[ 18팀 윤성용 ] 프레임워크 없이 SPA 만들기 #14
Changes from all commits
1142d4f
425fa93
4d0b0d4
2c74e9c
990366e
bc612d4
2cfd0be
5378514
b8b5b15
aec0dfa
f994dc7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
const Footer = () => { | ||
return ` | ||
<footer class="bg-gray-200 p-4 text-center"> | ||
<p>© 2024 항해플러스. All rights reserved.</p> | ||
</footer> | ||
` | ||
} | ||
|
||
export default Footer |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import {Store} from "../utils/store.js"; | ||
|
||
const Header = () => { | ||
const store = new Store() | ||
const {isLogin} = store.getState() | ||
const activeClass = (path) => location.pathname === path ? 'text-blue-600 font-bold' : 'text-gray-600'; | ||
|
||
return ` | ||
<header class="bg-blue-600 text-white p-4 sticky top-0"> | ||
<h1 class="text-2xl font-bold">항해플러스</h1> | ||
</header> | ||
<nav id="header-nav" class="bg-white shadow-md p-2 sticky top-14"> | ||
<ul class="flex justify-around"> | ||
${isLogin ? ` | ||
<li><a href="/" class="${activeClass('/')}">홈</a></li> | ||
<li><a href="/profile" class="${activeClass('/profile')}">프로필</a></li> | ||
<li><a href="/login" id="logout" class="text-gray-600" id="logout">로그아웃</a></li>` : | ||
`<li><a href="/" class="${activeClass('/')}">홈</a></li> | ||
<li><a href="/login" class="text-gray-600">로그인</a></li>`} | ||
</ul> | ||
</nav> | ||
` | ||
} | ||
|
||
export default Header | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import {Store} from "../utils/store.js"; | ||
import {Logger} from "../utils/logger.js"; | ||
import {Storage} from "../utils/storage.js"; | ||
|
||
export const addLogoutEvent = () => { | ||
const store = new Store() | ||
const logger = new Logger() | ||
const storage = new Storage() | ||
Comment on lines
+6
to
+8
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 logoutBtn = document.getElementById('logout'); | ||
|
||
if (logoutBtn) { | ||
logoutBtn.addEventListener('click', (e) => { | ||
storage.removeData('isLogin') | ||
storage.removeData('user') | ||
store.setState({ isLogin: false }); | ||
logger.log({ | ||
type : 'event', | ||
location : 'addLogoutEvent', | ||
message : 'success logout event' | ||
}) | ||
}); | ||
} | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,111 +1,3 @@ | ||
document.querySelector('#root').innerHTML = ` | ||
<div class="bg-gray-100 min-h-screen flex justify-center"> | ||
<div class="max-w-md w-full"> | ||
<header class="bg-blue-600 text-white p-4 sticky top-0"> | ||
<h1 class="text-2xl font-bold">항해플러스</h1> | ||
</header> | ||
import App from "./pages/App.js"; | ||
|
||
<nav class="bg-white shadow-md p-2 sticky top-14"> | ||
<ul class="flex justify-around"> | ||
<li><a href="./main.html" class="text-blue-600">홈</a></li> | ||
<li><a href="./profile.html" class="text-gray-600">프로필</a></li> | ||
<li><a href="#" class="text-gray-600">로그아웃</a></li> | ||
</ul> | ||
</nav> | ||
|
||
<main class="p-4"> | ||
<div class="mb-4 bg-white rounded-lg shadow p-4"> | ||
<textarea class="w-full p-2 border rounded" placeholder="무슨 생각을 하고 계신가요?"></textarea> | ||
<button class="mt-2 bg-blue-600 text-white px-4 py-2 rounded">게시</button> | ||
</div> | ||
|
||
<div class="space-y-4"> | ||
|
||
<div class="bg-white rounded-lg shadow p-4"> | ||
<div class="flex items-center mb-2"> | ||
<img src="https://via.placeholder.com/40" alt="프로필" class="rounded-full mr-2"> | ||
<div> | ||
<p class="font-bold">홍길동</p> | ||
<p class="text-sm text-gray-500">5분 전</p> | ||
</div> | ||
</div> | ||
<p>오늘 날씨가 정말 좋네요. 다들 좋은 하루 보내세요!</p> | ||
<div class="mt-2 flex justify-between text-gray-500"> | ||
<button>좋아요</button> | ||
<button>댓글</button> | ||
<button>공유</button> | ||
</div> | ||
</div> | ||
|
||
<div class="bg-white rounded-lg shadow p-4"> | ||
<div class="flex items-center mb-2"> | ||
<img src="https://via.placeholder.com/40" alt="프로필" class="rounded-full mr-2"> | ||
<div> | ||
<p class="font-bold">김철수</p> | ||
<p class="text-sm text-gray-500">15분 전</p> | ||
</div> | ||
</div> | ||
<p>새로운 프로젝트를 시작했어요. 열심히 코딩 중입니다!</p> | ||
<div class="mt-2 flex justify-between text-gray-500"> | ||
<button>좋아요</button> | ||
<button>댓글</button> | ||
<button>공유</button> | ||
</div> | ||
</div> | ||
|
||
<div class="bg-white rounded-lg shadow p-4"> | ||
<div class="flex items-center mb-2"> | ||
<img src="https://via.placeholder.com/40" alt="프로필" class="rounded-full mr-2"> | ||
<div> | ||
<p class="font-bold">이영희</p> | ||
<p class="text-sm text-gray-500">30분 전</p> | ||
</div> | ||
</div> | ||
<p>오늘 점심 메뉴 추천 받습니다. 뭐가 좋을까요?</p> | ||
<div class="mt-2 flex justify-between text-gray-500"> | ||
<button>좋아요</button> | ||
<button>댓글</button> | ||
<button>공유</button> | ||
</div> | ||
</div> | ||
|
||
<div class="bg-white rounded-lg shadow p-4"> | ||
<div class="flex items-center mb-2"> | ||
<img src="https://via.placeholder.com/40" alt="프로필" class="rounded-full mr-2"> | ||
<div> | ||
<p class="font-bold">박민수</p> | ||
<p class="text-sm text-gray-500">1시간 전</p> | ||
</div> | ||
</div> | ||
<p>주말에 등산 가실 분 계신가요? 함께 가요!</p> | ||
<div class="mt-2 flex justify-between text-gray-500"> | ||
<button>좋아요</button> | ||
<button>댓글</button> | ||
<button>공유</button> | ||
</div> | ||
</div> | ||
|
||
<div class="bg-white rounded-lg shadow p-4"> | ||
<div class="flex items-center mb-2"> | ||
<img src="https://via.placeholder.com/40" alt="프로필" class="rounded-full mr-2"> | ||
<div> | ||
<p class="font-bold">정수연</p> | ||
<p class="text-sm text-gray-500">2시간 전</p> | ||
</div> | ||
</div> | ||
<p>새로 나온 영화 재미있대요. 같이 보러 갈 사람?</p> | ||
<div class="mt-2 flex justify-between text-gray-500"> | ||
<button>좋아요</button> | ||
<button>댓글</button> | ||
<button>공유</button> | ||
</div> | ||
</div> | ||
</div> | ||
</main> | ||
|
||
<footer class="bg-gray-200 p-4 text-center"> | ||
<p>© 2024 항해플러스. All rights reserved.</p> | ||
</footer> | ||
</div> | ||
</div> | ||
`; | ||
App(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import Router from "../utils/router.js"; | ||
import {Store} from "../utils/store.js"; | ||
import {$, setTpl} from "../utils/dom.js"; | ||
import {Logger} from "../utils/logger.js"; | ||
|
||
const errorMessageTpl = (errorMessage) => { | ||
return ` | ||
<main class="min-h-screen flex justify-center"> | ||
<div class="flex flex-col items-center justify-center"> | ||
<p class="text-red-600">${errorMessage}</p> | ||
<p>오류 발생!</p> | ||
<p>의도적인 오류입니다.</p> | ||
</div> | ||
</main> | ||
` | ||
} | ||
|
||
const App = () => { | ||
const logger = new Logger() | ||
|
||
window.addEventListener('error', (event) => { | ||
const {error} = event | ||
|
||
try{ | ||
const {errorMessage,errorLog} = JSON.parse(error.message) | ||
setTpl(errorMessageTpl(errorMessage))($('#root')); | ||
logger.log(errorLog) | ||
}catch (e) { | ||
setTpl(errorMessageTpl('예기치 못한 에러가 발생했습니다.'))($('#root')); | ||
Comment on lines
+25
to
+29
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. 실행할 때 마다 querySelector로 root를 가져오게 되네요. |
||
logger.log({ | ||
type : 'error', | ||
location : 'addGlobalErrorHandler', | ||
message : 'error logs parse error' | ||
}) | ||
} | ||
}) | ||
|
||
new Router() | ||
new Store() | ||
} | ||
|
||
export default App |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import {$, setTpl} from "../../utils/dom.js"; | ||
import {dashboardTpl} from "./templates.js"; | ||
|
||
const setDashboardOnDocument = () => { | ||
setTpl(dashboardTpl())($('#root')); | ||
} | ||
|
||
export default setDashboardOnDocument |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import {Logger} from "../../utils/logger.js"; | ||
|
||
export const dashboardTpl = () => { | ||
const logger = new Logger() | ||
const loggerList = logger.getLogs() || [] | ||
|
||
|
||
return ` | ||
<main class="w-full flex justify-center p-6"> | ||
<table class="table-auto border-collapse w-full max-w-4xl"> | ||
<thead class="bg-gray-100"> | ||
<tr> | ||
<th class="border px-4 py-2 text-left">시간</th> | ||
<th class="border px-4 py-2 text-left">이벤트 타입</th> | ||
<th class="border px-4 py-2 text-left">발생 위치</th> | ||
<th class="border px-4 py-2 text-left">내용</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
${loggerList.map((items) => { | ||
return ` | ||
<tr class="bg-white border-b"> | ||
<td class="border px-4 py-2">${items.timestamp}</td> | ||
<td class="border px-4 py-2">${items.type}</td> | ||
<td class="border px-4 py-2">${items.location}</td> | ||
<td class="border px-4 py-2">${items.message}</td> | ||
</tr> | ||
Comment on lines
+3
to
+27
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. 템플릿 대시보드 형태의 함수를 만들어서 UI 구조를 가져가시는게 최고네요,, 성용님의 전용 로거들을 사용하기에 매우 좋은 환경으로 갖춰진 코드같습니다 👍🏻👍🏻 |
||
`; | ||
}).join('')} | ||
</tbody> | ||
</table> | ||
</main> | ||
`; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import {$, setTpl} from "../../utils/dom.js"; | ||
import {errorTpl} from "./templates.js"; | ||
import {Logger} from "../../utils/logger.js"; | ||
|
||
const setErrorOnDocument = () => { | ||
const logger = new Logger() | ||
logger.log({ | ||
type : 'error', | ||
location : 'errorPage', | ||
message : 'not find page error' | ||
}) | ||
|
||
setTpl(errorTpl())($('#root')); | ||
} | ||
|
||
export default setErrorOnDocument |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
export const errorTpl = () => { | ||
return ` | ||
<main class="bg-gray-100 flex items-center justify-center min-h-screen"> | ||
<div class="bg-white p-8 rounded-lg shadow-md w-full text-center" style="max-width: 480px"> | ||
<h1 class="text-2xl font-bold text-blue-600 mb-4">항해플러스</h1> | ||
<p class="text-4xl font-bold text-gray-800 mb-4">404</p> | ||
<p class="text-xl text-gray-600 mb-8">페이지를 찾을 수 없습니다</p> | ||
<p class="text-gray-600 mb-8"> | ||
요청하신 페이지가 존재하지 않거나 이동되었을 수 있습니다. | ||
</p> | ||
<a href="/" class="bg-blue-600 text-white px-4 py-2 rounded font-bold"> | ||
홈으로 돌아가기 | ||
</a> | ||
</div> | ||
</main> | ||
` | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import {$, setTpl} from "../../utils/dom.js"; | ||
import {homeTpl} from "./templates.js"; | ||
import {addLogoutEvent} from "../../events/addLogoutEvent.js"; | ||
|
||
const setHomeOnDocument = () => { | ||
setTpl(homeTpl())($('#root')); | ||
addLogoutEvent() | ||
} | ||
|
||
export default setHomeOnDocument |
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.
액티브 클래스라는 함수를 만들어서 로그인/비로그인시에 헤더 UI를 구분하는 것을 깔끔하게 구현하신 것 같아요👍🏻👍🏻