Merge pull request 'Various UI improvements' (#63) from ui/various into master
Reviewed-on: #63
This commit was merged in pull request #63.
This commit is contained in:
@@ -23,6 +23,7 @@ export default class PlaceDetails extends Component {
|
||||
@service storage;
|
||||
@service nostrAuth;
|
||||
@service nostrData;
|
||||
@service mapUi;
|
||||
@tracked isEditing = false;
|
||||
@tracked showLists = false;
|
||||
@tracked isPhotoUploadActive = false;
|
||||
@@ -345,9 +346,21 @@ export default class PlaceDetails extends Component {
|
||||
|
||||
get osmUrl() {
|
||||
const id = this.place.osmId;
|
||||
if (!id) return null;
|
||||
const type = this.place.osmType || 'node';
|
||||
return `https://www.openstreetmap.org/${type}/${id}`;
|
||||
if (id) {
|
||||
const type = this.place.osmType || 'node';
|
||||
return `https://www.openstreetmap.org/${type}/${id}`;
|
||||
}
|
||||
|
||||
const lat = this.place.lat;
|
||||
const lon = this.place.lon;
|
||||
if (!lat || !lon) return null;
|
||||
|
||||
const viewLat = this.mapUi.currentCenter?.lat ?? lat;
|
||||
const viewLon = this.mapUi.currentCenter?.lon ?? lon;
|
||||
const zoom = this.mapUi.currentZoom ?? 17;
|
||||
const roundedZoom = Math.round(zoom);
|
||||
|
||||
return `https://www.openstreetmap.org/search?lat=${lat}&lon=${lon}&zoom=${roundedZoom}#map=${roundedZoom}/${Number(viewLat).toFixed(5)}/${Number(viewLon).toFixed(5)}`;
|
||||
}
|
||||
|
||||
get gmapsUrl() {
|
||||
@@ -591,7 +604,7 @@ export default class PlaceDetails extends Component {
|
||||
|
||||
</div>
|
||||
|
||||
{{#if this.osmUrl}}
|
||||
{{#if this.place.osmId}}
|
||||
<div class="meta-info">
|
||||
<p class="content-with-icon">
|
||||
<Icon @name="feather-camera" />
|
||||
|
||||
@@ -1266,6 +1266,20 @@ span.icon {
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.content-with-icon > span:not(.icon) {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.content-with-icon > span:not(.icon) a {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.content-with-icon .icon {
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
|
||||
@@ -59,8 +59,12 @@ import bus from '@waysidemapping/pinhead/dist/icons/bus.svg?raw';
|
||||
import camera from '@waysidemapping/pinhead/dist/icons/camera.svg?raw';
|
||||
import boxingGloveUp from '@waysidemapping/pinhead/dist/icons/boxing_glove_up.svg?raw';
|
||||
import car from '@waysidemapping/pinhead/dist/icons/car.svg?raw';
|
||||
import carAndWrench from '@waysidemapping/pinhead/dist/icons/car_and_wrench.svg?raw';
|
||||
import castleKeep from '@waysidemapping/pinhead/dist/icons/castle_keep.svg?raw';
|
||||
import cigaretteWithSmokeCurl from '@waysidemapping/pinhead/dist/icons/cigarette_with_smoke_curl.svg?raw';
|
||||
import cityGate from '@waysidemapping/pinhead/dist/icons/city_gate.svg?raw';
|
||||
import classicalBuilding from '@waysidemapping/pinhead/dist/icons/classical_building.svg?raw';
|
||||
import classicalBuildingWithClock from '@waysidemapping/pinhead/dist/icons/classical_building_with_clock.svg?raw';
|
||||
import classicalBuildingWithDomeAndFlag from '@waysidemapping/pinhead/dist/icons/classical_building_with_dome_and_flag.svg?raw';
|
||||
import classicalBuildingWithFlag from '@waysidemapping/pinhead/dist/icons/classical_building_with_flag.svg?raw';
|
||||
import commercialBuilding from '@waysidemapping/pinhead/dist/icons/commercial_building.svg?raw';
|
||||
@@ -88,6 +92,7 @@ import grecianVase from '@waysidemapping/pinhead/dist/icons/grecian_vase.svg?raw
|
||||
import greekCross from '@waysidemapping/pinhead/dist/icons/greek_cross.svg?raw';
|
||||
import iceCreamOnCone from '@waysidemapping/pinhead/dist/icons/ice_cream_on_cone.svg?raw';
|
||||
import industrialBuilding from '@waysidemapping/pinhead/dist/icons/industrial_building.svg?raw';
|
||||
import infoI from '@waysidemapping/pinhead/dist/icons/info_i.svg?raw';
|
||||
import jewel from '@waysidemapping/pinhead/dist/icons/jewel.svg?raw';
|
||||
import lowriseBuilding from '@waysidemapping/pinhead/dist/icons/lowrise_building.svg?raw';
|
||||
import marketStall from '@waysidemapping/pinhead/dist/icons/market_stall.svg?raw';
|
||||
@@ -157,11 +162,13 @@ const ICONS = {
|
||||
'chevron-left': chevronLeft,
|
||||
'chevron-right': chevronRight,
|
||||
'cigarette-with-smoke-curl': cigaretteWithSmokeCurl,
|
||||
'city-gate': cityGate,
|
||||
climbing_wall: climbingWall,
|
||||
check,
|
||||
'alert-circle': alertCircle,
|
||||
'alert-triangle': alertTriangle,
|
||||
'classical-building': classicalBuilding,
|
||||
'classical-building-with-clock': classicalBuildingWithClock,
|
||||
'classical-building-with-dome-and-flag': classicalBuildingWithDomeAndFlag,
|
||||
'classical-building-with-flag': classicalBuildingWithFlag,
|
||||
'commercial-building': commercialBuilding,
|
||||
@@ -198,6 +205,7 @@ const ICONS = {
|
||||
'ice-cream-on-cone': iceCreamOnCone,
|
||||
'industrial-building': industrialBuilding,
|
||||
info,
|
||||
'info-i': infoI,
|
||||
instagram,
|
||||
jewel,
|
||||
'log-in': logIn,
|
||||
@@ -262,6 +270,8 @@ const ICONS = {
|
||||
winding_way_wide: windingWayWide,
|
||||
parking_p: parkingP,
|
||||
car,
|
||||
'car-and-wrench': carAndWrench,
|
||||
'castle-keep': castleKeep,
|
||||
x,
|
||||
zap,
|
||||
'loading-ring': loadingRing,
|
||||
|
||||
@@ -27,6 +27,8 @@ export const POI_ICON_RULES = [
|
||||
|
||||
{ tags: { amenity: 'bank' }, icon: 'banknote' },
|
||||
{ tags: { amenity: 'place_of_worship' }, icon: 'place-of-worship-building' },
|
||||
{ tags: { amenity: 'townhall' }, icon: 'classical-building-with-clock' },
|
||||
{ tags: { building: 'townhall' }, icon: 'classical-building-with-clock' },
|
||||
{ tags: { amenity: 'fire_station' }, icon: 'badge-shield-with-fire' },
|
||||
{ tags: { amenity: 'police' }, icon: 'police-officer-with-stop-arm' },
|
||||
{ tags: { amenity: 'toilets' }, icon: 'womens-and-mens-restroom-symbol' },
|
||||
@@ -72,6 +74,7 @@ export const POI_ICON_RULES = [
|
||||
tags: { shop: 'beauty' },
|
||||
icon: 'fancy-mirror-with-reflection-and-stars',
|
||||
},
|
||||
{ tags: { shop: 'car_repair' }, icon: 'car-and-wrench' },
|
||||
{ tags: { craft: 'tailor' }, icon: 'needle-and-spool-of-thread' },
|
||||
{ tags: { office: 'estate_agent' }, icon: 'village-buildings' },
|
||||
{ tags: { office: true }, icon: 'commercial-building' },
|
||||
@@ -103,6 +106,7 @@ export const POI_ICON_RULES = [
|
||||
{ tags: { tourism: 'viewpoint' }, icon: 'camera' },
|
||||
{ tags: { tourism: 'zoo' }, icon: 'camera' },
|
||||
{ tags: { tourism: 'artwork' }, icon: 'camera' },
|
||||
{ tags: { tourism: 'information' }, icon: 'info-i' },
|
||||
{ tags: { amenity: 'cinema' }, icon: 'film' },
|
||||
{ tags: { amenity: 'theatre' }, icon: 'camera' },
|
||||
{ tags: { amenity: 'arts_centre' }, icon: 'comedy-mask-and-tragedy-mask' },
|
||||
@@ -113,7 +117,9 @@ export const POI_ICON_RULES = [
|
||||
{ tags: { historic: 'bridge' }, icon: 'bridge' },
|
||||
{ tags: { historic: 'bridge_site' }, icon: 'bridge' },
|
||||
{ tags: { historic: 'fort' }, icon: 'fort' },
|
||||
{ tags: { historic: 'city_gate' }, icon: 'city-gate' },
|
||||
{ tags: { historic: 'castle' }, icon: 'palace' },
|
||||
{ tags: { building: 'tower', historic: 'yes' }, icon: 'castle-keep' },
|
||||
{ tags: { historic: 'building' }, icon: 'classical-building-with-flag' },
|
||||
{ tags: { historic: 'archaeological_site' }, icon: 'grecian-vase' },
|
||||
{ tags: { historic: 'memorial' }, icon: 'memorial-stone-with-inscription' },
|
||||
|
||||
@@ -56,15 +56,24 @@ const PLACE_TYPE_KEYS = [
|
||||
export function getPlaceType(tags) {
|
||||
if (!tags) return null;
|
||||
|
||||
let fallbackKey = null;
|
||||
|
||||
for (const key of PLACE_TYPE_KEYS) {
|
||||
const value = tags[key];
|
||||
if (value) {
|
||||
if (value === 'yes') {
|
||||
return humanizeOsmTag(key);
|
||||
if (!fallbackKey) {
|
||||
fallbackKey = key;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
return humanizeOsmTag(value);
|
||||
}
|
||||
}
|
||||
|
||||
if (fallbackKey) {
|
||||
return humanizeOsmTag(fallbackKey);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ export const POI_CATEGORIES = [
|
||||
label: 'Things to do',
|
||||
icon: 'feather-camera',
|
||||
filter: [
|
||||
'["tourism"~"^(museum|gallery|attraction|viewpoint|zoo|theme_park|aquarium|artwork)$"]',
|
||||
'["tourism"~"^(museum|gallery|attraction|viewpoint|zoo|theme_park|aquarium|artwork|information)$"]',
|
||||
'["amenity"~"^(cinema|theatre|arts_centre|planetarium)$"]',
|
||||
'["leisure"~"^(sports_centre|stadium|water_park)$"]',
|
||||
'["historic"]',
|
||||
@@ -55,7 +55,7 @@ export const POI_CATEGORIES = [
|
||||
id: 'accommodation',
|
||||
label: 'Hotels',
|
||||
icon: 'person-sleeping-in-bed',
|
||||
filter: ['["tourism"~"^(hotel|hostel|motel|chalet)$"]'],
|
||||
filter: ['["tourism"~"^(hotel|hostel|motel|chalet|guest_house)$"]'],
|
||||
types: ['node', 'way', 'relation'],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -334,4 +334,54 @@ module('Integration | Component | place-details', function (hooks) {
|
||||
assert.dom(links[0]).hasText('+44 987 654 321');
|
||||
assert.dom(links[1]).hasText('+1 234-567 8900');
|
||||
});
|
||||
|
||||
test('it renders correct OpenStreetMap link for an OSM place', async function (assert) {
|
||||
const place = {
|
||||
title: 'OSM Place',
|
||||
osmId: '12345',
|
||||
osmType: 'node',
|
||||
lat: 52.520008,
|
||||
lon: 13.404954,
|
||||
};
|
||||
|
||||
await render(<template><PlaceDetails @place={{place}} /></template>);
|
||||
|
||||
const osmLink = this.element.querySelector(
|
||||
'.meta-info a[href^="https://www.openstreetmap.org/node/12345"]'
|
||||
);
|
||||
assert.ok(osmLink, 'OpenStreetMap link is rendered');
|
||||
assert.strictEqual(
|
||||
osmLink.getAttribute('href'),
|
||||
'https://www.openstreetmap.org/node/12345'
|
||||
);
|
||||
|
||||
assert.dom('button.btn-link').hasText('Add a photo');
|
||||
});
|
||||
|
||||
test('it renders correct search-based OpenStreetMap link for a custom saved place', async function (assert) {
|
||||
class MockMapUi extends Service {
|
||||
currentCenter = { lat: 52.5, lon: 13.4 };
|
||||
currentZoom = 15.6;
|
||||
}
|
||||
this.owner.register('service:map-ui', MockMapUi);
|
||||
|
||||
const place = {
|
||||
title: 'Custom Place',
|
||||
lat: 52.520008,
|
||||
lon: 13.404954,
|
||||
};
|
||||
|
||||
await render(<template><PlaceDetails @place={{place}} /></template>);
|
||||
|
||||
const osmLink = this.element.querySelector(
|
||||
'.meta-info a[href^="https://www.openstreetmap.org/search"]'
|
||||
);
|
||||
assert.ok(osmLink, 'OpenStreetMap search link is rendered');
|
||||
assert.strictEqual(
|
||||
osmLink.getAttribute('href'),
|
||||
'https://www.openstreetmap.org/search?lat=52.520008&lon=13.404954&zoom=16#map=16/52.50000/13.40000'
|
||||
);
|
||||
|
||||
assert.dom('button.btn-link').doesNotExist();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -89,6 +89,12 @@ module('Unit | Utility | osm', function (hooks) {
|
||||
assert.strictEqual(result, 'Building');
|
||||
});
|
||||
|
||||
test('getPlaceType ignores generic "yes" values if a more specific tag is present', function (assert) {
|
||||
const tags = { historic: 'yes', building: 'tower' };
|
||||
const result = getPlaceType(tags);
|
||||
assert.strictEqual(result, 'Tower');
|
||||
});
|
||||
|
||||
test('getPlaceType prioritizes order (amenity > shop > building)', function (assert) {
|
||||
// If something is both a shop and a building, it should be a shop
|
||||
const tags = { building: 'yes', shop: 'supermarket' };
|
||||
|
||||
Reference in New Issue
Block a user