Fix mobile fullscreen panels and header active state (#1366)

* Render mobile side panels fullscreen below the header

* Fix bot comments

---------

Co-authored-by: Konstantin Zolin <zolin_ka@vk.com>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
kostazol
2026-05-24 13:55:01 +03:00
committed by GitHub
co-authored by Konstantin Zolin Bohdan Triapitsyn
parent 0776aca9c4
commit dffc4078a1
3 changed files with 216 additions and 181 deletions
+65 -15
View File
@@ -655,7 +655,6 @@ export const Header: React.FC<HeaderProps> = ({
const { t } = useI18n();
const setSessionSwitcherOpen = useUIStore((state) => state.setSessionSwitcherOpen);
const toggleSidebar = useUIStore((state) => state.toggleSidebar);
const setRightSidebarOpen = useUIStore((state) => state.setRightSidebarOpen);
const toggleBottomTerminal = useUIStore((state) => state.toggleBottomTerminal);
const toggleRightSidebar = useUIStore((state) => state.toggleRightSidebar);
const openContextOverview = useUIStore((state) => state.openContextOverview);
@@ -1344,6 +1343,45 @@ export const Header: React.FC<HeaderProps> = ({
const desktopHeaderIconButtonClass = DESKTOP_HEADER_ICON_BUTTON_CLASS;
const mobileHeaderIconButtonClass = MOBILE_HEADER_ICON_BUTTON_CLASS;
const mobileActiveHeaderItem = React.useMemo(() => {
if (isMobileRateLimitsOpen) {
return 'services';
}
if (leftDrawerOpen) {
return 'sessions';
}
if (rightDrawerOpen) {
return 'git';
}
return activeMainTab;
}, [activeMainTab, isMobileRateLimitsOpen, leftDrawerOpen, rightDrawerOpen]);
const closeMobileHeaderPanels = React.useCallback(() => {
setIsMobileRateLimitsOpen(false);
if (leftDrawerOpen && onToggleLeftDrawer) {
onToggleLeftDrawer();
}
if (rightDrawerOpen && onToggleRightDrawer) {
onToggleRightDrawer();
}
if (!onToggleLeftDrawer && isSessionSwitcherOpen) {
setSessionSwitcherOpen(false);
}
}, [isSessionSwitcherOpen, leftDrawerOpen, onToggleLeftDrawer, onToggleRightDrawer, rightDrawerOpen, setSessionSwitcherOpen]);
const handleMobileLeftDrawerToggle = React.useCallback(() => {
if (!leftDrawerOpen) {
setIsMobileRateLimitsOpen(false);
}
onToggleLeftDrawer?.();
}, [leftDrawerOpen, onToggleLeftDrawer]);
const handleMobileRightDrawerToggle = React.useCallback(() => {
if (!rightDrawerOpen) {
setIsMobileRateLimitsOpen(false);
}
onToggleRightDrawer?.();
}, [onToggleRightDrawer, rightDrawerOpen]);
const desktopPaddingClass = React.useMemo(() => {
if ((isDesktopApp && isMacPlatform && !isDesktopWindowFullscreen) || isTabletStandalonePwa) {
@@ -1629,7 +1667,8 @@ export const Header: React.FC<HeaderProps> = ({
if (num >= 1 && num <= tabs.length) {
e.preventDefault();
if (isMobile) {
setRightSidebarOpen(false);
blurActiveElement();
closeMobileHeaderPanels();
}
setActiveMainTab(tabs[num - 1].id);
}
@@ -1637,7 +1676,7 @@ export const Header: React.FC<HeaderProps> = ({
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [isMobile, setActiveMainTab, setRightSidebarOpen, tabs]);
}, [blurActiveElement, closeMobileHeaderPanels, isMobile, setActiveMainTab, tabs]);
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
@@ -1943,10 +1982,10 @@ export const Header: React.FC<HeaderProps> = ({
{onToggleLeftDrawer ? (
<button
type="button"
onClick={onToggleLeftDrawer}
onClick={handleMobileLeftDrawerToggle}
className={cn(
mobileHeaderIconButtonClass,
leftDrawerOpen && 'bg-interactive-selection text-interactive-selection-foreground'
mobileActiveHeaderItem === 'sessions' && 'bg-interactive-selection text-interactive-selection-foreground'
)}
aria-label={leftDrawerOpen ? t('header.actions.closeSessionsAria') : t('header.actions.openSessionsAria')}
>
@@ -1972,13 +2011,12 @@ export const Header: React.FC<HeaderProps> = ({
</button>
)}
{isSessionSwitcherOpen && (
{!onToggleLeftDrawer && isSessionSwitcherOpen && (
<span className="typography-ui-label font-semibold text-foreground">{t('header.sessions.title')}</span>
)}
</div>
{/* Hide tabs and right-side buttons when sessions sidebar is open */}
{!isSessionSwitcherOpen && (
{(!isSessionSwitcherOpen || Boolean(onToggleLeftDrawer)) && (
<>
<div className="app-region-no-drag flex min-w-0 flex-1 items-center">
<div className="flex min-w-0 flex-1 overflow-x-auto overflow-y-hidden scrollbar-hidden touch-pan-x overscroll-x-contain">
@@ -2000,7 +2038,7 @@ export const Header: React.FC<HeaderProps> = ({
onClick={() => {
if (isMobile) {
blurActiveElement();
setRightSidebarOpen(false);
closeMobileHeaderPanels();
}
setActiveMainTab(tab.id);
}}
@@ -2010,7 +2048,7 @@ export const Header: React.FC<HeaderProps> = ({
className={cn(
mobileHeaderIconButtonClass,
'relative rounded-lg',
isActive && 'bg-interactive-selection text-interactive-selection-foreground'
mobileActiveHeaderItem === tab.id && 'bg-interactive-selection text-interactive-selection-foreground'
)}
>
{isDiffTab ? (
@@ -2057,6 +2095,14 @@ export const Header: React.FC<HeaderProps> = ({
<DropdownMenu
open={isMobileRateLimitsOpen}
onOpenChange={(open) => {
if (open) {
if (leftDrawerOpen && onToggleLeftDrawer) {
onToggleLeftDrawer();
}
if (rightDrawerOpen && onToggleRightDrawer) {
onToggleRightDrawer();
}
}
setIsMobileRateLimitsOpen(open);
if (open && quotaResults.length === 0) {
fetchAllQuotas();
@@ -2069,7 +2115,10 @@ export const Header: React.FC<HeaderProps> = ({
<button
type="button"
aria-label={t('header.services.viewAria')}
className={mobileHeaderIconButtonClass}
className={cn(
mobileHeaderIconButtonClass,
mobileActiveHeaderItem === 'services' && 'bg-interactive-selection text-interactive-selection-foreground'
)}
>
<Icon name="stack" className="h-5 w-5" />
</button>
@@ -2082,10 +2131,11 @@ export const Header: React.FC<HeaderProps> = ({
<DropdownMenuContent
align="end"
sideOffset={0}
className="h-dvh w-[100vw] max-h-none rounded-none border-0 p-0 overflow-hidden"
positionerClassName="!fixed !bottom-0 !left-0 !right-0 !top-[var(--oc-header-height,56px)] !transform-none"
className="h-full w-screen max-h-none rounded-none border-0 p-0 pt-1 overflow-hidden"
>
<div className="flex h-full flex-col bg-[var(--surface-elevated)]">
<div className="sticky top-0 z-20 bg-[var(--surface-elevated)] px-2 py-px">
<div className="sticky top-0 z-20 bg-[var(--surface-elevated)] px-2 py-px">
<div className="flex items-center justify-between gap-2 px-3 py-0">
<div className="h-10 min-w-0 flex-1">
<SortableTabsStrip
@@ -2324,11 +2374,11 @@ export const Header: React.FC<HeaderProps> = ({
<TooltipTrigger asChild>
<button
type="button"
onClick={onToggleRightDrawer}
onClick={handleMobileRightDrawerToggle}
className={cn(
mobileHeaderIconButtonClass,
'relative',
rightDrawerOpen && 'bg-interactive-selection text-interactive-selection-foreground'
mobileActiveHeaderItem === 'git' && 'bg-interactive-selection text-interactive-selection-foreground'
)}
aria-label={rightDrawerOpen ? 'Close git sidebar' : 'Open git sidebar'}
>