help documentation

This commit is contained in:
2026-09-30 17:48:03 -05:00
parent 6134cc90ff
commit 1cd560d954
3 changed files with 396 additions and 5 deletions
+6
View File
@@ -278,6 +278,8 @@ pub struct App {
settings_test_status: String,
/// Whether the markdown cheatsheet window is open.
show_cheatsheet: bool,
/// Whether the User Guide window is open.
show_user_guide: bool,
/// Whether the find/replace bar above the editor is visible.
show_find: bool,
/// The search text.
@@ -510,6 +512,7 @@ impl App {
settings_test_rx: None,
settings_test_status: String::new(),
show_cheatsheet: false,
show_user_guide: false,
show_find: false,
find_query: String::new(),
replace_query: String::new(),
@@ -788,6 +791,9 @@ impl eframe::App for App {
if self.show_cheatsheet {
crate::help::cheatsheet_window(ctx, &mut self.show_cheatsheet);
}
if self.show_user_guide {
crate::help::user_guide_window(ctx, &mut self.show_user_guide);
}
if self.pending_repo.is_some() {
self.repo_prompt(ctx);
+4
View File
@@ -438,6 +438,10 @@ impl App {
}
});
ui.menu_button("Help", |ui| {
if ui.button("📖 User Guide").clicked() {
ui.close_menu();
self.show_user_guide = true;
}
if ui.button("📝 Markdown cheatsheet").clicked() {
ui.close_menu();
self.show_cheatsheet = true;
+386 -5
View File
@@ -1,9 +1,10 @@
//! In-app **Markdown cheatsheet** window: a quick reference for the markdown
//! md-manuscript understands, plus the manuscript-specific conventions (YAML frontmatter
//! metadata and comments) applied at export time.
//! In-app documentation, reached from the **Help** menu: a **Markdown
//! cheatsheet** (the markdown/frontmatter syntax md-manuscript understands)
//! and a broader **User Guide** (what every window, menu item and setting
//! actually does).
//!
//! Pure rendering — the caller owns the `open` flag so the window's ✕ works via
//! [`egui::Window::open`].
//! Pure rendering — the caller owns the `open` flag so each window's ✕ works
//! via [`egui::Window::open`].
use eframe::egui;
@@ -19,6 +20,369 @@ pub fn cheatsheet_window(ctx: &egui::Context, open: &mut bool) {
});
}
/// The User Guide window: what every window, menu item and setting does.
/// Complements the Markdown Cheatsheet, which covers syntax rather than
/// features.
pub fn user_guide_window(ctx: &egui::Context, open: &mut bool) {
egui::Window::new("📖 User Guide")
.open(open)
.resizable(true)
.default_width(640.0)
.default_height(620.0)
.show(ctx, |ui| {
egui::ScrollArea::vertical().show(ui, user_guide_body);
});
}
fn user_guide_body(ui: &mut egui::Ui) {
intro(
ui,
"What every window, menu item and setting does. For markdown and \
frontmatter syntax, see Help ▸ 📝 Markdown Cheatsheet instead.",
);
guide_getting_started(ui);
guide_organizing(ui);
guide_focus_and_pace(ui);
guide_planning_tools(ui);
guide_staying_on_track(ui);
guide_revision_and_safety(ui);
guide_exporting(ui);
guide_projects_and_templates(ui);
guide_proofing(ui);
guide_plot_beats(ui);
guide_settings_reference(ui);
}
fn guide_getting_started(ui: &mut egui::Ui) {
section(ui, "Getting started");
body(
ui,
"Set the Workspace path in the top bar (📂 to browse) and press Open — \
the folder is created if it doesn't exist. + New (type a name, \
optionally with folders like part-1/ch-01) or + New Scene creates a \
file; edit on the right and Ctrl+S (or Save) writes it to disk.",
);
note(
ui,
"Opening a folder that contains a 05-First Draft-style subfolder puts \
the app in Project mode: that subfolder's files are the book \
(ordered, numbered, exported); everything else — characters, \
outline, scratch pad — is reference material, reached through the \
Tools menu windows below rather than listed in the file panel. View \
▸ Show reference files lists it anyway, dimmed.",
);
body(
ui,
"File ▸ ⟳ Sync (git) commits everything, pulls --rebase, and pushes. \
Init git first if the workspace isn't a repository yet; Settings ▸ \
Git remote… attaches it to a server (and can create the repository \
on Gitea for you, given a server URL, user and token).",
);
}
fn guide_organizing(ui: &mut egui::Ui) {
section(ui, "Organizing the manuscript");
body(
ui,
"The file list is a tree: give a new file a path (part-2/ch-03) to \
nest it, and drag its ⠿ handle onto a folder — or among its files — \
to move it. Drop on “↥ drop here for the top level” to pull it back \
out. A folder exists only as long as it holds a file.",
);
note(
ui,
"Order is set by dragging and saved in order.json. A folder's files \
always stay together as a block, positioned by whichever of them \
sorts earliest — and the export is the tree read top to bottom, so \
this is also the chapter order.",
);
body(
ui,
"The Chapter title field overrides a file's auto-derived title (a \
Title: header field, or its position — “3.” — if there is none). \
Right-click a file for Rename…, Copy path, 🗄 Archive and 🗑 Delete….",
);
}
fn guide_focus_and_pace(ui: &mut egui::Ui) {
section(ui, "Focus & pace");
entries(
ui,
&[
(
"Ctrl/Cmd + D",
"Distraction-free: folds the toolbar and file list away, leaving \
the page. Again to bring them back.",
),
(
"View ▸ Typewriter scrolling & focus",
"While Distraction-free is on: keeps the caret's line centred \
and dims every paragraph but the current one.",
),
(
"Zoom / Contrast sliders",
"Above the editor — scale the editor text, or brighten it \
against the theme background.",
),
],
);
body(
ui,
"Tools ▸ ⏱ Sprint… tracks a daily whole-manuscript word goal \
(default 500, resets at the day boundary) with a progress bar, plus \
a start/stop Pomodoro-style sprint timer with a live words/minute \
readout. In Distraction-free mode, an active sprint's countdown \
also shows compactly in the status bar.",
);
note(
ui,
"The status bar's 🔥 N-day streak counts consecutive calendar days \
the manuscript's total word count grew — a day with no growth, or a \
skipped day, breaks it. It's recorded automatically on every save.",
);
}
fn guide_planning_tools(ui: &mut egui::Ui) {
section(ui, "Planning & reference");
body(
ui,
"These read a project's other parts — everything that isn't the \
draft itself.",
);
entries(
ui,
&[
(
"Tools ▸ ☑ Outline…",
"Reads the outline scaffold's HTML-comment beats and shows a \
progress bar per section, nested by heading. A beat with a \
matching chapter name gets a “→ open draft” link.",
),
(
"Tools ▸ 👥 Characters…",
"Every character sheet, which scenes they appear in (by \
matching Characters: fields), and ▦ Rebuild grid to \
regenerate character_grid.md.",
),
(
"Tools ▸ 📖 Story Bible…",
"Indexes character/location/lore sheets and auto-links \
mentions of them in the draft — no markup needed, though \
[[Name]] and @Name both work too. Hover a highlighted name \
for a summary card; click its window entries to jump to \
references.",
),
(
"Tools ▸ 📖 Story Bible editor…",
"A breakout window for editing Story Bible sheets directly: \
the full tree on the left, a text editor on the right. \
Saving refreshes the index automatically.",
),
(
"Tools ▸ 🗂 Corkboard…",
"One card per chapter — title and synopsis — drag to reorder \
the manuscript itself, the same reorder a file-panel drag \
does.",
),
(
"Tools ▸ 🧾 Synopsis…",
"Every chapter's Slug: line in one scrollable list, for \
scanning the whole manuscript's shape at a glance.",
),
(
"Snowflake progress",
"Collapsible strip at the top of the file panel: a ○/◐/● \
reading per snowflake-template stage folder, by word count. \
A nudge, not a gate — folders the current template doesn't \
have are simply left out.",
),
],
);
}
fn guide_staying_on_track(ui: &mut egui::Ui) {
section(ui, "Staying organized while drafting");
entries(
ui,
&[
(
"Tools ▸ 🔍 Placeholders…",
"Finds bracketed markers left mid-draft — [TODO], [TK], \
[FIXME], [XXX], [NOTE], [???] — grouped by file, click to \
jump to one.",
),
(
"Tools ▸ 📥 Quick note… (Ctrl+Shift+N)",
"A small popup for jotting a stray idea without losing your \
place — appended, timestamped, to Quick Notes.md in the \
project's Scratch Pad folder.",
),
(
"Misc Scenes",
"A dumping ground for scenes not yet placed (under \
05-First Draft in the bundled template) — visible, editable \
and word-counted like any other folder, but left out of \
every export. Configurable as export_exclude_folders in \
config.json.",
),
],
);
}
fn guide_revision_and_safety(ui: &mut egui::Ui) {
section(ui, "Revision & safety");
entries(
ui,
&[
(
"Edit ▸ 📸 Snapshots…",
"Automatic git commits at a configurable word-count interval \
(default every 250 words), plus a manual snapshot button and \
one-click rollback to any of them.",
),
(
"Edit ▸ ⇄ Changes since last commit…",
"Diffs the open file against its last committed version, \
coloured the way git colours a diff.",
),
(
"Edit ▸ 🔎 Search workspace… (Ctrl+Shift+F)",
"Find — and optionally replace — across every file in the \
workspace at once, not just the open one. A safety commit is \
made automatically before a workspace-wide replace.",
),
(
"Status: header field",
"Gives a file a badge in the file panel (initials, so \
“Structural Edit” shows as “SE”) and a Status filter above \
the list, to narrow it to one revision stage.",
),
(
"🗄 Archive",
"Moves a file into the project's archive folder (kept out of \
the file panel and the export) without deleting it — for \
material you've moved past, not material you want gone.",
),
],
);
}
fn guide_exporting(ui: &mut egui::Ui) {
section(ui, "Exporting");
body(
ui,
"File ▸ Export ODT concatenates every manuscript file into one \
document, each starting a new page, headed by its chapter title and \
optional Slug: caption. File ▸ Export chapters + master (.odm) \
instead writes one .odt per chapter plus a linking master — treat \
the master as a starting point to relink, not the assembled book.",
);
note(
ui,
"Settings ▸ Manuscript details…'s Standard manuscript format lays \
the export out the way a submission is expected to arrive (12pt \
Courier, double-spaced, page headers, chapters a third of the way \
down their page); Begin exports with a title page adds a title page \
in front, built from the title/author/contact fields there.",
);
body(
ui,
"Tick Screenplay (Fountain) in Manuscript details to make the \
project a screenplay instead: each file's body is read as Fountain, \
and Export ODT becomes Export PDF — a conventionally paginated \
screenplay, joined into one continuous script across files.",
);
}
fn guide_projects_and_templates(ui: &mut egui::Ui) {
section(ui, "Projects & templates");
body(
ui,
"File ▸ ✨ New project… scaffolds a whole project from a template \
(the bundled “snowflake” layout — premise, synopsis, story bible, \
outline, first draft, revisions, final — by default, compiled into \
the binary so nothing needs installing alongside it) and opens it \
straight into its drafting folder.",
);
note(
ui,
"Settings ▸ New-project settings… points Template at an external \
folder with its own cookiecutter.json to use instead — blank uses \
the bundled one, and a broken override falls back to it rather than \
failing project creation. Manuscript folder sets which project \
subfolder is the book (default 05-First Draft).",
);
body(
ui,
"Tick Publish to Gitea after creation there (with a server URL, user \
and token filled in) to have a new project pushed to a fresh Gitea \
repository automatically; Settings ▸ Git remote… does the same for \
a workspace you already have.",
);
}
fn guide_proofing(ui: &mut egui::Ui) {
section(ui, "Proofing");
body(
ui,
"Spelling is checked live, offline, as you type — no server, no \
network. Right-click an underlined word for corrections, or to add \
it to Settings ▸ Word list…, which also offers 👤 Add character \
names to pull in your whole cast at once. Canadian and British \
English are built in; pick one from the Spelling row's dropdown.",
);
note(
ui,
"Settings ▸ LanguageTool… connects a grammar-and-style server (a \
local instance keeps your manuscript off the network). Press ✓ \
Check to run it on the open file — its results take over the \
underlines until you next edit, then the offline spell checker \
resumes.",
);
}
fn guide_plot_beats(ui: &mut egui::Ui) {
section(ui, "Plot beats (Mistral)");
body(
ui,
"Tools ▸ ✨ Generate plot beats (Mistral)… turns a rough proposal \
file (characters, setting, a loose summary) into three-act plot \
beats, using the Mistral API. Set an API key first in Settings ▸ \
Mistral…. Results open in a window to edit, save as a new file, or \
copy.",
);
note(
ui,
"If the proposal's acts are already partly beaten out (three or more \
numbered beats under a heading counts as drafted), the generator \
writes only the missing acts instead of a whole sheet, treating the \
drafted ones as canon to work backwards from.",
);
}
fn guide_settings_reference(ui: &mut egui::Ui) {
section(ui, "Settings, at a glance");
entries(
ui,
&[
("LanguageTool…", "Grammar/spelling server connection (scheme, host, port, token, language)."),
("Mistral…", "API key, model and base URL for plot-beat generation."),
("New-file template…", "The frontmatter + New from template seeds a file with."),
("New-project settings…", "Template override, manuscript folder name, Gitea publishing defaults."),
("Git remote…", "Attach (or create on Gitea) the current workspace's remote."),
("Manuscript details…", "Title/author/contact, standard format, title page, screenplay toggle."),
("Spelling…", "The word list — names and invented terms the checker accepts."),
],
);
note(
ui,
"All settings live in ~/.config/md-manuscript/config.json and apply \
machine-wide; per-workspace data (order, titles, word list, word \
log) is committed alongside the manuscript in the workspace itself.",
);
}
fn cheatsheet_body(ui: &mut egui::Ui) {
intro(
ui,
@@ -235,3 +599,20 @@ fn syntax(ui: &mut egui::Ui, id: &str, rows: &[(&str, &str)]) {
}
});
}
/// A `label`/description list, stacked (label, then a wrapped paragraph)
/// rather than side by side — for descriptions too long to sit in
/// `syntax`'s two-column grid without either overflowing or forcing the
/// whole window wider to avoid wrapping, since a `Grid` sizes each column to
/// its widest cell instead of wrapping.
fn entries(ui: &mut egui::Ui, rows: &[(&str, &str)]) {
for (label, desc) in rows {
ui.label(
egui::RichText::new(*label)
.monospace()
.color(egui::Color32::from_rgb(120, 170, 120)),
);
ui.label(*desc);
ui.add_space(6.0);
}
}