// 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) } } }