language-learning-app/frontend/src/routes/app/adventures/AdventuresList.svelte

100 lines
2.4 KiB
Svelte
Raw Normal View History

<script lang="ts">
import AdventuresListItem from './AdventuresListItem.svelte';
import { resolve } from '$app/paths';
type Adventure = {
id: string;
title: string;
description: string | null;
created_at: string;
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>