From c50e139cc7626a9b58721c964b1506236d17a614 Mon Sep 17 00:00:00 2001 From: User Date: Wed, 11 Feb 2026 16:45:22 +0800 Subject: [PATCH] feat: add experimental option for sidebar auto-centering --- src/components/menulist-tab.ts | 21 ++++++++++++--------- src/config/config.ts | 1 + src/pages/options/options-i18n.ts | 2 ++ src/pages/options/options.html | 4 ++++ src/pages/options/options.ts | 9 +++++++++ static/_locales/en/messages.json | 6 +++++- 6 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/components/menulist-tab.ts b/src/components/menulist-tab.ts index fcd7113c..3d83d6dc 100644 --- a/src/components/menulist-tab.ts +++ b/src/components/menulist-tab.ts @@ -25,6 +25,7 @@ import { EventSink } from "weeg-events"; import { CompatTab } from 'weeg-tabs'; import { DisplayedContainer } from 'weeg-containers'; +import { config } from '../config/config'; import { TabIconService } from '../lib/TabIconService'; import { ModalSetTagElement } from './modal-set-tag'; @@ -125,9 +126,7 @@ export class MenulistTabElement extends HTMLElement { if (tab.active) { this.tabButton.classList.add("active"); // Scroll to center with a small delay to avoid initial render conflicts - if (document.body.classList.contains('popup')) { - setTimeout(() => this.scrollIntoViewIfActive(), 100); - } + setTimeout(() => this.scrollIntoViewIfActive(), 100); } } @@ -139,12 +138,16 @@ export class MenulistTabElement extends HTMLElement { this.tabMainElement.style.borderColor = displayedContainer.colorCode; } - private scrollIntoViewIfActive(): void { - // Scroll the active tab into view at the center of the sidebar - // Using requestAnimationFrame to ensure DOM is ready - requestAnimationFrame(() => { - this.scrollIntoView({ behavior: 'smooth', block: 'center' }); - }); + private async scrollIntoViewIfActive(): Promise { + const isPopup = document.body.classList.contains('popup'); + const autoCenter = await config['tab.autoCenterInSidebar'].getValue(); + if (isPopup || autoCenter) { + // Scroll the active tab into view at the center of the sidebar + // Using requestAnimationFrame to ensure DOM is ready + requestAnimationFrame(() => { + this.scrollIntoView({ behavior: 'smooth', block: 'center' }); + }); + } } private getShadowElement(id: string): HTMLElement { diff --git a/src/config/config.ts b/src/config/config.ts index 603b2246..d23587ad 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -43,6 +43,7 @@ export const config = { 'tab.autoDiscard.minAge': new StorageConfigurationOption('tab.autoDiscard.minAge', -1), 'tab.sorting.enabled': new StorageConfigurationOption('tab.sorting.enabled', true), 'tab.autoHide.enabled': new StorageConfigurationOption('tab.autoHide.enabled', false), + 'tab.autoCenterInSidebar': new StorageConfigurationOption('tab.autoCenterInSidebar', false), 'menu.hideEmptyContainers': new StorageConfigurationOption('menu.hideEmptyContainers', false), }; diff --git a/src/pages/options/options-i18n.ts b/src/pages/options/options-i18n.ts index a239bc72..ee70e80a 100644 --- a/src/pages/options/options-i18n.ts +++ b/src/pages/options/options-i18n.ts @@ -78,6 +78,8 @@ setTextContent('label[for="input-syncContainers"]', 'optionSyncContainers'); setTextContent('label[for="select-externalTabContainerOption"]', 'labelExternalTabSelectContainerOption'); +setTextContent('label[for="input-autoCenterInSidebar"]', 'optionAutoCenterInSidebar'); + setTextContent('label[for="input-autoHideContainers"]', 'optionAutoHideContainers'); setTextContent('#select-externalTabContainerOption > option[value="choose"]', 'labelExternalTabOptionChooseContainer'); diff --git a/src/pages/options/options.html b/src/pages/options/options.html index 3fc5f320..9c4dc8c2 100644 --- a/src/pages/options/options.html +++ b/src/pages/options/options.html @@ -73,6 +73,10 @@

optionsHeadingExperimental

+

+ + +