From e74c01b1d1edeb50cc6f5b54ab85b8030e2113d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Fri, 25 Sep 2026 15:55:47 +0200 Subject: [PATCH] Save/restore scroll position for bookmark lists Keep items loaded, same as for Activity and My Contributions lists --- app/controllers/lists/list.js | 16 ++++++ app/templates/lists/index.gjs | 11 +++- app/templates/lists/list.gjs | 2 +- tests/acceptance/collections-test.js | 81 ++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 2 deletions(-) diff --git a/app/controllers/lists/list.js b/app/controllers/lists/list.js index f567548..f9d9d51 100644 --- a/app/controllers/lists/list.js +++ b/app/controllers/lists/list.js @@ -23,18 +23,34 @@ export default class ListsListController extends Controller { @tracked model; @tracked loadedPlaces = []; + @tracked loadedListId = null; get listId() { return this.model?.list_id; } + get isLoading() { + // Only show the spinner when there is nothing to display yet. On re-entry + // the previously loaded places (plus live storage state) render instantly, + // so we avoid a loading flash and preserve restored scroll position. + return this.loadPlacesTask.isRunning && this.places.length === 0; + } + loadPlacesTask = task({ restartable: true }, async (listId) => { + // Already loaded this list: keep the existing places so returning from + // place details is instant (mirrors the activity service's load guard). + if (this.loadedListId === listId) { + return; + } + + this.loadedListId = listId; this.loadedPlaces = []; // Clear previous elements immediately to show fresh loader try { this.loadedPlaces = await this.storage.getPlacesInList(listId); } catch (e) { console.error('Failed to load places in list', listId, e); this.loadedPlaces = []; + this.loadedListId = null; // Allow a retry on next entry } }); diff --git a/app/templates/lists/index.gjs b/app/templates/lists/index.gjs index e24b840..b251042 100644 --- a/app/templates/lists/index.gjs +++ b/app/templates/lists/index.gjs @@ -5,6 +5,7 @@ import { fn } from '@ember/helper'; import { on } from '@ember/modifier'; import Icon from '#components/icon'; import { htmlSafe } from '@ember/template'; +import restoreScroll from '../../modifiers/restore-scroll'; export default class ListsIndexTemplate extends Component { @service storage; @@ -26,8 +27,16 @@ export default class ListsIndexTemplate extends Component { return htmlSafe(`background-color: ${finalColor}`); } + get scrollTop() { + return this.mapUi.getScrollPosition('lists-index'); + } + @action selectList(listId) { + const sidebarContent = document.querySelector('.sidebar-content'); + if (sidebarContent) { + this.mapUi.saveScrollPosition('lists-index', sidebarContent.scrollTop); + } this.router.transitionTo('lists.list', listId); } @@ -59,7 +68,7 @@ export default class ListsIndexTemplate extends Component { -