feat: add annotations, user profiles, watchers, stories, search and more
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user