From bcb9b20e85de7fb097e2099cbb426942959dd91f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Fri, 13 Mar 2026 12:09:03 +0400 Subject: [PATCH] WIP Add places to lists --- app/components/map.gjs | 33 +++- app/components/place-details.gjs | 60 ++++-- app/components/place-lists-manager.gjs | 95 +++++++++ app/services/storage.js | 96 ++++++++- app/styles/app.css | 60 ++++++ app/utils/place-mapping.js | 15 ++ .../components/place-details-test.gjs | 182 +++++++++++++++++- tests/unit/utils/place-mapping-test.js | 58 ++++++ 8 files changed, 576 insertions(+), 23 deletions(-) create mode 100644 app/components/place-lists-manager.gjs create mode 100644 app/utils/place-mapping.js create mode 100644 tests/unit/utils/place-mapping-test.js diff --git a/app/components/map.gjs b/app/components/map.gjs index 41bd482..14537d5 100644 --- a/app/components/map.gjs +++ b/app/components/map.gjs @@ -60,9 +60,27 @@ export default class MapComponent extends Component { // Create a vector source and layer for bookmarks this.bookmarkSource = new VectorSource(); - const bookmarkLayer = new VectorLayer({ - source: this.bookmarkSource, - style: [ + + const bookmarkStyleFunction = (feature) => { + const originalPlace = feature.get('originalPlace'); + let color = '#ffcc33'; // Default Yellow + + if ( + originalPlace && + originalPlace._listIds && + originalPlace._listIds.length > 0 + ) { + // Find the first list color + // We need access to storage.lists. + // Since this is inside setupMap, 'this' refers to the component instance. + const firstListId = originalPlace._listIds[0]; + const list = this.storage.lists.find((l) => l.id === firstListId); + if (list && list.color) { + color = list.color; + } + } + + return [ new Style({ image: new Circle({ radius: 10, @@ -73,14 +91,19 @@ export default class MapComponent extends Component { new Style({ image: new Circle({ radius: 9, - fill: new Fill({ color: '#ffcc33' }), // Gold/Yellow + fill: new Fill({ color: color }), stroke: new Stroke({ color: '#fff', width: 2, }), }), }), - ], + ]; + }; + + const bookmarkLayer = new VectorLayer({ + source: this.bookmarkSource, + style: bookmarkStyleFunction, zIndex: 10, // Ensure it sits above the map tiles }); diff --git a/app/components/place-details.gjs b/app/components/place-details.gjs index db23a2f..5ac2f18 100644 --- a/app/components/place-details.gjs +++ b/app/components/place-details.gjs @@ -4,20 +4,31 @@ import { on } from '@ember/modifier'; import { htmlSafe } from '@ember/template'; import { humanizeOsmTag } from '../utils/format-text'; import { getLocalizedName, getPlaceType } from '../utils/osm'; +import { mapToStorageSchema } from '../utils/place-mapping'; import { getSocialInfo } from '../utils/social-links'; import Icon from '../components/icon'; import PlaceEditForm from './place-edit-form'; +import PlaceListsManager from './place-lists-manager'; import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; export default class PlaceDetails extends Component { @tracked isEditing = false; + @tracked showLists = false; get place() { return this.args.place || {}; } + get saveablePlace() { + if (this.place.createdAt) { + return this.place; + } + + return mapToStorageSchema(this.place); + } + get tags() { return this.place.osmTags || {}; } @@ -37,6 +48,16 @@ export default class PlaceDetails extends Component { this.isEditing = false; } + @action + toggleLists() { + this.showLists = !this.showLists; + } + + @action + closeLists() { + this.showLists = false; + } + @action async saveChanges(changes) { if (this.args.onSave) { @@ -247,21 +268,30 @@ export default class PlaceDetails extends Component { {{/if}}
- +
+ + + {{#if this.showLists}} + + {{/if}} +
{{#if this.place.createdAt}}