fix: restore lost changes
C++ / fmt (pull_request) Failing after 3s
C++ / build (pull_request) Failing after 9s
C++ / clang-tidy (pull_request) Failing after 9s
JS/TS / fmt (pull_request) Successful in 7s
JS/TS / lint (pull_request) Successful in 8s
Python / static (pull_request) Successful in 25s
Rust / build (pull_request) Successful in 50s
Rust / fmt (pull_request) Successful in 30s
Python / verify (pull_request) Successful in 1m44s
Rust / clippy (pull_request) Successful in 45s

This commit is contained in:
2026-09-30 19:30:06 +02:00
parent 54f966b4ea
commit e8bf8b9727
29 changed files with 201 additions and 268 deletions
@@ -455,7 +455,7 @@ Item {
MaterialIcon {
anchors.centerIn: parent
font.pointSize: Tokens.font.size.large
fontStyle: Tokens.font.icon.large
text: thumb.fileIcon(thumb.modelData?.mimeType ?? "")
visible: !thumb.modelData?.isImage ?? false
}
@@ -67,7 +67,7 @@ CustomClippingRect {
anchors.leftMargin: Tokens.padding.large
anchors.top: parent.top
anchors.topMargin: Tokens.padding.large
font.pointSize: Tokens.font.size.extraLarge
fontStyle: Tokens.font.icon.extraLarge
text: root.modelData.icon || "check"
color: Colors.palette.m3onSurface
}
@@ -134,7 +134,7 @@ CustomClippingRect {
anchors.leftMargin: readOnly ? 0 : Tokens.padding.large
anchors.top: parent.top
anchors.topMargin: readOnly ? Tokens.padding.small : Tokens.padding.extraSmall * 2
font.pointSize: Tokens.font.size.normal
font: Tokens.font.body.medium
text: root.modelData.title || qsTr("New chat")
readOnly: true
color: Colors.palette.m3onSurface
@@ -192,7 +192,7 @@ CustomClippingRect {
anchors.topMargin: Tokens.spacing.extraSmall
anchors.left: parent.left
anchors.right: parent.right
font.pointSize: Tokens.font.size.small
font: Tokens.font.label.small
color: Colors.palette.m3onSurfaceVariant
text: qsTr("Created on: %1").arg(root.modelData.createdAt.toLocaleString(Qt.locale("en_US"), "MMM d, yyyy - h:mm AP"))
opacity: root.expanded ? 1 : 0
@@ -208,7 +208,7 @@ CustomClippingRect {
anchors.top: created.bottom
anchors.topMargin: Tokens.spacing.small
anchors.left: parent.left
font.pointSize: Tokens.font.size.small
font: Tokens.font.label.small
color: Colors.palette.m3onSurfaceVariant
text: qsTr("Updated on: ")
opacity: root.expanded ? 1 : 0
@@ -225,7 +225,7 @@ CustomClippingRect {
anchors.top: title.bottom
anchors.topMargin: Tokens.spacing.extraSmall
color: Colors.palette.m3onSurfaceVariant
font.pointSize: Tokens.font.size.small
font: Tokens.font.label.small
text: root.modelData.updatedAt.toLocaleString(Qt.locale("en_US"), "MMM d, yyyy - h:mm AP")
states: State {
@@ -256,7 +256,7 @@ CustomClippingRect {
y: infoContainer.implicitHeight + topMargin
elide: Text.ElideRight
color: Colors.palette.m3onSurfaceVariant
font.pointSize: Tokens.font.size.small
font: Tokens.font.body.small
maximumLineCount: 1
opacity: !root.expanded && !root.slim ? 1 : 0
text: root.modelData.messagesModel.lastMessage?.activeGeneration.content.replace(/\s+/g, " ").trim() ?? qsTr("No messages yet")
@@ -323,7 +323,7 @@ CustomClippingRect {
fillWidth: true
shapeMorph: true
isRound: true
font.pointSize: Tokens.font.size.large
font: Tokens.font.icon.medium
inactiveColor: Colors.layer(Colors.palette.m3surfaceContainerHighest, 3)
inactiveOnColor: Colors.palette.m3onSurfaceVariant
@@ -336,7 +336,7 @@ CustomClippingRect {
isToggle: true
fillWidth: true
shapeMorph: true
font.pointSize: Tokens.font.size.large
font: Tokens.font.icon.medium
isRound: true
inactiveColor: Colors.layer(Colors.palette.m3surfaceContainerHighest, 3)
inactiveOnColor: Colors.palette.m3onSurfaceVariant
@@ -156,7 +156,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
text: modelsContainer.expanded ? "unfold_less" : "unfold_more"
animate: true
font.pointSize: Tokens.font.size.large
fontStyle: Tokens.font.icon.large
visible: modelsList.count > 0
}
@@ -229,7 +229,7 @@ Item {
Layout.alignment: Qt.AlignRight
visible: model.selected
color: Colors.palette.m3onTertiaryContainer
font.pointSize: Tokens.font.size.normal
fontStyle: Tokens.font.icon.normal
opacity: model.selected ? 1 : 0
text: "check"
@@ -405,7 +405,7 @@ Item {
MaterialIcon {
text: fabMenuItem.modelData.icon
color: Colors.palette.m3onPrimaryContainer
font.pointSize: Tokens.font.size.large
fontStyle: Tokens.font.icon.large
fill: 1
}
@@ -3,7 +3,7 @@ pragma Singleton
import QtQuick
import Quickshell
import ZShell.Llm
import qs.Helpers
import qs.Services
Singleton {
id: root
@@ -20,7 +20,7 @@ Singleton {
property bool narrowSidebarExpanded: false
property bool windowIsWide: false
property ShellScreen screen
property bool sidebarVisible: Visibilities.getForActive().sidebar
property bool sidebarVisible: ShellState.forActive().sidebar
onSidebarVisibleChanged: if (!sidebarVisible)
fabExpanded = false
@@ -29,6 +29,7 @@ Item {
enabled: root.message.generationCount > 1 && root.message.activeGenerationIndex !== 0
icon: "chevron_left"
type: IconButton.Tonal
isRound: true
onClicked: {
if (!root.edit.readOnly)
@@ -40,8 +41,7 @@ Item {
IconButton {
enabled: false
icon: `${root.message.activeGenerationIndex + 1}`
label.font.family: Config.appearance.font.family.sans
label.font.pointSize: Tokens.font.size.small
label.font: Tokens.font.body.small
type: IconButton.Text
}
@@ -49,6 +49,7 @@ Item {
enabled: root.message.generationCount > 1 && root.message.activeGenerationIndex !== root.message.generationCount - 1
icon: "chevron_right"
type: IconButton.Tonal
isRound: true
onClicked: {
if (!root.edit.readOnly)
@@ -76,6 +77,7 @@ Item {
inactiveOnColor: Colors.palette.m3onSecondary
scale: root.edit.readOnly ? 1 : 0
visible: !root.isUser
isRound: true
Behavior on scale {
Anim {}
@@ -91,6 +93,7 @@ Item {
inactiveColor: Colors.palette.m3secondary
inactiveOnColor: Colors.palette.m3onSecondary
scale: root.edit.readOnly ? 1 : 0
isRound: true
Behavior on scale {
Anim {}
@@ -106,6 +109,7 @@ Item {
inactiveColor: Colors.palette.m3tertiary
inactiveOnColor: Colors.palette.m3onTertiary
visible: root.isUser
isRound: true
onClicked: {
root.edit.readOnly = !root.edit.readOnly;
@@ -10,7 +10,7 @@ TextEditBase {
color: Colors.palette.m3onSurface
readOnly: true
textFormat: Text.MarkdownText
font.pointSize: Tokens.font.size.smaller
font: Tokens.font.body.small
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
onLinkActivated: link => {
@@ -6,138 +6,138 @@ import qs.Services
import qs.Modules.Notifications.Sidebar.Chat
Item {
id: root
id: root
property int animOff
property Item currentItem
property bool noAnim: false
property bool loading: false
property int lastIdx: -1
property int animOff
property Item currentItem
property bool noAnim: false
property bool loading: false
property int lastIdx: -1
readonly property Component conversationComp: ChatContent {}
readonly property Component conversationComp: ChatContent {}
signal requestClose
signal requestClose
function loadConversation(chat): void {
if (currentItem) {
currentItem.destroy();
currentItem = null;
}
function loadConversation(chat): void {
if (currentItem) {
currentItem.destroy();
currentItem = null;
}
if (!chat)
return;
if (!chat)
return;
root.loading = true;
root.loading = true;
const incubator = root.conversationComp.incubateObject(container, {
chatData: chat
});
const incubator = root.conversationComp.incubateObject(container, {
chatData: chat
});
const attach = () => {
incubator.object.anchors.fill = container;
incubator.object.requestClose.connect(root.requestClose);
currentItem = incubator.object;
root.loading = false;
if (!noAnim)
enterAnim.start();
};
const attach = () => {
incubator.object.anchors.fill = container;
incubator.object.requestClose.connect(root.requestClose);
currentItem = incubator.object;
root.loading = false;
if (!noAnim)
enterAnim.start();
};
if (incubator.status === Component.Ready)
attach();
else
incubator.onStatusChanged = status => {
if (status === Component.Ready)
attach();
};
}
if (incubator.status === Component.Ready)
attach();
else
incubator.onStatusChanged = status => {
if (status === Component.Ready)
attach();
};
}
Item {
id: container
Item {
id: container
anchors.fill: parent
layer.enabled: opacity < 1
objectName: "ConversationContainer"
anchors.fill: parent
layer.enabled: opacity < 1
objectName: "ConversationContainer"
Component.onCompleted: {
if (ChatState.chatSession)
root.loadConversation(ChatState.chatSession);
}
}
Component.onCompleted: {
if (ChatState.chatSession)
root.loadConversation(ChatState.chatSession);
}
}
LoadingIndicator {
anchors.centerIn: parent
implicitSize: Tokens.font.size.extraLarge * 4
opacity: root.loading ? 1 : 0
visible: opacity > 0
LoadingIndicator {
anchors.centerIn: parent
implicitSize: Tokens.font.icon.extraLarge.pointSize * 4
opacity: root.loading ? 1 : 0
visible: opacity > 0
Behavior on opacity {
Anim {}
}
}
Behavior on opacity {
Anim {}
}
}
Connections {
function onChatSessionChanged(): void {
exitAnim.complete();
enterAnim.complete();
Connections {
function onChatSessionChanged(): void {
exitAnim.complete();
enterAnim.complete();
if (root.noAnim) {
root.loadConversation(ChatState.chatSession);
return;
}
if (root.noAnim) {
root.loadConversation(ChatState.chatSession);
return;
}
root.animOff = Tokens.padding.small * (ChatState.currentIdx > root.lastIdx ? 1 : -1);
root.lastIdx = ChatState.currentIdx;
exitAnim.start();
}
root.animOff = Tokens.padding.small * (ChatState.currentIdx > root.lastIdx ? 1 : -1);
root.lastIdx = ChatState.currentIdx;
exitAnim.start();
}
target: ChatState
}
target: ChatState
}
SequentialAnimation {
id: exitAnim
SequentialAnimation {
id: exitAnim
Anim {
property: "opacity"
target: container
to: 0
type: Anim.DefaultEffects
}
Anim {
property: "opacity"
target: container
to: 0
type: Anim.DefaultEffects
}
ScriptAction {
script: root.loadConversation(ChatState.chatSession)
}
}
ScriptAction {
script: root.loadConversation(ChatState.chatSession)
}
}
SequentialAnimation {
id: enterAnim
SequentialAnimation {
id: enterAnim
PropertyAction {
property: "topMargin"
target: container.anchors
value: root.animOff
}
PropertyAction {
property: "topMargin"
target: container.anchors
value: root.animOff
}
PropertyAction {
property: "bottomMargin"
target: container.anchors
value: -root.animOff
}
PropertyAction {
property: "bottomMargin"
target: container.anchors
value: -root.animOff
}
ParallelAnimation {
Anim {
from: 0
property: "opacity"
target: container
to: 1
type: Anim.SlowEffects
}
ParallelAnimation {
Anim {
from: 0
property: "opacity"
target: container
to: 1
type: Anim.SlowEffects
}
Anim {
properties: "topMargin,bottomMargin"
target: container.anchors
to: 0
type: Anim.SlowEffects
}
}
}
Anim {
properties: "topMargin,bottomMargin"
target: container.anchors
to: 0
type: Anim.SlowEffects
}
}
}
}
@@ -32,8 +32,7 @@ CustomRect {
function onHighlightSpans(token, spans) {
if (token !== root.highlightToken)
return;
if (root.code !== root.requestedCode ||
root.language !== root.requestedLanguage)
if (root.code !== root.requestedCode || root.language !== root.requestedLanguage)
return;
html = spans.length ? root.highlightedHtml(root.code, spans) : "";
colored = root.visible && html.length > 0;
@@ -84,15 +83,13 @@ CustomRect {
// whitespace kept, mid-line runs collapsed, tabs as single spaces) so the
// plain and colored layouts are identical.
function plainForDisplay(code): string {
return code.split("\n")
.map(line => {
const i = line.search(/\S/);
if (i < 0)
return "";
const lead = line.slice(0, i).replace(/\t/g, " ");
return lead + line.slice(i).replace(/\s+/g, " ").replace(/\s+$/, "");
})
.join("\n");
return code.split("\n").map(line => {
const i = line.search(/\S/);
if (i < 0)
return "";
const lead = line.slice(0, i).replace(/\t/g, " ");
return lead + line.slice(i).replace(/\s+/g, " ").replace(/\s+$/, "");
}).join("\n");
}
function highlightedHtml(code, spans): string {
@@ -136,7 +133,7 @@ CustomRect {
refreshTimer.restart();
}
onVisibleChanged: if (root.visible)
refreshTimer.restart();
refreshTimer.restart()
Timer {
id: refreshTimer
@@ -223,7 +220,7 @@ CustomRect {
Layout.alignment: Qt.AlignVCenter
color: root.codeHeaderColor
font.pointSize: Tokens.font.size.small
font: Tokens.font.label.small
text: CodeIcons.name(root.language)
visible: root.language.length > 0
}
@@ -289,8 +286,7 @@ CustomRect {
color: CodeColors.active.normal
layer.enabled: true
clip: false
font.family: Config.appearance.font.family.mono
font.pointSize: Tokens.font.size.small
font: Tokens.font.mono.small
textFormat: root.colored ? Text.RichText : Text.PlainText
text: root.colored ? root.html : root.plainForDisplay(root.code)
readOnly: true
@@ -85,7 +85,7 @@ Item {
animateCursor: false
color: root.isUser ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
cursor.color: root.isUser ? Colors.palette.m3onPrimary : Colors.palette.m3primary
font.pointSize: Tokens.font.size.smaller
font: Tokens.font.body.small
readOnly: true
selectionColor: Qt.alpha((root.isUser ? Colors.palette.m3onPrimary : Colors.palette.m3primary), 0.4)
text: root.isUser ? root.segment.text : ""
@@ -93,7 +93,7 @@ Item {
Layout.fillWidth: true
font.pointSize: Tokens.font.size.large
font: Tokens.font.headline.small
elide: CustomText.ElideRight
color: Colors.palette.m3onErrorContainer
@@ -120,7 +120,7 @@ Item {
isRound: true
icon: "close"
type: IconButton.Text
font.pointSize: Tokens.font.size.large
font: Tokens.font.icon.medium
onClicked: exitAnim.start()
}
@@ -62,13 +62,12 @@ Column {
text: modelData.text
textFormat: Text.MarkdownText
readOnly: true
font.bold: true
font.pointSize: {
font: {
if (modelData.level <= 1)
return Tokens.font.size.large;
return Tokens.font.title.builders.large.weight(Font.Bold).build();
if (modelData.level === 2)
return Tokens.font.size.normal;
return Tokens.font.size.smaller;
return Tokens.font.title.builders.medium.weight(Font.Bold).build();
return Tokens.font.title.builders.small.weight(Font.Bold).build();
}
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
}
@@ -9,7 +9,7 @@ Item {
required property string latex
property color mathColor: Colors.palette.m3onSurface
property real fontSize: Tokens.font.size.large
property font font: Tokens.font.headline.medium
implicitHeight: Math.max(equationImage.height, fallbackText.contentHeight) + Tokens.padding.small * 2
@@ -18,7 +18,7 @@ Item {
latex: root.latex
color: root.mathColor
fontPointSize: root.fontSize
fontPointSize: root.font.pointSize
devicePixelRatio: Screen.devicePixelRatio
}
@@ -39,8 +39,7 @@ Item {
anchors.centerIn: parent
color: root.mathColor
font.family: Config.appearance.font.family.mono
font.pointSize: Tokens.font.size.small
font: Tokens.font.mono.medium
text: root.latex
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
visible: !math.ok
@@ -231,7 +231,7 @@ MouseArea {
MaterialIcon {
anchors.centerIn: parent
font.pointSize: Tokens.font.size.extraLarge
fontStyle: Tokens.font.icon.extraLarge
text: thumb.fileIcon(thumb.modelData?.mimeType ?? "")
visible: !thumb.modelData?.isImage ?? false
}
@@ -70,7 +70,7 @@ Item {
IconButton {
id: expandBtn
font.pointSize: Tokens.font.size.large
font: Tokens.font.icon.medium
icon: "keyboard_arrow_down"
inactiveOnColor: hovered ? Colors.palette.m3onSurface : Colors.palette.m3outline
anchors.centerIn: parent
@@ -91,7 +91,7 @@ Item {
id: collapsedText
color: Colors.palette.m3outline
font.pointSize: Tokens.font.size.small
font: Tokens.font.label.small
Layout.fillWidth: true
Layout.leftMargin: Tokens.spacing.medium
text: {
@@ -139,7 +139,7 @@ Item {
CustomText {
id: requestHeader
text: qsTr("Tool call request")
font.pointSize: Tokens.font.size.large
font: Tokens.font.headline.medium
color: Colors.palette.m3onSurface
}
@@ -420,7 +420,7 @@ Item {
IconButton {
id: toolExpandBtn
font.pointSize: Tokens.font.size.large
font: Tokens.font.icon.medium
icon: "keyboard_arrow_down"
inactiveOnColor: hovered ? Colors.palette.m3onSurface : Colors.palette.m3outline
rotation: toolCall.expanded ? 180 : 0
@@ -609,7 +609,7 @@ Item {
anchors.topMargin: Tokens.spacing.small
anchors.right: parent.right
color: Colors.palette.m3outline
font.pointSize: Tokens.font.size.small
font: Tokens.font.body.small
wrapMode: CustomText.WrapAtWordBoundaryOrAnywhere
text: segment.modelData.type === LlmSegment.Type.Reasoning ? segment.modelData.text : qsTr("%1 %2").arg(content.prettyTool(segment.modelData)).arg(content.toolTarget(segment.modelData))
}
@@ -11,7 +11,7 @@ Singleton {
function create(parent: Item, props: var): void {
chatComp.createObject(parent ?? dummy, props);
Visibilities.getForActive().sidebar = false;
ShellState.forActive().sidebar = false;
ChatState.isWindow = true;
}
@@ -16,7 +16,7 @@ Item {
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
readonly property int iconSize: Math.round(Tokens.font.icon.extraLarge.pointSize * (96 / 72)) + Tokens.padding.large * 2
property alias conversationModel: sidebar.model
property bool chatOpen: ChatState.chatSession !== null
@@ -174,7 +174,7 @@ Item {
MaterialIcon {
Layout.alignment: Qt.AlignCenter
text: "chat_bubble_off"
font.pointSize: Tokens.font.size.extraLarge
fontStyle: Tokens.font.icon.extraLarge
color: Colors.tPalette.m3onSurfaceVariant
}
+5 -5
View File
@@ -15,7 +15,7 @@ Item {
Connections {
function onIsWindowChanged(): void {
if (ChatState.isWindow)
root.screenState.dashboardTab = 0;
root.screenState.sidebarTab = 0;
}
target: ChatState
@@ -46,9 +46,9 @@ Item {
anchors.bottom: parent.bottom
anchors.top: parent.top
implicitWidth: parent.width
opacity: root.screenState.dashboardTab === 0 ? 1 : 0
opacity: root.screenState.sidebarTab === 0 ? 1 : 0
visible: opacity > 0
x: root.screenState.dashboardTab === 0 ? 0 : -root.width
x: root.screenState.sidebarTab === 0 ? 0 : -root.width
Behavior on opacity {
Anim {}
@@ -80,9 +80,9 @@ Item {
sourceComponent: Item {
id: chatPage
opacity: root.screenState.dashboardTab === 1 ? 1 : 0
opacity: root.screenState.sidebarTab === 1 ? 1 : 0
visible: opacity > 0
x: root.screenState.dashboardTab === 0 ? root.width : 0
x: root.screenState.sidebarTab === 0 ? root.width : 0
z: 1
Behavior on opacity {
+3 -3
View File
@@ -24,7 +24,7 @@ Item {
anchors.right: parent.right
anchors.top: parent.top
background: null
currentIndex: root.screenState.dashboardTab
currentIndex: root.screenState.sidebarTab
implicitHeight: contentHeight
contentItem: RowLayout {
@@ -108,7 +108,7 @@ Item {
color: tab.current ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
radius: Tokens.rounding.small
onClicked: root.screenState.dashboardTab = tab.TabBar.index
onClicked: root.screenState.sidebarTab = tab.TabBar.index
}
MaterialIcon {
@@ -118,7 +118,7 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter
color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurfaceVariant
fill: tab.current ? 1 : 0
font.pointSize: 18
fontStyle: Tokens.font.icon.large
text: tab.iconName
Behavior on fill {