Files
ElyOffice/apps/ely-doc/src/actions.rs
T
ZacharyZhang-NY b7fca0146d Ely Office: six offline-first desktop apps in Rust and GPUI
ElyDoc, ElyTable, ElyShow (LibreOfficeKit), ElyPDF (MuPDF), ElyTree (Git),
ElyMark (Milkdown and CodeMirror in CEF). ElyMail and ElyAgent follow.
2026-10-08 21:20:08 -04:00

137 lines
4.2 KiB
Rust

//! New, and ElyDoc's own dialogs (DOC-01).
use std::rc::Rc;
use ely_gpui_component::{
buttons::Button,
documents::{Template as Pick, TemplatePicker},
forms::TextInput,
overlays::Dialog as Card,
};
use ely_office::prelude::*;
use ely_ui::commands::New;
use gpui::{AnyElement, App, Context, Entity, IntoElement, ParentElement as _, Window};
use crate::docs::Docs;
use crate::files::TEMPLATES;
use crate::refs::Ask;
pub enum Dialog {
Templates,
Table {
columns: f64,
rows: f64,
},
Section,
Ask {
ask: Ask,
field: Entity<TextInput>,
},
Link {
text: Entity<TextInput>,
url: Entity<TextInput>,
},
Reference {
marks: Vec<String>,
mark: String,
show: &'static str,
},
Output {
tab: u64,
print: bool,
all: bool,
pdf: ely_lok::Pdf,
},
}
impl Docs {
pub fn on_new(&mut self, _: &New, _: &mut Window, cx: &mut Context<Self>) {
self.dialog = Some(Dialog::Templates);
cx.notify();
}
/// The open dialog, if any.
pub fn dialog_element(&mut self, _: &mut Window, cx: &mut Context<Self>) -> Option<AnyElement> {
let this = cx.entity();
let dismiss = {
let this = this.clone();
move |_: &mut Window, cx: &mut App| {
this.update(cx, |docs, cx| {
docs.dialog = None;
cx.notify();
})
}
};
let card = match self.dialog.as_ref()? {
Dialog::Templates => templates(this, dismiss, cx),
Dialog::Section => {
return Some(crate::insert::section_dialog(this, dismiss, cx).into_any_element());
}
Dialog::Ask { ask, field } => {
let prompt = crate::refs::ask_dialog(this, ask, field, dismiss, cx);
return Some(prompt.into_any_element());
}
Dialog::Link { text, url } => crate::refs::link_dialog(this, (text, url), dismiss, cx),
Dialog::Reference { marks, mark, show } => {
crate::refs::reference_dialog(this, (marks, mark, show), dismiss, cx)
}
Dialog::Output {
tab,
print,
all,
pdf,
} => {
let last = self
.tab(*tab)
.expect("a modal keeps its tab")
.view
.read(cx)
.pages()
.len();
let last = u32::try_from(last).expect("a page count");
crate::output::output_dialog(this, (*print, *all, *pdf, last), dismiss, cx)
}
Dialog::Table { columns, rows } => {
crate::insert::table_dialog(this, (*columns, *rows), dismiss, cx)
}
};
Some(card.into_any_element())
}
}
/// The New dialog: bundled templates and a local file (DOC-01).
fn templates(
this: Entity<Docs>,
dismiss: impl Fn(&mut Window, &mut App) + 'static,
cx: &mut Context<Docs>,
) -> Card {
let picks: Vec<Pick> = TEMPLATES
.iter()
.map(|template| Pick {
name: Docs::text(cx, &format!("doc.template.{}", template.key()), &[]),
icon: "▤".into(),
category: Docs::text(cx, "doc.template.category", &[]),
description: Docs::text(cx, &format!("doc.template.{}.about", template.key()), &[]),
markdown: template.preview(cx).into(),
})
.collect();
let used = this.clone();
let picker = TemplatePicker::new("doc-templates", Rc::new(picks)).on_use(move |ix, _, cx| {
used.update(cx, |docs, cx| {
docs.dialog = None;
docs.new_from(TEMPLATES[ix], cx);
})
});
let label = Docs::text(cx, "doc.new.from_file", &[]);
Card::new("doc-new", Docs::text(cx, "doc.new.title", &[]), dismiss)
.child(picker)
.action(move |close| {
Button::new("doc-new-file", label).on_click(move |_, window, cx| {
close(window, cx);
this.update(cx, |docs, cx| {
docs.pick(false, cx, |docs, path, cx| docs.new_from_file(&path, cx))
});
})
})
}