- en/, ja/, zh/ 디렉토리 전체 삭제 - i18n/ 번역 JSON + js/i18n.js 삭제 - 전체 HTML에서 언어 스위처, hreflang 태그 제거 - common.css lang-switcher CSS 135줄 제거 - schedule.js 다국어 로직 제거 (한국어 직접 사용) - build-blog.js, devlog.js 한국어 전용으로 단순화 - sitemap.xml 한국어 URL만 유지 - build_i18n.js + package.json build:i18n 스크립트 제거 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
114 lines
4.4 KiB
JavaScript
114 lines
4.4 KiB
JavaScript
/**
|
|
* 밍글 스튜디오 DevLog 목록 페이지
|
|
* devlog/index.json에서 글 목록을 불러와 렌더링
|
|
*/
|
|
(function() {
|
|
'use strict';
|
|
|
|
var grid = document.getElementById('blogGrid');
|
|
var filtersWrap = document.getElementById('blogFilters');
|
|
var loadingEl = document.getElementById('blogLoading');
|
|
if (!grid) return;
|
|
|
|
var allPosts = [];
|
|
var currentFilter = 'all';
|
|
|
|
function init() {
|
|
fetch('/devlog/index.json?t=' + Date.now())
|
|
.then(function(res) { return res.json(); })
|
|
.then(function(posts) {
|
|
allPosts = posts;
|
|
if (loadingEl) loadingEl.style.display = 'none';
|
|
buildFilters();
|
|
renderPosts();
|
|
})
|
|
.catch(function() {
|
|
if (loadingEl) loadingEl.style.display = 'none';
|
|
grid.innerHTML = '<div class="blog-empty"><i class="fas fa-pen-fancy"></i><p>아직 작성된 글이 없습니다.</p></div>';
|
|
});
|
|
}
|
|
|
|
function buildFilters() {
|
|
if (!filtersWrap || allPosts.length === 0) return;
|
|
|
|
var categories = {};
|
|
allPosts.forEach(function(p) {
|
|
if (p.category) categories[p.category] = true;
|
|
});
|
|
|
|
var cats = Object.keys(categories).sort();
|
|
if (cats.length < 2) { filtersWrap.style.display = 'none'; return; }
|
|
|
|
var html = '<button class="blog-filter-btn active" data-cat="all">전체</button>';
|
|
cats.forEach(function(c) {
|
|
html += '<button class="blog-filter-btn" data-cat="' + c + '">' + c + '</button>';
|
|
});
|
|
filtersWrap.innerHTML = html;
|
|
|
|
filtersWrap.addEventListener('click', function(e) {
|
|
var btn = e.target.closest('.blog-filter-btn');
|
|
if (!btn) return;
|
|
filtersWrap.querySelectorAll('.blog-filter-btn').forEach(function(b) { b.classList.remove('active'); });
|
|
btn.classList.add('active');
|
|
currentFilter = btn.getAttribute('data-cat');
|
|
renderPosts();
|
|
});
|
|
}
|
|
|
|
function renderPosts() {
|
|
var filtered = currentFilter === 'all' ? allPosts : allPosts.filter(function(p) { return p.category === currentFilter; });
|
|
|
|
if (filtered.length === 0) {
|
|
grid.innerHTML = '<div class="blog-empty"><i class="fas fa-pen-fancy"></i><p>아직 작성된 글이 없습니다.</p></div>';
|
|
return;
|
|
}
|
|
|
|
var html = '';
|
|
filtered.forEach(function(post) {
|
|
var title = post.title || post.slug;
|
|
var desc = post.description || '';
|
|
var thumb = post.thumbnail ? '/blog/posts/' + post.slug + '/' + post.thumbnail : '';
|
|
var url = '/devlog/' + post.slug;
|
|
var date = formatDate(post.date);
|
|
|
|
html += '<article class="blog-card">';
|
|
html += '<a href="' + url + '">';
|
|
if (thumb) {
|
|
html += '<img class="blog-card-thumb" src="' + thumb + '" alt="' + escapeHtml(title) + '" loading="lazy">';
|
|
} else {
|
|
html += '<div class="blog-card-thumb-placeholder"><i class="fas fa-pen-fancy"></i></div>';
|
|
}
|
|
html += '</a>';
|
|
html += '<div class="blog-card-body">';
|
|
if (post.category) html += '<span class="blog-card-category">' + escapeHtml(post.category) + '</span>';
|
|
html += '<h2 class="blog-card-title"><a href="' + url + '" style="color:inherit;text-decoration:none">' + escapeHtml(title) + '</a></h2>';
|
|
html += '<p class="blog-card-desc">' + escapeHtml(desc) + '</p>';
|
|
html += '<div class="blog-card-footer">';
|
|
html += '<span class="blog-card-date"><i class="far fa-calendar-alt"></i> ' + date + '</span>';
|
|
html += '<a href="' + url + '" class="blog-card-link">자세히 보기 →</a>';
|
|
html += '</div></div></article>';
|
|
});
|
|
|
|
grid.innerHTML = html;
|
|
}
|
|
|
|
function formatDate(dateStr) {
|
|
if (!dateStr) return '';
|
|
var d = new Date(dateStr + 'T00:00:00');
|
|
if (isNaN(d)) return dateStr;
|
|
return d.getFullYear() + '.' + (d.getMonth() + 1) + '.' + d.getDate();
|
|
}
|
|
|
|
function escapeHtml(str) {
|
|
var div = document.createElement('div');
|
|
div.textContent = str;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', init);
|
|
} else {
|
|
init();
|
|
}
|
|
})();
|