Clean up a number of examples

This commit is contained in:
Jonathan Kelley committed 2024-01-15 13:06:05 -08:00
1 parent f2caa3a3ad
commit 6134a2ce24
30 files changed
+284 -413

No files matched your search

+10 -10
View File
@@ -26,15 +26,15 @@ fn app() -> Element {
val.set(String::new()); val.set(String::new());
} }
val.make_mut().push_str(num.to_string().as_str()); val.write().push_str(num.to_string().as_str());
}; };
let input_operator = move |key: &str| val.make_mut().push_str(key); let input_operator = move |key: &str| val.write().push_str(key);
let handle_key_down_event = move |evt: KeyboardEvent| match evt.key() { let handle_key_down_event = move |evt: KeyboardEvent| match evt.key() {
Key::Backspace => { Key::Backspace => {
if !val.len() != 0 { if !val().is_empty() {
val.make_mut().pop(); val.write().pop();
} }
} }
Key::Character(character) => match character.as_str() { Key::Character(character) => match character.as_str() {
@@ -72,16 +72,16 @@ fn app() -> Element {
class: "calculator-key key-clear", class: "calculator-key key-clear",
onclick: move |_| { onclick: move |_| {
val.set(String::new()); val.set(String::new());
if !val.is_empty(){ if !val().is_empty(){
val.set("0".into()); val.set("0".into());
} }
}, },
if val.is_empty() { "C" } else { "AC" } if val().is_empty() { "C" } else { "AC" }
} }
button { button {
class: "calculator-key key-sign", class: "calculator-key key-sign",
onclick: move |_| { onclick: move |_| {
let temp = calc_val(val.as_str()); let temp = calc_val(val().as_str());
if temp > 0.0 { if temp > 0.0 {
val.set(format!("-{temp}")); val.set(format!("-{temp}"));
} else { } else {
@@ -94,7 +94,7 @@ fn app() -> Element {
class: "calculator-key key-percent", class: "calculator-key key-percent",
onclick: move |_| { onclick: move |_| {
val.set( val.set(
format!("{}", calc_val(val.as_str()) / 100.0) format!("{}", calc_val(val().as_str()) / 100.0)
); );
}, },
"%" "%"
@@ -102,7 +102,7 @@ fn app() -> Element {
} }
div { class: "digit-keys", div { class: "digit-keys",
button { class: "calculator-key key-0", onclick: move |_| input_digit(0), "0" } button { class: "calculator-key key-0", onclick: move |_| input_digit(0), "0" }
button { class: "calculator-key key-dot", onclick: move |_| val.make_mut().push('.'), "●" } button { class: "calculator-key key-dot", onclick: move |_| val.write().push('.'), "●" }
for k in 1..10 { for k in 1..10 {
button { button {
class: "calculator-key {k}", class: "calculator-key {k}",
@@ -120,7 +120,7 @@ fn app() -> Element {
button { class: "calculator-key key-add", onclick: move |_| input_operator("+"), "+" } button { class: "calculator-key key-add", onclick: move |_| input_operator("+"), "+" }
button { button {
class: "calculator-key key-equals", class: "calculator-key key-equals",
onclick: move |_| val.set(format!("{}", calc_val(val.as_str()))), onclick: move |_| val.set(format!("{}", calc_val(val().as_str()))),
"=" "="
} }
} }
+2 -2
View File
@@ -10,9 +10,9 @@ fn app() -> Element {
let elements = use_signal(Vec::<Rc<MountedData>>::new); let elements = use_signal(Vec::<Rc<MountedData>>::new);
let running = use_signal(|| true); let running = use_signal(|| true);
use_future(|| async move { use_future(move || async move {
let mut focused = 0; let mut focused = 0;
if *running.current() { if *running() {
loop { loop {
tokio::time::sleep(std::time::Duration::from_millis(10)).await; tokio::time::sleep(std::time::Duration::from_millis(10)).await;
if let Some(element) = elements.with(|f| f.get(focused).cloned()) { if let Some(element) = elements.with(|f| f.get(focused).cloned()) {
+6 -6
View File
@@ -13,22 +13,22 @@ fn app() -> Element {
render! { render! {
div { div {
button { onclick: move |_| counters.make_mut().push(0), "Add counter" } button { onclick: move |_| counters.write().push(0), "Add counter" }
button { onclick: move |_| { counters.make_mut().pop(); }, "Remove counter" } button { onclick: move |_| { counters.write().pop(); }, "Remove counter" }
p { "Total: {sum}" } p { "Total: {sum}" }
for (i, counter) in counters.iter().enumerate() { for (i, counter) in counters.iter().enumerate() {
li { li {
button { onclick: move |_| counters.make_mut()[i] -= 1, "-1" } button { onclick: move |_| counters.write()[i] -= 1, "-1" }
input { input {
value: "{counter}", value: "{counter}",
oninput: move |e| { oninput: move |e| {
if let Ok(value) = e.value().parse::<usize>() { if let Ok(value) = e.value().parse::<usize>() {
counters.make_mut()[i] = value; counters.write()[i] = value;
} }
} }
} }
button { onclick: move |_| counters.make_mut()[i] += 1, "+1" } button { onclick: move |_| counters.write()[i] += 1, "+1" }
button { onclick: move |_| { counters.make_mut().remove(i); }, "x" } button { onclick: move |_| { counters.write().remove(i); }, "x" }
} }
} }
} }
+4 -9
View File
@@ -27,7 +27,7 @@ pub struct Client {
type ClientContext = Vec<Client>; type ClientContext = Vec<Client>;
#[component] #[component]
fn App(props: ()) -> Element { fn App() -> Element {
use_shared_state_provider::<ClientContext>(Default::default); use_shared_state_provider::<ClientContext>(Default::default);
render! { render! {
@@ -58,15 +58,10 @@ fn ClientList() -> Element {
rsx! { rsx! {
h2 { "List of Clients" } h2 { "List of Clients" }
Link { to: Route::ClientAdd {}, class: "pure-button pure-button-primary", "Add Client" } Link { to: Route::ClientAdd {}, class: "pure-button pure-button-primary", "Add Client" }
Link { to: Route::Settings {}, class: "pure-button", "Settings" } Link { to: Route::Settings {}, class: "pure-button", "Settings" }
for client in clients.read().iter() { for client in clients.read().iter() {
div { div { class: "client", style: "margin-bottom: 50px",
class: "client",
style: "margin-bottom: 50px",
p { "Name: {client.first_name} {client.last_name}" } p { "Name: {client.first_name} {client.last_name}" }
p { "Description: {client.description}" } p { "Description: {client.description}" }
} }
@@ -75,7 +70,7 @@ fn ClientList() -> Element {
} }
#[component] #[component]
fn ClientAdd(props: ()) -> Element { fn ClientAdd() -> Element {
let clients = use_shared_state::<ClientContext>().unwrap(); let clients = use_shared_state::<ClientContext>().unwrap();
let first_name = use_signal(String::new); let first_name = use_signal(String::new);
let last_name = use_signal(String::new); let last_name = use_signal(String::new);
@@ -142,7 +137,7 @@ fn ClientAdd(props: ()) -> Element {
} }
#[component] #[component]
fn Settings(props: ()) -> Element { fn Settings() -> Element {
let clients = use_shared_state::<ClientContext>().unwrap(); let clients = use_shared_state::<ClientContext>().unwrap();
rsx! { rsx! {
+3 -7
View File
@@ -9,17 +9,13 @@ fn app() -> Element {
rsx! { rsx! {
div { div {
button { button { onclick: move |_| disabled.toggle(),
onclick: move |_| disabled.set(!disabled),
"click to " "click to "
if disabled == true { "enable" } else { "disable" } if *disabled() { "enable" } else { "disable" }
" the lower button" " the lower button"
} }
button { button { disabled, "lower button" }
disabled: "{disabled}",
"lower button"
}
} }
} }
} }
+2 -3
View File
@@ -2,7 +2,7 @@ use dioxus::prelude::*;
use std::collections::HashMap; use std::collections::HashMap;
fn main() { fn main() {
dioxus_desktop::launch(|cx| render!(AppRoot {})); dioxus_desktop::launch(app);
} }
#[derive(Debug, Clone, PartialEq, serde::Deserialize)] #[derive(Debug, Clone, PartialEq, serde::Deserialize)]
@@ -10,8 +10,7 @@ struct ListBreeds {
message: HashMap<String, Vec<String>>, message: HashMap<String, Vec<String>>,
} }
#[component] fn app() -> Element {
fn AppRoot(_: ()) -> Element {
let breed = use_signal(|| "deerhound".to_string()); let breed = use_signal(|| "deerhound".to_string());
let breeds = use_future(|| async move { let breeds = use_future(|| async move {
+1 -2
View File
@@ -4,8 +4,7 @@ fn main() {
dioxus_desktop::launch(App); dioxus_desktop::launch(App);
} }
#[component] fn app() -> Element {
fn App(_: ()) -> Element {
rsx! { rsx! {
ErrorBoundary { ErrorBoundary {
handle_error: |error: CapturedError| rsx! {"Found error {error}"}, handle_error: |error: CapturedError| rsx! {"Found error {error}"},
-57
View File
@@ -1,57 +0,0 @@
#![allow(non_snake_case)]
use dioxus::prelude::*;
use fermi::*;
fn main() {
dioxus_desktop::launch(app)
}
static NAME: Atom<String> = Atom(|_| "world".to_string());
fn app() -> Element {
use_init_atom_root(cx);
let name = use_read(&NAME);
rsx! {
div { "hello {name}!" }
Child {}
ChildWithRef {}
}
}
fn Child() -> Element {
let set_name = use_set(&NAME);
rsx! {
button {
onclick: move |_| set_name("dioxus".to_string()),
"reset name"
}
}
}
static NAMES: AtomRef<Vec<String>> = AtomRef(|_| vec!["world".to_string()]);
fn ChildWithRef() -> Element {
let names = use_atom_ref(&NAMES);
rsx! {
div {
ul {
for name in names.read().iter() {
li { "hello: {name}" }
}
}
button {
onclick: move |_| {
let names = names.clone();
cx.spawn(async move {
names.write().push("asd".to_string());
})
},
"Add name"
}
}
}
}
+5 -6
View File
@@ -12,20 +12,19 @@ use dioxus::prelude::*;
use dioxus_desktop::{Config, WindowBuilder}; use dioxus_desktop::{Config, WindowBuilder};
fn main() { fn main() {
dioxus_desktop::launch_cfg( Config::new()
app, .with_window(WindowBuilder::new().with_resizable(true))
Config::new().with_window(WindowBuilder::new().with_resizable(true)), .launch(app)
);
} }
const _STYLE: &str = manganis::mg!(file("./examples/assets/fileexplorer.css")); const _STYLE: &str = manganis::mg!(file("./examples/assets/fileexplorer.css"));
fn app() -> Element { fn app(_props: ()) -> Element {
let files = use_signal(Files::new); let files = use_signal(Files::new);
rsx! { rsx! {
div { div {
link { href:"https://fonts.googleapis.com/icon?family=Material+Icons", rel:"stylesheet", } link { href:"https://fonts.googleapis.com/icon?family=Material+Icons", rel:"stylesheet" }
header { header {
i { class: "material-icons icon-menu", "menu" } i { class: "material-icons icon-menu", "menu" }
h1 { "Files: ", {files.read().current()} } h1 { "Files: ", {files.read().current()} }
+26 -34
View File
@@ -9,16 +9,33 @@ fn main() {
fn App() -> Element { fn App() -> Element {
let enable_directory_upload = use_signal(|| false); let enable_directory_upload = use_signal(|| false);
let files_uploaded: Signal<Vec<String>> = use_signal(Vec::new); let files_uploaded = use_signal(|| Vec::new() as Vec<String>);
let upload_files = move |evt: FormEvent| async move {
for file_name in evt.files().unwrap().files() {
// no files on form inputs?
sleep(std::time::Duration::from_secs(1)).await;
files_uploaded.write().push(file_name);
}
};
let handle_file_drop = move |evt: DragEvent| async move {
if let Some(file_engine) = &evt.files() {
let files = file_engine.files();
for file_name in &files {
if let Some(file) = file_engine.read_file_to_string(file_name).await {
files_uploaded.write().push(file);
}
}
}
};
rsx! { rsx! {
label { label {
input { input {
r#type: "checkbox", r#type: "checkbox",
checked: "{enable_directory_upload}", checked: enable_directory_upload,
oninput: move |evt| { oninput: move |evt| enable_directory_upload.set(evt.value().parse().unwrap()),
enable_directory_upload.set(evt.value().parse().unwrap());
},
}, },
"Enable directory upload" "Enable directory upload"
} }
@@ -27,41 +44,16 @@ fn App() -> Element {
r#type: "file", r#type: "file",
accept: ".txt,.rs", accept: ".txt,.rs",
multiple: true, multiple: true,
directory: **enable_directory_upload, directory: enable_directory_upload,
onchange: |evt| { onchange: upload_files,
to_owned![files_uploaded];
async move {
if let Some(file_engine) = &evt.files() {
let files = file_engine.files();
for file_name in files {
sleep(std::time::Duration::from_secs(1)).await;
files_uploaded.write().push(file_name);
}
}
}
},
} }
div { div {
width: "100px", width: "100px",
height: "100px", height: "100px",
border: "1px solid black", border: "1px solid black",
prevent_default: "ondrop dragover dragenter", prevent_default: "ondrop dragover dragenter",
ondrop: move |evt| { ondrop: handle_file_drop,
to_owned![files_uploaded]; ondragover: move |event| event.stop_propagation(),
async move {
if let Some(file_engine) = &evt.files() {
let files = file_engine.files();
for file_name in &files {
if let Some(file) = file_engine.read_file_to_string(file_name).await{
files_uploaded.write().push(file);
}
}
}
}
},
ondragover: move |event: DragEvent| {
event.stop_propagation();
},
"Drop files here" "Drop files here"
} }
+7 -7
View File
@@ -2,15 +2,15 @@ use dioxus::prelude::*;
use dioxus_desktop::Config; use dioxus_desktop::Config;
fn main() { fn main() {
let cfg = Config::new().with_file_drop_handler(|_w, e| { Config::new()
println!("{e:?}"); .with_file_drop_handler(|_w, e| {
true println!("{e:?}");
}); true
})
dioxus_desktop::launch_with_props(app, (), cfg); .launch(app)
} }
fn app() -> Element { fn app(_props: ()) -> Element {
rsx!( rsx!(
div { div {
h1 { "drag a file here and check your console" } h1 { "drag a file here and check your console" }
+11 -14
View File
@@ -5,20 +5,17 @@ use dioxus_router::prelude::*;
fn main() { fn main() {
env_logger::init(); env_logger::init();
let cfg = Config::new().with_window( Config::new()
WindowBuilder::new() .with_window(
.with_inner_size(LogicalSize::new(600, 1000)) WindowBuilder::new()
.with_resizable(false), .with_inner_size(LogicalSize::new(600, 1000))
); .with_resizable(false),
)
dioxus_desktop::launch_cfg(App, cfg) .launch(|| {
} render! {
Router::<Route> {}
#[component] }
fn App() -> Element { });
render! {
Router::<Route> {}
}
} }
#[derive(Routable, Clone)] #[derive(Routable, Clone)]
+4 -4
View File
@@ -12,13 +12,13 @@ fn app() -> Element {
} }
} }
#[derive(PartialEq, Props)] #[derive(PartialEq, Props, Clone)]
struct GenericChildProps<T: Display + PartialEq> { struct GenericChildProps<T: Display + PartialEq + Clone + 'static> {
data: T, data: T,
} }
fn generic_child<T: Display + PartialEq>(cx: Scope<GenericChildProps<T>>) -> Element { fn generic_child<T: Display + PartialEq + Clone>(props: GenericChildProps<T>) -> Element {
render! { render! {
div { "{&cx.props.data}" } div { "{&props.data}" }
} }
} }
+10 -9
View File
@@ -13,23 +13,24 @@ use dioxus::prelude::*;
use dioxus_desktop::Config; use dioxus_desktop::Config;
fn main() { fn main() {
let mut vdom = VirtualDom::new(app); Config::new()
let _ = vdom.rebuild(); .with_prerendered({
let content = dioxus_ssr::pre_render(&vdom); // We build the dom a first time, then pre-render it to HTML
let pre_rendered_dom = VirtualDom::prebuilt(app);
dioxus_desktop::launch_cfg(app, Config::new().with_prerendered(content)); // We then launch the app with the pre-rendered HTML
dioxus_ssr::pre_render(&pre_rendered_dom)
})
.launch(app);
} }
fn app() -> Element { fn app() -> Element {
let val = use_signal(|| 0); let mut val = use_signal(|| 0);
rsx! { rsx! {
div { div {
h1 { "hello world. Count: {val}" } h1 { "hello world. Count: {val}" }
button { button { onclick: move |_| val += 1, "click to increment" }
onclick: move |_| *val.make_mut() += 1,
"click to increment"
}
} }
} }
} }
+15 -19
View File
@@ -26,35 +26,31 @@ fn main() {
} }
fn app() -> Element { fn app() -> Element {
let div_element: Signal<Option<Rc<MountedData>>> = use_signal(|| None); let div_element = use_signal(|| None as Option<Rc<MountedData>>);
let dimensions = use_signal(Rect::zero);
let dimentions = use_signal(Rect::zero); let read_dims = move |_| async move {
let read = div_element.read();
let client_rect = read.as_ref().map(|el| el.get_client_rect());
if let Some(client_rect) = client_rect {
if let Ok(rect) = client_rect.await {
dimensions.set(rect);
}
}
};
rsx!( rsx!(
div { div {
width: "50%", width: "50%",
height: "50%", height: "50%",
background_color: "red", background_color: "red",
onmounted: move |cx| { onmounted: move |cx| div_element.set(Some(cx.inner().clone())),
div_element.set(Some(cx.inner().clone())); "This element is {dimensions.read():?}"
},
"This element is {dimentions.read():?}"
} }
button { button {
onclick: move |_| { onclick: read_dims,
to_owned![div_element, dimentions]; "Read dimensions"
async move {
let read = div_element.read();
let client_rect = read.as_ref().map(|el| el.get_client_rect());
if let Some(client_rect) = client_rect {
if let Ok(rect) = client_rect.await {
dimentions.set(rect);
}
}
}
},
"Read dimentions"
} }
) )
} }
-58
View File
@@ -1,58 +0,0 @@
//! This example just flexes the ability to use arbitrary expressions within RSX.
//! It also proves that lifetimes work properly, especially when used with use_ref
use dioxus::prelude::*;
fn main() {
let mut vdom = VirtualDom::new(example);
_ = vdom.rebuild();
let mut renderer = dioxus_ssr::Renderer::new();
renderer.pretty = true;
renderer.render(&vdom);
}
fn example() -> Element {
let items = use_signal(|| {
vec![Thing {
a: "asd".to_string(),
b: 10,
}]
});
let things = use_signal(|| {
vec![Thing {
a: "asd".to_string(),
b: 10,
}]
});
let things_list = things.read();
let mything = use_signal(|| Some(String::from("asd")));
let mything_read = mything.read();
rsx!(
div {
div { id: "asd",
"your neighborhood spiderman"
for item in items.iter().cycle().take(5) {
div { "{item.a}" }
}
for thing in things_list.iter() {
div { "{thing.a}" "{thing.b}" }
}
if let Some(f) = mything_read.as_ref() {
div { "{f}" }
}
}
}
))
}
struct Thing {
a: String,
b: u32,
}
+5 -10
View File
@@ -241,12 +241,10 @@ fn lowercase_helper() -> Element {
mod baller { mod baller {
use super::*; use super::*;
#[derive(Props, PartialEq, Eq)]
pub struct BallerProps {}
#[component] #[component]
/// This component totally balls /// This component totally balls
pub fn Baller(props: BallerProps) -> Element { pub fn Baller() -> Element {
todo!() todo!()
} }
@@ -259,16 +257,13 @@ mod baller {
} }
} }
#[derive(Props)] /// Documention for this component is visible within the rsx macro
pub struct TallerProps<'a> { #[component]
pub fn Taller(
/// Fields are documented and accessible in rsx! /// Fields are documented and accessible in rsx!
a: &'static str, a: &'static str,
children: Element, children: Element,
} ) -> Element {
/// Documention for this component is visible within the rsx macro
#[component]
pub fn Taller(props: TallerProps) -> Element {
rsx! { rsx! {
{&cx.props.children} {&cx.props.children}
} }
+1 -1
View File
@@ -19,7 +19,7 @@ fn app() -> Element {
} }
button { button {
onclick: async move |_| move { onclick: move |_| async move {
if let Some(header) = header_element.read().as_ref().cloned() { if let Some(header) = header_element.read().as_ref().cloned() {
let _ = header.scroll_to(ScrollBehavior::Smooth).await; let _ = header.scroll_to(ScrollBehavior::Smooth).await;
} }
+13 -13
View File
@@ -17,18 +17,13 @@ use dioxus::prelude::*;
use dioxus_desktop::{Config, LogicalSize, WindowBuilder}; use dioxus_desktop::{Config, LogicalSize, WindowBuilder};
fn main() { fn main() {
let cfg = Config::new().with_window( Config::new()
WindowBuilder::new() .with_window(
.with_title("Doggo Fetcher") WindowBuilder::new()
.with_inner_size(LogicalSize::new(600.0, 800.0)), .with_title("Doggo Fetcher")
); .with_inner_size(LogicalSize::new(600.0, 800.0)),
)
dioxus_desktop::launch_cfg(app, cfg); .launch(app)
}
#[derive(serde::Deserialize)]
struct DogApi {
message: String,
} }
fn app() -> Element { fn app() -> Element {
@@ -54,6 +49,11 @@ fn app() -> Element {
/// actually renders the data. /// actually renders the data.
fn Doggo() -> Element { fn Doggo() -> Element {
let fut = use_future(|_| async move { let fut = use_future(|_| async move {
#[derive(serde::Deserialize)]
struct DogApi {
message: String,
}
reqwest::get("https://dog.ceo/api/breeds/image/random/") reqwest::get("https://dog.ceo/api/breeds/image/random/")
.await .await
.unwrap() .unwrap()
@@ -61,7 +61,7 @@ fn Doggo() -> Element {
.await .await
}); });
cx.render(match fut.value() { match fut.value() {
Some(Ok(resp)) => rsx! { Some(Ok(resp)) => rsx! {
button { button {
onclick: move |_| fut.restart(), onclick: move |_| fut.restart(),
+73 -71
View File
@@ -1,77 +1,79 @@
use dioxus::prelude::*; use dioxus::prelude::*;
fn app() -> Element { fn app() -> Element {
rsx!( svg { rsx! {
width: "200", svg {
height: "250", width: "200",
xmlns: "http://www.w3.org/2000/svg", height: "250",
version: "1.1", xmlns: "http://www.w3.org/2000/svg",
rect { version: "1.1",
x: "10", rect {
y: "10", x: "10",
width: "30", y: "10",
height: "30", width: "30",
stroke: "black", height: "30",
fill: "transparent", stroke: "black",
stroke_width: "5", fill: "transparent",
} stroke_width: "5",
rect { }
x: "60", rect {
y: "10", x: "60",
width: "30", y: "10",
height: "30", width: "30",
stroke: "black", height: "30",
fill: "transparent", stroke: "black",
stroke_width: "5", fill: "transparent",
} stroke_width: "5",
circle { }
cx: "25", circle {
cy: "75", cx: "25",
r: "20", cy: "75",
stroke: "red", r: "20",
fill: "transparent", stroke: "red",
stroke_width: "5", fill: "transparent",
} stroke_width: "5",
ellipse { }
cx: "75", ellipse {
cy: "75", cx: "75",
rx: "20", cy: "75",
ry: "5", rx: "20",
stroke: "red", ry: "5",
fill: "transparent", stroke: "red",
stroke_width: "5", fill: "transparent",
} stroke_width: "5",
line { }
x1: "10", line {
x2: "50", x1: "10",
y1: "110", x2: "50",
y2: "150", y1: "110",
stroke: "orange", y2: "150",
stroke_width: "5", stroke: "orange",
} stroke_width: "5",
polyline { }
points: "60 110 65 120 70 115 75 130 80 125 85 140 90 135 95 150 100 145", polyline {
stroke: "orange", points: "60 110 65 120 70 115 75 130 80 125 85 140 90 135 95 150 100 145",
fill: "transparent", stroke: "orange",
stroke_width: "5", fill: "transparent",
} stroke_width: "5",
polygon { }
points: "50 160 55 180 70 180 60 190 65 205 50 195 35 205 40 190 30 180 45 180", polygon {
stroke: "green", points: "50 160 55 180 70 180 60 190 65 205 50 195 35 205 40 190 30 180 45 180",
fill: "transparent", stroke: "green",
stroke_width: "5", fill: "transparent",
} stroke_width: "5",
path { }
d: "M20,230 Q40,205 50,230 T90,230", path {
fill: "none", d: "M20,230 Q40,205 50,230 T90,230",
stroke: "blue", fill: "none",
stroke_width: "5", stroke: "blue",
} stroke_width: "5",
path { }
d: "M9.00001 9C9 62 103.5 124 103.5 178", path {
stroke: "#3CC4DC", d: "M9.00001 9C9 62 103.5 124 103.5 178",
"stroke-linecap": "square", stroke: "#3CC4DC",
"stroke-width": "square", "stroke-linecap": "square",
"stroke-width": "square",
}
} }
} }
} }
+1 -1
View File
@@ -21,7 +21,7 @@ pub struct TodoItem {
pub contents: String, pub contents: String,
} }
pub fn app(_props: ()) -> Element { pub fn app() -> Element {
let todos = use_signal(|| HashMap::<u32, TodoItem>::new()); let todos = use_signal(|| HashMap::<u32, TodoItem>::new());
let filter = use_signal(|| FilterState::All); let filter = use_signal(|| FilterState::All);
+20 -30
View File
@@ -1,34 +1,25 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_desktop::{Config, WindowBuilder}; use dioxus_desktop::{window, Config, WindowBuilder};
fn main() { fn main() {
let cfg = Config::new().with_window( Config::new()
WindowBuilder::new() .with_window(
.with_title("Borderless Window") WindowBuilder::new()
.with_decorations(false), .with_title("Borderless Window")
); .with_decorations(false),
)
dioxus_desktop::launch_cfg(app, cfg); .launch(app)
} }
fn app() -> Element { fn app() -> Element {
let window = dioxus_desktop::use_window(cx);
// if you want to make window fullscreen, you need close the resizable.
// window.set_fullscreen(true);
// window.set_resizable(false);
let fullscreen = use_signal(|| false); let fullscreen = use_signal(|| false);
let always_on_top = use_signal(|| false); let always_on_top = use_signal(|| false);
let decorations = use_signal(|| false); let decorations = use_signal(|| false);
rsx!( rsx!(
link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css", rel:"stylesheet" } link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css", rel:"stylesheet" }
header { header { class: "text-gray-400 bg-gray-900 body-font", onmousedown: move |_| window().drag(),
class: "text-gray-400 bg-gray-900 body-font", div { class: "container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center",
onmousedown: move |_| window.drag(),
div {
class: "container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center",
a { class: "flex title-font font-medium items-center text-white mb-4 md:mb-0", a { class: "flex title-font font-medium items-center text-white mb-4 md:mb-0",
span { class: "ml-3 text-xl", "Dioxus"} span { class: "ml-3 text-xl", "Dioxus"}
} }
@@ -36,24 +27,23 @@ fn app() -> Element {
button { button {
class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0", class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0",
onmousedown: |evt| evt.stop_propagation(), onmousedown: |evt| evt.stop_propagation(),
onclick: move |_| window.set_minimized(true), onclick: move |_| window().set_minimized(true),
"Minimize" "Minimize"
} }
button { button {
class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0", class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0",
onmousedown: |evt| evt.stop_propagation(), onmousedown: |evt| evt.stop_propagation(),
onclick: move |_| { onclick: move |_| {
window().set_fullscreen(!*fullscreen());
window.set_fullscreen(!**fullscreen); window().set_resizable(*fullscreen());
window.set_resizable(**fullscreen); fullscreen.toggle();
fullscreen.modify(|f| !*f);
}, },
"Fullscreen" "Fullscreen"
} }
button { button {
class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0", class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0",
onmousedown: |evt| evt.stop_propagation(), onmousedown: |evt| evt.stop_propagation(),
onclick: move |_| window.close(), onclick: move |_| window().close(),
"Close" "Close"
} }
} }
@@ -68,8 +58,8 @@ fn app() -> Element {
class: "inline-flex items-center text-white bg-green-500 border-0 py-1 px-3 hover:bg-green-700 rounded", class: "inline-flex items-center text-white bg-green-500 border-0 py-1 px-3 hover:bg-green-700 rounded",
onmousedown: |evt| evt.stop_propagation(), onmousedown: |evt| evt.stop_propagation(),
onclick: move |_| { onclick: move |_| {
window.set_always_on_top(!always_on_top); window().set_always_on_top(!*always_on_top());
always_on_top.set(!always_on_top); always_on_top.toggle();
}, },
"Always On Top" "Always On Top"
} }
@@ -79,8 +69,8 @@ fn app() -> Element {
class: "inline-flex items-center text-white bg-blue-500 border-0 py-1 px-3 hover:bg-green-700 rounded", class: "inline-flex items-center text-white bg-blue-500 border-0 py-1 px-3 hover:bg-green-700 rounded",
onmousedown: |evt| evt.stop_propagation(), onmousedown: |evt| evt.stop_propagation(),
onclick: move |_| { onclick: move |_| {
window.set_decorations(!decorations); window().set_decorations(!*decorations());
decorations.set(!decorations); decorations.toggle();
}, },
"Set Decorations" "Set Decorations"
} }
@@ -89,7 +79,7 @@ fn app() -> Element {
button { button {
class: "inline-flex items-center text-white bg-blue-500 border-0 py-1 px-3 hover:bg-green-700 rounded", class: "inline-flex items-center text-white bg-blue-500 border-0 py-1 px-3 hover:bg-green-700 rounded",
onmousedown: |evt| evt.stop_propagation(), onmousedown: |evt| evt.stop_propagation(),
onclick: move |_| window.set_title("Dioxus Application"), onclick: move |_| window().set_title("Dioxus Application"),
"Change Title" "Change Title"
} }
} }
+12 -16
View File
@@ -5,37 +5,33 @@ use dioxus_desktop::use_wry_event_handler;
use dioxus_desktop::{Config, WindowCloseBehaviour}; use dioxus_desktop::{Config, WindowCloseBehaviour};
fn main() { fn main() {
let cfg = Config::new().with_close_behaviour(WindowCloseBehaviour::CloseWindow); Config::new()
.with_close_behaviour(WindowCloseBehaviour::CloseWindow)
dioxus_desktop::launch_cfg(app, cfg); .launch(app)
} }
fn app() -> Element { fn app() -> Element {
let focused = use_signal(|| false); let focused = use_signal(|| false);
use_wry_event_handler(move |event, _| { use_wry_event_handler(move |event, _| match event {
if let WryEvent::WindowEvent { WryEvent::WindowEvent {
event: WindowEvent::Focused(new_focused), event: WindowEvent::Focused(new_focused),
.. ..
} = event } => focused.set(*new_focused),
{ _ => {}
focused.set(*new_focused);
}
}); });
rsx! { rsx! {
div{ div {
width: "100%", width: "100%",
height: "100%", height: "100%",
display: "flex", display: "flex",
flex_direction: "column", flex_direction: "column",
align_items: "center", align_items: "center",
{ if *focused() {
if *focused.get() { "This window is focused!"
"This window is focused!" } else {
} else { "This window is not focused!"
"This window is not focused!"
}
} }
} }
} }
+1 -1
View File
@@ -11,7 +11,7 @@ fn app() -> Element {
input { input {
r#type: "number", r#type: "number",
value: "{level}", value: "{level}",
oninput: |e| { oninput: move |e| {
if let Ok(new_zoom) = e.value().parse::<f64>() { if let Ok(new_zoom) = e.value().parse::<f64>() {
level.set(new_zoom); level.set(new_zoom);
dioxus_desktop::window().webview.zoom(new_zoom); dioxus_desktop::window().webview.zoom(new_zoom);
+15
View File
@@ -230,6 +230,13 @@ impl VirtualDom {
Self::new_with_props(|app| app(), app) Self::new_with_props(|app| app(), app)
} }
/// Create a new virtualdom and build it immediately
pub fn prebuilt(app: fn() -> Element) -> Self {
let mut dom = Self::new(app);
dom.rebuild_in_place();
dom
}
/// Create a new VirtualDom with the given properties for the root component. /// Create a new VirtualDom with the given properties for the root component.
/// ///
/// # Description /// # Description
@@ -568,6 +575,14 @@ impl VirtualDom {
to.append_children(ElementId(0), m); to.append_children(ElementId(0), m);
} }
/// Rebuild the virtualdom without handling any of the mutations
///
/// This is useful for testing purposes and in cases where you render the output of the virtualdom without
/// handling any of its mutations.
pub fn rebuild_in_place(&mut self) {
self.rebuild(&mut NoOpMutations);
}
/// [`VirtualDom::rebuild`] to a vector of mutations for testing purposes /// [`VirtualDom::rebuild`] to a vector of mutations for testing purposes
pub fn rebuild_to_vec(&mut self) -> Mutations { pub fn rebuild_to_vec(&mut self) -> Mutations {
let mut mutations = Mutations::default(); let mut mutations = Mutations::default();
+3 -3
View File
@@ -1,7 +1,7 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::path::PathBuf; use std::path::PathBuf;
use dioxus_core::prelude::Component; use dioxus_core::prelude::{Component, Element};
use tao::window::{Icon, WindowBuilder, WindowId}; use tao::window::{Icon, WindowBuilder, WindowId};
use wry::{ use wry::{
http::{Request as HttpRequest, Response as HttpResponse}, http::{Request as HttpRequest, Response as HttpResponse},
@@ -74,8 +74,8 @@ impl Config {
/// Launch a Dioxus app using the given component and config /// Launch a Dioxus app using the given component and config
/// ///
/// See the [`crate::launch::launch`] function for more details. /// See the [`crate::launch::launch`] function for more details.
pub fn launch(self, root: Component<()>) { pub fn launch(self, app: fn() -> Element) {
crate::launch::launch_cfg(root, self) self.launch_with_props(|props| props(), app)
} }
/// Launch a Dioxus app using the given component, config, and props /// Launch a Dioxus app using the given component, config, and props
+14 -14
View File
@@ -2,6 +2,7 @@ use crate::{
assets::*, ipc::UserWindowEvent, shortcut::IntoAccelerator, window, DesktopContext, assets::*, ipc::UserWindowEvent, shortcut::IntoAccelerator, window, DesktopContext,
ShortcutHandle, ShortcutRegistryError, WryEventHandler, ShortcutHandle, ShortcutRegistryError, WryEventHandler,
}; };
use dioxus_core::use_hook;
use tao::{event::Event, event_loop::EventLoopWindowTarget}; use tao::{event::Event, event_loop::EventLoopWindowTarget};
use wry::RequestAsyncResponder; use wry::RequestAsyncResponder;
@@ -12,22 +13,21 @@ use wry::RequestAsyncResponder;
// .unwrap() // .unwrap()
// } // }
// /// Get a closure that executes any JavaScript in the WebView context. /// Get a closure that executes any JavaScript in the WebView context.
// pub fn use_wry_event_handler( pub fn use_wry_event_handler(
// , handler: impl FnMut(&Event<UserWindowEvent>, &EventLoopWindowTarget<UserWindowEvent>) + 'static,
// handler: impl FnMut(&Event<UserWindowEvent>, &EventLoopWindowTarget<UserWindowEvent>) + 'static, ) -> WryEventHandler {
// ) -> &WryEventHandler { use_hook(move || {
// cx.use_hook(move || { let desktop = window();
// let desktop = window();
// let id = desktop.create_wry_event_handler(handler); let id = desktop.create_wry_event_handler(handler);
// WryEventHandler { WryEventHandler {
// handlers: desktop.shared.event_handlers.clone(), handlers: desktop.shared.event_handlers.clone(),
// id, id,
// } }
// }) })
// } }
// /// Provide a callback to handle asset loading yourself. // /// Provide a callback to handle asset loading yourself.
// /// // ///
+4 -4
View File
@@ -23,8 +23,8 @@ use tao::event::{Event, StartCause, WindowEvent};
/// }) /// })
/// } /// }
/// ``` /// ```
pub fn launch(root: fn() -> Element) { pub fn launch(app: fn() -> Element) {
launch_with_props(|root| root(), root, Config::default()) launch_with_props(|root| root(), app, Config::default())
} }
/// Launch the WebView and run the event loop, with configuration. /// Launch the WebView and run the event loop, with configuration.
@@ -47,8 +47,8 @@ pub fn launch(root: fn() -> Element) {
/// }) /// })
/// } /// }
/// ``` /// ```
pub fn launch_cfg(root: Component, config_builder: Config) { pub fn launch_cfg(app: fn() -> Element, config_builder: Config) {
launch_with_props(root, (), config_builder) launch_with_props(|props| props(), app, config_builder)
} }
/// Launch the WebView and run the event loop, with configuration and root props. /// Launch the WebView and run the event loop, with configuration and root props.
+2
View File
@@ -46,3 +46,5 @@ pub use desktop_context::{
// pub use hooks::{use_asset_handler, use_global_shortcut, use_window, use_wry_event_handler}; // pub use hooks::{use_asset_handler, use_global_shortcut, use_window, use_wry_event_handler};
pub use shortcut::{ShortcutHandle, ShortcutId, ShortcutRegistryError}; pub use shortcut::{ShortcutHandle, ShortcutId, ShortcutRegistryError};
pub use wry::RequestAsyncResponder; pub use wry::RequestAsyncResponder;
pub use hooks::*;
+14 -2
View File
@@ -7,8 +7,11 @@ use std::{
}; };
use dioxus_core::{ use dioxus_core::{
prelude::{current_scope_id, has_context, provide_context, schedule_update_any}, prelude::{
use_hook, ScopeId, current_scope_id, has_context, provide_context, schedule_update_any, use_hook,
IntoAttributeValue,
},
ScopeId,
}; };
use generational_box::{GenerationalRef, GenerationalRefMut}; use generational_box::{GenerationalRef, GenerationalRefMut};
@@ -306,6 +309,15 @@ impl<T: 'static> Signal<T> {
} }
} }
impl<T> IntoAttributeValue for Signal<T>
where
T: Clone + IntoAttributeValue,
{
fn into_value(self) -> dioxus_core::AttributeValue {
self.with(|f| f.clone().into_value())
}
}
impl<T: Clone + 'static> Signal<T> { impl<T: Clone + 'static> Signal<T> {
/// Get the current value of the signal. This will subscribe the current scope to the signal. /// Get the current value of the signal. This will subscribe the current scope to the signal.
/// If the signal has been dropped, this will panic. /// If the signal has been dropped, this will panic.