105 lines
3.0 KiB
Svelte
105 lines
3.0 KiB
Svelte
<script lang="ts">
|
|
import type { Target } from '../../game/tasks';
|
|
import type { Stage } from '../../game/stages';
|
|
import { progress } from '../../stores/progress';
|
|
import Crown from '../svg/Crown.svelte';
|
|
import Balloon from '../svg/Balloon.svelte';
|
|
import Cloud from '../svg/Cloud.svelte';
|
|
import Moon from '../svg/Moon.svelte';
|
|
import Star from '../svg/Star.svelte';
|
|
import Rainbow from '../svg/Rainbow.svelte';
|
|
|
|
type Props = { target: Target; highlightDate?: string | null };
|
|
let { target, highlightDate = null }: Props = $props();
|
|
|
|
const top5 = $derived($progress.perTarget[target]?.top5 ?? []);
|
|
// Slots immer 5 lang darstellen — leere Plätze bleiben grau.
|
|
const slots = $derived(Array.from({ length: 5 }, (_, i) => top5[i] ?? null));
|
|
|
|
// Erreichte Stufe → passendes Symbol. Stufe 0 (Boden) hat kein Symbol (siehe Markup).
|
|
// Größen pro Symbol leicht angeglichen, da die viewBoxes unterschiedlich proportioniert sind.
|
|
const SYMBOL: Record<number, { c: typeof Balloon; size: number }> = {
|
|
1: { c: Balloon, size: 38 },
|
|
2: { c: Cloud, size: 52 },
|
|
3: { c: Moon, size: 40 },
|
|
4: { c: Star, size: 36 },
|
|
5: { c: Rainbow, size: 56 },
|
|
};
|
|
</script>
|
|
|
|
<div class="column" aria-label="Beste Flüge">
|
|
{#each slots as slot, i (i)}
|
|
<!-- Bester Versuch (i===0) wird nur durch die Krone markiert, nicht zusätzlich hervorgehoben. -->
|
|
<div
|
|
class="slot"
|
|
class:empty={!slot}
|
|
class:current={slot && i !== 0 && highlightDate && slot.date === highlightDate}
|
|
>
|
|
{#if slot}
|
|
{#if i === 0}
|
|
<span class="crown"><Crown size={28} /></span>
|
|
{/if}
|
|
<span class="symbol" aria-label={`Stufe ${slot.stage}`}>
|
|
{#if slot.stage === 0}
|
|
<span class="ground" aria-hidden="true"></span>
|
|
{:else}
|
|
{@const Symbol = SYMBOL[slot.stage as Stage].c}
|
|
<Symbol size={SYMBOL[slot.stage as Stage].size} />
|
|
{/if}
|
|
</span>
|
|
{:else}
|
|
<div class="placeholder"></div>
|
|
{/if}
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
|
|
<style>
|
|
.column {
|
|
display: grid;
|
|
grid-template-rows: repeat(5, 1fr);
|
|
gap: 10px;
|
|
height: 100%;
|
|
}
|
|
.slot {
|
|
position: relative;
|
|
background: rgba(255, 255, 255, 0.16);
|
|
border-radius: 14px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 4px 8px;
|
|
min-height: 56px;
|
|
}
|
|
.slot.empty {
|
|
background: rgba(255, 255, 255, 0.06);
|
|
}
|
|
.slot.current {
|
|
background: rgba(255, 229, 102, 0.3);
|
|
box-shadow: 0 0 0 3px var(--c-rocket-window);
|
|
}
|
|
.crown {
|
|
position: absolute;
|
|
top: -10px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
}
|
|
.symbol {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
.ground {
|
|
width: 40px;
|
|
height: 18px;
|
|
border-radius: 40px 40px 0 0;
|
|
background: linear-gradient(to top, #4ea34e, var(--c-ground));
|
|
}
|
|
.placeholder {
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: 50%;
|
|
border: 2px dashed rgba(255, 255, 255, 0.3);
|
|
}
|
|
</style>
|