Skip to content

Commit

Permalink
SearchBox: add search by categories + overpass (#186)
Browse files Browse the repository at this point in the history
  • Loading branch information
zbycz authored Sep 30, 2023
1 parent 1b6af16 commit d7651e9
Show file tree
Hide file tree
Showing 28 changed files with 818 additions and 75 deletions.
3 changes: 3 additions & 0 deletions .gitpod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
tasks:
- init: yarn
command: yarn dev
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
},
"scripts": {
"dev": "next",
"test": "jest",
"lint": "eslint . --report-unused-disable-directives",
"lintfix": "prettier . --write && eslint ./src ./pages --report-unused-disable-directives --fix",
"prettify": "prettier . --write",
Expand Down Expand Up @@ -34,7 +35,6 @@
"@openstreetmap/id-tagging-schema": "^6.1.0",
"@sentry/browser": "^6.5.1",
"@sentry/node": "^6.5.1",
"@types/maplibre-gl": "^1.13.1",
"accept-language-parser": "^1.5.0",
"autosuggest-highlight": "^3.1.1",
"isomorphic-unfetch": "^3.1.0",
Expand All @@ -57,6 +57,7 @@
"styled-jsx": "^3.4.4"
},
"devDependencies": {
"@types/autosuggest-highlight": "^3.2.0",
"@types/jest": "^26.0.23",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"babel-eslint": "^10.1.0",
Expand Down
8 changes: 8 additions & 0 deletions src/components/FeaturePanel/OsmError.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,13 @@ export const OsmError = () => {
);
}

if (Object.keys(feature.tags).length === 0 && !feature.point) {
return (
<Alert variant="outlined" severity="info">
{t('featurepanel.info_no_tags')}
</Alert>
);
}

return null;
};
4 changes: 2 additions & 2 deletions src/components/Map/behaviour/useUpdateStyle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { osmappLayers } from '../../LayerSwitcher/osmappLayers';
import { rasterStyle } from '../styles/rasterStyle';
import { DEFAULT_MAP } from '../../../config';

export const getRasterLayer = (key) => {
export const getRasterStyle = (key) => {
const url = osmappLayers[key]?.url ?? key; // if `key` not found, it contains tiles URL
return rasterStyle(key, url);
};
Expand All @@ -18,6 +18,6 @@ export const useUpdateStyle = useMapEffect((map, activeLayers) => {
? basicStyle
: key === 'outdoor'
? outdoorStyle
: getRasterLayer(key),
: getRasterStyle(key),
);
});
8 changes: 8 additions & 0 deletions src/components/Map/consts.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// https://cloud.maptiler.com/account

const apiKey = '7dlhLl3hiXQ1gsth0kGu';

export const OSMAPP_SPRITE = `${window.location.protocol}//${window.location.host}/sprites/osmapp`;
Expand Down Expand Up @@ -28,6 +29,13 @@ export const OSMAPP_SOURCES = {
url: `https://api.maptiler.com/tiles/outdoor/tiles.json?key=${apiKey}`,
type: 'vector' as const,
},
overpass: {
type: 'geojson' as const,
data: {
type: 'FeatureCollection',
features: [],
},
},
};

export const BACKGROUND = [
Expand Down
7 changes: 6 additions & 1 deletion src/components/Map/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const isOsmLayer = (id) => {
if (id.startsWith('place-country-')) return false; // https://github.com/zbycz/osmapp/issues/35
if (id === 'place-continent') return false;
if (id === 'water-name-ocean') return false;
const prefixes = ['water-name-', 'poi-', 'place-'];
const prefixes = ['water-name-', 'poi-', 'place-', 'overpass-'];
return prefixes.some((prefix) => id.startsWith(prefix));
};

Expand All @@ -23,6 +23,11 @@ export const getIsOsmObject = ({ id, layer }) => {
if (layer.id === 'water-name-other' && id < 10e5) {
return false;
}

if (layer.id?.startsWith('overpass')) {
return true;
}

return layersWithOsmId.includes(layer.id);
};

Expand Down
2 changes: 2 additions & 0 deletions src/components/Map/styles/basicStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { poiLayers } from './layers/poiLayers';
import { addHoverPaint } from '../behaviour/featureHover';
import { BACKGROUND, GLYPHS, OSMAPP_SOURCES, OSMAPP_SPRITE } from '../consts';
import { motorwayConstruction } from './layers/contruction';
import { overpassLayers } from './layers/overpassLayers';

export const basicStyle = addHoverPaint({
version: 8,
Expand Down Expand Up @@ -2835,6 +2836,7 @@ export const basicStyle = addHoverPaint({
},
},
...poiLayers,
...overpassLayers,
],
id: 'ciw6czz2n00242kmg6hw20box',
});
120 changes: 120 additions & 0 deletions src/components/Map/styles/layers/overpassLayers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import type { LayerSpecification } from '@maplibre/maplibre-gl-style-spec';

