diff --git a/typhon-webapp/src/editable_text.rs b/typhon-webapp/src/editable_text.rs new file mode 100644 index 00000000..a3db6b28 --- /dev/null +++ b/typhon-webapp/src/editable_text.rs @@ -0,0 +1,113 @@ +use seed::{prelude::*, *}; + +#[derive(Clone)] +enum State { + Read, + Edit(String), + Sync(String), +} + +pub struct Model { + pub text: String, + state: State, +} + +#[derive(Clone, Debug)] +pub enum Msg { + Update(String), + Send, + Edit, + Synchronized, +} + +#[derive(Clone)] +pub enum OutMsg { + NewValue(String), +} + +pub fn value_synchronized() -> Msg { + Msg::Synchronized +} + +pub fn init(text: String) -> Model { + Model { + state: State::Read, + text, + } +} + +pub fn update(msg: Msg, model: &mut Model) -> Option { + match (msg, &mut *model) { + ( + Msg::Update(text), + Model { + state: State::Edit(_), + .. + }, + ) => { + model.state = State::Edit(text); + None + } + ( + Msg::Send, + Model { + state: State::Edit(text), + .. + }, + ) => { + let text = text.clone(); + model.state = State::Sync(text.clone()); + Some(OutMsg::NewValue(text)) + } + (Msg::Edit, _) => { + model.state = State::Edit(model.text.clone()); + None + } + ( + Msg::Synchronized, + Model { + state: State::Sync(text), + .. + }, + ) => { + model.text = text.clone(); + model.state = State::Read; + None + } + _ => None, + } +} + +pub fn view(model: &Model, wrap: Box Node>) -> Node { + match &model.state { + State::Read => div![ + wrap(model.text.clone()), + i![C!["ri-pencil-line"], ev(Ev::Click, |_| Msg::Edit)], + C!["editable-text", "read"], + if model.text.trim().is_empty() { + vec![C!["empty"]] + } else { + vec![] + } + ], + State::Edit(text) => div![ + input![ + attrs! {At::Value => text}, + input_ev(Ev::Input, Msg::Update), + keyboard_ev(Ev::KeyUp, |e| { + if e.key() == "Enter" { + Some(Msg::Send) + } else { + None + } + }) + ], + i![C!["ri-check-line"], ev(Ev::Click, |_| Msg::Send)], + C!["editable-text", "edit"] + ], + State::Sync(text) => div![ + input![attrs! {At::Value => text, At::Disabled => true}], + C!["editable-text", "sync"] + ], + } +} diff --git a/typhon-webapp/src/lib.rs b/typhon-webapp/src/lib.rs index d8f9d8a6..8bf1a400 100644 --- a/typhon-webapp/src/lib.rs +++ b/typhon-webapp/src/lib.rs @@ -1,5 +1,6 @@ mod appurl; mod build; +mod editable_text; mod evaluation; mod home; mod job; diff --git a/typhon-webapp/src/project.rs b/typhon-webapp/src/project.rs index 4f7186d6..f56a92fe 100644 --- a/typhon-webapp/src/project.rs +++ b/typhon-webapp/src/project.rs @@ -1,122 +1,9 @@ +use crate::editable_text; use crate::{appurl::AppUrl, perform_request, view_error, Urls}; -use seed::{prelude::*, *}; -use typhon_types::*; - -mod editable_text { - use seed::{prelude::*, *}; - - #[derive(Clone)] - enum State { - Read, - Edit(String), - Sync(String), - } - - pub struct Model { - pub text: String, - state: State, - } - - #[derive(Clone, Debug)] - pub enum Msg { - Update(String), - Send, - Edit, - Synchronized, - } - #[derive(Clone)] - pub enum OutMsg { - NewValue(String), - } - - pub fn value_synchronized() -> Msg { - Msg::Synchronized - } - - pub fn init(text: String) -> Model { - Model { - state: State::Read, - text, - } - } - - pub fn update(msg: Msg, model: &mut Model) -> Option { - match (msg, &mut *model) { - ( - Msg::Update(text), - Model { - state: State::Edit(_), - .. - }, - ) => { - model.state = State::Edit(text); - None - } - ( - Msg::Send, - Model { - state: State::Edit(text), - .. - }, - ) => { - let text = text.clone(); - model.state = State::Sync(text.clone()); - Some(OutMsg::NewValue(text)) - } - (Msg::Edit, _) => { - model.state = State::Edit(model.text.clone()); - None - } - ( - Msg::Synchronized, - Model { - state: State::Sync(text), - .. - }, - ) => { - model.text = text.clone(); - model.state = State::Read; - None - } - _ => None, - } - } +use seed::{prelude::*, *}; - pub fn view(model: &Model, wrap: Box Node>) -> Node { - match &model.state { - State::Read => div![ - wrap(model.text.clone()), - i![C!["ri-pencil-line"], ev(Ev::Click, |_| Msg::Edit)], - C!["editable-text", "read"], - if model.text.trim().is_empty() { - vec![C!["empty"]] - } else { - vec![] - } - ], - State::Edit(text) => div![ - input![ - attrs! {At::Value => text}, - input_ev(Ev::Input, Msg::Update), - keyboard_ev(Ev::KeyUp, |e| { - if e.key() == "Enter" { - Some(Msg::Send) - } else { - None - } - }) - ], - i![C!["ri-check-line"], ev(Ev::Click, |_| Msg::Send)], - C!["editable-text", "edit"] - ], - State::Sync(text) => div![ - input![attrs! {At::Value => text, At::Disabled => true}], - C!["editable-text", "sync"] - ], - } - } -} +use typhon_types::*; pub struct Model { error: Option,