style: adjust header and sidebar heights for improved layout consistency and update TabBar component for better responsiveness

This commit is contained in:
Anish Sarkar 2026-03-31 16:35:29 +05:30
parent 781984c224
commit 2327869147
6 changed files with 63 additions and 61 deletions

View file

@ -15,10 +15,11 @@ import { cn } from "@/lib/utils";
interface TabBarProps {
onTabSwitch?: (tab: Tab) => void;
onNewChat?: () => void;
rightActions?: React.ReactNode;
className?: string;
}
export function TabBar({ onTabSwitch, onNewChat, className }: TabBarProps) {
export function TabBar({ onTabSwitch, onNewChat, rightActions, className }: TabBarProps) {
const tabs = useAtomValue(tabsAtom);
const activeTabId = useAtomValue(activeTabIdAtom);
const switchTab = useSetAtom(switchTabAtom);
@ -45,12 +46,25 @@ export function TabBar({ onTabSwitch, onNewChat, className }: TabBarProps) {
[closeTab, onTabSwitch]
);
// Scroll active tab into view
// Keep active tab visible with minimal scroll shift.
useEffect(() => {
if (!scrollRef.current || !activeTabId) return;
const activeEl = scrollRef.current.querySelector(`[data-tab-id="${activeTabId}"]`);
if (activeEl) {
activeEl.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
const scroller = scrollRef.current;
const activeEl = scroller.querySelector<HTMLElement>(`[data-tab-id="${activeTabId}"]`);
if (!activeEl) return;
const viewLeft = scroller.scrollLeft;
const viewRight = viewLeft + scroller.clientWidth;
const tabLeft = activeEl.offsetLeft;
const tabRight = tabLeft + activeEl.offsetWidth;
if (tabLeft < viewLeft) {
scroller.scrollTo({ left: tabLeft, behavior: "smooth" });
return;
}
if (tabRight > viewRight) {
scroller.scrollTo({ left: tabRight - scroller.clientWidth, behavior: "smooth" });
}
}, [activeTabId]);
@ -60,13 +74,13 @@ export function TabBar({ onTabSwitch, onNewChat, className }: TabBarProps) {
return (
<div
className={cn(
"flex h-12 items-stretch shrink-0 border-b border-border/35 bg-main-panel",
"mb-2 flex h-9 items-center shrink-0 px-1 gap-0.5",
className
)}
>
<div
ref={scrollRef}
className="flex h-full items-stretch flex-1 overflow-x-auto overflow-y-hidden scrollbar-hide [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden"
className="flex h-full items-center flex-1 gap-0.5 overflow-x-auto overflow-y-hidden scrollbar-hide [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden py-1"
>
{tabs.map((tab) => {
const isActive = tab.id === activeTabId;
@ -78,13 +92,13 @@ export function TabBar({ onTabSwitch, onNewChat, className }: TabBarProps) {
data-tab-id={tab.id}
onClick={() => handleTabClick(tab)}
className={cn(
"group relative flex h-full w-[170px] items-center self-stretch px-3 min-w-0 overflow-hidden text-sm font-medium border-r border-border/35 transition-colors shrink-0",
"group relative flex h-full w-[150px] items-center px-3 min-h-0 overflow-hidden text-[13px] font-medium rounded-lg transition-all duration-150 shrink-0",
isActive
? "bg-muted/50 text-foreground"
: "bg-transparent text-muted-foreground hover:bg-muted/25 hover:text-foreground"
? "bg-muted/60 text-foreground"
: "bg-transparent text-muted-foreground hover:bg-muted/30 hover:text-foreground"
)}
>
<span className="block min-w-0 flex-1 truncate text-left transition-[padding-right] duration-150 group-hover:pr-5 group-focus-within:pr-5">
<span className="block min-w-0 flex-1 truncate text-left group-hover:pr-5 group-focus-within:pr-5">
{tab.title}
</span>
{/* biome-ignore lint/a11y/useSemanticElements: cannot nest button inside button */}
@ -99,7 +113,7 @@ export function TabBar({ onTabSwitch, onNewChat, className }: TabBarProps) {
}
}}
className={cn(
"absolute right-2 top-1/2 -translate-y-1/2 shrink-0 rounded-sm p-0.5 transition-colors",
"absolute right-2 top-1/2 -translate-y-1/2 shrink-0 rounded-full p-0.5 transition-all duration-150 hover:bg-muted-foreground/15",
isActive
? "opacity-0 group-hover:opacity-70 group-focus-within:opacity-70 hover:opacity-100"
: "opacity-0 group-hover:opacity-60 group-focus-within:opacity-60 hover:opacity-100!"
@ -110,18 +124,19 @@ export function TabBar({ onTabSwitch, onNewChat, className }: TabBarProps) {
</button>
);
})}
</div>
<div className="flex items-center gap-0.5 shrink-0">
{onNewChat && (
<div className="flex h-full items-center px-1.5 shrink-0">
<button
type="button"
onClick={onNewChat}
className="flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:text-foreground hover:bg-muted/60"
title="New Chat"
>
<Plus className="size-3.5" />
</button>
</div>
<button
type="button"
onClick={onNewChat}
className="flex h-6 w-6 items-center justify-center shrink-0 rounded-md text-muted-foreground transition-all duration-150 hover:text-foreground hover:bg-muted/40"
title="New Chat"
>
<Plus className="size-3.5" />
</button>
)}
{rightActions}
</div>
</div>
);