better support for opening chat in floating window

This commit is contained in:
2026-08-28 14:15:57 +02:00
parent 8a66c3b064
commit 327270f3fa
14 changed files with 419 additions and 168 deletions
@@ -2,90 +2,109 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Quickshell
import ZShell.Config
import ZShell.Llm
import qs.Components
import qs.Modules.Notifications.Sidebar.Chat.Content
import qs.Services
Item {
RowLayout {
id: root
property int breakpoint: 700
property alias conversationModel: sidebar.model
property var currentConversation: null // whatever model item is "open"
readonly property bool isWide: root.width >= root.breakpoint
property bool narrowShowsSidebar: true
function closeConversation() {
narrowShowsSidebar = true;
}
function openConversation(conv) {
currentConversation = conv;
narrowShowsSidebar = false; // in narrow mode, jump to the chat
function openConversation(conv: ChatSession, index: int): void {
}
ChatList {
id: sidebar
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: root.isWide ? undefined : parent.right
anchors.top: parent.top
implicitWidth: 20
list.currentIndex: -1
list.highlightFollowsCurrentItem: false
Layout.fillHeight: true
Layout.margins: Tokens.padding.medium
Layout.rightMargin: Tokens.spacing.medium
Layout.maximumWidth: Config.sidebar.sizes.width
Layout.preferredWidth: root.width / 4
Layout.minimumWidth: Config.sidebar.sizes.width / 2
highlight: true
Behavior on anchors.right {
AnchorAnim {}
}
Behavior on implicitWidth {
Anim {}
}
list.highlight: CustomRect {
color: Colors.palette.m3primary
implicitHeight: sidebar.list.currentItem?.implicitHeight ?? 0
implicitWidth: sidebar.list.width
radius: Tokens.rounding.medium
x: sidebar.list.currentItem?.chat.x ?? 0
y: sidebar.list.currentItem?.y ?? 0
Behavior on y {
Anim {
duration: Tokens.anim.durations.small
easing: Tokens.anim.expressiveDefaultEffects
}
}
}
model: ScriptModel {
values: Chat.chats.values
}
anchors.onRightChanged: {
if (anchors.right === undefined)
implicitWidth = 20;
}
onLoadChatRequest: (chat, index) => {
sidebar.list.currentIndex = index;
root.openConversation(chat);
ChatState.currentIdx = index;
ChatState.chatSession = chat;
}
onDeleteChatRequest: chat => {
Chat.chats.remove(chat);
ChatState.currentIdx = -1;
ChatState.chatSession = null;
}
onNewChatRequest: {
const data = Chat.chats.insert();
ChatState.currentIdx = 0;
ChatState.chatSession = data;
}
}
CustomClippingWrapperRect {
anchors.bottom: parent.bottom
anchors.left: sidebar.right
anchors.right: parent.right
anchors.top: parent.top
child: conversationView
Item {
Layout.margins: Tokens.padding.extraLarge
Layout.leftMargin: Tokens.spacing.extraLarge
Layout.topMargin: Tokens.padding.large
Layout.preferredWidth: Config.sidebar.sizes.width * 2
Layout.fillWidth: true
Layout.fillHeight: true
ChatHost {
id: convHost
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
implicitWidth: Math.min(parent.width, 800)
clip: true
onImplicitWidthChanged: console.log(implicitWidth)
}
ColumnLayout {
id: noChatLayout
anchors.centerIn: parent
opacity: ChatState.chatSession ? 0 : 1
visible: opacity > 0
Behavior on opacity {
Anim {}
}
MaterialIcon {
Layout.alignment: Qt.AlignCenter
text: "chat_bubble_off"
font.pointSize: Tokens.font.size.extraLarge
color: Colors.tPalette.m3onSurfaceVariant
}
CustomText {
Layout.alignment: Qt.AlignCenter
text: qsTr("Start or create a chat")
color: Colors.tPalette.m3onSurfaceVariant
}
}
}
ChatContent {
Component {
id: conversationView
anchors.fill: root
anchors.leftMargin: root.isWide ? Config.sidebar.sizes.width / 2 : 0
chatData: root.currentConversation
ChatContent {}
}
}