You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
200 lines
4.7 KiB
200 lines
4.7 KiB
<script lang="ts" context="module">
|
|
export const PROGRESS_COLORS = [
|
|
"none",
|
|
"bronze",
|
|
"silver",
|
|
"gold",
|
|
]
|
|
|
|
</script>
|
|
|
|
<script lang="ts">
|
|
export let name: string;
|
|
export let acquired: number;
|
|
export let required: number;
|
|
export let boat: number | null = null;
|
|
export let big: boolean = false;
|
|
export let bare: boolean = false;
|
|
export let fullwidth: boolean = false;
|
|
export let percentage: boolean = false;
|
|
export let green: boolean = false;
|
|
|
|
let offClass = PROGRESS_COLORS[0];
|
|
let onClass = PROGRESS_COLORS[1];
|
|
let ons = 0;
|
|
let offs = 1;
|
|
let segmented = false;
|
|
let boatClass = "gray";
|
|
let boatDone = false;
|
|
|
|
$: {
|
|
if (required > 0) {
|
|
let level = Math.floor(acquired / required);
|
|
if (level >= PROGRESS_COLORS.length - 1) {
|
|
offs = 0;
|
|
ons = required;
|
|
offClass = "gold";
|
|
onClass = "gold";
|
|
} else {
|
|
ons = acquired - (level * required);
|
|
offs = required - ons;
|
|
console.log(name, ons, offs);
|
|
offClass = PROGRESS_COLORS[level];
|
|
onClass = PROGRESS_COLORS[level + 1];
|
|
}
|
|
|
|
// Mark it non-segmented if the required is too high. This prevents a clunky progress bar,
|
|
// or a browser freeze if you set the required very high.
|
|
segmented = !percentage && (required <= (fullwidth ? 60 : 15));
|
|
} else {
|
|
offClass = "none";
|
|
segmented = true;
|
|
ons = 0;
|
|
offs = 1;
|
|
}
|
|
|
|
if (green) {
|
|
onClass = "green";
|
|
offClass = "none";
|
|
|
|
if (acquired >= required) {
|
|
ons = required;
|
|
offs = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
$: {
|
|
if (boat != null && required > 0) {
|
|
const diff = (acquired / required) - boat;
|
|
if (diff < -0.05) {
|
|
boatClass = "red";
|
|
} else if (diff > 0.05) {
|
|
boatClass = "green";
|
|
} else {
|
|
boatClass = "gray";
|
|
}
|
|
|
|
boatDone = acquired >= required;
|
|
} else {
|
|
boatClass = "gray";
|
|
boatDone = false;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<div class="progress" class:fullwidth>
|
|
<!-- Header -->
|
|
{#if !bare}
|
|
<div class="header">
|
|
<span>{name}</span>
|
|
{#if percentage}
|
|
<span class="ackreq">({((acquired / required) * 100).toFixed(0)}%)</span>
|
|
{:else}
|
|
<span class="ackreq">({Math.round(acquired)} / {Math.round(required)})</span>
|
|
{/if}
|
|
</div>
|
|
{/if}
|
|
|
|
<!-- Progress Bar -->
|
|
<div class="bar" class:big>
|
|
{#if segmented}
|
|
{#each {length: Math.max(ons, 0)} as _}
|
|
<div class="segmented on {onClass}"></div>
|
|
{/each}
|
|
{#each {length: Math.max(offs, 0)} as _}
|
|
<div class="segmented off {offClass}"></div>
|
|
{/each}
|
|
{:else}
|
|
{#if ons > 0}
|
|
<div style="flex: {ons}" class="non-segmented on {onClass}"></div>
|
|
{/if}
|
|
{#if offs > 0}
|
|
<div style="flex: {offs}" class="non-segmented off {offClass}"></div>
|
|
{/if}
|
|
{/if}
|
|
</div>
|
|
|
|
<!-- "Boat" -->
|
|
{#if boat != null && !boatDone}
|
|
<div class="bar boat">
|
|
<div style="flex: {Math.min(boat, 1)}" class="non-segmented on {boatClass}"></div>
|
|
<div style="flex: {Math.max(1 - boat, 0)}" class="non-segmented off none"></div>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
|
|
<style lang="scss">
|
|
div.progress {
|
|
padding: 0.25em 0.5ch;
|
|
font-size: 0.9em;
|
|
flex-basis: calc(33.33% - 1ch);
|
|
|
|
@media screen and (max-width: 1300px) {
|
|
flex-basis: calc(50% - 1ch);
|
|
}
|
|
|
|
@media screen and (max-width: 600px) {
|
|
font-size: 1.2em;
|
|
flex-basis: calc(100% - 1ch);
|
|
}
|
|
|
|
&.fullwidth {
|
|
flex-basis: calc(100% - 1ch);
|
|
}
|
|
}
|
|
|
|
div.bar {
|
|
display: flex;
|
|
flex-direction: row;
|
|
margin: 0;
|
|
box-sizing: border-box;
|
|
width: 100%;
|
|
height: 8px;
|
|
margin: 0.5px 0;
|
|
transform: skew(-11.25deg, 0);
|
|
|
|
margin-top: 0.2em;
|
|
|
|
@media screen and (max-width: 600px) {
|
|
height: 6px;
|
|
}
|
|
|
|
&.big {
|
|
height: 12px;
|
|
}
|
|
&.boat {
|
|
transform: skew(-11.25deg, 0) translateX(-1.1px);
|
|
margin-top: 0em;
|
|
height: 2.5px;
|
|
}
|
|
|
|
> div {
|
|
flex-grow: 1;
|
|
flex-basis: 0;
|
|
display: inline-block;
|
|
box-sizing: border-box;
|
|
margin: 0 0.5px;
|
|
border: 0.25px solid #000;
|
|
|
|
div.non-segmented {
|
|
flex-grow: inherit;
|
|
flex-basis: inherit;
|
|
}
|
|
|
|
&.on {opacity: 0.75; }
|
|
&.none { background-color: #000; }
|
|
&.gray { background-color: #999; opacity: 1; }
|
|
&.bronze { background-color: #f4b083; }
|
|
&.silver { background-color: #d8dce4; opacity: 0.8; }
|
|
&.gold { background-color: #ffd966; opacity: 0.9; }
|
|
&.green { background-color: #8ef88e; opacity: 0.8; }
|
|
&.red { background-color: hsl(0, 95%, 70%); opacity: 0.8; }
|
|
&.off {opacity: 0.30; }
|
|
}
|
|
}
|
|
|
|
span.ackreq {
|
|
opacity: 0.333;
|
|
}
|
|
</style>
|