diff --git a/src/classes/Router.js b/src/classes/Router.js
new file mode 100644
index 00000000..3976ae54
--- /dev/null
+++ b/src/classes/Router.js
@@ -0,0 +1,26 @@
+export class Router {
+ constructor() {
+ this.routes = {};
+ window.addEventListener("popstate", this.handlePopState.bind(this));
+ }
+
+ addRoute(path, handler) {
+ this.routes[path] = handler;
+ }
+
+ navigateTo(path, replace = false) {
+ if (replace) history.replaceState({}, "", path);
+ else history.pushState({}, "", path);
+ this.handleRoute(path);
+ }
+
+ handlePopState() {
+ this.handleRoute(window.location.pathname);
+ }
+
+ handleRoute(path) {
+ const handler = this.routes[path];
+ if (handler) handler();
+ else this.navigateTo("/404");
+ }
+}
diff --git a/src/classes/User.js b/src/classes/User.js
new file mode 100644
index 00000000..982d3df2
--- /dev/null
+++ b/src/classes/User.js
@@ -0,0 +1,23 @@
+export class User {
+ constructor() {
+ this.preferences = JSON.parse(localStorage.getItem("user")) || {};
+ }
+
+ set(key, value) {
+ this.preferences[key] = value;
+ this.save();
+ }
+
+ get(key) {
+ return this.preferences[key];
+ }
+
+ save() {
+ localStorage.setItem("user", JSON.stringify(this.preferences));
+ }
+
+ clear() {
+ this.preferences = {};
+ localStorage.removeItem("user");
+ }
+}
diff --git a/src/components/Footer.js b/src/components/Footer.js
new file mode 100644
index 00000000..ed9d133a
--- /dev/null
+++ b/src/components/Footer.js
@@ -0,0 +1,6 @@
+export function Footer() {
+ return `
+ `;
+}
diff --git a/src/components/Header.js b/src/components/Header.js
new file mode 100644
index 00000000..cf96c24c
--- /dev/null
+++ b/src/components/Header.js
@@ -0,0 +1,38 @@
+import { isLoggedIn } from "../main";
+
+export function Header() {
+ const currentPath = window.location.pathname;
+
+ const profileLinkClass =
+ currentPath === "/profile" ? "text-blue-600" : "text-gray-600";
+
+ const homeLinkeClass =
+ currentPath === "/" ? "text-blue-600 font-bold" : "text-gray-600";
+
+ return `
+
+
+ `;
+}
diff --git a/src/main.js b/src/main.js
index 755b2805..59a1b510 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,111 +1,53 @@
-document.querySelector('#root').innerHTML = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
오늘 날씨가 정말 좋네요. 다들 좋은 하루 보내세요!
-
-
-
-
-
-
-
-
-
-
-
-
-
새로운 프로젝트를 시작했어요. 열심히 코딩 중입니다!
-
-
-
-
-
-
-
-
-
-
-
-
-
오늘 점심 메뉴 추천 받습니다. 뭐가 좋을까요?
-
-
-
-
-
-
-
-
-
-
-
-
-
주말에 등산 가실 분 계신가요? 함께 가요!
-
-
-
-
-
-
-
-
-
-
-
-
-
새로 나온 영화 재미있대요. 같이 보러 갈 사람?
-
-
-
-
-
-
-
-
-
-
-
-
-`;
+import { Router } from "./classes/Router";
+import { User } from "./classes/User";
+import { HomePage } from "./pages/HomePage";
+import { LoginPage } from "./pages/LoginPage";
+import { NotFound } from "./pages/NotFound";
+import { ProfilePage } from "./pages/ProfilePage";
+
+export const router = new Router();
+export const user = new User();
+export function isLoggedIn() {
+ return user?.preferences?.username?.length > 0;
+}
+
+router.addRoute("/", HomePage);
+router.addRoute("/profile", ProfilePage);
+router.addRoute("/login", LoginPage);
+router.addRoute("/404", NotFound);
+
+export function handleRouting() {
+ const links = document.querySelectorAll("a");
+
+ links.forEach((link) => {
+ link.addEventListener("click", (e) => {
+ e.preventDefault();
+
+ if (e.target.getAttribute("href") === "/login") {
+ e.stopPropagation();
+ return;
+ }
+ router.navigateTo(e.target.getAttribute("href"));
+ });
+ });
+}
+
+export function Logout() {
+ const logoutEl = document.querySelector("#logout");
+ if (logoutEl)
+ logoutEl.addEventListener("click", () => {
+ user.clear();
+ router.navigateTo("/");
+ });
+}
+
+document.addEventListener("DOMContentLoaded", () => {
+ router.handleRoute(window.location.pathname);
+});
+
+window.addEventListener("error", (event) => {
+ const errorBoundary = document.createElement("div");
+ errorBoundary.id = "error-boundary";
+ errorBoundary.textContent = `오류 발생! ${event.message}`;
+ document.body.appendChild(errorBoundary);
+});
diff --git a/src/pages/HomePage.js b/src/pages/HomePage.js
new file mode 100644
index 00000000..49fa2326
--- /dev/null
+++ b/src/pages/HomePage.js
@@ -0,0 +1,132 @@
+import { Footer } from "../components/Footer";
+import { Header } from "../components/Header";
+import { Logout, handleRouting } from "../main";
+
+export function HomePage() {
+ let html;
+ html = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
오늘 날씨가 정말 좋네요. 다들 좋은 하루 보내세요!
+
+
+
+
+
+
+
+
+
+
+
+
+
새로운 프로젝트를 시작했어요. 열심히 코딩 중입니다!
+
+
+
+
+
+
+
+
+
+
+
+
+
오늘 점심 메뉴 추천 받습니다. 뭐가 좋을까요?
+
+
+
+
+
+
+
+
+
+
+
+
+
주말에 등산 가실 분 계신가요? 함께 가요!
+
+
+
+
+
+
+
+
+
+
+
+
+
새로 나온 영화 재미있대요. 같이 보러 갈 사람?
+
+
+
+
+
+
+
+
+
+
`;
+ document.querySelector(
+ "#root"
+ ).innerHTML = `
+
${Header()}${html}${Footer()}
+
`;
+
+ handleRouting();
+ Logout();
+}
diff --git a/src/pages/LoginPage.js b/src/pages/LoginPage.js
new file mode 100644
index 00000000..d70811e3
--- /dev/null
+++ b/src/pages/LoginPage.js
@@ -0,0 +1,68 @@
+import { handleRouting, isLoggedIn, router, user } from "../main";
+
+export function LoginPage() {
+ if (isLoggedIn()) {
+ router.navigateTo("/");
+ return;
+ }
+
+ const html = `
+
+
+ 항해플러스
+
+
+
+
+
+
+
+
+ `;
+ document.querySelector("#root").innerHTML = html;
+ handleRouting();
+ handleLogin();
+}
+
+function handleLogin() {
+ const loginForm = document.querySelector("#login-form");
+ if (loginForm) {
+ loginForm.addEventListener("submit", (e) => {
+ e.preventDefault();
+ const username = document.querySelector("#username").value;
+
+ user.set("username", username);
+ user.set("email", "");
+ user.set("bio", "");
+
+ if (isLoggedIn()) router.navigateTo("/profile");
+ });
+ }
+}
diff --git a/src/pages/NotFound.js b/src/pages/NotFound.js
new file mode 100644
index 00000000..5b3754c2
--- /dev/null
+++ b/src/pages/NotFound.js
@@ -0,0 +1,25 @@
+import { handleRouting } from "../main";
+
+export function NotFound() {
+ const html = `
+
+
항해플러스
+
404
+
페이지를 찾을 수 없습니다
+
+ 요청하신 페이지가 존재하지 않거나 이동되었을 수 있습니다.
+
+
+ 홈으로 돌아가기
+
+
+ `;
+ document.querySelector("#root").innerHTML = html;
+ handleRouting();
+}
diff --git a/src/pages/ProfilePage.js b/src/pages/ProfilePage.js
new file mode 100644
index 00000000..e1477774
--- /dev/null
+++ b/src/pages/ProfilePage.js
@@ -0,0 +1,106 @@
+import { Footer } from "../components/Footer";
+import { Header } from "../components/Header";
+import { Logout, handleRouting, isLoggedIn, router, user } from "../main";
+
+export function ProfilePage() {
+ if (!isLoggedIn()) {
+ router.navigateTo("/login", true);
+ return;
+ }
+
+ let html = `
+
+`;
+
+ document.querySelector(
+ "#root"
+ ).innerHTML = `
+
${Header()}${html}${Footer()}
+
`;
+
+ handleRouting();
+
+ const userName = user.preferences?.username;
+ const userIntro = user.preferences?.bio;
+ const email = user.preferences?.email;
+ const userNameInputEl = document.querySelector("#username");
+ const userIntroInputEl = document.querySelector("#bio");
+ const emailInputEl = document.querySelector("#email");
+
+ userNameInputEl.value = userName;
+ userIntroInputEl.value = userIntro;
+ emailInputEl.value = email;
+ handleProfileUpdate();
+ Logout();
+}
+
+function handleProfileUpdate() {
+ const profileForm = document.getElementById("profile-form");
+ const bioInput = document.getElementById("bio");
+ const usernameInput = document.getElementById("username");
+ const emailInput = document.getElementById("email");
+
+ if (profileForm) {
+ profileForm.addEventListener("submit", (e) => {
+ e.preventDefault();
+ user.set("username", usernameInput.value);
+ user.set("email", emailInput.value);
+ user.set("bio", bioInput.value);
+ alert("프로필이 업데이트 되었습니다");
+ });
+ }
+}