100 lines
2.4 KiB
Svelte
100 lines
2.4 KiB
Svelte
|
|
<script lang="ts">
|
||
|
|
import AdventuresListItem from './AdventuresListItem.svelte';
|
||
|
|
import { resolve } from '$app/paths';
|
||
|
|
|
||
|
|
type Adventure = {
|
||
|
|
id: string;
|
||
|
|
title: string;
|
||
|
|
description: string | null;
|
||
|
|
created_at: Date;
|
||
|
|
genres: string[];
|
||
|
|
vibes: string[];
|
||
|
|
};
|
||
|
|
|
||
|
|
type Props = {
|
||
|
|
adventures: Adventure[];
|
||
|
|
};
|
||
|
|
|
||
|
|
const { adventures }: Props = $props();
|
||
|
|
|
||
|
|
const makeEyebrowText = (adventure: Adventure): string => {
|
||
|
|
const genresText = adventure.genres.length > 0 ? adventure.genres.join(', ') : 'No genres';
|
||
|
|
const vibesText = adventure.vibes.length > 0 ? adventure.vibes.join(', ') : 'No vibes';
|
||
|
|
return `${genresText} | ${vibesText}`;
|
||
|
|
};
|
||
|
|
</script>
|
||
|
|
|
||
|
|
{#if adventures.length === 0}
|
||
|
|
<section class="adventures-empty" aria-label="No adventures yet">
|
||
|
|
<p class="adventures-empty__label">No adventures yet</p>
|
||
|
|
<p class="adventures-empty__copy">Create one to begin your next story.</p>
|
||
|
|
</section>
|
||
|
|
{:else}
|
||
|
|
<ol class="adventures-list" aria-label="Available adventures">
|
||
|
|
{#each adventures as adventure, index (adventure.id)}
|
||
|
|
<li class="adventures-list__item">
|
||
|
|
<AdventuresListItem
|
||
|
|
href={resolve('/app/adventures/[id]', { id: adventure.id })}
|
||
|
|
title={adventure.title}
|
||
|
|
description={adventure.description}
|
||
|
|
eyebrowText={makeEyebrowText(adventure)}
|
||
|
|
createdAt={new Date(adventure.created_at)}
|
||
|
|
/>
|
||
|
|
</li>
|
||
|
|
{/each}
|
||
|
|
</ol>
|
||
|
|
{/if}
|
||
|
|
|
||
|
|
<style>
|
||
|
|
.adventures-list {
|
||
|
|
list-style: none;
|
||
|
|
margin: 0;
|
||
|
|
padding: 0;
|
||
|
|
display: grid;
|
||
|
|
gap: var(--space-3);
|
||
|
|
background-color: var(--color-surface-container-low);
|
||
|
|
border-radius: var(--radius-xl);
|
||
|
|
padding: var(--space-3);
|
||
|
|
}
|
||
|
|
|
||
|
|
.adventures-list__item {
|
||
|
|
margin: 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.adventures-empty {
|
||
|
|
padding: var(--space-6) var(--space-4);
|
||
|
|
background-color: var(--color-surface-container-low);
|
||
|
|
border-radius: var(--radius-xl);
|
||
|
|
}
|
||
|
|
|
||
|
|
.adventures-empty__label {
|
||
|
|
margin: 0;
|
||
|
|
font-family: var(--font-label);
|
||
|
|
font-size: var(--text-label-md);
|
||
|
|
font-weight: var(--weight-medium);
|
||
|
|
letter-spacing: var(--tracking-wide);
|
||
|
|
text-transform: uppercase;
|
||
|
|
color: color-mix(in srgb, var(--color-on-surface) 70%, transparent);
|
||
|
|
}
|
||
|
|
|
||
|
|
.adventures-empty__copy {
|
||
|
|
margin: var(--space-2) 0 0;
|
||
|
|
font-family: var(--font-body);
|
||
|
|
font-size: var(--text-body-xl);
|
||
|
|
line-height: var(--leading-relaxed);
|
||
|
|
color: var(--color-on-surface);
|
||
|
|
}
|
||
|
|
|
||
|
|
@media (min-width: 60rem) {
|
||
|
|
.adventures-list {
|
||
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@media (max-width: 56rem) {
|
||
|
|
.adventures-list {
|
||
|
|
padding: var(--space-2);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</style>
|