From 1cd560d954603b17266e592c9c0bfc654058ee65 Mon Sep 17 00:00:00 2001 From: landon Date: Wed, 30 Sep 2026 17:48:03 -0500 Subject: [PATCH] help documentation --- src/app/mod.rs | 6 + src/app/ui.rs | 4 + src/help.rs | 391 ++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 396 insertions(+), 5 deletions(-) diff --git a/src/app/mod.rs b/src/app/mod.rs index 7ef1487..0f879bf 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -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); diff --git a/src/app/ui.rs b/src/app/ui.rs index 24a6db5..e1227a5 100644 --- a/src/app/ui.rs +++ b/src/app/ui.rs @@ -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; diff --git a/src/help.rs b/src/help.rs index 541a9ea..f3d8c60 100644 --- a/src/help.rs +++ b/src/help.rs @@ -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); + } +}