wip: move examples around
This commit is contained in:
1 parent
d298b626d3
commit
1e6e5e611b
86 files changed
+160
-216
No files matched your search
@@ -19,6 +19,7 @@ use dioxus_core_macro::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use rand::prelude::*;
|
||||
|
||||
fn main() {}
|
||||
criterion_group!(mbenches, create_rows);
|
||||
criterion_main!(mbenches);
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::format_args_f;
|
||||
use dioxus_core_macro::rsx;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
fn main() {
|
||||
let mut dom = VirtualDom::new(EXAMPLE);
|
||||
dom.rebuild();
|
||||
println!("{}", dom);
|
||||
}
|
||||
|
||||
pub static EXAMPLE: FC<()> = |(cx, _)| {
|
||||
let list = (0..10).map(|_f| {
|
||||
rsx! {
|
||||
"{_f}"
|
||||
}
|
||||
});
|
||||
// let list = (0..10).map(|_f| Some(Box::new(move |_f| todo!())));
|
||||
|
||||
cx.render(Some(LazyNodes::new(move |cx| {
|
||||
cx.raw_element(
|
||||
"div",
|
||||
None,
|
||||
[],
|
||||
[],
|
||||
[
|
||||
cx.text(format_args!("hello")),
|
||||
cx.text(format_args!("hello")),
|
||||
cx.fragment_from_iter(list),
|
||||
],
|
||||
None,
|
||||
)
|
||||
})))
|
||||
};
|
||||
@@ -1,15 +0,0 @@
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
fn main() {
|
||||
let mut dom = VirtualDom::new(App);
|
||||
dom.rebuild();
|
||||
}
|
||||
|
||||
const App: FC<()> = |(cx, props)| {
|
||||
let id = cx.scope_id();
|
||||
// cx.submit_task(Box::pin(async move { id }));
|
||||
|
||||
// let (handle, contents) = use_task(cx, || async { "hello world".to_string() });
|
||||
|
||||
todo!()
|
||||
};
|
||||
@@ -1,78 +0,0 @@
|
||||
//! Demonstrate that borrowed data is possible as a property type
|
||||
//! Borrowing (rather than cloning) is very important for speed and ergonomics.
|
||||
//!
|
||||
//! It's slightly more advanced than just cloning, but well worth the investment.
|
||||
//!
|
||||
//! If you use the FC macro, we handle the lifetimes automatically, making it easy to write efficient & performant components.
|
||||
fn main() {}
|
||||
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
struct AppProps {
|
||||
items: Vec<Rc<ListItem>>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
struct ListItem {
|
||||
name: String,
|
||||
age: u32,
|
||||
}
|
||||
|
||||
fn app<'a>(cx: Context<'a>, props: &AppProps) -> Element<'a> {
|
||||
// let (val, set_val) = use_state_classic(cx, || 0);
|
||||
|
||||
todo!()
|
||||
// cx.render(LazyNodes::new(move |_nodecx| {
|
||||
// todo!()
|
||||
// // builder::ElementBuilder::new(_nodecx, "div")
|
||||
// // .iter_child({
|
||||
// // cx.items.iter().map(|child| {
|
||||
// // builder::virtual_child(
|
||||
// // _nodecx,
|
||||
// // ChildItem,
|
||||
// // ChildProps {
|
||||
// // item: child.clone(),
|
||||
// // item_handler: set_val.clone(),
|
||||
// // },
|
||||
// // None,
|
||||
// // &[],
|
||||
// // )
|
||||
// // })
|
||||
// // })
|
||||
// // .iter_child([builder::ElementBuilder::new(_nodecx, "div")
|
||||
// // .iter_child([builder::text3(_nodecx.bump(), format_args!("{}", val))])
|
||||
// // .finish()])
|
||||
// // .finish()
|
||||
// }))
|
||||
}
|
||||
|
||||
// props should derive a partialeq implementation automatically, but implement ptr compare for & fields
|
||||
struct ChildProps {
|
||||
// Pass down complex structs
|
||||
item: Rc<ListItem>,
|
||||
|
||||
// Even pass down handlers!
|
||||
item_handler: Rc<dyn Fn(i32)>,
|
||||
}
|
||||
|
||||
fn ChildItem<'a>(cx: Context<'a>, props: &'a ChildProps) -> Element<'a> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
impl PartialEq for ChildProps {
|
||||
fn eq(&self, _other: &Self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
impl Properties for ChildProps {
|
||||
type Builder = ();
|
||||
const IS_STATIC: bool = true;
|
||||
fn builder() -> Self::Builder {
|
||||
()
|
||||
}
|
||||
unsafe fn memoize(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
fn main() {}
|
||||
struct SomeContext {
|
||||
items: Vec<String>,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
static Example: FC<()> = |(cx, props)| {
|
||||
todo!()
|
||||
|
||||
// let value = cx.use_context(|c: &SomeContext| c.items.last().unwrap());
|
||||
|
||||
// cx.render(LazyNodes::new(move |bump| {
|
||||
// builder::ElementBuilder::new(bump, "button")
|
||||
// .on("click", move |_| {
|
||||
// println!("Value is {}", cx.name);
|
||||
// println!("Value is {}", value.as_str());
|
||||
// println!("Value is {}", *value);
|
||||
// })
|
||||
// .on("click", move |_| {
|
||||
// println!("Value is {}", cx.name);
|
||||
// })
|
||||
// .finish()
|
||||
// }))
|
||||
// cx.render(html! {
|
||||
// <div>
|
||||
// <button onclick={move |_| println!("Value is {}", value)} />
|
||||
// <button onclick={move |_| println!("Value is {}", value)} />
|
||||
// <button onclick={move |_| println!("Value is {}", value)} />
|
||||
// <div>
|
||||
// <p> "Value is: {val}" </p>
|
||||
// </div>
|
||||
// </div>
|
||||
// })
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
fn main( ) {}
|
||||
@@ -1,46 +0,0 @@
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
fn main() {}
|
||||
|
||||
fn app<'a>(cx: Context<'a>, props: &()) -> Element<'a> {
|
||||
// let vak = use_suspense(
|
||||
// cx,
|
||||
// || async {},
|
||||
// |c, _res| c.render(LazyNodes::new(move |f| f.text(format_args!("")))),
|
||||
// );
|
||||
|
||||
// let d1 = cx.render(to_lazy_nodes(move |f| {
|
||||
// f.raw_element(
|
||||
// "div",
|
||||
// None,
|
||||
// [],
|
||||
// [],
|
||||
// [
|
||||
// // f.fragment_from_iter(vak),
|
||||
// f.text(format_args!("")),
|
||||
// f.text(format_args!("")),
|
||||
// f.text(format_args!("")),
|
||||
// f.text(format_args!("")),
|
||||
// ],
|
||||
// None,
|
||||
// )
|
||||
// }));
|
||||
|
||||
todo!()
|
||||
// cx.render(LazyNodes::new(move |f| {
|
||||
// f.raw_element(
|
||||
// "div",
|
||||
// None,
|
||||
// [],
|
||||
// [],
|
||||
// [
|
||||
// f.text(format_args!("")),
|
||||
// f.text(format_args!("")),
|
||||
// f.text(format_args!("")),
|
||||
// f.text(format_args!("")),
|
||||
// d1.unwrap(),
|
||||
// ],
|
||||
// None,
|
||||
// )
|
||||
// }))
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
use bumpalo::Bump;
|
||||
|
||||
fn main() {}
|
||||
|
||||
fn build(factory: Factory) {
|
||||
factory.text();
|
||||
div::new(factory)
|
||||
.r#class()
|
||||
.r#tag()
|
||||
.r#type()
|
||||
.add_children()
|
||||
.iter_children()
|
||||
.finish();
|
||||
}
|
||||
|
||||
/// # The `div` element
|
||||
///
|
||||
///
|
||||
/// The <div> HTML element is the generic container for flow content. It has no effect on the content or layout until
|
||||
/// styled in some way using CSS (e.g. styling is directly applied to it, or some kind of layout model like Flexbox is
|
||||
/// applied to its parent element).
|
||||
///
|
||||
/// As a "pure" container, the <div> element does not inherently represent anything. Instead, it's used to group content
|
||||
/// so it can be easily styled using the class or id attributes, marking a section of a document as being written in a
|
||||
/// different language (using the lang attribute), and so on.
|
||||
///
|
||||
/// ## Usage
|
||||
/// ```
|
||||
/// rsx!{
|
||||
/// div { class: "tall", id: "unique id"
|
||||
/// h1 {}
|
||||
/// p {}
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ## Specifications
|
||||
/// - Content categories: Flow content, palpable content.
|
||||
/// - Permitted content: Flow content.
|
||||
/// - Permitted parents: Any element that accepts flow content.
|
||||
#[allow(non_camel_case_types)]
|
||||
struct div {}
|
||||
|
||||
struct h1 {}
|
||||
|
||||
struct h2 {}
|
||||
|
||||
trait BasicElement: Sized {
|
||||
const TagName: &'static str;
|
||||
fn get_bump(&self) -> &Bump;
|
||||
fn new(factory: Factory) -> Self;
|
||||
fn add_children(self) -> Self {
|
||||
self
|
||||
}
|
||||
fn iter_children(self) -> Self {
|
||||
self
|
||||
}
|
||||
fn finish(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl BasicElement for div {
|
||||
const TagName: &'static str = "div";
|
||||
|
||||
fn get_bump(&self) -> &Bump {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn new(_factory: Factory) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl div {
|
||||
fn class(self) -> Self {
|
||||
self
|
||||
}
|
||||
fn tag(self) -> Self {
|
||||
self
|
||||
}
|
||||
fn r#type(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct Factory<'a> {
|
||||
bump: &'a bumpalo::Bump,
|
||||
}
|
||||
|
||||
impl<'a> Factory<'a> {
|
||||
fn text(&self) -> &str {
|
||||
todo!()
|
||||
}
|
||||
fn new_el(&'a self, tag: &'static str) -> ElementBuilder<'a> {
|
||||
ElementBuilder {
|
||||
bump: self.bump,
|
||||
tag,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ElementBuilder<'a> {
|
||||
tag: &'static str,
|
||||
bump: &'a bumpalo::Bump,
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use dioxus::component::Scope;
|
||||
use dioxus::events::on::MouseEvent;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use rand::prelude::*;
|
||||
use std::fmt::Display;
|
||||
|
||||
fn main() {
|
||||
let mut dom = VirtualDom::new(App);
|
||||
let g = dom.rebuild();
|
||||
assert!(g.edits.len() > 1);
|
||||
}
|
||||
|
||||
fn App((cx, props): Scope<()>) -> Element {
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
let rows = (0..10_000_usize).map(|f| {
|
||||
let label = Label::new(&mut rng);
|
||||
rsx! {
|
||||
Row {
|
||||
row_id: f,
|
||||
label: label
|
||||
}
|
||||
}
|
||||
});
|
||||
cx.render(rsx! {
|
||||
table {
|
||||
tbody {
|
||||
{rows}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Props)]
|
||||
struct RowProps {
|
||||
row_id: usize,
|
||||
label: Label,
|
||||
}
|
||||
|
||||
fn Row<'a>((cx, props): Scope<'a, RowProps>) -> Element<'a> {
|
||||
let handler = move |evt: MouseEvent| {
|
||||
let g = evt.button;
|
||||
};
|
||||
cx.render(rsx! {
|
||||
tr {
|
||||
// td { class:"col-md-1", "{props.row_id}" }
|
||||
// td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
|
||||
// a { class: "lbl", "{props.label}" }
|
||||
// }
|
||||
// td { class: "col-md-1"
|
||||
// a { class: "remove", onclick: {handler}
|
||||
// span { class: "glyphicon glyphicon-remove remove" aria_hidden: "true" }
|
||||
// }
|
||||
// }
|
||||
// td { class: "col-md-6" }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
struct Label([&'static str; 3]);
|
||||
|
||||
impl Label {
|
||||
fn new(rng: &mut SmallRng) -> Self {
|
||||
Label([
|
||||
ADJECTIVES.choose(rng).unwrap(),
|
||||
COLOURS.choose(rng).unwrap(),
|
||||
NOUNS.choose(rng).unwrap(),
|
||||
])
|
||||
}
|
||||
}
|
||||
impl Display for Label {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{} {} {}", self.0[0], self.0[1], self.0[2])
|
||||
}
|
||||
}
|
||||
|
||||
static ADJECTIVES: &[&str] = &[
|
||||
"pretty",
|
||||
"large",
|
||||
"big",
|
||||
"small",
|
||||
"tall",
|
||||
"short",
|
||||
"long",
|
||||
"handsome",
|
||||
"plain",
|
||||
"quaint",
|
||||
"clean",
|
||||
"elegant",
|
||||
"easy",
|
||||
"angry",
|
||||
"crazy",
|
||||
"helpful",
|
||||
"mushy",
|
||||
"odd",
|
||||
"unsightly",
|
||||
"adorable",
|
||||
"important",
|
||||
"inexpensive",
|
||||
"cheap",
|
||||
"expensive",
|
||||
"fancy",
|
||||
];
|
||||
|
||||
static COLOURS: &[&str] = &[
|
||||
"red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black",
|
||||
"orange",
|
||||
];
|
||||
|
||||
static NOUNS: &[&str] = &[
|
||||
"table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger",
|
||||
"pizza", "mouse", "keyboard",
|
||||
];
|
||||
@@ -1,148 +0,0 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use dioxus::component::Scope;
|
||||
use dioxus::events::on::MouseEvent;
|
||||
use dioxus::nodes::IntoVNode;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
fn main() {}
|
||||
|
||||
fn html_usage() {
|
||||
let mo = move |_| {};
|
||||
let r = rsx! {
|
||||
div {
|
||||
onclick: move |_| {}
|
||||
onmouseover: {mo}
|
||||
"type": "bar",
|
||||
"hello world"
|
||||
}
|
||||
};
|
||||
|
||||
let items = ["bob", "bill", "jack"];
|
||||
|
||||
let f = items
|
||||
.iter()
|
||||
.filter(|f| f.starts_with('b'))
|
||||
.map(|f| rsx!("hello {f}"));
|
||||
|
||||
// let p = rsx!(div { {f} });
|
||||
}
|
||||
|
||||
static App2: FC<()> = |(cx, _)| cx.render(rsx!("hello world!"));
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
let name = cx.use_state(|| 0);
|
||||
|
||||
cx.render(rsx!(div {
|
||||
h1 {}
|
||||
h2 {}
|
||||
}))
|
||||
};
|
||||
|
||||
pub trait UseState<'a, T: 'static> {
|
||||
fn use_state(self, f: impl FnOnce() -> T) -> &'a T;
|
||||
}
|
||||
impl<'a, T: 'static> UseState<'a, T> for Context<'a> {
|
||||
fn use_state(self, f: impl FnOnce() -> T) -> &'a T {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn App3((cx, props): Scope<()>) -> Element {
|
||||
let p = rsx! {
|
||||
Child {
|
||||
bame: 10,
|
||||
}
|
||||
};
|
||||
todo!()
|
||||
// cx.render(rsx!(Child {
|
||||
// bame: 102,
|
||||
// ..ChildProps { bame: 10 }
|
||||
// }))
|
||||
}
|
||||
|
||||
#[derive(Props, PartialEq, Debug)]
|
||||
struct ChildProps {
|
||||
bame: i32, // children: Children<'a>,
|
||||
}
|
||||
|
||||
fn Child<'a>((cx, props): Scope<'a, ChildProps>) -> Element<'a> {
|
||||
cx.render(rsx!(div {
|
||||
// {props.children}
|
||||
}))
|
||||
}
|
||||
|
||||
// Some(LazyNodes::new(|f| {
|
||||
// //
|
||||
// // let r = f.fragment_from_iter(&props.children);
|
||||
// r
|
||||
// // todo!()
|
||||
// }))
|
||||
// todo!()
|
||||
// rsx!({ Some(p) })
|
||||
// todo!()
|
||||
|
||||
pub struct Children<'a> {
|
||||
children: VNode<'static>,
|
||||
_p: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a> Children<'a> {
|
||||
pub fn new(children: VNode<'a>) -> Self {
|
||||
Self {
|
||||
children: unsafe { std::mem::transmute(children) },
|
||||
_p: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Bapp: FC<()> = |(cx, props)| {
|
||||
let name = cx.use_state(|| 0);
|
||||
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
div {
|
||||
|
||||
}
|
||||
div {
|
||||
|
||||
}
|
||||
}
|
||||
))
|
||||
};
|
||||
|
||||
static Match: FC<()> = |(cx, props)| {
|
||||
//
|
||||
let b: Box<dyn Fn(NodeFactory) -> VNode> = Box::new(|f| todo!());
|
||||
|
||||
let b = match "ag" {
|
||||
"a" => {
|
||||
let __b: Box<dyn FnOnce(NodeFactory) -> VNode> = Box::new(|f: NodeFactory| todo!());
|
||||
__b
|
||||
}
|
||||
_ => {
|
||||
let __b: Box<dyn FnOnce(NodeFactory) -> VNode> = Box::new(|f: NodeFactory| todo!());
|
||||
__b
|
||||
}
|
||||
};
|
||||
|
||||
// let b: Box<dyn Fn(NodeFactory) -> VNode> = match "alph" {
|
||||
// "beta" => Box::new(|f: NodeFactory| {
|
||||
// //
|
||||
// todo!()
|
||||
// }),
|
||||
// _ => Box::new(|f: NodeFactory| {
|
||||
// //
|
||||
// todo!()
|
||||
// }),
|
||||
// };
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
}
|
||||
})
|
||||
};
|
||||
@@ -1,259 +0,0 @@
|
||||
use std::borrow::BorrowMut;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use dioxus::component::Scope;
|
||||
use dioxus::events::on::MouseEvent;
|
||||
use dioxus::nodes::{IntoVNode, VComponent, VFragment, VText};
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
fn main() {}
|
||||
|
||||
fn t() {
|
||||
let g = rsx! {
|
||||
div {
|
||||
div {
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let g = {
|
||||
let ___p: Box<dyn FnOnce(NodeFactory) -> VNode> = Box::new(|__cx: NodeFactory| {
|
||||
use dioxus_elements::{GlobalAttributes, SvgAttributes};
|
||||
__cx.element(dioxus_elements::div, [], [], [], None)
|
||||
});
|
||||
// let __z = ___p as ;
|
||||
// __z
|
||||
};
|
||||
}
|
||||
|
||||
// #[derive(PartialEq, Props)]
|
||||
// struct OurProps {
|
||||
// foo: String,
|
||||
// }
|
||||
|
||||
// fn App<'a>((cx, props): Scope<'a, OurProps>) -> Element<'a> {
|
||||
// let a = rsx! {
|
||||
// div {
|
||||
// "asd"
|
||||
// "{props.foo}"
|
||||
// }
|
||||
// };
|
||||
|
||||
// let p = (0..10).map(|f| {
|
||||
// rsx! {
|
||||
// div {
|
||||
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// let g = match "text" {
|
||||
// "a" => {
|
||||
// rsx!("asd")
|
||||
// }
|
||||
// _ => {
|
||||
// rsx!("asd")
|
||||
// }
|
||||
// };
|
||||
|
||||
// let items = ["bob", "bill", "jack"];
|
||||
|
||||
// let f = items
|
||||
// .iter()
|
||||
// .filter(|f| f.starts_with('b'))
|
||||
// .map(|f| rsx!("hello {f}"));
|
||||
|
||||
// // use dioxus_hooks;
|
||||
// // let g = use_state(|| "hello".to_string());
|
||||
|
||||
// let s: &'a mut String = cx.use_hook(|_| String::new(), |f| f, |_| {});
|
||||
|
||||
// /*
|
||||
// the final closure is allowed to borrow anything provided it
|
||||
// */
|
||||
// // cx.render({
|
||||
// // let p: Option<Box<dyn FnOnce(_) -> _>> = Some(Box::new(move |__cx: NodeFactory| {
|
||||
// // use dioxus_elements::{GlobalAttributes, SvgAttributes};
|
||||
|
||||
// // let props = Child2Props { foo: s };
|
||||
// // let ch: VNode = __cx.component(Child2, props, None, []);
|
||||
// // __cx.element(
|
||||
// // dioxus_elements::div,
|
||||
// // [],
|
||||
// // [],
|
||||
// // [ch],
|
||||
// // // [__cx.component(Child2, fc_to_builder(Child2).foo(s).build(), None, [])],
|
||||
// // None,
|
||||
// // )
|
||||
// // }));
|
||||
// // p
|
||||
// // // let ___p: Box<dyn FnOnce(NodeFactory) -> VNode> = Box::new(move |__cx| {
|
||||
// // // use dioxus_elements::{GlobalAttributes, SvgAttributes};
|
||||
|
||||
// // // let props = Child2Props { foo: s };
|
||||
// // // let ch: VNode = __cx.component(Child2, props, None, []);
|
||||
// // // __cx.element(
|
||||
// // // dioxus_elements::div,
|
||||
// // // [],
|
||||
// // // [],
|
||||
// // // [ch],
|
||||
// // // // [__cx.component(Child2, fc_to_builder(Child2).foo(s).build(), None, [])],
|
||||
// // // None,
|
||||
// // // )
|
||||
// // // });
|
||||
// // // Some(___p)
|
||||
// // })
|
||||
|
||||
// let a = annotate_lazy(move |f| {
|
||||
// //
|
||||
// todo!()
|
||||
// });
|
||||
// let b = annotate_lazy(move |f| {
|
||||
// //
|
||||
// f.text(format_args!("{}", props.foo))
|
||||
// });
|
||||
|
||||
// let c = annotate_lazy(move |f| {
|
||||
// //
|
||||
// f.component(
|
||||
// Child,
|
||||
// OurProps {
|
||||
// //
|
||||
// foo: "hello".to_string(),
|
||||
// },
|
||||
// None,
|
||||
// [],
|
||||
// )
|
||||
// });
|
||||
|
||||
// let st: &'a String = cx.use_hook(|_| "hello".to_string(), |f| f, |_| {});
|
||||
|
||||
// let d = annotate_lazy(move |f| {
|
||||
// //
|
||||
// f.component(
|
||||
// Child2,
|
||||
// Child2Props {
|
||||
// //
|
||||
// foo: st,
|
||||
// },
|
||||
// None,
|
||||
// [],
|
||||
// )
|
||||
// });
|
||||
|
||||
// let e = match "asd" {
|
||||
// b => {
|
||||
// //
|
||||
|
||||
// annotate_lazy(move |f| {
|
||||
// //
|
||||
// f.text(format_args!("{}", props.foo))
|
||||
// })
|
||||
// }
|
||||
// a => {
|
||||
// //
|
||||
|
||||
// annotate_lazy(move |f| {
|
||||
// //
|
||||
// f.text(format_args!("{}", props.foo))
|
||||
// })
|
||||
// }
|
||||
// };
|
||||
|
||||
// cx.render(annotate_lazy(move |f| {
|
||||
// //
|
||||
|
||||
// f.raw_element(
|
||||
// "div",
|
||||
// None,
|
||||
// [],
|
||||
// [],
|
||||
// [
|
||||
// //
|
||||
// f.fragment_from_iter(a),
|
||||
// f.fragment_from_iter(b),
|
||||
// f.fragment_from_iter(c),
|
||||
// f.fragment_from_iter(e),
|
||||
// ],
|
||||
// None,
|
||||
// )
|
||||
// // todo!()
|
||||
// }))
|
||||
// // cx.render(rsx! {
|
||||
// // div {
|
||||
// // div {
|
||||
// // {a}
|
||||
// // // {p}
|
||||
// // // {g}
|
||||
// // // {f}
|
||||
// // }
|
||||
// // // div {
|
||||
// // // "asd"
|
||||
// // // div {
|
||||
// // // "asd"
|
||||
// // // }
|
||||
// // // }
|
||||
// // // Child {
|
||||
// // // foo: "asd".to_string(),
|
||||
// // // }
|
||||
// // Child2 {
|
||||
// // foo: s,
|
||||
// // }
|
||||
// // }
|
||||
// // })
|
||||
// }
|
||||
|
||||
// fn Child((cx, props): Scope<OurProps>) -> Element {
|
||||
// cx.render(rsx! {
|
||||
// div {
|
||||
// div {}
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
#[derive(Props)]
|
||||
struct Child2Props<'a> {
|
||||
foo: &'a String,
|
||||
}
|
||||
|
||||
fn Child2<'a>((cx, props): Scope<'a, Child2Props>) -> Element<'a> {
|
||||
let node = cx
|
||||
.render(rsx! {
|
||||
div {
|
||||
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
ChildrenComp {
|
||||
div {}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Props)]
|
||||
struct ChildrenTest<'a> {
|
||||
children: ScopeChildren<'a>,
|
||||
}
|
||||
|
||||
fn ChildrenComp<'a>((cx, props): Scope<'a, ChildrenTest<'a>>) -> Element<'a> {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
div {
|
||||
{&props.children}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn ChildrenMemo((cx, props): Scope<()>) -> Element {
|
||||
todo!()
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
fn main() {}
|
||||
@@ -1,17 +0,0 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use dioxus_core::{lazynodes::LazyNodes, prelude::*};
|
||||
|
||||
// #[async_std::main]
|
||||
fn main() {
|
||||
static App: FC<()> =
|
||||
|(cx, props)| cx.render(Some(LazyNodes::new(move |f| f.text(format_args!("hello")))));
|
||||
|
||||
let mut dom = VirtualDom::new(App);
|
||||
|
||||
dom.rebuild();
|
||||
|
||||
// let deadline = async_std::task::sleep(Duration::from_millis(50));
|
||||
|
||||
// let _fut = dom.run_with_deadline(|| deadline.);
|
||||
}
|
||||
@@ -5,7 +5,10 @@
|
||||
//! if the type supports PartialEq. The Properties trait is used by the rsx! and html! macros to generate the type-safe builder
|
||||
//! that ensures compile-time required and optional fields on cx.
|
||||
|
||||
use crate::innerlude::{Context, Element, VNode};
|
||||
use crate::{
|
||||
innerlude::{Context, Element, VAnchor, VFragment, VNode},
|
||||
LazyNodes, ScopeChildren,
|
||||
};
|
||||
/// A component is a wrapper around a Context and some Props that share a lifetime
|
||||
///
|
||||
///
|
||||
@@ -41,23 +44,39 @@ use crate::innerlude::{Context, Element, VNode};
|
||||
pub type Scope<'a, T> = (Context<'a>, &'a T);
|
||||
|
||||
pub struct FragmentProps<'a> {
|
||||
childen: &'a VNode<'a>,
|
||||
children: ScopeChildren<'a>,
|
||||
}
|
||||
pub struct FragmentPropsBuilder<'a> {
|
||||
childen: Option<&'a VNode<'a>>,
|
||||
|
||||
pub struct FragmentBuilder<'a, const BUILT: bool> {
|
||||
children: Option<ScopeChildren<'a>>,
|
||||
}
|
||||
impl<'a> FragmentBuilder<'a, false> {
|
||||
pub fn children(mut self, children: ScopeChildren<'a>) -> FragmentBuilder<'a, true> {
|
||||
FragmentBuilder {
|
||||
children: Some(children),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const A: bool> FragmentBuilder<'a, A> {
|
||||
pub fn build(self) -> FragmentProps<'a> {
|
||||
FragmentProps {
|
||||
children: self.children.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Properties for FragmentProps<'a> {
|
||||
type Builder = FragmentPropsBuilder<'a>;
|
||||
type Builder = FragmentBuilder<'a, false>;
|
||||
|
||||
const IS_STATIC: bool = false;
|
||||
|
||||
fn builder() -> Self::Builder {
|
||||
todo!()
|
||||
FragmentBuilder { children: None }
|
||||
}
|
||||
|
||||
unsafe fn memoize(&self, other: &Self) -> bool {
|
||||
todo!()
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,8 +102,10 @@ impl<'a> Properties for FragmentProps<'a> {
|
||||
/// You want to use this free-function when your fragment needs a key and simply returning multiple nodes from rsx! won't cut it.
|
||||
///
|
||||
#[allow(non_upper_case_globals, non_snake_case)]
|
||||
pub fn Fragment<'a>((_, props): Scope<'a, FragmentProps<'a>>) -> Element<'a> {
|
||||
Some(props.childen.decouple())
|
||||
pub fn Fragment<'a>((cx, props): Scope<'a, FragmentProps<'a>>) -> Element<'a> {
|
||||
cx.render(Some(LazyNodes::new(|f| {
|
||||
f.fragment_from_iter(&props.children)
|
||||
})))
|
||||
}
|
||||
|
||||
/// Every "Props" used for a component must implement the `Properties` trait. This trait gives some hints to Dioxus
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
//! The logic for this was borrowed from https://docs.rs/stack_dst/0.6.1/stack_dst/. Unfortunately, this crate does not
|
||||
//! support non-static closures, so we've implemented the core logic of `ValueA` in this module.
|
||||
|
||||
use crate::innerlude::{NodeFactory, VNode};
|
||||
use crate::prelude::{NodeFactory, VNode};
|
||||
use std::mem;
|
||||
|
||||
/// A concrete type provider for closures that build VNode structures.
|
||||
@@ -27,7 +27,7 @@ pub struct LazyNodes<'a, 'b> {
|
||||
inner: StackNodeStorage<'a, 'b>,
|
||||
}
|
||||
|
||||
type StackHeapSize = [usize; 12];
|
||||
type StackHeapSize = [usize; 0];
|
||||
|
||||
enum StackNodeStorage<'a, 'b> {
|
||||
Stack(LazyStack),
|
||||
@@ -77,7 +77,7 @@ impl<'a, 'b> LazyNodes<'a, 'b> {
|
||||
}
|
||||
} else {
|
||||
log::debug!("lazy nodes fits on stack!");
|
||||
let mut buf: StackHeapSize = [0; 12];
|
||||
let mut buf: StackHeapSize = StackHeapSize::default();
|
||||
|
||||
assert!(info.len() + round_to_words(size) <= buf.as_ref().len());
|
||||
|
||||
@@ -97,6 +97,8 @@ impl<'a, 'b> LazyNodes<'a, 'b> {
|
||||
*dataptr.add(i) = *src_ptr.add(i);
|
||||
}
|
||||
|
||||
std::mem::forget(val);
|
||||
|
||||
Self {
|
||||
inner: StackNodeStorage::Stack(LazyStack { _align: [], buf }),
|
||||
}
|
||||
|
||||
@@ -65,9 +65,9 @@ pub(crate) mod innerlude {
|
||||
}
|
||||
|
||||
pub use crate::innerlude::{
|
||||
Context, DioxusElement, DomEdit, Element, ElementId, EventPriority, MountType, Mutations,
|
||||
NodeFactory, Properties, SchedulerMsg, ScopeChildren, ScopeId, SuspendedContext, TaskHandle,
|
||||
TestDom, ThreadsafeVirtualDom, UserEvent, VNode, VirtualDom, FC,
|
||||
Context, DioxusElement, DomEdit, Element, ElementId, EventPriority, LazyNodes, MountType,
|
||||
Mutations, NodeFactory, Properties, SchedulerMsg, ScopeChildren, ScopeId, SuspendedContext,
|
||||
TaskHandle, TestDom, ThreadsafeVirtualDom, UserEvent, VNode, VirtualDom, FC,
|
||||
};
|
||||
|
||||
pub mod prelude {
|
||||
|
||||
@@ -765,6 +765,9 @@ impl<'a> ScopeChildren<'a> {
|
||||
pub fn new(root: VNode<'a>) -> Self {
|
||||
Self { root: Some(root) }
|
||||
}
|
||||
pub fn new_option(root: Option<VNode<'a>>) -> Self {
|
||||
Self { root }
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for &ScopeChildren<'_> {
|
||||
@@ -773,7 +776,7 @@ impl IntoIterator for &ScopeChildren<'_> {
|
||||
type IntoIter = std::iter::Once<Self>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
todo!()
|
||||
std::iter::once(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -303,27 +303,8 @@ fn anchors() {
|
||||
#[test]
|
||||
fn suspended() {
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
let val = use_suspense(
|
||||
cx,
|
||||
|| async {
|
||||
//
|
||||
},
|
||||
|cx, p| todo!(),
|
||||
// |cx, p| rsx! { "hi "},
|
||||
);
|
||||
let val = use_suspense(cx, || async {}, |cx, p| todo!());
|
||||
|
||||
// let prom = use_task(fetch());
|
||||
|
||||
// Value {
|
||||
// a: value.await,
|
||||
// b: value.await,
|
||||
// f: a.await
|
||||
// div {
|
||||
// div {
|
||||
// hidden: should_hide.await,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
cx.render(rsx! { {val} })
|
||||
};
|
||||
|
||||
|
||||
@@ -34,6 +34,3 @@ tokio_runtime = ["tokio"]
|
||||
dioxus-html = { path = "../html" }
|
||||
dioxus-hooks = { path = "../hooks" }
|
||||
simple_logger = "1.13.0"
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
@@ -1,5 +0,0 @@
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
fn main() {}
|
||||
@@ -1,109 +0,0 @@
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_hooks::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
fn main() {
|
||||
dioxus_desktop::launch(App, |c| c)
|
||||
}
|
||||
|
||||
enum Scene {
|
||||
ClientsList,
|
||||
NewClientForm,
|
||||
Settings,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Client {
|
||||
pub first_name: String,
|
||||
pub last_name: String,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, _)| {
|
||||
let mut scene = use_state(cx, || Scene::ClientsList);
|
||||
let clients = use_ref(cx, || vec![] as Vec<Client>);
|
||||
|
||||
let mut firstname = use_state(cx, String::new);
|
||||
let mut lastname = use_state(cx, String::new);
|
||||
let mut description = use_state(cx, String::new);
|
||||
|
||||
let scene = match scene.get() {
|
||||
Scene::ClientsList => {
|
||||
rsx!(cx, div { class: "crm"
|
||||
h2 { "List of clients" margin_bottom: "10px" }
|
||||
div { class: "clients" margin_left: "10px"
|
||||
{clients.read().iter().map(|client| rsx!(
|
||||
div { class: "client" style: "margin-bottom: 50px"
|
||||
p { "First Name: {client.first_name}" }
|
||||
p { "Last Name: {client.last_name}" }
|
||||
p {"Description: {client.description}"}
|
||||
})
|
||||
)}
|
||||
}
|
||||
button { class: "pure-button pure-button-primary" onclick: move |_| scene.set(Scene::NewClientForm), "Add New" }
|
||||
button { class: "pure-button" onclick: move |_| scene.set(Scene::Settings), "Settings" }
|
||||
})
|
||||
}
|
||||
Scene::NewClientForm => {
|
||||
let add_new = move |_| {
|
||||
clients.write().push(Client {
|
||||
description: (*description).clone(),
|
||||
first_name: (*firstname).clone(),
|
||||
last_name: (*lastname).clone(),
|
||||
});
|
||||
description.set(String::new());
|
||||
firstname.set(String::new());
|
||||
lastname.set(String::new());
|
||||
};
|
||||
rsx!(cx, div { class: "crm"
|
||||
h2 {"Add new client" margin_bottom: "10px" }
|
||||
form { class: "pure-form"
|
||||
input { class: "new-client firstname" placeholder: "First name" value: "{firstname}"
|
||||
oninput: move |evt| firstname.set(evt.value)
|
||||
}
|
||||
input { class: "new-client lastname" placeholder: "Last name" value: "{lastname}"
|
||||
oninput: move |evt| lastname.set(evt.value)
|
||||
}
|
||||
textarea { class: "new-client description" placeholder: "Description" value: "{description}"
|
||||
oninput: move |evt| description.set(evt.value)
|
||||
}
|
||||
}
|
||||
button { class: "pure-button pure-button-primary", onclick: {add_new}, "Add New" }
|
||||
button { class: "pure-button", onclick: move |_| scene.set(Scene::ClientsList), "Go Back" }
|
||||
})
|
||||
}
|
||||
Scene::Settings => {
|
||||
rsx!(cx, div {
|
||||
h2 { "Settings" margin_bottom: "10px" }
|
||||
button {
|
||||
background: "rgb(202, 60, 60)"
|
||||
class: "pure-button pure-button-primary"
|
||||
onclick: move |_| {
|
||||
clients.write().clear();
|
||||
scene.set(Scene::ClientsList);
|
||||
},
|
||||
"Remove all clients"
|
||||
}
|
||||
button {
|
||||
class: "pure-button pure-button-primary"
|
||||
onclick: move |_| scene.set(Scene::ClientsList),
|
||||
"Go Back"
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
rsx!(cx, body {
|
||||
link {
|
||||
rel: "stylesheet"
|
||||
href: "https://unpkg.com/purecss@2.0.6/build/pure-min.css"
|
||||
integrity: "sha384-Uu6IeWbM+gzNVXJcM9XV3SohHtmWE+3VGi496jvgX1jyvDTXfdK+rfZc8C1Aehk5"
|
||||
crossorigin: "anonymous"
|
||||
}
|
||||
margin_left: "35%"
|
||||
h1 {"Dioxus CRM Example"}
|
||||
{scene}
|
||||
})
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
fn main() {
|
||||
dioxus_desktop::launch(App, |c| c);
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
"hello world!"
|
||||
}
|
||||
{(0..10).map(|f| rsx!( div {"abc {f}"}))}
|
||||
))
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_hooks::*;
|
||||
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
fn main() {}
|
||||
@@ -1 +0,0 @@
|
||||
fn main() {}
|
||||
@@ -1,379 +0,0 @@
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: none;
|
||||
font-size: 100%;
|
||||
vertical-align: baseline;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
color: inherit;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
body {
|
||||
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
line-height: 1.4em;
|
||||
background: #f5f5f5;
|
||||
color: #4d4d4d;
|
||||
min-width: 230px;
|
||||
max-width: 550px;
|
||||
margin: 0 auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todoapp {
|
||||
background: #fff;
|
||||
margin: 130px 0 40px 0;
|
||||
position: relative;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
|
||||
0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.todoapp input::-webkit-input-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp input::-moz-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp input::input-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp h1 {
|
||||
position: absolute;
|
||||
top: -155px;
|
||||
width: 100%;
|
||||
font-size: 100px;
|
||||
font-weight: 100;
|
||||
text-align: center;
|
||||
color: rgba(175, 47, 47, 0.15);
|
||||
-webkit-text-rendering: optimizeLegibility;
|
||||
-moz-text-rendering: optimizeLegibility;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
.new-todo,
|
||||
.edit {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
font-size: 24px;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
line-height: 1.4em;
|
||||
border: 0;
|
||||
color: inherit;
|
||||
padding: 6px;
|
||||
border: 1px solid #999;
|
||||
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
|
||||
box-sizing: border-box;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.new-todo {
|
||||
padding: 16px 16px 16px 60px;
|
||||
border: none;
|
||||
background: rgba(0, 0, 0, 0.003);
|
||||
box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
.main {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.toggle-all {
|
||||
text-align: center;
|
||||
border: none;
|
||||
/* Mobile Safari */
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.toggle-all+label {
|
||||
width: 60px;
|
||||
height: 34px;
|
||||
font-size: 0;
|
||||
position: absolute;
|
||||
top: -52px;
|
||||
left: -13px;
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.toggle-all+label:before {
|
||||
content: '❯';
|
||||
font-size: 22px;
|
||||
color: #e6e6e6;
|
||||
padding: 10px 27px 10px 27px;
|
||||
}
|
||||
|
||||
.toggle-all:checked+label:before {
|
||||
color: #737373;
|
||||
}
|
||||
|
||||
.todo-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.todo-list li {
|
||||
position: relative;
|
||||
font-size: 24px;
|
||||
border-bottom: 1px solid #ededed;
|
||||
}
|
||||
|
||||
.todo-list li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.todo-list li.editing {
|
||||
border-bottom: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.todo-list li.editing .edit {
|
||||
display: block;
|
||||
width: 506px;
|
||||
padding: 12px 16px;
|
||||
margin: 0 0 0 43px;
|
||||
}
|
||||
|
||||
.todo-list li.editing .view {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle {
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
/* auto, since non-WebKit browsers doesn't support input styling */
|
||||
height: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto 0;
|
||||
border: none;
|
||||
/* Mobile Safari */
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.todo-list li .toggle+label {
|
||||
/*
|
||||
Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
|
||||
IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/
|
||||
*/
|
||||
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center left;
|
||||
}
|
||||
|
||||
.todo-list li .toggle:checked+label {
|
||||
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E');
|
||||
}
|
||||
|
||||
.todo-list li label {
|
||||
word-break: break-all;
|
||||
padding: 15px 15px 15px 60px;
|
||||
display: block;
|
||||
line-height: 1.2;
|
||||
transition: color 0.4s;
|
||||
}
|
||||
|
||||
.todo-list li.completed label {
|
||||
color: #d9d9d9;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.todo-list li .destroy {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
bottom: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: auto 0;
|
||||
font-size: 30px;
|
||||
color: #cc9a9a;
|
||||
margin-bottom: 11px;
|
||||
transition: color 0.2s ease-out;
|
||||
}
|
||||
|
||||
.todo-list li .destroy:hover {
|
||||
color: #af5b5e;
|
||||
}
|
||||
|
||||
.todo-list li .destroy:after {
|
||||
content: '×';
|
||||
}
|
||||
|
||||
.todo-list li:hover .destroy {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.todo-list li .edit {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todo-list li.editing:last-child {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
color: #777;
|
||||
padding: 10px 15px;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.footer:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
|
||||
0 8px 0 -3px #f6f6f6,
|
||||
0 9px 1px -3px rgba(0, 0, 0, 0.2),
|
||||
0 16px 0 -6px #f6f6f6,
|
||||
0 17px 2px -6px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.todo-count {
|
||||
float: left;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.todo-count strong {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.filters {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.filters li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.filters li a {
|
||||
color: inherit;
|
||||
margin: 3px;
|
||||
padding: 3px 7px;
|
||||
text-decoration: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.filters li a:hover {
|
||||
border-color: rgba(175, 47, 47, 0.1);
|
||||
}
|
||||
|
||||
.filters li a.selected {
|
||||
border-color: rgba(175, 47, 47, 0.2);
|
||||
}
|
||||
|
||||
.clear-completed,
|
||||
html .clear-completed:active {
|
||||
float: right;
|
||||
position: relative;
|
||||
line-height: 20px;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.clear-completed:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin: 65px auto 0;
|
||||
color: #bfbfbf;
|
||||
font-size: 10px;
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info p {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.info a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.info a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/*
|
||||
Hack to remove background from Mobile Safari.
|
||||
Can't use it globally since it destroys checkboxes in Firefox
|
||||
*/
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
|
||||
.toggle-all,
|
||||
.todo-list li .toggle {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle {
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 430px) {
|
||||
.footer {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.filters {
|
||||
bottom: 10px;
|
||||
}
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
#![allow(non_upper_case_globals, non_snake_case)]
|
||||
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_hooks::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use simple_logger::SimpleLogger;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn main() {
|
||||
if cfg!(debug_assertions) {
|
||||
SimpleLogger::new().init().unwrap();
|
||||
}
|
||||
|
||||
dioxus_desktop::launch(App, |c| c)
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum FilterState {
|
||||
All,
|
||||
Active,
|
||||
Completed,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct TodoItem {
|
||||
pub id: u32,
|
||||
pub checked: bool,
|
||||
pub contents: String,
|
||||
}
|
||||
pub type Todos = HashMap<u32, TodoItem>;
|
||||
|
||||
pub static App: FC<()> = |(cx, _)| {
|
||||
// Share our TodoList to the todos themselves
|
||||
use_provide_state(cx, || Todos::new());
|
||||
|
||||
// Save state for the draft, filter
|
||||
let mut draft = use_state(cx, || "".to_string());
|
||||
let mut filter = use_state(cx, || FilterState::All);
|
||||
let mut todo_id = use_state(cx, || 0);
|
||||
|
||||
// Consume the todos
|
||||
let todos = use_shared_state::<Todos>(cx)?;
|
||||
|
||||
// Filter the todos based on the filter state
|
||||
let mut filtered_todos = todos
|
||||
.read()
|
||||
.iter()
|
||||
.filter(|(_, item)| match *filter {
|
||||
FilterState::All => true,
|
||||
FilterState::Active => !item.checked,
|
||||
FilterState::Completed => item.checked,
|
||||
})
|
||||
.map(|f| *f.0)
|
||||
.collect::<Vec<_>>();
|
||||
filtered_todos.sort_unstable();
|
||||
|
||||
// Define the actions to manage the todolist
|
||||
let mut submit_todo = move || {
|
||||
if !draft.is_empty() {
|
||||
todos.write().insert(
|
||||
*todo_id,
|
||||
TodoItem {
|
||||
id: *todo_id,
|
||||
checked: false,
|
||||
contents: draft.get().clone(),
|
||||
},
|
||||
);
|
||||
todo_id += 1;
|
||||
draft.set("".to_string());
|
||||
}
|
||||
};
|
||||
let clear_completed = move || {
|
||||
todos.write().retain(|_, todo| todo.checked == false);
|
||||
};
|
||||
|
||||
// Some assists in actually rendering the content
|
||||
let show_clear_completed = todos.read().values().any(|todo| todo.checked);
|
||||
let items_left = filtered_todos.len();
|
||||
let item_text = match items_left {
|
||||
1 => "item",
|
||||
_ => "items",
|
||||
};
|
||||
|
||||
cx.render(rsx!{
|
||||
section { class: "todoapp"
|
||||
style { {[include_str!("./todomvc.css")]} }
|
||||
div {
|
||||
header { class: "header"
|
||||
h1 {"todos"}
|
||||
input {
|
||||
class: "new-todo"
|
||||
placeholder: "What needs to be done?"
|
||||
value: "{draft}"
|
||||
autofocus: "true"
|
||||
oninput: move |evt| draft.set(evt.value.clone())
|
||||
onkeydown: move |evt| {
|
||||
if evt.key == "Enter" {
|
||||
submit_todo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ul { class: "todo-list"
|
||||
{filtered_todos.iter().map(|id| rsx!(TodoEntry { key: "{id}", id: *id }))}
|
||||
}
|
||||
{(!todos.read().is_empty()).then(|| rsx!(
|
||||
footer { class: "footer"
|
||||
span { class: "todo-count" strong {"{items_left} "} span {"{item_text} left"} }
|
||||
ul { class: "filters"
|
||||
li { class: "All", a { onclick: move |_| filter.set(FilterState::All), "All" }}
|
||||
li { class: "Active", a { onclick: move |_| filter.set(FilterState::Active), "Active" }}
|
||||
li { class: "Completed", a { onclick: move |_| filter.set(FilterState::Completed), "Completed" }}
|
||||
}
|
||||
{(show_clear_completed).then(|| rsx!(
|
||||
button { class: "clear-completed", onclick: move |_| clear_completed(),
|
||||
"Clear completed"
|
||||
}
|
||||
))}
|
||||
}
|
||||
))}
|
||||
}
|
||||
}
|
||||
footer { class: "info"
|
||||
p {"Double-click to edit a todo"}
|
||||
p { "Created by ", a { "jkelleyrtp", href: "http://github.com/jkelleyrtp/" }}
|
||||
p { "Part of ", a { "TodoMVC", href: "http://todomvc.com" }}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
#[derive(PartialEq, Props)]
|
||||
pub struct TodoEntryProps {
|
||||
id: u32,
|
||||
}
|
||||
|
||||
pub fn TodoEntry((cx, props): Scope<TodoEntryProps>) -> Element {
|
||||
let todos = use_shared_state::<Todos>(cx)?;
|
||||
|
||||
let _todos = todos.read();
|
||||
let todo = _todos.get(&props.id)?;
|
||||
|
||||
let is_editing = use_state(cx, || false);
|
||||
let completed = if todo.checked { "completed" } else { "" };
|
||||
|
||||
cx.render(rsx!{
|
||||
li { class: "{completed}"
|
||||
div { class: "view"
|
||||
input { class: "toggle" r#type: "checkbox" id: "cbg-{todo.id}" checked: "{todo.checked}"
|
||||
onchange: move |evt| {
|
||||
todos.write().get_mut(&props.id).map(|todo| todo.checked = evt.value.parse().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
label { r#for: "cbg-{todo.id}" pointer_events: "none"
|
||||
"{todo.contents}"
|
||||
}
|
||||
|
||||
{is_editing.then(|| rsx!{
|
||||
input { value: "{todo.contents}"
|
||||
oninput: move |evt| {
|
||||
todos.write().get_mut(&props.id).map(|todo| todo.contents = evt.value.clone());
|
||||
},
|
||||
}
|
||||
})}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::cell::RefCell;
|
||||
|
||||
use dioxus::prelude::Scope;
|
||||
use dioxus::ScopeChildren;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::{Context, Element, LazyNodes, NodeFactory, Properties};
|
||||
use dioxus_core_macro::Props;
|
||||
@@ -42,6 +43,8 @@ pub struct WebviewWindowProps<'a> {
|
||||
|
||||
/// focuse me
|
||||
onfocused: &'a dyn FnMut(()),
|
||||
|
||||
children: ScopeChildren<'a>,
|
||||
}
|
||||
|
||||
/// A handle to a
|
||||
@@ -70,9 +73,10 @@ pub fn WebviewWindow<'a>((cx, props): Scope<'a, WebviewWindowProps>) -> Element<
|
||||
);
|
||||
|
||||
// render the children directly
|
||||
cx.render(LazyNodes::new(move |f: NodeFactory| {
|
||||
f.fragment_from_iter(cx.children())
|
||||
}))
|
||||
todo!()
|
||||
// cx.render(LazyNodes::new(move |f: NodeFactory| {
|
||||
// f.fragment_from_iter(cx.children())
|
||||
// }))
|
||||
}
|
||||
|
||||
pub struct WindowHandle {}
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
position: fixed;
|
||||
}
|
||||
</style> -->
|
||||
<link rel="stylesheet" href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css">
|
||||
<script src="https://cdn.plot.ly/plotly-1.52.3.min.js"></script>
|
||||
</head>
|
||||
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ use serde::{Deserialize, Serialize};
|
||||
pub use wry;
|
||||
|
||||
use wry::application::accelerator::{Accelerator, SysMods};
|
||||
use wry::application::event::{Event, StartCause, WindowEvent};
|
||||
use wry::application::event::{ElementState, Event, StartCause, WindowEvent};
|
||||
use wry::application::event_loop::{self, ControlFlow, EventLoop};
|
||||
use wry::application::keyboard::KeyCode;
|
||||
use wry::application::keyboard::{Key, KeyCode, ModifiersState};
|
||||
use wry::application::menu::{MenuBar, MenuItem, MenuItemAttributes};
|
||||
use wry::application::window::Fullscreen;
|
||||
use wry::webview::{WebView, WebViewBuilder};
|
||||
@@ -94,6 +94,11 @@ pub fn run<T: 'static + Send + Sync>(
|
||||
|
||||
let props_shared = Cell::new(Some(props));
|
||||
|
||||
// create local modifier state
|
||||
let mut modifiers = ModifiersState::default();
|
||||
|
||||
let quit_hotkey = Accelerator::new(SysMods::Cmd, KeyCode::KeyQ);
|
||||
|
||||
event_loop.run(move |event, event_loop, control_flow| {
|
||||
*control_flow = ControlFlow::Wait;
|
||||
|
||||
@@ -112,10 +117,8 @@ pub fn run<T: 'static + Send + Sync>(
|
||||
first_menu.add_native_item(MenuItem::HideOthers);
|
||||
first_menu.add_native_item(MenuItem::ShowAll);
|
||||
|
||||
let quit_item = first_menu.add_item(
|
||||
MenuItemAttributes::new("Quit")
|
||||
.with_accelerators(&Accelerator::new(SysMods::Cmd, KeyCode::KeyQ)),
|
||||
);
|
||||
first_menu.add_native_item(MenuItem::Quit);
|
||||
first_menu.add_native_item(MenuItem::CloseWindow);
|
||||
|
||||
// create second menu
|
||||
let mut second_menu = MenuBar::new();
|
||||
@@ -129,6 +132,7 @@ pub fn run<T: 'static + Send + Sync>(
|
||||
menu_bar_menu.add_submenu("Second menu", true, second_menu);
|
||||
|
||||
let window = WindowBuilder::new()
|
||||
.with_maximized(true)
|
||||
.with_menu(menu_bar_menu)
|
||||
.with_title("Dioxus App")
|
||||
.build(event_loop)
|
||||
@@ -197,6 +201,37 @@ pub fn run<T: 'static + Send + Sync>(
|
||||
event, window_id, ..
|
||||
} => match event {
|
||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||
WindowEvent::Destroyed { .. } => {
|
||||
webviews.remove(&window_id);
|
||||
if webviews.is_empty() {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
}
|
||||
}
|
||||
// catch only pressed event
|
||||
WindowEvent::KeyboardInput { event, .. } => {
|
||||
log::debug!("keybowrd input");
|
||||
if quit_hotkey.matches(&modifiers, &event.physical_key) {
|
||||
log::debug!("quitting");
|
||||
|
||||
webviews.remove(&window_id);
|
||||
if webviews.is_empty() {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
}
|
||||
}
|
||||
|
||||
// println!(
|
||||
// "KeyEvent: `Shift` + `1` | logical_key: {:?}",
|
||||
// &event.logical_key
|
||||
// );
|
||||
// we can match manually without `Accelerator`
|
||||
|
||||
// else if event.key_without_modifiers() == Key::Character("1")
|
||||
// && modifiers.is_empty()
|
||||
// {
|
||||
// println!("KeyEvent: `1`");
|
||||
// }
|
||||
}
|
||||
|
||||
WindowEvent::Resized(_) | WindowEvent::Moved(_) => {
|
||||
if let Some(view) = webviews.get_mut(&window_id) {
|
||||
let _ = view.resize();
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
fn main() {}
|
||||
|
||||
// struct CompState {
|
||||
// tasks: Vec<()>,
|
||||
// }
|
||||
// enum Actions {
|
||||
// Add,
|
||||
// MoveUp,
|
||||
// MoveDown,
|
||||
// Remvoe,
|
||||
// }
|
||||
|
||||
// static Component: FC<()> = |(cx, props)|{
|
||||
// let (tasks, dispatch) = use_reducer(
|
||||
// cx,
|
||||
// || CompState { tasks: Vec::new() },
|
||||
// |state, action: Actions| match action {
|
||||
// Actions::Add => state,
|
||||
// Actions::MoveUp => state,
|
||||
// Actions::MoveDown => state,
|
||||
// Actions::Remvoe => state,
|
||||
// },
|
||||
// );
|
||||
|
||||
// let tasklist = { (0..10).map(|f| html! { <li></li> }) }.collect::<Vec<_>>();
|
||||
|
||||
// html! {
|
||||
// <div>
|
||||
// <div>
|
||||
// <h1>"Tasks: "</h1>
|
||||
// <ul>
|
||||
// {tasklist}
|
||||
// </ul>
|
||||
// </div>
|
||||
// <div>
|
||||
// <button onclick=|_| dispatch(Action::Add)>{"Add"}</button>
|
||||
// <button onclick=|_| dispatch(Action::MoveUp)>{"MoveUp"}</button>
|
||||
// <button onclick=|_| dispatch(Action::MoveDown)>{"MoveDown"}</button>
|
||||
// <button onclick=|_| dispatch(Action::Remvoe)>{"Remvoe"}</button>
|
||||
// </div>
|
||||
// </div>
|
||||
// }
|
||||
// };
|
||||
|
||||
// fn use_reducer<Props, State, Action>(
|
||||
// cx: &mut Context<Props>,
|
||||
// init: fn() -> State,
|
||||
// reducer: fn(State, Action) -> State,
|
||||
// ) -> (State, impl Fn(Action)) {
|
||||
// let ii = init();
|
||||
// (ii, |_| {})
|
||||
// }
|
||||
@@ -1 +0,0 @@
|
||||
fn main() {}
|
||||
@@ -126,7 +126,7 @@ impl<'a, T: 'static> UseSharedState<'a, T> {
|
||||
///
|
||||
///
|
||||
/// TODO: We prevent unncessary notifications only in the hook, but we should figure out some more global lock
|
||||
pub fn write(&mut self) -> RefMut<'_, T> {
|
||||
pub fn write(&self) -> RefMut<'_, T> {
|
||||
self.cx.needs_update();
|
||||
self.notify_consumers();
|
||||
self.value.borrow_mut()
|
||||
|
||||
@@ -102,7 +102,7 @@ impl<'a, T: 'static> UseState<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, new_val: T) {
|
||||
pub fn set(&self, new_val: T) {
|
||||
*self.inner.wip.borrow_mut() = Some(new_val);
|
||||
self.needs_update();
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {}
|
||||
|
||||
enum Routes {
|
||||
Home,
|
||||
Blog,
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
let route = use_router::<Routes>(cx);
|
||||
|
||||
let content = match route {
|
||||
Routes::Home => rsx!(Home {}),
|
||||
Routes::Blog => rsx!(Blog {}),
|
||||
};
|
||||
|
||||
cx.render(rsx! {
|
||||
{content}
|
||||
})
|
||||
};
|
||||
|
||||
fn use_router<P>(cx: Context) -> &P {
|
||||
todo!()
|
||||
}
|
||||
|
||||
static Home: FC<()> = |(cx, props)| todo!();
|
||||
static Blog: FC<()> = |(cx, props)| todo!();
|
||||
@@ -1,88 +0,0 @@
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_router::{use_router, Link, Routable};
|
||||
|
||||
fn main() {
|
||||
dbg!(App as *const fn());
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub enum Route {
|
||||
// #[at("/")]
|
||||
Home,
|
||||
|
||||
// #[at("/:id")]
|
||||
AllUsers { page: u32 },
|
||||
|
||||
// #[at("/:id")]
|
||||
User { id: u32 },
|
||||
|
||||
// #[at("/:id")]
|
||||
BlogList { page: u32 },
|
||||
|
||||
// #[at("/:id")]
|
||||
BlogPost { post_id: u32 },
|
||||
|
||||
// #[at("/404")]
|
||||
// #[not_found]
|
||||
NotFound,
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
let route = use_router(cx, Route::parse)?;
|
||||
|
||||
cx.render(rsx! {
|
||||
nav {
|
||||
Link { to: Route::Home, "Go home!" }
|
||||
Link { to: Route::AllUsers { page: 0 }, "List all users" }
|
||||
Link { to: Route::BlogList { page: 0 }, "Blog posts" }
|
||||
}
|
||||
{match route {
|
||||
Route::Home => rsx!("Home"),
|
||||
Route::AllUsers { page } => rsx!("All users - page {page}"),
|
||||
Route::User { id } => rsx!("User - id: {id}"),
|
||||
Route::BlogList { page } => rsx!("Blog posts - page {page}"),
|
||||
Route::BlogPost { post_id } => rsx!("Blog post - post {post_id}"),
|
||||
Route::NotFound => rsx!("Not found"),
|
||||
}}
|
||||
footer {}
|
||||
})
|
||||
};
|
||||
|
||||
impl Route {
|
||||
// Generate the appropriate route from the "tail" end of the URL
|
||||
fn parse(url: &str) -> Self {
|
||||
use Route::*;
|
||||
match url {
|
||||
"/" => Home,
|
||||
"/users" => AllUsers { page: 1 },
|
||||
"/users/:page" => AllUsers { page: 1 },
|
||||
"/users/:page/:id" => User { id: 1 },
|
||||
"/blog" => BlogList { page: 1 },
|
||||
"/blog/:page" => BlogList { page: 1 },
|
||||
"/blog/:page/:id" => BlogPost { post_id: 1 },
|
||||
_ => NotFound,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Routable for Route {
|
||||
fn from_path(path: &str, params: &std::collections::HashMap<&str, &str>) -> Option<Self> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn to_path(&self) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn routes() -> Vec<&'static str> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn not_found_route() -> Option<Self> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn recognize(pathname: &str) -> Option<Self> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
use dioxus::virtual_dom::VirtualDom;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
fn main() {
|
||||
let mut dom = VirtualDom::new(App);
|
||||
dom.rebuild();
|
||||
println!(
|
||||
"{}",
|
||||
dioxus_ssr::render_vdom(&dom, |c| c.newline(true).indent(true))
|
||||
)
|
||||
}
|
||||
|
||||
pub static App: FC<()> = |(cx, props)| {
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
class: "overflow-hidden"
|
||||
ul {
|
||||
{(0..10).map(|i| rsx!{ li { class: "flex flex-col", "entry: {i}"}})}
|
||||
}
|
||||
"hello world!"
|
||||
}
|
||||
))
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
//! Example: realworld usage of hydration
|
||||
//!
|
||||
//!
|
||||
use dioxus::virtual_dom::VirtualDom;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_hooks::use_state;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
fn main() {}
|
||||
@@ -1,298 +0,0 @@
|
||||
<!-- a js-only interpreter for the dioxus patch stream :) -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
|
||||
<meta charset="UTF-8" />
|
||||
<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>hello dioxus</div>
|
||||
</body>
|
||||
<script>
|
||||
class Interpreter {
|
||||
constructor(root) {
|
||||
this.stack = [root];
|
||||
}
|
||||
|
||||
top() {
|
||||
return this.stack[this.stack.length - 1];
|
||||
}
|
||||
|
||||
pop() {
|
||||
return this.stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
class OPTABLE {
|
||||
// 0
|
||||
SetText(edit, interp) {
|
||||
interp.top(interp.stack).textContent = edit.text;
|
||||
}
|
||||
// 1
|
||||
RemoveSelfAndNextSiblings(edit) {
|
||||
const node = interp.pop();
|
||||
let sibling = node.nextSibling;
|
||||
while (sibling) {
|
||||
const temp = sibling.nextSibling;
|
||||
sibling.remove();
|
||||
sibling = temp;
|
||||
}
|
||||
node.remove();
|
||||
}
|
||||
|
||||
// 2
|
||||
ReplaceWith(edit, interp) {
|
||||
const newNode = interp.pop();
|
||||
const oldNode = interp.pop();
|
||||
oldNode.replaceWith(newNode);
|
||||
interp.stack.push(newNode);
|
||||
}
|
||||
|
||||
// 3
|
||||
SetAttribute(edit, interp) {
|
||||
const name = edit.name;
|
||||
const value = edit.value;
|
||||
const node = interp.top(interp.stack);
|
||||
node.setAttribute(name, value);
|
||||
|
||||
// Some attributes are "volatile" and don't work through `setAttribute`.
|
||||
if ((name === "value", interp)) {
|
||||
node.value = value;
|
||||
}
|
||||
if ((name === "checked", interp)) {
|
||||
node.checked = true;
|
||||
}
|
||||
if ((name === "selected", interp)) {
|
||||
node.selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 4
|
||||
RemoveAttribute(edit, interp) {
|
||||
const name = edit.name;
|
||||
const node = interp.top(interp.stack);
|
||||
node.removeAttribute(name);
|
||||
|
||||
// Some attributes are "volatile" and don't work through `removeAttribute`.
|
||||
if ((name === "value", interp)) {
|
||||
node.value = null;
|
||||
}
|
||||
if ((name === "checked", interp)) {
|
||||
node.checked = false;
|
||||
}
|
||||
if ((name === "selected", interp)) {
|
||||
node.selected = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 5
|
||||
PushReverseChild(edit, interp) {
|
||||
const n = edit.n;
|
||||
const parent = interp.top(interp.stack);
|
||||
const children = parent.childNodes;
|
||||
const child = children[children.length - n - 1];
|
||||
interp.stack.push(child);
|
||||
}
|
||||
|
||||
// 6
|
||||
PopPushChild(edit, interp) {
|
||||
const n = edit.n;
|
||||
interp.pop();
|
||||
const parent = interp.top(interp.stack);
|
||||
const children = parent.childNodes;
|
||||
const child = children[n];
|
||||
interp.stack.push(child);
|
||||
}
|
||||
|
||||
// 7
|
||||
Pop(edit, interp) {
|
||||
interp.pop();
|
||||
}
|
||||
|
||||
// 8
|
||||
AppendChild(edit, interp) {
|
||||
console.log(interp.stack);
|
||||
const child = interp.pop();
|
||||
console.log(interp.stack);
|
||||
interp.top().appendChild(child);
|
||||
}
|
||||
|
||||
// 9
|
||||
CreateTextNode(edit, interp) {
|
||||
// interp.stack.push(document.createTextNode("asd"));
|
||||
console.log(interp.stack);
|
||||
|
||||
interp.stack.push(document.createTextNode(edit.text));
|
||||
console.log(interp.stack);
|
||||
}
|
||||
|
||||
// 10
|
||||
CreateElement(edit, interp) {
|
||||
const tagName = edit.tag_name;
|
||||
interp.stack.push(document.createElement(tagName));
|
||||
}
|
||||
|
||||
// 11
|
||||
NewEventListener(edit, interp) {
|
||||
// todo!
|
||||
const eventId = mem32[i++];
|
||||
const eventType = interp.getCachedString(eventId);
|
||||
const a = mem32[i++];
|
||||
const b = mem32[i++];
|
||||
const el = interp.top(interp.stack);
|
||||
el.addEventListener(eventType, interp.eventHandler);
|
||||
el[`dodrio-a-${eventType}`] = a;
|
||||
el[`dodrio-b-${eventType}`] = b;
|
||||
}
|
||||
|
||||
// 12
|
||||
UpdateEventListener(edit, interp) {
|
||||
// todo!
|
||||
const eventId = mem32[i++];
|
||||
const eventType = interp.getCachedString(eventId);
|
||||
const el = interp.top(interp.stack);
|
||||
el[`dodrio-a-${eventType}`] = mem32[i++];
|
||||
el[`dodrio-b-${eventType}`] = mem32[i++];
|
||||
}
|
||||
|
||||
// 13
|
||||
RemoveEventListener(edit, interp) {
|
||||
// todo!
|
||||
const eventId = mem32[i++];
|
||||
const eventType = interp.getCachedString(eventId);
|
||||
const el = interp.top(interp.stack);
|
||||
el.removeEventListener(eventType, interp.eventHandler);
|
||||
}
|
||||
|
||||
// 14
|
||||
AddCachedString(edit, interp) {
|
||||
// todo!
|
||||
const pointer = mem32[i++];
|
||||
const length = mem32[i++];
|
||||
const id = mem32[i++];
|
||||
const str = string(mem8, pointer, length);
|
||||
interp.addCachedString(str, id);
|
||||
}
|
||||
|
||||
// 15
|
||||
DropCachedString(edit, interp) {
|
||||
// todo!
|
||||
const id = mem32[i++];
|
||||
interp.dropCachedString(id);
|
||||
}
|
||||
|
||||
// 16
|
||||
CreateElementNS(edit, interp) {
|
||||
// const tagNameId = mem32[i++];
|
||||
// const tagName = interp.getCachedString(tagNameId);
|
||||
// const nsId = mem32[i++];
|
||||
// const ns = interp.getCachedString(nsId);
|
||||
interp.stack.push(document.createElementNS(edit.ns, edit.tag_name));
|
||||
}
|
||||
|
||||
// 17
|
||||
SaveChildrenToTemporaries(edit, interp) {
|
||||
// let temp = mem32[i++];
|
||||
// const start = mem32[i++];
|
||||
// const end = mem32[i++];
|
||||
let temp = edit.temp;
|
||||
const start = edit.start;
|
||||
const end = edit.end;
|
||||
const parent = interp.top(interp.stack);
|
||||
const children = parent.childNodes;
|
||||
for (let i = start; i < end; i++, interp) {
|
||||
interp.temporaries[temp++] = children[i];
|
||||
}
|
||||
}
|
||||
|
||||
// 18
|
||||
PushChild(edit, interp) {
|
||||
const parent = interp.top(interp.stack);
|
||||
// const n = mem32[i++];
|
||||
const n = edit.n;
|
||||
const child = parent.childNodes[n];
|
||||
interp.stack.push(child);
|
||||
}
|
||||
|
||||
// 19
|
||||
PushTemporary(edit, interp) {
|
||||
// const temp = mem32[i++];
|
||||
const temp = edit.temp;
|
||||
interp.stack.push(interp.temporaries[temp]);
|
||||
}
|
||||
|
||||
// 20
|
||||
InsertBefore(edit, interp) {
|
||||
const before = interp.pop();
|
||||
const after = interp.pop();
|
||||
after.parentNode.insertBefore(before, after);
|
||||
interp.stack.push(before);
|
||||
}
|
||||
|
||||
// 21
|
||||
PopPushReverseChild(edit, interp) {
|
||||
// const n = mem32[i++];
|
||||
const n = edit.n;
|
||||
interp.pop();
|
||||
const parent = interp.top(interp.stack);
|
||||
const children = parent.childNodes;
|
||||
const child = children[children.length - n - 1];
|
||||
interp.stack.push(child);
|
||||
}
|
||||
|
||||
// 22
|
||||
RemoveChild(edit, interp) {
|
||||
// const n = mem32[i++];
|
||||
const n = edit.n;
|
||||
const parent = interp.top(interp.stack);
|
||||
const child = parent.childNodes[n];
|
||||
child.remove();
|
||||
}
|
||||
|
||||
// 23
|
||||
SetClass(edit, interp) {
|
||||
// const classId = mem32[i++];
|
||||
const className = edit.class_name;
|
||||
interp.top(interp.stack).className = className;
|
||||
}
|
||||
|
||||
// 24
|
||||
SaveTemplate(edit, interp) {
|
||||
const id = mem32[i++];
|
||||
const template = interp.top(interp.stack);
|
||||
interp.saveTemplate(id, template.cloneNode(true));
|
||||
}
|
||||
|
||||
// 25
|
||||
PushTemplate(edit, interp) {
|
||||
const id = mem32[i++];
|
||||
const template = interp.getTemplate(id);
|
||||
interp.stack.push(template.cloneNode(true));
|
||||
}
|
||||
|
||||
NewListener(edit, interp) {}
|
||||
}
|
||||
|
||||
const op_table = new OPTABLE();
|
||||
const interpreter = new Interpreter(window.document.body);
|
||||
|
||||
function EditListReceived(rawEditList) {
|
||||
let editList = JSON.parse(rawEditList);
|
||||
editList.forEach(function (edit, index) {
|
||||
op_table[edit.type](edit, interpreter);
|
||||
});
|
||||
}
|
||||
|
||||
let socket = new WebSocket("ws://127.0.0.1:8080/session/itsworkinggg");
|
||||
socket.onmessage = function(event) {
|
||||
console.log(event.data);
|
||||
EditListReceived(event.data);
|
||||
}
|
||||
// external.invoke("initiate");
|
||||
|
||||
</script>
|
||||
|
||||
</html>
|
||||
@@ -1,61 +0,0 @@
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
use dioxus::virtual_dom::VirtualDom;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_hooks::use_state;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
fn main() {}
|
||||
// use tide::{Request, Response};
|
||||
|
||||
// #[async_std::main]
|
||||
// async fn main() -> Result<(), std::io::Error> {
|
||||
// let mut app = tide::new();
|
||||
|
||||
// app.at("/:name").get(|req: Request<()>| async move {
|
||||
// let initial_name: String = req
|
||||
// .param("name")
|
||||
// .map(|f| f.parse().unwrap_or("...?".to_string()))
|
||||
// .unwrap_or("...?".to_string());
|
||||
|
||||
// let mut dom = VirtualDom::new_with_props(Example, ExampleProps { initial_name });
|
||||
|
||||
// dom.rebuild();
|
||||
|
||||
// Ok(Response::builder(200)
|
||||
// .body(format!("{}", dioxus_ssr::render_vdom(&dom, |c| c)))
|
||||
// .content_type(tide::http::mime::HTML)
|
||||
// .build())
|
||||
// });
|
||||
|
||||
// println!("Server available at [http://127.0.0.1:8080/bill]");
|
||||
// app.listen("127.0.0.1:8080").await?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// #[derive(PartialEq, Props)]
|
||||
// struct ExampleProps {
|
||||
// initial_name: String,
|
||||
// }
|
||||
|
||||
// static Example: FC<ExampleProps> = |(cx, props)| {
|
||||
// let dispaly_name = use_state(cx, move || props.initial_name.clone());
|
||||
|
||||
// cx.render(rsx! {
|
||||
// div { class: "py-12 px-4 text-center w-full max-w-2xl mx-auto",
|
||||
// span { class: "text-sm font-semibold"
|
||||
// "Dioxus Example: Jack and Jill"
|
||||
// }
|
||||
// h2 { class: "text-5xl mt-2 mb-6 leading-tight font-semibold font-heading"
|
||||
// "Hello, {dispaly_name}"
|
||||
// }
|
||||
// ul {
|
||||
// {(0..10).map(|f| rsx!( li {"Element {f}"} ))}
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// };
|
||||
@@ -1,147 +0,0 @@
|
||||
use dioxus::virtual_dom::VirtualDom;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_hooks::use_state;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_html::{GlobalAttributes, SvgAttributes};
|
||||
use dioxus_ssr::TextRenderer;
|
||||
|
||||
fn main() {
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
||||
let mut file = File::create("example.html").unwrap();
|
||||
|
||||
let mut dom = VirtualDom::new(App);
|
||||
|
||||
dom.rebuild();
|
||||
|
||||
file.write_fmt(format_args!(
|
||||
"{}",
|
||||
TextRenderer::from_vdom(&dom, Default::default())
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub static App: FC<()> = |(cx, props)| {
|
||||
cx.render(rsx!(
|
||||
div { class: "overflow-hidden"
|
||||
link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel:"stylesheet" }
|
||||
Header {}
|
||||
Entry {}
|
||||
Hero {}
|
||||
Hero {}
|
||||
Hero {}
|
||||
Hero {}
|
||||
Hero {}
|
||||
}
|
||||
))
|
||||
};
|
||||
|
||||
pub static Header: FC<()> = |(cx, props)| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
header { 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"
|
||||
a { class: "flex title-font font-medium items-center text-white mb-4 md:mb-0"
|
||||
StacksIcon {}
|
||||
span { class: "ml-3 text-xl" "Hello Dioxus!"}
|
||||
}
|
||||
nav { class: "md:ml-auto flex flex-wrap items-center text-base justify-center"
|
||||
a { class: "mr-5 hover:text-white" "First Link"}
|
||||
a { class: "mr-5 hover:text-white" "Second Link"}
|
||||
a { class: "mr-5 hover:text-white" "Third Link"}
|
||||
a { class: "mr-5 hover:text-white" "Fourth Link"}
|
||||
}
|
||||
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"
|
||||
"Button"
|
||||
RightArrowIcon {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
pub static Hero: FC<()> = |(cx, props)| {
|
||||
//
|
||||
cx.render(rsx! {
|
||||
section{ class: "text-gray-400 bg-gray-900 body-font"
|
||||
div { class: "container mx-auto flex px-5 py-24 md:flex-row flex-col items-center"
|
||||
div { class: "lg:flex-grow md:w-1/2 lg:pr-24 md:pr-16 flex flex-col md:items-start md:text-left mb-16 md:mb-0 items-center text-center"
|
||||
h1 { class: "title-font sm:text-4xl text-3xl mb-4 font-medium text-white"
|
||||
br { class: "hidden lg:inline-block" }
|
||||
"Dioxus Sneak Peek"
|
||||
}
|
||||
p {
|
||||
class: "mb-8 leading-relaxed"
|
||||
|
||||
"Dioxus is a new UI framework that makes it easy and simple to write cross-platform apps using web
|
||||
technologies! It is functional, fast, and portable. Dioxus can run on the web, on the desktop, and
|
||||
on mobile and embedded platforms."
|
||||
|
||||
}
|
||||
div { class: "flex justify-center"
|
||||
button {
|
||||
class: "inline-flex text-white bg-indigo-500 border-0 py-2 px-6 focus:outline-none hover:bg-indigo-600 rounded text-lg"
|
||||
"Learn more"
|
||||
}
|
||||
button {
|
||||
class: "ml-4 inline-flex text-gray-400 bg-gray-800 border-0 py-2 px-6 focus:outline-none hover:bg-gray-700 hover:text-white rounded text-lg"
|
||||
"Build an app"
|
||||
}
|
||||
}
|
||||
}
|
||||
div { class: "lg:max-w-lg lg:w-full md:w-1/2 w-5/6"
|
||||
img { class: "object-cover object-center rounded" alt: "hero" src: "https://i.imgur.com/oK6BLtw.png"
|
||||
referrerpolicy:"no-referrer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
pub static Entry: FC<()> = |(cx, props)| {
|
||||
//
|
||||
cx.render(rsx! {
|
||||
section{ class: "text-gray-400 bg-gray-900 body-font"
|
||||
div { class: "container mx-auto flex px-5 py-24 md:flex-row flex-col items-center"
|
||||
textarea {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
pub static StacksIcon: FC<()> = |(cx, props)| {
|
||||
cx.render(rsx!(
|
||||
svg {
|
||||
// xmlns: "http://www.w3.org/2000/svg"
|
||||
fill: "none"
|
||||
stroke: "currentColor"
|
||||
stroke_linecap: "round"
|
||||
stroke_linejoin: "round"
|
||||
stroke_width: "2"
|
||||
// class: "w-10 h-10 text-white p-2 bg-indigo-500 rounded-full"
|
||||
viewBox: "0 0 24 24"
|
||||
path { d: "M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"}
|
||||
}
|
||||
))
|
||||
};
|
||||
pub static RightArrowIcon: FC<()> = |(cx, props)| {
|
||||
cx.render(rsx!(
|
||||
svg {
|
||||
fill: "none"
|
||||
stroke: "currentColor"
|
||||
stroke_linecap: "round"
|
||||
stroke_linejoin: "round"
|
||||
stroke_width: "2"
|
||||
// class: "w-4 h-4 ml-1"
|
||||
viewBox: "0 0 24 24"
|
||||
path { d: "M5 12h14M12 5l7 7-7 7"}
|
||||
}
|
||||
))
|
||||
};
|
||||
+4
-10
@@ -31,10 +31,7 @@ impl SsrRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_lazy<'a, F: FnOnce(NodeFactory<'a>) -> VNode<'a>>(
|
||||
&'a mut self,
|
||||
f: LazyNodes<'a, F>,
|
||||
) -> String {
|
||||
pub fn render_lazy<'a>(&'a mut self, f: Option<LazyNodes<'a, '_>>) -> String {
|
||||
let bump = &mut self.inner as *mut _;
|
||||
let s = self.render_inner(f);
|
||||
// reuse the bump's memory
|
||||
@@ -42,10 +39,7 @@ impl SsrRenderer {
|
||||
s
|
||||
}
|
||||
|
||||
fn render_inner<'a, F: FnOnce(NodeFactory<'a>) -> VNode<'a>>(
|
||||
&'a self,
|
||||
f: LazyNodes<'a, F>,
|
||||
) -> String {
|
||||
fn render_inner<'a>(&'a self, f: Option<LazyNodes<'a, '_>>) -> String {
|
||||
let factory = NodeFactory::new(&self.inner);
|
||||
let root = f.into_vnode(factory);
|
||||
format!(
|
||||
@@ -59,7 +53,7 @@ impl SsrRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_lazy<'a, F: FnOnce(NodeFactory<'a>) -> VNode<'a>>(f: LazyNodes<'a, F>) -> String {
|
||||
pub fn render_lazy<'a>(f: Option<LazyNodes<'a, '_>>) -> String {
|
||||
let bump = bumpalo::Bump::new();
|
||||
let borrowed = ≎
|
||||
|
||||
@@ -398,7 +392,7 @@ mod tests {
|
||||
fn styles() {
|
||||
static STLYE_APP: FC<()> = |(cx, _)| {
|
||||
cx.render(rsx! {
|
||||
div { style: { color: "blue", font_size: "46px" } }
|
||||
div { color: "blue", font_size: "46px" }
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"rust-analyzer.inlayHints.enable": false
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
//! Basic example that renders a simple VNode to the browser.
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_hooks::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
fn main() {
|
||||
console_error_panic_hook::set_once();
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
dioxus_web::launch(APP, |c| c)
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
struct DogApi {
|
||||
message: String,
|
||||
}
|
||||
|
||||
static APP: FC<()> = |(cx, _props)| {
|
||||
let state = use_state(cx, || 0);
|
||||
|
||||
const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random/";
|
||||
let doggo = use_suspense(
|
||||
cx,
|
||||
|| async { reqwest::get(ENDPOINT).await.unwrap().json::<DogApi>().await },
|
||||
|cx, res| match res {
|
||||
Ok(res) => rsx!(
|
||||
cx,
|
||||
img {
|
||||
src: "{res.message}"
|
||||
}
|
||||
),
|
||||
Err(_err) => rsx!(cx, div { "No doggos for you :(" }),
|
||||
},
|
||||
);
|
||||
|
||||
rsx!(cx, div { align_items: "center"
|
||||
section { class: "py-12 px-4 text-center"
|
||||
div { class: "w-full max-w-2xl mx-auto"
|
||||
span { class: "text-sm font-semibold"
|
||||
"count: {state}"
|
||||
}
|
||||
div {
|
||||
button { onclick: move |_| state.set(state + 1), "incr" }
|
||||
button { onclick: move |_| state.set(state - 1), "decr" }
|
||||
}
|
||||
div {
|
||||
{doggo}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
@@ -1,89 +0,0 @@
|
||||
//! Basic example that renders a simple VNode to the browser.
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_hooks::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
fn main() {
|
||||
// Setup logging
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
// Run the app
|
||||
dioxus_web::launch(APP, |c| c)
|
||||
}
|
||||
|
||||
static APP: FC<()> = |(cx, _)| {
|
||||
let mut count = use_state(cx, || 3);
|
||||
let content = use_state(cx, || String::from("h1"));
|
||||
let text_content = use_state(cx, || String::from("Hello, world!"));
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 { "content val is {content}" }
|
||||
|
||||
input {
|
||||
r#type: "text",
|
||||
value: "{text_content}"
|
||||
oninput: move |e| text_content.set(e.value.clone())
|
||||
}
|
||||
|
||||
{(0..10).map(|_| {
|
||||
rsx!(
|
||||
button {
|
||||
onclick: move |_| count += 1,
|
||||
"Click to add."
|
||||
"Current count: {count}"
|
||||
}
|
||||
br {}
|
||||
)
|
||||
})}
|
||||
|
||||
select {
|
||||
name: "cars"
|
||||
id: "cars"
|
||||
value: "{content}"
|
||||
oninput: move |ev| {
|
||||
content.set(ev.value.clone());
|
||||
match ev.value.as_str() {
|
||||
"h1" => count.set(0),
|
||||
"h2" => count.set(5),
|
||||
"h3" => count.set(10),
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
|
||||
option { value: "h1", "h1" }
|
||||
option { value: "h2", "h2" }
|
||||
option { value: "h3", "h3" }
|
||||
}
|
||||
|
||||
{render_list(cx, *count)}
|
||||
|
||||
{render_bullets(cx)}
|
||||
|
||||
CHILD {}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
fn render_bullets(cx: Context) -> Element {
|
||||
rsx!(cx, div {
|
||||
"bite me"
|
||||
})
|
||||
}
|
||||
|
||||
fn render_list(cx: Context, count: usize) -> Element {
|
||||
let items = (0..count).map(|f| {
|
||||
rsx! {
|
||||
li { "a - {f}" }
|
||||
li { "b - {f}" }
|
||||
li { "c - {f}" }
|
||||
}
|
||||
});
|
||||
|
||||
rsx!(cx, ul { {items} })
|
||||
}
|
||||
|
||||
static CHILD: FC<()> = |(cx, _)| rsx!(cx, div {"hello child"});
|
||||
@@ -1,55 +0,0 @@
|
||||
//! Basic example that renders a simple VNode to the browser.
|
||||
|
||||
use dioxus::events::on::MouseEvent;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_hooks::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
use std::future::Future;
|
||||
|
||||
use std::{pin::Pin, time::Duration};
|
||||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
use dioxus_web::*;
|
||||
|
||||
fn main() {
|
||||
// Setup logging
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
// Run the app
|
||||
dioxus_web::launch(App, |c| c)
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
let mut state = use_state(cx, || 0);
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
style: {
|
||||
align_items: "center"
|
||||
}
|
||||
section { class: "py-12 px-4 text-center"
|
||||
div { class: "w-full max-w-2xl mx-auto"
|
||||
span { class: "text-sm font-semibold"
|
||||
"static subtree"
|
||||
}
|
||||
}
|
||||
}
|
||||
section { class: "py-12 px-4 text-center"
|
||||
div { class: "w-full max-w-2xl mx-auto"
|
||||
span { class: "text-sm font-semibold"
|
||||
"dynamic subtree {state}"
|
||||
}
|
||||
div {
|
||||
button { onclick: move |e| state+=1, "incr" }
|
||||
br {}
|
||||
button { onclick: move |e| state-=1, "decr" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
@@ -1,69 +0,0 @@
|
||||
//! Example: Webview Renderer
|
||||
//! -------------------------
|
||||
//!
|
||||
//! This example shows how to use the dioxus_desktop crate to build a basic desktop application.
|
||||
//!
|
||||
//! Under the hood, the dioxus_desktop crate bridges a native Dioxus VirtualDom with a custom prebuit application running
|
||||
//! in the webview runtime. Custom handlers are provided for the webview instance to consume patches and emit user events
|
||||
//! into the native VDom instance.
|
||||
//!
|
||||
//! Currently, NodeRefs won't work properly, but all other event functionality will.
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_hooks::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
// #[cfg]
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
dioxus_web::launch(App, |c| c);
|
||||
// env_logger::init();
|
||||
// dioxus::web::launch(App, |c| c);
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
dbg!("rednering parent");
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
But {
|
||||
h1 {"he"}
|
||||
}
|
||||
// But {
|
||||
// h1 {"llo"}
|
||||
// }
|
||||
// But {
|
||||
// h1 {"world"}
|
||||
// }
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
static But: FC<()> = |(cx, props)| {
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
// let d = Dropper { name: "asd" };
|
||||
// let handler = move |_| {
|
||||
// dbg!(d.name);
|
||||
// };
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 { "Hifive counter: {count}" }
|
||||
{cx.children()}
|
||||
button { onclick: move |_| count += 1, "Up high!" }
|
||||
button { onclick: move |_| count -= 1, "Down low!" }
|
||||
// button { onclick: {handler}, "Down low!" }
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
// struct Dropper {
|
||||
// name: &'static str,
|
||||
// }
|
||||
// impl Drop for Dropper {
|
||||
// fn drop(&mut self) {
|
||||
// dbg!("dropped");
|
||||
// }
|
||||
// }
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
Tiny CRM: A port of the Yew CRM example to Dioxus.
|
||||
*/
|
||||
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_hooks::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
fn main() {
|
||||
// Setup logging
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
dioxus_web::launch(App, |c| c)
|
||||
}
|
||||
|
||||
enum Scene {
|
||||
ClientsList,
|
||||
NewClientForm,
|
||||
Settings,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Client {
|
||||
pub first_name: String,
|
||||
pub last_name: String,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, _)| {
|
||||
let scene = use_state(cx, || Scene::ClientsList);
|
||||
let clients = use_ref(cx, || vec![] as Vec<Client>);
|
||||
|
||||
let firstname = use_state(cx, || String::new());
|
||||
let lastname = use_state(cx, || String::new());
|
||||
let description = use_state(cx, || String::new());
|
||||
|
||||
let scene = match *scene {
|
||||
Scene::ClientsList => {
|
||||
rsx!(cx, div { class: "crm"
|
||||
h2 { "List of clients" margin_bottom: "10px" }
|
||||
div { class: "clients" margin_left: "10px"
|
||||
{clients.read().iter().map(|client| rsx!(
|
||||
div { class: "client" style: "margin-bottom: 50px"
|
||||
p { "First Name: {client.first_name}" }
|
||||
p { "Last Name: {client.last_name}" }
|
||||
p {"Description: {client.description}"}
|
||||
})
|
||||
)}
|
||||
}
|
||||
button { class: "pure-button pure-button-primary" onclick: move |_| scene.set(Scene::NewClientForm), "Add New" }
|
||||
button { class: "pure-button" onclick: move |_| scene.set(Scene::Settings), "Settings" }
|
||||
})
|
||||
}
|
||||
Scene::NewClientForm => {
|
||||
let add_new = move |_| {
|
||||
clients.write().push(Client {
|
||||
description: (*description).clone(),
|
||||
first_name: (*firstname).clone(),
|
||||
last_name: (*lastname).clone(),
|
||||
});
|
||||
description.set(String::new());
|
||||
firstname.set(String::new());
|
||||
lastname.set(String::new());
|
||||
};
|
||||
rsx!(cx, div { class: "crm"
|
||||
h2 {"Add new client" margin_bottom: "10px" }
|
||||
form { class: "pure-form"
|
||||
input { class: "new-client firstname" placeholder: "First name" value: "{firstname}"
|
||||
oninput: move |evt| firstname.set(evt.value.clone())
|
||||
}
|
||||
input { class: "new-client lastname" placeholder: "Last name" value: "{lastname}"
|
||||
oninput: move |evt| lastname.set(evt.value.clone())
|
||||
}
|
||||
textarea { class: "new-client description" placeholder: "Description" value: "{description}"
|
||||
oninput: move |evt| description.set(evt.value.clone())
|
||||
}
|
||||
}
|
||||
button { class: "pure-button pure-button-primary", onclick: {add_new}, "Add New" }
|
||||
button { class: "pure-button", onclick: move |_| scene.set(Scene::ClientsList), "Go Back" }
|
||||
})
|
||||
}
|
||||
Scene::Settings => {
|
||||
rsx!(cx, div {
|
||||
h2 { "Settings" margin_bottom: "10px" }
|
||||
button {
|
||||
background: "rgb(202, 60, 60)"
|
||||
class: "pure-button pure-button-primary"
|
||||
onclick: move |_| {
|
||||
clients.write().clear();
|
||||
scene.set(Scene::ClientsList);
|
||||
},
|
||||
"Remove all clients"
|
||||
}
|
||||
button {
|
||||
class: "pure-button pure-button-primary"
|
||||
onclick: move |_| scene.set(Scene::ClientsList),
|
||||
"Go Back"
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
rsx!(cx, body {
|
||||
link {
|
||||
rel: "stylesheet"
|
||||
href: "https://unpkg.com/purecss@2.0.6/build/pure-min.css"
|
||||
integrity: "sha384-Uu6IeWbM+gzNVXJcM9XV3SohHtmWE+3VGi496jvgX1jyvDTXfdK+rfZc8C1Aehk5"
|
||||
crossorigin: "anonymous"
|
||||
}
|
||||
margin_left: "35%"
|
||||
h1 {"Dioxus CRM Example"}
|
||||
{scene}
|
||||
})
|
||||
};
|
||||
@@ -1,147 +0,0 @@
|
||||
//! Basic example that renders a simple VNode to the browser.
|
||||
|
||||
use dioxus::events::on::MouseEvent;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_hooks::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use std::future::Future;
|
||||
|
||||
use std::{pin::Pin, time::Duration};
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_html::SvgAttributes;
|
||||
|
||||
use dioxus_web::*;
|
||||
|
||||
fn main() {
|
||||
// Setup logging
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
// Run the app
|
||||
dioxus_web::launch(App, |c| c)
|
||||
}
|
||||
|
||||
pub static App: FC<()> = |(cx, props)| {
|
||||
cx.render(rsx!(
|
||||
div { class: "overflow-hidden"
|
||||
link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel:"stylesheet" }
|
||||
Header {}
|
||||
// Entry {}
|
||||
Hero {}
|
||||
Hero {}
|
||||
Hero {}
|
||||
Hero {}
|
||||
Hero {}
|
||||
}
|
||||
))
|
||||
};
|
||||
|
||||
pub static Header: FC<()> = |(cx, props)| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
header { 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"
|
||||
a { class: "flex title-font font-medium items-center text-white mb-4 md:mb-0"
|
||||
StacksIcon {}
|
||||
span { class: "ml-3 text-xl" "Hello Dioxus!"}
|
||||
}
|
||||
nav { class: "md:ml-auto flex flex-wrap items-center text-base justify-center"
|
||||
a { class: "mr-5 hover:text-white" "First Link"}
|
||||
a { class: "mr-5 hover:text-white" "Second Link"}
|
||||
a { class: "mr-5 hover:text-white" "Third Link"}
|
||||
a { class: "mr-5 hover:text-white" "Fourth Link"}
|
||||
}
|
||||
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"
|
||||
"Button"
|
||||
RightArrowIcon {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
pub static Hero: FC<()> = |(cx, props)| {
|
||||
//
|
||||
cx.render(rsx! {
|
||||
section{ class: "text-gray-400 bg-gray-900 body-font"
|
||||
div { class: "container mx-auto flex px-5 py-24 md:flex-row flex-col items-center"
|
||||
div { class: "lg:flex-grow md:w-1/2 lg:pr-24 md:pr-16 flex flex-col md:items-start md:text-left mb-16 md:mb-0 items-center text-center"
|
||||
h1 { class: "title-font sm:text-4xl text-3xl mb-4 font-medium text-white"
|
||||
br { class: "hidden lg:inline-block" }
|
||||
"Dioxus Sneak Peek"
|
||||
}
|
||||
p {
|
||||
class: "mb-8 leading-relaxed"
|
||||
|
||||
"Dioxus is a new UI framework that makes it easy and simple to write cross-platform apps using web
|
||||
technologies! It is functional, fast, and portable. Dioxus can run on the web, on the desktop, and
|
||||
on mobile and embedded platforms."
|
||||
|
||||
}
|
||||
div { class: "flex justify-center"
|
||||
button {
|
||||
class: "inline-flex text-white bg-indigo-500 border-0 py-2 px-6 focus:outline-none hover:bg-indigo-600 rounded text-lg"
|
||||
"Learn more"
|
||||
}
|
||||
button {
|
||||
class: "ml-4 inline-flex text-gray-400 bg-gray-800 border-0 py-2 px-6 focus:outline-none hover:bg-gray-700 hover:text-white rounded text-lg"
|
||||
"Build an app"
|
||||
}
|
||||
}
|
||||
}
|
||||
div { class: "lg:max-w-lg lg:w-full md:w-1/2 w-5/6"
|
||||
img { class: "object-cover object-center rounded" alt: "hero" src: "https://i.imgur.com/oK6BLtw.png"
|
||||
referrerpolicy:"no-referrer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
pub static Entry: FC<()> = |(cx, props)| {
|
||||
//
|
||||
cx.render(rsx! {
|
||||
section{ class: "text-gray-400 bg-gray-900 body-font"
|
||||
div { class: "container mx-auto flex px-5 py-24 md:flex-row flex-col items-center"
|
||||
textarea {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
pub static StacksIcon: FC<()> = |(cx, props)| {
|
||||
cx.render(rsx!(
|
||||
svg {
|
||||
// xmlns: "http://www.w3.org/2000/svg"
|
||||
fill: "none"
|
||||
stroke: "currentColor"
|
||||
stroke_linecap: "round"
|
||||
stroke_linejoin: "round"
|
||||
stroke_width: "2"
|
||||
// class: "w-10 h-10 text-white p-2 bg-indigo-500 rounded-full"
|
||||
viewBox: "0 0 24 24"
|
||||
path { d: "M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"}
|
||||
}
|
||||
))
|
||||
};
|
||||
pub static RightArrowIcon: FC<()> = |(cx, props)| {
|
||||
cx.render(rsx!(
|
||||
svg {
|
||||
fill: "none"
|
||||
stroke: "currentColor"
|
||||
stroke_linecap: "round"
|
||||
stroke_linejoin: "round"
|
||||
stroke_width: "2"
|
||||
// class: "w-4 h-4 ml-1"
|
||||
viewBox: "0 0 24 24"
|
||||
path { d: "M5 12h14M12 5l7 7-7 7"}
|
||||
}
|
||||
))
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
[package]
|
||||
name = "dioxus-webview-client"
|
||||
version = "0.0.0"
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
@@ -1,8 +0,0 @@
|
||||
# the client part of the vdom
|
||||
|
||||
|
||||
this crate is designed to be the "receiving end" of the dioxus virtualdom, using wasm_bindgen to expose an API for the receiving end.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
Reference in new issue
Block a user