feat: iPad split layout for the Capacitor app (#2104)
* fix: open mobile model/agent panels on tablet-width Capacitor shells and keep composer taps from dismissing the keyboard * feat: add iPadOS-style split layout to the Capacitor app - classify the Capacitor shell as mobile in device detection so shared surfaces (draft starters, panels) stop falling into tablet branches - add isIPadApp() and useOrientation() helpers - iPad: persistent full-height sessions sidebar (mobile sessions surface inline), Changes/Files in a right sidebar with header shortcut toggles - animate sidebar open/close like the desktop sidebars and add finger-sized drag-resize with persisted widths - anchor the overflow menu and the usage/metadata popover next to their header buttons regardless of open sidebars * fix: re-anchor metadata popover on layout shifts and untangle sidebar toggle updates - recompute the iPad metadata popover anchor via a ResizeObserver on its wrapper so sidebar toggles/resizes while it is open cannot leave it misplaced - move the portrait right-panel close out of the setIpadSidebarOpen updater into plain sequential state updates
This commit is contained in:
committed by
GitHub
parent
3d32ac7989
commit
ac93a52e21
@@ -60,6 +60,9 @@ import { MobileSurfaceShell } from './MobileSurfaceShell';
|
||||
type MobileSessionsSheetProps = {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
/** 'sheet' (default) wraps the content in the swipe-dismiss MobileSurfaceShell;
|
||||
'sidebar' renders the same content inline for the iPad persistent sidebar. */
|
||||
variant?: 'sheet' | 'sidebar';
|
||||
};
|
||||
|
||||
type ProjectMeta = {
|
||||
@@ -511,7 +514,7 @@ const SortableProjectRow: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
export const MobileSessionsSheet: React.FC<MobileSessionsSheetProps> = ({ open, onOpenChange }) => {
|
||||
export const MobileSessionsSheet: React.FC<MobileSessionsSheetProps> = ({ open, onOpenChange, variant = 'sheet' }) => {
|
||||
const { t } = useI18n();
|
||||
const { git } = useRuntimeAPIs();
|
||||
const liveSessions = useAllLiveSessions();
|
||||
@@ -999,14 +1002,7 @@ export const MobileSessionsSheet: React.FC<MobileSessionsSheetProps> = ({ open,
|
||||
</>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<MobileSurfaceShell
|
||||
open={open}
|
||||
onClose={() => onOpenChange(false)}
|
||||
ariaLabel={t('mobile.sessions.sheet.title')}
|
||||
title={t('mobile.sessions.sheet.title')}
|
||||
trailing={trailingActions}
|
||||
>
|
||||
const surfaceContent = (
|
||||
<div className="flex h-full flex-col">
|
||||
<div className={cn('shrink-0 px-4 pb-2 pt-1', editingOrder && 'hidden')}>
|
||||
<div className="relative">
|
||||
@@ -1294,6 +1290,34 @@ export const MobileSessionsSheet: React.FC<MobileSessionsSheetProps> = ({ open,
|
||||
onWorktreesChanged={() => setWorktreeRefreshKey((value) => value + 1)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
if (variant === 'sidebar') {
|
||||
if (!open) return null;
|
||||
return (
|
||||
<div className="flex h-full min-h-0 flex-col">
|
||||
<div className="flex h-[var(--oc-header-height,56px)] shrink-0 items-center justify-between gap-2 border-b border-border/30 px-4">
|
||||
<h2 className="truncate typography-ui-label font-semibold text-foreground">
|
||||
{t('mobile.sessions.sheet.title')}
|
||||
</h2>
|
||||
{trailingActions ? (
|
||||
<div className="flex shrink-0 items-center gap-2">{trailingActions}</div>
|
||||
) : null}
|
||||
</div>
|
||||
{surfaceContent}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<MobileSurfaceShell
|
||||
open={open}
|
||||
onClose={() => onOpenChange(false)}
|
||||
ariaLabel={t('mobile.sessions.sheet.title')}
|
||||
title={t('mobile.sessions.sheet.title')}
|
||||
trailing={trailingActions}
|
||||
>
|
||||
{surfaceContent}
|
||||
</MobileSurfaceShell>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user