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) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GYSGPDwkSzhm4qLqjCbqxU
This commit is contained in:
+88
-1
@@ -6,8 +6,15 @@ use super::*;
|
||||
impl App {
|
||||
// ---- UI ----------------------------------------------------------------
|
||||
|
||||
/// The toolbar — the Workspace, Export, Grammar and Spelling rows — and the
|
||||
/// status bar along the bottom, which is rendered here too.
|
||||
///
|
||||
/// The toolbar collapses through `show_animated`, which reserves no height
|
||||
/// when hidden and slides rather than snapping. Note that it guards only the
|
||||
/// top panel: the status bar shares this function and must keep drawing.
|
||||
pub(super) fn top_bar(&mut self, ctx: &egui::Context) {
|
||||
egui::TopBottomPanel::top("top").show(ctx, |ui| {
|
||||
let show_toolbar = self.config.show_toolbar;
|
||||
egui::TopBottomPanel::top("top").show_animated(ctx, show_toolbar, |ui| {
|
||||
ui.add_space(4.0);
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Workspace:");
|
||||
@@ -56,6 +63,16 @@ impl App {
|
||||
if ui.button("Export ODT").clicked() {
|
||||
self.export_odt();
|
||||
}
|
||||
// Resolved first: the hover text borrows the path, and the click
|
||||
// handler needs `self` mutably.
|
||||
let project = self.project_root().display().to_string();
|
||||
if ui
|
||||
.button("📁")
|
||||
.on_hover_text(format!("Open the project folder {project}"))
|
||||
.clicked()
|
||||
{
|
||||
self.open_project_folder();
|
||||
}
|
||||
ui.separator();
|
||||
if ui
|
||||
.checkbox(&mut self.config.show_preview, "Preview")
|
||||
@@ -310,6 +327,35 @@ impl App {
|
||||
}
|
||||
});
|
||||
ui.menu_button("View", |ui| {
|
||||
if ui
|
||||
.checkbox(&mut self.config.show_toolbar, "Toolbar")
|
||||
.on_hover_text(
|
||||
"The Workspace, Export, Grammar and Spelling rows \
|
||||
under the menu bar",
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
self.config.save();
|
||||
}
|
||||
if ui
|
||||
.checkbox(&mut self.config.show_file_panel, "File list")
|
||||
.on_hover_text("The file tree down the left-hand side")
|
||||
.clicked()
|
||||
{
|
||||
self.config.save();
|
||||
}
|
||||
if ui
|
||||
.button("🖹 Distraction-free Ctrl+D")
|
||||
.on_hover_text(
|
||||
"Fold away the toolbar and the file list together, \
|
||||
leaving nothing but the page. Again to bring them back.",
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
ui.close_menu();
|
||||
self.toggle_distraction_free();
|
||||
}
|
||||
ui.separator();
|
||||
if ui
|
||||
.checkbox(&mut self.config.show_preview, "Preview pane")
|
||||
.clicked()
|
||||
@@ -375,6 +421,30 @@ impl App {
|
||||
self.show_cheatsheet = true;
|
||||
}
|
||||
});
|
||||
// Right-aligned, and in the menu bar rather than the toolbar:
|
||||
// a control that hides the toolbar cannot live inside it.
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
let (icon, hint) = if self.config.show_toolbar {
|
||||
("⬆", "Hide the toolbar (Workspace, Export, Grammar, Spelling)")
|
||||
} else {
|
||||
("⬇", "Show the toolbar (Workspace, Export, Grammar, Spelling)")
|
||||
};
|
||||
if ui.button(icon).on_hover_text(hint).clicked() {
|
||||
self.config.show_toolbar = !self.config.show_toolbar;
|
||||
self.config.save();
|
||||
}
|
||||
// Added second, so in a right-to-left layout it sits to the
|
||||
// left of the toolbar toggle -- the side its panel is on.
|
||||
let (icon, hint) = if self.config.show_file_panel {
|
||||
("⬅", "Hide the file list")
|
||||
} else {
|
||||
("➡", "Show the file list")
|
||||
};
|
||||
if ui.button(icon).on_hover_text(hint).clicked() {
|
||||
self.config.show_file_panel = !self.config.show_file_panel;
|
||||
self.config.save();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -535,6 +605,23 @@ impl App {
|
||||
/// It exists so a hidden header can never be mistaken for a file that has
|
||||
/// none: the editor is showing less than the file holds, and that has to be
|
||||
/// visible without opening a menu.
|
||||
/// Fold away everything that is not the page — the toolbar and the file
|
||||
/// list — and put both back on the next invocation.
|
||||
///
|
||||
/// One command in and out, rather than a mode with a state of its own: if
|
||||
/// any chrome is showing, hide it all; otherwise restore it all.
|
||||
pub(super) fn toggle_distraction_free(&mut self) {
|
||||
let any_chrome = self.config.show_toolbar || self.config.show_file_panel;
|
||||
self.config.show_toolbar = !any_chrome;
|
||||
self.config.show_file_panel = !any_chrome;
|
||||
self.config.save();
|
||||
self.status = if any_chrome {
|
||||
"Distraction-free — Ctrl+D to bring the panels back".to_string()
|
||||
} else {
|
||||
"Panels restored".to_string()
|
||||
};
|
||||
}
|
||||
|
||||
pub(super) fn header_toggle(&mut self, ui: &mut egui::Ui) {
|
||||
let collapsed = self.header_stash.is_some();
|
||||
// Nothing to say about a file with no marker to fold at.
|
||||
|
||||
Reference in New Issue
Block a user