v4.0.0: 덱 UX·i18n·썸네일 저장 개선 및 413 수정
즐겨찾기·홀드 미리보기·페이지 도움말·3개국어 번역을 추가하고, 덱 저장 시 썸네일을 1200px로 통일하며 Nginx/API 업로드 제한을 상향했다. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -11,6 +11,18 @@
|
||||
let currentUser = null;
|
||||
let dropdownOpen = false;
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {string} fallback
|
||||
* @returns {string}
|
||||
*/
|
||||
function t(key, fallback) {
|
||||
if (window.UaPageI18n?.t) {
|
||||
return window.UaPageI18n.t(key, fallback);
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML 이스케이프
|
||||
* @param {string} str
|
||||
@@ -51,6 +63,16 @@
|
||||
return src;
|
||||
}
|
||||
|
||||
/**
|
||||
* 표시용 닉네임
|
||||
* @param {object|null} user
|
||||
* @returns {string}
|
||||
*/
|
||||
function getDisplayName(user) {
|
||||
if (!user) return '';
|
||||
return String(user.username || user.displayName || '').trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* 아바타 HTML
|
||||
* @param {object|null} user
|
||||
@@ -62,18 +84,19 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* 프로필 버튼 HTML (아바타 + 사용자명)
|
||||
* 프로필 버튼 HTML (아바타 + 닉네임)
|
||||
* @param {object|null} user
|
||||
* @returns {string}
|
||||
*/
|
||||
function profileBtnHtml(user) {
|
||||
const name = getDisplayName(user);
|
||||
const avatar = avatarHtml(user);
|
||||
if (!user?.username) {
|
||||
return `<span class="auth-avatar-wrap">${avatar}</span>`;
|
||||
if (!name) {
|
||||
return `<span class="auth-avatar-circle">${avatar}</span>`;
|
||||
}
|
||||
return `
|
||||
<span class="auth-avatar-wrap">${avatar}</span>
|
||||
<span class="auth-username">${escapeHtml(user.username)}</span>
|
||||
<span class="auth-avatar-circle">${avatar}</span>
|
||||
<span class="auth-username">${escapeHtml(name)}</span>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -86,28 +109,28 @@
|
||||
|
||||
if (!currentUser) {
|
||||
dd.innerHTML = `
|
||||
<a href="/login.html" class="auth-dropdown-item">로그인</a>
|
||||
<a href="/signup.html" class="auth-dropdown-item">회원가입</a>
|
||||
<a href="/login.html" class="auth-dropdown-item">${escapeHtml(t('authLogin', '로그인'))}</a>
|
||||
<a href="/signup.html" class="auth-dropdown-item">${escapeHtml(t('authSignup', '회원가입'))}</a>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
const adminLink =
|
||||
currentUser.role === 'admin'
|
||||
? `<a href="/admin.html" class="auth-dropdown-item">관리자</a>`
|
||||
? `<a href="/admin.html" class="auth-dropdown-item">${escapeHtml(t('authAdmin', '관리자'))}</a>`
|
||||
: '';
|
||||
|
||||
dd.innerHTML = `
|
||||
<div class="auth-dropdown-header">
|
||||
<div class="auth-dropdown-name">${currentUser.username}</div>
|
||||
<div class="auth-dropdown-email">${currentUser.email || ''}</div>
|
||||
<div class="auth-dropdown-name">${escapeHtml(getDisplayName(currentUser))}</div>
|
||||
<div class="auth-dropdown-email">${escapeHtml(currentUser.email || '')}</div>
|
||||
</div>
|
||||
<a href="/profile.html" class="auth-dropdown-item">내 프로필</a>
|
||||
<a href="/deckHistory.html" class="auth-dropdown-item">내 덱 관리</a>
|
||||
<a href="/preset.html" class="auth-dropdown-item">공개 덱</a>
|
||||
<a href="/profile.html" class="auth-dropdown-item">${escapeHtml(t('authMyProfile', '내 프로필'))}</a>
|
||||
<a href="/deckHistory.html" class="auth-dropdown-item">${escapeHtml(t('authMyDecks', '내 덱 관리'))}</a>
|
||||
<a href="/preset.html" class="auth-dropdown-item">${escapeHtml(t('authPublicDecks', '공개 덱'))}</a>
|
||||
${adminLink}
|
||||
<div class="auth-dropdown-divider"></div>
|
||||
<button type="button" class="auth-dropdown-item danger" id="auth-logout-btn">로그아웃</button>
|
||||
<button type="button" class="auth-dropdown-item danger" id="auth-logout-btn">${escapeHtml(t('authLogout', '로그아웃'))}</button>
|
||||
`;
|
||||
|
||||
const logoutBtn = document.getElementById('auth-logout-btn');
|
||||
@@ -127,8 +150,14 @@
|
||||
function renderHeader() {
|
||||
const btn = document.getElementById('auth-avatar-btn');
|
||||
if (btn) {
|
||||
const name = getDisplayName(currentUser);
|
||||
btn.innerHTML = profileBtnHtml(currentUser);
|
||||
btn.classList.toggle('auth-profile-btn--named', Boolean(currentUser?.username));
|
||||
btn.classList.toggle('auth-profile-trigger--named', Boolean(name));
|
||||
btn.classList.toggle('auth-profile-trigger--guest', !name);
|
||||
const menuLabel = name
|
||||
? t('authAccountMenuNamed', '{name} 계정 메뉴').replace('{name}', name)
|
||||
: t('authAccountMenu', '계정 메뉴');
|
||||
btn.setAttribute('aria-label', menuLabel);
|
||||
}
|
||||
renderDropdown();
|
||||
}
|
||||
@@ -140,7 +169,7 @@
|
||||
function mount(slot) {
|
||||
slot.innerHTML = `
|
||||
<div class="auth-header-wrap">
|
||||
<button type="button" id="auth-avatar-btn" class="auth-avatar-btn" aria-label="계정 메뉴">
|
||||
<button type="button" id="auth-avatar-btn" class="auth-profile-trigger auth-profile-trigger--guest" aria-label="${escapeHtml(t('authAccountMenu', '계정 메뉴'))}">
|
||||
${profileBtnHtml(currentUser)}
|
||||
</button>
|
||||
<div id="auth-dropdown" class="auth-dropdown"></div>
|
||||
@@ -185,6 +214,10 @@
|
||||
* 초기화
|
||||
*/
|
||||
async function init() {
|
||||
if (window.UaPageI18n?.applyPageI18n) {
|
||||
await window.UaPageI18n.applyPageI18n();
|
||||
}
|
||||
|
||||
currentUser = window.UaDeckApi.getCachedUser();
|
||||
await refreshCurrentUser();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user