feat: apply feedback updates and streamline online delivery
Publish GitHub Pages output / publish (push) Successful in 34s
Publish GitHub Pages output / publish (push) Successful in 34s
This commit is contained in:
@@ -1,23 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { dev } from '$app/environment';
|
||||
import updateHistoryMarkdown from '../../../UPDATES.md?raw';
|
||||
import { renderReleaseMarkdown } from '$lib/release-notes/markdown';
|
||||
import { currentAppVersion, releaseNotes } from '$lib/release-notes/release-note-store';
|
||||
import { versionTagIsNewer } from '$lib/release-notes/version';
|
||||
import { parseUpdateHistoryDocument } from '$lib/update-history-document.ts';
|
||||
|
||||
let previewUpdate = false;
|
||||
const updateHistoryDocument = parseUpdateHistoryDocument(updateHistoryMarkdown);
|
||||
|
||||
onMount(() => {
|
||||
previewUpdate = dev && new URLSearchParams(window.location.search).get('previewUpdate') === '1';
|
||||
void releaseNotes.load();
|
||||
});
|
||||
|
||||
$: latestRelease = $releaseNotes.releases[0] ?? null;
|
||||
$: updateAvailable = latestRelease !== null && (previewUpdate || versionTagIsNewer(latestRelease.tagName, currentAppVersion));
|
||||
|
||||
function updatedDateTime(value: string | null): string {
|
||||
if (!value) return '시각 미등록';
|
||||
const date = new Date(value);
|
||||
@@ -32,91 +18,32 @@
|
||||
}).format(date);
|
||||
}
|
||||
|
||||
function publishedDate(value: string): string {
|
||||
const date = new Date(value);
|
||||
if (Number.isNaN(date.getTime())) return value;
|
||||
return new Intl.DateTimeFormat('ko-KR', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
}).format(date);
|
||||
}
|
||||
</script>
|
||||
|
||||
<aside class:available={updateAvailable} class="update-notice" aria-live="polite">
|
||||
<aside class="update-notice" aria-live="polite">
|
||||
<div class="notice-header">
|
||||
<div class="version-summary">
|
||||
<span class="label">최근 업데이트</span>
|
||||
<strong><time datetime={updateHistoryDocument.updatedAt ?? undefined}>{updatedDateTime(updateHistoryDocument.updatedAt)}</time></strong>
|
||||
{#if previewUpdate}
|
||||
<span class="status"><b>업데이트 알림 미리보기</b></span>
|
||||
{:else if updateAvailable}
|
||||
<span class="status"><b>{latestRelease.tagName}</b> 업데이트를 사용할 수 있습니다.</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<a class="action" href="/updates">업데이트 내역 확인 <span aria-hidden="true">→</span></a>
|
||||
</div>
|
||||
|
||||
{#if updateAvailable && latestRelease}
|
||||
<section class="latest-note" aria-labelledby="latest-release-title">
|
||||
<header>
|
||||
<div>
|
||||
<span class="release-tag">{latestRelease.tagName}</span>
|
||||
<h2 id="latest-release-title">{latestRelease.name}</h2>
|
||||
</div>
|
||||
<time datetime={latestRelease.publishedAt}>{publishedDate(latestRelease.publishedAt)}</time>
|
||||
</header>
|
||||
|
||||
{#if latestRelease.body.trim()}
|
||||
<div class="markdown-body">{@html renderReleaseMarkdown(latestRelease.body)}</div>
|
||||
{:else}
|
||||
<p class="no-notes">작성된 릴리즈 노트가 없습니다.</p>
|
||||
{/if}
|
||||
</section>
|
||||
{/if}
|
||||
</aside>
|
||||
|
||||
<style>
|
||||
.update-notice { margin-bottom: 12px; border: 1px solid #2c3440; border-radius: 12px; background: #151a22; overflow: hidden; }
|
||||
.update-notice.available { border-color: rgb(237 139 181 / 38%); background: rgb(237 139 181 / 6%); }
|
||||
.notice-header { display: flex; align-items: center; justify-content: space-between; gap: 24px; padding: 14px 18px; }
|
||||
.version-summary { display: flex; align-items: baseline; min-width: 0; gap: 10px; }
|
||||
.label { color: #7f8998; font-size: 13px; font-weight: 800; }
|
||||
strong { color: #eef1f5; font-size: 15px; }
|
||||
.status { color: #a4adba; font-size: 14px; }
|
||||
.status b { color: #f0a1c3; }
|
||||
.action { flex: 0 0 auto; color: #aab3c0; font-size: 14px; font-weight: 800; text-decoration: none; }
|
||||
.available .action { color: #f2a6c6; }
|
||||
.action span { margin-left: 4px; }
|
||||
.action:hover { color: #ffd0e2; }
|
||||
.action:focus-visible { outline: 3px solid rgb(239 139 182 / 28%); outline-offset: 3px; }
|
||||
.latest-note { padding: 24px 26px 28px; border-top: 1px solid rgb(237 139 181 / 20%); background: rgb(13 16 22 / 38%); }
|
||||
.latest-note > header { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; padding-bottom: 18px; border-bottom: 1px solid rgb(255 255 255 / 8%); }
|
||||
.release-tag { color: #f0a1c3; font-size: 13px; font-weight: 900; }
|
||||
.latest-note h2 { margin: 6px 0 0; color: #edf0f5; font-size: 22px; letter-spacing: -.025em; }
|
||||
.latest-note time { flex: 0 0 auto; color: #858f9e; font-size: 13px; }
|
||||
.markdown-body { padding-top: 18px; color: #b7bfca; font-size: 14px; line-height: 1.7; overflow-wrap: anywhere; }
|
||||
.markdown-body :global(:first-child) { margin-top: 0; }
|
||||
.markdown-body :global(:last-child) { margin-bottom: 0; }
|
||||
.markdown-body :global(h1), .markdown-body :global(h2), .markdown-body :global(h3), .markdown-body :global(h4) { margin: 1.35em 0 .5em; color: #eef1f5; line-height: 1.35; }
|
||||
.markdown-body :global(h1) { font-size: 22px; }
|
||||
.markdown-body :global(h2) { font-size: 19px; }
|
||||
.markdown-body :global(h3) { font-size: 17px; }
|
||||
.markdown-body :global(p), .markdown-body :global(ul), .markdown-body :global(ol), .markdown-body :global(blockquote), .markdown-body :global(pre) { margin: .75em 0; }
|
||||
.markdown-body :global(ul), .markdown-body :global(ol) { padding-left: 1.5em; }
|
||||
.markdown-body :global(a) { color: #f0a1c3; text-underline-offset: 3px; }
|
||||
.markdown-body :global(code) { padding: 2px 5px; border-radius: 5px; color: #e8b3ca; background: #202631; font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: .9em; }
|
||||
.markdown-body :global(pre) { padding: 14px; border: 1px solid #303846; border-radius: 9px; background: #10141a; overflow-x: auto; }
|
||||
.markdown-body :global(pre code) { padding: 0; color: #c9d0da; background: transparent; }
|
||||
.markdown-body :global(blockquote) { padding-left: 14px; border-left: 3px solid #596475; color: #929cab; }
|
||||
.markdown-body :global(img) { max-width: 100%; border-radius: 9px; }
|
||||
.no-notes { margin: 18px 0 0; color: #818b99; font-size: 14px; }
|
||||
|
||||
@media (max-width: 680px) {
|
||||
.notice-header { align-items: flex-start; flex-direction: column; gap: 8px; }
|
||||
.version-summary { align-items: flex-start; flex-wrap: wrap; }
|
||||
.latest-note { padding: 22px 18px 24px; }
|
||||
.latest-note > header { flex-direction: column; gap: 8px; }
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user