diff --git a/src/components/common/footer.js b/src/components/common/footer.js new file mode 100644 index 00000000..bb1a2dff --- /dev/null +++ b/src/components/common/footer.js @@ -0,0 +1,5 @@ +const Footer = () => ``; + +export default Footer; diff --git a/src/components/common/header.js b/src/components/common/header.js new file mode 100644 index 00000000..35828c51 --- /dev/null +++ b/src/components/common/header.js @@ -0,0 +1,6 @@ +const Header = () => ` +
+

항해플러스

+
`; + +export default Header; diff --git a/src/components/common/nav.js b/src/components/common/nav.js new file mode 100644 index 00000000..d05d2a57 --- /dev/null +++ b/src/components/common/nav.js @@ -0,0 +1,41 @@ +import UserPreferences from "../../utils/userPreference"; + +const Nav = () => { + const pref = new UserPreferences(); + const updateNav = () => { + const username = pref.get("username"); + const currentPage = window.location.pathname; + console.log(username); + + const navEl = document.querySelector("nav"); + if (navEl) { + navEl.innerHTML = ` + + `; + } + }; + + window.addEventListener("userPreferencesChanged", updateNav); + + const username = pref.get("username"); + const isHashMode = window.location.pathname.endsWith("hash.html"); + const currentPage = isHashMode + ? window.location.hash.slice(1) || "/" + : window.location.pathname; + + return ` + + `; +}; + +export default Nav; diff --git a/src/main.js b/src/main.js index 036c2a38..1dffcc7a 100644 --- a/src/main.js +++ b/src/main.js @@ -1,241 +1,55 @@ -const MainPage = () => ` -
-
-
-

항해플러스

-
- - - -
-
- - -
- -
- -
-
- 프로필 -
-

홍길동

-

5분 전

-
-
-

오늘 날씨가 정말 좋네요. 다들 좋은 하루 보내세요!

-
- - - -
-
- -
-
- 프로필 -
-

김철수

-

15분 전

-
-
-

새로운 프로젝트를 시작했어요. 열심히 코딩 중입니다!

-
- - - -
-
- -
-
- 프로필 -
-

이영희

-

30분 전

-
-
-

오늘 점심 메뉴 추천 받습니다. 뭐가 좋을까요?

-
- - - -
-
- -
-
- 프로필 -
-

박민수

-

1시간 전

-
-
-

주말에 등산 가실 분 계신가요? 함께 가요!

-
- - - -
-
- -
-
- 프로필 -
-

정수연

-

2시간 전

-
-
-

새로 나온 영화 재미있대요. 같이 보러 갈 사람?

-
- - - -
-
-
-
- - -
-
-`; - -const ErrorPage = () => ` -
-
-

항해플러스

-

404

-

페이지를 찾을 수 없습니다

-

- 요청하신 페이지가 존재하지 않거나 이동되었을 수 있습니다. -

- - 홈으로 돌아가기 - -
-
-`; - -const LoginPage = () => ` -
-
-

항해플러스

-
-
- -
-
- -
- -
- -
-
- -
-
-
-`; - -const ProfilePage = () => ` -
-
-
-
-

항해플러스

-
- - - -
-
-

- 내 프로필 -

-
-
- - -
-
- - -
-
- - -
- -
-
-
- - -
-
-
-`; - -document.body.innerHTML = ` - ${MainPage()} - ${ProfilePage()} - ${LoginPage()} - ${ErrorPage()} -`; +import Router from "./routes/router.js"; +import UserPreferences from "./utils/userPreference.js"; +import MainPage from "./pages/mainPage.js"; +import ErrorPage from "./pages/errorPage.js"; +import LoginPage, { loginInit } from "./pages/loginPage.js"; +import ProfilePage from "./pages/profilePage.js"; + +const router = new Router(); +const prefs = new UserPreferences(); + +function init() { + router.addRoute("/", () => { + const mainPage = MainPage(); + mainPage.render(); + addNavListener(); + }); + router.addRoute("/profile", () => { + const profilePage = ProfilePage(); + profilePage.render(); + addNavListener(); + }); + router.addRoute("/login", () => { + const loginPage = LoginPage(); + loginPage.render(); + loginInit(); + }); + router.addRoute("/error", () => { + const errorPage = ErrorPage(); + errorPage.render(); + }); + + router.renderInit(); +} + +function addNavListener() { + const nav = document.querySelector("nav"); + if (nav) { + nav.addEventListener("click", (e) => { + e.preventDefault(); + if (e.target && e.target.pathname === "/login") { + prefs.remove(); + router.navigateTo(e.target.pathname); + } else if (e.target && e.target.pathname === "/profile") { + router.navigateTo(e.target.pathname); + } else if (e.target && e.target.pathname === "/") { + router.navigateTo(e.target.pathname); + } else { + return; + } + }); + } +} + +init(); +addNavListener(); diff --git a/src/pages/errorPage.js b/src/pages/errorPage.js new file mode 100644 index 00000000..af9a45ed --- /dev/null +++ b/src/pages/errorPage.js @@ -0,0 +1,27 @@ +const template = ` +
+
+

항해플러스

+

404

+

페이지를 찾을 수 없습니다

+

+ 요청하신 페이지가 존재하지 않거나 이동되었을 수 있습니다. +

+ + 홈으로 돌아가기 + +
+
+`; + +const ErrorPage = () => { + const render = () => { + document.getElementById("root").innerHTML = template; + }; + + return { + render, + }; +}; + +export default ErrorPage; diff --git a/src/pages/loginPage.js b/src/pages/loginPage.js new file mode 100644 index 00000000..d5a8f97a --- /dev/null +++ b/src/pages/loginPage.js @@ -0,0 +1,60 @@ +import UserPreferences from "../utils/userPreference.js"; +import Router from "../routes/router.js"; + +const template = ` +
+
+

항해플러스

+
+
+ +
+
+ +
+ +
+ +
+
+ +
+
+
+`; + +const LoginPage = () => { + const render = () => { + document.getElementById("root").innerHTML = template; + }; + + return { + render, + }; +}; + +export const loginInit = () => { + const prefs = new UserPreferences(); + const form = document.getElementById("login-form"); + const email = document.getElementById("username"); + const router = new Router(); + + form.addEventListener("submit", (e) => handleLogin(e)); + document + .getElementById("login-btn") + .addEventListener("click", (e) => handleLogin(e)); + + const handleLogin = (e) => { + e.preventDefault(); + if (email.value != "") { + prefs.set("username", email.value); + prefs.set("email", ""); + prefs.set("bio", ""); + router.navigateTo("/profile"); + } + }; +}; + +export default LoginPage; diff --git a/src/pages/mainPage.js b/src/pages/mainPage.js new file mode 100644 index 00000000..620e353f --- /dev/null +++ b/src/pages/mainPage.js @@ -0,0 +1,117 @@ +import Nav from "../components/common/nav.js"; +import Header from "../components/common/header.js"; +import Footer from "../components/common/footer.js"; + +const MainPage = () => { + const template = ` +
+
+ ${Header()} + + ${Nav()} + +
+
+ + +
+ +
+ +
+
+ 프로필 +
+

홍길동

+

5분 전

+
+
+

오늘 날씨가 정말 좋네요. 다들 좋은 하루 보내세요!

+
+ + + +
+
+ +
+
+ 프로필 +
+

김철수

+

15분 전

+
+
+

새로운 프로젝트를 시작했어요. 열심히 코딩 중입니다!

+
+ + + +
+
+ +
+
+ 프로필 +
+

이영희

+

30분 전

+
+
+

오늘 점심 메뉴 추천 받습니다. 뭐가 좋을까요?

+
+ + + +
+
+ +
+
+ 프로필 +
+

박민수

+

1시간 전

+
+
+

주말에 등산 가실 분 계신가요? 함께 가요!

+
+ + + +
+
+ +
+
+ 프로필 +
+

정수연

+

2시간 전

+
+
+

새로 나온 영화 재미있대요. 같이 보러 갈 사람?

+
+ + + +
+
+
+
+ + ${Footer()} +
+
+`; + + const render = () => { + document.getElementById("root").innerHTML = template; + }; + + return { + render, + }; +}; + +export default MainPage; diff --git a/src/pages/profilePage.js b/src/pages/profilePage.js new file mode 100644 index 00000000..8abfc03d --- /dev/null +++ b/src/pages/profilePage.js @@ -0,0 +1,116 @@ +import Nav from "../components/common/nav.js"; +import Header from "../components/common/header.js"; +import Footer from "../components/common/footer.js"; +import UserPreferences from "../utils/userPreference.js"; +import Router from "../routes/router.js"; + +const ProfilePage = () => { + const router = new Router(); + const prefs = new UserPreferences(); + const username = prefs.get("username"); + const email = prefs.get("email"); + const bio = prefs.get("bio"); + + function redirectHome() { + if (!username) { + router.navigateTo("/login"); + return true; + } + return false; + } + + const template = ` +
+
+ ${Header()} + + ${Nav()} + +
+
+

+ 내 프로필 +

+
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+ + ${Footer()} +
+
+`; + + const render = () => { + if (redirectHome()) return; + document.getElementById("root").innerHTML = template; + setup(); + }; + + const setup = () => { + const form = document.getElementById("profile-form"); + const inputEmail = document.getElementById("email"); + const inputBio = document.getElementById("bio"); + form.addEventListener("submit", (e) => { + e.preventDefault(); + prefs.set("email", inputEmail.value); + prefs.set("bio", inputBio.value); + + window.alert("프로필이 업데이트되었습니다."); + }); + }; + + return { + render, + }; +}; + +export default ProfilePage; diff --git a/src/routes/router.js b/src/routes/router.js new file mode 100644 index 00000000..2e4b3dea --- /dev/null +++ b/src/routes/router.js @@ -0,0 +1,74 @@ +import UserPreferences from "../utils/userPreference"; +export default class Router { + constructor() { + if (Router.instance) { + return Router.instance; + } + Router.instance = this; + this.routes = {}; + this.isHashMode = window.location.pathname.endsWith("hash.html"); + window.addEventListener("hashchange", this.handleHashChange.bind(this)); + window.addEventListener("popstate", this.handlePopState.bind(this)); + } + + addRoute(path, handler) { + this.routes[path] = handler; + } + + navigateTo(path) { + if (this.isHashMode) { + window.location.hash = path === "/" ? "" : path; + } else { + history.pushState(null, "", path); + this.handleRoute(path); + } + } + + handlePopState() { + const path = this.isHashMode + ? window.location.hash.slice(1) || "/" + : window.location.pathname; + this.handleRoute(path); + } + + handleHashChange() { + const path = window.location.hash.slice(1) || "/"; + this.handleRoute(path); + } + + handleRoute(path) { + const prefs = new UserPreferences(); + const username = prefs.get("username"); + + if (username && path === "/login") { + if (this.isHashMode) { + window.location.hash = "/"; + } else { + this.navigateTo("/"); + } + return; + } + + const handler = this.routes[path]; + if (handler) { + handler(); + } else { + const errorHandler = this.routes["/error"]; + if (errorHandler) errorHandler(); + } + } + + renderInit() { + if (this.isHashMode) { + const path = window.location.hash.slice(1) || "/"; + this.handleRoute(path); + } else { + const path = window.location.pathname; + if (["/", "/profile", "/login"].includes(path)) { + this.navigateTo(path); + } else { + this.navigateTo("/error"); + } + } + } +} diff --git a/src/utils/userPreference.js b/src/utils/userPreference.js new file mode 100644 index 00000000..6827ebcc --- /dev/null +++ b/src/utils/userPreference.js @@ -0,0 +1,25 @@ +export default class UserPreferences { + constructor() { + this.preferences = JSON.parse(localStorage.getItem("user")) || {}; + } + + set(key, value) { + this.preferences[key] = value; + this.save(); + window.dispatchEvent(new CustomEvent("userPreferencesChanged")); + } + + get(key) { + return this.preferences[key]; + } + + save() { + localStorage.setItem("user", JSON.stringify(this.preferences)); + } + + remove() { + this.preferences = {}; + localStorage.removeItem("user"); + window.dispatchEvent(new CustomEvent("userPreferencesChanged")); + } +} diff --git a/src/utils/utils.js b/src/utils/utils.js new file mode 100644 index 00000000..e98e5005 --- /dev/null +++ b/src/utils/utils.js @@ -0,0 +1 @@ +export default class Utils {}