pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts import QtQuick.Controls import Quickshell import ZShell.Blobs import ZShell.Config import ZShell.Llm import qs.Components import qs.Modules.Notifications.Sidebar.Chat.Content import qs.Services Item { id: root property int breakpoint: Math.round(Config.sidebar.sizes.width * 2) + Tokens.spacing.medium * 2 + Tokens.padding.medium * 3 property color blobColor: Colors.tPalette.m3surfaceContainerLow readonly property int iconSize: Math.round(Tokens.font.size.extraLarge * (96 / 72)) + Tokens.padding.large * 2 property alias conversationModel: sidebar.model property bool chatOpen: ChatState.chatSession !== null readonly property bool isWide: root.width >= root.breakpoint readonly property bool showList: isWide || !chatOpen readonly property bool showContent: !isWide && chatOpen function openConversation(conv: ChatSession, index: int): void { } BlobGroup { id: blobGroup color: root.blobColor smoothing: Tokens.rounding.medium } BlobInvertedRect { anchors.fill: parent borderBottom: Tokens.padding.small borderLeft: sidebar.implicitWidth + sidebar.anchors.margins + Tokens.spacing.medium borderRight: Tokens.padding.small borderTop: Tokens.padding.small group: blobGroup opacity: root.blobColor.a radius: Tokens.rounding.largeIncreased } ChatList { id: sidebar anchors.top: parent.top anchors.left: parent.left anchors.bottom: parent.bottom anchors.margins: Tokens.padding.medium implicitWidth: root.isWide ? Config.sidebar.sizes.width : root.iconSize highlight: true slim: !root.isWide Behavior on implicitWidth { Anim { type: Anim.DefaultEffects } } model: ScriptModel { values: Chat.chats.values } onLoadChatRequest: (chat, index) => { ChatState.currentIdx = index; ChatState.chatSession = chat; } onDeleteChatRequest: chat => { if (chat === ChatState.chatSession) { ChatState.chatSession = null; ChatState.currentIdx = -1; } Chat.chats.remove(chat); } onNewChatRequest: { const data = Chat.chats.insert(); ChatState.currentIdx = 0; ChatState.chatSession = data; } } Item { id: contentArea property int leftMargin: sidebar.implicitWidth z: 1 anchors.top: parent.top anchors.bottom: parent.bottom anchors.margins: Tokens.padding.medium * 2 anchors.right: parent.right implicitWidth: root.width - leftMargin - sidebar.anchors.margins - Tokens.spacing.medium * 2 - anchors.margins states: State { name: "wide" when: !root.isWide PropertyChanges { contentArea.leftMargin: root.iconSize } } transitions: Transition { to: "wide" Anim { type: Anim.DefaultEffects property: "leftMargin" } } ChatHost { id: convHost anchors.top: parent.top anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter implicitWidth: Math.max(Math.min(parent.width, 800), Config.sidebar.sizes.width) clip: true onLoadingChanged: if (!loading) root.chatOpen = true } 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 } } } Binding { target: ChatState property: "windowIsWide" value: root.showList } Component { id: conversationView ChatContent {} } }