mirror of
https://git.pumpin.online/funkpower/menologion.git
synced 2026-10-22 18:57:14 +00:00
`import qs.horologion.modules` was the README's headline instruction and it
fails outright: Quickshell resolves `qs` against the host config root, not
the subtree, so in an empty shell the type is unavailable and in a populated
one the widget would have silently bound to the host's Config and Theme
instead of its own. The imports inside are now relative and each directory
carries a qmldir, so `import "horologion/modules"` works in any host and the
three pieces really are usable on their own.
- refresh() dropped a request made while a run was in flight, so a
jurisdiction or date set a moment after startup never took effect until
midnight. It queues now.
- The waybar script exited non-zero on its error paths, and waybar hides a
module whose script does that -- so a missing typikon made the module
vanish rather than say so, and the .error CSS was dead. An unrecognised
--format field raised instead of rendering empty, and the tooltip
interpolated unescaped text into Pango markup, which matters because
--update-menaion fetches commemorations from a page nobody here controls.
- The installer aborted the whole run at the point where it printed
'leaving it alone', and a wholly successful run exited 1 because the last
statement was a failed [ -d ] test under set -e. --help demanded typikon,
which is what --help would have told you to install.
- eww painted every day with the feast colour and printed a dangling
separator, because it compares against "" and eww renders a JSON null as
the string "null". The parenthesised ?: form two lines away was already
right. The week list also repeated today.
pip install typikon installed nothing; there is no such package, and that was
the first line of every install path. Pascha now carries its label instead of
being a bare ISO date in a corner.
tests/smoke.sh covers the scripts, which is where all of this lived and where
nothing was covered. It caught two of these while being written.
210 lines
7.2 KiB
QML
210 lines
7.2 KiB
QML
import QtQuick
|
|
import QtQuick.Layouts
|
|
import ".."
|
|
import "../services"
|
|
|
|
Panel {
|
|
id: root
|
|
title: "Church calendar"
|
|
// The church date, always: on the old calendar it is the answer people
|
|
// came for, and on the new it is a harmless echo of the title bar.
|
|
note: Typikon.available ? Typikon.churchDate : ""
|
|
|
|
// The glyph carries what kind of fast it is, so obligation has to be shown
|
|
// some other way or it disappears with the text: the weekday takes the
|
|
// colour. Under the Typikon nothing binds and everything is yellow; under
|
|
// a particular law that does bind, the days that bind go red. A panel that
|
|
// blurs the two states something untrue.
|
|
function tint(d) {
|
|
if (!d) return Theme.fgDim;
|
|
if (d.fast === "none") return Theme.fgDim;
|
|
return d.obligation === "obligatory" ? Theme.red : Theme.yellow;
|
|
}
|
|
|
|
// The legend is built from the week in view rather than hardcoded, because
|
|
// the levels a tradition uses are its own — six under the Typikon, three
|
|
// under Ruthenian law — and the words for them differ too.
|
|
readonly property var legend: {
|
|
const seen = [], out = [];
|
|
for (const d of Typikon.week) {
|
|
if (!d.emoji || seen.indexOf(d.fast) !== -1) continue;
|
|
seen.push(d.fast);
|
|
out.push({ emoji: d.emoji, label: d.fastLabel });
|
|
}
|
|
return out;
|
|
}
|
|
|
|
ColumnLayout {
|
|
spacing: 7
|
|
|
|
Text {
|
|
visible: !Typikon.available
|
|
Layout.fillWidth: true
|
|
text: Typikon.error !== "" ? Typikon.error
|
|
: "unavailable — is `typikon` on PATH?"
|
|
color: Theme.fgDim
|
|
wrapMode: Text.WordWrap
|
|
font.family: Config.font
|
|
font.pixelSize: Config.fontSize - 1
|
|
}
|
|
|
|
// Today, given room because it is the day being asked about.
|
|
RowLayout {
|
|
Layout.fillWidth: true
|
|
visible: Typikon.available
|
|
spacing: 11
|
|
|
|
Text {
|
|
text: Typikon.emoji
|
|
font.family: Config.font
|
|
font.pixelSize: 28
|
|
}
|
|
|
|
ColumnLayout {
|
|
Layout.fillWidth: true
|
|
spacing: 1
|
|
|
|
Text {
|
|
Layout.fillWidth: true
|
|
text: Typikon.title
|
|
color: Typikon.feast !== "" ? Theme.accent : Theme.fg
|
|
wrapMode: Text.WordWrap
|
|
maximumLineCount: 2
|
|
elide: Text.ElideRight
|
|
font.family: Config.font
|
|
font.pixelSize: Config.fontSize
|
|
font.bold: true
|
|
}
|
|
|
|
Text {
|
|
Layout.fillWidth: true
|
|
text: {
|
|
const bits = [Typikon.weekday];
|
|
if (Typikon.season !== "") bits.push(Typikon.season);
|
|
if (Typikon.obligatory) bits.push("obligatory");
|
|
return bits.join(" · ");
|
|
}
|
|
color: root.tint(Typikon.today)
|
|
elide: Text.ElideRight
|
|
font.family: Config.font
|
|
font.pixelSize: Config.fontSize - 3
|
|
font.bold: Typikon.obligatory
|
|
}
|
|
|
|
// Forefeast, afterfeast, leave-taking. These repeat for days at
|
|
// a time, so they get their own quiet line rather than crowding
|
|
// out the commemoration that makes the day itself.
|
|
Text {
|
|
Layout.fillWidth: true
|
|
visible: Typikon.cycle !== ""
|
|
text: Typikon.cycle
|
|
color: Qt.alpha(Theme.fgDim, 0.8)
|
|
elide: Text.ElideRight
|
|
font.family: Config.font
|
|
font.pixelSize: Config.fontSize - 3
|
|
font.italic: true
|
|
}
|
|
}
|
|
}
|
|
|
|
// The rest of today's commemorations, under it.
|
|
ColumnLayout {
|
|
Layout.fillWidth: true
|
|
Layout.leftMargin: 39
|
|
visible: Typikon.available
|
|
spacing: 0
|
|
|
|
Repeater {
|
|
model: Typikon.commemorations.filter(c => c !== Typikon.title).slice(0, 3)
|
|
|
|
delegate: Text {
|
|
required property var modelData
|
|
Layout.fillWidth: true
|
|
text: "· " + modelData
|
|
color: Theme.fgDim
|
|
elide: Text.ElideRight
|
|
font.family: Config.font
|
|
font.pixelSize: Config.fontSize - 3
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
Layout.fillWidth: true
|
|
visible: Typikon.week.length > 1
|
|
implicitHeight: 1
|
|
color: Qt.alpha(Theme.overlay, 0.6)
|
|
}
|
|
|
|
// The rest of the week: glyph, weekday, and what is kept that day.
|
|
Repeater {
|
|
model: Typikon.week.length > 1 ? Typikon.week.slice(1) : []
|
|
|
|
delegate: RowLayout {
|
|
required property var modelData
|
|
Layout.fillWidth: true
|
|
spacing: 9
|
|
|
|
Text {
|
|
text: modelData.emoji
|
|
font.family: Config.font
|
|
font.pixelSize: Config.fontSize + 3
|
|
}
|
|
Text {
|
|
Layout.preferredWidth: 32
|
|
text: modelData.weekday.substring(0, 3)
|
|
color: root.tint(modelData)
|
|
font.family: Config.font
|
|
font.pixelSize: Config.fontSize - 2
|
|
font.bold: modelData.obligation === "obligatory"
|
|
}
|
|
Text {
|
|
Layout.fillWidth: true
|
|
text: modelData.title
|
|
color: modelData.feast ? Theme.accent : Theme.fgDim
|
|
elide: Text.ElideRight
|
|
font.family: Config.font
|
|
font.pixelSize: Config.fontSize - 3
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
Layout.fillWidth: true
|
|
visible: Typikon.available
|
|
implicitHeight: 1
|
|
color: Qt.alpha(Theme.overlay, 0.6)
|
|
}
|
|
|
|
RowLayout {
|
|
Layout.fillWidth: true
|
|
visible: Typikon.available
|
|
spacing: 10
|
|
|
|
Flow {
|
|
Layout.fillWidth: true
|
|
spacing: 9
|
|
|
|
Repeater {
|
|
model: root.legend
|
|
delegate: Text {
|
|
required property var modelData
|
|
text: modelData.emoji + " " + modelData.label
|
|
color: Qt.alpha(Theme.fgDim, 0.75)
|
|
font.family: Config.font
|
|
font.pixelSize: Config.fontSize - 4
|
|
}
|
|
}
|
|
}
|
|
|
|
Text {
|
|
// Labelled, because a bare ISO date in a corner is a riddle.
|
|
text: Typikon.pascha !== "" ? "Pascha " + Typikon.pascha : ""
|
|
color: Theme.fgDim
|
|
font.family: Config.font
|
|
font.pixelSize: Config.fontSize - 4
|
|
}
|
|
}
|
|
}
|
|
}
|