Watch
1
0
Fork
You've already forked souveraine
0

sidebar: the garden's micro-view — Lens service, vault card in the right panel

The vault card lives where notifications were — header with sync pill
(clean/ahead/behind/dirty), today's note entry, five freshest notes,
cold start and push rows — over the notification list. Lens.qml owns
souveraine-lens the way Face owns the rig: one socket, event lines up,
no vault access of its own. Kiyoshi's slash grammar and tool registry
are noted for the fuller app; the micro view only opens and plants.
This commit is contained in:
Fimeg 2026-08-10 21:24:23 -04:00
commit cb7dd73d2b
5 changed files with 543 additions and 0 deletions

View file

@ -0,0 +1,30 @@
import qs.modules.common
import qs.modules.common.widgets
import qs.services
import qs.modules.ii.sidebarRight.notifications
import qs.modules.ii.sidebarRight.lens
import QtQuick
import QtQuick.Layouts
Rectangle {
id: root
clip: true
radius: Appearance.rounding.normal
color: Appearance.colors.colLayer1
ColumnLayout {
anchors.fill: parent
anchors.margins: 5
spacing: 5
LensWidget {
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
}
NotificationList {
Layout.fillWidth: true
Layout.fillHeight: true
}
}
}

View file

@ -0,0 +1,281 @@
// The garden's micro-view the vault card in the right panel.
//
// The micro view is a window into the lens window, not a second editor:
// it shows the freshest notes, the sync truth, a daily note entry point
// and a quick capture and every tap either opens the garden at that
// note or plants one in it. The full app is the lens window itself; this
// is the pulse.
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
import QtQuick.Layouts
Item {
id: root
implicitHeight: column.implicitHeight
property var shown: Lens.joined ? Lens.notes.slice(0, 5) : []
function dailyRel() {
return new Date().toISOString().slice(0, 10) + ".md";
}
function openDaily() {
if (!Lens.joined) {
Lens.join();
return;
}
const rel = root.dailyRel();
const exists = Lens.notes.some(n => n.rel === rel);
if (exists)
Lens.openNote(rel);
else
Lens.createNote(rel.replace(/\.md$/, ""));
}
function relTime(mtime) {
const s = Math.max(0, Date.now() / 1000 - mtime);
if (s < 60) return Translation.tr("just now");
if (s < 3600) return Translation.tr("%1m ago").arg(Math.floor(s / 60));
if (s < 86400) return Translation.tr("%1h ago").arg(Math.floor(s / 3600));
if (s < 604800) return Translation.tr("%1d ago").arg(Math.floor(s / 86400));
return new Date(mtime * 1000).toLocaleDateString(Qt.locale(), "dd MMM");
}
onVisibleChanged: {
if (root.visible && Lens.joined)
Lens.requestState();
}
ColumnLayout {
id: column
anchors.fill: parent
spacing: 4
// header
RowLayout {
Layout.fillWidth: true
spacing: 6
MaterialSymbol {
text: "hub"
iconSize: Appearance.font.pixelSize.larger
color: Appearance.colors.colPrimary
}
ColumnLayout {
Layout.fillWidth: true
spacing: 0
StyledText {
font.pixelSize: Appearance.font.pixelSize.larger
color: Appearance.colors.colOnLayer1
text: Translation.tr("Garden")
}
StyledText {
visible: Lens.joined && Lens.head.length > 0
font.pixelSize: Appearance.font.pixelSize.small
color: Appearance.colors.colOnLayer1Inactive
text: Lens.branch + " @" + Lens.head
}
}
Rectangle {
id: syncPill
Layout.alignment: Qt.AlignVCenter
radius: 8
color: Appearance.colors.colLayer0
implicitHeight: pillText.implicitHeight + 6
implicitWidth: pillText.implicitWidth + 14
Row {
anchors.centerIn: parent
spacing: 5
Rectangle {
anchors.verticalCenter: parent.verticalCenter
width: 7
height: 7
radius: width / 2
color: root.pillColor
}
StyledText {
id: pillText
font.pixelSize: Appearance.font.pixelSize.small
color: Appearance.colors.colOnLayer0
text: Lens.stateText
}
}
}
}
Rectangle {
Layout.fillWidth: true
Layout.topMargin: 2
height: 1
color: Appearance.colors.colLayer0Border
}
// the daily note
Item {
Layout.fillWidth: true
Layout.topMargin: 2
implicitHeight: dailyRow.implicitHeight
RowLayout {
id: dailyRow
anchors.fill: parent
spacing: 6
MaterialSymbol {
text: "today"
iconSize: Appearance.font.pixelSize.normal
color: Appearance.colors.colOnLayer1Inactive
}
StyledText {
Layout.fillWidth: true
font.pixelSize: Appearance.font.pixelSize.normal
color: Appearance.colors.colOnLayer1
text: Translation.tr("Today's note")
}
StyledText {
font.pixelSize: Appearance.font.pixelSize.small
color: Appearance.colors.colPrimary
text: Translation.tr("open")
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: root.openDaily()
}
}
// fresh notes
Repeater {
model: root.shown
delegate: Item {
required property var modelData
required property int index
Layout.fillWidth: true
implicitHeight: noteRow.implicitHeight
RowLayout {
id: noteRow
anchors.fill: parent
spacing: 6
Rectangle {
Layout.alignment: Qt.AlignVCenter
width: 4
height: 4
radius: width / 2
color: index === 0 ? Appearance.colors.colPrimary : Appearance.colors.colOnLayer1Inactive
}
StyledText {
Layout.fillWidth: true
elide: Text.ElideRight
font.pixelSize: Appearance.font.pixelSize.normal
color: Appearance.colors.colOnLayer1
text: modelData.title
}
StyledText {
font.pixelSize: Appearance.font.pixelSize.small
color: Appearance.colors.colOnLayer1Inactive
text: root.relTime(modelData.mtime)
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: Lens.openNote(modelData.rel)
}
}
}
// cold card
Item {
Layout.fillWidth: true
visible: !Lens.joined
implicitHeight: coldRow.implicitHeight
RowLayout {
id: coldRow
anchors.fill: parent
spacing: 6
MaterialSymbol {
text: "crop_free"
iconSize: Appearance.font.pixelSize.normal
color: Appearance.colors.colOnLayer1Inactive
}
StyledText {
Layout.fillWidth: true
font.pixelSize: Appearance.font.pixelSize.normal
color: Appearance.colors.colOnLayer1Inactive
text: Translation.tr("The garden is closed")
}
StyledText {
font.pixelSize: Appearance.font.pixelSize.normal
color: Appearance.colors.colPrimary
text: Translation.tr("Open")
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: Lens.join()
}
}
// push the truth
Item {
Layout.fillWidth: true
visible: Lens.joined && (Lens.syncState === "ahead" || Lens.syncState === "diverged" || Lens.syncState === "dirty")
implicitHeight: pushRow.implicitHeight
RowLayout {
id: pushRow
anchors.fill: parent
spacing: 6
MaterialSymbol {
text: "upload"
iconSize: Appearance.font.pixelSize.normal
color: Appearance.colors.colPrimary
}
StyledText {
Layout.fillWidth: true
font.pixelSize: Appearance.font.pixelSize.normal
color: Appearance.colors.colOnLayer1
text: Translation.tr("The garden is ahead — push it")
}
StyledText {
font.pixelSize: Appearance.font.pixelSize.normal
color: Appearance.colors.colPrimary
text: Translation.tr("Push")
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: Lens.syncNow()
}
}
}
// Pill color: one dot, one meaning.
readonly property color pillColor: {
if (!Lens.joined) return Appearance.colors.colOnLayer1Inactive;
switch (Lens.syncState) {
case "clean": return Appearance.colors.colPrimary;
case "dirty": return Appearance.m3colors.m3error;
case "ahead":
case "diverged": return Appearance.m3colors.m3tertiary;
case "behind": return Appearance.m3colors.m3error;
default: return Appearance.colors.colOnLayer1Inactive;
}
}
}