Listings browser

Every home, filtered and paged in the browser.

The block on the listings page (ADR 0039): a white filter panel (a location picker of cities and their neighbourhoods, room chips, a rent range, and "more filters" opening in place: size, move-in date, status), then a live result count with the sort, one page ofListingCards in the shared grid, and numbered pagination.

The browser holds an index, not the cards. The page ships the first page of cards; the script fetches the index (every unit's filter fields, about 100 bytes each) from one JSON file that every page of the browser shares, filters and sorts it, and fetches each further card once, from a fragment built by the same ListingCard. Here every card is rendered up front, so only the index is fetched.

The state lives in the URL, replaced in place. With no JavaScript the first page shows and the controls are inert; the pagination is drawn by the script, so it is absent rather than broken.

Five homes, two a page

Tone
6.500 kr.–11.500 kr.

4 homes

Props

packages/primitives/src/ListingsBrowser.astro
PropTypeRequired
index

For the counts the server draws. Not put in the page: the script reads the same index from `indexUrl`.

IndexEntry[]yes
indexUrl

Where the index is served as JSON, exactly as `index`.

stringyes
listings

The cards rendered at build time, in index order.

Card[]yes
cardUrl

A URL with "{id}", answering with one card's fragment.

stringyes
pageSizenumber—
locale

Formats the ranges' numbers.

stringyes
places

Counts are of the default view, which leaves let homes out; the script recounts them as the status toggles change.

Place[]yes
roomFilters

Keys "1", "2", "3", "4+"; "4+" matches four rooms or more.

Facet[]yes
rentRange

A range is left out when every home has the same value.

Range & { currency: string }—
sizeRangeRange—
sortOptions

The first is the default. Keys: "move-in", "rent", "area".

Option[]yes
placeUrls

The page of each place that has one (ADR 0043), by the picker's key: a city's name, "city/neighbourhood", or "" for every place. Closing the picker on one of them goes to its page.

Record<string, string>—
ownPlace

The place this page is about, by the same key; picked when the URL names none, and left out of the URL.

string—
listLabelstringyes
locationLabelstringyes
anywhereLabelstringyes
placeSearchLabelstringyes
areasInLabel

"{city}" template.

stringyes
otherAreaLabelstringyes
selectAllLabelstringyes
noPlaceMatchLabelstringyes
clearLabelstringyes
clearLocationLabelstringyes
showCountOne

"{count}" templates.

stringyes
showCountOtherstringyes
roomsLabelstringyes
filterRoomsLabelstringyes
rentLabelstringyes
rentMinLabelstringyes
rentMaxLabelstringyes
sizeLabelstringyes
sizeMinLabelstringyes
sizeMaxLabelstringyes
moreFiltersLabelstringyes
moveInByLabelstringyes
filterStatusLabel

The status toggles: their group's name, then each toggle's label. A toggle shows only when the index holds a home it would change.

stringyes
showLetLabelstringyes
hideReservedLabelstringyes
resetLabelstringyes
sortLabelstringyes
countLabelOne

"{count}" templates.

stringyes
countLabelOtherstringyes
emptyLabelstringyes
emptyLetOne

"{count}" templates: the empty grid when let homes, hidden by default, would match. Said with a button that shows them.

stringyes
emptyLetOtherstringyes
loadErrorLabelstringyes
paginationLabelstringyes
prevLabelstringyes
nextLabelstringyes
pageLabel

"{page}" template, the accessible name of a page link.

stringyes
cardHeadingLevel1 | 2 | 3 | 4 | 5 | 6—
IndexEntry — referenced by a prop above
FieldTypeRequired
idstringyes
place

A key of an area in `places`, "city/neighbourhood".

stringyes
roomsnumber | nullyes
rentnumber | nullyes
areanumber | nullyes
from

ISO date; null sorts as "now".

string | nullyes
status

Let homes are hidden until the reader asks for them.

"available" | "reserved" | "let"yes
Facet — referenced by a prop above
FieldTypeRequired
keystringyes
labelstringyes
countnumberyes
Range — referenced by a prop above
FieldTypeRequired
minnumberyes
maxnumberyes
stepnumberyes
Option — referenced by a prop above
FieldTypeRequired
valuestringyes
labelstringyes