История: содержимое версии как кнопка Просмотр
- Вкладка Содержимое версии -> Просмотр версии: MarkdownView с markdown версии (vaultRoot/fileDir файла), как режим Просмотр в редакторе - Ссылки в исторической версии только чтение: задачи/вики не трогаем, flora://open открывает в редакторе, внешние — в браузере, копирование кода с тостом Скопировано - Легенда diff только на вкладке Изменения, emptyText для пустого состояния
This commit is contained in:
@@ -29,8 +29,33 @@ Dialog {
|
|||||||
property int selectedIndex: -1
|
property int selectedIndex: -1
|
||||||
property string selectedHash: ""
|
property string selectedHash: ""
|
||||||
property string diffHtml: ""
|
property string diffHtml: ""
|
||||||
|
property string versionContent: ""
|
||||||
property bool busy: false
|
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() {
|
function reload() {
|
||||||
if (vaultPath.length===0 || filePath.length===0) {
|
if (vaultPath.length===0 || filePath.length===0) {
|
||||||
historyModel = []
|
historyModel = []
|
||||||
@@ -49,6 +74,7 @@ Dialog {
|
|||||||
} else {
|
} else {
|
||||||
selectedIndex = -1
|
selectedIndex = -1
|
||||||
selectedHash = ""
|
selectedHash = ""
|
||||||
|
versionContent = ""
|
||||||
const hasFile = filePath.length>0
|
const hasFile = filePath.length>0
|
||||||
if (hasFile) {
|
if (hasFile) {
|
||||||
const st = gitManager.fileGitStatus(vaultPath, filePath)
|
const st = gitManager.fileGitStatus(vaultPath, filePath)
|
||||||
@@ -67,14 +93,14 @@ Dialog {
|
|||||||
function updateDiff() {
|
function updateDiff() {
|
||||||
if (selectedHash.length===0) {
|
if (selectedHash.length===0) {
|
||||||
diffHtml = ""
|
diffHtml = ""
|
||||||
|
versionContent = ""
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const html = gitManager.fileDiffHtml(vaultPath, filePath, selectedHash)
|
const html = gitManager.fileDiffHtml(vaultPath, filePath, selectedHash)
|
||||||
if (html.length===0) diffHtml = "<p style='color:" + Theme.textFaint + "'>" + qsTr("Нет изменений") + "</p>"
|
if (html.length===0) diffHtml = "<p style='color:" + Theme.textFaint + "'>" + qsTr("Нет изменений") + "</p>"
|
||||||
else diffHtml = html
|
else diffHtml = html
|
||||||
// также обновляем превью содержимого версии
|
// содержимое версии — сырой markdown, отрисуется через MarkdownView как в «Просмотре»
|
||||||
const content = gitManager.fileContentAt(vaultPath, filePath, selectedHash)
|
versionContent = gitManager.fileContentAt(vaultPath, filePath, selectedHash)
|
||||||
previewArea.text = content
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onOpened: reload()
|
onOpened: reload()
|
||||||
@@ -268,7 +294,7 @@ Dialog {
|
|||||||
id: tabBar
|
id: tabBar
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
TabButton { text: qsTr("Изменения") }
|
TabButton { text: qsTr("Изменения") }
|
||||||
TabButton { text: qsTr("Содержимое версии") }
|
TabButton { text: qsTr("Просмотр версии") }
|
||||||
}
|
}
|
||||||
|
|
||||||
StackLayout {
|
StackLayout {
|
||||||
@@ -300,32 +326,37 @@ Dialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preview вкладка
|
// Просмотр версии — как кнопка «Просмотр» в редакторе
|
||||||
Rectangle {
|
Rectangle {
|
||||||
color: Theme.editorBg
|
color: Theme.editorBg
|
||||||
border.color: Theme.divider
|
border.color: Theme.divider
|
||||||
ScrollView {
|
ScrollView {
|
||||||
|
id: versionScroll
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: 6
|
anchors.margins: 6
|
||||||
clip: true
|
clip: true
|
||||||
ScrollBar.vertical: ScrollBar {}
|
ScrollBar.vertical: ScrollBar {}
|
||||||
TextArea {
|
Column {
|
||||||
id: previewArea
|
width: versionScroll.availableWidth
|
||||||
readOnly: true
|
MarkdownView {
|
||||||
wrapMode: Text.Wrap
|
id: versionPreview
|
||||||
color: Theme.text
|
width: parent.width
|
||||||
selectionColor: Theme.selectionBg
|
markdown: root.versionContent
|
||||||
background: Rectangle { color: Theme.editorBg }
|
vaultRoot: root.vaultPath
|
||||||
font.family: "Menlo, monospace"
|
fileDir: root.fileDirOf(root.filePath)
|
||||||
font.pixelSize: 12
|
emptyText: qsTr("Нет версии для просмотра")
|
||||||
|
onLinkActivated: (href) => root.handleHistoryLink(href)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Легенда
|
// Легенда — только для вкладки «Изменения»
|
||||||
Row {
|
Row {
|
||||||
|
visible: tabBar.currentIndex === 0
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: tabBar.currentIndex === 0 ? implicitHeight : 0
|
||||||
Layout.margins: 6
|
Layout.margins: 6
|
||||||
spacing: 12
|
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 } }
|
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 }
|
background: Rectangle { color: Theme.surface; border.color: Theme.borderStrong; radius: 10 }
|
||||||
Label { id: errorLabel; color: Theme.errorText; wrapMode: Text.Wrap; width: 360 }
|
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 }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ Item {
|
|||||||
property string markdown: ""
|
property string markdown: ""
|
||||||
property string vaultRoot: ""
|
property string vaultRoot: ""
|
||||||
property string fileDir: ""
|
property string fileDir: ""
|
||||||
|
property string emptyText: qsTr("Пустой файл — начните писать в режиме редактирования")
|
||||||
implicitHeight: column.implicitHeight + 24
|
implicitHeight: column.implicitHeight + 24
|
||||||
|
|
||||||
signal linkActivated(string href)
|
signal linkActivated(string href)
|
||||||
@@ -86,7 +87,7 @@ Item {
|
|||||||
|
|
||||||
Label {
|
Label {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: markdown.trim().length === 0 ? qsTr("Пустой файл — начните писать в режиме редактирования") : ""
|
text: markdown.trim().length === 0 ? emptyText : ""
|
||||||
color: Theme.textFaint
|
color: Theme.textFaint
|
||||||
wrapMode: Text.Wrap
|
wrapMode: Text.Wrap
|
||||||
font.italic: true
|
font.italic: true
|
||||||
|
|||||||
Reference in New Issue
Block a user