Files
CST-agent/archive/qt-app/qml/MessageCard.qml
T
WHCandCursor 5538ed3412
ci / tcc-check (push) Successful in 1m8s
ci / linux (aarch64, 0) (push) Failing after 1h0m3s
ci / linux (x86, 1) (push) Failing after 1h0m3s
ci / linux (x86_64, 1) (push) Failing after 1h0m2s
ci / windows (push) Failing after 50s
refactor: archive GUI clients; keep minimal TUI with hooks/API
Move Qt/Tauri/full Web SPA under archive/, ship hermit as CLI/TUI plus
libcstcore and cst-webui/1 HTTP+SSE (turn lifecycle hooks, capabilities).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-30 22:49:23 +08:00

118 lines
3.7 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
// One message in the transcript: the prompt, the answer, or an error. The
// answer arrives as plain text while it streams and is rendered from markdown
// (by the engine, through AgentCore::renderMarkdown) once it is complete.
Rectangle {
id: card
property string role: "agent" // user | agent | error
property string text: ""
property string html: ""
property bool complete: true
property string images: ""
radius: Theme.radius
color: role === "user" ? Theme.surfaceAlt : Theme.surface
border.width: 1
border.color: role === "error" ? Theme.err
: role === "user" ? Theme.border : Theme.border
implicitHeight: layout.implicitHeight + Theme.pad * 2
ColumnLayout {
id: layout
anchors {
left: parent.left
right: parent.right
top: parent.top
margins: Theme.pad
}
spacing: Theme.gap
RowLayout {
spacing: Theme.gap
Rectangle {
width: 6
height: 6
radius: 3
color: card.role === "user" ? Theme.accent
: card.role === "error" ? Theme.err : Theme.ok
}
Text {
text: card.role === "user" ? "You"
: card.role === "error" ? "Error" : "CST-agent"
color: Theme.textDim
font.pixelSize: Theme.smallSize
font.bold: true
}
Text {
visible: !card.complete
text: "streaming…"
color: Theme.textFaint
font.pixelSize: Theme.smallSize
}
Item { Layout.fillWidth: true }
ToolButton {
implicitWidth: 26
implicitHeight: 22
visible: card.text.length > 0
ToolTip.visible: hovered
ToolTip.text: "Copy"
contentItem: ThemeIcon {
name: "edit-copy"
glyph: "⧉"
size: 14
color: parent.hovered ? Theme.text : Theme.textFaint
}
background: Rectangle {
radius: Theme.radiusSm
color: parent.hovered ? Theme.surfaceHi : "transparent"
}
onClicked: {
plain.text = card.text
plain.selectAll()
plain.copy()
}
}
}
// Hidden holder so "copy" always has the plain text, rtf or not.
TextEdit {
id: plain
visible: false
}
TextEdit {
id: streamText
visible: card.html.length === 0
Layout.fillWidth: true
text: card.text
readOnly: true
selectByMouse: true
wrapMode: TextEdit.Wrap
color: card.role === "error" ? Theme.err : Theme.text
font.pixelSize: Theme.bodySize
selectionColor: Theme.accentDim
}
Text {
visible: card.html.length > 0
Layout.fillWidth: true
text: card.html
textFormat: Text.RichText
color: Theme.text
font.pixelSize: Theme.bodySize
wrapMode: Text.Wrap
onLinkActivated: function (link) { Qt.openUrlExternally(link) }
}
// What the prompt carried: pictures from the store, not their names.
ImageStrip {
Layout.fillWidth: true
visible: card.images.length > 0
text: card.images
}
}
}