Files
Flora/qml/panels/MonthCalendar.qml
T
grendervill 95c03040c7 Prod: полный аудит и стабилизация — исправлены критические баги, расширено покрытие тестами, подготовлен бандл
- FileStore: защита от выхода за пределы хранилища (isInsideVault), валидация имён (запрет скрытых, зарезервированных, управляющих символов), проверка destDir, лимит watcher, dailyNote валидация, openVault проверка isDir
- DocumentManager: лимит 10МБ, кламп автосейва 0.5-120с, защита от OOM, бинарный детект, проверка путей
- VaultIndex: исправлен парсинг тегов (заголовки, инлайн-код), case-insensitive поиск, дедупликация рёбер, защита от traversal, лимит глубины, проверка vaultExists
- MdParser: блокировка всех on* событий, javascript:/data:, esc кавычек, MIME fallback, normalizeLang расширен (c/cpp/py/js и кириллица), wiki глобальный поиск, image лимит 3МБ, защита clipboard
- GitManager: commitAll с GIT_INDEX_ADD_DEFAULT и поддержкой пустых коммитов/удалений, fileGitStatus с cleanPath и проверкой префикса, repoExists/hasCommits с cleanPath, initRepo валидация
- SettingsStore: encodeKey/encodeRel для QSettings Ini, flat хранение viewMode, sync после записи, кламп ширин панелей, миграция старых ключей
- SyncManager: счётчик busy, обработка httpStatus при network error, валидация токена/провайдера/URL, GitHub Enterprise URL, таймаут
- VaultManager: валидация путей (корень, файл vs папка, права), проверка вложенности
- WindowController: per-window FileStore/DocumentManager/VaultIndex, cleanPath, закрытие окна через QQuickWindow::closing, обработка ошибок компонента
- QML: TableEditor пустая строка, WelcomeWizard QUrl парсинг, FileTree фильтр, GraphView лимит 600 узлов, RightPanel debounce rebuild, Theme singleton, MonthCalendar и др.
- Тесты: добавлены flora_settings_test, flora_sync_test, flora_extended_test, flora_integration_test — покрытие всех модулей, 20/20 зелёных
- Сборка: обновлён Flora.app (4.6М бинарь -> 173М бандл, ad-hoc подпись, проверен offscreen запуск, версия 0.0.1 + cmark 0.29 + libgit2 1.9)
- .gitignore: добавлены Testing/, coverage, gcda/gcov, __pycache__, .tmp, test-vault и др.
2026-09-01 19:25:07 +03:00

157 lines
5.7 KiB
QML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Flora
Item {
id: cal
signal daySelected(string dateStr)
property date currentMonth: new Date()
readonly property int year: currentMonth.getFullYear()
readonly property int month: currentMonth.getMonth()
function fmtDate(d) {
function pad(n) { return n < 10 ? "0" + n : "" + n }
return d.getFullYear() + "-" + pad(d.getMonth() + 1) + "-" + pad(d.getDate())
}
function gridModel() {
const first = new Date(year, month, 1)
const dowSun0 = first.getDay()
const startDow = (dowSun0 + 6) % 7
const daysInMonth = new Date(year, month + 1, 0).getDate()
const list = []
for (let i = 0; i < startDow; ++i) list.push(0)
for (let d = 1; d <= daysInMonth; ++d) list.push(d)
while (list.length % 7 !== 0) list.push(0)
while (list.length < 42) list.push(0)
return list
}
ColumnLayout {
anchors.fill: parent
spacing: 4
RowLayout {
Layout.fillWidth: true
ToolButton {
text: "‹"
font.pixelSize: 16
onClicked: cal.currentMonth = new Date(year, month - 1, 1)
}
Label {
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
font.bold: true
color: Theme.text
text: Qt.locale().monthName(month, Locale.LongFormat) + " " + year
}
ToolButton {
text: "›"
font.pixelSize: 16
onClicked: cal.currentMonth = new Date(year, month + 1, 1)
}
ToolButton {
text: "\u2302"
font.pixelSize: 12
ToolTip.text: qsTr("Сегодня")
ToolTip.visible: hovered
onClicked: cal.currentMonth = new Date()
}
}
RowLayout {
Layout.fillWidth: true
Repeater {
model: ["Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"]
Label {
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 10
font.bold: true
color: Theme.textMuted
text: modelData
}
}
}
Grid {
Layout.fillWidth: true
Layout.fillHeight: true
columns: 7
rowSpacing: 2
columnSpacing: 2
Repeater {
model: cal.gridModel()
delegate: Rectangle {
required property int modelData
width: (cal.width - 12) / 7
height: (cal.height - 50) / 6
radius: 6
border.width: isToday ? 1 : 0
border.color: Theme.accent
color: {
if (modelData <= 0) return "transparent"
if (isToday) return Theme.calendarToday
if (isSelected) return Theme.accentMuted
if (hasNote) return Theme.isDark ? "#252a33" : "#f8f9fb"
return Theme.surface
}
readonly property var now: { const t = new Date(); return { day: t.getDate(), month: t.getMonth(), year: t.getFullYear() } }
readonly property bool isToday: modelData > 0 && now.day === modelData && now.month === cal.month && now.year === cal.year
readonly property string ds: modelData > 0 ? Qt.formatDate(new Date(cal.year, cal.month, modelData), "yyyy-MM-dd") : ""
readonly property bool hasNote: {
const _ = cal.currentMonth
if (modelData <= 0 || !fileStore.ready) return false
return fileStore.fileExists(fileStore.vault + "/Журнал/" + ds + ".md")
}
readonly property bool isSelected: false // можно подсветить выбранный день
Label {
id: dayLabel
anchors.centerIn: parent
anchors.verticalCenterOffset: hasNote ? -3 : 0
visible: modelData > 0
text: modelData
font.pixelSize: 11
font.bold: isToday
color: modelData > 0 ? (isToday ? Theme.accentText : Theme.text) : "transparent"
}
Rectangle {
visible: modelData > 0 && parent.hasNote
width: 5; height: 5; radius: 2.5
color: Theme.calendarDot
anchors.top: dayLabel.bottom
anchors.topMargin: 2
anchors.horizontalCenter: parent.horizontalCenter
}
MouseArea {
anchors.fill: parent
enabled: modelData > 0
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
const d = new Date(cal.year, cal.month, modelData)
cal.daySelected(fmtDate(d))
}
}
}
}
}
// подпись
Label {
Layout.fillWidth: true
text: qsTr("Клик — заметка дня")
color: Theme.textFaint
font.pixelSize: 9
horizontalAlignment: Text.AlignHCenter
}
}
}