Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions src/components/menulist-tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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);
}

}
Expand All @@ -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<void> {
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' });
});
}
}
Comment on lines +141 to 151
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This async function call on every tab render creates unnecessary performance overhead. The config value is cached by StorageConfigurationOption after the first access, so you should use the synchronous tryGetValueSync() method instead. This is particularly important since this code path is triggered for every active tab during rendering. Consider this pattern used elsewhere in the codebase (e.g., panel-windows.ts line 96):

private scrollIntoViewIfActive(): void {
  const isPopup = document.body.classList.contains('popup');
  const autoCenter = config['tab.autoCenterInSidebar'].tryGetValueSync() ?? false;
  if (isPopup || autoCenter) {
    requestAnimationFrame(() => {
      this.scrollIntoView({ behavior: 'smooth', block: 'center' });
    });
  }
}

The cached value will be available after the config is initialized, and the default value of false is safe to use as a fallback.

Copilot uses AI. Check for mistakes.

private getShadowElement(id: string): HTMLElement {
Expand Down
1 change: 1 addition & 0 deletions src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const config = {
'tab.autoDiscard.minAge': new StorageConfigurationOption<number>('tab.autoDiscard.minAge', -1),
'tab.sorting.enabled': new StorageConfigurationOption<boolean>('tab.sorting.enabled', true),
'tab.autoHide.enabled': new StorageConfigurationOption<boolean>('tab.autoHide.enabled', false),
'tab.autoCenterInSidebar': new StorageConfigurationOption<boolean>('tab.autoCenterInSidebar', false),
'menu.hideEmptyContainers': new StorageConfigurationOption<boolean>('menu.hideEmptyContainers', false),
};

Expand Down
2 changes: 2 additions & 0 deletions src/pages/options/options-i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
4 changes: 4 additions & 0 deletions src/pages/options/options.html
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ <h2 id='optionsHeadingExperimental'>optionsHeadingExperimental</h2>
<input type='checkbox' id='input-newtabKeepContainer'/>
<label class='browser-style-label' for='input-newtabKeepContainer'>labelNewTabKeepContainer</label>
</p>
<p class='browser-style'>
<input type='checkbox' id='input-autoCenterInSidebar'/>
<label class='browser-style-label' for='input-autoCenterInSidebar'>optionAutoCenterInSidebar</label>
</p>
<p>
<label class='browser-style-label' for='select-externalTabContainerOption'>labelExternalTabSelectContainerOption</label>
<select id='select-externalTabContainerOption' class='browser-style'>
Expand Down
9 changes: 9 additions & 0 deletions src/pages/options/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ const paneContainerOverrides = document.querySelector<HTMLElement>('#optionsPane
const inputTabSortingEnabled = document.querySelector<HTMLInputElement>('#input-enableSorting');
const inputSyncContainers = document.querySelector<HTMLInputElement>('#input-syncContainers');
const inputAutoHideContainers = document.querySelector<HTMLInputElement>('#input-autoHideContainers');
const inputAutoCenterInSidebar = document.querySelector<HTMLInputElement>('#input-autoCenterInSidebar');

const inputFeatureLanguageOverrides = document.querySelector<HTMLInputElement>('#input-featureLanguageOverrides');
const inputFeatureUaOverrides = document.querySelector<HTMLInputElement>('#input-featureUaOverrides');
Expand Down Expand Up @@ -246,3 +247,11 @@ config['tab.autoHide.enabled'].observe((value) => {
inputAutoHideContainers?.addEventListener('change', () => {
setConfigValue(config['tab.autoHide.enabled'], inputAutoHideContainers.checked);
});

config['tab.autoCenterInSidebar'].observe((value) => {
setInputChecked(inputAutoCenterInSidebar, value);
});

inputAutoCenterInSidebar?.addEventListener('change', () => {
setConfigValue(config['tab.autoCenterInSidebar'], inputAutoCenterInSidebar.checked);
});
6 changes: 5 additions & 1 deletion static/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,10 @@
"message": "Auto-hide Unused Containers",
"description": "Label text for auto-hide unused containers option."
},
"optionAutoCenterInSidebar": {
"message": "Auto-center active tab in sidebar",
"description": "Label text for auto-center active tab in sidebar option."
},
"saveDebuggingInformation": {
"message": "Save Debugging Information",
"description": "Save debugging information button."
Expand Down Expand Up @@ -804,4 +808,4 @@
"message": "Copy Cookies",
"description": "Copy cookies button or label text."
}
}
}
Loading