fix(mobile): navigation back behavior, scroll button position
- New Chat → Chat uses replaceState so back skips new chat screen - Active tab persisted to sessionStorage, restored on back navigation - Scroll-to-bottom button positioned relative to footer (not hardcoded) - overscroll-behavior: none to prevent iOS rubber-band Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+6
-2
@@ -36,7 +36,7 @@ function persistView(view: View) {
|
||||
sessionStorage.setItem('currentView', JSON.stringify(view));
|
||||
}
|
||||
|
||||
function navigateTo(view: View) {
|
||||
function navigateTo(view: View, replace = false) {
|
||||
persistView(view);
|
||||
let url = '/';
|
||||
if (view.name === 'chat' && view.sessionId) {
|
||||
@@ -45,8 +45,12 @@ function navigateTo(view: View) {
|
||||
} else if (view.name === 'settings') {
|
||||
url = '/?view=settings';
|
||||
}
|
||||
if (replace) {
|
||||
window.history.replaceState({ view }, '', url);
|
||||
} else {
|
||||
window.history.pushState({ view }, '', url);
|
||||
}
|
||||
}
|
||||
|
||||
export function App() {
|
||||
const [authed, setAuthed] = useState(isAuthenticated());
|
||||
@@ -225,7 +229,7 @@ export function App() {
|
||||
// Navigate to chat view with cwd — ChatView will pick up globals and send the prompt
|
||||
const chatCwd = view.name === 'newchat' ? view.cwd : undefined;
|
||||
const v: View = { name: 'chat', cwd: chatCwd, initialPrompt: options.prompt, adapter: options.adapter };
|
||||
navigateTo(v);
|
||||
navigateTo(v, true); // replace newchat → chat so back goes to session list
|
||||
setView(v);
|
||||
}, [view]);
|
||||
|
||||
|
||||
@@ -253,16 +253,18 @@ export function ChatBody({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Scroll-to-bottom button */}
|
||||
{/* Scroll-to-bottom button — sits just above the footer area */}
|
||||
<div className="relative shrink-0">
|
||||
{userScrolled && (
|
||||
<button
|
||||
onClick={() => { setUserScrolled(false); scrollToBottom(true); }}
|
||||
className="absolute bottom-20 right-4 w-8 h-8 rounded-full bg-surface border border-border flex items-center justify-center shadow-lg hover:bg-surface-light transition-colors z-10"
|
||||
className="absolute -top-10 right-4 w-8 h-8 rounded-full bg-surface border border-border flex items-center justify-center shadow-lg hover:bg-surface-light transition-colors z-10"
|
||||
aria-label="Scroll to bottom"
|
||||
>
|
||||
<ArrowDownToLine className="w-4 h-4 text-text-secondary" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{renderAboveInput?.()}
|
||||
|
||||
|
||||
@@ -8,7 +8,14 @@ export function useSessions() {
|
||||
() => localStorage.getItem(STORAGE.PROJECT_DIR)
|
||||
);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [activeTab, setActiveTab] = useState<'projects' | 'active'>('projects');
|
||||
const [activeTab, _setActiveTab] = useState<'projects' | 'active'>(() => {
|
||||
const stored = sessionStorage.getItem(STORAGE.SESSIONS_TAB);
|
||||
return stored === 'active' ? 'active' : 'projects';
|
||||
});
|
||||
const setActiveTab = useCallback((tab: 'projects' | 'active') => {
|
||||
_setActiveTab(tab);
|
||||
sessionStorage.setItem(STORAGE.SESSIONS_TAB, tab);
|
||||
}, []);
|
||||
const [activeSessions, setActiveSessions] = useState<any[]>([]);
|
||||
|
||||
const fetchAll = useCallback(async () => {
|
||||
|
||||
@@ -5,6 +5,7 @@ export const STORAGE = {
|
||||
PROJECT_DIR: 'clawtap:projectDir',
|
||||
DRAFT: 'clawtap:draft',
|
||||
INSTALL_DISMISSED: 'clawtap:install-dismissed',
|
||||
SESSIONS_TAB: 'clawtap:sessionsTab',
|
||||
adapterPrefs: (id: string) => `clawtap:adapterPrefs:${id}` as const,
|
||||
} as const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user