import QtQuick import QtQuick.Controls import QtQuick.Layouts import Flora Rectangle { id: root property string code: "" property string language: "text" property string codeId: "" signal copyRequested(string codeId) // Telegram-like bubble color: "#2e4d6a" radius: 12 // adaptive width like Telegram message width: parent ? Math.min(parent.width * 0.88, implicitWidth) : implicitWidth implicitWidth: 400 implicitHeight: column.implicitHeight + 20 // For syntax highlighting, we use a TextArea with RichText // The highlighted code is set from outside via highlightedText property string highlightedText: "" Column { id: column width: parent.width - 20 anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right anchors.margins: 10 spacing: 6 // Header with language and copy button — строго справа RowLayout { width: parent.width height: 24 spacing: 8 Label { text: root.language.toUpperCase() color: "#8a9ba8" font.pixelSize: 10 font.bold: true font.letterSpacing: 0.4 Layout.alignment: Qt.AlignVCenter visible: root.language !== "text" && root.language !== "" } Item { Layout.fillWidth: true height: 1 } Label { id: languageLabel text: root.language visible: false } // Copy button - Telegram style, hover/active feedback Rectangle { id: copyButton Layout.preferredWidth: copyLabel.implicitWidth + 16 Layout.preferredHeight: 22 implicitWidth: copyLabel.implicitWidth + 16 implicitHeight: 22 radius: 11 color: copyHover.hovered ? (copyTap.pressed ? Qt.rgba(1,1,1,0.30) : Qt.rgba(1,1,1,0.22)) : Qt.rgba(1,1,1,0.12) border.color: copyHover.hovered ? Qt.rgba(1,1,1,0.28) : Qt.rgba(1,1,1,0.18) border.width: 1 property bool copied: false Timer { id: copyResetTimer; interval: 1500; onTriggered: copyButton.copied = false } Label { id: copyLabel anchors.centerIn: parent text: copyButton.copied ? "✓" : "📋" color: copyButton.copied ? "#6ab2f6" : "#ffffff" font.pixelSize: 13 font.family: "-apple-system, sans-serif" } HoverHandler { id: copyHover } TapHandler { id: copyTap onTapped: { root.copyRequested(root.codeId) copyButton.copied = true copyResetTimer.restart() } } // For mouse cursor HoverHandler { cursorShape: Qt.PointingHandCursor } } } // Code area - как в редакторе, но без скролла — весь текст виден целиком Rectangle { width: parent.width color: Qt.rgba(0,0,0,0.22) radius: 8 implicitHeight: codeText.implicitHeight + 20 TextEdit { id: codeText anchors.fill: parent anchors.margins: 10 // Сохраняем форматирование как ввёл пользователь: оборачиваем в
с pre-wrap
text: {
let src = root.highlightedText
if (!src || src.length === 0) {
src = root.code.replace(/&/g, "&").replace(//g, ">").replace(/\"/g, """)
}
return "" + src + "
"
}
textFormat: TextEdit.RichText
wrapMode: TextEdit.Wrap
readOnly: true
selectByMouse: true
color: "#ffffff"
selectionColor: "#3a6ea5"
selectedTextColor: "#ffffff"
font.family: "JetBrains Mono, Fira Code, Menlo, Consolas, monospace"
font.pixelSize: 13
}
}
}
// For bracket matching highlight in editor, we could add a similar indicator
// But for preview, this is just display
}