mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-26 22:20:19 +00:00
docs: remove old examples
This commit is contained in:
parent
ef2daf62a3
commit
2b7dd45aa2
41 changed files with 0 additions and 3092 deletions
|
@ -1,49 +0,0 @@
|
|||
fn main() {
|
||||
// render the
|
||||
let transition = move |cx, (width, height)| {};
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
Transition {
|
||||
start: (0, 5),
|
||||
stop: (10, 10),
|
||||
render: transition
|
||||
}
|
||||
|
||||
Transition {
|
||||
start: (0, 5),
|
||||
stop: (10, 10),
|
||||
render: move |cx, (width, height)| {
|
||||
//
|
||||
cx.render(rsx!{
|
||||
div {
|
||||
style {
|
||||
width: width,
|
||||
width: height
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Animations with signals
|
||||
fn signal_based(cx: ()) {
|
||||
const InitPos: (i32, i32) = (0, 0);
|
||||
const EndPos: (i32, i32) = (100, 200);
|
||||
|
||||
let spring = use_spring(cx, move |spring| spring.from(InitPos).to(EndPos));
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
style: [
|
||||
width: spring.0,
|
||||
height: spring.1
|
||||
]
|
||||
button { onclick: move |_| spring.set(InitPos), "Reset" }
|
||||
button { onclick: move |_| spring.set(EndPos), "Animate" }
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,57 +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_html as dioxus_elements;
|
||||
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
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
static App: FC<()> = |cx, props| {
|
||||
let (state, set_state) = use_state_classic(cx, || 0);
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
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 {
|
||||
C1 {
|
||||
onclick: move |_| set_state(state + 1)
|
||||
"incr"
|
||||
}
|
||||
C1 {
|
||||
onclick: move |_| set_state(state - 1)
|
||||
"decr"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
#[derive(Props)]
|
||||
struct IncrementerProps<'a> {
|
||||
onclick: &'a dyn Fn(MouseEvent),
|
||||
}
|
||||
|
||||
fn C1<'a, 'b>(cx: Context<'a, IncrementerProps<'b>>) -> DomTree<'a> {
|
||||
cx.render(rsx! {
|
||||
button {
|
||||
class: "inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
|
||||
onclick: {cx.onclick}
|
||||
"becr"
|
||||
{cx.children()}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,188 +0,0 @@
|
|||
//! Example: Calculator
|
||||
//! ------------------
|
||||
//!
|
||||
//! This example showcases a basic iOS-style calculator app using classic react-style `use_state` hooks. A counterpart of
|
||||
//! this example is in `model.rs` which shows the same calculator app implemented using the `model` paradigm. We've found
|
||||
//! that the most natural Rust code is more "model-y" than "React-y", but opt to keep this example to show the different
|
||||
//! flavors of programming you can use in Dioxus.
|
||||
|
||||
use dioxus::events::on::*;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
const STYLE: &str = include_str!("../../../examples/assets/calculator.css");
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
enum Operator {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
}
|
||||
|
||||
static App: FC<()> = |cx, props| {
|
||||
let (cur_val, set_cur_val) = use_state_classic(cx, || 0.0_f64);
|
||||
let (operator, set_operator) = use_state_classic(cx, || None as Option<Operator>);
|
||||
let (display_value, set_display_value) = use_state_classic(cx, || "0".to_string());
|
||||
|
||||
let clear_display = display_value.eq("0");
|
||||
let clear_text = if clear_display { "C" } else { "AC" };
|
||||
|
||||
let input_digit = move |num: u8| {
|
||||
let mut new = if operator.is_some() {
|
||||
String::new()
|
||||
} else if display_value == "0" {
|
||||
String::new()
|
||||
} else {
|
||||
display_value.clone()
|
||||
};
|
||||
if operator.is_some() {
|
||||
let val = display_value.parse::<f64>().unwrap();
|
||||
set_cur_val(val);
|
||||
}
|
||||
|
||||
new.push_str(num.to_string().as_str());
|
||||
set_display_value(new);
|
||||
};
|
||||
|
||||
let input_dot = move || {
|
||||
let mut new = display_value.clone();
|
||||
new.push_str(".");
|
||||
set_display_value(new);
|
||||
};
|
||||
|
||||
let perform_operation = move || {
|
||||
if let Some(op) = operator.as_ref() {
|
||||
let rhs = display_value.parse::<f64>().unwrap();
|
||||
let new_val = match op {
|
||||
Operator::Add => *cur_val + rhs,
|
||||
Operator::Sub => *cur_val - rhs,
|
||||
Operator::Mul => *cur_val * rhs,
|
||||
Operator::Div => *cur_val / rhs,
|
||||
};
|
||||
set_cur_val(new_val);
|
||||
set_display_value(new_val.to_string());
|
||||
set_operator(None);
|
||||
}
|
||||
};
|
||||
|
||||
let toggle_sign = move |_| {
|
||||
if display_value.starts_with("-") {
|
||||
set_display_value(display_value.trim_start_matches("-").to_string())
|
||||
} else {
|
||||
set_display_value(format!("-{}", *display_value))
|
||||
}
|
||||
};
|
||||
let toggle_percent = move |_| todo!();
|
||||
|
||||
let clear_key = move |_| {
|
||||
set_display_value("0".to_string());
|
||||
if !clear_display {
|
||||
set_operator(None);
|
||||
set_cur_val(0.0);
|
||||
}
|
||||
};
|
||||
|
||||
let keydownhandler = move |evt: KeyboardEvent| match evt.key_code() {
|
||||
KeyCode::Backspace => {
|
||||
let mut new = display_value.clone();
|
||||
if !new.as_str().eq("0") {
|
||||
new.pop();
|
||||
}
|
||||
set_display_value(new);
|
||||
}
|
||||
KeyCode::_0 => input_digit(0),
|
||||
KeyCode::_1 => input_digit(1),
|
||||
KeyCode::_2 => input_digit(2),
|
||||
KeyCode::_3 => input_digit(3),
|
||||
KeyCode::_4 => input_digit(4),
|
||||
KeyCode::_5 => input_digit(5),
|
||||
KeyCode::_6 => input_digit(6),
|
||||
KeyCode::_7 => input_digit(7),
|
||||
KeyCode::_8 => input_digit(8),
|
||||
KeyCode::_9 => input_digit(9),
|
||||
KeyCode::Add => set_operator(Some(Operator::Add)),
|
||||
KeyCode::Subtract => set_operator(Some(Operator::Sub)),
|
||||
KeyCode::Divide => set_operator(Some(Operator::Div)),
|
||||
KeyCode::Multiply => set_operator(Some(Operator::Mul)),
|
||||
_ => {}
|
||||
};
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
id: "wrapper"
|
||||
div { class: "app" onkeydown: {keydownhandler}
|
||||
style { "{STYLE}" }
|
||||
div { class: "calculator",
|
||||
CalculatorDisplay { val: &display_value}
|
||||
div { class: "calculator-keypad"
|
||||
div { class: "input-keys"
|
||||
div { class: "function-keys"
|
||||
CalculatorKey { name: "key-clear", onclick: {clear_key} "{clear_text}" }
|
||||
CalculatorKey { name: "key-sign", onclick: {toggle_sign}, "±"}
|
||||
CalculatorKey { name: "key-percent", onclick: {toggle_percent} "%"}
|
||||
}
|
||||
div { class: "digit-keys"
|
||||
CalculatorKey { name: "key-0", onclick: move |_| input_digit(0), "0" }
|
||||
CalculatorKey { name: "key-dot", onclick: move |_| input_dot(), "●" }
|
||||
{(1..10).map(move |k| rsx!{
|
||||
CalculatorKey { key: "{k}", name: "key-{k}", onclick: move |_| input_digit(k), "{k}" }
|
||||
})}
|
||||
}
|
||||
}
|
||||
div { class: "operator-keys"
|
||||
CalculatorKey { name: "key-divide", onclick: move |_| set_operator(Some(Operator::Div)) "÷" }
|
||||
CalculatorKey { name: "key-multiply", onclick: move |_| set_operator(Some(Operator::Mul)) "×" }
|
||||
CalculatorKey { name: "key-subtract", onclick: move |_| set_operator(Some(Operator::Sub)) "−" }
|
||||
CalculatorKey { name: "key-add", onclick: move |_| set_operator(Some(Operator::Add)) "+" }
|
||||
CalculatorKey { name: "key-equals", onclick: move |_| perform_operation() "=" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
#[derive(Props)]
|
||||
struct CalculatorKeyProps<'a> {
|
||||
/// Name!
|
||||
name: &'static str,
|
||||
|
||||
/// Click!
|
||||
onclick: &'a dyn Fn(MouseEvent),
|
||||
}
|
||||
|
||||
fn CalculatorKey<'a, 'r>(cx: Context<'a, CalculatorKeyProps<'r>>) -> DomTree<'a> {
|
||||
cx.render(rsx! {
|
||||
button {
|
||||
class: "calculator-key {cx.name}"
|
||||
onclick: {cx.onclick}
|
||||
{cx.children()}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Props, PartialEq)]
|
||||
struct CalculatorDisplayProps<'a> {
|
||||
val: &'a str,
|
||||
}
|
||||
|
||||
fn CalculatorDisplay<'a>(cx: Context<'a, CalculatorDisplayProps>) -> DomTree<'a> {
|
||||
use separator::Separatable;
|
||||
// Todo, add float support to the num-format crate
|
||||
let formatted = cx.val.parse::<f64>().unwrap().separated_string();
|
||||
// TODO: make it autoscaling with css
|
||||
cx.render(rsx! {
|
||||
div { class: "calculator-display"
|
||||
div { class: "auto-scaling-text", "{formatted}" }
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,181 +0,0 @@
|
|||
use dioxus::events::on::*;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_core as dioxus;
|
||||
|
||||
const STYLE: &str = include_str!("../../../examples/assets/calculator.css");
|
||||
|
||||
fn main() {
|
||||
dioxus_desktop::launch(
|
||||
|builder| {
|
||||
builder
|
||||
.title("Test Dioxus App")
|
||||
.size(340, 560)
|
||||
.resizable(false)
|
||||
.debug(true)
|
||||
},
|
||||
(),
|
||||
App,
|
||||
)
|
||||
.expect("Webview finished");
|
||||
}
|
||||
|
||||
static App: FC<()> = |cx, props| {
|
||||
let state = use_model(&cx, || Calculator::new());
|
||||
|
||||
let clear_display = state.display_value.eq("0");
|
||||
let clear_text = if clear_display { "C" } else { "AC" };
|
||||
let formatted = state.formatted_display();
|
||||
|
||||
cx.render(rsx! {
|
||||
div { id: "wrapper"
|
||||
div { class: "app", style { "{STYLE}" }
|
||||
div { class: "calculator", onkeypress: move |evt| state.get_mut().handle_keydown(evt),
|
||||
div { class: "calculator-display", "{formatted}"}
|
||||
div { class: "calculator-keypad"
|
||||
div { class: "input-keys"
|
||||
div { class: "function-keys"
|
||||
CalculatorKey { name: "key-clear", onclick: move |_| state.get_mut().clear_display(), "{clear_text}" }
|
||||
CalculatorKey { name: "key-sign", onclick: move |_| state.get_mut().toggle_sign(), "±"}
|
||||
CalculatorKey { name: "key-percent", onclick: move |_| state.get_mut().toggle_percent(), "%"}
|
||||
}
|
||||
div { class: "digit-keys"
|
||||
CalculatorKey { name: "key-0", onclick: move |_| state.get_mut().input_digit(0), "0" }
|
||||
CalculatorKey { name: "key-dot", onclick: move |_| state.get_mut().input_dot(), "●" }
|
||||
{(1..10).map(move |k| rsx!{
|
||||
CalculatorKey { key: "{k}", name: "key-{k}", onclick: move |_| state.get_mut().input_digit(k), "{k}" }
|
||||
})}
|
||||
}
|
||||
}
|
||||
div { class: "operator-keys"
|
||||
CalculatorKey { name:"key-divide", onclick: move |_| state.get_mut().set_operator(Operator::Div), "÷" }
|
||||
CalculatorKey { name:"key-multiply", onclick: move |_| state.get_mut().set_operator(Operator::Mul), "×" }
|
||||
CalculatorKey { name:"key-subtract", onclick: move |_| state.get_mut().set_operator(Operator::Sub), "−" }
|
||||
CalculatorKey { name:"key-add", onclick: move |_| state.get_mut().set_operator(Operator::Add), "+" }
|
||||
CalculatorKey { name:"key-equals", onclick: move |_| state.get_mut().perform_operation(), "=" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
#[derive(Props)]
|
||||
struct CalculatorKeyProps<'a> {
|
||||
name: &'static str,
|
||||
onclick: &'a dyn Fn(MouseEvent),
|
||||
}
|
||||
|
||||
fn CalculatorKey<'a, 'r>(cx: Context<'a, CalculatorKeyProps<'r>>) -> DomTree<'a> {
|
||||
cx.render(rsx! {
|
||||
button {
|
||||
class: "calculator-key {cx.name}"
|
||||
onclick: {cx.onclick}
|
||||
{cx.children()}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Calculator {
|
||||
display_value: String,
|
||||
operator: Option<Operator>,
|
||||
waiting_for_operand: bool,
|
||||
cur_val: f64,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
enum Operator {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
}
|
||||
|
||||
impl Calculator {
|
||||
fn new() -> Self {
|
||||
Calculator {
|
||||
display_value: "0".to_string(),
|
||||
operator: None,
|
||||
waiting_for_operand: false,
|
||||
cur_val: 0.0,
|
||||
}
|
||||
}
|
||||
fn formatted_display(&self) -> String {
|
||||
// use separator::Separatable;
|
||||
self.display_value.clone()
|
||||
// .parse::<f64>()
|
||||
// .unwrap()
|
||||
// .separated_string()
|
||||
}
|
||||
fn clear_display(&mut self) {
|
||||
self.display_value = "0".to_string();
|
||||
}
|
||||
fn input_digit(&mut self, digit: u8) {
|
||||
let content = digit.to_string();
|
||||
if self.waiting_for_operand || self.display_value == "0" {
|
||||
self.waiting_for_operand = false;
|
||||
self.display_value = content;
|
||||
} else {
|
||||
self.display_value.push_str(content.as_str());
|
||||
}
|
||||
}
|
||||
fn input_dot(&mut self) {
|
||||
if self.display_value.find(".").is_none() {
|
||||
self.display_value.push_str(".");
|
||||
}
|
||||
}
|
||||
fn perform_operation(&mut self) {
|
||||
if let Some(op) = &self.operator {
|
||||
let rhs = self.display_value.parse::<f64>().unwrap();
|
||||
let new_val = match op {
|
||||
Operator::Add => self.cur_val + rhs,
|
||||
Operator::Sub => self.cur_val - rhs,
|
||||
Operator::Mul => self.cur_val * rhs,
|
||||
Operator::Div => self.cur_val / rhs,
|
||||
};
|
||||
self.cur_val = new_val;
|
||||
self.display_value = new_val.to_string();
|
||||
self.operator = None;
|
||||
}
|
||||
}
|
||||
fn toggle_sign(&mut self) {
|
||||
if self.display_value.starts_with("-") {
|
||||
self.display_value = self.display_value.trim_start_matches("-").to_string();
|
||||
} else {
|
||||
self.display_value = format!("-{}", self.display_value);
|
||||
}
|
||||
}
|
||||
fn toggle_percent(&mut self) {
|
||||
self.display_value = (self.display_value.parse::<f64>().unwrap() / 100.0).to_string();
|
||||
}
|
||||
fn backspace(&mut self) {
|
||||
if !self.display_value.as_str().eq("0") {
|
||||
self.display_value.pop();
|
||||
}
|
||||
}
|
||||
fn set_operator(&mut self, operator: Operator) {
|
||||
self.operator = Some(operator);
|
||||
self.cur_val = self.display_value.parse::<f64>().unwrap();
|
||||
self.waiting_for_operand = true;
|
||||
}
|
||||
fn handle_keydown(&mut self, evt: KeyboardEvent) {
|
||||
match evt.key_code() {
|
||||
KeyCode::Backspace => self.backspace(),
|
||||
KeyCode::_0 => self.input_digit(0),
|
||||
KeyCode::_1 => self.input_digit(1),
|
||||
KeyCode::_2 => self.input_digit(2),
|
||||
KeyCode::_3 => self.input_digit(3),
|
||||
KeyCode::_4 => self.input_digit(4),
|
||||
KeyCode::_5 => self.input_digit(5),
|
||||
KeyCode::_6 => self.input_digit(6),
|
||||
KeyCode::_7 => self.input_digit(7),
|
||||
KeyCode::_8 => self.input_digit(8),
|
||||
KeyCode::_9 => self.input_digit(9),
|
||||
KeyCode::Add => self.operator = Some(Operator::Add),
|
||||
KeyCode::Subtract => self.operator = Some(Operator::Sub),
|
||||
KeyCode::Divide => self.operator = Some(Operator::Div),
|
||||
KeyCode::Multiply => self.operator = Some(Operator::Mul),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
//! Basic example that renders a simple VNode to the browser.
|
||||
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
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
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
static App: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
Calcier {
|
||||
h2 {"abc 1"}
|
||||
h2 {"abc 2"}
|
||||
h2 {"abc 3"}
|
||||
h2 {"abc 4"}
|
||||
h2 {"abc 5"}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
static Calcier: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 {
|
||||
"abc 0"
|
||||
}
|
||||
{cx.children()}
|
||||
}
|
||||
})
|
||||
};
|
|
@ -1,65 +0,0 @@
|
|||
//! Example: Context API
|
||||
//! --------------------
|
||||
//! This example demonstrates how to use the raw context api for sharing state throughout the VirtualDOM Tree.
|
||||
//! A custom context must be its own unique type - otherwise use_context will fail. A context may be c
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));
|
||||
console_error_panic_hook::set_once();
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CustomContext([&'static str; 3]);
|
||||
|
||||
pub static Example: FC<()> = |cx, props|{
|
||||
cx.use_create_context(|| CustomContext(["Jack", "Jill", "Bob"]));
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
CustomButton { id: 0 }
|
||||
CustomButton { id: 1 }
|
||||
CustomButton { id: 2 }
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
#[derive(Props, PartialEq)]
|
||||
struct ButtonProps {
|
||||
id: u8,
|
||||
}
|
||||
|
||||
fn CustomButton(cx: Context<ButtonProps>) -> DomTree {
|
||||
let names = cx.use_context::<CustomContext>();
|
||||
let name = names.0[cx.id as usize];
|
||||
|
||||
cx.render(rsx!{
|
||||
button {
|
||||
class: "inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
|
||||
"{name}"
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(CustomA))
|
||||
}
|
||||
|
||||
fn CustomA(cx: Context<()>) -> DomTree {
|
||||
let (val, set_val) = use_state_classic(cx, || "abcdef".to_string() as String);
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
class: "m-8"
|
||||
"CustomA {val}"
|
||||
button {
|
||||
"Upper"
|
||||
onclick: move |_| set_val(val.to_ascii_uppercase())
|
||||
}
|
||||
button {
|
||||
"Lower"
|
||||
onclick: move |_| set_val(val.to_ascii_lowercase())
|
||||
}
|
||||
components::CustomB {
|
||||
val: val.clone()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
mod components {
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Props, PartialEq)]
|
||||
pub struct PropsB {
|
||||
val: String,
|
||||
}
|
||||
|
||||
pub fn CustomB(cx: Context<PropsB>) -> DomTree {
|
||||
let (first, last) = cx.val.split_at(3);
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
class: "m-8"
|
||||
"CustomB {cx.val}"
|
||||
CustomC {
|
||||
val: first.to_string()
|
||||
}
|
||||
CustomC {
|
||||
val: last.to_string()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, Props, PartialEq)]
|
||||
struct PropsC {
|
||||
val: String,
|
||||
}
|
||||
|
||||
fn CustomC(cx: Context<PropsC>) -> DomTree {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
class: "m-8"
|
||||
"CustomC {cx.val}"
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
//! An example where the dioxus vdom is running in a native thread, interacting with webview
|
||||
//! Content is passed from the native thread into the webview
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
fn main() {
|
||||
dioxus_desktop::launch(
|
||||
|builder| {
|
||||
builder
|
||||
.title("Test Dioxus App")
|
||||
.size(320, 480)
|
||||
.resizable(false)
|
||||
.debug(true)
|
||||
},
|
||||
(),
|
||||
Example,
|
||||
)
|
||||
.expect("Webview finished");
|
||||
}
|
||||
|
||||
// pub static Example: FC<()> = |cx, props|{
|
||||
// cx.render(html! {
|
||||
// <div>
|
||||
// <svg class="octicon octicon-star v-align-text-bottom"
|
||||
// viewBox="0 0 14 16" version="1.1"
|
||||
// width="14" height="16"
|
||||
// xmlns="http://www.w3.org/2000/svg"
|
||||
// >
|
||||
|
||||
// <path
|
||||
// d="M14 6l-4.9-.64L7 1 4.9 5.36 0 6l3.6 3.26L2.67 14"
|
||||
// xmlns="http://www.w3.org/2000/svg"
|
||||
// >
|
||||
// </path>
|
||||
|
||||
// </svg>
|
||||
// </div>
|
||||
// })
|
||||
// };
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
cx.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: "font-bold text-xl", "Example desktop app" }
|
||||
div { class: "text-sm text-gray-500", "This is running natively" }
|
||||
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"
|
||||
"Made with dioxus"
|
||||
}
|
||||
}
|
||||
ul {
|
||||
{(0..10).map(|f| rsx!(li {
|
||||
key: "{f}"
|
||||
"{f}"
|
||||
}))}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
|
@ -1 +0,0 @@
|
|||
fn main() {}
|
|
@ -1,89 +0,0 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_html::*;
|
||||
use dioxus_web::{dioxus::prelude::*, WebsysRenderer};
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App))
|
||||
}
|
||||
|
||||
fn App(cx: Context<()>) -> DomTree {
|
||||
cx.render(rsx! {
|
||||
div { class: "dark:bg-gray-800 bg-white relative h-screen"
|
||||
NavBar {}
|
||||
{(0..10).map(|f| rsx!(Landing { key: "{f}" }))}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn NavBar(cx: Context<()>) -> DomTree {
|
||||
cx.render(rsx!{
|
||||
header { class: "h-24 sm:h-32 flex items-center z-30 w-full"
|
||||
div { class: "container mx-auto px-6 flex items-center justify-between"
|
||||
div { class: "uppercase text-gray-800 dark:text-white font-black text-3xl"
|
||||
svg { focusable:"false" width:"100" height:"100" viewBox: "0 0 512 309"
|
||||
path { fill: "#000"
|
||||
d: "M120.81 80.561h96.568v7.676h-87.716v57.767h82.486v7.675h-82.486v63.423h88.722v7.675H120.81V80.561zm105.22 0h10.26l45.467 63.423L328.23 80.56L391.441 0l-103.85 150.65l53.515 74.127h-10.663l-48.686-67.462l-48.888 67.462h-10.461l53.917-74.128l-50.296-70.088zm118.898 7.676V80.56h110.048v7.676h-50.699v136.54h-8.852V88.237h-50.497zM0 80.56h11.065l152.58 228.323l-63.053-84.107L9.254 91.468l-.402 133.31H0V80.56zm454.084 134.224c-1.809 0-3.165-1.4-3.165-3.212c0-1.81 1.356-3.212 3.165-3.212c1.83 0 3.165 1.401 3.165 3.212c0 1.811-1.335 3.212-3.165 3.212zm8.698-8.45h4.737c.064 2.565 1.937 4.29 4.693 4.29c3.079 0 4.823-1.854 4.823-5.325v-21.99h4.823v22.011c0 6.252-3.617 9.853-9.603 9.853c-5.62 0-9.473-3.493-9.473-8.84zm25.384-.28h4.78c.409 2.953 3.294 4.828 7.45 4.828c3.875 0 6.717-2.005 6.717-4.764c0-2.371-1.809-3.794-5.921-4.764l-4.005-.97c-5.62-1.316-8.181-4.032-8.181-8.602c0-5.54 4.521-9.227 11.303-9.227c6.308 0 10.916 3.686 11.196 8.925h-4.694c-.452-2.867-2.95-4.657-6.567-4.657c-3.81 0-6.35 1.833-6.35 4.635c0 2.22 1.635 3.493 5.683 4.441l3.423.841c6.373 1.488 9 4.075 9 8.753c0 5.95-4.607 9.68-11.97 9.68c-6.89 0-11.52-3.558-11.864-9.12z"
|
||||
}
|
||||
}
|
||||
}
|
||||
div { class:"flex items-center"
|
||||
nav { class: "font-sen text-gray-800 dark:text-white uppercase text-lg lg:flex items-center hidden"
|
||||
a { href: "#", class:"py-2 px-6 flex text-indigo-500 border-b-2 border-indigo-500"
|
||||
"Home"
|
||||
}
|
||||
a { href: "#", class: "py-2 px-6 flex hover:text-indigo-500"
|
||||
"Watch"
|
||||
}
|
||||
a { href: "#", class: "py-2 px-6 flex hover:text-indigo-500"
|
||||
"Product"
|
||||
}
|
||||
a { href: "#", class: "py-2 px-6 flex hover:text-indigo-500"
|
||||
"Contact"
|
||||
}
|
||||
a { href: "#", class: "py-2 px-6 flex hover:text-indigo-500"
|
||||
"Career"
|
||||
}
|
||||
}
|
||||
button { class: "lg:hidden flex flex-col ml-4"
|
||||
span { class: "w-6 h-1 bg-gray-800 dark:bg-white mb-1" }
|
||||
span { class: "w-6 h-1 bg-gray-800 dark:bg-white mb-1" }
|
||||
span { class: "w-6 h-1 bg-gray-800 dark:bg-white mb-1" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn Landing(cx: Context<()>) -> DomTree {
|
||||
cx.render(rsx!{
|
||||
div { class: "bg-white dark:bg-gray-800 flex relative z-20 items-center"
|
||||
div { class: "container mx-auto px-6 flex flex-col justify-between items-center relative py-8"
|
||||
div { class: "flex flex-col"
|
||||
h1 { class: "font-light w-full uppercase text-center text-4xl sm:text-5xl dark:text-white text-gray-800"
|
||||
"The Dioxus Framework for Production"
|
||||
}
|
||||
h2{ class: "font-light max-w-2xl mx-auto w-full text-xl dark:text-white text-gray-500 text-center py-8"
|
||||
"Next.js gives you the best developer experience with all the features you need for production: \n
|
||||
hybrid static & server rendering, TypeScript support, smart bundling, route pre-fetching, and \n
|
||||
more. No config needed."
|
||||
}
|
||||
div { class: "flex items-center justify-center mt-4"
|
||||
a { href: "#" class: "uppercase py-2 px-4 bg-gray-800 border-2 border-transparent text-white text-md mr-4 hover:bg-gray-900"
|
||||
"Get started"
|
||||
}
|
||||
a{ href: "#" class: "uppercase py-2 px-4 bg-transparent border-2 border-gray-800 text-gray-800 dark:text-white hover:bg-gray-800 hover:text-white text-md"
|
||||
"Documentation"
|
||||
}
|
||||
}
|
||||
}
|
||||
div { class: "block w-full mx-auto mt-6 md:mt-0 relative"
|
||||
img { src: "/images/object/12.svg" class: "max-w-xs md:max-w-2xl m-auto" }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
use dioxus::{events::on::MouseEvent, prelude::*};
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
fn App(cx: Context<()>) -> DomTree {
|
||||
let cansee = use_state(cx, || false);
|
||||
rsx! { in cx,
|
||||
div {
|
||||
"Shadow of the child:"
|
||||
button { onclick: move |_| cansee.set(!**cansee)
|
||||
"Gaze into the void"
|
||||
}
|
||||
{cansee.then(|| rsx!{ Child {} })}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn Child(cx: Context<()>) -> DomTree {
|
||||
rsx! { in cx,
|
||||
section { class: "py-6 bg-coolGray-100 text-coolGray-900"
|
||||
div { class: "container mx-auto flex flex-col items-center justify-center p-4 space-y-8 md:p-10 md:px-24 xl:px-48"
|
||||
h1 { class: "text-5xl font-bold leading-none text-center",
|
||||
"Sign up now"
|
||||
}
|
||||
p { class: "text-xl font-medium text-center",
|
||||
"At a assumenda quas cum earum ut itaque commodi saepe rem aspernatur quam natus quis nihil quod, hic explicabo doloribus magnam neque, exercitationem eius sunt!"
|
||||
}
|
||||
div { class: "flex flex-col space-y-4 sm:space-y-0 sm:flex-row sm:space-x-8"
|
||||
button { class: "px-8 py-3 text-lg font-semibold rounded bg-violet-600 text-coolGray-50",
|
||||
"Get started"
|
||||
}
|
||||
button { class: "px-8 py-3 text-lg font-normal border rounded bg-coolGray-800 text-coolGray-50 border-coolGray-700",
|
||||
"Learn more"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_core::events::on::*;
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
fn main() {}
|
||||
|
||||
fn autocomplete() {
|
||||
// let handler = move |evt| {
|
||||
// let r = evt.alt_key();
|
||||
// if evt.alt_key() {}
|
||||
// };
|
||||
|
||||
// let g = rsx! {
|
||||
// button {
|
||||
// button {
|
||||
// onclick: {handler}
|
||||
// }
|
||||
// }
|
||||
|
||||
// };
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
//! Basic example that renders a simple VNode to the browser.
|
||||
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
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
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
static App: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
h2 { "abc 1" }
|
||||
div {
|
||||
"hello world!"
|
||||
}
|
||||
Fragment {
|
||||
h2 { "abc 2"}
|
||||
}
|
||||
})
|
||||
};
|
|
@ -1,33 +0,0 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
fn main() {
|
||||
// wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
// console_error_panic_hook::set_once();
|
||||
|
||||
// log::info!("hello world");
|
||||
dioxus_web::intern_cache();
|
||||
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
|
||||
}
|
||||
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
let nodes = (0..500).map(|f| rsx! (li {"div"}));
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
span {
|
||||
class: "px-2 py-1 flex w-36 mt-4 items-center text-xs rounded-md font-semibold text-yellow-500 bg-yellow-100"
|
||||
"DUE DATE : 189 JUN"
|
||||
}
|
||||
p {
|
||||
"these"
|
||||
"are"
|
||||
"text"
|
||||
"nodes"
|
||||
}
|
||||
{nodes}
|
||||
}
|
||||
})
|
||||
};
|
|
@ -1,13 +0,0 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_web::prelude::*;
|
||||
|
||||
fn main() {
|
||||
wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(App))
|
||||
}
|
||||
|
||||
fn App(cx: Context<()>) -> DomTree {
|
||||
cx.render(rsx! {
|
||||
div { "Hello, world!" }
|
||||
})
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
//! An example where the dioxus vdom is running in a native thread, interacting with webview
|
||||
//! Content is passed from the native thread into the webview
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
fn main() {
|
||||
dioxus_desktop::launch(
|
||||
|builder| {
|
||||
builder
|
||||
.title("Test Dioxus App")
|
||||
.size(320, 480)
|
||||
.resizable(false)
|
||||
.debug(true)
|
||||
},
|
||||
(),
|
||||
App,
|
||||
)
|
||||
.expect("Webview finished");
|
||||
}
|
||||
|
||||
static App: FC<()> = |cx, props| {
|
||||
let hifives = use_model(&cx, || 0);
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 { "Hi-fives collected: {hifives}" }
|
||||
button { "Hi five me!", onclick: move |_| *hifives.get_mut() += 1 }
|
||||
}
|
||||
})
|
||||
};
|
|
@ -1,59 +0,0 @@
|
|||
<div class="shadow-lg rounded-2xl p-4 bg-white dark:bg-gray-700 w-full">
|
||||
<p class="font-bold text-md text-black dark:text-white">
|
||||
"Messages"
|
||||
</p>
|
||||
<ul>
|
||||
<li class="flex items-center my-6 space-x-2">
|
||||
<a href="#" class="block relative">
|
||||
<img alt="profil" src="/images/person/1.jpg" class="mx-auto object-cover rounded-full h-10 w-10 " />
|
||||
</a>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm text-gray-900 font-semibold dark:text-white ml-2">
|
||||
{title}
|
||||
</span>
|
||||
<span class="text-sm text-gray-400 dark:text-gray-300 ml-2">
|
||||
"Hey John ! Do you read the NextJS doc ?"
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="flex items-center my-6 space-x-2">
|
||||
<a href="#" class="block relative">
|
||||
<img alt="profil" src="/images/person/5.jpg" class="mx-auto object-cover rounded-full h-10 w-10 " />
|
||||
</a>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm text-gray-900 font-semibold dark:text-white ml-2">
|
||||
"Marie Lou"
|
||||
</span>
|
||||
<span class="text-sm text-gray-400 dark:text-gray-300 ml-2">
|
||||
"No I think the dog is better..."
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="flex items-center my-6 space-x-2">
|
||||
<a href="#" class="block relative">
|
||||
<img alt="profil" src="/images/person/6.jpg" class="mx-auto object-cover rounded-full h-10 w-10 " />
|
||||
</a>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm text-gray-900 font-semibold dark:text-white ml-2">
|
||||
"Ivan Buck"
|
||||
</span>
|
||||
<span class="text-sm text-gray-400 dark:text-gray-300 ml-2">
|
||||
"Seriously ? haha Bob is not a children !"
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="flex items-center my-6 space-x-2">
|
||||
<a href="#" class="block relative">
|
||||
<img alt="profil" src="/images/person/7.jpg" class="mx-auto object-cover rounded-full h-10 w-10 " />
|
||||
</a>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm text-gray-900 font-semibold dark:text-white ml-2">
|
||||
"Marina Farga"
|
||||
</span>
|
||||
<span class="text-sm text-gray-400 dark:text-gray-300 ml-2">
|
||||
"Do you need that deisgn ?"
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
|
@ -1,59 +0,0 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_core::{events::on::MouseEvent, prelude::*};
|
||||
use dioxus_web::WebsysRenderer;
|
||||
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();
|
||||
|
||||
log::info!("hello world");
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
|
||||
}
|
||||
|
||||
// this is a component
|
||||
pub static Example: FC<()> = |cx, props|{
|
||||
let (event, set_event) = use_state_classic(cx, || None);
|
||||
|
||||
let handler = move |evt| {
|
||||
set_event(Some(evt));
|
||||
};
|
||||
|
||||
log::info!("hello world");
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
class: "py-12 px-4 w-full max-w-2xl mx-auto bg-red-100"
|
||||
span {
|
||||
class: "text-sm font-semibold"
|
||||
"Dioxus Example: Synthetic Events"
|
||||
}
|
||||
button {
|
||||
class: "inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
|
||||
"press me"
|
||||
}
|
||||
pre {
|
||||
onmousemove: {handler}
|
||||
id: "json"
|
||||
"Hello world"
|
||||
}
|
||||
Example2 { name: "Blah".into() }
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Props)]
|
||||
struct ExampleProps {
|
||||
name: String,
|
||||
}
|
||||
|
||||
pub static Example2: FC<ExampleProps> = |cx, props|{
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 {"hello {cx.name}"}
|
||||
}
|
||||
})
|
||||
};
|
|
@ -1,67 +0,0 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
|
||||
fn main() {
|
||||
// wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
log::info!("hello world");
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
static App: FC<()> = |cx, props|{
|
||||
let (val, set_val) = use_state_classic(cx, || "asd".to_string());
|
||||
|
||||
cx.render(rsx! {
|
||||
div { class: "max-w-lg max-w-xs bg-blue-800 shadow-2xl rounded-lg mx-auto text-center py-12 mt-4 rounded-xl"
|
||||
div { class: "container py-5 max-w-md mx-auto"
|
||||
h1 { class: "text-gray-200 text-center font-extrabold -mt-3 text-3xl",
|
||||
"Text Input Example"
|
||||
}
|
||||
div { class: "mb-4"
|
||||
input {
|
||||
placeholder: "Username"
|
||||
class: "shadow appearance-none rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||
id: "username"
|
||||
r#type: "text"
|
||||
value: "{val}"
|
||||
oninput: move |evet| set_val(evet.value())
|
||||
}
|
||||
p { "Val is: {val}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
pub static Example: FC<()> = |cx, props|{
|
||||
cx.render(rsx! {
|
||||
div { class: "max-w-lg max-w-xs bg-blue-800 shadow-2xl rounded-lg mx-auto text-center py-12 mt-4 rounded-xl"
|
||||
div { class: "container py-5 max-w-md mx-auto"
|
||||
h1 { class: "text-gray-200 text-center font-extrabold -mt-3 text-3xl",
|
||||
"Text Input Example"
|
||||
}
|
||||
UserInput {}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
static UserInput: FC<()> = |cx, props|{
|
||||
let (val, set_val) = use_state_classic(cx, || "asd".to_string());
|
||||
|
||||
rsx! { in cx,
|
||||
div { class: "mb-4"
|
||||
input { class: "shadow appearance-none rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||
placeholder: "Username"
|
||||
id: "username"
|
||||
r#type: "text"
|
||||
oninput: move |evet| set_val(evet.value())
|
||||
}
|
||||
p { "Val is: {val}" }
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,49 +0,0 @@
|
|||
use dioxus::prelude::*;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example))
|
||||
}
|
||||
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
let (name, set_name) = use_state_classic(cx, || "...?");
|
||||
|
||||
log::debug!("Running component....");
|
||||
|
||||
cx.render(html! {
|
||||
<div>
|
||||
<section class="py-12 px-4 text-center">
|
||||
<div class="w-full max-w-2xl mx-auto">
|
||||
// Tagline
|
||||
<span class="text-sm font-semibold">
|
||||
"Dioxus Example: Jack and Jill"
|
||||
</span>
|
||||
|
||||
// Header
|
||||
<h2 class="text-5xl mt-2 mb-6 leading-tight font-semibold font-heading">
|
||||
"Hello, {name}"
|
||||
</h2>
|
||||
|
||||
// Control buttons
|
||||
<div>
|
||||
<button
|
||||
class="inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
|
||||
onclick={move |_| set_name("jack")}>
|
||||
"Jack!"
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
|
||||
onclick={move |_| set_name("jill")}>
|
||||
"Jill!"
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
})
|
||||
};
|
|
@ -1,38 +0,0 @@
|
|||
use dioxus::prelude::*;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example))
|
||||
}
|
||||
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
let (name, set_name) = use_state_classic(cx, || "...?");
|
||||
cx.render(rsx! {
|
||||
section { class: "py-12 px-4 text-center"
|
||||
div { class: "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, {name}"
|
||||
}
|
||||
div {
|
||||
button {
|
||||
class:"inline-block py-4 px-8 m-2 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
|
||||
onclick: move |_| set_name("jack")
|
||||
"Jack!"
|
||||
}
|
||||
button {
|
||||
class:"inline-block py-4 px-8 m-2 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
|
||||
onclick: move |_| set_name("jill")
|
||||
"Jill!"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
|
@ -1,45 +0,0 @@
|
|||
//! Basic example that renders a simple VNode to the browser.
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
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
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
static App: FC<()> = |cx, props| {
|
||||
let (contents, set_contents) = use_state_classic(cx, || "asd");
|
||||
|
||||
cx.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: "font-bold text-xl", "Example cloud app" }
|
||||
div { class: "text-sm text-gray-500", "This is running in the cloud!!" }
|
||||
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"
|
||||
"Made with dioxus"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
|
@ -1,37 +0,0 @@
|
|||
//! Basic example that renders a simple VNode to the browser.
|
||||
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_web::*;
|
||||
|
||||
fn main() {
|
||||
// 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));
|
||||
}
|
||||
|
||||
static App: FC<()> = |cx, props| {
|
||||
let (contents, set_contents) = use_state_classic(cx, || "asd");
|
||||
|
||||
cx.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: "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: "font-medium text-6xl", "100%" }
|
||||
}
|
||||
div { class: "flex flex-row justify-between mt-6"
|
||||
a { href: "https://www.dioxuslabs.com", class: "underline"
|
||||
"Made with dioxus"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
|
@ -1,174 +0,0 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
static APP_STYLE: &'static str = include_str!("./todomvc/style.css");
|
||||
|
||||
#[derive(PartialEq, Clone, Copy)]
|
||||
pub enum FilterState {
|
||||
All,
|
||||
Active,
|
||||
Completed,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct TodoItem {
|
||||
pub id: uuid::Uuid,
|
||||
pub checked: bool,
|
||||
pub contents: String,
|
||||
}
|
||||
|
||||
static App: FC<()> = |cx, props| {
|
||||
let (draft, set_draft) = use_state_classic(cx, || "".to_string());
|
||||
let (filter, set_filter) = use_state_classic(cx, || FilterState::All);
|
||||
let todos = use_state(cx, || BTreeMap::<uuid::Uuid, TodoItem>::new());
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
id: "app"
|
||||
div {
|
||||
header {
|
||||
class: "header"
|
||||
h1 {"todos"}
|
||||
button {
|
||||
"press me"
|
||||
onclick: move |evt| {
|
||||
let contents = draft.clone();
|
||||
todos.modify(|f| {
|
||||
let id = uuid::Uuid::new_v4();
|
||||
f.insert(id.clone(), TodoItem {
|
||||
id,
|
||||
checked: false,
|
||||
contents
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
input {
|
||||
class: "new-todo"
|
||||
placeholder: "What needs to be done?"
|
||||
oninput: move |evt| set_draft(evt.value())
|
||||
}
|
||||
}
|
||||
|
||||
{ // list
|
||||
todos
|
||||
.iter()
|
||||
.filter(|(id, item)| match filter {
|
||||
FilterState::All => true,
|
||||
FilterState::Active => !item.checked,
|
||||
FilterState::Completed => item.checked,
|
||||
})
|
||||
.map(|(id, todo)| {
|
||||
rsx!{
|
||||
li {
|
||||
key: "{id}"
|
||||
"{todo.contents}"
|
||||
input {
|
||||
class: "toggle"
|
||||
r#type: "checkbox"
|
||||
"{todo.checked}"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// filter toggle (show only if the list isn't empty)
|
||||
{(!todos.is_empty()).then(||
|
||||
rsx!{
|
||||
footer {
|
||||
span {
|
||||
strong {"10"}
|
||||
span {"0 items left"}
|
||||
}
|
||||
ul {
|
||||
class: "filters"
|
||||
{[
|
||||
("All", "", FilterState::All),
|
||||
("Active", "active", FilterState::Active),
|
||||
("Completed", "completed", FilterState::Completed),
|
||||
]
|
||||
.iter()
|
||||
.map(|(name, path, filter)| {
|
||||
rsx!(
|
||||
li {
|
||||
class: "{name}"
|
||||
a {
|
||||
href: "{path}"
|
||||
onclick: move |_| set_filter(filter.clone())
|
||||
"{name}"
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
}}
|
||||
}
|
||||
}
|
||||
)}
|
||||
}
|
||||
|
||||
|
||||
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" }
|
||||
}
|
||||
}
|
||||
}
|
||||
))
|
||||
};
|
||||
|
||||
pub fn FilterToggles(cx: Context<()>) -> DomTree {
|
||||
// let reducer = recoil::use_callback(&cx, || ());
|
||||
// let items_left = recoil::use_atom_family(&cx, &TODOS, uuid::Uuid::new_v4());
|
||||
|
||||
let toggles = [
|
||||
("All", "", FilterState::All),
|
||||
("Active", "active", FilterState::Active),
|
||||
("Completed", "completed", FilterState::Completed),
|
||||
]
|
||||
.iter()
|
||||
.map(|(name, path, _filter)| {
|
||||
rsx!(
|
||||
li {
|
||||
class: "{name}"
|
||||
a {
|
||||
href: "{path}"
|
||||
// onclick: move |_| reducer.set_filter(&filter)
|
||||
"{name}"
|
||||
}
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
// todo
|
||||
let item_text = "";
|
||||
let items_left = "";
|
||||
|
||||
cx.render(rsx! {
|
||||
footer {
|
||||
span {
|
||||
strong {"{items_left}"}
|
||||
span {"{item_text} left"}
|
||||
}
|
||||
ul {
|
||||
class: "filters"
|
||||
{toggles}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
log::info!("hello world");
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(JonsFavoriteCustomApp));
|
||||
}
|
||||
|
||||
fn JonsFavoriteCustomApp(cx: Context<()>) -> DomTree {
|
||||
let items = (0..20).map(|f| {
|
||||
rsx! {
|
||||
li {"{f}"}
|
||||
}
|
||||
});
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
"list"
|
||||
ul {
|
||||
{items}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
log::info!("hello world");
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
|
||||
}
|
||||
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
span {
|
||||
class: "px-2 py-1 flex w-36 mt-4 items-center text-xs rounded-md font-semibold text-yellow-500 bg-yellow-100"
|
||||
"DUE DATE : 18 JUN"
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
|
@ -1,193 +0,0 @@
|
|||
//! Example: Calculator
|
||||
//! -------------------
|
||||
//!
|
||||
//! Some components benefit through the use of "Models". Models are a single block of encapsulated state that allow mutative
|
||||
//! methods to be performed on them. Dioxus exposes the ability to use the model pattern through the "use_model" hook.
|
||||
//!
|
||||
//! Models are commonly used in the "Model-View-Component" approach for building UI state.
|
||||
//!
|
||||
//! `use_model` is basically just a fancy wrapper around set_state, but saves a "working copy" of the new state behind a
|
||||
//! RefCell. To modify the working copy, you need to call "get_mut" which returns the RefMut. This makes it easy to write
|
||||
//! fully encapsulated apps that retain a certain feel of native Rusty-ness. A calculator app is a good example of when this
|
||||
//! is useful.
|
||||
//!
|
||||
//! Do note that "get_mut" returns a `RefMut` (a lock over a RefCell). If two `RefMut`s are held at the same time (ie in a loop)
|
||||
//! the RefCell will panic and crash. You can use `try_get_mut` or `.modify` to avoid this problem, or just not hold two
|
||||
//! RefMuts at the same time.
|
||||
|
||||
use dioxus::events::on::*;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
const STYLE: &str = include_str!("../../../examples/assets/calculator.css");
|
||||
|
||||
fn main() {
|
||||
// Setup logging
|
||||
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));
|
||||
}
|
||||
|
||||
static App: FC<()> = |cx, props| {
|
||||
let state = use_model(&cx, || Calculator::new());
|
||||
|
||||
let clear_display = state.display_value.eq("0");
|
||||
let clear_text = if clear_display { "C" } else { "AC" };
|
||||
let formatted = state.formatted_display();
|
||||
|
||||
cx.render(rsx! {
|
||||
div { id: "wrapper"
|
||||
div { class: "app", style { "{STYLE}" }
|
||||
div { class: "calculator", onkeypress: move |evt| state.get_mut().handle_keydown(evt),
|
||||
div { class: "calculator-display", "{formatted}"}
|
||||
div { class: "calculator-keypad"
|
||||
div { class: "input-keys"
|
||||
div { class: "function-keys"
|
||||
CalculatorKey { name: "key-clear", onclick: move |_| state.get_mut().clear_display(), "{clear_text}" }
|
||||
CalculatorKey { name: "key-sign", onclick: move |_| state.get_mut().toggle_sign(), "±"}
|
||||
CalculatorKey { name: "key-percent", onclick: move |_| state.get_mut().toggle_percent(), "%"}
|
||||
}
|
||||
div { class: "digit-keys"
|
||||
CalculatorKey { name: "key-0", onclick: move |_| state.get_mut().input_digit(0), "0" }
|
||||
CalculatorKey { name: "key-dot", onclick: move |_| state.get_mut().input_dot(), "●" }
|
||||
{(1..10).map(move |k| rsx!{
|
||||
CalculatorKey { key: "{k}", name: "key-{k}", onclick: move |_| state.get_mut().input_digit(k), "{k}" }
|
||||
})}
|
||||
}
|
||||
}
|
||||
div { class: "operator-keys"
|
||||
CalculatorKey { name:"key-divide", onclick: move |_| state.get_mut().set_operator(Operator::Div), "÷" }
|
||||
CalculatorKey { name:"key-multiply", onclick: move |_| state.get_mut().set_operator(Operator::Mul), "×" }
|
||||
CalculatorKey { name:"key-subtract", onclick: move |_| state.get_mut().set_operator(Operator::Sub), "−" }
|
||||
CalculatorKey { name:"key-add", onclick: move |_| state.get_mut().set_operator(Operator::Add), "+" }
|
||||
CalculatorKey { name:"key-equals", onclick: move |_| state.get_mut().perform_operation(), "=" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
#[derive(Props)]
|
||||
struct CalculatorKeyProps<'a> {
|
||||
name: &'static str,
|
||||
onclick: &'a dyn Fn(MouseEvent),
|
||||
}
|
||||
|
||||
fn CalculatorKey<'a, 'r>(cx: Context<'a, CalculatorKeyProps<'r>>) -> DomTree<'a> {
|
||||
cx.render(rsx! {
|
||||
button {
|
||||
class: "calculator-key {cx.name}"
|
||||
onclick: {cx.onclick}
|
||||
{cx.children()}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Calculator {
|
||||
display_value: String,
|
||||
operator: Option<Operator>,
|
||||
waiting_for_operand: bool,
|
||||
cur_val: f64,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
enum Operator {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
}
|
||||
|
||||
impl Calculator {
|
||||
fn new() -> Self {
|
||||
Calculator {
|
||||
display_value: "0".to_string(),
|
||||
operator: None,
|
||||
waiting_for_operand: false,
|
||||
cur_val: 0.0,
|
||||
}
|
||||
}
|
||||
fn formatted_display(&self) -> String {
|
||||
use separator::Separatable;
|
||||
self.display_value
|
||||
.parse::<f64>()
|
||||
.unwrap()
|
||||
.separated_string()
|
||||
}
|
||||
fn clear_display(&mut self) {
|
||||
self.display_value = "0".to_string();
|
||||
}
|
||||
fn input_digit(&mut self, digit: u8) {
|
||||
let content = digit.to_string();
|
||||
if self.waiting_for_operand || self.display_value == "0" {
|
||||
self.waiting_for_operand = false;
|
||||
self.display_value = content;
|
||||
} else {
|
||||
self.display_value.push_str(content.as_str());
|
||||
}
|
||||
}
|
||||
fn input_dot(&mut self) {
|
||||
if self.display_value.find(".").is_none() {
|
||||
self.display_value.push_str(".");
|
||||
}
|
||||
}
|
||||
fn perform_operation(&mut self) {
|
||||
if let Some(op) = &self.operator {
|
||||
let rhs = self.display_value.parse::<f64>().unwrap();
|
||||
let new_val = match op {
|
||||
Operator::Add => self.cur_val + rhs,
|
||||
Operator::Sub => self.cur_val - rhs,
|
||||
Operator::Mul => self.cur_val * rhs,
|
||||
Operator::Div => self.cur_val / rhs,
|
||||
};
|
||||
self.cur_val = new_val;
|
||||
self.display_value = new_val.to_string();
|
||||
self.operator = None;
|
||||
}
|
||||
}
|
||||
fn toggle_sign(&mut self) {
|
||||
if self.display_value.starts_with("-") {
|
||||
self.display_value = self.display_value.trim_start_matches("-").to_string();
|
||||
} else {
|
||||
self.display_value = format!("-{}", self.display_value);
|
||||
}
|
||||
}
|
||||
fn toggle_percent(&mut self) {
|
||||
self.display_value = (self.display_value.parse::<f64>().unwrap() / 100.0).to_string();
|
||||
}
|
||||
fn backspace(&mut self) {
|
||||
if !self.display_value.as_str().eq("0") {
|
||||
self.display_value.pop();
|
||||
}
|
||||
}
|
||||
fn set_operator(&mut self, operator: Operator) {
|
||||
self.operator = Some(operator);
|
||||
self.cur_val = self.display_value.parse::<f64>().unwrap();
|
||||
self.waiting_for_operand = true;
|
||||
}
|
||||
fn handle_keydown(&mut self, evt: KeyboardEvent) {
|
||||
match evt.key_code() {
|
||||
KeyCode::Backspace => self.backspace(),
|
||||
KeyCode::_0 => self.input_digit(0),
|
||||
KeyCode::_1 => self.input_digit(1),
|
||||
KeyCode::_2 => self.input_digit(2),
|
||||
KeyCode::_3 => self.input_digit(3),
|
||||
KeyCode::_4 => self.input_digit(4),
|
||||
KeyCode::_5 => self.input_digit(5),
|
||||
KeyCode::_6 => self.input_digit(6),
|
||||
KeyCode::_7 => self.input_digit(7),
|
||||
KeyCode::_8 => self.input_digit(8),
|
||||
KeyCode::_9 => self.input_digit(9),
|
||||
KeyCode::Add => self.operator = Some(Operator::Add),
|
||||
KeyCode::Subtract => self.operator = Some(Operator::Sub),
|
||||
KeyCode::Divide => self.operator = Some(Operator::Div),
|
||||
KeyCode::Multiply => self.operator = Some(Operator::Mul),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
#[derive(Props)]
|
||||
struct MyProps<'a> {
|
||||
blah: u128,
|
||||
b: &'a (),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// let p = unsafe { MyProps {}.memoize(&MyProps {}) };
|
||||
// dbg!(p);
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
// use dioxus_core::prelude::*;
|
||||
// use dioxus_web::WebsysRenderer;
|
||||
|
||||
// fn main() {
|
||||
// wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
|
||||
// }
|
||||
|
||||
// fn Example(cx: Context, props: ()) -> DomTree {
|
||||
// let user_data = use_sql_query(&cx, USER_DATA_QUERY);
|
||||
|
||||
// cx.render(rsx! {
|
||||
// h1 { "Hello, {username}"}
|
||||
// button {
|
||||
// "Delete user"
|
||||
// onclick: move |_| user_data.delete()
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
fn main() {}
|
|
@ -1,86 +0,0 @@
|
|||
#![allow(non_snake_case)]
|
||||
use std::rc::Rc;
|
||||
|
||||
use dioxus::{events::on::MouseEvent, prelude::*};
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
wasm_bindgen_futures::spawn_local(async {
|
||||
let props = ExampleProps {
|
||||
initial_name: "..?",
|
||||
};
|
||||
WebsysRenderer::new_with_props(Example, props)
|
||||
.run()
|
||||
.await
|
||||
.unwrap()
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Props)]
|
||||
struct ExampleProps {
|
||||
initial_name: &'static str,
|
||||
}
|
||||
|
||||
pub static Example: FC<ExampleProps> = |cx, props|{
|
||||
let name = use_state(cx, move || cx.initial_name);
|
||||
|
||||
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, {name}"
|
||||
}
|
||||
|
||||
CustomButton { name: "Jack!", handler: move |_| name.set("Jack") }
|
||||
CustomButton { name: "Jill!", handler: move |_| name.set("Jill") }
|
||||
CustomButton { name: "Bob!", handler: move |_| name.set("Bob")}
|
||||
Placeholder {val: name}
|
||||
Placeholder {val: name}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
#[derive(Props)]
|
||||
struct ButtonProps<'src, F: Fn(MouseEvent)> {
|
||||
name: &'src str,
|
||||
handler: F,
|
||||
}
|
||||
|
||||
fn CustomButton<'a, F: Fn(MouseEvent)>(cx: Context<'a, ButtonProps<'a, F>>) -> DomTree {
|
||||
cx.render(rsx!{
|
||||
button {
|
||||
class: "inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
|
||||
onmouseover: {&cx.handler}
|
||||
"{cx.name}"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
impl<F: Fn(MouseEvent)> PartialEq for ButtonProps<'_, F> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Props, PartialEq)]
|
||||
struct PlaceholderProps {
|
||||
val: &'static str,
|
||||
}
|
||||
fn Placeholder(cx: Context<PlaceholderProps>) -> DomTree {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
"child: {cx.val}"
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
use std::{collections::HashMap, rc::Rc};
|
||||
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
static APP_STYLE: &'static str = include_str!("./todomvc/style.css");
|
||||
|
||||
fn main() {
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum FilterState {
|
||||
All,
|
||||
Active,
|
||||
Completed,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct TodoItem {
|
||||
pub id: uuid::Uuid,
|
||||
pub checked: bool,
|
||||
pub contents: String,
|
||||
}
|
||||
|
||||
pub fn App(cx: Context<()>) -> DomTree {
|
||||
let (draft, set_draft) = use_state_classic(cx, || "".to_string());
|
||||
let (todos, set_todos) = use_state_classic(cx, || HashMap::<uuid::Uuid, Rc<TodoItem>>::new());
|
||||
let (filter, set_filter) = use_state_classic(cx, || FilterState::All);
|
||||
|
||||
let filtered_todos = todos.iter().filter(move |(id, item)| match filter {
|
||||
FilterState::All => true,
|
||||
FilterState::Active => !item.checked,
|
||||
FilterState::Completed => item.checked,
|
||||
});
|
||||
let items_left = filtered_todos.clone().count();
|
||||
let item_text = match items_left {
|
||||
1 => "item",
|
||||
_ => "items",
|
||||
};
|
||||
|
||||
cx.render(rsx! {
|
||||
div { id: "app"
|
||||
div {
|
||||
header { class: "header"
|
||||
h1 {"todos"}
|
||||
input {
|
||||
class: "new-todo"
|
||||
placeholder: "What needs to be done?"
|
||||
value: "{draft}"
|
||||
oninput: move |evt| set_draft(evt.value())
|
||||
}
|
||||
}
|
||||
|
||||
{filtered_todos.map(|(id, item)| {
|
||||
rsx!(TodoEntry {
|
||||
key: "{id}",
|
||||
item: item.clone()
|
||||
})
|
||||
})}
|
||||
|
||||
// filter toggle (show only if the list isn't empty)
|
||||
{(!todos.is_empty()).then(|| rsx!(
|
||||
footer {
|
||||
span {
|
||||
strong {"{items_left}"}
|
||||
span {"{item_text} left"}
|
||||
}
|
||||
ul {
|
||||
class: "filters"
|
||||
li { class: "All", a { href: "", onclick: move |_| set_filter(FilterState::All), "All" }}
|
||||
li { class: "Active", a { href: "active", onclick: move |_| set_filter(FilterState::Active), "Active" }}
|
||||
li { class: "Completed", a { href: "completed", onclick: move |_| set_filter(FilterState::Completed), "Completed" }}
|
||||
}
|
||||
}
|
||||
))}
|
||||
}
|
||||
// footer
|
||||
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 {
|
||||
item: Rc<TodoItem>,
|
||||
}
|
||||
|
||||
pub fn TodoEntry(cx: Context<TodoEntryProps>) -> DomTree {
|
||||
let (is_editing, set_is_editing) = use_state_classic(cx, || false);
|
||||
let contents = "";
|
||||
let todo = TodoItem {
|
||||
checked: false,
|
||||
contents: "asd".to_string(),
|
||||
id: uuid::Uuid::new_v4(),
|
||||
};
|
||||
|
||||
cx.render(rsx! (
|
||||
li {
|
||||
"{todo.id}"
|
||||
input {
|
||||
class: "toggle"
|
||||
r#type: "checkbox"
|
||||
"{todo.checked}"
|
||||
}
|
||||
{is_editing.then(|| rsx!{
|
||||
input {
|
||||
value: "{contents}"
|
||||
}
|
||||
})}
|
||||
}
|
||||
))
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
use crate::recoil;
|
||||
use crate::state::{FilterState, TODOS};
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
pub fn FilterToggles(cx: Context<()>) -> DomTree {
|
||||
let reducer = recoil::use_callback(&cx, || ());
|
||||
let items_left = recoil::use_atom_family(&cx, &TODOS, uuid::Uuid::new_v4());
|
||||
|
||||
let toggles = [
|
||||
("All", "", FilterState::All),
|
||||
("Active", "active", FilterState::Active),
|
||||
("Completed", "completed", FilterState::Completed),
|
||||
]
|
||||
.iter()
|
||||
.map(|(name, path, filter)| {
|
||||
rsx!(li {
|
||||
class: "{name}"
|
||||
a {
|
||||
"{name}"
|
||||
href: "{path}"
|
||||
onclick: move |_| reducer.set_filter(&filter)
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// todo
|
||||
let item_text = "";
|
||||
let items_left = "";
|
||||
|
||||
cx.render(rsx! {
|
||||
footer {
|
||||
span {
|
||||
strong {"{items_left}"}
|
||||
span {"{item_text} left"}
|
||||
}
|
||||
ul {
|
||||
class: "filters"
|
||||
{toggles}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_web::{prelude::*, WebsysRenderer};
|
||||
|
||||
// mod filtertoggles;
|
||||
// mod recoil;
|
||||
// mod state;
|
||||
// mod todoitem;
|
||||
// mod todolist;
|
||||
|
||||
static APP_STYLE: &'static str = include_str!("./style.css");
|
||||
|
||||
fn main() {
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
id: "app"
|
||||
// style { "{APP_STYLE}" }
|
||||
|
||||
// list
|
||||
// todolist::TodoList {}
|
||||
|
||||
// footer
|
||||
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" }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}))
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
use dioxus_core::context::Context;
|
||||
|
||||
pub struct RecoilContext<T: 'static> {
|
||||
_inner: T,
|
||||
}
|
||||
|
||||
impl<T: 'static> RecoilContext<T> {
|
||||
/// Get the value of an atom. Returns a reference to the underlying data.
|
||||
|
||||
pub fn get(&self) {}
|
||||
|
||||
/// Replace an existing value with a new value
|
||||
///
|
||||
/// This does not replace the value instantly, and all calls to "get" within the current scope will return
|
||||
pub fn set(&self) {}
|
||||
|
||||
// Modify lets you modify the value in place. However, because there's no previous value around to compare
|
||||
// the new one with, we are unable to memoize the change. As such, all downsteam users of this Atom will
|
||||
// be updated, causing all subsrcibed components to re-render.
|
||||
//
|
||||
// This is fine for most values, but might not be performant when dealing with collections. For collections,
|
||||
// use the "Family" variants as these will stay memoized for inserts, removals, and modifications.
|
||||
//
|
||||
// Note - like "set" this won't propogate instantly. Once all "gets" are dropped, only then will we run the
|
||||
pub fn modify(&self) {}
|
||||
}
|
||||
|
||||
pub fn use_callback<'a, G>(c: &Context<'a>, f: impl Fn() -> G) -> &'a RecoilContext<G> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn use_atom<T: PartialEq, O>(c: &Context, t: &'static Atom<T>) -> O {
|
||||
todo!()
|
||||
}
|
||||
pub fn use_batom<T: PartialEq, O>(c: &Context, t: impl Readable) -> O {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub trait Readable {}
|
||||
impl<T: PartialEq> Readable for &'static Atom<T> {}
|
||||
impl<K: PartialEq, V: PartialEq> Readable for &'static AtomFamily<K, V> {}
|
||||
|
||||
pub fn use_atom_family<'a, K: PartialEq, V: PartialEq>(
|
||||
c: &Context<'a>,
|
||||
t: &'static AtomFamily<K, V>,
|
||||
g: K,
|
||||
) -> &'a V {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub use atoms::{atom, Atom};
|
||||
pub use atoms::{atom_family, AtomFamily};
|
||||
mod atoms {
|
||||
|
||||
use super::*;
|
||||
pub struct AtomBuilder<T: PartialEq> {
|
||||
pub key: String,
|
||||
pub manual_init: Option<Box<dyn Fn() -> T>>,
|
||||
_never: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: PartialEq> AtomBuilder<T> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
key: uuid::Uuid::new_v4().to_string(),
|
||||
manual_init: None,
|
||||
_never: std::marker::PhantomData {},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init<A: Fn() -> T + 'static>(&mut self, f: A) {
|
||||
self.manual_init = Some(Box::new(f));
|
||||
}
|
||||
|
||||
pub fn set_key(&mut self, _key: &'static str) {}
|
||||
}
|
||||
|
||||
pub struct atom<T: PartialEq>(pub fn(&mut AtomBuilder<T>) -> T);
|
||||
pub type Atom<T: PartialEq> = atom<T>;
|
||||
|
||||
pub struct AtomFamilyBuilder<K, V> {
|
||||
_never: std::marker::PhantomData<(K, V)>,
|
||||
}
|
||||
|
||||
pub struct atom_family<K: PartialEq, V: PartialEq>(pub fn(&mut AtomFamilyBuilder<K, V>));
|
||||
pub type AtomFamily<K: PartialEq, V: PartialEq> = atom_family<K, V>;
|
||||
}
|
||||
|
||||
pub use selectors::selector;
|
||||
mod selectors {
|
||||
pub struct SelectorBuilder<Out, const Built: bool> {
|
||||
_p: std::marker::PhantomData<Out>,
|
||||
}
|
||||
impl<O> SelectorBuilder<O, false> {
|
||||
pub fn getter(self, f: impl Fn(()) -> O) -> SelectorBuilder<O, true> {
|
||||
todo!()
|
||||
// std::rc::Rc::pin(value)
|
||||
// todo!()
|
||||
}
|
||||
}
|
||||
pub struct selector<O>(pub fn(SelectorBuilder<O, false>) -> SelectorBuilder<O, true>);
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
use crate::recoil::*;
|
||||
|
||||
pub static TODOS: AtomFamily<uuid::Uuid, TodoItem> = atom_family(|_| {});
|
||||
pub static FILTER: Atom<FilterState> = atom(|_| FilterState::All);
|
||||
pub static SHOW_ALL_TODOS: selector<bool> = selector(|g| g.getter(|f| false));
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum FilterState {
|
||||
All,
|
||||
Active,
|
||||
Completed,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct TodoItem {
|
||||
pub id: uuid::Uuid,
|
||||
pub checked: bool,
|
||||
pub contents: String,
|
||||
}
|
||||
|
||||
impl RecoilContext<()> {
|
||||
pub fn add_todo(&self, contents: String) {}
|
||||
|
||||
pub fn remove_todo(&self, id: &uuid::Uuid) {
|
||||
// TODOS.with().remove(id)
|
||||
}
|
||||
|
||||
pub fn select_all_todos(&self) {}
|
||||
|
||||
pub fn toggle_todo(&self, id: &uuid::Uuid) {}
|
||||
|
||||
pub fn clear_completed(&self) {
|
||||
// let (set, get) = (self.set, self.get);
|
||||
|
||||
// TOODS
|
||||
// .get(&cx)
|
||||
// .iter()
|
||||
// .filter(|(k, v)| v.checked)
|
||||
// .map(|(k, v)| TODOS.remove(&cx, k));
|
||||
}
|
||||
|
||||
pub fn set_filter(&self, filter: &FilterState) {}
|
||||
}
|
|
@ -1,376 +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,29 +0,0 @@
|
|||
use super::state::TODOS;
|
||||
use crate::recoil::use_atom_family;
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
#[derive(PartialEq, Props)]
|
||||
pub struct TodoEntryProps {
|
||||
id: uuid::Uuid,
|
||||
}
|
||||
|
||||
pub fn TodoEntry(cx: Context, props: &TodoEntryProps) -> DomTree {
|
||||
let (is_editing, set_is_editing) = use_state(cx, || false);
|
||||
let todo = use_atom_family(&cx, &TODOS, cx.id);
|
||||
|
||||
cx.render(rsx! (
|
||||
li {
|
||||
"{todo.id}"
|
||||
input {
|
||||
class: "toggle"
|
||||
type: "checkbox"
|
||||
"{todo.checked}"
|
||||
}
|
||||
{is_editing.then(|| rsx!(
|
||||
input {
|
||||
value: "{todo.contents}"
|
||||
}
|
||||
))}
|
||||
}
|
||||
))
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
use crate::{
|
||||
filtertoggles,
|
||||
recoil::use_atom,
|
||||
state::{FilterState, TodoItem, FILTER, TODOS},
|
||||
todoitem::TodoEntry,
|
||||
};
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
pub fn TodoList(cx: Context<()>) -> DomTree {
|
||||
let (draft, set_draft) = use_state(cx, || "".to_string());
|
||||
let (todos, _) = use_state(cx, || Vec::<TodoItem>::new());
|
||||
let filter = use_atom(&cx, &FILTER);
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
header {
|
||||
class: "header"
|
||||
h1 {"todos"}
|
||||
input {
|
||||
class: "new-todo"
|
||||
placeholder: "What needs to be done?"
|
||||
value: "{draft}"
|
||||
oninput: move |evt| set_draft(evt.value)
|
||||
}
|
||||
}
|
||||
|
||||
{ // list
|
||||
todos
|
||||
.iter()
|
||||
.filter(|item| match filter {
|
||||
FilterState::All => true,
|
||||
FilterState::Active => !item.checked,
|
||||
FilterState::Completed => item.checked,
|
||||
})
|
||||
.map(|item| {
|
||||
rsx!(TodoEntry {
|
||||
key: "{order}",
|
||||
id: item.id,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// filter toggle (show only if the list isn't empty)
|
||||
{(!todos.is_empty()).then(||
|
||||
rsx!( filtertoggles::FilterToggles {})
|
||||
)}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
use std::{collections::HashMap, rc::Rc};
|
||||
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
static APP_STYLE: &'static str = include_str!("./todomvc/style.css");
|
||||
|
||||
fn main() {
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum FilterState {
|
||||
All,
|
||||
Active,
|
||||
Completed,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct TodoItem {
|
||||
pub id: uuid::Uuid,
|
||||
pub checked: bool,
|
||||
pub contents: String,
|
||||
}
|
||||
|
||||
// =======================
|
||||
// Components
|
||||
// =======================
|
||||
pub fn App(cx: Context<()>) -> DomTree {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
id: "app"
|
||||
|
||||
// list
|
||||
TodoList {}
|
||||
|
||||
// footer
|
||||
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" }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn TodoList(cx: Context<()>) -> DomTree {
|
||||
let (draft, set_draft) = use_state_classic(cx, || "".to_string());
|
||||
let (todos, set_todos) = use_state_classic(cx, || HashMap::<uuid::Uuid, Rc<TodoItem>>::new());
|
||||
let (filter, set_filter) = use_state_classic(cx, || FilterState::All);
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
header {
|
||||
class: "header"
|
||||
h1 {"todos"}
|
||||
input {
|
||||
class: "new-todo"
|
||||
placeholder: "What needs to be done?"
|
||||
value: "{draft}"
|
||||
oninput: move |evt| set_draft(evt.value())
|
||||
}
|
||||
}
|
||||
|
||||
{ // list
|
||||
todos
|
||||
.iter()
|
||||
.filter(|(id, item)| match filter {
|
||||
FilterState::All => true,
|
||||
FilterState::Active => !item.checked,
|
||||
FilterState::Completed => item.checked,
|
||||
})
|
||||
.map(|(id, item)| {
|
||||
// TodoEntry!();
|
||||
todo!()
|
||||
// rsx!(TodoEntry {
|
||||
// key: "{order}",
|
||||
// item: item.clone()
|
||||
// })
|
||||
})
|
||||
}
|
||||
|
||||
// filter toggle (show only if the list isn't empty)
|
||||
{(!todos.is_empty()).then(||
|
||||
rsx!( FilterToggles {})
|
||||
)}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Props)]
|
||||
pub struct TodoEntryProps {
|
||||
item: Rc<TodoItem>,
|
||||
}
|
||||
|
||||
pub fn TodoEntry(cx: Context<TodoEntryProps>) -> DomTree {
|
||||
let (is_editing, set_is_editing) = use_state_classic(cx, || false);
|
||||
let contents = "";
|
||||
let todo = TodoItem {
|
||||
checked: false,
|
||||
contents: "asd".to_string(),
|
||||
id: uuid::Uuid::new_v4(),
|
||||
};
|
||||
|
||||
cx.render(rsx! (
|
||||
li {
|
||||
"{todo.id}"
|
||||
input {
|
||||
class: "toggle"
|
||||
r#type: "checkbox"
|
||||
"{todo.checked}"
|
||||
}
|
||||
{is_editing.then(|| rsx!{
|
||||
input {
|
||||
value: "{contents}"
|
||||
}
|
||||
})}
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
pub fn FilterToggles(cx: Context<()>) -> DomTree {
|
||||
let toggles = [
|
||||
("All", "", FilterState::All),
|
||||
("Active", "active", FilterState::Active),
|
||||
("Completed", "completed", FilterState::Completed),
|
||||
]
|
||||
.iter()
|
||||
.map(|(name, path, filter)| {
|
||||
rsx!(
|
||||
li {
|
||||
class: "{name}"
|
||||
a {
|
||||
href: "{path}"
|
||||
// onclick: move |_| reducer.set_filter(&filter)
|
||||
"{name}"
|
||||
}
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
// todo
|
||||
let item_text = "";
|
||||
let items_left = "";
|
||||
|
||||
cx.render(rsx! {
|
||||
footer {
|
||||
span {
|
||||
strong {"{items_left}"}
|
||||
span {"{item_text} left"}
|
||||
}
|
||||
ul {
|
||||
class: "filters"
|
||||
{toggles}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,200 +0,0 @@
|
|||
//! Example: TODOVMC - One file
|
||||
//! ---------------------------
|
||||
//! This example shows how to build a one-file TODO MVC app with Dioxus and Recoil.
|
||||
//! This project is confined to a single file to showcase the suggested patterns
|
||||
//! for building a small but mighty UI with Dioxus without worrying about project structure.
|
||||
//!
|
||||
//! If you want an example on recommended project structure, check out the TodoMVC folder
|
||||
//!
|
||||
//! Here, we show to use Dioxus' Recoil state management solution to simplify app logic
|
||||
#![allow(non_snake_case)]
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_web::dioxus::prelude::*;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(PartialEq, Clone, Copy)]
|
||||
pub enum FilterState {
|
||||
All,
|
||||
Active,
|
||||
Completed,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct TodoItem {
|
||||
pub id: Uuid,
|
||||
pub checked: bool,
|
||||
pub contents: String,
|
||||
}
|
||||
|
||||
// Declare our global app state
|
||||
const TODO_LIST: AtomHashMap<Uuid, TodoItem> = |_| {};
|
||||
const FILTER: Atom<FilterState> = |_| FilterState::All;
|
||||
const TODOS_LEFT: Selector<usize> = |api| api.get(&TODO_LIST).len();
|
||||
|
||||
// Implement a simple abstraction over sets/gets of multiple atoms
|
||||
struct TodoManager(RecoilApi);
|
||||
impl TodoManager {
|
||||
fn add_todo(&self, contents: String) {
|
||||
let item = TodoItem {
|
||||
checked: false,
|
||||
contents,
|
||||
id: Uuid::new_v4(),
|
||||
};
|
||||
self.0.modify(&TODO_LIST, move |list| {
|
||||
list.insert(item.id, item);
|
||||
});
|
||||
}
|
||||
fn remove_todo(&self, id: &Uuid) {
|
||||
self.0.modify(&TODO_LIST, move |list| {
|
||||
list.remove(id);
|
||||
})
|
||||
}
|
||||
fn select_all_todos(&self) {
|
||||
self.0.modify(&TODO_LIST, move |list| {
|
||||
for item in list.values_mut() {
|
||||
item.checked = true;
|
||||
}
|
||||
})
|
||||
}
|
||||
fn toggle_todo(&self, id: &Uuid) {
|
||||
self.0.modify(&TODO_LIST, move |list| {
|
||||
list.get_mut(id).map(|item| item.checked = !item.checked)
|
||||
});
|
||||
}
|
||||
fn clear_completed(&self) {
|
||||
self.0.modify(&TODO_LIST, move |list| {
|
||||
*list = list.drain().filter(|(_, item)| !item.checked).collect();
|
||||
})
|
||||
}
|
||||
fn set_filter(&self, filter: &FilterState) {
|
||||
self.0.modify(&FILTER, move |f| *f = *filter);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn TodoList(cx: Context<()>) -> DomTree {
|
||||
let draft = use_state(cx, || "".to_string());
|
||||
let todos = use_read(&cx, &TODO_LIST);
|
||||
let filter = use_read(&cx, &FILTER);
|
||||
|
||||
let todolist = todos
|
||||
.values()
|
||||
.filter(|item| match filter {
|
||||
FilterState::All => true,
|
||||
FilterState::Active => !item.checked,
|
||||
FilterState::Completed => item.checked,
|
||||
})
|
||||
.map(|item| {
|
||||
rsx!(TodoEntry {
|
||||
key: "{order}",
|
||||
id: item.id,
|
||||
})
|
||||
});
|
||||
|
||||
rsx! { in cx,
|
||||
div {
|
||||
header {
|
||||
class: "header"
|
||||
h1 {"todos"}
|
||||
input {
|
||||
class: "new-todo"
|
||||
placeholder: "What needs to be done?"
|
||||
value: "{draft}"
|
||||
oninput: move |evt| draft.set(evt.value)
|
||||
}
|
||||
}
|
||||
{todolist}
|
||||
|
||||
// rsx! accepts optionals, so we suggest the `then` method in place of ternary
|
||||
{(!todos.is_empty()).then(|| rsx!( FilterToggles {}) )}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Props)]
|
||||
pub struct TodoEntryProps {
|
||||
id: Uuid,
|
||||
}
|
||||
|
||||
pub fn TodoEntry(cx: Context, props: &TodoEntryProps) -> DomTree {
|
||||
let (is_editing, set_is_editing) = use_state_classic(cx, || false);
|
||||
let todo = use_read(&cx, &TODO_LIST).get(&cx.id).unwrap();
|
||||
|
||||
cx.render(rsx! (
|
||||
li {
|
||||
"{todo.id}"
|
||||
input {
|
||||
class: "toggle"
|
||||
type: "checkbox"
|
||||
"{todo.checked}"
|
||||
}
|
||||
{is_editing.then(|| rsx!(
|
||||
input {
|
||||
value: "{todo.contents}"
|
||||
}
|
||||
))}
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
pub fn FilterToggles(cx: Context<()>) -> DomTree {
|
||||
let reducer = TodoManager(use_recoil_api(cx));
|
||||
let items_left = use_read(cx, &TODOS_LEFT);
|
||||
|
||||
let item_text = match items_left {
|
||||
1 => "item",
|
||||
_ => "items",
|
||||
};
|
||||
|
||||
let toggles = rsx! {
|
||||
ul {
|
||||
class: "filters"
|
||||
li { class: "All", a { href: "", onclick: move |_| reducer.set_filter(&FilterState::All), "All" }}
|
||||
li { class: "Active", a { href: "active", onclick: move |_| reducer.set_filter(&FilterState::Active), "Active" }}
|
||||
li { class: "Completed", a { href: "completed", onclick: move |_| reducer.set_filter(&FilterState::Completed), "Completed" }}
|
||||
}
|
||||
};
|
||||
|
||||
rsx! { in cx,
|
||||
footer {
|
||||
span {
|
||||
strong {"{items_left}"}
|
||||
span { "{item_text} left" }
|
||||
}
|
||||
{toggles}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn Footer(cx: Context<()>) -> DomTree {
|
||||
rsx! { in cx,
|
||||
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" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const APP_STYLE: &'static str = include_str!("./todomvc/style.css");
|
||||
|
||||
fn App(cx: Context<()>) -> DomTree {
|
||||
use_init_recoil_root(cx, |_| {});
|
||||
rsx! { in cx,
|
||||
div { id: "app"
|
||||
TodoList {}
|
||||
Footer {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(App));
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
//! basic example that renders a simple VNode to the page :)
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_web::*;
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|cx, props| {
|
||||
cx.render(html! {
|
||||
<div>
|
||||
<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">
|
||||
// Title
|
||||
<div class="font-bold text-xl">
|
||||
"Jon's awesome site!!"
|
||||
</div>
|
||||
|
||||
// Subtext / description
|
||||
<div class="text-sm text-gray-500">
|
||||
"He worked so hard on it :)"
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row items-center justify-center mt-6">
|
||||
// Main number
|
||||
<div class="font-medium text-6xl">
|
||||
"1337"
|
||||
</div>
|
||||
</div>
|
||||
|
||||
// Try another
|
||||
<div class="flex flex-row justify-between mt-6">
|
||||
// <a href=format!("http://localhost:8080/fib/{}", other_fib_to_try) class="underline">
|
||||
"Legit made my own React"
|
||||
// </a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
})
|
||||
}));
|
||||
}
|
Loading…
Reference in a new issue