fix: api/toast/timeAgo 함수를 body 스크립트보다 앞에 배치

스크립트 실행 순서: __INIT__ → 유틸함수 → 페이지 스크립트

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
chpark
2026-03-27 13:20:53 +09:00
parent d576cb5255
commit 2343c1903d
+17 -25
View File
@@ -116,48 +116,40 @@ tr:hover td{background:rgba(255,255,255,.02)}
</div> </div>
<div class="content"> <div class="content">
<%- typeof ssrData !== 'undefined' ? ssrData : '' %> <%- typeof ssrData !== 'undefined' ? ssrData : '' %>
<%- body %>
</div>
</div>
<div class="toast" id="toast"></div>
<script> <script>
function api(method, url, data) { function api(method, url, data) {
const opts = { method, headers: { 'Content-Type': 'application/json' }, credentials: 'same-origin' }; var opts = { method: method, headers: { 'Content-Type': 'application/json' }, credentials: 'same-origin' };
if (data) opts.body = JSON.stringify(data); if (data) opts.body = JSON.stringify(data);
return fetch(url, opts).then(r => { return fetch(url, opts).then(function(r) {
const ct = r.headers.get('content-type') || ''; var ct = r.headers.get('content-type') || '';
if (r.status === 401) { if (r.status === 401) { window.location.href = '/login?redirect=' + encodeURIComponent(window.location.pathname); return []; }
window.location.href = '/login?redirect=' + encodeURIComponent(window.location.pathname); if (!ct.includes('application/json')) { console.error('API non-JSON:', r.status); return []; }
return [];
}
if (!ct.includes('application/json')) {
console.error('API returned non-JSON:', r.status, ct);
return [];
}
return r.json(); return r.json();
}).catch(err => { }).catch(function(err) { console.error('API Error:', err); return []; });
console.error('API Error:', err);
return [];
});
} }
function toast(msg, type = 'success') { function toast(msg, type) {
const el = document.getElementById('toast'); type = type || 'success';
var el = document.getElementById('toast');
el.textContent = msg; el.textContent = msg;
el.style.borderLeftColor = type === 'success' ? 'var(--success)' : type === 'error' ? 'var(--danger)' : 'var(--warning)'; el.style.borderLeftColor = type === 'success' ? 'var(--success)' : type === 'error' ? 'var(--danger)' : 'var(--warning)';
el.style.borderLeftWidth = '3px'; el.style.borderLeftWidth = '3px';
el.classList.add('show'); el.classList.add('show');
setTimeout(() => el.classList.remove('show'), 3000); setTimeout(function() { el.classList.remove('show'); }, 3000);
} }
function timeAgo(dateStr) { function timeAgo(dateStr) {
if (!dateStr) return '-'; if (!dateStr) return '-';
const diff = Date.now() - new Date(dateStr).getTime(); var diff = Date.now() - new Date(dateStr).getTime();
const m = Math.floor(diff / 60000); var m = Math.floor(diff / 60000);
if (m < 1) return '방금'; if (m < 1) return '방금';
if (m < 60) return m + '분 전'; if (m < 60) return m + '분 전';
const h = Math.floor(m / 60); var h = Math.floor(m / 60);
if (h < 24) return h + '시간 전'; if (h < 24) return h + '시간 전';
return Math.floor(h / 24) + '일 전'; return Math.floor(h / 24) + '일 전';
} }
</script> </script>
<%- body %>
</div>
</div>
<div class="toast" id="toast"></div>
</body> </body>
</html> </html>