feat(web): add AlphabeticalGrid wrapper with letter dividers
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
<script lang="ts" generics="T">
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
let {
|
||||
items,
|
||||
getKey,
|
||||
item
|
||||
}: {
|
||||
items: T[];
|
||||
getKey: (it: T) => string;
|
||||
item: Snippet<[T]>;
|
||||
} = $props();
|
||||
|
||||
// Compute the divider letter for each item; if it differs from the
|
||||
// previous item's letter, that index gets a divider above it.
|
||||
const segments = $derived.by(() => {
|
||||
const out: { divider: string | null; item: T }[] = [];
|
||||
let last: string | null = null;
|
||||
for (const it of items) {
|
||||
const k = (getKey(it) || '').charAt(0).toUpperCase();
|
||||
if (k !== last) {
|
||||
out.push({ divider: k, item: it });
|
||||
last = k;
|
||||
} else {
|
||||
out.push({ divider: null, item: it });
|
||||
}
|
||||
}
|
||||
return out;
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="alpha-grid">
|
||||
{#each segments as seg, i (i)}
|
||||
{#if seg.divider}
|
||||
<div class="divider">
|
||||
<span class="letter">{seg.divider}</span>
|
||||
<span class="rule"></span>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="cell">
|
||||
{@render item(seg.item)}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.alpha-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
.divider {
|
||||
grid-column: 1 / -1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding-top: 8px;
|
||||
}
|
||||
.letter {
|
||||
font-family: var(--fs-font-display);
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
color: var(--fs-parchment);
|
||||
}
|
||||
.rule {
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: var(--fs-pewter);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user