Add anime, shows and movies to about page
This commit is contained in:
1 parent
d7476cff98
commit
7845cb5e6f
12 files changed
+754
-22
No files matched your search
@@ -0,0 +1,238 @@
|
||||
<script lang="ts">
|
||||
import Icon from '@iconify/svelte';
|
||||
import type { AnimeProfile } from '#lib/anime/types';
|
||||
import LinkButton from '#lib/components/ui/LinkButton.svelte';
|
||||
import Panel from '#lib/components/ui/Panel.svelte';
|
||||
import AnimeProfileHeader from './AnimeProfileHeader.svelte';
|
||||
|
||||
let { anime }: { anime: AnimeProfile } = $props();
|
||||
|
||||
const collapsedCount = 12;
|
||||
|
||||
let showAll = $state(false);
|
||||
|
||||
const shownTopRated = $derived(showAll ? anime.topRated : anime.topRated.slice(0, collapsedCount));
|
||||
|
||||
function progressPercent(progress: number, episodes: number | null): number {
|
||||
return episodes ? Math.min(100, (progress / episodes) * 100) : 0;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="overview" class:single={!anime.watching.length}>
|
||||
<Panel title="anilist" icon="simple-icons:anilist">
|
||||
<AnimeProfileHeader {anime} />
|
||||
</Panel>
|
||||
|
||||
{#if anime.watching.length}
|
||||
<Panel title="Currently watching" icon="mdi:play-circle-outline">
|
||||
<div class="watching">
|
||||
{#each anime.watching as entry (entry.id)}
|
||||
<a class="watching-row" href={entry.url} target="_blank" rel="noopener noreferrer">
|
||||
<img src={entry.cover} alt={entry.title} loading="lazy" />
|
||||
<div class="watching-text">
|
||||
<span class="title">{entry.title}</span>
|
||||
<div class="progress-track">
|
||||
<div class="progress-fill" style:width="{progressPercent(entry.progress, entry.episodes)}%"></div>
|
||||
</div>
|
||||
<span class="muted episode">Episode {entry.progress} / {entry.episodes ?? '?'}</span>
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</Panel>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<h3 class="subheading"><Icon icon="mdi:star" width="16" /> Top rated</h3>
|
||||
<div class="cover-grid">
|
||||
{#each shownTopRated as entry (entry.id)}
|
||||
<a class="cover-card" href={entry.url} target="_blank" rel="noopener noreferrer" title={entry.title}>
|
||||
<div class="cover">
|
||||
<img src={entry.cover} alt={entry.title} loading="lazy" />
|
||||
<span class="score"><Icon icon="mdi:star" width="13" />{entry.score}</span>
|
||||
</div>
|
||||
<span class="cover-title">{entry.title}</span>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
{#if anime.topRated.length > collapsedCount}
|
||||
<button class="toggle" onclick={() => (showAll = !showAll)}>
|
||||
<Icon icon={showAll ? 'mdi:chevron-up' : 'mdi:chevron-down'} width="16" />
|
||||
{showAll ? 'Show less' : `Show all ${anime.topRated.length}`}
|
||||
</button>
|
||||
{/if}
|
||||
<LinkButton href={anime.profileUrl} icon="simple-icons:anilist">Full list on AniList ({anime.completedCount} completed)</LinkButton>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.subheading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
margin: 1.25rem 0 0.6rem;
|
||||
color: var(--foreground);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.overview {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.overview.single {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.watching {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.watching-row {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
padding: 0.4rem;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.watching-row:hover,
|
||||
.cover-card:hover .cover {
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.watching-row img {
|
||||
flex-shrink: 0;
|
||||
width: 52px;
|
||||
height: 74px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.watching-text {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 0.4rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
overflow: hidden;
|
||||
font-size: 0.9rem;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.progress-track {
|
||||
height: 4px;
|
||||
background: color-mix(in srgb, var(--foreground) 15%, transparent);
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: var(--accent);
|
||||
}
|
||||
|
||||
.episode {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.cover-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||||
gap: 0.9rem 0.75rem;
|
||||
}
|
||||
|
||||
.cover-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.cover {
|
||||
position: relative;
|
||||
aspect-ratio: 2 / 3;
|
||||
overflow: hidden;
|
||||
border: 1px solid color-mix(in srgb, var(--foreground) 20%, transparent);
|
||||
transition: border-color 0.15s ease;
|
||||
}
|
||||
|
||||
.cover img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.cover-card:hover img {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.score {
|
||||
position: absolute;
|
||||
top: 0.35rem;
|
||||
right: 0.35rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.15rem;
|
||||
padding: 0 0.35rem;
|
||||
background: var(--background);
|
||||
color: var(--yellow);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.cover-title {
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.3;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.cover-card:hover .cover-title {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
padding: 0.3rem 0.7rem;
|
||||
background: none;
|
||||
border: 1px solid color-mix(in srgb, var(--foreground) 30%, transparent);
|
||||
color: var(--foreground);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.toggle:hover {
|
||||
border-color: var(--accent);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
@container (max-width: 800px) {
|
||||
.overview {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@container (max-width: 520px) {
|
||||
.cover-grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user