114 lines
2.5 KiB
Svelte
114 lines
2.5 KiB
Svelte
<script lang="ts">
|
|
import { untrack } from "svelte";
|
|
import { type AvatarKind, loadAvatarVariant } from "$lib/api/avatars";
|
|
import { getAvatarHistory } from "$lib/api/endpoints";
|
|
import type { AvatarHistoryView } from "$lib/api/types";
|
|
import { formatFull } from "$lib/format/datetime";
|
|
import { accounts } from "$lib/stores/accounts.svelte";
|
|
|
|
interface Props {
|
|
id: number;
|
|
kind: AvatarKind;
|
|
name: string;
|
|
}
|
|
|
|
let { kind, id, name }: Props = $props();
|
|
|
|
let items = $state<AvatarHistoryView[]>([]);
|
|
const urls = $state<Record<string, string | null>>({});
|
|
|
|
$effect(() => {
|
|
if (accounts.selectedId === null) {
|
|
return;
|
|
}
|
|
let active = true;
|
|
items = [];
|
|
getAvatarHistory(kind, id)
|
|
.then((result) => {
|
|
if (active) {
|
|
items = result;
|
|
}
|
|
})
|
|
.catch(() => undefined);
|
|
return () => {
|
|
active = false;
|
|
};
|
|
});
|
|
|
|
$effect(() => {
|
|
const list = items;
|
|
let active = true;
|
|
untrack(() => {
|
|
for (const item of list) {
|
|
if (!(item.downloaded && urls[item.unique_id] === undefined)) {
|
|
continue;
|
|
}
|
|
urls[item.unique_id] = null;
|
|
loadAvatarVariant(kind, id, item.unique_id).then((url) => {
|
|
if (active) {
|
|
urls[item.unique_id] = url;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
return () => {
|
|
active = false;
|
|
};
|
|
});
|
|
</script>
|
|
|
|
{#if items.length > 0}
|
|
<section>
|
|
<h3>История аватарок ({items.length})</h3>
|
|
<div class="grid">
|
|
{#each items as item (item.unique_id)}
|
|
<figure title={formatFull(item.first_seen_at)}>
|
|
{#if urls[item.unique_id]}
|
|
<img src={urls[item.unique_id]} alt={name}>
|
|
{:else}
|
|
<div class="placeholder"></div>
|
|
{/if}
|
|
</figure>
|
|
{/each}
|
|
</div>
|
|
</section>
|
|
{/if}
|
|
|
|
<style lang="scss">
|
|
section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.75rem;
|
|
}
|
|
|
|
h3 {
|
|
margin: 0;
|
|
font-size: 0.75rem;
|
|
font-weight: var(--font-weight-medium);
|
|
color: var(--color-text-secondary);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.03em;
|
|
}
|
|
|
|
.grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(4rem, 1fr));
|
|
gap: 0.375rem;
|
|
}
|
|
|
|
figure {
|
|
aspect-ratio: 1;
|
|
margin: 0;
|
|
overflow: hidden;
|
|
border-radius: 0.5rem;
|
|
background-color: var(--color-background-secondary);
|
|
}
|
|
|
|
img,
|
|
.placeholder {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
}
|
|
</style>
|