Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions web/src/search/search.css
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,7 @@
.search-badge-village {
background-color: #7a4bbd;
}

.search-badge-shower {
background-color: #157a8a;
}
2 changes: 2 additions & 0 deletions web/src/search/searchcontrol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const categoryZoom: Record<SearchCategory, number> = {
structure: 18,
gate: 17.5,
village: 17.5,
shower: 17,
area: 17,
camping: 16.5,
parking: 16.5,
Expand All @@ -22,6 +23,7 @@ const categoryLabel: Record<SearchCategory, string> = {
parking: 'parking',
gate: 'gate',
village: 'village',
shower: 'shower',
}

const emptyCollection: GeoJSON.FeatureCollection = { type: 'FeatureCollection', features: [] }
Expand Down
30 changes: 25 additions & 5 deletions web/src/search/searchindex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ import Pbf from 'pbf'
import maplibregl, { GeoJSONSource } from 'maplibre-gl'
import { center } from '../style/map_style.ts'

export type SearchCategory = 'structure' | 'area' | 'camping' | 'parking' | 'gate' | 'village'
export type SearchCategory = 'structure' | 'area' | 'camping' | 'parking' | 'gate' | 'village' | 'shower'

export interface SearchEntry {
displayName: string
normalized: string
category: SearchCategory
coords: [number, number]
importance: number
/* Crew-only feature: hidden from results unless the query mentions "crew",
so e.g. "kitchen" doesn't surface the Crew Kitchen. Shared features that
merely happen to name crew (e.g. "Long Stay / Crew" parking) are not
flagged, so they stay findable by their public name. */
crewOnly: boolean
}

export interface SearchIndex {
Expand Down Expand Up @@ -63,12 +68,14 @@ function makeEntry(
importance: number
): SearchEntry | undefined {
if (geometry?.type !== 'Point' || !validCoords(geometry.coordinates)) return undefined
const normalized = normalize(displayName)
return {
displayName,
normalized: normalize(displayName),
normalized,
category,
coords: geometry.coordinates as [number, number],
importance,
crewOnly: /^crew\b/.test(normalized),
}
}

Expand All @@ -86,13 +93,25 @@ const extractors: LayerExtractor[] = [
{
sourceLayer: 'structure_centroid',
category: 'structure',
displayName: (props) => (props.name ? String(props.name) : undefined),
// Shower-named structures are back-of-house (e.g. crew showers). Public
// showers are their own `showers`-typed area (below), so keep any
// shower-named structure out of public search.
displayName: (props) =>
props.name && !/shower/i.test(String(props.name)) ? String(props.name) : undefined,
importance: (props) => (typeof props.importance === 'number' ? props.importance : 0),
},
{
sourceLayer: 'areas_event_centroid',
category: 'shower',
displayName: (props) => (props.type === 'showers' && props.name ? String(props.name) : undefined),
importance: constImportance,
},
{
sourceLayer: 'areas_event_centroid',
category: 'area',
displayName: (props) => (props.name && props.type !== 'toilets' ? String(props.name) : undefined),
// toilets are unlabelled; showers are indexed separately as their own category
displayName: (props) =>
props.name && props.type !== 'toilets' && props.type !== 'showers' ? String(props.name) : undefined,
importance: constImportance,
},
{
Expand Down Expand Up @@ -241,9 +260,10 @@ function score(entry: SearchEntry, query: string): number {
export function search(index: SearchEntry[], query: string, limit: number = 20): SearchEntry[] {
const q = normalize(query)
if (!q) return []
const wantsCrew = q.includes('crew')
return index
.map((entry) => ({ entry, score: score(entry, q) }))
.filter((item) => item.score > 0)
.filter((item) => item.score > 0 && (wantsCrew || !item.entry.crewOnly))
.sort(
(a, b) =>
b.score - a.score ||
Expand Down