feat: add Holo-work tracking, teams and board bonuses
Publish GitHub Pages output / publish (push) Successful in 30s

This commit is contained in:
2026-09-12 15:16:30 +09:00
parent cfea24f5f5
commit dd37f59565
25 changed files with 1237 additions and 33 deletions
+20
View File
@@ -0,0 +1,20 @@
<script lang="ts">
import type { HoloWorkBoardBonus } from '$lib/engine/board-effects';
export let bonus: HoloWorkBoardBonus | undefined;
export let showEmpty = false;
const labels = { lesson: '레슨 Pt', cube: '큐브', training: '특훈 아이템' };
$: entries = (Object.keys(labels) as (keyof HoloWorkBoardBonus)[]).filter((key) => (bonus?.[key] ?? 0) > 0);
</script>
{#if entries.length}
<div class="bonuses" aria-label="홀로워크 보드 보너스">
{#each entries as key}<span>{labels[key]} <strong>+{bonus![key].toLocaleString('ko-KR', { maximumFractionDigits: 3 })}%</strong></span>{/each}
</div>
{:else if showEmpty}<p class="empty">활성 보드 보너스 없음</p>{/if}
<style>
.bonuses { display: flex; flex-wrap: wrap; gap: 6px; }
.bonuses span { padding: 5px 8px; border: 1px solid #65552c; border-radius: 7px; background: rgb(226 190 95 / 8%); color: #d9c890; font-size: 12px; line-height: 1.5; }
strong { color: #f1d583; white-space: nowrap; }
.empty { margin: 0; color: #a4adba; font-size: 13px; }
</style>
@@ -0,0 +1,19 @@
<script lang="ts">
import achievements from '$lib/data/holo-work-achievements.json';
import { workAchievement } from '$lib/storage/holo-work';
export let memberId: string;
export let count: number;
$: progress = workAchievement(count, (achievements.thresholdsByMember as Record<string, number[]>)[memberId] ?? []);
</script>
<span class="progress" class:complete={progress.complete}>
<strong>{count.toLocaleString('ko-KR')}</strong> / {progress.target?.toLocaleString('ko-KR') ?? '—'}회
{#if progress.complete}<small>완료</small>{/if}
</span>
<style>
.progress { white-space: nowrap; color: #a4adba; font-variant-numeric: tabular-nums; font-size: 14px; }
strong { color: #f3b4d0; font-size: 17px; }
.complete strong, small { color: #98dbbc; }
small { margin-left: 6px; font-size: 12px; }
</style>
+16
View File
@@ -0,0 +1,16 @@
<script lang="ts">
export let active: 'random' | 'holo-work';
</script>
<nav aria-label="도구 메뉴">
<a href="/tools/random" aria-current={active === 'random' ? 'page' : undefined}>악곡 랜덤</a>
<a href="/tools/holo-work" aria-current={active === 'holo-work' ? 'page' : undefined}>홀로워크 관리</a>
</nav>
<style>
nav { display: flex; gap: 5px; margin: 24px 0; padding: 5px; border: 1px solid #2c3441; border-radius: 12px; background: #171c24; }
a { flex: 1; padding: 9px 12px; border-radius: 8px; color: #929cad; font-size: 14px; font-weight: 800; text-align: center; text-decoration: none; }
a:hover { color: #dfe4eb; background: rgb(255 255 255 / 4%); }
a[aria-current='page'] { color: #f3a5c5; background: rgb(239 139 182 / 12%); }
a:focus-visible { outline: 3px solid #ed8bb5; outline-offset: 3px; }
</style>