Tab strip scrolls horizontally on overflow
Tabs live in their own min-w-0 overflow-x-auto container (scrollbar hidden, trackpad scrolls); the new-tab button and the options gear sit outside it and stay pinned. The active tab scrolls into view when it changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { Component, inject, signal } from '@angular/core';
|
import { Component, ElementRef, effect, inject, signal, viewChild } from '@angular/core';
|
||||||
import { NgIcon } from '@ng-icons/core';
|
import { NgIcon } from '@ng-icons/core';
|
||||||
import { PanelsService } from '../panels.service';
|
import { PanelsService } from '../panels.service';
|
||||||
import { IS_MAC_CHROME } from '../platform';
|
import { IS_MAC_CHROME } from '../platform';
|
||||||
@@ -26,9 +26,14 @@ const CONCURRENCY_CHOICES = [2, 3, 4, 6, 8] as const;
|
|||||||
[class.pl-1.5]="!isMacChrome"
|
[class.pl-1.5]="!isMacChrome"
|
||||||
[class.pt-1]="!isMacChrome"
|
[class.pt-1]="!isMacChrome"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
#tabScroll
|
||||||
|
class="flex min-w-0 items-center gap-0.5 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
|
||||||
|
>
|
||||||
@for (ws of panels.workspaces(); track ws.id; let i = $index) {
|
@for (ws of panels.workspaces(); track ws.id; let i = $index) {
|
||||||
<div
|
<div
|
||||||
class="group relative flex max-w-52 items-center rounded-md electrobun-webkit-app-region-no-drag"
|
[attr.data-tab-id]="ws.id"
|
||||||
|
class="group relative flex max-w-52 shrink-0 items-center rounded-md electrobun-webkit-app-region-no-drag"
|
||||||
[class.bg-accent]="ws.id === panels.activeWorkspaceId()"
|
[class.bg-accent]="ws.id === panels.activeWorkspaceId()"
|
||||||
[class.opacity-50]="draggedId() === ws.id"
|
[class.opacity-50]="draggedId() === ws.id"
|
||||||
[style.box-shadow]="dropIndicatorShadow(i)"
|
[style.box-shadow]="dropIndicatorShadow(i)"
|
||||||
@@ -69,6 +74,7 @@ const CONCURRENCY_CHOICES = [2, 3, 4, 6, 8] as const;
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
(click)="panels.newWorkspace()"
|
(click)="panels.newWorkspace()"
|
||||||
title="New tab (⌘T)"
|
title="New tab (⌘T)"
|
||||||
@@ -201,6 +207,18 @@ export class TabBar {
|
|||||||
readonly draggedId = signal<number | null>(null);
|
readonly draggedId = signal<number | null>(null);
|
||||||
readonly dropTarget = signal<{ index: number; before: boolean } | null>(null);
|
readonly dropTarget = signal<{ index: number; before: boolean } | null>(null);
|
||||||
|
|
||||||
|
private readonly tabScroll = viewChild.required<ElementRef<HTMLDivElement>>('tabScroll');
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
// keep the active tab visible when the strip overflows
|
||||||
|
effect(() => {
|
||||||
|
const id = this.panels.activeWorkspaceId();
|
||||||
|
this.tabScroll()
|
||||||
|
.nativeElement.querySelector(`[data-tab-id="${id}"]`)
|
||||||
|
?.scrollIntoView({ inline: 'nearest', block: 'nearest' });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
close(event: MouseEvent, id: number): void {
|
close(event: MouseEvent, id: number): void {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
this.panels.closeWorkspace(id);
|
this.panels.closeWorkspace(id);
|
||||||
|
|||||||
Reference in New Issue
Block a user