diff --git a/apps/mobile/src/components/code-reviewer/review-memory-screen.mounted.test.tsx b/apps/mobile/src/components/code-reviewer/review-memory-screen.mounted.test.tsx
index 33aa35f43c7..0c7bfe5320d 100644
--- a/apps/mobile/src/components/code-reviewer/review-memory-screen.mounted.test.tsx
+++ b/apps/mobile/src/components/code-reviewer/review-memory-screen.mounted.test.tsx
@@ -141,6 +141,8 @@ vi.mock('@/components/query-error', () => ({
vi.mock('@/components/screen-header', () => ({ ScreenHeader: () => null }));
+vi.mock('@/components/tab-screen', () => ({ useTabBarBottomPadding: () => 0 }));
+
vi.mock('@/components/ui/button', () => ({
Button: (props: { children?: unknown; onPress?: () => void; accessibilityLabel?: string }) => {
buttons.rendered.push(props);
diff --git a/apps/mobile/src/components/code-reviewer/review-memory-screen.tsx b/apps/mobile/src/components/code-reviewer/review-memory-screen.tsx
index ff572669941..fd7edd8b0f9 100644
--- a/apps/mobile/src/components/code-reviewer/review-memory-screen.tsx
+++ b/apps/mobile/src/components/code-reviewer/review-memory-screen.tsx
@@ -9,6 +9,7 @@ import { CenteredState } from '@/components/centered-state';
import { EmptyState } from '@/components/empty-state';
import { QueryError } from '@/components/query-error';
import { ScreenHeader } from '@/components/screen-header';
+import { useTabBarBottomPadding } from '@/components/tab-screen';
import { Button } from '@/components/ui/button';
import { Brain } from '@/components/ui/icons';
import { Skeleton } from '@/components/ui/skeleton';
@@ -32,6 +33,7 @@ export function ReviewMemoryScreen({ scope }: Readonly<{ scope: string }>) {
const trpc = useTRPC();
const { t } = useTranslation();
const colors = useThemeColors();
+ const paddingBottom = useTabBarBottomPadding();
const ownerInput = reviewMemoryOwnerInput(scope);
const permission = useReviewerPermission(scope);
@@ -180,7 +182,12 @@ export function ReviewMemoryScreen({ scope }: Readonly<{ scope: string }>) {
)}
- ListFooterComponent={footer}
+ ListFooterComponent={
+ <>
+ {footer}
+
+ >
+ }
onEndReached={() => {
if (proposalsQuery.hasNextPage && !proposalsQuery.isFetchingNextPage) {
void proposalsQuery.fetchNextPage();
diff --git a/apps/mobile/src/components/empty-state.tsx b/apps/mobile/src/components/empty-state.tsx
index e9e461f9091..381295753ff 100644
--- a/apps/mobile/src/components/empty-state.tsx
+++ b/apps/mobile/src/components/empty-state.tsx
@@ -29,11 +29,12 @@ type EmptyStateProps = {
iconStrokeWidth?: number;
/** Set to 'header' when the title acts as the screen's heading (QueryError does). */
titleAccessibilityRole?: 'header';
- /** Renders the short presentation (no icon bubble, tighter block gaps) for a
- * caller whose clear region cannot hold the full height; the title, the
- * description and the action all stay. When omitted, the centered form
- * reads the band the `CenteredState` around it publishes and compacts on its
- * own, so the form cannot disagree with the reserve the caller set. */
+ /** Renders the short presentation (no icon bubble, tighter block gaps, and
+ * no top pin air above a `top`-placed stack) for a caller whose clear region
+ * cannot hold the full height; the title, the description and the action all
+ * stay. When omitted, the centered form reads the band the `CenteredState`
+ * around it publishes and compacts on its own, so the form cannot disagree
+ * with the reserve the caller set. */
compact?: boolean;
};
@@ -74,7 +75,10 @@ function EmptyStateBody({
// scroll brings them back. The bubble is decoration: a short band drops it
// and halves the gaps, which keeps the copy and the action inside the band
// with no scroll. `placement="top"` and `placement="static"` states are laid
- // out by their own caller and keep the full stack.
+ // out by their own caller and keep the full stack, unless the caller says
+ // the band is short: then the top pin's fixed air goes too, because 64pt of
+ // it is a band's whole height when a footer above the tab bar already owns
+ // the rest of a landscape window.
//
// A caller that measured its own clear region passes `compact` and owns the
// decision (the Agents screen does); otherwise the centered form reads the
@@ -87,7 +91,7 @@ function EmptyStateBody({
className={cn(
'items-center px-6',
compact ? 'gap-2' : 'gap-4',
- placement === 'top' && 'pt-16',
+ placement === 'top' && !compact && 'pt-16',
className
)}
>
diff --git a/apps/mobile/src/components/passkeys-screen.landscape.mounted.test.tsx b/apps/mobile/src/components/passkeys-screen.landscape.mounted.test.tsx
new file mode 100644
index 00000000000..62e9530600d
--- /dev/null
+++ b/apps/mobile/src/components/passkeys-screen.landscape.mounted.test.tsx
@@ -0,0 +1,62 @@
+import {
+ first,
+ hasButtonLabel,
+ list,
+ mount,
+ nodes,
+ store,
+ windowSize,
+} from './passkeys-screen.test-helpers';
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+import { waitFor } from '@/test/render-with-providers';
+
+beforeEach(() => {
+ vi.clearAllMocks();
+ windowSize.width = 411;
+ windowSize.height = 914;
+ store.rows = [];
+ list.supported.mockReturnValue(true);
+ list.queryFn.mockImplementation(() => ({ success: true, passkeys: store.rows }));
+});
+
+// ── Tests ──────────────────────────────────────────────────────────────────
+
+describe('PasskeysScreen empty state in a short window', () => {
+ it('keeps the icon bubble above the copy in portrait', async () => {
+ const view = await mount();
+ await waitFor(() => nodes(view, 'EmptyState').length === 1);
+
+ const empty = first(view, 'EmptyState');
+ expect(empty.props.compact).toBe(false);
+ expect(empty.props.title).toBe('No passkeys yet');
+ expect(hasButtonLabel(view, 'Add a passkey')).toBe(true);
+ view.unmount();
+ });
+
+ it('drops the decoration when the window is a phone held sideways', async () => {
+ // The footer above the tab bar owns most of a landscape window, so the
+ // empty state's band is shorter than the bubble plus the copy: the title
+ // and the hint would start below the fold.
+ windowSize.width = 914;
+ windowSize.height = 411;
+ const view = await mount();
+ await waitFor(() => nodes(view, 'EmptyState').length === 1);
+
+ const empty = first(view, 'EmptyState');
+ expect(empty.props.compact).toBe(true);
+ expect(empty.props.title).toBe('No passkeys yet');
+ expect(empty.props.description).toBe('Add a passkey to sign in without a password.');
+ expect(hasButtonLabel(view, 'Add a passkey')).toBe(true);
+ view.unmount();
+ });
+
+ it('keeps the full stack for a tablet in landscape', async () => {
+ windowSize.width = 1024;
+ windowSize.height = 600;
+ const view = await mount();
+ await waitFor(() => nodes(view, 'EmptyState').length === 1);
+
+ expect(first(view, 'EmptyState').props.compact).toBe(false);
+ view.unmount();
+ });
+});
diff --git a/apps/mobile/src/components/passkeys-screen.test-helpers.ts b/apps/mobile/src/components/passkeys-screen.test-helpers.ts
index a391808eb32..dd38b74442f 100644
--- a/apps/mobile/src/components/passkeys-screen.test-helpers.ts
+++ b/apps/mobile/src/components/passkeys-screen.test-helpers.ts
@@ -52,12 +52,15 @@ const list = vi.hoisted(() => ({
supported: vi.fn(() => true),
}));
const store = vi.hoisted(() => ({ rows: [] as unknown[] }));
+/** The window the screen lays out in; a test sets a landscape size to read the
+ * short-window presentation and restores it afterwards. */
+const windowSize = vi.hoisted(() => ({ width: 411, height: 914 }));
const toastSuccess = vi.hoisted(() => vi.fn());
const toastError = vi.hoisted(() => vi.fn());
const confirmSpy = vi.hoisted(() => vi.fn());
// `vi.hoisted` results cannot be exported at their declaration (vitest hoists
// them above the export), so they are exported after the declaration instead.
-export { confirmSpy, list, store, toastError, toastSuccess };
+export { confirmSpy, list, store, toastError, toastSuccess, windowSize };
/**
* The confirmation the stubbed `useConfirmDialog` captured; mirrors the
@@ -101,6 +104,7 @@ vi.mock('react-native', () => ({
Pressable: 'Pressable',
ScrollView: 'ScrollView',
TextInput: 'TextInput',
+ useWindowDimensions: () => windowSize,
View: 'View',
}));
vi.mock('@/lib/hooks/use-theme-colors', () => ({
diff --git a/apps/mobile/src/components/passkeys-screen.tsx b/apps/mobile/src/components/passkeys-screen.tsx
index d9a2e871705..4dbc2406cd6 100644
--- a/apps/mobile/src/components/passkeys-screen.tsx
+++ b/apps/mobile/src/components/passkeys-screen.tsx
@@ -1,7 +1,7 @@
import { hashKey, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { type ReactNode, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { ScrollView, View } from 'react-native';
+import { ScrollView, useWindowDimensions, View } from 'react-native';
import { toast } from 'sonner-native';
import { EmptyState } from '@/components/empty-state';
@@ -21,6 +21,7 @@ import { Skeleton } from '@/components/ui/skeleton';
import { Text } from '@/components/ui/text';
import { useAuth } from '@/lib/auth/auth-context';
import { passkeysSupported, registerPasskey } from '@/lib/auth/passkey-client';
+import { isShortViewport } from '@/lib/centered-state-layout';
import {
isLatestMutationGeneration,
nextMutationGeneration,
@@ -95,6 +96,11 @@ export function PasskeysScreen() {
const colors = useThemeColors();
const { token } = useAuth();
const tabBarBottomPadding = useTabBarBottomPadding();
+ // The body sits between the header and a footer that already reserves the
+ // tab bar, so in a phone held sideways its band is only a few dozen points
+ // tall and the full stack starts below the fold. Centered states learn this
+ // from their measured band; this plain body asks the window instead.
+ const windowSize = useWindowDimensions();
const listKey = trpc.user.getPasskeys.queryKey();
// Stable per-cache key for the removal generations: overlapping removals must
@@ -353,6 +359,7 @@ export function PasskeysScreen() {
{failureNotice}
({
}));
vi.mock('@/components/screen-header', () => ({ ScreenHeader: () => null }));
+vi.mock('@/components/tab-screen', () => ({ TabScreenScrollView: 'ScrollView' }));
vi.mock('@/components/ui/button', () => ({ Button: 'Button' }));
vi.mock('@/components/ui/form-field', () => ({ FormField: 'FormField' }));
vi.mock('@/components/ui/segmented-control', () => ({ SegmentedControl: 'SegmentedControl' }));
diff --git a/apps/mobile/src/components/profiles/new-profile-screen.tsx b/apps/mobile/src/components/profiles/new-profile-screen.tsx
index 993f79c9763..8974fec4248 100644
--- a/apps/mobile/src/components/profiles/new-profile-screen.tsx
+++ b/apps/mobile/src/components/profiles/new-profile-screen.tsx
@@ -2,7 +2,7 @@ import { canManageOrganization } from '@kilocode/app-shared/organizations';
import { useRouter } from 'expo-router';
import { useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { ScrollView, View } from 'react-native';
+import { View } from 'react-native';
import { toast } from 'sonner-native';
import {
@@ -12,6 +12,7 @@ import {
type ProfileOwnerChoice,
} from '@/components/profiles/profile-owner-model';
import { ScreenHeader } from '@/components/screen-header';
+import { TabScreenScrollView } from '@/components/tab-screen';
import { Button } from '@/components/ui/button';
import { FormField } from '@/components/ui/form-field';
import { SegmentedControl } from '@/components/ui/segmented-control';
@@ -108,7 +109,7 @@ export function NewProfileScreen() {
return (
-
{t('profiles.createAction')}
-
+
);
}
diff --git a/apps/mobile/src/components/profiles/profile-agents-screen.tsx b/apps/mobile/src/components/profiles/profile-agents-screen.tsx
index 9e8111c8bf8..59795408af7 100644
--- a/apps/mobile/src/components/profiles/profile-agents-screen.tsx
+++ b/apps/mobile/src/components/profiles/profile-agents-screen.tsx
@@ -1,6 +1,6 @@
import { type ReactNode, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { Pressable, ScrollView, View } from 'react-native';
+import { Pressable, View } from 'react-native';
import { toast } from 'sonner-native';
import { EmptyState } from '@/components/empty-state';
@@ -8,6 +8,7 @@ import { AgentFormSheet } from '@/components/profiles/agent-form-sheet';
import { agentRows, type AgentSource } from '@/components/profiles/profile-agents-model';
import { QueryError } from '@/components/query-error';
import { ScreenHeader } from '@/components/screen-header';
+import { TabScreenScrollView } from '@/components/tab-screen';
import { Button } from '@/components/ui/button';
import { useConfirmDialog } from '@/components/ui/dialog';
import { Bot, Pencil, Trash2 } from '@/components/ui/icons';
@@ -245,7 +246,7 @@ export function ProfileAgentsScreen({
return (
-
{content}
-
+
{form !== null ? (
({
useThemeColors: () => ({ mutedForeground: '#000000', destructive: '#FF0000' }),
}));
vi.mock('@/components/screen-header', () => ({ ScreenHeader: 'ScreenHeader' }));
+vi.mock('@/components/tab-screen', () => ({ TabScreenScrollView: 'ScrollView' }));
vi.mock('@/components/query-error', () => ({ QueryError: 'QueryError' }));
vi.mock('@/components/empty-state', () => ({ EmptyState: 'EmptyState' }));
vi.mock('@/components/ui/button', () => ({ Button: 'Button' }));
diff --git a/apps/mobile/src/components/profiles/profile-commands-screen.save.mounted.test.tsx b/apps/mobile/src/components/profiles/profile-commands-screen.save.mounted.test.tsx
index c04b2337fb5..fee63bb3f89 100644
--- a/apps/mobile/src/components/profiles/profile-commands-screen.save.mounted.test.tsx
+++ b/apps/mobile/src/components/profiles/profile-commands-screen.save.mounted.test.tsx
@@ -45,6 +45,7 @@ vi.mock('@/lib/hooks/use-theme-colors', () => ({
useThemeColors: () => ({ mutedForeground: '#000000', destructive: '#FF0000' }),
}));
vi.mock('@/components/screen-header', () => ({ ScreenHeader: 'ScreenHeader' }));
+vi.mock('@/components/tab-screen', () => ({ TabScreenScrollView: 'ScrollView' }));
vi.mock('@/components/query-error', () => ({ QueryError: 'QueryError' }));
vi.mock('@/components/empty-state', () => ({ EmptyState: 'EmptyState' }));
vi.mock('@/components/ui/button', () => ({ Button: 'Button' }));
diff --git a/apps/mobile/src/components/profiles/profile-commands-screen.tsx b/apps/mobile/src/components/profiles/profile-commands-screen.tsx
index ff33b429b94..28e3f985a1e 100644
--- a/apps/mobile/src/components/profiles/profile-commands-screen.tsx
+++ b/apps/mobile/src/components/profiles/profile-commands-screen.tsx
@@ -1,7 +1,7 @@
import { useRouter } from 'expo-router';
import { type ReactNode, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { Pressable, ScrollView, View } from 'react-native';
+import { Pressable, View } from 'react-native';
import { EmptyState } from '@/components/empty-state';
import {
@@ -18,6 +18,7 @@ import {
} from '@/components/profiles/profile-commands-model';
import { QueryError } from '@/components/query-error';
import { ScreenHeader } from '@/components/screen-header';
+import { TabScreenScrollView } from '@/components/tab-screen';
import { Button } from '@/components/ui/button';
import { FormField } from '@/components/ui/form-field';
import { ChevronDown, ChevronUp, Terminal, Trash2 } from '@/components/ui/icons';
@@ -272,7 +273,7 @@ export function ProfileCommandsScreen({
void leave();
}}
/>
-
{content}
-
+
);
}
diff --git a/apps/mobile/src/components/profiles/profile-kilo-commands-screen.tsx b/apps/mobile/src/components/profiles/profile-kilo-commands-screen.tsx
index ec7210cee00..de318163b92 100644
--- a/apps/mobile/src/components/profiles/profile-kilo-commands-screen.tsx
+++ b/apps/mobile/src/components/profiles/profile-kilo-commands-screen.tsx
@@ -1,6 +1,6 @@
import { type ReactNode, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { ScrollView, View } from 'react-native';
+import { View } from 'react-native';
import { toast } from 'sonner-native';
import { EmptyState } from '@/components/empty-state';
@@ -17,6 +17,7 @@ import {
} from '@/components/profiles/profile-kilo-commands-model';
import { QueryError } from '@/components/query-error';
import { ScreenHeader } from '@/components/screen-header';
+import { TabScreenScrollView } from '@/components/tab-screen';
import { Button } from '@/components/ui/button';
import { useConfirmDialog } from '@/components/ui/dialog';
import { Terminal } from '@/components/ui/icons';
@@ -222,7 +223,7 @@ export function ProfileKiloCommandsScreen({
return (
-
{content}
-
+
{form !== null ? (
({
}));
vi.mock('@/components/sheet-header', () => ({ SheetHeader: 'SheetHeader' }));
vi.mock('@/components/screen-header', () => ({ ScreenHeader: 'ScreenHeader' }));
+vi.mock('@/components/tab-screen', () => ({ TabScreenScrollView: 'ScrollView' }));
vi.mock('@/components/query-error', () => ({ QueryError: 'QueryError' }));
vi.mock('@/components/empty-state', () => ({ EmptyState: 'EmptyState' }));
vi.mock('@/components/ui/button', () => ({ Button: 'Button' }));
diff --git a/apps/mobile/src/components/profiles/profile-mcp-screen.tsx b/apps/mobile/src/components/profiles/profile-mcp-screen.tsx
index 7eae98ae97e..98e9be4db45 100644
--- a/apps/mobile/src/components/profiles/profile-mcp-screen.tsx
+++ b/apps/mobile/src/components/profiles/profile-mcp-screen.tsx
@@ -1,6 +1,6 @@
import { type ReactNode, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { Pressable, ScrollView, Switch, View } from 'react-native';
+import { Pressable, Switch, View } from 'react-native';
import { toast } from 'sonner-native';
import { EmptyState } from '@/components/empty-state';
@@ -12,6 +12,7 @@ import {
} from '@/components/profiles/profile-mcp-model';
import { QueryError } from '@/components/query-error';
import { ScreenHeader } from '@/components/screen-header';
+import { TabScreenScrollView } from '@/components/tab-screen';
import { Button } from '@/components/ui/button';
import { useConfirmDialog } from '@/components/ui/dialog';
import { Lock, Pencil, Server, Trash2 } from '@/components/ui/icons';
@@ -245,7 +246,7 @@ export function ProfileMcpScreen({
return (
-
{content}
-
+
{form !== null ? (
({
}));
vi.mock('@/components/sheet-header', () => ({ SheetHeader: 'SheetHeader' }));
vi.mock('@/components/screen-header', () => ({ ScreenHeader: 'ScreenHeader' }));
+vi.mock('@/components/tab-screen', () => ({ TabScreenScrollView: 'ScrollView' }));
vi.mock('@/components/query-error', () => ({ QueryError: 'QueryError' }));
vi.mock('@/components/empty-state', () => ({ EmptyState: 'EmptyState' }));
vi.mock('@/components/ui/button', () => ({ Button: 'Button' }));
diff --git a/apps/mobile/src/components/profiles/profile-skills-screen.tsx b/apps/mobile/src/components/profiles/profile-skills-screen.tsx
index 17f2d3f777e..9adab74fa4c 100644
--- a/apps/mobile/src/components/profiles/profile-skills-screen.tsx
+++ b/apps/mobile/src/components/profiles/profile-skills-screen.tsx
@@ -1,6 +1,6 @@
import { type ReactNode, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { Pressable, ScrollView, Switch, View } from 'react-native';
+import { Pressable, Switch, View } from 'react-native';
import { toast } from 'sonner-native';
import { EmptyState } from '@/components/empty-state';
@@ -8,6 +8,7 @@ import { skillRowSubtitle } from '@/components/profiles/skill-markdown';
import { SkillFormSheet, type SkillFormSubmission } from '@/components/profiles/skill-form-sheet';
import { QueryError } from '@/components/query-error';
import { ScreenHeader } from '@/components/screen-header';
+import { TabScreenScrollView } from '@/components/tab-screen';
import { Button } from '@/components/ui/button';
import { useConfirmDialog } from '@/components/ui/dialog';
import { Pencil, Sparkles, Trash2 } from '@/components/ui/icons';
@@ -224,7 +225,7 @@ export function ProfileSkillsScreen({
return (
-
{content}
-
+
{form !== null ? (
({
useConfirmDialog: () => ({ confirm: h.confirm, dialog: null }),
}));
vi.mock('@/components/screen-header', () => ({ ScreenHeader: 'ScreenHeader' }));
+vi.mock('@/components/tab-screen', () => ({ TabScreenScrollView: 'ScrollView' }));
vi.mock('@/components/query-error', () => ({ QueryError: 'QueryError' }));
vi.mock('@/components/empty-state', () => ({ EmptyState: 'EmptyState' }));
vi.mock('@/components/ui/button', () => ({ Button: 'Button' }));
diff --git a/apps/mobile/src/components/profiles/profile-variables-screen.tsx b/apps/mobile/src/components/profiles/profile-variables-screen.tsx
index 74314d2316f..c100b9145b4 100644
--- a/apps/mobile/src/components/profiles/profile-variables-screen.tsx
+++ b/apps/mobile/src/components/profiles/profile-variables-screen.tsx
@@ -1,6 +1,6 @@
import { type ReactNode, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { ScrollView, View } from 'react-native';
+import { View } from 'react-native';
import { toast } from 'sonner-native';
import { EmptyState } from '@/components/empty-state';
@@ -18,6 +18,7 @@ import {
} from '@/components/profiles/profile-variables-rows';
import { QueryError } from '@/components/query-error';
import { ScreenHeader } from '@/components/screen-header';
+import { TabScreenScrollView } from '@/components/tab-screen';
import { Button } from '@/components/ui/button';
import { useConfirmDialog } from '@/components/ui/dialog';
import { KeyRound } from '@/components/ui/icons';
@@ -207,7 +208,7 @@ export function ProfileVariablesScreen({
return (
-
{content}
-
+
{dialog}
diff --git a/apps/mobile/src/components/profiles/repo-bindings-screen.mounted.test.tsx b/apps/mobile/src/components/profiles/repo-bindings-screen.mounted.test.tsx
index 9b6fd86ea0a..4a09e90cabf 100644
--- a/apps/mobile/src/components/profiles/repo-bindings-screen.mounted.test.tsx
+++ b/apps/mobile/src/components/profiles/repo-bindings-screen.mounted.test.tsx
@@ -82,6 +82,7 @@ vi.mock('@/components/agents/session-page-sheet', () => ({
}));
vi.mock('@/components/sheet-header', () => ({ SheetHeader: 'SheetHeader' }));
vi.mock('@/components/screen-header', () => ({ ScreenHeader: 'ScreenHeader' }));
+vi.mock('@/components/tab-screen', () => ({ TabScreenScrollView: 'ScrollView' }));
vi.mock('@/components/query-error', () => ({ QueryError: 'QueryError' }));
vi.mock('@/components/empty-state', () => ({ EmptyState: 'EmptyState' }));
vi.mock('@/components/ui/button', () => ({ Button: 'Button' }));
diff --git a/apps/mobile/src/components/profiles/repo-bindings-screen.tsx b/apps/mobile/src/components/profiles/repo-bindings-screen.tsx
index 0f6cc95bd83..1b8d64b5ba8 100644
--- a/apps/mobile/src/components/profiles/repo-bindings-screen.tsx
+++ b/apps/mobile/src/components/profiles/repo-bindings-screen.tsx
@@ -1,6 +1,6 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { Pressable, ScrollView, View } from 'react-native';
+import { Pressable, View } from 'react-native';
import { toast } from 'sonner-native';
import { EmptyState } from '@/components/empty-state';
@@ -14,6 +14,7 @@ import {
} from '@/components/profiles/repo-bindings-model';
import { QueryError } from '@/components/query-error';
import { ScreenHeader } from '@/components/screen-header';
+import { TabScreenScrollView } from '@/components/tab-screen';
import { Button } from '@/components/ui/button';
import { ChevronDown, GitBranch, Trash2 } from '@/components/ui/icons';
import { Skeleton } from '@/components/ui/skeleton';
@@ -190,7 +191,7 @@ export function RepoBindingsScreen({ organizationId }: Readonly<{ organizationId
return (
- {t('profiles.repoBindings.add')}
)}
-
+
{repoPickerOpen ? (