173 lines
4 KiB
Svelte
173 lines
4 KiB
Svelte
<script lang="ts">
|
|
type Props = {
|
|
options: { label: string; id: string }[];
|
|
onSelect: (optionId: string) => void;
|
|
};
|
|
|
|
const { options, onSelect }: Props = $props();
|
|
|
|
let isSubmitting = $state(false);
|
|
|
|
const handleOptionSelect = async (optionId: string) => {
|
|
if (isSubmitting) {
|
|
return;
|
|
}
|
|
|
|
isSubmitting = true;
|
|
try {
|
|
await onSelect(optionId);
|
|
} finally {
|
|
isSubmitting = false;
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<section class="next-steps" aria-label="Choose what happens next">
|
|
<header class="next-steps__header">
|
|
<p class="next-steps__kicker">Choose your path</p>
|
|
<h2 class="next-steps__title">What happens next?</h2>
|
|
</header>
|
|
|
|
<ol class="next-steps__list">
|
|
{#each options as option, index (option.id)}
|
|
<li class="next-steps__item">
|
|
<button
|
|
class="next-steps__button"
|
|
onclick={() => handleOptionSelect(option.id)}
|
|
disabled={isSubmitting}
|
|
>
|
|
<span class="next-steps__index" aria-hidden="true"
|
|
>{String(index + 1).padStart(2, '0')}</span
|
|
>
|
|
<span class="next-steps__label">{option.label}</span>
|
|
<span class="next-steps__meta" aria-hidden="true">Choose</span>
|
|
</button>
|
|
</li>
|
|
{/each}
|
|
</ol>
|
|
</section>
|
|
|
|
<style>
|
|
.next-steps {
|
|
--next-steps-surface: var(--color-surface-container-low);
|
|
--next-steps-surface-hover: var(--color-surface-container-lowest);
|
|
|
|
max-width: 72ch;
|
|
margin: var(--space-6) auto 0;
|
|
padding: clamp(1rem, 0.9rem + 0.9vw, 1.8rem);
|
|
border-radius: var(--radius-xl);
|
|
background-color: var(--next-steps-surface);
|
|
}
|
|
|
|
.next-steps__header {
|
|
margin-bottom: var(--space-4);
|
|
}
|
|
|
|
.next-steps__kicker {
|
|
margin: 0;
|
|
font-family: var(--font-label);
|
|
font-size: var(--text-label-md);
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
color: color-mix(in srgb, var(--color-on-surface) 70%, transparent);
|
|
}
|
|
|
|
.next-steps__title {
|
|
margin: var(--space-1) 0 0;
|
|
font-family: var(--font-display);
|
|
font-size: clamp(1.35rem, 1.2rem + 0.9vw, 2rem);
|
|
line-height: 1.15;
|
|
color: var(--color-on-surface);
|
|
}
|
|
|
|
.next-steps__list {
|
|
list-style: none;
|
|
padding: 0;
|
|
margin: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-3);
|
|
}
|
|
|
|
.next-steps__item {
|
|
margin: 0;
|
|
}
|
|
|
|
.next-steps__button {
|
|
width: 100%;
|
|
display: grid;
|
|
grid-template-columns: auto 1fr auto;
|
|
align-items: center;
|
|
gap: var(--space-3);
|
|
padding: clamp(0.9rem, 0.8rem + 0.5vw, 1.2rem);
|
|
border: none;
|
|
border-radius: var(--radius-lg);
|
|
background: var(--color-surface-container);
|
|
text-align: left;
|
|
cursor: pointer;
|
|
transition:
|
|
transform var(--duration-fast) var(--ease-standard),
|
|
background-color var(--duration-fast) var(--ease-standard);
|
|
}
|
|
|
|
.next-steps__index {
|
|
font-family: var(--font-label);
|
|
font-size: var(--text-label-md);
|
|
font-weight: var(--weight-semibold);
|
|
letter-spacing: 0.08em;
|
|
color: color-mix(in srgb, var(--color-on-surface) 72%, transparent);
|
|
}
|
|
|
|
.next-steps__label {
|
|
font-family: var(--font-body);
|
|
font-size: clamp(1rem, 0.95rem + 0.3vw, 1.18rem);
|
|
line-height: 1.35;
|
|
color: var(--color-on-surface);
|
|
text-wrap: pretty;
|
|
}
|
|
|
|
.next-steps__meta {
|
|
font-family: var(--font-label);
|
|
font-size: var(--text-label-md);
|
|
font-weight: var(--weight-medium);
|
|
letter-spacing: var(--tracking-wide);
|
|
text-transform: uppercase;
|
|
line-height: 1;
|
|
color: color-mix(in srgb, var(--color-primary) 72%, var(--color-on-surface));
|
|
}
|
|
|
|
.next-steps__button:hover:enabled {
|
|
background: var(--next-steps-surface-hover);
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.next-steps__button:hover:enabled .next-steps__meta,
|
|
.next-steps__button:focus-visible .next-steps__meta {
|
|
color: var(--color-primary);
|
|
}
|
|
|
|
.next-steps__button:focus-visible {
|
|
outline: 2px solid color-mix(in srgb, var(--colour-outline-variant) 20%, transparent);
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
.next-steps__button:disabled {
|
|
opacity: 0.7;
|
|
cursor: progress;
|
|
}
|
|
|
|
@media (max-width: 42rem) {
|
|
.next-steps {
|
|
margin-top: var(--space-4);
|
|
padding: var(--space-3);
|
|
}
|
|
|
|
.next-steps__button {
|
|
grid-template-columns: auto 1fr;
|
|
}
|
|
|
|
.next-steps__meta {
|
|
display: none;
|
|
}
|
|
}
|
|
</style>
|