diff --git a/qml/dialogs/HistoryDialog.qml b/qml/dialogs/HistoryDialog.qml index f21d9de..d0445af 100644 --- a/qml/dialogs/HistoryDialog.qml +++ b/qml/dialogs/HistoryDialog.qml @@ -29,8 +29,33 @@ Dialog { property int selectedIndex: -1 property string selectedHash: "" property string diffHtml: "" + property string versionContent: "" property bool busy: false + function fileDirOf(p) { + const i = p.lastIndexOf("/") + return i >= 0 ? p.substring(0, i) : "" + } + + // Ссылки внутри просмотра исторической версии: только чтение, без правок + function handleHistoryLink(href) { + if (href.startsWith("flora://copycode/")) { + copyFeedback.text = qsTr("Скопировано!") + copyFeedback.visible = true + copyTimer.restart() + return + } + if (href.startsWith("flora://task/")) { + return // историческая версия — только чтение, галочки не переключаем + } else if (href.startsWith("flora://open/")) { + documentManager.openDocument(decodeURIComponent(href.substring(13))) + } else if (href.startsWith("flora://wiki/")) { + return // несуществующие заметки из истории не создаём + } else { + Qt.openUrlExternally(href) + } + } + function reload() { if (vaultPath.length===0 || filePath.length===0) { historyModel = [] @@ -49,6 +74,7 @@ Dialog { } else { selectedIndex = -1 selectedHash = "" + versionContent = "" const hasFile = filePath.length>0 if (hasFile) { const st = gitManager.fileGitStatus(vaultPath, filePath) @@ -67,14 +93,14 @@ Dialog { function updateDiff() { if (selectedHash.length===0) { diffHtml = "" + versionContent = "" return } const html = gitManager.fileDiffHtml(vaultPath, filePath, selectedHash) if (html.length===0) diffHtml = "

" + qsTr("Нет изменений") + "

" else diffHtml = html - // также обновляем превью содержимого версии - const content = gitManager.fileContentAt(vaultPath, filePath, selectedHash) - previewArea.text = content + // содержимое версии — сырой markdown, отрисуется через MarkdownView как в «Просмотре» + versionContent = gitManager.fileContentAt(vaultPath, filePath, selectedHash) } onOpened: reload() @@ -268,7 +294,7 @@ Dialog { id: tabBar Layout.fillWidth: true TabButton { text: qsTr("Изменения") } - TabButton { text: qsTr("Содержимое версии") } + TabButton { text: qsTr("Просмотр версии") } } StackLayout { @@ -300,32 +326,37 @@ Dialog { } } - // Preview вкладка + // Просмотр версии — как кнопка «Просмотр» в редакторе Rectangle { color: Theme.editorBg border.color: Theme.divider ScrollView { + id: versionScroll anchors.fill: parent anchors.margins: 6 clip: true ScrollBar.vertical: ScrollBar {} - TextArea { - id: previewArea - readOnly: true - wrapMode: Text.Wrap - color: Theme.text - selectionColor: Theme.selectionBg - background: Rectangle { color: Theme.editorBg } - font.family: "Menlo, monospace" - font.pixelSize: 12 + Column { + width: versionScroll.availableWidth + MarkdownView { + id: versionPreview + width: parent.width + markdown: root.versionContent + vaultRoot: root.vaultPath + fileDir: root.fileDirOf(root.filePath) + emptyText: qsTr("Нет версии для просмотра") + onLinkActivated: (href) => root.handleHistoryLink(href) + } } } } } - // Легенда + // Легенда — только для вкладки «Изменения» Row { + visible: tabBar.currentIndex === 0 Layout.fillWidth: true + Layout.preferredHeight: tabBar.currentIndex === 0 ? implicitHeight : 0 Layout.margins: 6 spacing: 12 Row { spacing: 4; Rectangle { width:12; height:12; color:"#e6ffec"; border.color:"#1a7f37"; radius:2; anchors.verticalCenter: parent.verticalCenter } Label { text: qsTr("добавлено"); color: Theme.textMuted; font.pixelSize:10 } } @@ -436,4 +467,27 @@ Dialog { background: Rectangle { color: Theme.surface; border.color: Theme.borderStrong; radius: 10 } Label { id: errorLabel; color: Theme.errorText; wrapMode: Text.Wrap; width: 360 } } + + // Тост "Скопировано" для кнопки копирования в блоках кода + Rectangle { + id: copyToast + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 8 + visible: copyFeedback.visible + color: "#333" + radius: 6 + width: copyFeedback.implicitWidth + 16 + height: copyFeedback.implicitHeight + 10 + z: 10 + Label { + id: copyFeedback + anchors.centerIn: parent + visible: false + text: qsTr("Скопировано!") + color: "white" + font.pixelSize: 11 + } + } + Timer { id: copyTimer; interval: 1500; onTriggered: copyFeedback.visible = false } } diff --git a/qml/panels/MarkdownView.qml b/qml/panels/MarkdownView.qml index 3b20d08..6398501 100644 --- a/qml/panels/MarkdownView.qml +++ b/qml/panels/MarkdownView.qml @@ -8,6 +8,7 @@ Item { property string markdown: "" property string vaultRoot: "" property string fileDir: "" + property string emptyText: qsTr("Пустой файл — начните писать в режиме редактирования") implicitHeight: column.implicitHeight + 24 signal linkActivated(string href) @@ -86,7 +87,7 @@ Item { Label { width: parent.width - text: markdown.trim().length === 0 ? qsTr("Пустой файл — начните писать в режиме редактирования") : "" + text: markdown.trim().length === 0 ? emptyText : "" color: Theme.textFaint wrapMode: Text.Wrap font.italic: true