@@ -28,7 +58,7 @@ export class FriendsList extends Component {
-
Add
+
${translations.addText}
@@ -54,12 +84,12 @@ export class FriendsList extends Component {
this.friends = data; // 응답에서 friends list 꺼내기
// 친구 목록에서 닉네임 리스트를 추출합니다.
- const friendNicknameList = this.friends.map(friend => `${friend.nickname}#${friend.user_id}`);
-
+ const friendNicknameList = this.friends.map(friend => `${friend.nickname}`);
+ const friendIdList = this.friends.map(friend => `${friend.user_id}`);
// 친구 닉네임 리스트를 이용해 친구 목록 생성
const ulElement = document.querySelector("ul#friendsLists");
this.children.push(new List(ulElement,
- { className: "fList", contents: friendNicknameList }));
+ { className: "fList", ids: friendIdList, contents: friendNicknameList }));
})
.catch(error => {
console.error('Fetch operation failed:', error);
@@ -77,13 +107,12 @@ export class FriendsList extends Component {
this.children.splice(index, 1);
}
}
-
- const part = event.target.id.split('#');
- const uid = parseInt(part[1]);
+
+ const uid = parseInt(event.target.id);
const friend = this.friends.find(user => user.user_id === uid);
-
// 새로운 FriendsInfo 인스턴스를 생성하고, this.children에 추가
- this.info = new FriendsInfo(ulElement, {is_online: friend.is_online, nickname: `${friend.nickname}#${friend.user_id}`, img_url: friend.img_url});
+ this.info = new FriendsInfo(ulElement, {is_online: friend.is_online, nickname: `${friend.nickname}#${friend.user_id}`,
+ img_url: friend.img_url, profileText: this.translations.profileText, removeText: this.translations.removeText});
this.children.push(this.info);
});
@@ -104,7 +133,7 @@ export class FriendsList extends Component {
const index = this.children.indexOf(this.search);
if (index !== -1) this.children.splice(index, 1);
}
- this.search = new Input(ulElement, {inputId: "searchInput", imageId: "addInputImage", img: "/img/plus.jpeg"});
+ this.search = new Input(ulElement, {inputId: "searchInput", imageId: "addInputImage", img: "/img/plus.jpeg", searchText: this.translations.searchText});
this.children.push(this.search);
});
diff --git a/frontend/src/components/Friends.js b/frontend/src/components/Friends.js
index 9ae4280..088de2c 100644
--- a/frontend/src/components/Friends.js
+++ b/frontend/src/components/Friends.js
@@ -4,6 +4,6 @@ import { FriendsList } from "./Friends-List.js";
export class Friends extends Default {
mounted(){
- new FriendsList(document.querySelector("div#contents"));
+ new FriendsList(document.querySelector("div#contents"), this.props);
}
}
diff --git a/frontend/src/components/Home.js b/frontend/src/components/Home.js
index eb0d068..4f5f2ff 100644
--- a/frontend/src/components/Home.js
+++ b/frontend/src/components/Home.js
@@ -4,6 +4,6 @@ import { Login } from "./Home-Login.js";
export class Home extends Default {
mounted(){
- new Login(document.querySelector("div#contents"));
+ new Login(document.querySelector("div#contents"), this.props);
}
}
diff --git a/frontend/src/components/Input.js b/frontend/src/components/Input.js
index 79a7168..49c4b03 100644
--- a/frontend/src/components/Input.js
+++ b/frontend/src/components/Input.js
@@ -3,9 +3,10 @@ import { Component } from "../core/Component.js";
export class Input extends Component {
template () {
+ console.log(this.props.searchText);
return `
diff --git a/frontend/src/components/List.js b/frontend/src/components/List.js
index 6f63efb..def1ad6 100644
--- a/frontend/src/components/List.js
+++ b/frontend/src/components/List.js
@@ -3,12 +3,12 @@ import { Component } from "../core/Component.js";
export class List extends Component {
template () {
- const { className, contents } = this.props;
+ const { className, ids, contents } = this.props;
return `
- ${contents.map(element => {
+ ${contents.map((element, index) => {
const part = element.split('#');
const nickname = part[0];
- return `
${nickname}`
+ return `
${nickname}`
}).join('')}
`;
}
diff --git a/frontend/src/components/Main-Menu.js b/frontend/src/components/Main-Menu.js
index 6630346..5d68a49 100644
--- a/frontend/src/components/Main-Menu.js
+++ b/frontend/src/components/Main-Menu.js
@@ -5,22 +5,48 @@ import { parseJWT } from "../core/jwt.js";
export class Menu extends Component {
+ translate() {
+ const languages = {
+ 0: {
+ gameMenuTexts: ["Local Game", "Multi Game", "AI", "Tournament"],
+ userMenuTexts: ["Friends", "Profile", "Logout"],
+ lanText: "Change Language"
+ },
+ 1: {
+ gameMenuTexts: ["로컬 게임", "멀티 게임", "AI", "토너먼트"],
+ userMenuTexts: ["친구", "프로필", "로그아웃"],
+ lanText: "언어 변경"
+ },
+ 2: {
+ gameMenuTexts: ["ローカルゲーム", "マルチゲーム", "AI", "トーナメント"],
+ userMenuTexts: ["友達", "プロフィール", "ログアウト"],
+ lanText: "言語を変更"
+ }
+ };
+
+ this.translations = languages[this.props.lan.value];
+
+ }
+
template () {
const payload = parseJWT();
if (!payload) this.uid = null;
else this.uid = payload.id;
+ const translations = this.translations;
+
return `
`;
}
mounted(){
- new List(document.querySelector("ul#gameMenu"), { className: "gameMode", contents: ["Local Game", "Multi Game", "AI", "Tournament"]});
- new List(document.querySelector("ul#userMenu"), { className: "showInfo", contents: ["Friends", "Profile", "Logout"]});
+ new List(document.querySelector("ul#gameMenu"), { className: "gameMode", ids: ["Local Game", "Multi Game", "AI", "Tournament"], contents: this.translations.gameMenuTexts});
+ new List(document.querySelector("ul#userMenu"), { className: "showInfo", ids: ["Friends", "Profile", "Logout"], contents: this.translations.userMenuTexts});
}
setEvent () {
@@ -28,6 +54,11 @@ export class Menu extends Component {
changeUrl("/main/friends");
});
+ this.addEvent('click', '#lanButton', () => {
+ this.props.lan.value = (this.props.lan.value + 1) % 3;
+ changeUrl("/main")
+ });
+
this.addEvent('click', '#Profile', () => {
if (this.uid) changeUrl(`/main/profile/${this.uid}`);
else changeUrl("/");
diff --git a/frontend/src/components/Main.js b/frontend/src/components/Main.js
index 32656df..d09f491 100644
--- a/frontend/src/components/Main.js
+++ b/frontend/src/components/Main.js
@@ -3,6 +3,7 @@ import { Menu } from "./Main-Menu.js";
export class Main extends Default {
mounted(){
- new Menu(document.querySelector("div#contents"));
+ new Menu(document.querySelector("div#contents"), this.props);
+ console.log(this.props.lan.value);
}
}
\ No newline at end of file
diff --git a/frontend/src/components/Profile-Info.js b/frontend/src/components/Profile-Info.js
index ade47f3..cb3ef78 100644
--- a/frontend/src/components/Profile-Info.js
+++ b/frontend/src/components/Profile-Info.js
@@ -4,8 +4,36 @@ import { MatchList } from "./Profile-List.js";
import { parseJWT } from "../core/jwt.js";
export class ProfileInfo extends Component {
-
+
+ translate() {
+ const languages = {
+ 0: {
+ headText: "Profile",
+ winText: "Win",
+ loseText: "Lose",
+ minText: "min",
+ editText: "edit"
+ },
+ 1: {
+ headText: "프로필",
+ winText: "승리",
+ loseText: "패배",
+ minText: "분",
+ editText: "수정"
+ },
+ 2: {
+ headText: "プロフィール",
+ winText: "勝ち",
+ loseText: "負け",
+ minText: "分",
+ editText: "編集"
+ }
+ };
+ this.translations = languages[this.props.lan.value];
+ }
+
initState() {
+ console.log(this.props.lan.value);
const payload = parseJWT();
if (!payload) this.uid = null;
else this.uid = payload.id;
@@ -35,17 +63,18 @@ export class ProfileInfo extends Component {
}
template () {
+ const translations = this.translations;
return `
- ${parseInt(this.props.uid) === this.uid ? `
edit
` : ""}
+ ${parseInt(this.props.uid) === this.uid ? `
${translations.editText}
` : ""}
${this.state.user.nickname}
@@ -66,14 +95,13 @@ export class ProfileInfo extends Component {
- Win ${this.state.user.win}
- Lose ${this.state.user.lose}
+ ${translations.winText} ${this.state.user.win}
+ ${translations.loseText} ${this.state.user.lose}
(${this.state.rate}%)
@@ -86,7 +114,7 @@ export class ProfileInfo extends Component {
}
mounted() {
- new MatchList(document.querySelector("ul#matches"), {matches: this.state.games});
+ new MatchList(document.querySelector("ul#matches"), { matches: this.state.games, minText: this.translations.minText });
this.drawBackgroundCircle();
this.drawProgressCircle();
this.updatePercentage();
diff --git a/frontend/src/components/Profile-List.js b/frontend/src/components/Profile-List.js
index cf2051b..ad11a7e 100644
--- a/frontend/src/components/Profile-List.js
+++ b/frontend/src/components/Profile-List.js
@@ -7,12 +7,21 @@ export class MatchList extends Component {
if (!matches) return "";
return `
${matches.map(element => {
+ // Date 객체로 변환
+ const date = new Date(element.start_timestamp);
+
+ // 월, 일, 시, 분 추출
+ const month = date.getMonth() + 1; // getMonth()는 0부터 시작하므로 1을 더해줍니다.
+ const day = date.getDate();
+ const hours = date.getHours();
+ const minutes = date.getMinutes();
+
return `
Date
-
${element.start_timestamp}
-
${element.playtime}min
+
${month}/${day} ${hours}:${minutes}
+
${element.playtime}${this.props.minText}
VS
diff --git a/frontend/src/core/Component.js b/frontend/src/core/Component.js
index 124c29b..74af623 100644
--- a/frontend/src/core/Component.js
+++ b/frontend/src/core/Component.js
@@ -2,7 +2,7 @@ import { observable, observe } from './observer.js';
export class Component {
- state; props; $el; children;
+ state; props; $el; children; translations;
constructor ($el, props) {
this.$el = $el;
@@ -13,6 +13,7 @@ export class Component {
}
setup() {
+ this.translate();
this.state = observable(this.initState());
observe(() => {
this.render();
@@ -25,6 +26,7 @@ export class Component {
template () { return ''; }
render () { this.$el.innerHTML = this.template(); }
setEvent () {}
+ translate() {}
mounted () {}
addEvent (eventType, selector, callback) {
diff --git a/frontend/src/core/router.js b/frontend/src/core/router.js
index 9af46c9..e86e527 100644
--- a/frontend/src/core/router.js
+++ b/frontend/src/core/router.js
@@ -1,36 +1,32 @@
import { Home } from "../components/Home.js";
-import { root } from "../app.js";
+import { root, routes } from "../app.js";
import { Main } from "../components/Main.js";
import { Friends } from "../components/Friends.js";
import { Profile } from "../components/Profile.js";
import { TwoFA } from "../components/2FA.js";
import { Edit } from "../components/Edit.js";
-export const routes = {
- "/": {
- component: () => new Home(root.app),
- props: {}
- },
- "/main": {
- component: () => new Main(root.app),
- props: {}
- },
- "/main/friends": {
- component: () => new Friends(root.app),
- props: {}
- },
- "/main/profile/:uid": {
- component: (props) => new Profile(root.app, props),
- props: { uid: "" }
- },
- "/2FA": {
- component: () => new TwoFA(root.app),
- props: {}
- },
- "/main/profile/:uid/edit": {
- component: (props) => new Edit(root.app, props),
- props: { uid: "" }
- }
+export const createRoutes = (root) => {
+ return {
+ "/": {
+ component: (props) => new Home(root.app, props),
+ },
+ "/main": {
+ component: (props) => new Main(root.app, props),
+ },
+ "/main/friends": {
+ component: (props) => new Friends(root.app, props),
+ },
+ "/main/profile/:uid": {
+ component: (props) => new Profile(root.app, props),
+ },
+ "/2FA": {
+ component: (props) => new TwoFA(root.app, props),
+ },
+ "/main/profile/:uid/edit": {
+ component: (props) => new Edit(root.app, props),
+ }
+ };
};
export const changeUrl = async (requestedUrl, usePushState = true) => {
@@ -107,12 +103,13 @@ export async function parsePath(path) {
const regex = new RegExp('^' + key.replace(/:\w+/g, '([\\w-]+)') + '$');
const match = path.match(regex);
if (match) {
- const props = { ...route.props };
+ const props = { lan: root.lan, ...route.props };
const values = match.slice(1);
const keys = key.match(/:\w+/g) || [];
keys.forEach((key, index) => {
props[key.substring(1)] = values[index];
});
+ console.log(props);
route.component(props);
return;
}
diff --git a/frontend/style.css b/frontend/style.css
index 40cce66..5c3e957 100644
--- a/frontend/style.css
+++ b/frontend/style.css
@@ -165,6 +165,7 @@ p#login:hover {
div#menuBox {
+ position: relative;
width: 100%;
height: 100%;
display: flex;
@@ -173,6 +174,31 @@ div#menuBox {
justify-content: center;
}
+div#lanButton {
+ position: absolute;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-weight: 400;
+ border-radius: 10px;
+ width: 160px;
+ height: 50px;
+ bottom: 30px;
+ right: 30px;
+ font-size: 17px;
+ border-radius: 50px;
+ color: white;
+ cursor: pointer;
+ background: #357ABD;
+ box-shadow: 0 0 0 rgba(0, 0, 0, 0); /* 기본 상태에서 그림자 없음 */
+ transition: box-shadow 0.3s ease, transform 0.3s ease;
+}
+
+div#lanButton:hover {
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); /* 호버 시 더 깊은 그림자 */
+ transform: translateY(-2px); /* 살짝 위로 이동 */
+}
+
ul#gameMenu{
width: 100%;
height: 50%;
@@ -188,7 +214,7 @@ ul#gameMenu{
li.gameMode{
margin-left: 1%;
margin-right: 1%;
- width: 250px;
+ width: 280px;
height: 230px;
font-size: 2.7rem;
border-radius: 50px;
@@ -224,10 +250,10 @@ ul#userMenu{
li.showInfo{
margin-left: 1%;
margin-right: 1%;
- width: 120px;
- height: 120px;
+ width: 160px;
+ height: 150px;
border-radius: 50%;
- font-size: 2rem;
+ font-size: 1.8rem;
color: #31363F;
cursor: pointer;
text-align: center;
@@ -628,7 +654,7 @@ div#profileHeaderBox {
font-weight: 900;
color:#31363F;
font-size: 3.0rem;
- width: 200px;
+ width: 300px;
height: 100%;
text-align: center;
display: flex;
@@ -872,21 +898,20 @@ span#date {
}
div#startTime {
- width: 60%;
- height: 40%;
+ width: 80%;
+ height: 45%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
padding-bottom: 5px;
- font-size: 18px;
+ font-size: 16px;
color:#31363F;
font-weight: 700;
- border-bottom: 0.5px solid #31363F;
}
div#playTime {
- width: 100%;
+ width: 60%;
height: 40%;
display: flex;
flex-direction: column;
@@ -895,6 +920,7 @@ div#playTime {
color:#656262;
padding-top: 5px;
font-weight: 700;
+ border-top: 0.5px solid #31363F;
}