feat: 모바일 UX 대폭 개선 + PWA 구현 + 로그인 루프 수정
- 모바일 하단 네비: 메뉴 제거, 4개 핵심 기능(홈/TBM/작업보고/출근) SVG 아이콘 - 모바일 사이드바 스킵: 768px 이하에서 사이드바 미로드, 레이아웃 오프셋 해결 - 모바일 헤더: 햄버거 메뉴 숨김, 본문 margin/overflow 정리 - TBM 모바일: 풀스크린 모달, 저장 버튼 하단 고정, 터치 UX 개선 - PWA: manifest.json, sw.js(network-first), 앱 아이콘, iOS 메타태그, 킬스위치 - 로그인 무한루프 수정: 토큰 만료 검증, 쿠키 정리, loginPage 경로 수정 - 신고 메뉴 tkreport 리다이렉트: navbar + sidebar cross-system-link 적용 - TBM API: 작업장별 안전점검 체크리스트 조회 엔드포인트 추가 - 안전점검 체크리스트 관리 UI 개선 - tkuser: 이슈유형 관리 기능 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -491,28 +491,35 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 사이드바 컨테이너 생성 (없으면)
|
||||
let sidebarContainer = document.getElementById('sidebar-container');
|
||||
if (!sidebarContainer) {
|
||||
sidebarContainer = document.createElement('div');
|
||||
sidebarContainer.id = 'sidebar-container';
|
||||
document.body.prepend(sidebarContainer);
|
||||
console.log('📦 사이드바 컨테이너 생성됨');
|
||||
// 3. 네비바 로드 (모바일이면 사이드바 스킵)
|
||||
var isMobile = window.innerWidth <= 768;
|
||||
|
||||
if (!isMobile) {
|
||||
// 데스크톱: 사이드바 컨테이너 생성 및 로드
|
||||
let sidebarContainer = document.getElementById('sidebar-container');
|
||||
if (!sidebarContainer) {
|
||||
sidebarContainer = document.createElement('div');
|
||||
sidebarContainer.id = 'sidebar-container';
|
||||
document.body.prepend(sidebarContainer);
|
||||
}
|
||||
|
||||
console.log('📥 컴포넌트 로딩 시작 (데스크톱: 네비바+사이드바)');
|
||||
await Promise.all([
|
||||
loadComponent('navbar', '#navbar-container', (doc) => processNavbar(doc, currentUser, accessiblePageKeys)),
|
||||
loadComponent('sidebar-nav', '#sidebar-container', (doc) => processSidebar(doc, currentUser, accessiblePageKeys))
|
||||
]);
|
||||
|
||||
setupNavbarEvents();
|
||||
setupSidebarEvents();
|
||||
document.body.classList.add('has-sidebar');
|
||||
} else {
|
||||
// 모바일: 네비바만 로드, 사이드바 없음
|
||||
console.log('📥 컴포넌트 로딩 시작 (모바일: 네비바만)');
|
||||
await loadComponent('navbar', '#navbar-container', (doc) => processNavbar(doc, currentUser, accessiblePageKeys));
|
||||
setupNavbarEvents();
|
||||
}
|
||||
|
||||
// 4. 네비바와 사이드바 동시 로드
|
||||
console.log('📥 컴포넌트 로딩 시작');
|
||||
await Promise.all([
|
||||
loadComponent('navbar', '#navbar-container', (doc) => processNavbar(doc, currentUser, accessiblePageKeys)),
|
||||
loadComponent('sidebar-nav', '#sidebar-container', (doc) => processSidebar(doc, currentUser, accessiblePageKeys))
|
||||
]);
|
||||
console.log('✅ 컴포넌트 로딩 완료');
|
||||
|
||||
// 5. 이벤트 설정
|
||||
setupNavbarEvents();
|
||||
setupSidebarEvents();
|
||||
document.body.classList.add('has-sidebar');
|
||||
|
||||
// 6. 페이지 전환 로딩 인디케이터 설정
|
||||
setupPageTransitionLoader();
|
||||
|
||||
@@ -527,9 +534,69 @@
|
||||
setTimeout(loadNotifications, 200);
|
||||
setInterval(loadNotifications, 30000);
|
||||
|
||||
// 10. PWA 설정 (manifest + 서비스 워커 + iOS 메타태그)
|
||||
setupPWA();
|
||||
|
||||
console.log('✅ app-init 완료');
|
||||
}
|
||||
|
||||
// ===== PWA 설정 =====
|
||||
function setupPWA() {
|
||||
// manifest.json 동적 추가
|
||||
if (!document.querySelector('link[rel="manifest"]')) {
|
||||
var manifest = document.createElement('link');
|
||||
manifest.rel = 'manifest';
|
||||
manifest.href = '/manifest.json';
|
||||
document.head.appendChild(manifest);
|
||||
}
|
||||
|
||||
// iOS 홈 화면 앱 메타태그
|
||||
if (!document.querySelector('meta[name="apple-mobile-web-app-capable"]')) {
|
||||
var metaTags = [
|
||||
{ name: 'apple-mobile-web-app-capable', content: 'yes' },
|
||||
{ name: 'apple-mobile-web-app-status-bar-style', content: 'default' },
|
||||
{ name: 'apple-mobile-web-app-title', content: 'TK공장' },
|
||||
{ name: 'theme-color', content: '#1e40af' }
|
||||
];
|
||||
metaTags.forEach(function(tag) {
|
||||
var meta = document.createElement('meta');
|
||||
meta.name = tag.name;
|
||||
meta.content = tag.content;
|
||||
document.head.appendChild(meta);
|
||||
});
|
||||
|
||||
// iOS 아이콘
|
||||
var appleIcon = document.createElement('link');
|
||||
appleIcon.rel = 'apple-touch-icon';
|
||||
appleIcon.href = '/img/icon-192x192.png';
|
||||
document.head.appendChild(appleIcon);
|
||||
}
|
||||
|
||||
// 서비스 워커 등록 (킬스위치 포함)
|
||||
if ('serviceWorker' in navigator) {
|
||||
// 킬스위치: ?sw-kill 파라미터로 서비스 워커 해제
|
||||
if (window.location.search.includes('sw-kill')) {
|
||||
navigator.serviceWorker.getRegistrations().then(function(regs) {
|
||||
regs.forEach(function(r) { r.unregister(); });
|
||||
caches.keys().then(function(keys) {
|
||||
keys.forEach(function(k) { caches.delete(k); });
|
||||
});
|
||||
console.log('SW 해제 완료');
|
||||
window.location.replace(window.location.pathname);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.serviceWorker.register('/sw.js')
|
||||
.then(function(reg) {
|
||||
console.log('SW 등록 완료');
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.warn('SW 등록 실패:', err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 페이지 전환 로딩 인디케이터 =====
|
||||
function setupPageTransitionLoader() {
|
||||
// 로딩 바 스타일 추가
|
||||
|
||||
Reference in New Issue
Block a user