feat: show three recent updates on the homepage
Publish GitHub Pages output / publish (push) Successful in 42s

This commit is contained in:
2026-09-02 12:33:15 +09:00
parent 1e3d1d0b08
commit ed21888eaf
3 changed files with 46 additions and 2 deletions
+15 -1
View File
@@ -1,8 +1,9 @@
<script lang="ts"> <script lang="ts">
import updateHistoryMarkdown from '../../../UPDATES.md?raw'; import updateHistoryMarkdown from '../../../UPDATES.md?raw';
import { parseUpdateHistoryDocument } from '$lib/update-history-document.ts'; import { parseUpdateHistoryDocument, recentUpdateEntries } from '$lib/update-history-document.ts';
const updateHistoryDocument = parseUpdateHistoryDocument(updateHistoryMarkdown); const updateHistoryDocument = parseUpdateHistoryDocument(updateHistoryMarkdown);
const recentUpdates = recentUpdateEntries(updateHistoryDocument.body);
function updatedDateTime(value: string | null): string { function updatedDateTime(value: string | null): string {
if (!value) return '시각 미등록'; if (!value) return '시각 미등록';
@@ -29,6 +30,13 @@
<a class="action" href="/updates">업데이트 내역 확인 <span aria-hidden="true">→</span></a> <a class="action" href="/updates">업데이트 내역 확인 <span aria-hidden="true">→</span></a>
</div> </div>
{#if recentUpdates.length > 0}
<ul class="recent-updates" aria-label="최신 업데이트 3개">
{#each recentUpdates as update}
<li><span class="update-title">{update.title}</span><span class="update-date">{update.date}</span></li>
{/each}
</ul>
{/if}
</aside> </aside>
<style> <style>
@@ -41,9 +49,15 @@
.action span { margin-left: 4px; } .action span { margin-left: 4px; }
.action:hover { color: #ffd0e2; } .action:hover { color: #ffd0e2; }
.action:focus-visible { outline: 3px solid rgb(239 139 182 / 28%); outline-offset: 3px; } .action:focus-visible { outline: 3px solid rgb(239 139 182 / 28%); outline-offset: 3px; }
.recent-updates { display: grid; gap: 9px; margin: 0 18px; padding: 13px 0 16px; border-top: 1px solid #2c3440; list-style: none; }
.recent-updates li { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; font-size: 14px; line-height: 1.5; }
.update-title { min-width: 0; color: #cbd2dc; overflow-wrap: anywhere; }
.update-date { flex: 0 0 auto; color: #7f8998; font-size: 12px; }
@media (max-width: 680px) { @media (max-width: 680px) {
.notice-header { align-items: flex-start; flex-direction: column; gap: 8px; } .notice-header { align-items: flex-start; flex-direction: column; gap: 8px; }
.version-summary { align-items: flex-start; flex-wrap: wrap; } .version-summary { align-items: flex-start; flex-wrap: wrap; }
.recent-updates li { gap: 10px; font-size: 13px; }
.update-date { font-size: 11px; }
} }
</style> </style>
+18 -1
View File
@@ -1,6 +1,6 @@
import assert from 'node:assert/strict'; import assert from 'node:assert/strict';
import test from 'node:test'; import test from 'node:test';
import { parseUpdateHistoryDocument } from '../update-history-document.ts'; import { parseUpdateHistoryDocument, recentUpdateEntries } from '../update-history-document.ts';
test('업데이트 Markdown의 최근 업데이트 시각을 본문과 분리한다', () => { test('업데이트 Markdown의 최근 업데이트 시각을 본문과 분리한다', () => {
const document = parseUpdateHistoryDocument('---\nupdatedAt: 2026-08-31T14:15:17+09:00\n---\n\n## 업데이트'); const document = parseUpdateHistoryDocument('---\nupdatedAt: 2026-08-31T14:15:17+09:00\n---\n\n## 업데이트');
@@ -13,3 +13,20 @@ test('메타데이터가 없는 Markdown도 그대로 표시한다', () => {
const markdown = '## 업데이트'; const markdown = '## 업데이트';
assert.deepEqual(parseUpdateHistoryDocument(markdown), { updatedAt: null, body: markdown }); assert.deepEqual(parseUpdateHistoryDocument(markdown), { updatedAt: null, body: markdown });
}); });
test('최근 업데이트 3개를 날짜 경계를 넘어 문서 순서대로 가져온다', () => {
const body = '## 2026년 9월 2일\r\n\r\n### 첫 업데이트\r\n설명\r\n### 다음 업데이트\r\n\r\n---\r\n## 2026년 9월 1일\r\n### 이전 업데이트\r\n### 네 번째 업데이트';
assert.deepEqual(recentUpdateEntries(body), [
{ date: '2026년 9월 2일', title: '첫 업데이트' },
{ date: '2026년 9월 2일', title: '다음 업데이트' },
{ date: '2026년 9월 1일', title: '이전 업데이트' }
]);
});
test('업데이트가 부족하거나 없으면 있는 항목만 표시한다', () => {
assert.deepEqual(recentUpdateEntries('### 날짜 없는 제목'), []);
assert.deepEqual(recentUpdateEntries(''), []);
assert.deepEqual(recentUpdateEntries('## 2026년 9월 2일\n### 한 항목'), [
{ date: '2026년 9월 2일', title: '한 항목' }
]);
});
+13
View File
@@ -3,6 +3,19 @@ export type UpdateHistoryDocument = {
body: string; body: string;
}; };
export function recentUpdateEntries(body: string, limit = 3): { date: string; title: string }[] {
const entries: { date: string; title: string }[] = [];
let date = '';
for (const line of body.split(/\r?\n/)) {
if (entries.length >= limit) break;
const dateHeading = line.match(/^##\s+(\d{4}년 \d{1,2}월 \d{1,2}일)\s*$/);
if (dateHeading) date = dateHeading[1];
const titleHeading = line.match(/^###\s+(.+?)\s*$/);
if (date && titleHeading) entries.push({ date, title: titleHeading[1] });
}
return entries;
}
export function parseUpdateHistoryDocument(markdown: string): UpdateHistoryDocument { export function parseUpdateHistoryDocument(markdown: string): UpdateHistoryDocument {
const frontmatter = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/); const frontmatter = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
if (!frontmatter) return { updatedAt: null, body: markdown }; if (!frontmatter) return { updatedAt: null, body: markdown };