From 14ca2e7526f5809d007f60b7db8f781547493b7c Mon Sep 17 00:00:00 2001 From: silverwind Date: Sun, 26 Jul 2026 12:26:52 +0200 Subject: [PATCH] fix(ui): avoid layout shifts in `overflow-menu` and repo filter (#37818) Eliminate two layout shifts in the menu, one related to non-existant label on page load and one to `0` value rendering. Signed-off-by: silverwind Co-authored-by: Claude (Opus 4.7) Co-authored-by: bircni --- web_src/css/base.css | 11 +++++++++++ web_src/js/components/DashboardRepoList.vue | 10 +++++----- web_src/js/webcomponents/overflow-menu.ts | 1 + 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/web_src/css/base.css b/web_src/css/base.css index 64da8fa9c1..49e3f94ab6 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -522,6 +522,11 @@ overflow-menu { position: relative; } +/* hide until JS has arranged the items, so the un-collapsed menu is never painted */ +overflow-menu:not([data-ready]) { + visibility: hidden; +} + overflow-menu .overflow-menu-popup { position: absolute; top: calc(100% + 8px); @@ -609,6 +614,12 @@ overflow-menu .overflow-menu-button:hover { overflow-menu .ui.label { margin-left: 7px !important; /* save some space */ + font-variant-numeric: tabular-nums; /* equal-width digits so counts don't reflow the row */ +} + +/* count not loaded yet, keep the reserved space so filling it in does not shift the row */ +overflow-menu .ui.label:empty { + visibility: hidden; } .activity-bar-graph { diff --git a/web_src/js/components/DashboardRepoList.vue b/web_src/js/components/DashboardRepoList.vue index 5b0842336f..a87c158dd6 100644 --- a/web_src/js/components/DashboardRepoList.vue +++ b/web_src/js/components/DashboardRepoList.vue @@ -63,6 +63,7 @@ export default defineComponent({ finalPage: 1, searchQuery, isLoading: false, + initialSearchDone: false, staticPrefix: assetUrlPrefix, counts: {} as Record, repoTypes: { @@ -186,7 +187,6 @@ export default defineComponent({ this.reposFilter = filter; this.repos = []; this.page = 1; - this.counts[`${filter}:${this.archivedFilter}:${this.privateFilter}`] = 0; this.searchRepos(); }, @@ -247,7 +247,6 @@ export default defineComponent({ } this.page = 1; this.repos = []; - this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = 0; this.searchRepos(); }, @@ -261,7 +260,6 @@ export default defineComponent({ } this.page = 1; this.repos = []; - this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = 0; this.searchRepos(); }, @@ -276,7 +274,6 @@ export default defineComponent({ this.page = 1; } this.repos = []; - this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = 0; await this.searchRepos(); }, @@ -308,6 +305,7 @@ export default defineComponent({ } catch { if (searchedURL === this.searchURL) { this.isLoading = false; + this.initialSearchDone = true; } return; } @@ -329,6 +327,7 @@ export default defineComponent({ this.finalPage = Math.ceil(count / this.searchLimit); this.updateHistory(); this.isLoading = false; + this.initialSearchDone = true; } }, @@ -449,7 +448,8 @@ export default defineComponent({ - + +