yarn build
export VERSION=${GITREF/*v/}
mkdir nominatim-ui-${VERSION}
- mv dist LICENSE README.md nominatim-ui-${VERSION}/
+ mv dist LICENSE README.md screenshot.png nominatim-ui-${VERSION}/
mkdir artifacts
tar czf artifacts/nominatim-ui-${VERSION}.tar.gz nominatim-ui-${VERSION}
zip -qr artifacts/nominatim-ui-${VERSION}.zip nominatim-ui-${VERSION}
.DS_Store
-dist/config.js
+dist/theme/config.theme.js
+dist/build/bundle.*
node_modules
# CHANGES
+* unreleased
+ * Add theming
+ * Replace config.js with config.default.js and theme/config.theme.js
+
* version 2.3.0 - 2021-02-19
* New top-level navigation: Search, Reverse, Search-by-id
# Developing Nominatim-UI
+[![Continuous Integration](https://github.com/osm-search/nominatim-ui/actions/workflows/ci.yml/badge.svg)](https://github.com/osm-search/nominatim-ui/actions/workflows/ci.yml)
+
## Background
The user interface used to be included in the geocoder. Thus the
first version avoid being a redesign and still uses some of the
-same configuration values.
+same configuration values. Version 2 was a full refactor using
+Svelte. Version 3 added theme and easier configuration.
Uses [svelte](https://svelte.dev/) framework,
[leaflet](https://leafletjs.com/) for map interaction,
Debugging user interface for [Nominatim](https://nominatim.org/)
([source](https://github.com/osm-search/Nominatim/)) geocoder.
-The frontend runs standalone as website and will requests data
-from a separate Nominatim API (either on the same server or
-remote).
-For technical details see [CONTRIBUTE.md](CONTRIBUTE.md) file.
+The frontend runs standalone as website and will request data
+from a separate Nominatim API running on http://localhost:80/nominatim/ (configurable, see below).
+
+Download a stable release from [https://github.com/osm-search/nominatim-ui/releases]().
+For technical background, how to develop and create a release see [CONTRIBUTE.md](CONTRIBUTE.md) file at [https://github.com/osm-search/nominatim-ui/]().
![Screenshot](screenshot.png)
## Starting the frontend
-* You can open the `dist` directory in your browser.
+You can either
+
+* open the `dist` directory in your browser.
-* If you have python installed (part of the Nominatim server installation):
+* if you have Python installed (part of the Nominatim API server installation):
1. `cd dist`
2. start webserver `python3 -m http.server 8765`
- 3. open http://localhost:8765/ in your browser
+ 3. open [http://localhost:8765/]() in your browser
-* Start a webserver using ([Big list of http static server one-liners](https://gist.github.com/willurd/5720255)) or configure Apache, nginx or other webservers to serve the `dist` directory.
+* start a webserver using ([Big list of http static server one-liners](https://gist.github.com/willurd/5720255)) or configure Apache, nginx or other webservers to serve the `dist` directory.
## Configuration
-Create a `dist/config.js` file, you can use `dist/config.example.js` as basis (just copy it). All settings are optional. Usually you want to set the `Nominatim_API_Endpoint` value at least.
-
-Defaults:
-
-| setting | default |
-|---|---|
-| `Nominatim_API_Endpoint` | http://localhost/nominatim/ (port 80) |
-| `Images_Base_Url` | images in [mapicons](dist/mapicons) |
-| `Search_AreaPolygons` | yes, print boundaries of search results on map |
-| `Reverse_Default_Search_Zoom` | 18 (house-number level) |
-| `Map_Default_Lat`, `Map_Default_Lon`, `Map_Default_Zoom` | display whole world |
-| `Map_Tile_URL` | load from openstreetmap.org |
-| `Map_Tile_Attribution` | [OpenStreetMap](https://openstreetmap.org/copyright) obviously |
-
-
-## Theming
+Defaults are set in `dist/config.default.js`.
+You can overwrite settings in `dist/config.theme.js`, for example:
-You can customize parts of the website by overwriting files in `dist/theme/`
+```javascript
+ Nominatim_Config.Nominatim_API_Endpoint = 'http://my-server:1234/';
+```
- * Set a `Page_Title` in the configuration
- * Logo
- * Content of Welcome and About&Help page
- * Additional CSS styling
+The `dist/theme/` directory also contains files make it easy to set a different
+logo image, colors, welcome and help text.
## License
<title>Nominatim Demo</title>
- <link rel="icon" type="image/png" href="theme/favicon-194x194.png" sizes="194x194" />
- <link rel="icon" type="image/png" href="theme/favicon-32x32.png" sizes="32x32" />
+ <link rel="icon" type="image/png" href="theme/favicon-194x194.png" sizes="194x194">
+ <link rel="icon" type="image/png" href="theme/favicon-32x32.png" sizes="32x32">
<link rel='stylesheet' href='build/bundle.css'>
<link rel='stylesheet' href='theme/style.css'>
- <script src='config.js'></script>
+ <script src='config.defaults.js'></script>
+ <script src='theme/config.theme.js'></script>
<script defer src='build/bundle.js'></script>
</head>
--- /dev/null
+// You can overwrite any defaults in dist/theme/config.theme.js
+
+let Nominatim_Config = {
+ Page_Title: 'Nominatim Demo',
+
+ // Where Nominatim API runs. Remember to add port if needed and trailing slash.
+ Nominatim_API_Endpoint: 'http://localhost/nominatim/',
+
+ // relative path or full URL
+ Images_Base_Url: 'mapicons/',
+
+ // If the API should return polygons to be displayed on the map
+ Search_AreaPolygons: true,
+
+ // ---- MAP ----
+ Reverse_Default_Search_Zoom: 18,
+ Map_Default_Lat: 20.0,
+ Map_Default_Lon: 0.0,
+ Map_Default_Zoom: 2,
+
+ // For what {x}, {y} etc stand for see
+ // https://leafletjs.com/reference-1.6.0.html#tilelayer
+ Map_Tile_URL: 'https://{s}.tile.osm.org/{z}/{x}/{y}.png',
+
+ // Can be text or HTML. To hide set to ''
+ Map_Tile_Attribution: '<a href="https://osm.org/copyright">OpenStreetMap contributors</a>'
+};
+++ /dev/null
-// The app loads an optional file config.js
-//
-// You can use this file as base for config.js (just copy or rename it), all
-// keys are optional.
-
-var Nominatim_Config = [];
-
-// Where Nominatim API runs. Remember to add port if needed and trailing slash.
-// Nominatim_Config['Nominatim_API_Endpoint'] = 'http://localhost/nominatim/';
-
-// Nominatim_Config['Images_Base_Url'] = '/mapicons/';
-
-// If the API should return polygons to be displayed on the map
-// Nominatim_Config['Search_AreaPolygons'] = 1;
-// Nominatim_Config['Reverse_Default_Search_Zoom'] = 18;
-
-// ---- MAP ----
-// For what {x}, {y} etc stand for see
-// https://leafletjs.com/reference-1.6.0.html#tilelayer
-// Nominatim_Config['Map_Tile_URL'] = 'https://{s}.tile.osm.org/{z}/{x}/{y}.png';
-
-// Can be text or HTML. To hide set to ''
-// Nominatim_Config['Map_Tile_Attribution'] = '<a href="https://osm.org/copyright">OpenStreetMap contributors</a>';
-
-// Nominatim_Config['Map_Default_Lat'] = 20.0;
-// Nominatim_Config['Map_Default_Lon'] = 0.0;
-// Nominatim_Config['Map_Default_Zoom'] = 2;
-
-// ---- BRANDING ----
-// Nominatim_Config['Page_Title'] = 'Nominatim Demo';
<title>Nominatim Demo</title>
- <link rel="icon" type="image/png" href="theme/favicon-194x194.png" sizes="194x194" />
- <link rel="icon" type="image/png" href="theme/favicon-32x32.png" sizes="32x32" />
+ <link rel="icon" type="image/png" href="theme/favicon-194x194.png" sizes="194x194">
+ <link rel="icon" type="image/png" href="theme/favicon-32x32.png" sizes="32x32">
<link rel='stylesheet' href='build/bundle.css'>
<link rel='stylesheet' href='theme/style.css'>
- <script src='config.js'></script>
+ <script src='config.defaults.js'></script>
+ <script src='theme/config.theme.js'></script>
<script defer src='build/bundle.js'></script>
</head>
<title>Nominatim Demo</title>
- <link rel="icon" type="image/png" href="theme/favicon-194x194.png" sizes="194x194" />
- <link rel="icon" type="image/png" href="theme/favicon-32x32.png" sizes="32x32" />
+ <link rel="icon" type="image/png" href="theme/favicon-194x194.png" sizes="194x194">
+ <link rel="icon" type="image/png" href="theme/favicon-32x32.png" sizes="32x32">
<link rel='stylesheet' href='build/bundle.css'>
<link rel='stylesheet' href='theme/style.css'>
- <script src='config.js'></script>
+ <script src='config.defaults.js'></script>
+ <script src='theme/config.theme.js'></script>
<script defer src='build/bundle.js'></script>
</head>
<title>Nominatim Demo</title>
- <link rel="icon" type="image/png" href="theme/favicon-194x194.png" sizes="194x194" />
- <link rel="icon" type="image/png" href="theme/favicon-32x32.png" sizes="32x32" />
+ <link rel="icon" type="image/png" href="theme/favicon-194x194.png" sizes="194x194">
+ <link rel="icon" type="image/png" href="theme/favicon-32x32.png" sizes="32x32">
<link rel='stylesheet' href='build/bundle.css'>
<link rel='stylesheet' href='theme/style.css'>
- <script src='config.js'></script>
+ <script src='config.defaults.js'></script>
+ <script src='theme/config.theme.js'></script>
<script defer src='build/bundle.js'></script>
</head>
<title>Nominatim Demo</title>
- <link rel="icon" type="image/png" href="theme/favicon-194x194.png" sizes="194x194" />
- <link rel="icon" type="image/png" href="theme/favicon-32x32.png" sizes="32x32" />
+ <link rel="icon" type="image/png" href="theme/favicon-194x194.png" sizes="194x194">
+ <link rel="icon" type="image/png" href="theme/favicon-32x32.png" sizes="32x32">
<link rel='stylesheet' href='build/bundle.css'>
<link rel='stylesheet' href='theme/style.css'>
- <script src='config.js'></script>
+ <script src='config.defaults.js'></script>
+ <script src='theme/config.theme.js'></script>
<script defer src='build/bundle.js'></script>
</head>
<title>Nominatim Demo</title>
- <link rel="icon" type="image/png" href="theme/favicon-194x194.png" sizes="194x194" />
- <link rel="icon" type="image/png" href="theme/favicon-32x32.png" sizes="32x32" />
+ <link rel="icon" type="image/png" href="theme/favicon-194x194.png" sizes="194x194">
+ <link rel="icon" type="image/png" href="theme/favicon-32x32.png" sizes="32x32">
<link rel='stylesheet' href='build/bundle.css'>
<link rel='stylesheet' href='theme/style.css'>
- <script src='config.js'></script>
+ <script src='config.defaults.js'></script>
+ <script src='theme/config.theme.js'></script>
<script defer src='build/bundle.js'></script>
</head>
import Error from './Error.svelte';
import { page } from '../lib/stores.js';
- import { get_config_value } from '../lib/config_reader.js';
$: view = $page.tab;
+ $: page_title = Nominatim_Config.Page_Title;
</script>
<style>
<div class="navbar-brand">
<PageLink page="search">
<img alt="logo" id="theme-logo" src="theme/logo.png" />
- <h1>{get_config_value('Page_Title')}</h1>
+ <h1>{page_title}</h1>
</PageLink>
</div>
<!-- Toggler (hamburger button) -->
import 'leaflet-minimap/dist/Control.MiniMap.min.css';
import { get } from 'svelte/store';
- import { get_config_value } from '../lib/config_reader.js';
import { map_store } from '../lib/stores.js';
import MapPosition from '../components/MapPosition.svelte';
let dataLayers = [];
function createMap(container) {
- const attribution = get_config_value('Map_Tile_Attribution') || null;
+ const attribution = Nominatim_Config.Map_Tile_Attribution;
let map = new L.map(container, {
attributionControl: (attribution && attribution.length),
scrollWheelZoom: true, // !L.Browser.touch,
touchZoom: false,
center: [
- get_config_value('Map_Default_Lat'),
- get_config_value('Map_Default_Lon')
+ Nominatim_Config.Map_Default_Lat,
+ Nominatim_Config.Map_Default_Lon
],
- zoom: get_config_value('Map_Default_Zoom')
+ zoom: Nominatim_Config.Map_Default_Zoom
});
- L.tileLayer(get_config_value('Map_Tile_URL'), {
+ L.tileLayer(Nominatim_Config.Map_Tile_URL, {
attribution: attribution
}).addTo(map);
if (display_minimap) {
- let osm2 = new L.TileLayer(get_config_value('Map_Tile_URL'), {
+ let osm2 = new L.TileLayer(Nominatim_Config.Map_Tile_URL, {
minZoom: 0,
maxZoom: 13,
attribution: attribution
<script>
export let aPlace;
- import { get_config_value } from '../lib/config_reader.js';
let sIcon = getIcon(aPlace.category, aPlace.type);
let title = 'icon for ' + aPlace.category + ' ' + aPlace.type;
- let url = get_config_value('Images_Base_Url') + sIcon + '.p.20.png';
+ let url = Nominatim_Config.Images_Base_Url + sIcon + '.p.20.png';
function getIcon(category, type) {
// equivalent to PHP Nominatim::ClassTypes::getIcon
-
-import { get_config_value } from './config_reader.js';
import { last_api_request_url_store, error_store } from './stores.js';
-
function api_request_progress(status) {
var loading_el = document.getElementById('loading');
if (!loading_el) return; // might not be on page yet
await fetch(url)
.then(response => response.text())
.then(html => {
- html = html.replace('Nominatim_API_Endpoint', get_config_value('Nominatim_API_Endpoint'));
+ html = html.replace('Nominatim_API_Endpoint', Nominatim_Config.Nominatim_API_Endpoint);
dom_element.innerHTML = html;
fetch_content_cache[url] = html;
});
}
function generate_nominatim_api_url(endpoint_name, params) {
- return get_config_value('Nominatim_API_Endpoint') + endpoint_name + '.php?'
+ return Nominatim_Config.Nominatim_API_Endpoint + endpoint_name + '.php?'
+ Object.keys(clean_up_parameters(params)).map((k) => {
return encodeURIComponent(k) + '=' + encodeURIComponent(params[k]);
}).join('&');
}
export function update_html_title(title) {
- document.title = [title, get_config_value('Page_Title')]
+ document.title = [title, Nominatim_Config.Page_Title]
.filter((val) => val && val.length > 1)
.join(' | ');
}
+++ /dev/null
-module.exports.get_config_value = get_config_value;
-
-
-const Nominatim_Config_Defaults = {
- Nominatim_API_Endpoint: 'http://localhost/nominatim/',
- Images_Base_Url: 'mapicons/',
- Search_AreaPolygons: 1,
- Reverse_Default_Search_Zoom: 18,
- Map_Default_Lat: 20.0,
- Map_Default_Lon: 0.0,
- Map_Default_Zoom: 2,
- Map_Tile_URL: 'https://{s}.tile.osm.org/{z}/{x}/{y}.png',
- Map_Tile_Attribution: '<a href="https://osm.org/copyright">OpenStreetMap contributors</a>',
- Page_Title: 'Nominatim Demo'
-};
-
-function get_config_value(str, default_val) {
- var value = ((typeof Nominatim_Config !== 'undefined')
- && (typeof Nominatim_Config[str] !== 'undefined'))
- ? Nominatim_Config[str]
- : Nominatim_Config_Defaults[str];
- return (typeof value !== 'undefined' ? value : default_val);
-}
<script>
import { page, results_store } from '../lib/stores.js';
- import { get_config_value } from '../lib/config_reader.js';
import { fetch_from_api, update_html_title } from '../lib/api_utils.js';
import Header from '../components/Header.svelte';
lon: search_params.get('lon'),
zoom: (search_params.get('zoom') > 1
? Number(search_params.get('zoom'))
- : Number(get_config_value('Reverse_Default_Search_Zoom'))),
+ : Number(Nominatim_Config.Reverse_Default_Search_Zoom)),
format: 'jsonv2'
};
<script>
import { page, results_store } from '../lib/stores.js';
- import { get_config_value } from '../lib/config_reader.js';
import { fetch_from_api, update_html_title } from '../lib/api_utils.js';
import Header from '../components/Header.svelte';
state: search_params.get('state'),
country: search_params.get('country'),
postalcode: search_params.get('postalcode'),
- polygon_geojson: get_config_value('Search_AreaPolygons', false) ? 1 : 0,
+ polygon_geojson: Nominatim_Config.Search_AreaPolygons ? 1 : 0,
viewbox: search_params.get('viewbox'),
bounded: search_params.get('bounded'),
dedupe: search_params.get('dedupe'),