diff --git a/packages/app/src/components/adaptive-modal-sheet.tsx b/packages/app/src/components/adaptive-modal-sheet.tsx
index d7052892b..d27993080 100644
--- a/packages/app/src/components/adaptive-modal-sheet.tsx
+++ b/packages/app/src/components/adaptive-modal-sheet.tsx
@@ -20,6 +20,7 @@ import {
useIsolatedBottomSheetVisibility,
} from "@/components/ui/isolated-bottom-sheet-modal";
import { isNative, isWeb } from "@/constants/platform";
+import { useSafeAreaInsets } from "react-native-safe-area-context";
// Horizontal indent token shared by the sheet header (title, back arrow,
// leading icon, search input icon) and any row primitive rendered inside the
@@ -458,7 +459,12 @@ export function AdaptiveModalSheet({
}: AdaptiveModalSheetProps) {
const { theme } = useUnistyles();
const isMobile = useIsCompactFormFactor();
+ const insets = useSafeAreaInsets();
const resolvedSnapPoints = useMemo(() => snapPoints ?? ["65%", "90%"], [snapPoints]);
+ const footerStyle = useMemo(
+ () => [styles.footer, isMobile ? { paddingBottom: theme.spacing[3] + insets.bottom } : null],
+ [insets.bottom, isMobile, theme.spacing],
+ );
const handleIndicatorStyle = useMemo(
() => ({ backgroundColor: theme.colors.surface2 }),
[theme.colors.surface2],
@@ -515,7 +521,7 @@ export function AdaptiveModalSheet({
) : (
{children}
)}
- {footer ? {footer} : null}
+ {footer ? {footer} : null}
);
}
@@ -534,7 +540,7 @@ export function AdaptiveModalSheet({
) : (
{children}
)}
- {footer ? {footer} : null}
+ {footer ? {footer} : null}
>
);
diff --git a/packages/app/src/components/provider-diagnostic-sheet.tsx b/packages/app/src/components/provider-diagnostic-sheet.tsx
index 79abc2487..c7edf1ae2 100644
--- a/packages/app/src/components/provider-diagnostic-sheet.tsx
+++ b/packages/app/src/components/provider-diagnostic-sheet.tsx
@@ -16,6 +16,7 @@ import {
} from "@/components/adaptive-modal-sheet";
import { Button } from "@/components/ui/button";
import { LoadingSpinner } from "@/components/ui/loading-spinner";
+import { useIsCompactFormFactor } from "@/constants/layout";
import { isWeb } from "@/constants/platform";
import { CODE_SURFACE_DATASET } from "@/styles/code-surface";
import { useDaemonConfig } from "@/hooks/use-daemon-config";
@@ -359,6 +360,69 @@ interface ProviderModalBodyProps {
theme: { iconSize: { md: number }; colors: { foregroundMuted: string } };
}
+interface ProviderSheetFooterInput {
+ fetchedAtLabel: string | null;
+ isCompact: boolean;
+ modelsRefreshing: boolean;
+ onOpenAddSheet: () => void;
+ onOpenDiagSheet: () => void;
+ onRefreshModels: () => void;
+}
+
+function renderProviderSheetFooter({
+ fetchedAtLabel,
+ isCompact,
+ modelsRefreshing,
+ onOpenAddSheet,
+ onOpenDiagSheet,
+ onRefreshModels,
+}: ProviderSheetFooterInput) {
+ const contentStyle = isCompact ? sheetStyles.compactFooterContent : sheetStyles.footerContent;
+ const actionsStyle = isCompact ? sheetStyles.compactFooterActions : sheetStyles.footerActions;
+ const buttonStyle = isCompact ? sheetStyles.compactFooterButton : null;
+ const metaStyle = isCompact ? COMPACT_FOOTER_META_STYLE : sheetStyles.footerMeta;
+
+ return (
+
+ {fetchedAtLabel || !isCompact ? (
+
+ {fetchedAtLabel ? `Updated ${fetchedAtLabel}` : ""}
+
+ ) : null}
+
+
+
+
+
+
+ );
+}
+
function ProviderModalBody(props: ProviderModalBodyProps) {
const {
discoveredCount,
@@ -446,6 +510,7 @@ export function ProviderDiagnosticSheet({
serverId,
}: ProviderDiagnosticSheetProps) {
const { theme } = useUnistyles();
+ const isCompact = useIsCompactFormFactor();
const { entries: snapshotEntries, refresh, isRefreshing } = useProvidersSnapshot(serverId);
const { config, patchConfig } = useDaemonConfig(serverId);
const [query, setQuery] = useState("");
@@ -545,38 +610,20 @@ export function ProviderDiagnosticSheet({
[providerLabel],
);
- const footer = (
- <>
-
- {fetchedAtLabel ? `Updated ${fetchedAtLabel}` : ""}
-
-
-
-
-
-
- >
- );
-
return (
<>
({
alignItems: "center",
gap: theme.spacing[3],
},
+ footerContent: {
+ flex: 1,
+ flexDirection: "row",
+ alignItems: "center",
+ justifyContent: "space-between",
+ gap: theme.spacing[2],
+ },
+ compactFooterContent: {
+ flex: 1,
+ gap: theme.spacing[2],
+ },
footerMeta: {
flex: 1,
fontSize: theme.fontSize.xs,
color: theme.colors.foregroundMuted,
},
+ compactFooterMeta: {
+ flex: 0,
+ },
footerActions: {
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[2],
},
+ compactFooterActions: {
+ gap: theme.spacing[2],
+ },
+ compactFooterButton: {
+ alignSelf: "stretch",
+ },
formGroup: {
gap: theme.spacing[3],
},
@@ -741,6 +808,7 @@ const sheetStyles = StyleSheet.create((theme) => ({
}));
const FORM_INPUT_STYLE = [sheetStyles.formInput, isWeb && { outlineStyle: "none" }];
+const COMPACT_FOOTER_META_STYLE = [sheetStyles.footerMeta, sheetStyles.compactFooterMeta];
const MAIN_SNAP_POINTS = ["65%", "92%"];
const ADD_SNAP_POINTS = ["40%"];