diff --git a/crates/aceditor/src/lib.rs b/crates/aceditor/src/lib.rs index 70ade67..88cf2e6 100644 --- a/crates/aceditor/src/lib.rs +++ b/crates/aceditor/src/lib.rs @@ -36,6 +36,9 @@ mod bindgen { #[wasm_bindgen(method, js_name = getValue)] pub fn get_value(this: &Editor) -> String; + + #[wasm_bindgen(method, js_name = getSelectedText)] + pub fn get_selected_text(this: &Editor) -> String; } } @@ -171,4 +174,8 @@ impl Editor { pub fn get_value(&self) -> String { self.js.get_value() } + + pub fn get_selected_value(&self) -> String { + self.js.get_selected_text() + } } diff --git a/src/app/advanced_options_menu.rs b/src/app/advanced_options_menu.rs new file mode 100644 index 0000000..528ec26 --- /dev/null +++ b/src/app/advanced_options_menu.rs @@ -0,0 +1,35 @@ +use leptos::prelude::*; +use reactive_stores::Store; + +use crate::app::{ + GlobalState, GlobalStateStoreFields, config_element::Either, menu_group::MenuGroup, +}; + +#[component] +pub fn AdvancedOptionsMenu() -> impl IntoView { + let state = expect_context::>(); + + let value = move || *state.run_selected_code().read(); + let is_default = move || !*state.run_selected_code().read(); + let on_change = move |value: &bool| { + state.run_selected_code().set(*value); + }; + + view! { + <> + + + + + } +} diff --git a/src/app/button_set.rs b/src/app/button_set.rs index 48a6c76..e7d3bb9 100644 --- a/src/app/button_set.rs +++ b/src/app/button_set.rs @@ -66,3 +66,22 @@ where pub fn Rule() -> impl IntoView { view! { } } + +#[component] +pub fn IconButton( + #[prop(default = false)] is_small: bool, + #[prop(optional)] node_ref: NodeRef, + on_click: C, + children: Children, +) -> impl IntoView +where + C: FnMut(MouseEvent) + Send + 'static, +{ + let style = if is_small { styles::small } else { "" }; + let style = format!("{} {style}", styles::icon); + view! { + + } +} diff --git a/src/app/config_element.rs b/src/app/config_element.rs index ff31545..ab628fd 100644 --- a/src/app/config_element.rs +++ b/src/app/config_element.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use istyles::istyles; use leptos::prelude::*; use web_sys::Event; @@ -9,11 +11,83 @@ istyles!( "assets/module.postcss/config_element.module.css.map" ); +#[component] +pub fn Either( + on_change: E, + id: String, + a: T, + b: T, + a_label: Option, + b_label: Option, + value: V, + name: String, + #[prop(default = Box::new(|| true))] is_default: Box bool + Send>, +) -> impl IntoView +where + E: Fn(&T) + Send + Sync + 'static, + V: Fn() -> T + Send + Sync + 'static, + T: PartialEq + Eq + Send + Sync + ToString + 'static, +{ + let a_label = if let Some(label) = a_label { + label + } else { + a.to_string() + }; + + let b_label = if let Some(label) = b_label { + label + } else { + b.to_string() + }; + + let a_id = format!("{id}-a"); + let b_id = format!("{id}-b"); + + let on_change1 = Arc::new(on_change); + let on_change2 = Arc::clone(&on_change1); + + let value1 = Arc::new(value); + let value2 = Arc::clone(&value1); + + let a_value = a.to_string(); + let b_value = b.to_string(); + + let a1 = Arc::new(a); + let a2 = Arc::clone(&a1); + let b1 = Arc::new(b); + let b2 = Arc::clone(&b1); + + view! { + +
+ + + + +
+
+ } +} + #[component] pub fn Select( on_change: E, name: String, - #[prop(default = true)] is_default: bool, + #[prop(default = Box::new(|| true))] is_default: Box bool + Send>, children: Children, ) -> impl IntoView where @@ -31,13 +105,15 @@ where #[component] pub fn ConfigElement( name: String, - #[prop(default = true)] is_default: bool, + #[prop(default = Box::new(|| true))] is_default: Box bool + Send>, children: Children, ) -> impl IntoView { - let style = if is_default { - styles::name - } else { - styles::notDefault + let style = move || { + if is_default() { + styles::name + } else { + styles::notDefault + } }; view! { diff --git a/src/app/header.rs b/src/app/header.rs index a7f1c7f..66dd598 100644 --- a/src/app/header.rs +++ b/src/app/header.rs @@ -6,10 +6,11 @@ use web_sys::{Url, UrlSearchParams}; use crate::{ PrepareOptions, WorkerRequest, app::{ - button_set::{Button, ButtonSet, Rule}, + advanced_options_menu::AdvancedOptionsMenu, + button_set::{Button, ButtonSet, IconButton, Rule}, config_menu::ConfigMenu, context_menu::ContextMenu, - icon::{build_icon, config_icon, expandable_icon}, + icon::{build_icon, config_icon, expandable_icon, more_options_icon}, output::change_focus, pop_button::PopButton, state::{Focus, GlobalState, GlobalStateStoreFields}, @@ -35,6 +36,8 @@ pub fn Header() -> impl IntoView { + +
@@ -53,21 +56,29 @@ pub fn Header() -> impl IntoView { pub fn execute(state: Store) -> Box { Box::new(move || { - let Some(code) = state + let Some((code, selected_code)) = state .editor() .read_untracked() .as_ref() - .map(|editor| editor.get_value()) + .map(|editor| (editor.get_value(), editor.get_selected_value())) else { return; }; + + let run_selected_code = state.run_selected_code().get(); + state.code().set(code.clone()); change_focus(state, Some(Focus::Execute)); std::mem::take(&mut *state.output().write()); + if let Some(worker) = &*state.worker().read_untracked() { worker.send_task(WorkerRequest::Prepare(PrepareOptions { id: String::new(), - sql: code, + sql: if !selected_code.is_empty() && run_selected_code { + selected_code + } else { + code + }, clear_on_prepare: !*state.keep_ctx().read_untracked(), })); worker.send_task(WorkerRequest::Continue(String::new())); @@ -157,6 +168,26 @@ fn ConfigMenuButton(menu_container: NodeRef) -> impl IntoVie } } +#[component] +fn AdvancedOptionsMenuButton(menu_container: NodeRef) -> impl IntoView { + let button = |toggle, node_ref| { + view! { + + {more_options_icon()} + + } + .into_any() + }; + + view! { + }.into_any() }) + menu_container=menu_container + > + } +} + #[component] fn ShareButton() -> impl IntoView { let state = expect_context::>(); diff --git a/src/app/icon.rs b/src/app/icon.rs index 8cd70c6..4c2fb47 100644 --- a/src/app/icon.rs +++ b/src/app/icon.rs @@ -79,3 +79,17 @@ pub fn clipboard_icon() -> AnyView { }.into_any() } + +pub fn more_options_icon() -> AnyView { + view! { + + + + }.into_any() +} diff --git a/src/app/mod.rs b/src/app/mod.rs index 67f6da7..1b24d4e 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,3 +1,4 @@ +mod advanced_options_menu; mod button_set; mod config_element; mod config_menu; diff --git a/src/app/playground.rs b/src/app/playground.rs index 61f3e5e..88a9b3d 100644 --- a/src/app/playground.rs +++ b/src/app/playground.rs @@ -58,6 +58,7 @@ fn hanlde_save_state(state: Store) { state.theme().track(); state.keep_ctx().track(); state.code().track(); + state.run_selected_code().track(); state.read_untracked().save(); }); diff --git a/src/app/state.rs b/src/app/state.rs index 8e6ee38..1efb798 100644 --- a/src/app/state.rs +++ b/src/app/state.rs @@ -18,6 +18,7 @@ pub struct GlobalState { theme: Theme, keep_ctx: bool, code: String, + run_selected_code: bool, // runtime state below #[serde(skip)] worker: Option, @@ -57,6 +58,7 @@ impl Default for GlobalState { worker: None, editor: None, last_error: None, + run_selected_code: false, } } }