docs/ is engineering artifacts -- design specs, plans, an upstream ledger -- and none of it is written for the person who has to live here. Five chapters that are: coming from another desktop, the keyboard, windows and workspaces, when something breaks, and making it yours. Rendered inside Settings rather than opened in a browser, so a chapter that says "the Displays page reverts after fifteen seconds" is one click from the Displays page. Qt's markdown renderer does the work; one chapter per Text, because Text has an implicit texture size limit and a document long enough to hit it goes blank rather than complaining. The chapters live beside the shell in manual/ rather than at the repository root, which departs from the plan. The reason is the path: the shell finds them through Quickshell.shellDir, which is correct wherever the repository is, whereas walking upward out of the shell directory is only correct by accident. The contract fails that pattern if it comes back. The contract also pins the set both ways -- every chapter listed exists, every chapter that exists is listed -- because a renamed file shows an error card where a chapter should be, which reads as a broken manual rather than as a moved file.
97 lines
3.5 KiB
QML
97 lines
3.5 KiB
QML
// The manual.
|
|
//
|
|
// Panama's docs/ directory is engineering artifacts: design specs, plans, an
|
|
// upstream ledger. None of it is written for the person using the desktop,
|
|
// and the person using the desktop is the one with questions.
|
|
//
|
|
// So the manual is prose, in chapters, rendered here rather than opened in a
|
|
// browser. Keeping it in Settings means it is reachable from the same place
|
|
// as everything else it talks about, and a link to a settings page can just
|
|
// be a settings page.
|
|
//
|
|
// The chapters live beside the shell in manual/, not at the repository root.
|
|
// They are read at runtime through Quickshell.shellDir, which resolves whether
|
|
// or not the repository is where it usually is; a path walked upward out of
|
|
// the shell directory does not.
|
|
//
|
|
// One Text per chapter, never the whole manual at once: Text has an implicit
|
|
// texture size limit, and a document long enough to hit it fails by going
|
|
// blank rather than by complaining.
|
|
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
import QtQuick
|
|
import qs.config
|
|
import qs.services
|
|
|
|
SettingsPage {
|
|
id: root
|
|
|
|
title: "Manual"
|
|
lede: "How this desktop works, for the person using it."
|
|
|
|
// Chapter files are numbered so their order is their filename. The title
|
|
// shown here is the first heading of each, read from the file, so a
|
|
// chapter cannot be renamed in one place and not the other.
|
|
readonly property var chapters: [
|
|
{ file: "01-coming-from-another-desktop.md", label: "Coming from another desktop" },
|
|
{ file: "02-the-keyboard.md", label: "The keyboard" },
|
|
{ file: "03-windows-and-workspaces.md", label: "Windows and workspaces" },
|
|
{ file: "04-when-something-breaks.md", label: "When something breaks" },
|
|
{ file: "05-making-it-yours.md", label: "Making it yours" }
|
|
]
|
|
|
|
property int current: 0
|
|
|
|
// A deep link picks the chapter once and then lets go, so arriving at a
|
|
// chapter does not pin you to it. Same consume-once idiom ShellState uses
|
|
// for settings sections.
|
|
Component.onCompleted: {
|
|
const section = ShellState.takeSettingsSection();
|
|
for (let index = 0; index < root.chapters.length; index++) {
|
|
if (root.chapters[index].file.indexOf(section) >= 0 && section !== "") {
|
|
root.current = index;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SettingsTabs {
|
|
tabs: root.chapters.map((chapter, index) => ({
|
|
value: String(index),
|
|
label: chapter.label
|
|
}))
|
|
current: String(root.current)
|
|
onSelected: value => root.current = parseInt(value, 10)
|
|
}
|
|
|
|
SettingsCard {
|
|
FileView {
|
|
id: chapterFile
|
|
path: Quickshell.shellDir + "/manual/" + root.chapters[root.current].file
|
|
printErrors: false
|
|
onLoaded: body.text = this.text()
|
|
onLoadFailed: body.text =
|
|
"This chapter could not be read.\n\nIt should be at `"
|
|
+ chapterFile.path + "`."
|
|
}
|
|
|
|
Text {
|
|
id: body
|
|
|
|
width: parent.width
|
|
textFormat: Text.MarkdownText
|
|
wrapMode: Text.WordWrap
|
|
color: Theme.fgDim
|
|
linkColor: Theme.accent
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSize
|
|
// Markdown's own line height is tight for a wall of prose at this
|
|
// size; a document read once needs to be easy on the first pass.
|
|
lineHeight: 1.35
|
|
|
|
onLinkActivated: link => Qt.openUrlExternally(link)
|
|
}
|
|
}
|
|
}
|