feat: release version 1.0.7

This commit is contained in:
2026-08-21 19:06:55 +09:00
parent 5d29b63f3a
commit 71dfe11bc4
406 changed files with 3086 additions and 1172 deletions
+79
View File
@@ -0,0 +1,79 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import { songOptions, type SongChartSummary, type SongSort } from '$lib/data/song-catalog.ts';
export let charts: readonly SongChartSummary[];
export let difficulty: string;
export let value: string;
const dispatch = createEventDispatcher<{ change: void }>();
let query = '';
let sort: SongSort = 'title';
$: options = songOptions(charts, difficulty, query, sort);
function selectSong(event: Event) {
const nextValue = (event.currentTarget as HTMLSelectElement).value;
if (!nextValue) return;
value = nextValue;
dispatch('change');
}
</script>
<div class="song-picker">
<label class="song-search">
<span>악곡 검색</span>
<input bind:value={query} type="search" placeholder="영문 곡명 검색" autocomplete="off">
</label>
<label class="song-sort">
<span>정렬</span>
<select bind:value={sort}>
<option value="title">알파벳순</option>
<option value="difficulty-asc">난이도 낮은순</option>
<option value="difficulty-desc">난이도 높은순</option>
</select>
</label>
<label class="song-select">
<span>악곡 <small>{options.length}곡</small></span>
<select value={value} on:change={selectSong} disabled={options.length === 0}>
{#if options.length === 0}
<option>검색 결과가 없습니다</option>
{:else}
{#if !options.some((song) => song.id === value)}
<option value="" disabled>검색 결과에서 악곡을 선택하세요</option>
{/if}
{#each options as song}
<option value={song.id}>{song.title}{song.difficultyLevel === null ? '' : ` · Lv. ${song.difficultyLevel}`}</option>
{/each}
{/if}
</select>
</label>
{#if query.trim()}
<p class:no-results={options.length === 0} class="search-status" aria-live="polite">
{options.length > 0
? `${options.length}곡을 찾았습니다. 목록에서 선택하세요.`
: '검색 결과가 없습니다.'}
</p>
{/if}
</div>
<style>
.song-picker { display: grid; grid-template-columns: minmax(180px, .9fr) minmax(140px, .55fr) minmax(260px, 1.4fr); gap: 9px; }
label { display: grid; gap: 7px; min-width: 0; color: #8f98a8; font-size: 14px; font-weight: 750; }
label > span { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
small { color: #737d8d; font-size: 11px; }
input, select { width: 100%; min-width: 0; height: 42px; padding: 0 12px; border: 1px solid #343c49; border-radius: 9px; color: #e8ebf1; background: #11151b; font: inherit; }
input::placeholder { color: #68717f; opacity: 1; }
input:focus, select:focus { border-color: #d86f9c; outline: 3px solid rgb(216 111 156 / 14%); }
select:disabled { color: #747d8b; }
.search-status { grid-column: 1 / -1; margin: -1px 2px 0; color: #8fa99c; font-size: 12px; font-weight: 750; line-height: 1.45; }
.search-status.no-results { color: #d09494; }
@media (max-width: 900px) {
.song-picker { grid-template-columns: 1fr minmax(140px, .55fr); }
.song-select { grid-column: 1 / -1; }
}
@media (max-width: 520px) {
.song-picker { grid-template-columns: 1fr; }
.song-select { grid-column: auto; }
}
</style>