fix(web): keep mobile views scrollable and new-session actions reachable (#364)

This commit is contained in:
Qihan
2026-03-26 08:04:58 +08:00
committed by GitHub
parent 92885ddef0
commit 2b133feec5
10 changed files with 33 additions and 14 deletions
+1 -1
View File
@@ -347,7 +347,7 @@ function AppInner() {
/>
<VoiceErrorBanner />
<OfflineBanner />
<div className="h-full flex flex-col">
<div className="h-full min-h-0 flex flex-col">
<Outlet />
</div>
<ToastContainer />
+17 -1
View File
@@ -1,4 +1,4 @@
import { useState } from 'react'
import { useEffect, useState } from 'react'
import { usePWAInstall } from '@/hooks/usePWAInstall'
import { usePlatform } from '@/hooks/usePlatform'
import { CloseIcon, ShareIcon, PlusCircleIcon } from '@/components/icons'
@@ -9,6 +9,22 @@ export function InstallPrompt() {
const { canInstall, canInstallIOS, promptInstall, dismissInstall, isStandalone } = usePWAInstall()
const { isTelegram, haptic } = usePlatform()
const [showIOSGuide, setShowIOSGuide] = useState(false)
const showFloatingPrompt = !isTelegram && !isStandalone && ((canInstallIOS && !showIOSGuide) || canInstall)
useEffect(() => {
const root = document.documentElement
if (!root) return
if (showFloatingPrompt) {
root.style.setProperty('--app-floating-bottom-offset', '112px')
} else {
root.style.removeProperty('--app-floating-bottom-offset')
}
return () => {
root.style.removeProperty('--app-floating-bottom-offset')
}
}, [showFloatingPrompt])
if (isTelegram || isStandalone) {
return null
@@ -13,7 +13,7 @@ export function ActionButtons(props: {
const { t } = useTranslation()
return (
<div className="flex gap-2 px-3 py-3">
<div className="flex gap-2 px-3 pt-3 pb-[calc(env(safe-area-inset-bottom)+1rem)]">
<Button
variant="secondary"
onClick={props.onCancel}
@@ -13,7 +13,7 @@ export function AgentSelector(props: {
<label className="text-xs font-medium text-[var(--app-hint)]">
{t('newSession.agent')}
</label>
<div className="flex gap-3">
<div className="flex flex-wrap gap-x-3 gap-y-2">
{(['claude', 'codex', 'cursor', 'gemini', 'opencode'] as const).map((agentType) => (
<label
key={agentType}
+1 -1
View File
@@ -323,7 +323,7 @@ export function SessionChat(props: {
})
return (
<div className="flex h-full flex-col">
<div className="flex h-full min-h-0 flex-col">
<SessionHeader
session={props.session}
onBack={props.onBack}
+4 -1
View File
@@ -368,7 +368,10 @@ function NewSessionPage() {
<div className="flex-1 font-semibold">{t('newSession.title')}</div>
</div>
<div className="app-scroll-y flex-1 min-h-0">
<div
className="app-scroll-y flex-1 min-h-0"
style={{ paddingBottom: 'calc(var(--app-floating-bottom-offset, 0px) + env(safe-area-inset-bottom))' }}
>
{machinesError ? (
<div className="p-3 text-sm text-red-600">
{machinesError}
+2 -2
View File
@@ -196,7 +196,7 @@ export default function FilePage() {
const diffErrorMessage = diffError ? `Diff unavailable: ${diffError}` : null
return (
<div className="flex h-full flex-col">
<div className="flex h-full min-h-0 flex-col">
<div className="bg-[var(--app-bg)] pt-[env(safe-area-inset-top)]">
<div className="mx-auto w-full max-w-content flex items-center gap-2 p-3 border-b border-[var(--app-border)]">
<button
@@ -249,7 +249,7 @@ export default function FilePage() {
</div>
) : null}
<div className="app-scroll-y flex-1">
<div className="app-scroll-y flex-1 min-h-0">
<div className="mx-auto w-full max-w-content p-4">
{diffErrorMessage ? (
<div className="mb-3 rounded-md bg-amber-500/10 p-2 text-xs text-[var(--app-hint)]">
+2 -2
View File
@@ -306,7 +306,7 @@ export default function FilesPage() {
}, [navigate, sessionId])
return (
<div className="flex h-full flex-col">
<div className="flex h-full min-h-0 flex-col">
<div className="bg-[var(--app-bg)] pt-[env(safe-area-inset-top)]">
<div className="mx-auto w-full max-w-content flex items-center gap-2 p-3 border-b border-[var(--app-border)]">
<button
@@ -390,7 +390,7 @@ export default function FilesPage() {
</div>
) : null}
<div className="app-scroll-y flex-1">
<div className="app-scroll-y flex-1 min-h-0">
<div className="mx-auto w-full max-w-content">
{showGitErrorBanner && activeTab === 'changes' ? (
<div className="border-b border-[var(--app-divider)] bg-amber-500/10 px-3 py-2 text-xs text-[var(--app-hint)]">
+2 -2
View File
@@ -409,7 +409,7 @@ export default function TerminalPage() {
: null
return (
<div className="flex h-full flex-col">
<div className="flex h-full min-h-0 flex-col">
<div className="bg-[var(--app-bg)] pt-[env(safe-area-inset-top)]">
<div className="mx-auto w-full max-w-content flex items-center gap-2 p-3 border-b border-[var(--app-border)]">
<button
@@ -452,7 +452,7 @@ export default function TerminalPage() {
</div>
) : null}
<div className="flex-1 overflow-hidden bg-[var(--app-bg)]">
<div className="flex-1 min-h-0 overflow-hidden bg-[var(--app-bg)]">
<div className="mx-auto h-full w-full max-w-content p-3">
{terminalSupported ? (
<TerminalView onMount={handleTerminalMount} onResize={handleResize} className="h-full w-full" />
+2 -2
View File
@@ -177,7 +177,7 @@ export default function SettingsPage() {
}, [isOpen, isAppearanceOpen, isFontOpen, isTerminalFontOpen, isVoiceOpen])
return (
<div className="flex h-full flex-col">
<div className="flex h-full min-h-0 flex-col">
<div className="bg-[var(--app-bg)] pt-[env(safe-area-inset-top)]">
<div className="mx-auto w-full max-w-content flex items-center gap-2 p-3 border-b border-[var(--app-border)]">
<button
@@ -191,7 +191,7 @@ export default function SettingsPage() {
</div>
</div>
<div className="app-scroll-y flex-1">
<div className="app-scroll-y flex-1 min-h-0">
<div className="mx-auto w-full max-w-content">
{/* Language section */}
<div className="border-b border-[var(--app-divider)]">