language-learning-app/frontend/src/routes/app/adventures/[id]/PreviousEntries.svelte

245 lines
6 KiB
Svelte
Raw Normal View History

<script lang="ts">
import { locale, makeTranslate } from '$lib/i8n';
import translations from '../translations';
type Props = {
entries: {
id: string;
text: string;
possibleChoices: {
id: string;
text: string;
isSelected: boolean;
}[];
}[];
};
const t = $derived(makeTranslate(translations, $locale));
const { entries }: Props = $props();
function toParagraphs(text: string): string[] {
return text
.split(/\n\s*\n/g)
.map((paragraph) => paragraph.trim())
.filter(Boolean);
}
</script>
{#if entries.length > 0}
<section class="previous-entries" aria-label="Previous story entries">
<header class="previous-entries__header">
<h2 class="previous-entries__title">{t('previousEntries.title')}</h2>
</header>
<ol class="list">
{#each entries as entry, index (entry.id)}
<li class="previous-entries__item">
<article
class="entry-card"
aria-label={t('previousEntries.entryTitle', {
entryNumber: String(index + 1).padStart(2, '0')
})}
>
<header class="entry-card__header">
<p class="entry-card__index">
{t('previousEntries.entryTitle', {
entryNumber: String(index + 1).padStart(2, '0')
})}
</p>
</header>
<div class="entry-card__body">
{#each toParagraphs(entry.text) as paragraph, paragraphIndex (paragraphIndex)}
<p class="entry-card__paragraph">{paragraph}</p>
{/each}
</div>
{#if entry.possibleChoices.length > 0}
<footer class="entry-card__choices">
<p class="entry-card__choices-label">{t('previousEntries.possibleChoices')}</p>
<ul class="entry-card__choices-list" aria-label="Choices for this entry">
{#each entry.possibleChoices as choice, choiceIndex (choice.id)}
<li
class="entry-card__choice"
class:entry-card__choice--selected={choice.isSelected}
>
<span class="entry-card__choice-index" aria-hidden="true"
>{String(choiceIndex + 1).padStart(2, '0')}</span
>
<span class="entry-card__choice-text">{choice.text}</span>
{#if choice.isSelected}
<span class="entry-card__choice-state">{t('options.selected')}</span>
{/if}
</li>
{/each}
</ul>
</footer>
{/if}
</article>
</li>
{/each}
</ol>
</section>
{/if}
<style>
.previous-entries {
--previous-surface: var(--color-surface-container-low);
--previous-surface-elevated: var(--color-surface-container-lowest);
max-width: 88rem;
border-radius: var(--radius-xl);
}
.previous-entries__header {
margin-bottom: var(--space-4);
}
.previous-entries__title {
margin: var(--space-1) 0 0;
font-family: var(--font-display);
font-size: clamp(1.3rem, 1.12rem + 0.85vw, 1.9rem);
line-height: 1.15;
color: var(--color-on-surface);
}
.previous-entries .list {
list-style: none;
padding: 0;
margin: 0;
display: grid;
gap: var(--space-5);
grid-template-columns: 1fr;
}
.entry-card {
border-radius: var(--radius-lg);
background-color: var(--previous-surface-elevated);
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto 1fr;
place-items: center;
gap: var(--space-5);
padding: var(--space-4) var(--space-1);
}
.entry-card__header {
margin-bottom: var(--space-2);
}
.entry-card__index {
margin: 0;
font-family: var(--font-label);
font-size: var(--text-label-md);
font-weight: var(--weight-semibold);
letter-spacing: 0.08em;
text-transform: uppercase;
color: color-mix(in srgb, var(--color-on-surface) 72%, transparent);
}
.entry-card__body::-webkit-scrollbar {
width: 0.65rem;
}
.entry-card__body::-webkit-scrollbar-track {
background: transparent;
}
.entry-card__body::-webkit-scrollbar-thumb {
background-color: color-mix(in srgb, var(--colour-yellow-300) 26%, transparent);
border: 0.16rem solid transparent;
border-radius: var(--radius-full);
background-clip: content-box;
}
.entry-card__paragraph {
font-family: var(--font-body);
font-size: var(--text-body-md);
line-height: var(--leading-xloose);
color: var(--color-on-surface);
text-wrap: pretty;
max-width: 65ch;
}
.entry-card__paragraph + .entry-card__paragraph {
margin-top: var(--space-3);
padding-top: var(--space-3);
}
.entry-card__choices {
max-width: 65ch;
font-size: var(--text-body-md);
}
.entry-card__choices-label {
margin: 0 0 var(--space-2);
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) 72%, transparent);
}
.entry-card__choices-list {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: var(--space-2);
}
.entry-card__choice {
display: grid;
grid-template-columns: auto 1fr auto;
place-items: center;
gap: var(--space-2);
padding: var(--space-2);
border-radius: var(--radius-md);
}
.entry-card__choice-index {
font-family: var(--font-label);
font-size: var(--text-label-md);
font-weight: var(--weight-medium);
letter-spacing: var(--tracking-wide);
color: color-mix(in srgb, var(--color-on-surface) 62%, transparent);
}
.entry-card__choice-text {
font-family: var(--font-body);
font-size: var(--text-body-md);
line-height: var(--leading-relaxed);
color: color-mix(in srgb, var(--color-on-surface) 84%, transparent);
text-wrap: pretty;
width: 100%;
}
.entry-card__choice-state {
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: var(--color-primary);
}
.entry-card__choice--selected {
background-color: color-mix(in srgb, var(--color-primary-container) 56%, transparent);
}
.entry-card__choice--selected .entry-card__choice-text {
color: var(--color-on-surface);
}
@media (max-width: 42rem) {
.previous-entries {
padding: var(--space-2);
}
.entry-card {
padding: var(--space-3);
}
}
</style>