Files
decision/web/src/lib/components/WaterLevel.svelte
T

73 lines
1.8 KiB
Svelte

<script lang="ts">
// The signature of this tool: a proposal rises toward the surface as its
// « for » votes approach the threshold; reached, it stands full, in moss.
import { t } from '$lib/i18n/index.svelte';
import type { Evaluation, Tally } from '$lib/types';
let {
tally,
evaluation,
blocked = false,
size = 'row',
}: { tally: Tally; evaluation: Evaluation | null; blocked?: boolean; size?: 'mini' | 'row' | 'large' } = $props();
const ratio = $derived(
evaluation && evaluation.required > 0 ? Math.min(1, tally.for / evaluation.required) : 0,
);
const pct = $derived(Math.round(ratio * 100));
</script>
<span
class="level {size}"
class:reached={evaluation?.reached}
class:blocked
role="img"
aria-label={t('tally.level', { pct })}
title={t('tally.level', { pct })}
>
<span class="water" style:height="{Math.max(pct, tally.for > 0 ? 6 : 0)}%"></span>
</span>
<style>
.level {
position: relative;
display: inline-block;
flex: none;
width: 8px;
height: 2.4rem;
border-radius: 6px;
background: var(--surface-2);
box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.08);
overflow: hidden;
}
/* A section folded: one small bar per article, where the support rises. */
.level.mini {
width: 5px;
height: 1.1rem;
border-radius: 3px;
}
.level.large {
width: 14px;
height: 5.5rem;
border-radius: 8px;
}
.water {
position: absolute;
inset: auto 0 0 0;
background: linear-gradient(to top, var(--water), color-mix(in srgb, var(--water) 55%, var(--water-light)));
transition: height 0.7s var(--ease);
}
.reached .water {
height: 100% !important;
background: var(--moss);
}
.blocked {
box-shadow: inset 0 0 0 2px var(--ochre);
}
@media (prefers-reduced-motion: reduce) {
.water {
transition: none;
}
}
</style>