Refine changes panel controls
This commit is contained in:
@@ -199,7 +199,7 @@ const getTabLabel = (
|
||||
}
|
||||
|
||||
if (tab.mode === 'diff') {
|
||||
return tab.stagedDiff ? t('contextPanel.mode.stagedDiff') : t('contextPanel.mode.workingDiff');
|
||||
return t('contextPanel.mode.diff');
|
||||
}
|
||||
|
||||
return getModeLabel(tab.mode, t);
|
||||
@@ -1997,6 +1997,7 @@ export const ContextPanel: React.FC = () => {
|
||||
const panelState = useUIStore((state) => (directoryKey ? state.contextPanelByDirectory[directoryKey] : undefined));
|
||||
const closeContextPanel = useUIStore((state) => state.closeContextPanel);
|
||||
const closeContextPanelTab = useUIStore((state) => state.closeContextPanelTab);
|
||||
const openContextPanelTab = useUIStore((state) => state.openContextPanelTab);
|
||||
const toggleContextPanelExpanded = useUIStore((state) => state.toggleContextPanelExpanded);
|
||||
const setContextPanelWidth = useUIStore((state) => state.setContextPanelWidth);
|
||||
const setActiveContextPanelTab = useUIStore((state) => state.setActiveContextPanelTab);
|
||||
@@ -2178,6 +2179,18 @@ export const ContextPanel: React.FC = () => {
|
||||
|
||||
const activeChatTabID = activeTab?.mode === 'chat' ? activeTab.id : null;
|
||||
|
||||
const handleDiffScopeChange = React.useCallback((nextScope: 'working' | 'staged') => {
|
||||
if (!directoryKey || activeTab?.mode !== 'diff') {
|
||||
return;
|
||||
}
|
||||
|
||||
openContextPanelTab(directoryKey, {
|
||||
mode: 'diff',
|
||||
targetPath: activeTab.targetPath,
|
||||
stagedDiff: nextScope === 'staged',
|
||||
});
|
||||
}, [activeTab, directoryKey, openContextPanelTab]);
|
||||
|
||||
const postThemeSyncToEmbeddedChat = React.useCallback(() => {
|
||||
if (typeof window === 'undefined') {
|
||||
return;
|
||||
@@ -2286,6 +2299,7 @@ export const ContextPanel: React.FC = () => {
|
||||
pinSelectedFileHeaderToTopOnNavigate
|
||||
showOpenInEditorAction
|
||||
diffScope={activeTab.stagedDiff ? 'staged' : 'working'}
|
||||
onDiffScopeChange={handleDiffScopeChange}
|
||||
targetFilePath={activeTab.targetPath}
|
||||
flushContent
|
||||
/>
|
||||
|
||||
@@ -717,6 +717,7 @@ export const Header: React.FC<HeaderProps> = ({
|
||||
const openContextOverview = useUIStore((state) => state.openContextOverview);
|
||||
const openContextPlan = useUIStore((state) => state.openContextPlan);
|
||||
const openContextBrowser = useUIStore((state) => state.openContextBrowser);
|
||||
const openContextPanelTab = useUIStore((state) => state.openContextPanelTab);
|
||||
const closeContextPanel = useUIStore((state) => state.closeContextPanel);
|
||||
const contextPanelByDirectory = useUIStore((state) => state.contextPanelByDirectory);
|
||||
const activeMainTab = useUIStore((state) => state.activeMainTab);
|
||||
@@ -1495,6 +1496,21 @@ export const Header: React.FC<HeaderProps> = ({
|
||||
openContextPlan(directory);
|
||||
}, [closeContextPanel, contextPanelByDirectory, openContextPlan, openDirectory]);
|
||||
|
||||
const handleOpenContextChanges = React.useCallback(() => {
|
||||
const directory = normalize(openDirectory || '');
|
||||
if (!directory) {
|
||||
return;
|
||||
}
|
||||
|
||||
const panelState = contextPanelByDirectory[directory];
|
||||
if (getActiveContextMode(panelState) === 'diff') {
|
||||
closeContextPanel(directory);
|
||||
return;
|
||||
}
|
||||
|
||||
openContextPanelTab(directory, { mode: 'diff', stagedDiff: false });
|
||||
}, [closeContextPanel, contextPanelByDirectory, openContextPanelTab, openDirectory]);
|
||||
|
||||
const handleOpenContextBrowser = React.useCallback(() => {
|
||||
const directory = normalize(openDirectory || '');
|
||||
if (!directory) {
|
||||
@@ -1519,6 +1535,15 @@ export const Header: React.FC<HeaderProps> = ({
|
||||
return getActiveContextMode(panelState) === 'plan';
|
||||
}, [contextPanelByDirectory, openDirectory]);
|
||||
|
||||
const isContextChangesActive = React.useMemo(() => {
|
||||
const directory = normalize(openDirectory || '');
|
||||
if (!directory) {
|
||||
return false;
|
||||
}
|
||||
const panelState = contextPanelByDirectory[directory];
|
||||
return getActiveContextMode(panelState) === 'diff';
|
||||
}, [contextPanelByDirectory, openDirectory]);
|
||||
|
||||
const isContextBrowserActive = React.useMemo(() => {
|
||||
const directory = normalize(openDirectory || '');
|
||||
if (!directory) {
|
||||
@@ -1992,6 +2017,28 @@ export const Header: React.FC<HeaderProps> = ({
|
||||
|
||||
const desktopSidebarActions = (
|
||||
<>
|
||||
{!isVSCode ? (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
aria-label={t('header.actions.toggleChangesPanelAria')}
|
||||
aria-pressed={isContextChangesActive}
|
||||
onClick={handleOpenContextChanges}
|
||||
className={desktopHeaderIconButtonClass}
|
||||
>
|
||||
<span className="relative h-5 w-5 overflow-hidden rounded-[2px]">
|
||||
<span className="absolute left-[4px] top-[4px] h-3 w-[5px] bg-[var(--status-error)]/25" />
|
||||
<span className="absolute right-[4px] top-[4px] h-3 w-[5px] bg-[var(--status-success)]/25" />
|
||||
<Icon name="layout-column" className="absolute inset-0 h-5 w-5" />
|
||||
</span>
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t('header.actions.toggleChangesPanel')}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{showPlanTab && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
|
||||
@@ -176,12 +176,22 @@ const createTextDiffDataFromPatch = (filePath: string, patch: string): DiffData
|
||||
};
|
||||
};
|
||||
|
||||
const formatDiffTotals = (insertions?: number, deletions?: number) => {
|
||||
const formatDiffTotals = (
|
||||
insertions?: number,
|
||||
deletions?: number,
|
||||
options?: { shrink?: boolean; className?: string },
|
||||
) => {
|
||||
const added = insertions ?? 0;
|
||||
const removed = deletions ?? 0;
|
||||
if (!added && !removed) return null;
|
||||
return (
|
||||
<span className="typography-meta flex flex-shrink-0 items-center gap-1 text-xs whitespace-nowrap">
|
||||
<span
|
||||
className={cn(
|
||||
'typography-meta flex items-center gap-1 text-xs whitespace-nowrap',
|
||||
options?.shrink ? 'min-w-0 overflow-hidden' : 'flex-shrink-0',
|
||||
options?.className,
|
||||
)}
|
||||
>
|
||||
{added ? <span style={{ color: 'var(--status-success)' }}>+{added}</span> : null}
|
||||
{removed ? <span style={{ color: 'var(--status-error)' }}>-{removed}</span> : null}
|
||||
</span>
|
||||
@@ -232,6 +242,7 @@ interface FileSelectorProps {
|
||||
selectedFile: string | null;
|
||||
selectedFileEntry: FileEntry | null;
|
||||
onSelectFile: (path: string) => void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const FileSelector = React.memo<FileSelectorProps>(({
|
||||
@@ -239,6 +250,7 @@ const FileSelector = React.memo<FileSelectorProps>(({
|
||||
selectedFile,
|
||||
selectedFileEntry,
|
||||
onSelectFile,
|
||||
className,
|
||||
}) => {
|
||||
const { t } = useI18n();
|
||||
|
||||
@@ -247,24 +259,27 @@ const FileSelector = React.memo<FileSelectorProps>(({
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button className="flex h-7 min-w-0 max-w-[min(52rem,60vw)] items-center gap-2 rounded-lg border border-input bg-transparent px-2 typography-ui-label text-foreground outline-none hover:bg-interactive-hover hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring">
|
||||
<button className={cn(
|
||||
'diff-toolbar__file-trigger flex h-7 min-w-[3.75rem] max-w-full items-center gap-2 rounded-lg border border-input bg-transparent px-2 typography-ui-label text-foreground outline-none hover:bg-interactive-hover hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring',
|
||||
className,
|
||||
)}>
|
||||
{selectedFileEntry ? (
|
||||
<div className="flex min-w-0 flex-1 items-center gap-3">
|
||||
<div className="diff-toolbar__file-trigger-content flex min-w-0 flex-1 items-center gap-2">
|
||||
<FileTypeIcon filePath={selectedFileEntry.path} className="h-3.5 w-3.5 flex-shrink-0" />
|
||||
<DiffFilePathLabel path={selectedFileEntry.path} className="flex-1" />
|
||||
{formatDiffTotals(selectedFileEntry.insertions, selectedFileEntry.deletions)}
|
||||
<DiffFilePathLabel path={selectedFileEntry.path} className="diff-toolbar__file-label min-w-0 flex-1" />
|
||||
{formatDiffTotals(selectedFileEntry.insertions, selectedFileEntry.deletions, { shrink: true, className: 'diff-toolbar__file-stats' })}
|
||||
</div>
|
||||
) : (
|
||||
<span className="text-muted-foreground">{t('diffView.selector.selectFile')}</span>
|
||||
<span className="min-w-0 truncate text-muted-foreground">{t('diffView.selector.selectFile')}</span>
|
||||
)}
|
||||
<Icon name="arrow-down-s" className="size-4 opacity-50" />
|
||||
<Icon name="arrow-down-s" className="size-4 flex-shrink-0 opacity-50" />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="max-h-[70vh] w-[max(var(--anchor-width),min(28rem,calc(100vw-2rem)))] max-w-[calc(100vw-2rem)] overflow-y-auto">
|
||||
<DropdownMenuContent className="max-h-[70vh] w-[min(max(var(--anchor-width),18rem),36rem,calc(100vw-2rem))] max-w-[calc(100vw-2rem)] overflow-y-auto">
|
||||
<DropdownMenuRadioGroup value={selectedFile ?? ''} onValueChange={onSelectFile}>
|
||||
{changedFiles.map((file) => (
|
||||
<DropdownMenuRadioItem key={file.path} value={file.path} className="min-w-0 items-center">
|
||||
<div className="flex w-full min-w-0 items-center gap-3">
|
||||
<div className="flex w-full min-w-0 items-center gap-2.5">
|
||||
<FileTypeIcon filePath={file.path} className="h-3.5 w-3.5 flex-shrink-0" />
|
||||
<DiffFilePathLabel path={file.path} className="flex-1" />
|
||||
{formatDiffTotals(file.insertions, file.deletions)}
|
||||
@@ -277,6 +292,64 @@ const FileSelector = React.memo<FileSelectorProps>(({
|
||||
);
|
||||
});
|
||||
|
||||
interface ChangeScopeSelectorProps {
|
||||
scope: Extract<DiffScope, 'working' | 'staged'>;
|
||||
workingCount: number;
|
||||
stagedCount: number;
|
||||
onScopeChange?: (scope: Extract<DiffScope, 'working' | 'staged'>) => void;
|
||||
}
|
||||
|
||||
const ChangeScopeSelector = React.memo<ChangeScopeSelectorProps>(({
|
||||
scope,
|
||||
workingCount,
|
||||
stagedCount,
|
||||
onScopeChange,
|
||||
}) => {
|
||||
const { t } = useI18n();
|
||||
const currentCount = scope === 'staged' ? stagedCount : workingCount;
|
||||
const currentLabel = scope === 'staged' ? t('diffView.scope.staged') : t('diffView.scope.changed');
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="flex h-7 flex-shrink-0 items-center gap-1.5 rounded-md px-2 typography-ui-label font-semibold text-foreground outline-none hover:bg-interactive-hover focus-visible:ring-2 focus-visible:ring-ring"
|
||||
aria-label={t('diffView.scope.selectorAria')}
|
||||
>
|
||||
<span className="whitespace-nowrap">
|
||||
{currentLabel}<span className="diff-toolbar__scope-count">: {currentCount}</span>
|
||||
</span>
|
||||
<Icon name="arrow-down-s" className="size-4 flex-shrink-0 opacity-60" />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start" className="w-40">
|
||||
<DropdownMenuRadioGroup
|
||||
value={scope}
|
||||
onValueChange={(value) => {
|
||||
if (value === 'working' || value === 'staged') {
|
||||
onScopeChange?.(value);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DropdownMenuRadioItem value="working">
|
||||
<span className="flex min-w-0 flex-1 items-center justify-between gap-3">
|
||||
<span>{t('diffView.scope.changed')}</span>
|
||||
<span className="typography-meta text-muted-foreground">{workingCount}</span>
|
||||
</span>
|
||||
</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem value="staged">
|
||||
<span className="flex min-w-0 flex-1 items-center justify-between gap-3">
|
||||
<span>{t('diffView.scope.staged')}</span>
|
||||
<span className="typography-meta text-muted-foreground">{stagedCount}</span>
|
||||
</span>
|
||||
</DropdownMenuRadioItem>
|
||||
</DropdownMenuRadioGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
});
|
||||
|
||||
interface FileListProps {
|
||||
changedFiles: FileEntry[];
|
||||
selectedFile: string | null;
|
||||
@@ -766,6 +839,7 @@ interface DiffViewProps {
|
||||
pinSelectedFileHeaderToTopOnNavigate?: boolean;
|
||||
showOpenInEditorAction?: boolean;
|
||||
diffScope?: DiffScope;
|
||||
onDiffScopeChange?: (scope: Extract<DiffScope, 'working' | 'staged'>) => void;
|
||||
targetFilePath?: string | null;
|
||||
/** Render diff content flush with the container edges (no outer padding). */
|
||||
flushContent?: boolean;
|
||||
@@ -778,6 +852,7 @@ export const DiffView: React.FC<DiffViewProps> = ({
|
||||
pinSelectedFileHeaderToTopOnNavigate = false,
|
||||
showOpenInEditorAction = false,
|
||||
diffScope = 'all',
|
||||
onDiffScopeChange,
|
||||
targetFilePath = null,
|
||||
flushContent = false,
|
||||
}) => {
|
||||
@@ -868,6 +943,16 @@ export const DiffView: React.FC<DiffViewProps> = ({
|
||||
.sort((a, b) => a.path.localeCompare(b.path));
|
||||
}, [diffScope, status]);
|
||||
|
||||
const workingFileCount = React.useMemo(() => {
|
||||
if (!status?.files) return 0;
|
||||
return status.files.filter(isWorkingStatusFile).length;
|
||||
}, [status]);
|
||||
|
||||
const stagedFileCount = React.useMemo(() => {
|
||||
if (!status?.files) return 0;
|
||||
return status.files.filter(isStagedStatusFile).length;
|
||||
}, [status]);
|
||||
|
||||
const selectedFileEntry = React.useMemo(() => {
|
||||
if (!selectedFile) return null;
|
||||
return changedFiles.find((file) => file.path === selectedFile) ?? null;
|
||||
@@ -1391,18 +1476,26 @@ export const DiffView: React.FC<DiffViewProps> = ({
|
||||
|
||||
return (
|
||||
<div className="flex h-full flex-col overflow-hidden bg-background">
|
||||
<div className="flex items-center gap-3 px-3 py-2 bg-background">
|
||||
<div className="@container/diff-toolbar flex min-w-0 items-center gap-2 px-3 py-2 bg-background">
|
||||
{!isMobile && (
|
||||
<div className="flex items-center gap-1 rounded-md px-2 py-1 text-muted-foreground shrink-0">
|
||||
<Icon name="git-commit" className="h-4 w-4" />
|
||||
<span className="typography-ui-label font-semibold text-foreground">
|
||||
{isLoadingStatus && !status
|
||||
? t('diffView.state.loadingChanges')
|
||||
: (changedFiles.length === 1
|
||||
? t('diffView.summary.changedFilesSingle', { count: changedFiles.length })
|
||||
: t('diffView.summary.changedFilesPlural', { count: changedFiles.length }))}
|
||||
</span>
|
||||
</div>
|
||||
diffScope === 'working' || diffScope === 'staged' ? (
|
||||
<ChangeScopeSelector
|
||||
scope={diffScope}
|
||||
workingCount={workingFileCount}
|
||||
stagedCount={stagedFileCount}
|
||||
onScopeChange={onDiffScopeChange}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex items-center gap-1 rounded-md px-2 py-1 text-muted-foreground shrink-0">
|
||||
<span className="typography-ui-label font-semibold text-foreground">
|
||||
{isLoadingStatus && !status
|
||||
? t('diffView.state.loadingChanges')
|
||||
: (changedFiles.length === 1
|
||||
? t('diffView.summary.changedFilesSingle', { count: changedFiles.length })
|
||||
: t('diffView.summary.changedFilesPlural', { count: changedFiles.length }))}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
{showFileSelector && (
|
||||
<FileSelector
|
||||
@@ -1410,22 +1503,26 @@ export const DiffView: React.FC<DiffViewProps> = ({
|
||||
selectedFile={selectedFile}
|
||||
selectedFileEntry={selectedFileEntry}
|
||||
onSelectFile={handleSelectFileAndScroll}
|
||||
className="w-fit min-w-0"
|
||||
/>
|
||||
)}
|
||||
<div className="flex-1" />
|
||||
{!showFileSelector ? <div className="min-w-0 flex-1" /> : null}
|
||||
{changedFiles.length > 0 && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={handleExpandOrCollapseAll}
|
||||
className="h-7 gap-1.5 px-2 text-muted-foreground hover:text-foreground"
|
||||
className={cn(
|
||||
'diff-toolbar__expand-button h-7 flex-shrink-0 gap-1 px-1.5 text-muted-foreground hover:text-foreground',
|
||||
showFileSelector && 'ml-auto',
|
||||
)}
|
||||
title={expandedFiles.size > 0 ? t('diffView.actions.collapseAll') : t('diffView.actions.expandAll')}
|
||||
>
|
||||
<Icon
|
||||
name={expandedFiles.size > 0 ? 'arrow-up-s' : 'arrow-down-s'}
|
||||
name="expand-up-down"
|
||||
className="size-4"
|
||||
/>
|
||||
<span className="typography-ui-label hidden sm:inline">
|
||||
<span className="diff-toolbar__expand-label typography-ui-label">
|
||||
{expandedFiles.size > 0 ? t('diffView.actions.collapseAll') : t('diffView.actions.expandAll')}
|
||||
</span>
|
||||
</Button>
|
||||
|
||||
@@ -857,6 +857,41 @@ html:not(.dark) .chat-scroll {
|
||||
}
|
||||
}
|
||||
|
||||
/* Diff toolbar: drop low-priority labels as the context panel narrows. */
|
||||
@container diff-toolbar (max-width: 34rem) {
|
||||
.diff-toolbar__file-stats {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@container diff-toolbar (max-width: 40rem) {
|
||||
.diff-toolbar__scope-count,
|
||||
.diff-toolbar__expand-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.diff-toolbar__expand-button {
|
||||
padding-inline: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@container diff-toolbar (max-width: 29rem) {
|
||||
.diff-toolbar__file-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.diff-toolbar__file-trigger {
|
||||
flex: 0 0 auto;
|
||||
gap: 0.375rem;
|
||||
padding-inline: 0.625rem;
|
||||
}
|
||||
|
||||
.diff-toolbar__file-trigger-content {
|
||||
flex: 0 0 auto;
|
||||
gap: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Status row: collapse optional text when narrow to keep both sides in one line. */
|
||||
@container status-row (max-width: 30rem) {
|
||||
.status-row__active-todo {
|
||||
|
||||
@@ -953,7 +953,7 @@ export const dict = {
|
||||
'gitView.worktree.availableInWorktreeMode': 'Available only in worktree mode',
|
||||
'contextPanel.mode.chat': 'Chat',
|
||||
'contextPanel.mode.files': 'Files',
|
||||
'contextPanel.mode.diff': 'Diff',
|
||||
'contextPanel.mode.diff': 'Changes',
|
||||
'contextPanel.mode.stagedDiff': 'Staged Diff',
|
||||
'contextPanel.mode.workingDiff': 'Working Diff',
|
||||
'contextPanel.mode.plan': 'Plan',
|
||||
@@ -1202,6 +1202,9 @@ export const dict = {
|
||||
'diffView.state.largeDiffDescription': 'Rendering may be slow. You can still view the diff by clicking below.',
|
||||
'diffView.summary.changedFilesSingle': '{count} file changed',
|
||||
'diffView.summary.changedFilesPlural': '{count} files changed',
|
||||
'diffView.scope.changed': 'Changed',
|
||||
'diffView.scope.staged': 'Staged',
|
||||
'diffView.scope.selectorAria': 'Select change mode',
|
||||
'diffView.actions.retry': 'Retry',
|
||||
'diffView.actions.renderAnyway': 'Render anyway',
|
||||
'diffView.actions.expandAll': 'Expand all',
|
||||
@@ -1298,6 +1301,8 @@ export const dict = {
|
||||
'header.services.modelFamily.other': 'Other',
|
||||
'header.services.shutdownDev': 'Stop OpenChamber',
|
||||
'header.actions.openPlanAria': 'Open plan',
|
||||
'header.actions.toggleChangesPanel': 'Changes panel',
|
||||
'header.actions.toggleChangesPanelAria': 'Toggle changes panel',
|
||||
'header.actions.planWithShortcut': 'Plan ({shortcut})',
|
||||
'header.actions.terminalPanelWithShortcut': 'Terminal panel ({shortcut})',
|
||||
'header.actions.toggleTerminalPanelAria': 'Toggle terminal panel',
|
||||
|
||||
@@ -954,7 +954,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
"gitView.worktree.availableInWorktreeMode": "Disponible solo en modo worktree",
|
||||
"contextPanel.mode.chat": "Chat",
|
||||
"contextPanel.mode.files": "Archivos",
|
||||
"contextPanel.mode.diff": "Diff",
|
||||
"contextPanel.mode.diff": "Cambios",
|
||||
"contextPanel.mode.stagedDiff": "Staged Diff",
|
||||
"contextPanel.mode.workingDiff": "Working Diff",
|
||||
"contextPanel.mode.plan": "Plan",
|
||||
@@ -1168,6 +1168,9 @@ export const dict: Record<I18nKey, string> = {
|
||||
"diffView.state.largeDiffDescription": "El renderizado puede ser lento. Aun así puedes ver el diff con el botón de abajo.",
|
||||
"diffView.summary.changedFilesSingle": "{count} archivo modificado",
|
||||
"diffView.summary.changedFilesPlural": "{count} archivos modificados",
|
||||
"diffView.scope.changed": "Cambiados",
|
||||
"diffView.scope.staged": "Staged",
|
||||
"diffView.scope.selectorAria": "Seleccionar modo de cambios",
|
||||
"diffView.actions.retry": "Volver a intentar",
|
||||
"diffView.actions.renderAnyway": "Renderizar de todos modos",
|
||||
"diffView.actions.expandAll": "Expandir todo",
|
||||
@@ -1264,6 +1267,8 @@ export const dict: Record<I18nKey, string> = {
|
||||
"header.services.modelFamily.other": "Otro",
|
||||
"header.services.shutdownDev": "Detener OpenChamber",
|
||||
"header.actions.openPlanAria": "Abrir plan",
|
||||
"header.actions.toggleChangesPanel": "Panel de cambios",
|
||||
"header.actions.toggleChangesPanelAria": "Alternar panel de cambios",
|
||||
"header.actions.planWithShortcut": "Plan ({shortcut})",
|
||||
"header.actions.terminalPanelWithShortcut": "Panel de terminal ({shortcut})",
|
||||
"header.actions.toggleTerminalPanelAria": "Mostrar u ocultar panel de terminal",
|
||||
|
||||
@@ -831,7 +831,7 @@ export const dict = {
|
||||
'gitView.worktree.availableInWorktreeMode': 'Disponible uniquement en mode worktree',
|
||||
'contextPanel.mode.chat': 'Chat',
|
||||
'contextPanel.mode.files': 'Fichiers',
|
||||
'contextPanel.mode.diff': 'Différence',
|
||||
"contextPanel.mode.diff": "Changements",
|
||||
'contextPanel.mode.stagedDiff': 'Différence par étapes',
|
||||
'contextPanel.mode.workingDiff': 'Différentiel de travail',
|
||||
'contextPanel.mode.plan': 'Plan',
|
||||
@@ -1075,6 +1075,9 @@ export const dict = {
|
||||
'diffView.state.largeDiffDescription': 'Le rendu peut être lent. Vous pouvez tout de même afficher le diff avec le bouton ci-dessous.',
|
||||
'diffView.summary.changedFilesSingle': 'Le fichier {count} a été modifié',
|
||||
'diffView.summary.changedFilesPlural': 'Fichiers {count} modifiés',
|
||||
"diffView.scope.changed": "Modifiés",
|
||||
"diffView.scope.staged": "Staged",
|
||||
"diffView.scope.selectorAria": "Sélectionner le mode de changements",
|
||||
'diffView.actions.retry': 'Réessayer',
|
||||
'diffView.actions.renderAnyway': 'Afficher quand même',
|
||||
'diffView.actions.expandAll': 'Tout développer',
|
||||
@@ -1164,6 +1167,8 @@ export const dict = {
|
||||
'header.services.modelFamily.other': 'Autre',
|
||||
'header.services.shutdownDev': 'Arrêter OpenChamber',
|
||||
'header.actions.openPlanAria': 'Plan ouvert',
|
||||
"header.actions.toggleChangesPanel": "Panneau des changements",
|
||||
"header.actions.toggleChangesPanelAria": "Basculer le panneau des changements",
|
||||
'header.actions.planWithShortcut': 'Forfait ({shortcut})',
|
||||
'header.actions.terminalPanelWithShortcut': 'Panneau à bornes ({shortcut})',
|
||||
'header.actions.toggleTerminalPanelAria': 'Basculer le panneau à bornes',
|
||||
|
||||
@@ -954,7 +954,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'gitView.worktree.availableInWorktreeMode': '워크트리 모드에서만 사용할 수 있습니다',
|
||||
'contextPanel.mode.chat': '채팅',
|
||||
'contextPanel.mode.files': '파일',
|
||||
'contextPanel.mode.diff': '변경사항',
|
||||
"contextPanel.mode.diff": "Changes",
|
||||
'contextPanel.mode.stagedDiff': 'Staged Diff',
|
||||
'contextPanel.mode.workingDiff': 'Working Diff',
|
||||
'contextPanel.mode.plan': '계획',
|
||||
@@ -1205,6 +1205,9 @@ export const dict: Record<I18nKey, string> = {
|
||||
'diffView.state.largeDiffDescription': '렌더링이 느릴 수 있습니다. 아래 버튼으로 diff를 계속 볼 수 있습니다.',
|
||||
'diffView.summary.changedFilesSingle': '파일 {count}개 변경됨',
|
||||
'diffView.summary.changedFilesPlural': '파일 {count}개 변경됨',
|
||||
"diffView.scope.changed": "Changed",
|
||||
"diffView.scope.staged": "Staged",
|
||||
"diffView.scope.selectorAria": "변경 모드 선택",
|
||||
'diffView.actions.retry': '다시 시도',
|
||||
'diffView.actions.renderAnyway': '그래도 렌더링',
|
||||
'diffView.actions.expandAll': '모두 펼치기',
|
||||
@@ -1300,6 +1303,8 @@ export const dict: Record<I18nKey, string> = {
|
||||
'header.services.remaining': '남은 양',
|
||||
'header.services.modelFamily.other': '기타',
|
||||
'header.actions.openPlanAria': '플랜 열기',
|
||||
"header.actions.toggleChangesPanel": "변경 패널",
|
||||
"header.actions.toggleChangesPanelAria": "변경 패널 전환",
|
||||
'header.actions.planWithShortcut': '플랜 ({shortcut})',
|
||||
'header.actions.terminalPanelWithShortcut': '터미널 패널 ({shortcut})',
|
||||
'header.actions.toggleTerminalPanelAria': '토글 터미널 패널',
|
||||
|
||||
@@ -1244,7 +1244,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'contextPanel.iframe.sessionChatTitle': 'Czat sesji {sessionID}',
|
||||
'contextPanel.mode.chat': 'Chat',
|
||||
'contextPanel.mode.context': 'Context',
|
||||
'contextPanel.mode.diff': 'Różnice',
|
||||
"contextPanel.mode.diff": "Zmiany",
|
||||
'contextPanel.mode.stagedDiff': 'Staged Diff',
|
||||
'contextPanel.mode.workingDiff': 'Working Diff',
|
||||
'contextPanel.mode.files': 'Pliki',
|
||||
@@ -1440,6 +1440,9 @@ export const dict: Record<I18nKey, string> = {
|
||||
'diffView.state.notGitRepository': 'To nie jest repozytorium Git. Użyj karty Git, aby zainicjować lub zmienić katalog.',
|
||||
'diffView.state.selectSessionDirectory': 'Wybierz katalog sesji, aby zobaczyć diffy',
|
||||
'diffView.summary.changedFilesPlural': 'Zmieniono {count} plików',
|
||||
"diffView.scope.changed": "Zmienione",
|
||||
"diffView.scope.staged": "Staged",
|
||||
"diffView.scope.selectorAria": "Wybierz tryb zmian",
|
||||
'diffView.summary.changedFilesSingle': 'Zmieniono {count} plik',
|
||||
'directoryExplorerDialog.actions.addProject': 'Dodaj projekt',
|
||||
'directoryExplorerDialog.actions.addLocalProject': 'Dodaj projekt lokalny',
|
||||
@@ -1950,6 +1953,8 @@ export const dict: Record<I18nKey, string> = {
|
||||
'header.actions.newSessionAria': 'Nowa sesja',
|
||||
'header.actions.newSessionWithShortcut': 'Nowa sesja ({shortcut})',
|
||||
'header.actions.openPlanAria': 'Otwórz plan',
|
||||
"header.actions.toggleChangesPanel": "Panel zmian",
|
||||
"header.actions.toggleChangesPanelAria": "Przełącz panel zmian",
|
||||
'header.actions.openSessionsAria': 'Otwórz sesje',
|
||||
'header.actions.openAppMenu': 'Menu OpenChamber',
|
||||
'header.actions.openAppMenuAria': 'Otwórz menu OpenChamber',
|
||||
|
||||
@@ -954,7 +954,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
"gitView.worktree.availableInWorktreeMode": "Disponível apenas em modo worktree",
|
||||
"contextPanel.mode.chat": "Chat",
|
||||
"contextPanel.mode.files": "Arquivos",
|
||||
"contextPanel.mode.diff": "Diff",
|
||||
"contextPanel.mode.diff": "Alterações",
|
||||
"contextPanel.mode.stagedDiff": "Staged Diff",
|
||||
"contextPanel.mode.workingDiff": "Working Diff",
|
||||
"contextPanel.mode.plan": "Plano",
|
||||
@@ -1168,6 +1168,9 @@ export const dict: Record<I18nKey, string> = {
|
||||
"diffView.state.largeDiffDescription": "A renderização pode ser lenta. Você ainda pode ver o diff pelo botão abaixo.",
|
||||
"diffView.summary.changedFilesSingle": "{count} arquivo modificado",
|
||||
"diffView.summary.changedFilesPlural": "{count} arquivos modificados",
|
||||
"diffView.scope.changed": "Alteradas",
|
||||
"diffView.scope.staged": "Staged",
|
||||
"diffView.scope.selectorAria": "Selecionar modo de alterações",
|
||||
"diffView.actions.retry": "Tentar novamente",
|
||||
"diffView.actions.renderAnyway": "Renderizar mesmo assim",
|
||||
"diffView.actions.expandAll": "Expandir tudo",
|
||||
@@ -1264,6 +1267,8 @@ export const dict: Record<I18nKey, string> = {
|
||||
"header.services.modelFamily.other": "Outro",
|
||||
"header.services.shutdownDev": "Parar OpenChamber",
|
||||
"header.actions.openPlanAria": "Abrir plano",
|
||||
"header.actions.toggleChangesPanel": "Painel de alterações",
|
||||
"header.actions.toggleChangesPanelAria": "Alternar painel de alterações",
|
||||
"header.actions.planWithShortcut": "Plano ({shortcut})",
|
||||
"header.actions.terminalPanelWithShortcut": "Painel de terminal ({shortcut})",
|
||||
"header.actions.toggleTerminalPanelAria": "Mostrar ou ocultar painel de terminal",
|
||||
|
||||
@@ -954,7 +954,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
"gitView.worktree.availableInWorktreeMode": "Доступно лише в режимі worktree",
|
||||
"contextPanel.mode.chat": "Чат",
|
||||
"contextPanel.mode.files": "Файли",
|
||||
"contextPanel.mode.diff": "Diff",
|
||||
"contextPanel.mode.diff": "Зміни",
|
||||
"contextPanel.mode.stagedDiff": "Staged Diff",
|
||||
"contextPanel.mode.workingDiff": "Working Diff",
|
||||
"contextPanel.mode.plan": "План",
|
||||
@@ -1168,6 +1168,9 @@ export const dict: Record<I18nKey, string> = {
|
||||
"diffView.state.largeDiffDescription": "Рендеринг може бути повільним. Ви все одно можете переглянути diff кнопкою нижче.",
|
||||
"diffView.summary.changedFilesSingle": "Змінено файл: {count}",
|
||||
"diffView.summary.changedFilesPlural": "Змінено файлів: {count}",
|
||||
"diffView.scope.changed": "Змінені",
|
||||
"diffView.scope.staged": "Індексовані",
|
||||
"diffView.scope.selectorAria": "Вибрати режим змін",
|
||||
"diffView.actions.retry": "Повторити спробу",
|
||||
"diffView.actions.renderAnyway": "Все одно відрендерити",
|
||||
"diffView.actions.expandAll": "Розгорнути все",
|
||||
@@ -1264,6 +1267,8 @@ export const dict: Record<I18nKey, string> = {
|
||||
"header.services.shutdownDev": "Зупинити OpenChamber",
|
||||
"header.services.modelFamily.other": "інше",
|
||||
"header.actions.openPlanAria": "Відкрити план",
|
||||
"header.actions.toggleChangesPanel": "Панель змін",
|
||||
"header.actions.toggleChangesPanelAria": "Перемкнути панель змін",
|
||||
"header.actions.planWithShortcut": "План ({shortcut})",
|
||||
"header.actions.terminalPanelWithShortcut": "Термінальна панель ({shortcut})",
|
||||
"header.actions.toggleTerminalPanelAria": "Перемкнути панель терміналу",
|
||||
|
||||
@@ -954,7 +954,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'gitView.worktree.availableInWorktreeMode': '仅在工作树模式下可用',
|
||||
'contextPanel.mode.chat': '聊天',
|
||||
'contextPanel.mode.files': '文件',
|
||||
'contextPanel.mode.diff': '差异',
|
||||
"contextPanel.mode.diff": "更改",
|
||||
'contextPanel.mode.stagedDiff': 'Staged Diff',
|
||||
'contextPanel.mode.workingDiff': 'Working Diff',
|
||||
'contextPanel.mode.plan': '计划',
|
||||
@@ -1168,6 +1168,9 @@ export const dict: Record<I18nKey, string> = {
|
||||
'diffView.state.largeDiffDescription': '渲染可能较慢。你仍可点击下方按钮查看差异。',
|
||||
'diffView.summary.changedFilesSingle': '{count} 个文件已变更',
|
||||
'diffView.summary.changedFilesPlural': '{count} 个文件已变更',
|
||||
"diffView.scope.changed": "已更改",
|
||||
"diffView.scope.staged": "已暂存",
|
||||
"diffView.scope.selectorAria": "选择更改模式",
|
||||
'diffView.actions.retry': '重试',
|
||||
'diffView.actions.renderAnyway': '仍然渲染',
|
||||
'diffView.actions.expandAll': '全部展开',
|
||||
@@ -1264,6 +1267,8 @@ export const dict: Record<I18nKey, string> = {
|
||||
'header.services.shutdownDev': '停止 OpenChamber',
|
||||
'header.services.modelFamily.other': '其他',
|
||||
'header.actions.openPlanAria': '打开计划',
|
||||
"header.actions.toggleChangesPanel": "更改面板",
|
||||
"header.actions.toggleChangesPanelAria": "切换更改面板",
|
||||
'header.actions.planWithShortcut': '计划({shortcut})',
|
||||
'header.actions.terminalPanelWithShortcut': '终端面板({shortcut})',
|
||||
'header.actions.toggleTerminalPanelAria': '切换终端面板',
|
||||
|
||||
@@ -966,7 +966,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'gitView.worktree.availableInWorktreeMode': '僅在 worktree 模式可用',
|
||||
'contextPanel.mode.chat': '聊天',
|
||||
'contextPanel.mode.files': '檔案',
|
||||
'contextPanel.mode.diff': '差異',
|
||||
"contextPanel.mode.diff": "變更",
|
||||
'contextPanel.mode.stagedDiff': 'Staged Diff',
|
||||
'contextPanel.mode.workingDiff': 'Working Diff',
|
||||
'contextPanel.mode.plan': '計畫',
|
||||
@@ -1178,6 +1178,9 @@ export const dict: Record<I18nKey, string> = {
|
||||
'diffView.state.largeDiffDescription': '渲染可能較慢。你仍可點擊下方按鈕查看差異。',
|
||||
'diffView.summary.changedFilesSingle': '{count} 個檔案已變更',
|
||||
'diffView.summary.changedFilesPlural': '{count} 個檔案已變更',
|
||||
"diffView.scope.changed": "已變更",
|
||||
"diffView.scope.staged": "已暫存",
|
||||
"diffView.scope.selectorAria": "選擇變更模式",
|
||||
'diffView.actions.retry': '重試',
|
||||
'diffView.actions.renderAnyway': '仍然渲染',
|
||||
'diffView.actions.expandAll': '全部展開',
|
||||
@@ -1268,6 +1271,8 @@ export const dict: Record<I18nKey, string> = {
|
||||
'header.services.shutdownDev': '停止 OpenChamber',
|
||||
'header.services.modelFamily.other': '其他',
|
||||
'header.actions.openPlanAria': '開啟計畫',
|
||||
"header.actions.toggleChangesPanel": "變更面板",
|
||||
"header.actions.toggleChangesPanelAria": "切換變更面板",
|
||||
'header.actions.planWithShortcut': '計畫({shortcut})',
|
||||
'header.actions.terminalPanelWithShortcut': '終端機面板({shortcut})',
|
||||
'header.actions.toggleTerminalPanelAria': '切換終端機面板',
|
||||
|
||||
@@ -191,6 +191,10 @@ const normalizeContextPanelTabDedupeKey = (
|
||||
targetPath: string | null,
|
||||
dedupeKey: string | null | undefined,
|
||||
): string => {
|
||||
if (mode === 'diff') {
|
||||
return mode;
|
||||
}
|
||||
|
||||
if (typeof dedupeKey === 'string') {
|
||||
const trimmed = dedupeKey.trim();
|
||||
if (trimmed) {
|
||||
@@ -1032,7 +1036,6 @@ export const useUIStore = create<UIStore>()(
|
||||
get().openContextPanelTab(normalizedDirectory, {
|
||||
mode: 'diff',
|
||||
targetPath: normalizedFilePath,
|
||||
dedupeKey: staged ? 'staged' : null,
|
||||
stagedDiff: staged,
|
||||
});
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user