mirror of
https://github.com/andy-stack/vaultkeeper-ai.git
synced 2026-07-22 06:42:03 +00:00
fix: improve chat scroll calculation and conversation deletion handling
- Use getOuterHeight helper for accurate element measurements including margins - Simplify gap calculation for thought and streaming indicators - Add top fade gradient to chat area for better visual polish - Queue AI file deletions to prevent blocking conversation deletion - Only trigger modal close callback when no conversation is active
This commit is contained in:
parent
71d19545dd
commit
e3e30a2b47
4 changed files with 29 additions and 9 deletions
|
|
@ -11,6 +11,7 @@
|
|||
import { tick } from "svelte";
|
||||
import { Selector } from "Enums/Selector";
|
||||
import { Exception } from "Helpers/Exception";
|
||||
import { getOuterHeight } from "Helpers/ElementHelper";
|
||||
|
||||
export let cancelling: boolean = false;
|
||||
export let messages: ConversationContent[] = [];
|
||||
|
|
@ -45,20 +46,19 @@
|
|||
return;
|
||||
}
|
||||
|
||||
const gap = parseFloat(getComputedStyle(chatContainer).gap) || 0;
|
||||
const paddingTop = parseFloat(getComputedStyle(chatContainer).paddingTop) || 0;
|
||||
const paddingBottom = parseFloat(getComputedStyle(chatContainer).paddingBottom) || 0;
|
||||
|
||||
const messageElement = messageElements.sort((a, b) => a.index - b.index)[messageElements.length - 1];
|
||||
let messageSpace = messageElement.element.offsetHeight;
|
||||
let messageSpace = getOuterHeight(messageElement.element);
|
||||
|
||||
if (!shouldSettle) {
|
||||
const gap = parseFloat(getComputedStyle(chatContainer).gap) || 0;
|
||||
|
||||
if (thoughtIndicatorElement) {
|
||||
messageSpace += thoughtIndicatorElement.offsetHeight + gap + gap;
|
||||
messageSpace += getOuterHeight(thoughtIndicatorElement) + gap;
|
||||
}
|
||||
if (streamingIndicatorElement) {
|
||||
messageSpace += streamingIndicatorElement.offsetHeight + gap + gap;
|
||||
messageSpace += getOuterHeight(streamingIndicatorElement) + gap;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -247,6 +247,7 @@
|
|||
</script>
|
||||
|
||||
<div class="chat-area" bind:this={chatContainer} on:scroll={handleScroll} use:observeResize>
|
||||
<div class="top-fade"></div>
|
||||
{#each messages as message, index}
|
||||
{@const content = message.getDisplayContent()}
|
||||
{#if message.shouldDisplayContent && content.trim() !== ""}
|
||||
|
|
@ -294,12 +295,22 @@
|
|||
</div>
|
||||
|
||||
<style>
|
||||
.top-fade {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: var(--size-4-4);
|
||||
background-image: linear-gradient(to bottom, var(--background-secondary), transparent);
|
||||
margin-top: calc(var(--size-4-4) * -1);
|
||||
margin-left: calc(var(--size-4-3) * -1);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.chat-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding: var(--size-4-3);
|
||||
padding: var(--size-4-4) var(--size-4-3) var(--size-4-3) var(--size-4-3);
|
||||
gap: var(--size-4-2);
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
|
|
|||
5
Helpers/ElementHelper.ts
Normal file
5
Helpers/ElementHelper.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export function getOuterHeight(element: HTMLElement): number {
|
||||
const marginTop = parseFloat(getComputedStyle(element).marginTop) || 0;
|
||||
const marginBottom = parseFloat(getComputedStyle(element).marginBottom) || 0;
|
||||
return element.offsetHeight + marginTop + marginBottom;
|
||||
}
|
||||
|
|
@ -129,6 +129,8 @@ export class ConversationHistoryModal extends Modal {
|
|||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
|
||||
this.onModalClose?.();
|
||||
if (this.conversationFileSystemService.getCurrentConversationPath() === null) {
|
||||
this.onModalClose?.();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ export class ConversationFileSystemService {
|
|||
private aiFileService: IAIFileService | undefined;
|
||||
|
||||
private currentConversationPath: string | null = null;
|
||||
private deletionQueue: Promise<void> = Promise.resolve();
|
||||
|
||||
public constructor() {
|
||||
this.fileSystemService = Resolve<FileSystemService>(Services.FileSystemService);
|
||||
|
|
@ -92,8 +93,9 @@ export class ConversationFileSystemService {
|
|||
return readResult;
|
||||
}
|
||||
|
||||
await this.attemptAIFileDeletion(readResult);
|
||||
|
||||
// Queue this to execute silently in the background - it's just a best effort
|
||||
this.deletionQueue = this.deletionQueue.then(() => this.attemptAIFileDeletion(readResult));
|
||||
|
||||
const deleteResult = await this.fileSystemService.deleteFile(this.currentConversationPath, true, false);
|
||||
|
||||
if (deleteResult instanceof Error) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue