feat: improve chat streaming UX and add Mermaid diagram rendering (#438)

* feat: show current branch in empty chat state

* fix: display current git branch for worktrees and update them with branch change

* refactor: improve read tool output parsing with structured data

* feat: add support for message part delta events

* fix(chat): improve streaming rendering, scroll behavior, and assistant action visibility

* feat: Add mermaid diagram support to chat markdown rendering

* fix: update table download functionality to include success notification and remove unused MarkdownRenderer import

* refactor: streamline Streamdown component props for improved readability

* fix: preserve Streamdown code-block markers and use native Tauri cache clearing

* feat: add context overview panel to view conversation details
This commit is contained in:
Bohdan Triapitsyn
2026-02-17 18:25:03 +02:00
committed by GitHub
parent 138772e66e
commit 4d71bb27eb
31 changed files with 1391 additions and 182 deletions
+68 -2
View File
@@ -6,7 +6,7 @@ import { SEMANTIC_TYPOGRAPHY, getTypographyVariable, type SemanticTypographyKey
export type MainTab = 'chat' | 'plan' | 'git' | 'diff' | 'terminal' | 'files';
export type RightSidebarTab = 'git' | 'files';
export type ContextPanelMode = 'diff' | 'file';
export type ContextPanelMode = 'diff' | 'file' | 'context';
type ContextPanelDirectoryState = {
isOpen: boolean;
@@ -224,6 +224,7 @@ interface UIStore {
setRightSidebarTab: (tab: RightSidebarTab) => void;
openContextDiff: (directory: string, filePath: string) => void;
openContextFile: (directory: string, filePath: string) => void;
openContextOverview: (directory: string) => void;
closeContextPanel: (directory: string) => void;
toggleContextPanelExpanded: (directory: string) => void;
setContextPanelWidth: (directory: string, width: number) => void;
@@ -404,6 +405,18 @@ export const useUIStore = create<UIStore>()(
setSidebarOpen: (open) => {
set((state) => {
if (state.isSidebarOpen === open) {
if (!open) {
return state;
}
if (!state.hasManuallyResizedLeftSidebar && state.sidebarWidth !== LEFT_SIDEBAR_MIN_WIDTH) {
return {
isSidebarOpen: open,
sidebarWidth: LEFT_SIDEBAR_MIN_WIDTH,
};
}
return state;
}
if (open && !state.hasManuallyResizedLeftSidebar) {
return {
isSidebarOpen: open,
@@ -434,6 +447,18 @@ export const useUIStore = create<UIStore>()(
setRightSidebarOpen: (open) => {
set((state) => {
if (state.isRightSidebarOpen === open) {
if (!open) {
return state;
}
if (!state.hasManuallyResizedRightSidebar && state.rightSidebarWidth !== RIGHT_SIDEBAR_MIN_WIDTH) {
return {
isRightSidebarOpen: open,
rightSidebarWidth: RIGHT_SIDEBAR_MIN_WIDTH,
};
}
return state;
}
if (open && !state.hasManuallyResizedRightSidebar) {
return {
isRightSidebarOpen: open,
@@ -501,6 +526,29 @@ export const useUIStore = create<UIStore>()(
});
},
openContextOverview: (directory) => {
const normalizedDirectory = normalizeDirectoryPath((directory || '').trim());
if (!normalizedDirectory) {
return;
}
set((state) => {
const prev = state.contextPanelByDirectory[normalizedDirectory];
const current = touchContextPanelState(prev);
const byDirectory = {
...state.contextPanelByDirectory,
[normalizedDirectory]: {
...current,
isOpen: true,
mode: 'context' as const,
targetPath: null,
},
};
return { contextPanelByDirectory: clampContextPanelRoots(byDirectory, 20) };
});
},
closeContextPanel: (directory) => {
const normalizedDirectory = normalizeDirectoryPath((directory || '').trim());
if (!normalizedDirectory) {
@@ -585,7 +633,25 @@ export const useUIStore = create<UIStore>()(
},
setBottomTerminalOpen: (open) => {
set(() => {
set((state) => {
if (state.isBottomTerminalOpen === open) {
if (!open) {
return state;
}
if (!state.hasManuallyResizedBottomTerminal && typeof window !== 'undefined') {
const proportionalHeight = Math.floor(window.innerHeight * 0.32);
if (state.bottomTerminalHeight === proportionalHeight && state.hasManuallyResizedBottomTerminal === false) {
return state;
}
return {
isBottomTerminalOpen: open,
bottomTerminalHeight: proportionalHeight,
hasManuallyResizedBottomTerminal: false,
};
}
return state;
}
if (open && typeof window !== 'undefined') {
const proportionalHeight = Math.floor(window.innerHeight * 0.32);
return {