On mobile, the task detail page supports swiping right from the left edge to return to the task list. However, the workspace detail page (SpacesPage / SpaceDetail) does not have this swipe-back gesture on the chat list pane.
Users expect consistent mobile navigation across the app — swiping right from the left edge should always return them to the previous level (workspace list → task detail → back to workspace list).
Root Cause
SpaceDetail.tsx's SpaceChat component has a chat list pane on the left and a conversation detail pane on the right (via SwipeableTabs for mobile).
The conversation detail pane already has swipe-back via SwipeableTabs' onSwipeBackFromFirst → onSelectSpaceTask(0) (returns to chat list).
The chat list pane has no edge swipe handler — it does not call onSelectSpace(undefined) on right-swipe.
App.tsx has a top-level useEdgeSwipe hook for opening the navigation drawer, but it doesn't cover the chat list inside SpaceDetail.
Proposed Fix
In ui/src/components/spaces/SpaceDetail.tsx:
Pass onSelectSpace to SpaceChat so the chat list pane knows when to return to the workspace list.
Add useEdgeSwipe (existing hook) to the chat list <div> with onOpen: () => onSelectSpace?.(undefined).
Enable conditionally: only when onSelectSpace is provided, spaceTaskId == null (chat list view, not conversation), and !showCreate (no create dialog open).
## Problem
On mobile, the task detail page supports swiping right from the left edge to return to the task list. However, the workspace detail page (`SpacesPage` / `SpaceDetail`) does not have this swipe-back gesture on the chat list pane.
Users expect consistent mobile navigation across the app — swiping right from the left edge should always return them to the previous level (workspace list → task detail → back to workspace list).
## Root Cause
`SpaceDetail.tsx`'s `SpaceChat` component has a chat list pane on the left and a conversation detail pane on the right (via `SwipeableTabs` for mobile).
- The **conversation detail pane** already has swipe-back via `SwipeableTabs`' `onSwipeBackFromFirst` → `onSelectSpaceTask(0)` (returns to chat list).
- The **chat list pane** has no edge swipe handler — it does not call `onSelectSpace(undefined)` on right-swipe.
`App.tsx` has a top-level `useEdgeSwipe` hook for opening the navigation drawer, but it doesn't cover the chat list inside `SpaceDetail`.
## Proposed Fix
In `ui/src/components/spaces/SpaceDetail.tsx`:
1. **Pass `onSelectSpace` to `SpaceChat`** so the chat list pane knows when to return to the workspace list.
2. **Add `useEdgeSwipe`** (existing hook) to the chat list `<div>` with `onOpen: () => onSelectSpace?.(undefined)`.
3. **Enable conditionally**: only when `onSelectSpace` is provided, `spaceTaskId == null` (chat list view, not conversation), and `!showCreate` (no create dialog open).
## Diff
```diff
diff --git a/ui/src/components/spaces/SpaceDetail.tsx b/ui/src/components/spaces/SpaceDetail.tsx
index 62d9fef..921c526 100644
--- a/ui/src/components/spaces/SpaceDetail.tsx
+++ b/ui/src/components/spaces/SpaceDetail.tsx
@@ -1,4 +1,4 @@
-import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import { useCallback, useEffect, useMemo, useRef, useState, type TouchEvent } from 'react';
import { useTranslation } from 'react-i18next';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useSpaces, useArchiveSpace } from '../../hooks/useSpaces';
@@ -30,6 +30,7 @@ import { SpaceSettings } from './SpaceSettings';
import { SpaceCalendar } from './SpaceCalendar';
import { SchedulesPage } from '../../pages/SpacesPage';
import { SpaceApps } from './SpaceApps';
+import { useEdgeSwipe } from '../../hooks/useEdgeSwipe';
import { useAuthState } from '../../App';
import { SkeletonChatPane } from '../shared/Skeleton';
import { EmptyState } from '../shared/EmptyState';
@@ -189,6 +190,7 @@ export function SpaceDetail({ spaceId, spaceTaskId, initialTab, onInitialTabAppl
spaceId={spaceId}
isPersonalSpace={space.kind === 'personal'}
spaceTaskId={spaceTaskId}
+ onSelectSpace={onSelectSpace}
onSelectSpaceTask={onSelectSpaceTask}
onCreateTask={onCreateTask}
filter={chatFilter}
@@ -426,6 +428,7 @@ function SpaceChat({
spaceId,
isPersonalSpace,
spaceTaskId,
+ onSelectSpace,
onSelectSpaceTask,
filter,
onFilterChange,
@@ -433,6 +436,7 @@ function SpaceChat({
spaceId: string;
isPersonalSpace: boolean;
spaceTaskId?: number;
+ onSelectSpace?: (id: string | undefined) => void;
onSelectSpaceTask: (id: number) => void;
onCreateTask: SpaceDetailProps['onCreateTask'];
filter: SpaceChatFilter;
@@ -501,10 +505,19 @@ function SpaceChat({
onSelectSpaceTask(created.task.id);
}, [qc, onSelectSpaceTask]);
+ // 右スワイプでチャット一覧(ワークスペース一覧)に戻る(モバイル操作感)。
+ // チャット一覧画面のみで有効(会話はSwipeableTabsが処理)。
+ const edgeSwipe = useEdgeSwipe({
+ enabled: !!onSelectSpace && spaceTaskId == null && !showCreate,
+ onOpen: () => { onSelectSpace?.(undefined); },
+ });
+
return (
<div className="flex h-full min-h-0">
- {/* 左: チャット一覧。会話を開いている狭幅では隠す(会話が一覧を置き換える)。 */}
+ {/* 左: チャット一覧。右スワイプでワークスペース一覧へ戻る。
+ 会話を開いている狭幅では隠す(会話が一覧を置き換える)。 */}
<div
+ {...edgeSwipe}
className={`w-full md:w-[280px] md:shrink-0 flex flex-col min-h-0 overflow-hidden border-r border-hairline ${
spaceTaskId != null || showCreate ? 'hidden md:flex' : 'flex'
}`}
```
## Notes
- The `useEdgeSwipe` hook is already tested and used in `App.tsx` for the nav drawer. Reusing it for consistency.
- Edge width: 20px, open threshold: 60px / 22% width, vertical tolerance: 40px (from `useEdgeSwipe` defaults).
- No new dependencies or components needed.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
On mobile, the task detail page supports swiping right from the left edge to return to the task list. However, the workspace detail page (
SpacesPage/SpaceDetail) does not have this swipe-back gesture on the chat list pane.Users expect consistent mobile navigation across the app — swiping right from the left edge should always return them to the previous level (workspace list → task detail → back to workspace list).
Root Cause
SpaceDetail.tsx'sSpaceChatcomponent has a chat list pane on the left and a conversation detail pane on the right (viaSwipeableTabsfor mobile).SwipeableTabs'onSwipeBackFromFirst→onSelectSpaceTask(0)(returns to chat list).onSelectSpace(undefined)on right-swipe.App.tsxhas a top-leveluseEdgeSwipehook for opening the navigation drawer, but it doesn't cover the chat list insideSpaceDetail.Proposed Fix
In
ui/src/components/spaces/SpaceDetail.tsx:onSelectSpacetoSpaceChatso the chat list pane knows when to return to the workspace list.useEdgeSwipe(existing hook) to the chat list<div>withonOpen: () => onSelectSpace?.(undefined).onSelectSpaceis provided,spaceTaskId == null(chat list view, not conversation), and!showCreate(no create dialog open).Diff
Notes
useEdgeSwipehook is already tested and used inApp.tsxfor the nav drawer. Reusing it for consistency.useEdgeSwipedefaults).