From f35397b49b158b9698756b3617629b6c945763e7 Mon Sep 17 00:00:00 2001 From: landon Date: Tue, 25 Aug 2026 17:58:59 -0500 Subject: [PATCH] Add title pages, standard manuscript format and collapsible panels Five changes to the export and the window chrome: * Manuscript details gains a contact field and a "Begin exports with a title page" option: the title, the author beneath it, and the contact details beneath that, laid out line for line as typed. A chapters + master export puts the title page on the master, not on each chapter. * "Standard manuscript format" lays an export out the way an agent or an editor expects a submission: 12pt Courier, double-spaced, half-inch first-line indents, a Surname / Title / page header on every page but the title page, chapters opening a third of the way down, and `---` rendered as the conventional centred `#` scene break. The title page becomes the submission kind, with contact top-left and an approximate word count top-right. Off by default; margins were already the standard 1in on US Letter and are unchanged either way. * A folder button beside Export ODT opens the project folder in the file manager -- the enclosing git work tree, including one still awaiting confirmation, since showing a folder is a smaller question than choosing which repository to commit to. * The toolbar and the file list each collapse, from the pair of buttons at the right of the menu bar or from the View menu, and Ctrl+D folds both away together for distraction-free writing. Both choices persist. * The editor sizes to its viewport instead of a fixed 30 rows, so the height a folded panel gives back reaches the page rather than leaving grey space below the text box that did not even take focus. Two traps worth recording. ODF's style:master-page-name is inherited, and any paragraph style carrying one forces a page break before every paragraph that uses it -- a four-line contact block came out as four pages until Contact_20_Line stopped inheriting from Contact_20_Block; a test now pins which styles may carry one. And the status bar shares a function with the toolbar, so guarding that function's top rather than the top panel alone silently took the word counts away with it. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GYSGPDwkSzhm4qLqjCbqxU --- README.md | 66 +++- src/app/editor.rs | 11 +- src/app/file_list.rs | 7 +- src/app/mod.rs | 5 + src/app/project.rs | 47 ++- src/app/ui.rs | 89 +++++- src/app/workspace.rs | 105 ++++++- src/config.rs | 35 +++ src/odt.rs | 731 ++++++++++++++++++++++++++++++++++++++++--- 9 files changed, 1038 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index b61be5f..9c5a457 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,29 @@ so a defaulted title in `part-2/` continues counting from `part-1/`. A manuscript project is more than its chapters. These read the rest of it. +### Distraction-free writing (Ctrl+D) + +**Ctrl+D** folds away everything that is not the page β€” the toolbar and the file +list together β€” leaving the menu bar, the editor and the status line. Press it +again to bring both back. It is also **View β–Έ πŸ–Ή Distraction-free**. + +The two panels toggle separately as well, from the pair of buttons at the right +of the menu bar or from **View β–Έ Toolbar** and **View β–Έ File list**: + +| | Hides | Gives back | +|---|---|---| +| **⬆** / **⬇** | the Workspace, Export, Grammar and Spelling rows | about an inch of height | +| **β¬…** / **➑** | the file list down the left | about 260px of width | + +Both choices are remembered between runs, so the window opens the way you left +it. The toggles live in the menu bar rather than in the panels they hide, since +a control that hides a panel cannot sit inside it, and the menu bar is the one +strip that never goes away. The status bar is unaffected β€” the word counts stay +visible while you write. + +The editor grows into whatever the panels give back rather than staying a fixed +height, so folding them is worth real writing space and not just grey margin. + ### Hiding the header while you write A scene card's fields sit at the top of the same file as its prose, and once @@ -306,9 +329,42 @@ the **whole manuscript's total**. Reference files are not counted. ### Manuscript details (Settings β–Έ Manuscript details…) -Title and author, written into exported `.odt` files as their document -properties β€” what a word processor shows under File β–Έ Properties. A blank title -uses the project folder's name. Exports previously carried no metadata at all. +Title, author and contact details. The title and author are written into +exported `.odt` files as their document properties β€” what a word processor shows +under File β–Έ Properties. A blank title uses the project folder's name. Exports +previously carried no metadata at all. + +**Standard manuscript format** lays the export out the way an agent or an editor +expects a submission to arrive, which is not a matter of taste: a monospaced, +double-spaced page is a predictable ~250 words, and the margins leave somewhere +for their notes to go. Turning it on gives you + +- 12pt Courier (readers substitute a metric-compatible font where it is absent), + double-spaced, with half-inch first-line indents and no blank line between + paragraphs β€” a blank line would read as a scene break; +- `Surname / Title / page` flush right on every page but the title page, with + the numbering starting at 1 on the first page of text; +- chapters opening about a third of the way down their page; +- `---` in your markdown rendered as the conventional centred `#` scene break; +- a submission title page: contact details in the top-left corner, an + approximate word count opposite them in the top-right, and the title a third + of the way down with the byline beneath it. + +Margins are 1 inch on all four sides of US Letter either way β€” that part was +already standard before the option existed. + +**Begin exports with a title page** puts a page of its own at the front of every +export: the title, the author beneath it, and the contact details beneath that, +with the first chapter starting on the page after (in standard manuscript +format it takes the submission layout described above instead). The contact box +is free-form +and laid out line for line as typed, so an address, an email and a phone number +each land where you put them β€” including the blank line you leave between them. +The option is off by default, and an export with nothing to put on the page +skips it rather than opening on a blank sheet. + +For a chapters-plus-master export the title page goes on the master, not on each +chapter file. ### Exporting chapter files (File β–Έ Export chapters + master) @@ -316,8 +372,8 @@ Writes one `.odt` per chapter into a `chapters/` folder, plus an `.odm` master document that links them β€” the shape the template's `Full Text.odm` implies. **The per-chapter files are the reliable part**: they are ordinary documents and -open anywhere. The master is a shell with a title page and one linked section -per chapter; LibreOffice does not follow those links when it opens the file, so +open anywhere. The master is a shell with the title, the author (or the full +title page, if you asked for one) and one linked section per chapter; LibreOffice does not follow those links when it opens the file, so treat it as a starting point to relink rather than as the assembled book. For a single finished document, use **Export ODT**. diff --git a/src/app/editor.rs b/src/app/editor.rs index ded0ee9..8b426e4 100644 --- a/src/app/editor.rs +++ b/src/app/editor.rs @@ -82,11 +82,20 @@ impl App { self.apply_field_completion(ui.ctx(), &field); } + // Fill the viewport rather than a fixed number of rows, so the + // height handed back by a folded toolbar or file list reaches + // the page instead of leaving grey space under the editor. + // Measured against the *unzoomed* row height because that is + // what `desired_rows` is multiplied by, whatever the layouter + // then draws at. + let row_h = ui.text_style_height(&egui::TextStyle::Monospace).max(1.0); + let rows = (ui.available_height() / row_h).floor().max(10.0) as usize; + let output = egui::TextEdit::multiline(&mut self.buffer) .id(egui::Id::new(EDITOR_ID)) .code_editor() .desired_width(f32::INFINITY) - .desired_rows(30) + .desired_rows(rows) .layouter(&mut layouter) .show(ui); if output.response.changed() { diff --git a/src/app/file_list.rs b/src/app/file_list.rs index ee8ba54..4e3664a 100644 --- a/src/app/file_list.rs +++ b/src/app/file_list.rs @@ -105,7 +105,12 @@ pub(super) fn build_rows(files: &[String], collapsed: &HashSet) -> Vec