export const overpassLayers: LayerSpecification[] = [
{
id: 'overpass-line-casing',
type: 'line',
source: 'overpass',
paint: {
'line-color': '#f8f4f0',
'line-width': 6,
},
},
{
id: 'overpass-line',
type: 'line',
source: 'overpass',
paint: {
'line-color': '#f00',
'line-width': 2,
'line-opacity': [
'case',
['boolean', ['feature-state', 'hover'], false],
0.5,
1,
],
},
},
{
id: 'overpass-line-text',
type: 'symbol',
source: 'overpass',
layout: {
'symbol-placement': 'line',
'text-font': ['Noto Sans Regular'],
'text-field': '{name}',
'text-size': 12,
'text-rotation-alignment': 'map',
},
paint: {
'text-color': '#000000',
'text-halo-width': 1.5,
'text-halo-color': 'rgba(255,255,255,0.7)',
'text-opacity': [
'case',
['boolean', ['feature-state', 'hover'], false],
0.5,
1,
],
},
},
{
id: 'overpass-fill',
type: 'fill',
source: 'overpass',
filter: ['all', ['==', '$type', 'Polygon']],
paint: {
'fill-color': '#f00',
'fill-opacity': [
'case',
['boolean', ['feature-state', 'hover'], false],
0.2,
0.5,
],
},
},
{
id: 'overpass-circle',
type: 'circle',
source: 'overpass',
filter: ['all', ['==', '$type', 'Point']],
paint: {
'circle-color': 'rgba(255,255,255,0.9)',
'circle-radius': 12,
'circle-stroke-width': 1,
'circle-stroke-color': 'rgba(255,0,0,0.9)',
'circle-opacity': [
'case',
['boolean', ['feature-state', 'hover'], false],
0.5,
1,
],
},
},
{
id: 'overpass-symbol',
type: 'symbol',
source: 'overpass',
filter: ['all', ['==', '$type', 'Point']],
layout: {
'text-padding': 2,
'text-font': ['Noto Sans Regular'],
'text-anchor': 'top',
'icon-image': '{class}_11',
'text-field': '{name}',
'text-offset': [0, 0.6],
'text-size': 12,
'text-max-width': 9,
'icon-allow-overlap': true,
'icon-ignore-placement': true,
},
paint: {
// 'text-halo-blur': 0.5,
'text-color': '#000',
'text-halo-width': 1.5,
'text-halo-color': 'rgba(255,255,255,0.7)',
'icon-opacity': [
'case',
['boolean', ['feature-state', 'hover'], false],
0.5,
1,
],
'text-opacity': [
'case',
['boolean', ['feature-state', 'hover'], false],
0.5,
1,
],
},
},
];
5 changes: 3 additions & 2 deletions src/components/Map/styles/layers/poiLayers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// originaly from basicStyle
import type { LayerSpecification } from '@maplibre/maplibre-gl-style-spec';

