From 68e058e07c2437678314c6fca1077e629a933fac Mon Sep 17 00:00:00 2001 From: narumincho <16481886+narumincho@users.noreply.github.com> Date: Sun, 1 Mar 2026 13:31:00 +0900 Subject: [PATCH 1/2] =?UTF-8?q?codex=20=E3=81=8C=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- definy-client/src/lib.rs | 1 + definy-event/src/event.rs | 2 ++ definy-server/src/main.rs | 1 + definy-ui/Cargo.toml | 1 + definy-ui/src/account_detail.rs | 9 +++++-- definy-ui/src/app_state.rs | 1 + definy-ui/src/event_detail.rs | 13 +++++++++ definy-ui/src/event_list.rs | 47 +++++++++++++++++++++++++++++++++ definy-ui/tests/browser_e2e.rs | 1 + narumincho-vdom/src/elements.rs | 16 +++++++++++ 10 files changed, 90 insertions(+), 2 deletions(-) diff --git a/definy-client/src/lib.rs b/definy-client/src/lib.rs index ff73d113..0c1a489b 100644 --- a/definy-client/src/lib.rs +++ b/definy-client/src/lib.rs @@ -71,6 +71,7 @@ impl narumincho_vdom_client::App for DefinyApp { created_account_events: ssr_events.unwrap_or_default(), current_key: None, part_name_input: String::new(), + part_description_input: String::new(), composing_expression: definy_event::event::Expression::Number(definy_event::event::NumberExpression { value: 0 }), part_definition_eval_result: None, event_detail_eval_result: None, diff --git a/definy-event/src/event.rs b/definy-event/src/event.rs index 3a7f8396..d5e1ecca 100644 --- a/definy-event/src/event.rs +++ b/definy-event/src/event.rs @@ -30,6 +30,8 @@ pub enum EventContent { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct PartDefinitionEvent { pub part_name: Box, + #[serde(default)] + pub description: Box, pub expression: Expression, } diff --git a/definy-server/src/main.rs b/definy-server/src/main.rs index 98ec3f52..ffba41f7 100644 --- a/definy-server/src/main.rs +++ b/definy-server/src/main.rs @@ -240,6 +240,7 @@ async fn handle_html( }, current_key: None, part_name_input: String::new(), + part_description_input: String::new(), composing_expression: definy_event::event::Expression::Number(definy_event::event::NumberExpression { value: 0 }), part_definition_eval_result: None, event_detail_eval_result: None, diff --git a/definy-ui/Cargo.toml b/definy-ui/Cargo.toml index a722d935..a52071a2 100644 --- a/definy-ui/Cargo.toml +++ b/definy-ui/Cargo.toml @@ -19,6 +19,7 @@ web-sys = { version = "0.3.85", features = [ "Event", "HtmlDialogElement", "HtmlInputElement", + "HtmlTextAreaElement", "Navigator", "Clipboard", "Request", diff --git a/definy-ui/src/account_detail.rs b/definy-ui/src/account_detail.rs index 772ca0eb..8d182c3f 100644 --- a/definy-ui/src/account_detail.rs +++ b/definy-ui/src/account_detail.rs @@ -142,9 +142,14 @@ fn event_summary(event: &definy_event::event::Event) -> String { format!("Profile changed: {}", change_profile_event.account_name) } EventContent::PartDefinition(part_definition_event) => format!( - "{} = {}", + "{} = {}{}", part_definition_event.part_name, - expression_to_source(&part_definition_event.expression) + expression_to_source(&part_definition_event.expression), + if part_definition_event.description.is_empty() { + String::new() + } else { + format!(" - {}", part_definition_event.description) + } ), } } diff --git a/definy-ui/src/app_state.rs b/definy-ui/src/app_state.rs index 692f3af1..755f50f8 100644 --- a/definy-ui/src/app_state.rs +++ b/definy-ui/src/app_state.rs @@ -10,6 +10,7 @@ pub struct AppState { )>, pub current_key: Option, pub part_name_input: String, + pub part_description_input: String, pub composing_expression: definy_event::event::Expression, pub part_definition_eval_result: Option, pub event_detail_eval_result: Option, diff --git a/definy-ui/src/event_detail.rs b/definy-ui/src/event_detail.rs index e6ba58a3..0f178fda 100644 --- a/definy-ui/src/event_detail.rs +++ b/definy-ui/src/event_detail.rs @@ -171,6 +171,19 @@ fn render_event_detail( part_definition_event.part_name, expression_to_source(&part_definition_event.expression) )), + if part_definition_event.description.is_empty() { + Div::new().children([]).into_node() + } else { + Div::new() + .style( + Style::new() + .set("font-size", "1rem") + .set("color", "var(--text-secondary)") + .set("white-space", "pre-wrap"), + ) + .children([text(part_definition_event.description.as_ref())]) + .into_node() + }, { let expression = part_definition_event.expression.clone(); Button::new() diff --git a/definy-ui/src/event_list.rs b/definy-ui/src/event_list.rs index acb9dc2d..7d509461 100644 --- a/definy-ui/src/event_list.rs +++ b/definy-ui/src/event_list.rs @@ -35,6 +35,7 @@ pub fn event_list_view(state: &AppState) -> Node { ) .children([ part_name_input(state), + part_description_input(state), Div::new() .style(Style::new().set("color", "var(--text-secondary)").set("font-size", "0.9rem")) .children([text("Expression Builder")]) @@ -87,6 +88,7 @@ pub fn event_list_view(state: &AppState) -> Node { }; let part_name = state.part_name_input.trim().to_string(); + let description = state.part_description_input.clone(); if part_name.is_empty() { return AppState { part_definition_eval_result: Some( @@ -109,6 +111,7 @@ pub fn event_list_view(state: &AppState) -> Node { definy_event::event::EventContent::PartDefinition( definy_event::event::PartDefinitionEvent { part_name: part_name.into(), + description: description.into(), expression, }, ), @@ -137,6 +140,7 @@ pub fn event_list_view(state: &AppState) -> Node { }); AppState { part_name_input: String::new(), + part_description_input: String::new(), part_definition_eval_result: None, composing_expression: definy_event::event::Expression::Number( @@ -495,6 +499,19 @@ fn event_view( part_definition_event.part_name, expression_to_source(&part_definition_event.expression) )), + if part_definition_event.description.is_empty() { + Div::new().children([]).into_node() + } else { + Div::new() + .style( + Style::new() + .set("font-size", "0.9rem") + .set("color", "var(--text-secondary)") + .set("white-space", "pre-wrap"), + ) + .children([text(part_definition_event.description.as_ref())]) + .into_node() + }, ]) .into_node(), }, @@ -542,6 +559,36 @@ fn part_name_input(state: &AppState) -> Node { input.into_node() } +fn part_description_input(state: &AppState) -> Node { + let mut textarea = Textarea::new() + .name("part-description") + .value(&state.part_description_input) + .style(Style::new().set("min-height", "6rem")); + textarea.attributes.push(( + "placeholder".to_string(), + "description (supports multiple lines)".to_string(), + )); + textarea.events.push(( + "input".to_string(), + EventHandler::new(move |set_state| async move { + let value = web_sys::window() + .and_then(|window| window.document()) + .and_then(|document| document.query_selector("textarea[name='part-description']").ok()) + .flatten() + .and_then(|element| { + wasm_bindgen::JsCast::dyn_into::(element).ok() + }) + .map(|textarea| textarea.value()) + .unwrap_or_default(); + set_state(Box::new(move |state: AppState| AppState { + part_description_input: value, + ..state.clone() + })); + }), + )); + textarea.into_node() +} + #[cfg(test)] mod tests { use super::{set_node_kind, set_number_value, NodeKind, PathStep}; diff --git a/definy-ui/tests/browser_e2e.rs b/definy-ui/tests/browser_e2e.rs index b5b30de2..1d122afe 100644 --- a/definy-ui/tests/browser_e2e.rs +++ b/definy-ui/tests/browser_e2e.rs @@ -313,6 +313,7 @@ fn render_html_response(path: &str) -> Response> { created_account_events: vec![], current_key: None, part_name_input: String::new(), + part_description_input: String::new(), composing_expression: definy_event::event::Expression::Number(definy_event::event::NumberExpression { value: 0 }), part_definition_eval_result: None, event_detail_eval_result: None, diff --git a/narumincho-vdom/src/elements.rs b/narumincho-vdom/src/elements.rs index 733e67ee..4be5186e 100644 --- a/narumincho-vdom/src/elements.rs +++ b/narumincho-vdom/src/elements.rs @@ -122,6 +122,11 @@ define_element!( "input", "https://developer.mozilla.org/docs/Web/HTML/Reference/Elements/input" ); +define_element!( + Textarea, + "textarea", + "https://developer.mozilla.org/docs/Web/HTML/Reference/Elements/textarea" +); define_element!( Label, "label", @@ -195,6 +200,17 @@ impl Input { } } +// Textarea specific +impl Textarea { + pub fn name(self, name: &str) -> Self { + self.attribute("name", name) + } + + pub fn value(self, value: &str) -> Self { + self.attribute("value", value) + } +} + impl Form { /// https://developer.mozilla.org/docs/Web/API/HTMLFormElement/submit_event pub fn on_submit(mut self, msg: EventHandler) -> Self { From 8232e8d102d07175031638bcc52bda9a02e3e607 Mon Sep 17 00:00:00 2001 From: narumincho <16481886+narumincho@users.noreply.github.com> Date: Sun, 1 Mar 2026 13:31:34 +0900 Subject: [PATCH 2/2] fix lint error --- narumincho-vdom-client/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/narumincho-vdom-client/src/lib.rs b/narumincho-vdom-client/src/lib.rs index 3e8f2be9..ce1f8d3c 100644 --- a/narumincho-vdom-client/src/lib.rs +++ b/narumincho-vdom-client/src/lib.rs @@ -125,7 +125,7 @@ pub fn start>() { Reflect::get(&event, &JsValue::from_str("canIntercept")) { if can_intercept.is_truthy() { - if let Ok(user_initiated) = + if let Ok(_user_initiated) = Reflect::get(&event, &JsValue::from_str("userInitiated")) { // Only intercept if it was a user click (not script navigation, etc) if we want