diff --git a/Cargo.toml b/Cargo.toml index cd6fed8b1..e1f47ae1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,9 +6,10 @@ members = [ "packages/web", "packages/dioxus", "packages/ssr", + "packages/docsite", + "packages/recoil", + "packages/router", ] -# "packages/recoil", -# "packages/docsite", # "packages/webview", # "packages/cli", diff --git a/README.md b/README.md index 19b7dd6a5..39f81854e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Dioxus is a portable, performant, and ergonomic framework for building cross-platform user experiences in Rust. ```rust -fn Example(ctx: Context<()>) -> VNodes { +fn Example(ctx: Context<()>) -> VNode { let (selection, set_selection) = use_state(&ctx, || "..?"); ctx.render(rsx! { @@ -41,7 +41,7 @@ If you know React, then you already know Dioxus. Web Desktop Mobile - State Management + State Docs Tools diff --git a/packages/docsite/src/components/app.rs b/packages/core/examples/app.rs similarity index 100% rename from packages/docsite/src/components/app.rs rename to packages/core/examples/app.rs diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 5d0d62de8..2a35a341a 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -314,6 +314,10 @@ impl VirtualDom { Ok(()) } + + pub fn base_scope(&self) -> &Scope { + todo!() + } } // TODO! @@ -802,6 +806,14 @@ Any function prefixed with "use" should not be called conditionally. |_| {}, ) } + + fn suspend( + &self, + f: impl Future, + g: impl FnOnce(O) -> VNode<'src> + 'src, + ) -> VNode<'src> { + todo!() + } } // ================================================================================== diff --git a/packages/docsite/src/blah.html b/packages/docsite/src/blah.html new file mode 100644 index 000000000..a47e6caa4 --- /dev/null +++ b/packages/docsite/src/blah.html @@ -0,0 +1,17 @@ + + + + diff --git a/packages/docsite/src/components/blog.rs b/packages/docsite/src/components/blog.rs new file mode 100644 index 000000000..7d6780102 --- /dev/null +++ b/packages/docsite/src/components/blog.rs @@ -0,0 +1,9 @@ +use dioxus_ssr::prelude::*; + +pub static Blog: FC<()> = |ctx| { + rsx! { in ctx, + div { + + } + } +}; diff --git a/packages/docsite/src/components/community.rs b/packages/docsite/src/components/community.rs new file mode 100644 index 000000000..277b25917 --- /dev/null +++ b/packages/docsite/src/components/community.rs @@ -0,0 +1,9 @@ +use dioxus_ssr::prelude::*; + +pub static Community: FC<()> = |ctx| { + rsx! { in ctx, + div { + + } + } +}; diff --git a/packages/docsite/src/components/docs.rs b/packages/docsite/src/components/docs.rs new file mode 100644 index 000000000..564b309e6 --- /dev/null +++ b/packages/docsite/src/components/docs.rs @@ -0,0 +1,9 @@ +use dioxus_ssr::prelude::*; + +pub static Docs: FC<()> = |ctx| { + rsx! { in ctx, + div { + + } + } +}; diff --git a/packages/docsite/src/components/homepage.rs b/packages/docsite/src/components/homepage.rs new file mode 100644 index 000000000..d6bb9cd20 --- /dev/null +++ b/packages/docsite/src/components/homepage.rs @@ -0,0 +1,42 @@ +use dioxus_ssr::prelude::*; + +const HeroContent: [(&'static str, &'static str); 3] = [ + ("Declarative", + "React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.\nDeclarative views make your code more predictable and easier to debug."), + + ("Component-Based", "Build encapsulated components that manage their own state, then compose them to make complex UIs.\nSince component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep state out of the DOM."), + + ("Learn Once, Write Anywhere", "We don’t make assumptions about the rest of your technology stack, so you can develop new features in React without rewriting existing code.\nReact can also render on the server using Node and power mobile apps using React Native."), +]; + +const SnippetHighlights: &'static str = include_str!("./../snippets.md"); + +pub static Home: FC<()> = |ctx| { + let hero = HeroContent.iter().map(|(title, body)| { + rsx! { + div { + h3 { "{title}" } + div { {body.split("\n").map(|paragraph| rsx!( p{"{paragraph}"} ))} } + } + } + }); + let snippets: Vec = crate::utils::markdown_to_snippet(ctx, SnippetHighlights); + + rsx! { in ctx, + div { + header { + // Hero + section { + div { {hero} } + } + hr {} + // Highlighted Snippets + section { + {snippets} + } + } + div {} + section {} + } + } +}; diff --git a/packages/docsite/src/components/tutorial.rs b/packages/docsite/src/components/tutorial.rs new file mode 100644 index 000000000..ecb88c2ef --- /dev/null +++ b/packages/docsite/src/components/tutorial.rs @@ -0,0 +1,9 @@ +use dioxus_ssr::prelude::*; + +pub static Tutorial: FC<()> = |ctx| { + rsx! { in ctx, + div { + + } + } +}; diff --git a/packages/docsite/src/main.rs b/packages/docsite/src/main.rs index 3240a25a3..6a139a748 100644 --- a/packages/docsite/src/main.rs +++ b/packages/docsite/src/main.rs @@ -1,97 +1,152 @@ #![allow(non_upper_case_globals)] -use dioxus_ssr::{ - prelude::*, - prelude::{builder::IntoVNode, dioxus::events::on::MouseEvent}, - TextRenderer, -}; -mod utils; +use dioxus_ssr::{prelude::*, TextRenderer}; +pub mod utils; +mod components { + mod community; + pub use community::*; + mod docs; + pub use docs::*; + mod blog; + pub use blog::*; + mod homepage; + pub use homepage::*; + mod tutorial; + pub use tutorial::*; +} +use components::*; fn main() { let renderer = TextRenderer::new(App); + /* + renderer.render_at("community") + + */ } static App: FC<()> = |ctx| { - rsx! { in ctx, + let (url, set_url) = use_state(&ctx, || ""); + + let body = match *url { + "community" => rsx!(in ctx, Community {}), + "tutorial" => rsx!(in ctx, Tutorial {}), + "blog" => rsx!(in ctx, Blog {}), + "docs" => rsx!(in ctx, Docs {}), + _ => rsx!(in ctx, Home {}), + }; + + ctx.render(rsx! { div { - Home {} - Docs {} - Tutorial {} - Blog {} - Community {} + NavBar {} + {body} + Footer {} } - } + }) }; -const HeroContent: [(&'static str, &'static str); 3] = [ - ("Declarative", - "React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.\nDeclarative views make your code more predictable and easier to debug."), +static NavBar: FC<()> = |ctx| { + ctx.render(rsx! { + header { + a { + href: "/" + img { /*logo*/ } + span {} + } + nav { + a { href: "/community/support", "Community" } + a { href: "/docs/getting-started", "Docs" } + a { href: "/tutorial/tutorial", "Tutorial" } + a { href: "/blog/", "Blog" } + } + form {} + div {} + } + }) +}; - ("Component-Based", "Build encapsulated components that manage their own state, then compose them to make complex UIs.\nSince component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep state out of the DOM."), - - ("Learn Once, Write Anywhere", "We don’t make assumptions about the rest of your technology stack, so you can develop new features in React without rewriting existing code.\nReact can also render on the server using Node and power mobile apps using React Native."), +static SECTIONS: &[(&str, &[(&str, &str)])] = &[ + ( + "Docs", + &[ + ("Installation", "docs/installation"), + ("Main Concepts", "docs/main"), + ("Advanced Guides", "docs/advanced"), + ("Hooks", "docs/hooks"), + ("Testing", "docs/testing"), + ("Contributing", "docs/contributing"), + ("FAQ", "docs/faq"), + ], + ), + ( + "Channels", + &[("Github", "https://github.com/jkelleyrtp/dioxus")], + ), + ( + "Community", + &[ + ("Code of Conduct", "docs/installation"), + ("Community Resources", "docs/main"), + ], + ), + ( + "More", + &[ + ("Tutorial", "docs/installation"), + ("Blog", "docs/main"), + ("Privacy", "docs/advanced"), + ("Terms", "docs/hooks"), + ], + ), ]; -const SnippetHighlights: &'static str = include_str!("./snippets.md"); - -static Home: FC<()> = |ctx| { - let hero = HeroContent.iter().map(|(title, body)| { +fn Footer(ctx: Context<()>) -> VNode { + let sections = SECTIONS.iter().map(|(section, raw_links)| { + let links = raw_links.iter().map(|(link_name, href)| { + rsx! ( + a { href: "{href}", + "{link_name}", + {href.starts_with("http").then(|| rsx!( ExternalLinkIcon {} ))} + } + ) + }); rsx! { div { - h3 { "{title}" } - div { {body.split("\n").map(|paragraph| rsx!( p{"{paragraph}"} ))} } + div { "{section}" } + {links} } } }); - let snippets: Vec = utils::markdown_to_snippet(ctx, SnippetHighlights); - rsx! { in ctx, - div { - header { - // Hero - section { - div { {hero} } - } - hr {} - // Highlighted Snippets - section { - {snippets} + ctx.render(rsx! { + footer { + div { + div { + div { + {sections} + } + section { + a { + img {} + } + p {} + } } } - div {} - section {} } - } -}; - -static Docs: FC<()> = |ctx| { - rsx! { in ctx, - div { - - } - } -}; - -static Tutorial: FC<()> = |ctx| { - rsx! { in ctx, - div { - - } - } -}; - -static Blog: FC<()> = |ctx| { - rsx! { in ctx, - div { - - } - } -}; - -static Community: FC<()> = |ctx| { - rsx! { in ctx, - div { - - } - } + }) +} + +const ExternalLinkIcon: FC<()> = |ctx| { + ctx.render(html! { + + + + + }) }; diff --git a/packages/recoil/.vscode/settings.json b/packages/recoil/.vscode/settings.json index 2f418701b..80f51cff8 100644 --- a/packages/recoil/.vscode/settings.json +++ b/packages/recoil/.vscode/settings.json @@ -1,3 +1,3 @@ { - "rust-analyzer.inlayHints.enable": true + "rust-analyzer.inlayHints.enable": false } \ No newline at end of file diff --git a/packages/recoil/Cargo.toml b/packages/recoil/Cargo.toml index 105019bff..0d955a6cd 100644 --- a/packages/recoil/Cargo.toml +++ b/packages/recoil/Cargo.toml @@ -12,6 +12,7 @@ dioxus-core = { path = "../core" } thiserror = "1.0.24" log = "0.4.14" im-rc = "15.0.0" +futures = "0.3.15" [dev-dependencies] uuid = { version = "0.8.2", features = ["v4", "wasm-bindgen"] } diff --git a/packages/recoil/examples/api_mvc.rs b/packages/recoil/examples/api_mvc.rs index dc3f2f692..31e65b9ab 100644 --- a/packages/recoil/examples/api_mvc.rs +++ b/packages/recoil/examples/api_mvc.rs @@ -29,9 +29,9 @@ impl TitleController { fn main() { wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(|ctx| { - let title = use_read(ctx, &TITLE); - let subtitle = use_read(ctx, &SUBTITLE); - let controller = use_recoil_api(ctx, TitleController::new); + let title = use_read(&ctx, &TITLE); + let subtitle = use_read(&ctx, &SUBTITLE); + let controller = TitleController::new(use_recoil_api(&ctx)); rsx! { in ctx, div { diff --git a/packages/recoil/examples/callback.rs b/packages/recoil/examples/callback.rs index be67683b4..78152cdbe 100644 --- a/packages/recoil/examples/callback.rs +++ b/packages/recoil/examples/callback.rs @@ -21,7 +21,7 @@ fn update_title(api: &RecoilApi) { static App: FC<()> = |ctx| { let title = use_read(&ctx, &TITLE); - let next_light = use_recoil_api(ctx, |api| move |_| update_title(&api)); + let next_light = use_recoil_api(&ctx, |api| move |_| update_title(&api)); rsx! { in ctx, div { diff --git a/packages/recoil/examples/familypoc.rs b/packages/recoil/examples/familypoc.rs index a1bd0f327..f00cfaf2f 100644 --- a/packages/recoil/examples/familypoc.rs +++ b/packages/recoil/examples/familypoc.rs @@ -14,7 +14,7 @@ struct Todo { static App: FC<()> = |ctx| { use_init_recoil_root(ctx, |_| {}); - let todos = use_read(ctx, &TODOS); + let todos = use_read(&ctx, &TODOS); rsx! { in ctx, div { diff --git a/packages/recoil/examples/hellorecoil.rs b/packages/recoil/examples/hellorecoil.rs index f4c82bef5..5b5b32a03 100644 --- a/packages/recoil/examples/hellorecoil.rs +++ b/packages/recoil/examples/hellorecoil.rs @@ -6,7 +6,7 @@ const COUNT: Atom = |_| 0; static App: FC<()> = |ctx| { use_init_recoil_root(ctx, |_| {}); - let (count, set_count) = use_read_write(ctx, &COUNT); + let (count, set_count) = use_read_write(&ctx, &COUNT); rsx! { in ctx, div { diff --git a/packages/recoil/examples/selectors.rs b/packages/recoil/examples/selectors.rs index 822f697a0..29b92a70c 100644 --- a/packages/recoil/examples/selectors.rs +++ b/packages/recoil/examples/selectors.rs @@ -17,12 +17,12 @@ static App: FC<()> = |ctx| { }; static Banner: FC<()> = |ctx| { - let count = use_read(ctx, &C); + let count = use_read(&ctx, &C); ctx.render(rsx! { h1 { "Count: {count}" } }) }; static BtnA: FC<()> = |ctx| { - let (a, set) = use_read_write(ctx, &A); + let (a, set) = use_read_write(&ctx, &A); rsx! { in ctx, div { "a" button { "+", onclick: move |_| set(a + 1) } @@ -32,7 +32,7 @@ static BtnA: FC<()> = |ctx| { }; static BtnB: FC<()> = |ctx| { - let (b, set) = use_read_write(ctx, &B); + let (b, set) = use_read_write(&ctx, &B); rsx! { in ctx, div { "b" button { "+", onclick: move |_| set(b + 1) } diff --git a/packages/recoil/examples/supense_integration.rs b/packages/recoil/examples/supense_integration.rs new file mode 100644 index 000000000..cb3e6d869 --- /dev/null +++ b/packages/recoil/examples/supense_integration.rs @@ -0,0 +1,50 @@ +// const Posts: AtomFamily = |family| { +// family.on_get(|key| { + +// // +// }) +// }; + +fn main() { + wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(App)) +} + +use std::future::Future; + +use dioxus_core::prelude::*; + +static App: FC<()> = |ctx| { + // + + let title = use_async_atom(); + let title_card = suspend(&ctx, title, move |val| { + // + rsx!(in ctx, div { + h3 { "{val}" } + }) + }); + + // let fut = (use_async_atom(), use_async_atom()); + // let title_card2 = ctx.suspend(fut, move |(text, text2)| { + // ctx.render(rsx!( h3 { "{text}" } )) + // }); + + ctx.render(rsx! { + div { + {title_card} + // {title_card2} + } + }) +}; + +async fn use_async_atom() -> String { + todo!() +} + +fn suspend<'a, O>( + c: &impl Scoped<'a>, + f: impl Future, + g: impl FnOnce(O) -> VNode<'a> + 'a, +) -> VNode<'a> { + todo!() +} diff --git a/packages/recoil/src/lib.rs b/packages/recoil/src/lib.rs index 634d9442e..8c8aa15f6 100644 --- a/packages/recoil/src/lib.rs +++ b/packages/recoil/src/lib.rs @@ -525,6 +525,8 @@ mod utils { use super::*; use dioxus_core::prelude::*; + pub struct RecoilApi {} + /// This tiny util wraps your main component with the initializer for the recoil root. /// This is useful for small programs and the examples in this crate pub fn RecoilApp( diff --git a/packages/router/README.md b/packages/router/README.md index 97ba9cca2..060e4fc07 100644 --- a/packages/router/README.md +++ b/packages/router/README.md @@ -4,7 +4,7 @@ Dioxus-router provides a use_router hook that returns a different value dependin The router is generic over any value, however it makes sense to return a different set of VNodes and feed them into the App's return VNodes. -Using the router should feel similar to tide's routing framework where an "address" book is assembled at the head. +Using the router should feel similar to tide's routing framework where an "address" book is assembled at the head of the app. Here's an example of how to use the router hook: @@ -13,32 +13,27 @@ static App: FC<()> = |ctx| { // Route returns the associated VNodes // This hook re-fires when the route changes - let route = use_router(ctx, |cfg| { - cfg.at("/").serve(|ctx| { - html!{ } + let route = use_router(ctx, |router| { + router.at("/").get(|path| { + rsx!{ } }); - - cfg.at("/shoes/:id").serve(|ctx| { - let id: Uuid = ctx.ctx.parse().unwrap(); - html!{ } + router.at("/shoes/:id").get(|path| { + let id: Uuid = path.parse().unwrap(); + rsx!{ } }); - - cfg.at("/pants/:id").serve(|ctx| { - let id: Uuid = ctx.ctx.parse().unwrap(); - html!{ } + router.at("/pants/:id").get(|path| { + let id: Uuid = path.parse().unwrap(); + rsx!{ } }); }); - html! { - "Uh oh!"}}> - - -
- {route} - - - - } + ctx.render(rsx!{ + div { + Navbar {} + {route} + Footer {} + } + }) }; ``` diff --git a/packages/ssr/src/tostring.rs b/packages/ssr/src/tostring.rs index f95e7d577..d9b9596f1 100644 --- a/packages/ssr/src/tostring.rs +++ b/packages/ssr/src/tostring.rs @@ -34,10 +34,11 @@ fn html_render( write!(f, "\n", el.tag_name)?; Ok(()) } - VNode::Text(t) => write!(f, "{}", t.text), + VNode::Text(text) => write!(f, "{}", text), VNode::Suspended => todo!(), VNode::Component(vcomp) => { - let id = vcomp.ass_scope.as_ref().borrow().unwrap(); + let id = vcomp.ass_scope.borrow().unwrap(); + // let id = vcomp.ass_scope.as_ref().borrow().unwrap(); let new_node = dom .components .try_get(id) @@ -46,6 +47,7 @@ fn html_render( .current_head_node(); html_render(&dom, new_node, f) } + VNode::Fragment(_) => todo!(), } } @@ -61,7 +63,7 @@ fn test_serialize() { {(0..20).map(|f| rsx!{ div { title: "About W3Schools" - style: "color:blue;text-align:center" + // style: "color:blue;text-align:center" class: "About W3Schools" p { title: "About W3Schools" diff --git a/packages/web/Cargo.toml b/packages/web/Cargo.toml index 11cc37035..4529f631e 100644 --- a/packages/web/Cargo.toml +++ b/packages/web/Cargo.toml @@ -28,6 +28,7 @@ recoil = { path = "../recoil" } # html-validation = { path = "../html-validation", version = "0.1.1" } async-channel = "1.6.1" +wee_alloc = "0.4.5" # futures-lite = "1.11.3" [dependencies.web-sys] @@ -62,7 +63,13 @@ features = [ ] [profile.release] -debug = true +lto = true +opt-level = 's' + +# debug = true + +# [profile.release] + [lib] crate-type = ["cdylib", "rlib"] diff --git a/packages/web/examples/basic.rs b/packages/web/examples/basic.rs index e4b9012d9..fa36129fd 100644 --- a/packages/web/examples/basic.rs +++ b/packages/web/examples/basic.rs @@ -37,3 +37,32 @@ static C2: FC<()> = |ctx| { } }) }; + +static DocExamples: FC<()> = |ctx| { + // + + let is_ready = false; + + let items = (0..10).map(|i| rsx! { li {"{i}"} }); + let _ = rsx! { + ul { + {items} + } + }; + + rsx! { + div {} + h1 {} + {""} + "asbasd" + dioxus::Fragment { + // + } + } + + ctx.render(rsx! { + div { + { is_ready.then(|| rsx!{ h1 {"We are ready!"} }) } + } + }) +}; diff --git a/packages/web/examples/derive.rs b/packages/web/examples/derive.rs index 1c5530a42..d249197d4 100644 --- a/packages/web/examples/derive.rs +++ b/packages/web/examples/derive.rs @@ -8,14 +8,17 @@ fn main() { wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App)); } +// Use `wee_alloc` as the global allocator. +#[global_allocator] +static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; + fn App(ctx: Context<()>) -> VNode { let cansee = use_state_new(&ctx, || false); rsx! { in ctx, div { "Shadow of the child:" - button { + button { onclick: move |_| cansee.set(!**cansee) "Gaze into the void" - onclick: move |_| cansee.set(!**cansee) } {cansee.then(|| rsx!{ Child {} })} } diff --git a/packages/web/examples/landingpage2.rs b/packages/web/examples/landingpage2.rs index 2a10ebeee..6d4b04978 100644 --- a/packages/web/examples/landingpage2.rs +++ b/packages/web/examples/landingpage2.rs @@ -1,13 +1,14 @@ //! Basic example that renders a simple VNode to the browser. -use std::rc::Rc; +use std::{future::Future, pin::Pin, rc::Rc}; use dioxus_core::prelude::*; use dioxus_web::*; fn main() { - // Setup logging + // Setup logging and panic handling wasm_logger::init(wasm_logger::Config::new(log::Level::Debug)); console_error_panic_hook::set_once(); + // Run the app wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App)); } @@ -16,23 +17,16 @@ static App: FC<()> = |ctx| { let (contents, set_contents) = use_state(&ctx, || "asd"); ctx.render(rsx! { - div { - class: "flex items-center justify-center flex-col" - div { - class: "flex items-center justify-center" - div { - class: "flex flex-col bg-white rounded p-4 w-full max-w-xs" + div { class: "flex items-center justify-center flex-col" + div { class: "flex items-center justify-center" + div { class: "flex flex-col bg-white rounded p-4 w-full max-w-xs" div { class: "font-bold text-xl", "Example Web app" } div { class: "text-sm text-gray-500", "This is running in your browser!" } - div { - class: "flex flex-row items-center justify-center mt-6" + div { class: "flex flex-row items-center justify-center mt-6" div { class: "font-medium text-6xl", "100%" } } - div { - class: "flex flex-row justify-between mt-6" - a { - href: "https://www.dioxuslabs.com" - class: "underline" + div { class: "flex flex-row justify-between mt-6" + a { href: "https://www.dioxuslabs.com", class: "underline" "Made with dioxus" } } diff --git a/packages/web/examples/list.rs b/packages/web/examples/list.rs index 08d55782a..933e151f8 100644 --- a/packages/web/examples/list.rs +++ b/packages/web/examples/list.rs @@ -28,17 +28,10 @@ pub struct TodoItem { static App: FC<()> = |ctx| { let (draft, set_draft) = use_state(&ctx, || "".to_string()); let (filter, set_filter) = use_state(&ctx, || FilterState::All); - let (is_editing, set_is_editing) = use_state(&ctx, || false); - // let (todos, set_todos) = use_state(&ctx, || BTreeMap::::new()); - - // let todos = use_ref(&ctx, || BTreeMap::::new()); let todos = use_state_new(&ctx, || BTreeMap::::new()); - - // let blah = "{draft}" ctx.render(rsx!( div { id: "app" - div { header { class: "header" @@ -60,7 +53,6 @@ static App: FC<()> = |ctx| { input { class: "new-todo" placeholder: "What needs to be done?" - // value: "{draft}" oninput: move |evt| set_draft(evt.value) } } @@ -76,17 +68,13 @@ static App: FC<()> = |ctx| { .map(|(id, todo)| { rsx!{ li { + key: "{id}" "{todo.contents}" input { class: "toggle" type: "checkbox" "{todo.checked}" } - // {is_editing.then(|| rsx!( - // input { - // value: "{contents}" - // } - // ))} } } })