export const poiLayers = [
// originaly from basicStyle
export const poiLayers: LayerSpecification[] = [
{
id: 'poi-level-3',
type: 'symbol',
Expand Down
2 changes: 2 additions & 0 deletions src/components/Map/styles/outdoorStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { poiLayers } from './layers/poiLayers';
import { addHoverPaint } from '../behaviour/featureHover';
import { BACKGROUND, GLYPHS, OSMAPP_SOURCES, OSMAPP_SPRITE } from '../consts';
import { motorwayConstruction } from './layers/contruction';
import { overpassLayers } from './layers/overpassLayers';

// TODO add icons for outdoor to our sprite (guideposts, benches, etc)
// https://api.maptiler.com/maps/outdoor/sprite.png?key=7dlhLl3hiXQ1gsth0kGu
Expand Down Expand Up @@ -3884,6 +3885,7 @@ export const outdoorStyle = addHoverPaint({
'source-layer': 'place',
},
...poiLayers,
...overpassLayers,
],
bearing: 0,
sources: OSMAPP_SOURCES,
Expand Down
2 changes: 2 additions & 0 deletions src/components/Map/styles/rasterStyle.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { StyleSpecification } from '@maplibre/maplibre-gl-style-spec';
import { GLYPHS, OSMAPP_SOURCES, OSMAPP_SPRITE } from '../consts';
import { overpassLayers } from './layers/overpassLayers';

const getSource = (url) => {
if (url.match('{bingSubdomains}')) {
Expand Down Expand Up @@ -38,6 +39,7 @@ export const rasterStyle = (id, url): StyleSpecification => {
minzoom: 0,
},
// ...poiLayers, // TODO maybe add POIs
...overpassLayers,
],
sources: {
...OSMAPP_SOURCES, // keep default sources for faster switching
Expand Down
45 changes: 42 additions & 3 deletions src/components/SearchBox/AutocompleteInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,30 @@ import { t } from '../../services/intl';
import { onHighlightFactory, onSelectedFactory } from './onSelectedFactory';
import { useMobileMode } from '../helpers';
import { useUserThemeContext } from '../../helpers/theme';
import { useMapStateContext } from '../utils/MapStateContext';

const useFocusOnSlash = () => {
const inputRef = React.useRef<HTMLInputElement>(null);

useEffect(() => {
const onKeydown = (e) => {
if (e.key === '/') {
e.preventDefault();
inputRef.current?.focus();
}
};
window.addEventListener('keydown', onKeydown);

return () => {
window.removeEventListener('keydown', onKeydown);
};
}, []);

return inputRef;
};

const SearchBoxInput = ({ params, setInputValue, autocompleteRef }) => {
const inputRef = useFocusOnSlash();
const { InputLabelProps, InputProps, ...restParams } = params;

useEffect(() => {
Expand All @@ -21,8 +43,9 @@ const SearchBoxInput = ({ params, setInputValue, autocompleteRef }) => {

return (
<InputBase
placeholder={t('searchbox.placeholder')}
{...restParams} // eslint-disable-line react/jsx-props-no-spreading
inputRef={inputRef}
placeholder={t('searchbox.placeholder')}
onChange={onChange}
onFocus={onFocus}
/>
Expand All @@ -36,18 +59,34 @@ export const AutocompleteInput = ({
autocompleteRef,
}) => {
const { setFeature, setPreview } = useFeatureContext();
const { bbox, showToast } = useMapStateContext();
const mobileMode = useMobileMode();
const { currentTheme } = useUserThemeContext();
return (
<Autocomplete
inputValue={inputValue}
options={options}
// we need null to be able to select the same again (eg. category search)
value={null}
filterOptions={(x) => x}
getOptionLabel={(option) =>
option.properties.name || buildPhotonAddress(option.properties)
option.properties?.name ||
option.preset?.presetForSearch?.name ||
(option.overpass &&
Object.entries(option.overpass)
?.map(([k, v]) => `${k}=${v}`)
.join(' ')) ||
(option.loader ? '' : buildPhotonAddress(option.properties))
}
onChange={onSelectedFactory(setFeature, setPreview, mobileMode)}
onChange={onSelectedFactory(
setFeature,
setPreview,
mobileMode,
bbox,
showToast,
)}
onHighlightChange={onHighlightFactory(setPreview)}
getOptionDisabled={(o) => o.loader}
autoComplete
disableClearable
autoHighlight
Expand Down
Loading

1 comment on commit d7651e9

@vercel
Copy link

@vercel vercel bot commented on d7651e9 Sep 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

osmapp – ./

osmapp.vercel.app
osmapp-git-master-zbycz.vercel.app
osmapp.org
osmapp-zbycz.vercel.app

Please sign in to comment.