Add games library with IGDB, file explorer and static files script
This commit is contained in:
1 parent
a16444451a
commit
ec57bd73b3
65 files changed
+2230
-352
No files matched your search
@@ -1,51 +1,53 @@
|
||||
<script lang="ts">
|
||||
import Icon from '@iconify/svelte';
|
||||
import type { Game } from '#lib/content';
|
||||
import { storeFor } from '#lib/library/stores';
|
||||
|
||||
let { game }: { game: Game } = $props();
|
||||
|
||||
const storeNames: Record<string, { label: string; icon: string }> = {
|
||||
'store.steampowered.com': { label: 'Steam', icon: 'mdi:steam' }
|
||||
};
|
||||
|
||||
const store = $derived.by(() => {
|
||||
const host = new URL(game.url).hostname;
|
||||
return storeNames[host] ?? { label: host.replace(/^www\./, ''), icon: 'mdi:web' };
|
||||
});
|
||||
|
||||
const details = $derived(game.details);
|
||||
const image = $derived(game.image ?? details?.screenshot ?? details?.cover ?? null);
|
||||
const releaseYear = $derived(details?.released?.match(/\d{4}/)?.[0] ?? null);
|
||||
const metaLine = $derived([releaseYear, details?.developers[0]].filter(Boolean).join(' · '));
|
||||
const score = $derived(
|
||||
details?.criticScore != null ? `${details.criticScore}%` : details?.mobyScore != null ? `${details.mobyScore}` : null
|
||||
);
|
||||
const link = $derived(game.url ?? game.igdbUrl ?? '');
|
||||
const store = $derived(storeFor(link));
|
||||
const releaseYear = $derived(game.released?.slice(0, 4) ?? null);
|
||||
const metaLine = $derived([releaseYear, game.developers[0]].filter(Boolean).join(' · '));
|
||||
</script>
|
||||
|
||||
<a class="game-card" href={game.url} target="_blank" rel="noopener noreferrer" title={details?.description ?? game.name}>
|
||||
<a class="game-card" href={link || undefined} target="_blank" rel="noopener noreferrer" title={game.summary ?? game.name}>
|
||||
<div class="cover">
|
||||
{#if image}
|
||||
<img src={image} alt="" loading="lazy" />
|
||||
{#if game.image}
|
||||
<img src={game.image} alt="" loading="lazy" />
|
||||
{:else}
|
||||
<span class="placeholder"><Icon icon="mdi:gamepad-variant-outline" width="36" /></span>
|
||||
{/if}
|
||||
{#if score}
|
||||
<span class="score" title={details?.criticScore != null ? 'Critic score' : 'Moby score'}><Icon icon="mdi:star" width="13" />{score}</span>
|
||||
{#if game.favorite}
|
||||
<span class="favorite"><Icon icon="mdi:star" width="13" />favorite</span>
|
||||
{/if}
|
||||
{#if game.rating !== undefined}
|
||||
<span class="score"><Icon icon="mdi:star" width="13" />{game.rating}/10</span>
|
||||
{:else if game.score !== null}
|
||||
<span class="score community" title="IGDB rating"><Icon icon="mdi:star-outline" width="13" />{game.score}</span>
|
||||
{/if}
|
||||
{#if game.status === 'playing'}
|
||||
<span class="status playing"><Icon icon="mdi:play" width="13" />playing</span>
|
||||
{:else if game.status === 'planning'}
|
||||
<span class="status planning"><Icon icon="mdi:bookmark-outline" width="13" />planning</span>
|
||||
{:else if game.status === 'replayable'}
|
||||
<span class="status replayable"><Icon icon="mdi:repeat" width="13" />replayable</span>
|
||||
{/if}
|
||||
{#if link}
|
||||
<span class="play"><Icon icon="mdi:play" width="16" /> Play</span>
|
||||
{/if}
|
||||
<span class="play"><Icon icon="mdi:play" width="16" /> Play</span>
|
||||
</div>
|
||||
<div class="details">
|
||||
<span class="name">{game.name}</span>
|
||||
<span class="store"><Icon icon={store.icon} width="14" />{store.label}</span>
|
||||
{#if link}
|
||||
<span class="store"><Icon icon={store.icon} width="14" />{store.label}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{#if metaLine}
|
||||
<span class="meta">{metaLine}</span>
|
||||
{/if}
|
||||
{#if details?.genres.length}
|
||||
<span class="meta">{details.genres.slice(0, 3).join(' · ')}</span>
|
||||
{/if}
|
||||
{#if game.mobygames}
|
||||
<span class="meta source"><Icon icon="mdi:database-outline" width="12" />MobyGames</span>
|
||||
{#if game.genres.length}
|
||||
<span class="meta">{game.genres.slice(0, 3).join(' · ')}</span>
|
||||
{/if}
|
||||
</a>
|
||||
|
||||
@@ -109,10 +111,47 @@
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.source {
|
||||
.favorite {
|
||||
position: absolute;
|
||||
top: 0.4rem;
|
||||
left: 0.4rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
gap: 0.2rem;
|
||||
padding: 0 0.4rem;
|
||||
background: var(--yellow);
|
||||
color: var(--background);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.score.community {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.status {
|
||||
position: absolute;
|
||||
bottom: 0.4rem;
|
||||
left: 0.4rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
padding: 0 0.4rem;
|
||||
color: var(--background);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.status.playing {
|
||||
background: var(--blue);
|
||||
}
|
||||
|
||||
.status.planning {
|
||||
background: var(--magenta);
|
||||
}
|
||||
|
||||
.status.replayable {
|
||||
background: var(--cyan);
|
||||
}
|
||||
|
||||
.play {
|
||||
|
||||
Reference in new issue
Block a user