Add mobile context notes tab (#1355)
* Add mobile context notes tab * Fix bot comments --------- Co-authored-by: Konstantin Zolin <zolin_ka@vk.com> Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
committed by
GitHub
co-authored by
Konstantin Zolin
Bohdan Triapitsyn
parent
0244d7ffcd
commit
9af0de0056
@@ -655,6 +655,7 @@ export const Header: React.FC<HeaderProps> = ({
|
||||
const { t } = useI18n();
|
||||
const setSessionSwitcherOpen = useUIStore((state) => state.setSessionSwitcherOpen);
|
||||
const toggleSidebar = useUIStore((state) => state.toggleSidebar);
|
||||
const setRightSidebarOpen = useUIStore((state) => state.setRightSidebarOpen);
|
||||
const toggleBottomTerminal = useUIStore((state) => state.toggleBottomTerminal);
|
||||
const toggleRightSidebar = useUIStore((state) => state.toggleRightSidebar);
|
||||
const openContextOverview = useUIStore((state) => state.openContextOverview);
|
||||
@@ -1506,6 +1507,7 @@ export const Header: React.FC<HeaderProps> = ({
|
||||
{ id: 'diff', label: t('layout.mainTab.diff'), icon: 'diff' },
|
||||
{ id: 'files', label: t('layout.mainTab.files'), icon: "folder-6" },
|
||||
{ id: 'terminal', label: t('layout.mainTab.terminal'), icon: "terminal-box" },
|
||||
{ id: 'context', label: t('layout.mainTab.context'), icon: "file-list-2" },
|
||||
);
|
||||
|
||||
return base;
|
||||
@@ -1520,7 +1522,7 @@ export const Header: React.FC<HeaderProps> = ({
|
||||
}, [shortcutOverrides]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isMobile && (activeMainTab === 'git' || activeMainTab === 'terminal' || activeMainTab === 'diff' || activeMainTab === 'files')) {
|
||||
if (!isMobile && (activeMainTab === 'git' || activeMainTab === 'terminal' || activeMainTab === 'diff' || activeMainTab === 'files' || activeMainTab === 'context')) {
|
||||
setActiveMainTab('chat');
|
||||
}
|
||||
}, [activeMainTab, isMobile, setActiveMainTab]);
|
||||
@@ -1626,13 +1628,16 @@ export const Header: React.FC<HeaderProps> = ({
|
||||
const num = parseInt(e.key, 10);
|
||||
if (num >= 1 && num <= tabs.length) {
|
||||
e.preventDefault();
|
||||
if (isMobile) {
|
||||
setRightSidebarOpen(false);
|
||||
}
|
||||
setActiveMainTab(tabs[num - 1].id);
|
||||
}
|
||||
}
|
||||
};
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
return () => window.removeEventListener('keydown', handleKeyDown);
|
||||
}, [tabs, setActiveMainTab]);
|
||||
}, [isMobile, setActiveMainTab, setRightSidebarOpen, tabs]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
@@ -1995,6 +2000,7 @@ export const Header: React.FC<HeaderProps> = ({
|
||||
onClick={() => {
|
||||
if (isMobile) {
|
||||
blurActiveElement();
|
||||
setRightSidebarOpen(false);
|
||||
}
|
||||
setActiveMainTab(tab.id);
|
||||
}}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Header } from './Header';
|
||||
import { BottomTerminalDock } from './BottomTerminalDock';
|
||||
import { Sidebar, SIDEBAR_CONTENT_WIDTH } from './Sidebar';
|
||||
import { RightSidebar, RIGHT_SIDEBAR_CONTENT_WIDTH } from './RightSidebar';
|
||||
import { RightSidebarTabs } from './RightSidebarTabs';
|
||||
import { ProjectContextPanel, RightSidebarTabs } from './RightSidebarTabs';
|
||||
import { ContextPanel } from './ContextPanel';
|
||||
import { ErrorBoundary } from '../ui/ErrorBoundary';
|
||||
import { CommandPalette } from '../ui/CommandPalette';
|
||||
@@ -308,6 +308,13 @@ export const MainLayout: React.FC = () => {
|
||||
};
|
||||
}, [isMobile, isTablet, setBottomTerminalOpen, setRightSidebarOpen]);
|
||||
|
||||
const handleToggleMobileRightDrawer = React.useCallback(() => {
|
||||
if (mobileLeftDrawerOpen) {
|
||||
setMobileLeftDrawerOpen(false);
|
||||
}
|
||||
setRightSidebarOpen(!isRightSidebarOpen);
|
||||
}, [isRightSidebarOpen, mobileLeftDrawerOpen, setRightSidebarOpen]);
|
||||
|
||||
const secondaryView = React.useMemo(() => {
|
||||
switch (activeMainTab) {
|
||||
case 'plan':
|
||||
@@ -320,6 +327,8 @@ export const MainLayout: React.FC = () => {
|
||||
return <React.Suspense fallback={null}><TerminalView /></React.Suspense>;
|
||||
case 'files':
|
||||
return <React.Suspense fallback={null}><FilesView /></React.Suspense>;
|
||||
case 'context':
|
||||
return <React.Suspense fallback={null}><ProjectContextPanel /></React.Suspense>;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -361,12 +370,7 @@ export const MainLayout: React.FC = () => {
|
||||
}
|
||||
setMobileLeftDrawerOpen(!mobileLeftDrawerOpen);
|
||||
},
|
||||
toggleRightDrawer: () => {
|
||||
if (mobileLeftDrawerOpen) {
|
||||
setMobileLeftDrawerOpen(false);
|
||||
}
|
||||
setRightSidebarOpen(!isRightSidebarOpen);
|
||||
},
|
||||
toggleRightDrawer: handleToggleMobileRightDrawer,
|
||||
leftDrawerX,
|
||||
rightDrawerX,
|
||||
leftDrawerWidth,
|
||||
@@ -383,10 +387,7 @@ export const MainLayout: React.FC = () => {
|
||||
setMobileLeftDrawerOpen(!mobileLeftDrawerOpen);
|
||||
}}
|
||||
onToggleRightDrawer={() => {
|
||||
if (mobileLeftDrawerOpen) {
|
||||
setMobileLeftDrawerOpen(false);
|
||||
}
|
||||
setRightSidebarOpen(!isRightSidebarOpen);
|
||||
handleToggleMobileRightDrawer();
|
||||
}}
|
||||
leftDrawerOpen={mobileLeftDrawerOpen}
|
||||
rightDrawerOpen={isRightSidebarOpen}
|
||||
|
||||
@@ -40,7 +40,7 @@ function useRightSidebarGitSync(directory: string | undefined, isSidebarOpen: bo
|
||||
}, [directory, git, isSidebarOpen, ensureStatus]);
|
||||
}
|
||||
|
||||
const ContextSidebarPanel: React.FC = () => {
|
||||
export const ProjectContextPanel: React.FC = () => {
|
||||
const activeProjectId = useProjectsStore((state) => state.activeProjectId);
|
||||
const projects = useProjectsStore((state) => state.projects);
|
||||
const homeDirectory = useDirectoryStore((state) => state.homeDirectory);
|
||||
@@ -113,7 +113,7 @@ export const RightSidebarTabs: React.FC = () => {
|
||||
{
|
||||
id: 'context',
|
||||
label: t('layout.rightSidebar.context'),
|
||||
icon: <Icon name="booklet" className="h-3.5 w-3.5" />,
|
||||
icon: <Icon name="file-list-2" className="h-3.5 w-3.5" />,
|
||||
},
|
||||
], [t]);
|
||||
|
||||
@@ -133,7 +133,7 @@ export const RightSidebarTabs: React.FC = () => {
|
||||
<div className="min-h-0 flex-1 overflow-hidden">
|
||||
{rightSidebarTab === 'git' && <GitView />}
|
||||
{rightSidebarTab === 'files' && <SidebarFilesTree />}
|
||||
{rightSidebarTab === 'context' && <ContextSidebarPanel />}
|
||||
{rightSidebarTab === 'context' && <ProjectContextPanel />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -16,6 +16,7 @@ import type { SortableDragHandleProps } from './sortableItems';
|
||||
import { SortableGroupItem, SortableProjectItem } from './sortableItems';
|
||||
import { formatProjectLabel } from './utils';
|
||||
import { useI18n } from '@/lib/i18n';
|
||||
import type { MainTab } from '@/stores/useUIStore';
|
||||
|
||||
type ProjectSection = {
|
||||
project: {
|
||||
@@ -50,7 +51,7 @@ type Props = {
|
||||
alwaysShowActions: boolean;
|
||||
toggleProject: (id: string) => void;
|
||||
setActiveProjectIdOnly: (id: string) => void;
|
||||
setActiveMainTab: (tab: 'chat' | 'plan' | 'git' | 'diff' | 'terminal' | 'files') => void;
|
||||
setActiveMainTab: (tab: MainTab) => void;
|
||||
setSessionSwitcherOpen: (open: boolean) => void;
|
||||
openNewSessionDraft: (options?: { directoryOverride?: string | null }) => void;
|
||||
openNewWorktreeDialog: () => void;
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import type { Session } from '@opencode-ai/sdk/v2';
|
||||
import type { SessionGroup, SessionNode } from '../types';
|
||||
import { normalizePath } from '../utils';
|
||||
import type { MainTab } from '@/stores/useUIStore';
|
||||
|
||||
type ProjectSection = {
|
||||
project: { id: string; normalizedPath: string };
|
||||
@@ -18,7 +19,7 @@ type Args = {
|
||||
newSessionDraftOpen: boolean;
|
||||
mobileVariant: boolean;
|
||||
openNewSessionDraft: (options?: { directoryOverride?: string | null }) => void;
|
||||
setActiveMainTab: (tab: 'chat' | 'plan' | 'git' | 'diff' | 'terminal' | 'files') => void;
|
||||
setActiveMainTab: (tab: MainTab) => void;
|
||||
setSessionSwitcherOpen: (open: boolean) => void;
|
||||
sessions: Session[];
|
||||
worktreeMetadata: Map<string, { path?: string | null }>;
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { Session } from '@opencode-ai/sdk/v2';
|
||||
import { toast } from '@/components/ui';
|
||||
import { copyTextToClipboard } from '@/lib/clipboard';
|
||||
import { useI18n } from '@/lib/i18n';
|
||||
import type { MainTab } from '@/stores/useUIStore';
|
||||
|
||||
type DeleteSessionConfirmSetter = React.Dispatch<React.SetStateAction<{
|
||||
session: Session;
|
||||
@@ -24,7 +25,7 @@ type Args = {
|
||||
setIsSessionSearchOpen: (open: boolean) => void;
|
||||
setActiveProjectIdOnly: (id: string) => void;
|
||||
setDirectory: (directory: string, options?: { showOverlay?: boolean }) => void;
|
||||
setActiveMainTab: (tab: 'chat' | 'plan' | 'git' | 'diff' | 'terminal' | 'files') => void;
|
||||
setActiveMainTab: (tab: MainTab) => void;
|
||||
setSessionSwitcherOpen: (open: boolean) => void;
|
||||
setCurrentSession: (sessionId: string | null, directoryHint?: string | null) => void;
|
||||
updateSessionTitle: (id: string, title: string) => Promise<void>;
|
||||
|
||||
@@ -24,6 +24,7 @@ export const dict = {
|
||||
'layout.mainTab.diff': 'Diff',
|
||||
'layout.mainTab.files': 'Files',
|
||||
'layout.mainTab.terminal': 'Terminal',
|
||||
'layout.mainTab.context': 'Context',
|
||||
'layout.rightSidebar.git': 'Git',
|
||||
'layout.rightSidebar.files': 'Files',
|
||||
'layout.rightSidebar.context': 'Context',
|
||||
|
||||
@@ -25,6 +25,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
"layout.mainTab.diff": "Diff",
|
||||
"layout.mainTab.files": "Archivos",
|
||||
"layout.mainTab.terminal": "Terminal",
|
||||
"layout.mainTab.context": "Contexto",
|
||||
"layout.rightSidebar.git": "Git",
|
||||
"layout.rightSidebar.files": "Archivos",
|
||||
"layout.rightSidebar.context": "Contexto",
|
||||
|
||||
@@ -25,6 +25,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'layout.mainTab.diff': '변경사항',
|
||||
'layout.mainTab.files': '파일',
|
||||
'layout.mainTab.terminal': '터미널',
|
||||
'layout.mainTab.context': '컨텍스트',
|
||||
'layout.rightSidebar.git': 'Git',
|
||||
'layout.rightSidebar.files': '파일',
|
||||
'layout.rightSidebar.context': '컨텍스트',
|
||||
|
||||
@@ -26,6 +26,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'layout.mainTab.diff': 'Różnice',
|
||||
'layout.mainTab.files': 'Pliki',
|
||||
'layout.mainTab.terminal': 'Terminal',
|
||||
'layout.mainTab.context': 'Kontekst',
|
||||
'layout.rightSidebar.git': 'Git',
|
||||
'layout.rightSidebar.files': 'Pliki',
|
||||
'layout.rightSidebar.context': 'Kontekst',
|
||||
|
||||
@@ -25,6 +25,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
"layout.mainTab.diff": "Diff",
|
||||
"layout.mainTab.files": "Arquivos",
|
||||
"layout.mainTab.terminal": "Terminal",
|
||||
"layout.mainTab.context": "Contexto",
|
||||
"layout.rightSidebar.git": "Git",
|
||||
"layout.rightSidebar.files": "Arquivos",
|
||||
"layout.rightSidebar.context": "Contexto",
|
||||
|
||||
@@ -25,6 +25,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
"layout.mainTab.diff": "Diff",
|
||||
"layout.mainTab.files": "Файли",
|
||||
"layout.mainTab.terminal": "Термінал",
|
||||
"layout.mainTab.context": "Контекст",
|
||||
"layout.rightSidebar.git": "Git",
|
||||
"layout.rightSidebar.files": "Файли",
|
||||
"layout.rightSidebar.context": "Контекст",
|
||||
|
||||
@@ -25,6 +25,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'layout.mainTab.diff': '差异',
|
||||
'layout.mainTab.files': '文件',
|
||||
'layout.mainTab.terminal': '终端',
|
||||
'layout.mainTab.context': '上下文',
|
||||
'layout.rightSidebar.git': 'Git',
|
||||
'layout.rightSidebar.files': '文件',
|
||||
'layout.rightSidebar.context': '上下文',
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { ShortcutCombo } from '@/lib/shortcuts';
|
||||
import { DEFAULT_MONO_FONT, DEFAULT_UI_FONT, type MonoFontOption, type UiFontOption } from '@/lib/fontOptions';
|
||||
import { getStoredMobileKeyboardMode, type MobileKeyboardMode } from '@/lib/mobileKeyboardMode';
|
||||
|
||||
export type MainTab = 'chat' | 'plan' | 'git' | 'diff' | 'terminal' | 'files';
|
||||
export type MainTab = 'chat' | 'plan' | 'git' | 'diff' | 'terminal' | 'files' | 'context';
|
||||
export type RightSidebarTab = 'git' | 'files' | 'context';
|
||||
export type ContextPanelMode = 'diff' | 'file' | 'context' | 'plan' | 'chat' | 'preview' | 'browser';
|
||||
export type MermaidRenderingMode = 'svg' | 'ascii';
|
||||
|
||||
Reference in New Issue
Block a user