feat: implement file and text drop handling for chat and add shrunk sidebar override for window view

This commit is contained in:
2026-10-24 16:28:13 +02:00
parent e35c87b3f2
commit 5401cfbc0a
13 changed files with 929 additions and 486 deletions
+52 -1
View File
@@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import QtQuick.Layouts
import ZShell.Services
import ZShell.Components
import ZShell.Config
import ZShell.Llm
@@ -90,7 +91,9 @@ Item {
signal requestClose
readonly property bool atNewestEnd: !listLoader.item || listLoader.item.contentY < 4
readonly property bool importing: importIds.length > 0
property var importIds: []
property var pendingAttachments: []
function attachFiles(): void {
@@ -541,7 +544,7 @@ Item {
bg.border.color: Colors.palette.m3outlineVariant
bg.color: Colors.tPalette.m3surfaceContainerLowest
fastGlow: LlmClient.busy
glow.opacity: input.activeFocus && (!LlmClient.busy || ChatState.isWindow)
glow.opacity: !ChatState.narrowSidebarExpanded ? (input.activeFocus && (!LlmClient.busy || ChatState.isWindow) ? 1 : 0) : 0
font: Tokens.font.body.small
implicitHeight: Math.min(root.height / 5, contentHeight + topPadding + bottomPadding)
focus: true
@@ -578,4 +581,52 @@ Item {
root.send(text);
}
}
Connections {
target: DropImporter
function onImportFinished(id: int, paths: var, errors: var): void {
if (!root.importIds.includes(id))
return;
root.importIds = root.importIds.filter(i => i !== id);
if (paths.length > 0) {
const added = root.chatData.addAttachments(paths);
root.pendingAttachments = root.pendingAttachments.concat(added);
}
for (const e of errors)
console.warn("Drop import:", e);
}
}
DropArea {
id: dropArea
anchors.fill: parent
onEntered: drag => {
drag.accepted = drag.hasUrls || drag.hasText || drag.hasHtml || drag.formats.some(f => f.startsWith("image/"));
}
onDropped: drop => {
const formats = drop.formats;
const urls = drop.hasUrls ? drop.urls : [];
const text = drop.hasText ? drop.text : "";
const html = drop.hasHtml ? drop.html : "";
const imgFormat = formats.find(f => f.startsWith("image/"));
const raw = imgFormat ? drop.getDataAsArrayBuffer(imgFormat) : new ArrayBuffer(0);
switch (DropImporter.decide(urls, text, html, raw.byteLength > 0)) {
case DropImporter.Attach:
root.importIds = [...root.importIds, DropImporter.importAttachments(urls, html, raw)];
break;
case DropImporter.InsertText:
input.insert(input.cursorPosition, text || urls.map(u => u.toString()).join("\n"));
root.focusInput();
break;
}
drop.acceptProposedAction();
}
}
}