Search titles and sections of every page. ↑↓ to move, ↵ to open

Tutorial

6. Filtering

1 min read Edit on GitHub

A reading list is mostly about what's left to read. The shelf should show the unread links first, with the read ones a click away.

The filter goes in the URL: /?show=read. That way it survives a reload, works with the back button, and can be shared as a link, and the load reads it like any other part of the request.

#The load

In src/routes/page.server.go, read show from the query and pass it to List, which already takes it:

type Data struct {
	Links []shelf.Link `json:"links"`
	Show  string       `json:"show"`
}

func Load(ctx *kit.Ctx) (Data, error) {
	show := ctx.URL().Query().Get("show")
	if show != "read" && show != "all" {
		show = "unread"
	}
	links, err := shelf.List(ctx, show)
	if err != nil {
		return Data{}, err
	}
	return Data{Links: links, Show: show}, nil
}

Anything other than read or all means unread, so a mistyped URL still shows something sensible.

#The page

In src/routes/+page.svelte, list the filters in the script:

const filters = [
	{ show: 'unread', label: 'To read' },
	{ show: 'read', label: 'Read' },
	{ show: 'all', label: 'All' }
];

Put them above the list, and say what's missing when a filter is empty:

<nav class="filters" aria-label="Show">
	{#each filters as f (f.show)}
		<a href="?show={f.show}" aria-current={data.show === f.show ? 'page' : undefined}>{f.label}</a>
	{/each}
</nav>

{#if data.links.length === 0}
	<p class="empty">{data.show === 'read' ? 'Nothing read yet.' : 'Nothing here. Save a link above.'}</p>
{:else}

And style them:

.filters {
	display: flex;
	gap: 0.25rem;
	margin-bottom: 0.5rem;
}
.filters a {
	padding: 0.25rem 0.75rem;
	border-radius: 999px;
	color: var(--tern-muted);
	font-size: 0.875rem;
	text-decoration: none;
}
.filters a[aria-current='page'] {
	background: var(--tern-surface);
	color: var(--tern-fg);
}

The filters are plain links. When you click one, the router sees that it's the same page with a different query, asks the server for the page's data only, and updates the list. No code of yours handles the click. Mark a link read on its page, go back, and it has moved from "To read" to "Read".

Next: Accounts.