feat: overhaul examples and clean things up

This commit is contained in:
Jonathan Kelley committed 2022-01-03 00:42:17 -05:00
1 parent 601632fc7e
commit 420a30e5d4
33 files changed
+1086 -1414

No files matched your search

+2 -18
View File
@@ -60,24 +60,8 @@ num-format = "0.4.0"
separator = "0.4.1"
serde = { version = "1.0.131", features = ["derive"] }
im-rc = "15.0.0"
fxhash = "0.2.1"
anyhow = "1.0.51"
serde_json = "1.0.73"
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
argh = "0.1.7"
env_logger = "0.9.0"
rand = { version = "0.8.4", features = ["small_rng"] }
tokio = { version = "1.14.0", features = ["full"] }
rand = { version = "0.8.4", features = ["small_rng"] }
gloo-timers = "0.2.2"
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
gloo-timers = "0.2.2"
wasm-logger = "0.2.0"
console_error_panic_hook = "0.1.7"
rand = { version = "0.8.4", features = ["small_rng"] }
wasm-bindgen = { version = "0.2.78", features = ["enable-interning"] }
[dev-dependencies.getrandom]
version = "0.2.3"
features = ["js"]
reqwest = { version = "0.11.8", features = ["json"] }
+180
View File
@@ -0,0 +1,180 @@
* {
margin: 0;
padding: 0;
font-family: 'Roboto', sans-serif;
user-select: none;
transition: .2s all;
}
body {
padding-top: 77px;
}
/* header {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 10;
padding: 20px;
background-color: #2196F3;
color: white;
}
header h1 {
float: left;
font-size: 20px;
font-weight: 400;
}
header .material-icons {
float: right;
cursor: pointer;
}
header .icon-menu {
float: left;
margin-right: 20px;
} */
main {
padding: 20px 50px;
}
.folder * {
width: 100px;
}
.folder {
float: left;
width: 100px;
height: 152px;
/* //padding: 20px; */
margin-right: 50px;
margin-bottom: 70px;
border-radius: 2px;
/* //overflow: hidden; */
cursor: pointer;
}
.folder:hover h1 {
display: none;
}
.folder:hover p.cooltip {
opacity: 1;
top: 0;
}
.folder * {
text-align: center;
}
.folder i {
margin: 0;
font-size: 100px;
color: #607D8B;
}
.folder h1 {
position: relative;
display: block;
top: -37px;
font-size: 20px;
font-weight: 400;
}
.folder p.cooltip {
position: relative;
top: 5px;
left: -50%;
margin-left: 35px;
background: #212121;
font-size: 15px;
color: white;
border-radius: 4px;
padding: 10px 20px;
padding-right: 30px;
width: 100px;
opacity: 0;
}
.folder p.cooltip:before {
content: '';
position: absolute;
display: block;
top: -4px;
left: 50%;
margin-left: -5px;
height: 10px;
width: 10px;
border-radius: 2px;
background-color: #212121;
transform: rotate(45deg);
}
div.properties {
position: fixed;
top: 0;
right: 0;
bottom: 0;
z-index: 10;
width: 300px;
background-color: white;
}
div.properties:before {
content: '';
position: fixed;
top: 0;
left: 0;
right: 300px;
bottom: 0;
background-color: #212121;
opacity: .5;
overflow: hidden;
}
div.properties img {
position: relative;
top: -1px;
left: -1px;
width: 110%;
height: 200px;
filter: blur(2px);
}
div.properties h1 {
position: relative;
width: 100%;
text-align: left;
margin-left: 20px;
color: white;
}
header {
position: fixed;
top: 0;
left: 0;
right: 0;
padding: 20px;
background-color: #2196F3;
color: white;
display: flex;
align-items: center;
}
header h1 {
font-weight: 400;
}
header span {
flex: 1;
}
header i {
margin: 0 10px;
cursor: pointer;
}
header i:nth-child(1) {
margin: 0 20px;
}
+373
View File
@@ -0,0 +1,373 @@
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;
}
}
-48
View File
@@ -1,48 +0,0 @@
/*
This example shows how to use async and loops to implement a coroutine in a component. Coroutines can be controlled via
the `TaskHandle` object.
*/
use dioxus::prelude::*;
use gloo_timers::future::TimeoutFuture;
#[tokio::main]
async fn main() {
dioxus::desktop::launch(app);
}
fn app(cx: Scope) -> Element {
let count = use_state(&cx, || 0);
let direction = use_state(&cx, || 1);
let (async_count, dir) = (count.for_async(), *direction);
let task = use_coroutine(&cx, move || {
//
async move {
loop {
TimeoutFuture::new(250).await;
// *async_count.modify() += dir;
}
}
});
cx.render(rsx! {
div {
h1 {"count is {count}"}
button { onclick: move |_| task.stop(),
"Stop counting"
}
button { onclick: move |_| task.resume(),
"Start counting"
}
button {
onclick: move |_| {
*direction.modify() *= -1;
task.restart();
},
"Switch counting direcion"
}
}
})
}
+121 -132
View File
@@ -1,160 +1,149 @@
#![allow(non_snake_case)]
/*
This example is a simple iOS-style calculator. This particular example can run any platform - Web, Mobile, Desktop.
This calculator version uses React-style state management. All state is held as individual use_states.
*/
use std::sync::Arc;
use dioxus::events::*;
use dioxus::prelude::*;
use separator::Separatable;
fn main() {
dioxus::desktop::launch(app);
use dioxus::desktop::tao::dpi::LogicalSize;
dioxus::desktop::launch_cfg(app, |cfg| {
cfg.with_window(|w| {
w.with_title("Calculator Demo")
.with_resizable(false)
.with_inner_size(LogicalSize::new(320.0, 530.0))
})
});
}
fn app(cx: Scope) -> Element {
let cur_val = use_state(&cx, || 0.0_f64);
let operator = use_state(&cx, || None as Option<&'static str>);
let display_value = use_state(&cx, || String::from(""));
let operator = use_state(&cx, Option::default);
let display_value = use_state(&cx, String::new);
let toggle_percent = move |_| todo!();
let input_digit = move |num: u8| display_value.modify().push_str(num.to_string().as_str());
cx.render(rsx!(
style { [include_str!("./assets/calculator.css")] }
div {
class: "calculator",
onkeydown: move |evt| match evt.key_code {
KeyCode::Add => operator.set(Some("+")),
KeyCode::Subtract => operator.set(Some("-")),
KeyCode::Divide => operator.set(Some("/")),
KeyCode::Multiply => operator.set(Some("*")),
KeyCode::Num0 => input_digit(0),
KeyCode::Num1 => input_digit(1),
KeyCode::Num2 => input_digit(2),
KeyCode::Num3 => input_digit(3),
KeyCode::Num4 => input_digit(4),
KeyCode::Num5 => input_digit(5),
KeyCode::Num6 => input_digit(6),
KeyCode::Num7 => input_digit(7),
KeyCode::Num8 => input_digit(8),
KeyCode::Num9 => input_digit(9),
KeyCode::Backspace => {
if !display_value.as_str().eq("0") {
display_value.modify().pop();
}
}
_ => {}
},
div { class: "calculator-display", [cur_val.separated_string()] }
div { class: "input-keys",
div { class: "function-keys",
CalculatorKey {
name: "key-clear",
onclick: move |_| {
display_value.set("0".to_string());
if display_value != "0" {
operator.set(None);
cur_val.set(0.0);
div { id: "wrapper",
div { class: "app",
div { class: "calculator",
onkeydown: move |evt| match evt.key_code {
KeyCode::Add => operator.set(Some("+")),
KeyCode::Subtract => operator.set(Some("-")),
KeyCode::Divide => operator.set(Some("/")),
KeyCode::Multiply => operator.set(Some("*")),
KeyCode::Num0 => input_digit(0),
KeyCode::Num1 => input_digit(1),
KeyCode::Num2 => input_digit(2),
KeyCode::Num3 => input_digit(3),
KeyCode::Num4 => input_digit(4),
KeyCode::Num5 => input_digit(5),
KeyCode::Num6 => input_digit(6),
KeyCode::Num7 => input_digit(7),
KeyCode::Num8 => input_digit(8),
KeyCode::Num9 => input_digit(9),
KeyCode::Backspace => {
if !display_value.as_str().eq("0") {
display_value.modify().pop();
}
},
[if display_value == "0" { "C" } else { "AC" }]
}
CalculatorKey {
name: "key-sign",
onclick: move |_| {
if display_value.starts_with("-") {
display_value.set(display_value.trim_start_matches("-").to_string())
} else {
display_value.set(format!("-{}", *display_value))
}
},
"±"
}
CalculatorKey {
onclick: toggle_percent,
name: "key-percent",
"%"
}
}
div { class: "digit-keys",
CalculatorKey { name: "key-0", onclick: move |_| input_digit(0),
"0"
}
CalculatorKey { name: "key-dot", onclick: move |_| display_value.modify().push_str("."),
"●"
}
(1..9).map(|k| rsx!{
CalculatorKey {
key: "{k}",
name: "key-{k}",
onclick: move |_| input_digit(k),
"{k}"
}
}),
}
div { class: "operator-keys",
CalculatorKey {
name: "key-divide",
onclick: move |_| operator.set(Some("/")),
"÷"
}
CalculatorKey {
name: "key-multiply",
onclick: move |_| operator.set(Some("*")),
"×"
}
CalculatorKey {
name: "key-subtract",
onclick: move |_| operator.set(Some("-")),
"−"
}
CalculatorKey {
name: "key-add",
onclick: move |_| operator.set(Some("+")),
"+"
}
CalculatorKey {
name: "key-equals",
onclick: move |_| {
if let Some(op) = operator.as_ref() {
let rhs = display_value.parse::<f64>().unwrap();
let new_val = match *op {
"+" => *cur_val + rhs,
"-" => *cur_val - rhs,
"*" => *cur_val * rhs,
"/" => *cur_val / rhs,
_ => unreachable!(),
};
cur_val.set(new_val);
display_value.set(new_val.to_string());
operator.set(None);
_ => {}
},
div { class: "calculator-display", [cur_val.separated_string()] }
div { class: "calculator-keypad",
div { class: "input-keys",
div { class: "function-keys",
button {
class: "calculator-key key-clear",
onclick: move |_| {
display_value.set("0".to_string());
if display_value != "0" {
operator.set(None);
cur_val.set(0.0);
}
},
[if display_value == "0" { "C" } else { "AC" }]
}
button {
class: "calculator-key key-sign",
onclick: move |_| {
if display_value.starts_with("-") {
display_value.set(display_value.trim_start_matches("-").to_string())
} else {
display_value.set(format!("-{}", *display_value))
}
},
"±"
}
button {
class: "calculator-key key-percent",
onclick: move |_| {
let pct = (display_value.parse::<f64>().unwrap() / 100.0).to_string();
display_value.set(pct);
},
"%"
}
}
},
"="
div { class: "digit-keys",
button { class: "calculator-key key-0", onclick: move |_| input_digit(0),
"0"
}
button { class: "calculator-key key-dot", onclick: move |_| display_value.modify().push_str("."),
"●"
}
(1..10).map(|k| rsx!{
button {
class: "calculator-key {k}",
name: "key-{k}",
onclick: move |_| input_digit(k),
"{k}"
}
}),
}
}
div { class: "operator-keys",
button { class: "calculator-key key-divide",
onclick: move |_| operator.set(Some("/")),
"÷"
}
button { class: "calculator-key key-multiply",
onclick: move |_| operator.set(Some("*")),
"×"
}
button { class: "calculator-key key-subtract",
onclick: move |_| operator.set(Some("-")),
"−"
}
button { class: "calculator-key key-add",
onclick: move |_| operator.set(Some("+")),
"+"
}
button { class: "calculator-key key-equals",
onclick: move |_| {
if let Some(op) = operator.as_ref() {
let rhs = display_value.parse::<f64>().unwrap();
let new_val = match *op {
"+" => *cur_val + rhs,
"-" => *cur_val - rhs,
"*" => *cur_val * rhs,
"/" => *cur_val / rhs,
_ => unreachable!(),
};
cur_val.set(new_val);
display_value.set(new_val.to_string());
operator.set(None);
}
},
"="
}
}
}
}
}
}
))
}
#[inline_props]
fn CalculatorKey<'a>(
cx: Scope,
name: &'static str,
onclick: &'a dyn Fn(Arc<MouseEvent>),
children: Element<'a>,
) -> Element {
cx.render(rsx! {
button {
class: "calculator-key {name}",
onclick: onclick,
children
}
})
}
-73
View File
@@ -1,73 +0,0 @@
//! Example: Coroutines!
//! --------------------
//!
//! Coroutines are an awesome way to write concurrent code. Dioxus heavily leverages coroutines to make sense of complex
//! ongoing asynchronous tasks. The async scheduler of Dioxus supports both single-threaded and multi-threaded coroutines,
//! so you can drop in code to run across multiple threads without blocking the main thread.
//!
//! Dioxus cannot simply abstract away the threading model for the web, unfortunately. If you want to use "web threads"
//! you either need to limit support for Chrome, or you need to use a Web Workers and message passing. This is easy enough
//! to do in your own code, and doesn't require 1st-party support from Dioxus itself.
//!
//! UseState and friends work fine with coroutines, but coroutines might be easier to use with the Dirac global state
//! management API. This lets you easily drive global state from a coroutine without having to subscribe to the state.
//!
//! For now, this example shows how to use coroutines used with use_state.
//!
//!
//! ## What is a Coroutine?
//!
//! A coroutine is a function that can be paused and resumed. It can be paused internally through "await" or externally
//! using the `TaskHandle` API. Within a coroutine, you may execute asynchronous code, that modifies values captured when
//! the coroutine was initiated. `use_state` always returns the same setter, so you don't need to worry about
fn main() {
dioxus::desktop::launch(app);
}
use dioxus::prelude::*;
fn app(cx: Scope) -> Element {
let p1 = use_state(&cx, || 0);
let p2 = use_state(&cx, || 0);
let (mut p1_async, mut p2_async) = (p1.for_async(), p2.for_async());
let (p1_handle, _) = use_coroutine(cx, || async move {
loop {
*p1_async.get_mut() += 1;
async_std::task::sleep(std::time::Duration::from_millis(75)).await;
}
});
let (p2_handle, _) = use_coroutine(cx, || async move {
loop {
*p2_async.get_mut() += 1;
async_std::task::sleep(std::time::Duration::from_millis(100)).await;
}
});
cx.render(rsx! {
div {
width: "400px", height: "400px", position: "relative", background: "yellow"
button { "reset", onclick: move |_| {} }
Horsey { pos: *p1, "horsey 1" }
Horsey { pos: *p2, "horsey 2" }
}
})
}
#[derive(Props)]
struct HorseyProps<'a> {
pos: i32,
children: Element<'a>,
}
fn Horsey<'a>(cx: Scope<'a, HorseyProps<'a>>) -> Element {
cx.render(rsx! {
div {
button { "pause" }
div {
{&cx.props.children}
}
}
})
}
+1 -1
View File
@@ -21,10 +21,10 @@ pub struct Client {
fn app(cx: Scope) -> Element {
let scene = use_state(&cx, || Scene::ClientsList);
let clients = use_ref(&cx, || vec![] as Vec<Client>);
let firstname = use_state(&cx, String::new);
let lastname = use_state(&cx, String::new);
let description = use_state(&cx, String::new);
let clients = use_ref(&cx, || vec![] as Vec<Client>);
cx.render(rsx!(
body {
+51 -30
View File
@@ -11,37 +11,53 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch_cfg(app, |c| {
c.with_window(|w| {
w.with_resizable(true)
.with_inner_size(dioxus::desktop::tao::dpi::LogicalSize::new(400.0, 800.0))
})
});
dioxus::desktop::launch_cfg(app, |c| c.with_window(|w| w.with_resizable(true)));
}
fn app(cx: Scope) -> Element {
let files = use_ref(&cx, Files::new);
let files = use_ref(&cx, || Files::new());
cx.render(rsx!(
h1 { "Files: " }
h3 { "Cur dir: " [files.read().current()] }
button { onclick: move |_| files.write().go_up(), "go up" }
ol {
files.read().path_names.iter().enumerate().map(|(dir_id, path)| rsx!(
li { key: "{path}",
a { href: "#", onclick: move |_| files.write().enter_dir(dir_id),
"{path}",
}
}
))
rsx!(cx, div {
link { href:"https://fonts.googleapis.com/icon?family=Material+Icons", rel:"stylesheet", }
style { [include_str!("./assets/fileexplorer.css")] }
header {
i { class: "material-icons icon-menu", "menu" }
h1 { "Files: " [files.read().current()] }
span { }
i { class: "material-icons", onclick: move |_| files.write().go_up(), "logout" }
}
files.read().err.as_ref().map(|err| rsx!(
div {
code { "{err}" }
button { onclick: move |_| files.write().clear_err(), "x" }
}
))
))
main {
files.read().path_names.iter().enumerate().map(|(dir_id, path)| {
let path_end = path.split('/').last().unwrap_or(path.as_str());
let icon_type = if path_end.contains(".") {
"description"
} else {
"folder"
};
rsx! (
div {
class: "folder",
key: "{path}",
i { class: "material-icons",
onclick: move |_| files.write().enter_dir(dir_id),
"{icon_type}"
p { class: "cooltip", "0 folders / 0 files" }
}
h1 { "{path_end}" }
}
)
}),
files.read().err.as_ref().map(|err| {
rsx! (
div {
code { "{err}" }
button { onclick: move |_| files.write().clear_err(), "x" }
}
)
})
}
})
}
struct Files {
@@ -64,21 +80,26 @@ impl Files {
}
fn reload_path_list(&mut self) {
let paths = match std::fs::read_dir(self.path_stack.last().unwrap()) {
let cur_path = self.path_stack.last().unwrap();
let paths = match std::fs::read_dir(cur_path) {
Ok(e) => e,
Err(err) => {
self.err = Some(format!("An error occured: {:?}", err));
let err = format!("An error occured: {:?}", err);
self.err = Some(err);
self.path_stack.pop();
return;
}
};
let collected = paths.collect::<Vec<_>>();
// clear the current state
self.clear_err();
self.path_names.clear();
self.path_names
.extend(paths.map(|path| path.unwrap().path().display().to_string()));
for path in collected {
self.path_names
.push(path.unwrap().path().display().to_string());
}
}
fn go_up(&mut self) {
+60 -22
View File
@@ -22,7 +22,6 @@ use dioxus::events::*;
use dioxus::prelude::*;
fn main() {
env_logger::init();
dioxus::desktop::launch_cfg(app, |cfg| {
cfg.with_window(|w| {
w.with_title("Calculator Demo")
@@ -35,38 +34,78 @@ fn main() {
fn app(cx: Scope) -> Element {
let state = use_ref(&cx, || Calculator::new());
let clear_display = state.read().display_value.eq("0");
let clear_text = if clear_display { "C" } else { "AC" };
let formatted = state.read().formatted_display();
cx.render(rsx!{
cx.render(rsx! {
style { [include_str!("./assets/calculator.css")] }
div { id: "wrapper",
div {
class: "app",
style { [include_str!("./assets/calculator.css")] }
div { class: "app",
div { class: "calculator", onkeypress: move |evt| state.write().handle_keydown(evt),
div { class: "calculator-display", "{formatted}"}
div { class: "calculator-display", [state.read().formatted_display()]}
div { class: "calculator-keypad",
div { class: "input-keys",
div { class: "function-keys",
CalculatorKey { name: "key-clear", onclick: move |_| state.write().clear_display(), "{clear_text}" }
CalculatorKey { name: "key-sign", onclick: move |_| state.write().toggle_sign(), "±"}
CalculatorKey { name: "key-percent", onclick: move |_| state.write().toggle_percent(), "%"}
CalculatorKey {
name: "key-clear",
onclick: move |_| state.write().clear_display(),
[if state.read().display_value == "0" { "C" } else { "AC" }]
}
CalculatorKey {
name: "key-sign",
onclick: move |_| state.write().toggle_sign(),
"±"
}
CalculatorKey {
name: "key-percent",
onclick: move |_| state.write().toggle_percent(),
"%"
}
}
div { class: "digit-keys",
CalculatorKey { name: "key-0", onclick: move |_| state.write().input_digit(0), "0" }
CalculatorKey { name: "key-dot", onclick: move |_| state.write().input_dot(), "●" }
CalculatorKey {
name: "key-0",
onclick: move |_| state.write().input_digit(0),
"0"
}
CalculatorKey {
name: "key-dot",
onclick: move |_| state.write().input_dot(),
"●"
}
(1..10).map(move |k| rsx!{
CalculatorKey { key: "{k}", name: "key-{k}", onclick: move |_| state.write().input_digit(k), "{k}" }
CalculatorKey {
key: "{k}",
name: "key-{k}",
onclick: move |_| state.write().input_digit(k),
"{k}"
}
})
}
}
div { class: "operator-keys",
CalculatorKey { name:"key-divide", onclick: move |_| state.write().set_operator(Operator::Div), "÷" }
CalculatorKey { name:"key-multiply", onclick: move |_| state.write().set_operator(Operator::Mul), "×" }
CalculatorKey { name:"key-subtract", onclick: move |_| state.write().set_operator(Operator::Sub), "−" }
CalculatorKey { name:"key-add", onclick: move |_| state.write().set_operator(Operator::Add), "+" }
CalculatorKey { name:"key-equals", onclick: move |_| state.write().perform_operation(), "=" }
CalculatorKey {
name: "key-divide",
onclick: move |_| state.write().set_operator(Operator::Div),
"÷"
}
CalculatorKey {
name: "key-multiply",
onclick: move |_| state.write().set_operator(Operator::Mul),
"×"
}
CalculatorKey {
name: "key-subtract",
onclick: move |_| state.write().set_operator(Operator::Sub),
"−"
}
CalculatorKey {
name: "key-add",
onclick: move |_| state.write().set_operator(Operator::Add),
"+"
}
CalculatorKey {
name: "key-equals",
onclick: move |_| state.write().perform_operation(),
"="
}
}
}
}
@@ -105,7 +144,6 @@ enum Operator {
Mul,
Div,
}
impl Calculator {
fn new() -> Self {
Calculator {
+5 -2
View File
@@ -4,10 +4,13 @@
//! This example shows how to encapsulate state in dioxus components with the reducer pattern.
//! This pattern is very useful when a single component can handle many types of input that can
//! be represented by an enum.
//!
//! Currently we don't have a reducer pattern hook. If you'd like to add it,
//! feel free to make a PR.
use dioxus::prelude::*;
fn main() {
env_logger::init();
dioxus::desktop::launch(app);
}
@@ -17,7 +20,7 @@ fn app(cx: Scope) -> Element {
cx.render(rsx!(
div {
h1 {"Select an option"}
h3 { "The radio is... " [state.is_playing()], "!" }
h3 { "The radio is... " [state.is_playing()] "!" }
button { onclick: move |_| state.modify().reduce(PlayerAction::Pause),
"Pause"
}
+32 -2
View File
@@ -1,10 +1,40 @@
//! Example: SSR
//!
//! This example shows how we can render the Dioxus Virtualdom using SSR.
use std::fmt::Write;
use dioxus::prelude::*;
use dioxus::ssr;
fn main() {
// We can render VirtualDoms
let mut vdom = VirtualDom::new(app);
let _ = vdom.rebuild();
println!("{}", ssr::render_vdom(&vdom));
println!("{}", dioxus::ssr::render_vdom(&vdom));
// Or we can render rsx! calls themselves
println!(
"{}",
dioxus::ssr::render_lazy(rsx! {
div {
h1 { "Hello, world!" }
}
})
);
// We can configure the SSR rendering to add ids for rehydration
println!(
"{}",
dioxus::ssr::render_vdom_cfg(&vdom, |c| c.pre_render(true))
);
// We can even render as a writer
let mut file = String::new();
let _ = file.write_fmt(format_args!(
"{}",
dioxus::ssr::TextRenderer::from_vdom(&vdom, Default::default())
));
println!("{}", file);
}
fn app(cx: Scope) -> Element {
-26
View File
@@ -1,26 +0,0 @@
use dioxus::virtual_dom::VirtualDom;
use dioxus_core as dioxus;
use dioxus_core::prelude::*;
use dioxus_core_macro::*;
use dioxus_html as dioxus_elements;
fn main() {
let mut dom = VirtualDom::new(app);
dom.rebuild();
println!(
"{}",
dioxus_ssr::render_vdom(&dom, |c| c.newline(true).indent(true))
)
}
fn app(cx: Scope) -> Element {
cx.render(rsx!(
div {
class: "overflow-hidden"
ul {
(0..10).map(|i| rsx!{ li { class: "flex flex-col", "entry: {i}"}})
}
"hello world!"
}
))
}
-149
View File
@@ -1,149 +0,0 @@
use dioxus::virtual_dom::VirtualDom;
use dioxus_core as dioxus;
use dioxus_core::prelude::*;
use dioxus_core_macro::*;
use dioxus_hooks::use_state;
use dioxus_html as dioxus_elements;
use dioxus_html::{GlobalAttributes, SvgAttributes};
use dioxus_ssr::TextRenderer;
fn main() {
use std::fs::File;
use std::io::Write;
let mut file = File::create("example.html").unwrap();
let mut dom = VirtualDom::new(App);
dom.rebuild();
file.write_fmt(format_args!(
"{}",
TextRenderer::from_vdom(&dom, Default::default())
))
.unwrap();
}
pub fn App(cx: Scope) -> Element {
cx.render(rsx!(
div { class: "overflow-hidden"
link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel:"stylesheet" }
Header {}
Entry {}
Hero {}
Hero {}
Hero {}
Hero {}
Hero {}
}
))
}
pub fn Header(cx: Scope) -> Element {
cx.render(rsx! {
div {
header { class: "text-gray-400 bg-gray-900 body-font"
div { class: "container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center"
a { class: "flex title-font font-medium items-center text-white mb-4 md:mb-0"
StacksIcon {}
span { class: "ml-3 text-xl" "Hello Dioxus!"}
}
nav { class: "md:ml-auto flex flex-wrap items-center text-base justify-center"
a { class: "mr-5 hover:text-white" "First Link"}
a { class: "mr-5 hover:text-white" "Second Link"}
a { class: "mr-5 hover:text-white" "Third Link"}
a { class: "mr-5 hover:text-white" "Fourth Link"}
}
button {
class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0"
"Button"
RightArrowIcon {}
}
}
}
}
})
}
pub fn Hero(cx: Scope) -> Element {
//
cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font"
div { class: "container mx-auto flex px-5 py-24 md:flex-row flex-col items-center"
div { class: "lg:flex-grow md:w-1/2 lg:pr-24 md:pr-16 flex flex-col md:items-start md:text-left mb-16 md:mb-0 items-center text-center"
h1 { class: "title-font sm:text-4xl text-3xl mb-4 font-medium text-white"
br { class: "hidden lg:inline-block" }
"Dioxus Sneak Peek"
}
p {
class: "mb-8 leading-relaxed"
"Dioxus is a new UI framework that makes it easy and simple to write cross-platform apps using web
technologies! It is functional, fast, and portable. Dioxus can run on the web, on the desktop, and
on mobile and embedded platforms."
}
div { class: "flex justify-center"
button {
class: "inline-flex text-white bg-indigo-500 border-0 py-2 px-6 focus:outline-none hover:bg-indigo-600 rounded text-lg"
"Learn more"
}
button {
class: "ml-4 inline-flex text-gray-400 bg-gray-800 border-0 py-2 px-6 focus:outline-none hover:bg-gray-700 hover:text-white rounded text-lg"
"Build an app"
}
}
}
div { class: "lg:max-w-lg lg:w-full md:w-1/2 w-5/6"
img { class: "object-cover object-center rounded" alt: "hero" src: "https://i.imgur.com/oK6BLtw.png"
referrerpolicy:"no-referrer"
}
}
}
}
})
}
pub fn Entry(cx: Scope) -> Element {
//
cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font"
div { class: "container mx-auto flex px-5 py-24 md:flex-row flex-col items-center"
textarea {
}
}
}
})
}
pub fn StacksIcon(cx: Scope) -> Element {
cx.render(rsx!(
svg {
xmlns: "http://www.w3.org/2000/svg"
fill: "none"
stroke: "currentColor"
stroke_linecap: "round"
stroke_linejoin: "round"
stroke_width: "2"
class: "w-10 h-10 text-white p-2 bg-indigo-500 rounded-full"
view_box: "0 0 24 24"
path { d: "M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"}
}
))
}
pub fn RightArrowIcon(cx: Scope) -> Element {
cx.render(rsx!(
svg {
fill: "none"
stroke: "currentColor"
stroke_linecap: "round"
stroke_linejoin: "round"
stroke_width: "2"
class: "w-4 h-4 ml-1"
view_box: "0 0 24 24"
path { d: "M5 12h14M12 5l7 7-7 7"}
}
))
}
+72
View File
@@ -0,0 +1,72 @@
//! Suspense in Dioxus
//!
//! Currently, `rsx!` does not accept futures as values. To achieve the functionality
//! of suspense, we need to make a new component that performs its own suspense
//! handling.
//!
//! In this example, we render the `Doggo` component which starts a future that
//! will cause it to fetch a random dog image from the Dog API. Since the data
//! is not ready immediately, we render some loading text.
//!
//! We can achieve the majoirty of suspense functionality by composing "suspenseful"
//! primitives in our own custom components.
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app)
}
#[derive(serde::Deserialize)]
struct DogApi {
message: String,
}
fn app(cx: Scope) -> Element {
cx.render(rsx! {
div {
h1 {"Dogs are very important"}
p {
"The dog or domestic dog (Canis familiaris[4][5] or Canis lupus familiaris[5])"
"is a domesticated descendant of the wolf which is characterized by an upturning tail."
"The dog derived from an ancient, extinct wolf,[6][7] and the modern grey wolf is the"
"dog's nearest living relative.[8] The dog was the first species to be domesticated,[9][8]"
"by hunter–gatherers over 15,000 years ago,[7] before the development of agriculture.[1]"
}
h3 { "Illustrious Dog Photo" }
Doggo { }
}
})
}
/// This component will re-render when the future has finished
/// Suspense is achieved my moving the future into only the component that
/// actually renders the data.
fn Doggo(cx: Scope) -> Element {
let fut = use_future(&cx, || async move {
reqwest::get("https://dog.ceo/api/breeds/image/random/")
.await
.unwrap()
.json::<DogApi>()
.await
});
cx.render(match fut.value() {
Some(Ok(resp)) => rsx! {
button {
onclick: move |_| fut.restart(),
"Click to fetch another dog"
}
div {
img {
max_width: "500px",
max_height: "500px",
src: "{resp.message}",
}
}
},
Some(Err(_)) => rsx! { div { "loading dogs failed" } },
None => rsx! { div { "loading dogs..." } },
})
}
+48 -67
View File
@@ -1,8 +1,18 @@
//! Example: Basic Tailwind usage
//!
//! This example shows how an app might be styled with TailwindCSS.
//!
//! To minify your tailwind bundle, currently you need to use npm. Follow these instructions:
//!
//! https://dev.to/arctic_hen7/how-to-set-up-tailwind-css-with-yew-and-trunk-il9
use dioxus::prelude::*;
fn main() {
use dioxus::desktop::wry::application::platform::macos::*;
dioxus::desktop::launch_cfg(App, |c| {
dioxus::desktop::launch_cfg(app, |c| {
// we can configure our primary window through the Tauri Config
use dioxus::desktop::tao::platform::macos::*;
c.with_window(|w| {
w.with_fullsize_content_view(true)
.with_titlebar_buttons_hidden(false)
@@ -12,26 +22,9 @@ fn main() {
});
}
const STYLE: &str = "body {overflow:hidden;}";
pub fn App(cx: Scope) -> Element {
pub fn app(cx: Scope) -> Element {
cx.render(rsx!(
div { class: "overflow-hidden",
style { "{STYLE}" }
link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css", rel:"stylesheet" }
Header {}
Entry {}
Hero {}
Hero {}
Hero {}
Hero {}
Hero {}
}
))
}
pub fn Header(cx: Scope) -> Element {
cx.render(rsx! {
link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css", rel:"stylesheet" }
div {
header { class: "text-gray-400 bg-gray-900 body-font",
div { class: "container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center",
@@ -52,65 +45,52 @@ pub fn Header(cx: Scope) -> Element {
}
}
}
}
})
}
pub fn Hero(cx: Scope) -> Element {
//
cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font",
div { class: "container mx-auto flex px-5 py-24 md:flex-row flex-col items-center",
div { class: "lg:flex-grow md:w-1/2 lg:pr-24 md:pr-16 flex flex-col md:items-start md:text-left mb-16 md:mb-0 items-center text-center",
h1 { class: "title-font sm:text-4xl text-3xl mb-4 font-medium text-white",
br { class: "hidden lg:inline-block" }
"Dioxus Sneak Peek"
}
p {
class: "mb-8 leading-relaxed",
"Dioxus is a new UI framework that makes it easy and simple to write cross-platform apps using web
technologies! It is functional, fast, and portable. Dioxus can run on the web, on the desktop, and
on mobile and embedded platforms."
}
div { class: "flex justify-center",
button {
class: "inline-flex text-white bg-indigo-500 border-0 py-2 px-6 focus:outline-none hover:bg-indigo-600 rounded text-lg",
"Learn more"
section { class: "text-gray-400 bg-gray-900 body-font",
div { class: "container mx-auto flex px-5 py-24 md:flex-row flex-col items-center",
div { class: "lg:flex-grow md:w-1/2 lg:pr-24 md:pr-16 flex flex-col md:items-start md:text-left mb-16 md:mb-0 items-center text-center",
h1 { class: "title-font sm:text-4xl text-3xl mb-4 font-medium text-white",
br { class: "hidden lg:inline-block" }
"Dioxus Sneak Peek"
}
button {
class: "ml-4 inline-flex text-gray-400 bg-gray-800 border-0 py-2 px-6 focus:outline-none hover:bg-gray-700 hover:text-white rounded text-lg",
"Build an app"
p {
class: "mb-8 leading-relaxed",
"Dioxus is a new UI framework that makes it easy and simple to write cross-platform apps using web
technologies! It is functional, fast, and portable. Dioxus can run on the web, on the desktop, and
on mobile and embedded platforms."
}
div { class: "flex justify-center",
button {
class: "inline-flex text-white bg-indigo-500 border-0 py-2 px-6 focus:outline-none hover:bg-indigo-600 rounded text-lg",
"Learn more"
}
button {
class: "ml-4 inline-flex text-gray-400 bg-gray-800 border-0 py-2 px-6 focus:outline-none hover:bg-gray-700 hover:text-white rounded text-lg",
"Build an app"
}
}
}
div { class: "lg:max-w-lg lg:w-full md:w-1/2 w-5/6",
img {
class: "object-cover object-center rounded",
src: "https://i.imgur.com/oK6BLtw.png",
referrerpolicy:"no-referrer",
alt: "hero",
}
}
}
div { class: "lg:max-w-lg lg:w-full md:w-1/2 w-5/6",
img { class: "object-cover object-center rounded", alt: "hero", src: "https://i.imgur.com/oK6BLtw.png",
referrerpolicy:"no-referrer"
}
}
}
}
})
))
}
pub fn Entry(cx: Scope) -> Element {
//
cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font",
div { class: "container mx-auto flex px-5 py-24 md:flex-row flex-col items-center",
textarea {
}
}
}
})
}
pub fn StacksIcon(cx: Scope) -> Element {
cx.render(rsx!(
svg {
// xmlns: "http://www.w3.org/2000/svg"
fill: "none",
stroke: "currentColor",
stroke_linecap: "round",
@@ -122,6 +102,7 @@ pub fn StacksIcon(cx: Scope) -> Element {
}
))
}
pub fn RightArrowIcon(cx: Scope) -> Element {
cx.render(rsx!(
svg {
+3 -3
View File
@@ -25,10 +25,10 @@ fn app(cx: Scope) -> Element {
cx.render(rsx! {
div {
h1 { "High-Five counter: {count}" }
h1 { "Current count: {count}" }
button {
onclick: move |_| *count.modify() += 1,
"Click me!"
onclick: move |_| count.set(0),
"Reset the count"
}
}
})
+75 -51
View File
@@ -1,7 +1,5 @@
#![allow(non_upper_case_globals, non_snake_case)]
use dioxus::prelude::*;
use im_rc::HashMap;
use std::rc::Rc;
fn main() {
dioxus::desktop::launch(app);
@@ -14,99 +12,125 @@ pub enum FilterState {
Completed,
}
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
pub struct TodoItem {
pub id: u32,
pub checked: bool,
pub contents: String,
}
fn app(cx: Scope) -> Element {
let draft = use_state(&cx, || "".to_string());
let todos = use_state(&cx, || HashMap::<u32, Rc<TodoItem>>::new());
let filter = use_state(&cx, || FilterState::All);
let todolist = todos
pub fn app(cx: Scope<()>) -> Element {
let todos = use_state(&cx, || im_rc::HashMap::<u32, TodoItem>::default());
let filter = use_state(&cx, || FilterState::All);
let draft = use_state(&cx, || "".to_string());
let mut todo_id = use_state(&cx, || 0);
// Filter the todos based on the filter state
let mut filtered_todos = todos
.iter()
.filter(|(_id, item)| match *filter {
.filter(|(_, item)| match *filter {
FilterState::All => true,
FilterState::Active => !item.checked,
FilterState::Completed => item.checked,
})
.map(|(id, todo)| {
rsx!(TodoEntry {
key: "{id}",
todo: todo.clone()
})
})
.map(|f| *f.0)
.collect::<Vec<_>>();
filtered_todos.sort_unstable();
let items_left = todolist.len();
let show_clear_completed = todos.values().any(|todo| todo.checked);
let items_left = filtered_todos.len();
let item_text = match items_left {
1 => "item",
_ => "items",
};
cx.render(rsx!(
div { id: "app",
cx.render(rsx!{
section { class: "todoapp",
style { [include_str!("./assets/todomvc.css")] }
div {
header {
class: "header",
h1 { "todos" }
header { class: "header",
h1 {"todos"}
input {
class: "new-todo",
placeholder: "What needs to be done?",
value: "{draft}",
autofocus: "true",
oninput: move |evt| draft.set(evt.value.clone()),
onkeydown: move |evt| {
if evt.key == "Enter" {
if !draft.is_empty() {
todos.modify().insert(
*todo_id,
TodoItem {
id: *todo_id,
checked: false,
contents: draft.get().clone(),
},
);
todo_id += 1;
draft.set("".to_string());
}
}
}
}
}
todolist,
ul { class: "todo-list",
filtered_todos.iter().map(|id| rsx!(todo_entry( key: "{id}", id: *id, todos: todos )))
}
(!todos.is_empty()).then(|| rsx!(
footer {
span {
strong {"{items_left}"}
footer { class: "footer",
span { class: "todo-count",
strong {"{items_left} "}
span {"{item_text} left"}
}
ul { class: "filters",
li { class: "All", a { href: "", onclick: move |_| filter.set(FilterState::All), "All" }}
li { class: "Active", a { href: "active", onclick: move |_| filter.set(FilterState::Active), "Active" }}
li { class: "Completed", a { href: "completed", onclick: move |_| filter.set(FilterState::Completed), "Completed" }}
li { class: "All", a { onclick: move |_| filter.set(FilterState::All), "All" }}
li { class: "Active", a { onclick: move |_| filter.set(FilterState::Active), "Active" }}
li { class: "Completed", a { onclick: move |_| filter.set(FilterState::Completed), "Completed" }}
}
(show_clear_completed).then(|| rsx!(
button {
class: "clear-completed",
onclick: move |_| todos.modify().retain(|_, todo| todo.checked == false),
"Clear completed"
}
))
}
))
}
footer { class: "info",
p {"Double-click to edit a todo"}
p { "Created by ", a { href: "http://github.com/jkelleyrtp/", "jkelleyrtp" }}
p { "Part of ", a { href: "http://todomvc.com", "TodoMVC" }}
}
}
))
footer { class: "info",
p {"Double-click to edit a todo"}
p { "Created by ", a { href: "http://github.com/jkelleyrtp/", "jkelleyrtp" }}
p { "Part of ", a { href: "http://todomvc.com", "TodoMVC" }}
}
})
}
#[derive(PartialEq, Props)]
pub struct TodoEntryProps {
todo: Rc<TodoItem>,
#[derive(Props)]
pub struct TodoEntryProps<'a> {
todos: UseState<'a, im_rc::HashMap<u32, TodoItem>>,
id: u32,
}
pub fn TodoEntry(cx: Scope<TodoEntryProps>) -> Element {
pub fn todo_entry<'a>(cx: Scope<'a, TodoEntryProps<'a>>) -> Element {
let todo = &cx.props.todos[&cx.props.id];
let is_editing = use_state(&cx, || false);
let contents = use_state(&cx, || String::from(""));
let todo = &cx.props.todo;
let completed = if todo.checked { "completed" } else { "" };
cx.render(rsx! {
li {
"{todo.id}"
input {
class: "toggle",
r#type: "checkbox",
"{todo.checked}"
rsx!(cx, li { class: "{completed}",
div { class: "view",
input { class: "toggle", r#type: "checkbox", id: "cbg-{todo.id}", checked: "{todo.checked}",
onchange: move |evt| {
cx.props.todos.modify()[&cx.props.id].checked = evt.value.parse().unwrap();
}
}
is_editing.then(|| rsx!{
label { r#for: "cbg-{todo.id}", pointer_events: "none", "{todo.contents}" }
is_editing.then(|| rsx!{
input {
value: "{contents}",
oninput: move |evt| contents.set(evt.value.clone())
value: "{todo.contents}",
oninput: move |evt| cx.props.todos.modify()[&cx.props.id].contents = evt.value.clone(),
}
})
}
-67
View File
@@ -1,67 +0,0 @@
//! Example: Weather App
//! --------------------
//!
//!
//!
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
}
const ENDPOINT: &str = "https://api.openweathermap.org/data/2.5/weather";
fn app(cx: Scope) -> Element {
//
let body = use_suspense(
&cx,
|| async {
todo!()
// let content = reqwest::get(ENDPOINT)
// .await
// .unwrap()
// .json::<serde_json::Value>()
// .await
// .unwrap();
},
|props| {
//
cx.render(rsx!(WeatherDisplay {}))
},
);
cx.render(rsx! {
div {
{body}
}
})
}
#[derive(PartialEq, Props)]
struct WeatherProps {}
fn WeatherDisplay(cx: Scope<WeatherProps>) -> Element {
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",
"Jon's awesome site!!"
}
div{ class: "text-sm text-gray-500",
"He worked so hard on it :)"
}
div { class: "flex flex-row items-center justify-center mt-6",
div { class: "font-medium text-6xl",
"1337"
}
}
div { class: "flex flex-row justify-between mt-6",
"Legit made my own React"
}
}
}
}
))
}
-53
View File
@@ -1,53 +0,0 @@
//! Basic example that renders a simple VNode to the browser.
use dioxus_core as dioxus;
use dioxus_core::prelude::*;
use dioxus_core_macro::*;
use dioxus_hooks::*;
use dioxus_html as dioxus_elements;
fn main() {
console_error_panic_hook::set_once();
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
dioxus_web::launch(APP)
}
#[derive(serde::Deserialize)]
struct DogApi {
message: String,
}
static APP: Component = |(cx, _props)| {
let state = use_state(&cx, || 0);
const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random/";
let doggo = use_suspense(
cx,
|| async { reqwest::get(ENDPOINT).await.unwrap().json::<DogApi>().await },
|cx, res| match res {
Ok(res) => rsx!(
cx,
img {
src: "{res.message}"
}
),
Err(_err) => rsx!(cx, div { "No doggos for you :(" }),
},
);
rsx!(cx, div { align_items: "center"
section { class: "py-12 px-4 text-center"
div { class: "w-full max-w-2xl mx-auto"
span { class: "text-sm font-semibold"
"count: {state}"
}
div {
button { onclick: move |_| state.set(state + 1), "incr" }
button { onclick: move |_| state.set(state - 1), "decr" }
}
div {
{doggo}
}
}
}
})
};
-89
View File
@@ -1,89 +0,0 @@
//! Basic example that renders a simple VNode to the browser.
use dioxus_core as dioxus;
use dioxus_core::prelude::*;
use dioxus_core_macro::*;
use dioxus_hooks::*;
use dioxus_html as dioxus_elements;
fn main() {
// Setup logging
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
console_error_panic_hook::set_once();
// Run the app
dioxus_web::launch(APP)
}
static APP: Component = |cx| {
let mut count = use_state(&cx, || 3);
let content = use_state(&cx, || String::from("h1"));
let text_content = use_state(&cx, || String::from("Hello, world!"));
cx.render(rsx! {
div {
h1 { "content val is {content}" }
input {
r#type: "text",
value: "{text_content}"
oninput: move |e| text_content.set(e.value.clone())
}
{(0..10).map(|_| {
rsx!(
button {
onclick: move |_| count += 1,
"Click to add."
"Current count: {count}"
}
br {}
)
})}
select {
name: "cars"
id: "cars"
value: "{content}"
oninput: move |ev| {
content.set(ev.value.clone());
match ev.value.as_str() {
"h1" => count.set(0),
"h2" => count.set(5),
"h3" => count.set(10),
_ => {}
}
},
option { value: "h1", "h1" }
option { value: "h2", "h2" }
option { value: "h3", "h3" }
}
{render_list(cx, *count)}
{render_bullets(cx)}
CHILD {}
}
})
};
fn render_bullets(cx: Scope) -> Element {
rsx!(cx, div {
"bite me"
})
}
fn render_list(cx: Scope, count: usize) -> Element {
let items = (0..count).map(|f| {
rsx! {
li { "a - {f}" }
li { "b - {f}" }
li { "c - {f}" }
}
});
rsx!(cx, ul { {items} })
}
static CHILD: Component = |cx, _| rsx!(cx, div {"hello child"});
-55
View File
@@ -1,55 +0,0 @@
//! Basic example that renders a simple VNode to the browser.
use dioxus::events::on::MouseEvent;
use dioxus_core as dioxus;
use dioxus_core::prelude::*;
use dioxus_core_macro::*;
use dioxus_hooks::*;
use dioxus_html as dioxus_elements;
use std::future::Future;
use std::{pin::Pin, time::Duration};
use dioxus::prelude::*;
use dioxus_web::*;
fn main() {
// Setup logging
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
console_error_panic_hook::set_once();
// Run the app
dioxus_web::launch(App)
}
static App: Component = |cx| {
let mut state = use_state(&cx, || 0);
cx.render(rsx! {
div {
style: {
align_items: "center"
}
section { class: "py-12 px-4 text-center"
div { class: "w-full max-w-2xl mx-auto"
span { class: "text-sm font-semibold"
"static subtree"
}
}
}
section { class: "py-12 px-4 text-center"
div { class: "w-full max-w-2xl mx-auto"
span { class: "text-sm font-semibold"
"dynamic subtree {state}"
}
div {
button { onclick: move |e| state+=1, "incr" }
br {}
button { onclick: move |e| state-=1, "decr" }
}
}
}
}
})
};
-69
View File
@@ -1,69 +0,0 @@
//! Example: Webview Renderer
//! -------------------------
//!
//! This example shows how to use the dioxus_desktop crate to build a basic desktop application.
//!
//! Under the hood, the dioxus_desktop crate bridges a native Dioxus VirtualDom with a custom prebuit application running
//! in the webview runtime. Custom handlers are provided for the webview instance to consume patches and emit user events
//! into the native VDom instance.
//!
//! Currently, NodeRefs won't work properly, but all other event functionality will.
use dioxus::prelude::*;
use dioxus_core as dioxus;
use dioxus_core_macro::*;
use dioxus_hooks::*;
use dioxus_html as dioxus_elements;
// #[cfg]
fn main() {
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
dioxus_web::launch(App);
// env_logger::init();
// dioxus::web::launch(App);
}
static App: Component = |cx| {
dbg!("rednering parent");
cx.render(rsx! {
div {
But {
h1 {"he"}
}
// But {
// h1 {"llo"}
// }
// But {
// h1 {"world"}
// }
}
})
};
static But: Component = |cx| {
let mut count = use_state(&cx, || 0);
// let d = Dropper { name: "asd" };
// let handler = move |_| {
// dbg!(d.name);
// };
cx.render(rsx! {
div {
h1 { "Hifive counter: {count}" }
{cx.children()}
button { onclick: move |_| count += 1, "Up high!" }
button { onclick: move |_| count -= 1, "Down low!" }
// button { onclick: {handler}, "Down low!" }
}
})
};
// struct Dropper {
// name: &'static str,
// }
// impl Drop for Dropper {
// fn drop(&mut self) {
// dbg!("dropped");
// }
// }
-116
View File
@@ -1,116 +0,0 @@
/*
Tiny CRM: A port of the Yew CRM example to Dioxus.
*/
use dioxus_core as dioxus;
use dioxus_core::prelude::*;
use dioxus_core_macro::*;
use dioxus_hooks::*;
use dioxus_html as dioxus_elements;
fn main() {
// Setup logging
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
console_error_panic_hook::set_once();
dioxus_web::launch(App)
}
enum Scene {
ClientsList,
NewClientForm,
Settings,
}
#[derive(Clone, Debug, Default)]
pub struct Client {
pub first_name: String,
pub last_name: String,
pub description: String,
}
static App: Component = |cx| {
let scene = use_state(&cx, || Scene::ClientsList);
let clients = use_ref(&cx, || vec![] as Vec<Client>);
let firstname = use_state(&cx, || String::new());
let lastname = use_state(&cx, || String::new());
let description = use_state(&cx, || String::new());
let scene = match *scene {
Scene::ClientsList => {
rsx!(cx, div { class: "crm"
h2 { "List of clients" margin_bottom: "10px" }
div { class: "clients" margin_left: "10px"
{clients.read().iter().map(|client| rsx!(
div { class: "client" style: "margin-bottom: 50px"
p { "First Name: {client.first_name}" }
p { "Last Name: {client.last_name}" }
p {"Description: {client.description}"}
})
)}
}
button { class: "pure-button pure-button-primary" onclick: move |_| scene.set(Scene::NewClientForm), "Add New" }
button { class: "pure-button" onclick: move |_| scene.set(Scene::Settings), "Settings" }
})
}
Scene::NewClientForm => {
let add_new = move |_| {
clients.write().push(Client {
description: (*description).clone(),
first_name: (*firstname).clone(),
last_name: (*lastname).clone(),
});
description.set(String::new());
firstname.set(String::new());
lastname.set(String::new());
};
rsx!(cx, div { class: "crm"
h2 {"Add new client" margin_bottom: "10px" }
form { class: "pure-form"
input { class: "new-client firstname" placeholder: "First name" value: "{firstname}"
oninput: move |evt| firstname.set(evt.value.clone())
}
input { class: "new-client lastname" placeholder: "Last name" value: "{lastname}"
oninput: move |evt| lastname.set(evt.value.clone())
}
textarea { class: "new-client description" placeholder: "Description" value: "{description}"
oninput: move |evt| description.set(evt.value.clone())
}
}
button { class: "pure-button pure-button-primary", onclick: {add_new}, "Add New" }
button { class: "pure-button", onclick: move |_| scene.set(Scene::ClientsList), "Go Back" }
})
}
Scene::Settings => {
rsx!(cx, div {
h2 { "Settings" margin_bottom: "10px" }
button {
background: "rgb(202, 60, 60)"
class: "pure-button pure-button-primary"
onclick: move |_| {
clients.write().clear();
scene.set(Scene::ClientsList);
},
"Remove all clients"
}
button {
class: "pure-button pure-button-primary"
onclick: move |_| scene.set(Scene::ClientsList),
"Go Back"
}
})
}
};
rsx!(cx, body {
link {
rel: "stylesheet"
href: "https://unpkg.com/purecss@2.0.6/build/pure-min.css"
integrity: "sha384-Uu6IeWbM+gzNVXJcM9XV3SohHtmWE+3VGi496jvgX1jyvDTXfdK+rfZc8C1Aehk5"
crossorigin: "anonymous"
}
margin_left: "35%"
h1 {"Dioxus CRM Example"}
{scene}
})
};
-147
View File
@@ -1,147 +0,0 @@
//! Basic example that renders a simple VNode to the browser.
use dioxus::events::on::MouseEvent;
use dioxus_core as dioxus;
use dioxus_core::prelude::*;
use dioxus_core_macro::*;
use dioxus_hooks::*;
use dioxus_html as dioxus_elements;
use std::future::Future;
use std::{pin::Pin, time::Duration};
use dioxus::prelude::*;
use dioxus_html::SvgAttributes;
use dioxus_web::*;
fn main() {
// Setup logging
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
console_error_panic_hook::set_once();
// Run the app
dioxus_web::launch(App)
}
pub static App: Component = |cx| {
cx.render(rsx!(
div { class: "overflow-hidden"
link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel:"stylesheet" }
Header {}
// Entry {}
Hero {}
Hero {}
Hero {}
Hero {}
Hero {}
}
))
};
pub static Header: Component = |cx| {
cx.render(rsx! {
div {
header { class: "text-gray-400 bg-gray-900 body-font"
div { class: "container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center"
a { class: "flex title-font font-medium items-center text-white mb-4 md:mb-0"
StacksIcon {}
span { class: "ml-3 text-xl" "Hello Dioxus!"}
}
nav { class: "md:ml-auto flex flex-wrap items-center text-base justify-center"
a { class: "mr-5 hover:text-white" "First Link"}
a { class: "mr-5 hover:text-white" "Second Link"}
a { class: "mr-5 hover:text-white" "Third Link"}
a { class: "mr-5 hover:text-white" "Fourth Link"}
}
button {
class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0"
"Button"
RightArrowIcon {}
}
}
}
}
})
};
pub static Hero: Component = |cx| {
//
cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font"
div { class: "container mx-auto flex px-5 py-24 md:flex-row flex-col items-center"
div { class: "lg:flex-grow md:w-1/2 lg:pr-24 md:pr-16 flex flex-col md:items-start md:text-left mb-16 md:mb-0 items-center text-center"
h1 { class: "title-font sm:text-4xl text-3xl mb-4 font-medium text-white"
br { class: "hidden lg:inline-block" }
"Dioxus Sneak Peek"
}
p {
class: "mb-8 leading-relaxed"
"Dioxus is a new UI framework that makes it easy and simple to write cross-platform apps using web
technologies! It is functional, fast, and portable. Dioxus can run on the web, on the desktop, and
on mobile and embedded platforms."
}
div { class: "flex justify-center"
button {
class: "inline-flex text-white bg-indigo-500 border-0 py-2 px-6 focus:outline-none hover:bg-indigo-600 rounded text-lg"
"Learn more"
}
button {
class: "ml-4 inline-flex text-gray-400 bg-gray-800 border-0 py-2 px-6 focus:outline-none hover:bg-gray-700 hover:text-white rounded text-lg"
"Build an app"
}
}
}
div { class: "lg:max-w-lg lg:w-full md:w-1/2 w-5/6"
img { class: "object-cover object-center rounded" alt: "hero" src: "https://i.imgur.com/oK6BLtw.png"
referrerpolicy:"no-referrer"
}
}
}
}
})
};
pub static Entry: Component = |cx| {
//
cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font"
div { class: "container mx-auto flex px-5 py-24 md:flex-row flex-col items-center"
textarea {
}
}
}
})
};
pub static StacksIcon: Component = |cx| {
cx.render(rsx!(
svg {
// xmlns: "http://www.w3.org/2000/svg"
fill: "none"
stroke: "currentColor"
stroke_linecap: "round"
stroke_linejoin: "round"
stroke_width: "2"
// class: "w-10 h-10 text-white p-2 bg-indigo-500 rounded-full"
viewBox: "0 0 24 24"
path { d: "M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"}
}
))
};
pub static RightArrowIcon: Component = |cx| {
cx.render(rsx!(
svg {
fill: "none"
stroke: "currentColor"
stroke_linecap: "round"
stroke_linejoin: "round"
stroke_width: "2"
// class: "w-4 h-4 ml-1"
viewBox: "0 0 24 24"
path { d: "M5 12h14M12 5l7 7-7 7"}
}
))
};
-127
View File
@@ -1,127 +0,0 @@
#![allow(non_upper_case_globals, non_snake_case)]
//! Example: Webview Renderer
//! -------------------------
//!
//! This example shows how to use the dioxus_desktop crate to build a basic desktop application.
//!
//! Under the hood, the dioxus_desktop crate bridges a native Dioxus VirtualDom with a custom prebuilt application running
//! in the webview runtime. Custom handlers are provided for the webview instance to consume patches and emit user events
//! into the native VDom instance.
//!
//! Currently, NodeRefs won't work properly, but all other event functionality will.
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
}
fn app(cx: Scope) -> Element {
let mut rng = SmallRng::from_entropy();
cx.render(rsx! {
table {
tbody {
(0..1_000).map(|f| {
let label = Label::new(&mut rng);
rsx! (Row { row_id: f, label: label })
})
}
}
})
}
#[derive(PartialEq, Props)]
struct RowProps {
row_id: usize,
label: Label,
}
fn Row(cx: Scope<RowProps>) -> Element {
let [adj, col, noun] = cx.props.label.0;
cx.render(rsx! {
tr {
td { class:"col-md-1", "{cx.props.row_id}" }
td { class:"col-md-1", onclick: move |_| { /* run onselect */ },
a { class: "lbl", "{adj}" "{col}" "{noun}" }
}
td { class: "col-md-1",
a { class: "remove", onclick: move |_| {/* remove */},
span { class: "glyphicon glyphicon-remove remove", aria_hidden: "true" }
}
}
td { class: "col-md-6" }
}
})
}
use rand::prelude::*;
#[derive(PartialEq)]
struct Label([&'static str; 3]);
impl Label {
fn new(rng: &mut SmallRng) -> Self {
Label([
ADJECTIVES.choose(rng).unwrap(),
COLOURS.choose(rng).unwrap(),
NOUNS.choose(rng).unwrap(),
])
}
}
static ADJECTIVES: &[&str] = &[
"pretty",
"large",
"big",
"small",
"tall",
"short",
"long",
"handsome",
"plain",
"quaint",
"clean",
"elegant",
"easy",
"angry",
"crazy",
"helpful",
"mushy",
"odd",
"unsightly",
"adorable",
"important",
"inexpensive",
"cheap",
"expensive",
"fancy",
];
static COLOURS: &[&str] = &[
"red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black",
"orange",
];
static NOUNS: &[&str] = &[
"table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger",
"pizza", "mouse", "keyboard",
];
#[cfg(target_arch = "wasm32")]
fn intern_strings() {
for adj in ADJECTIVES {
wasm_bindgen::intern(adj);
}
for col in COLOURS {
wasm_bindgen::intern(col);
}
for no in NOUNS {
wasm_bindgen::intern(no);
}
wasm_bindgen::intern("col-md-1");
wasm_bindgen::intern("col-md-6");
wasm_bindgen::intern("glyphicon glyphicon-remove remove");
wasm_bindgen::intern("remove");
wasm_bindgen::intern("dioxus");
wasm_bindgen::intern("lbl");
wasm_bindgen::intern("true");
}
-28
View File
@@ -1,28 +0,0 @@
//! Example: Webview Renderer
//! -------------------------
//!
//! This example shows how to use the dioxus_desktop crate to build a basic desktop application.
//!
//! Under the hood, the dioxus_desktop crate bridges a native Dioxus VirtualDom with a custom prebuilt application running
//! in the webview runtime. Custom handlers are provided for the webview instance to consume patches and emit user events
//! into the native VDom instance.
//!
//! Currently, NodeRefs won't work properly, but all other event functionality will.
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
}
fn app(cx: Scope) -> Element {
let mut count = use_state(&cx, || 0);
cx.render(rsx! {
div {
h1 { "Hifive counter: {count}" }
button { onclick: move |_| count += 1, "Up high!" }
button { onclick: move |_| count -= 1, "Down low!" }
}
})
}
+4 -1
View File
@@ -9,10 +9,13 @@ fn main() {
}
fn app(cx: Scope) -> Element {
let contents = use_state(&cx, || String::from("<script>alert(123)</script>"));
let contents = use_state(&cx, || {
String::from("<script>alert(\"hello world\")</script>")
});
cx.render(rsx! {
div {
h1 {"Dioxus is XSS-Safe"}
h3 { "{contents}" }
input {
value: "{contents}",
+2 -2
View File
@@ -5,7 +5,6 @@
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" charset="utf-8" />
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0 maximum-scale=1.0 user-scalable=no" charset="utf-8" /> -->
</head>
@@ -13,6 +12,7 @@
<div id="main">
</div>
</body>
<script type="text/javascript" src="index.js"> </script>
<script type="text/javascript" src="index.js">
</script>
</html>
+1 -1
View File
@@ -191,7 +191,7 @@ impl DesktopController {
// create `first_menu`
let mut first_menu = MenuBar::new();
first_menu.add_native_item(MenuItem::About("Todos".to_string()));
first_menu.add_native_item(MenuItem::About("App".to_string()));
first_menu.add_native_item(MenuItem::Services);
first_menu.add_native_item(MenuItem::Separator);
first_menu.add_native_item(MenuItem::Hide);
+52 -31
View File
@@ -3,27 +3,16 @@ use std::{cell::Cell, future::Future, rc::Rc};
pub fn use_future<'a, T: 'static, F: Future<Output = T> + 'static>(
cx: &'a ScopeState,
f: impl FnOnce() -> F,
) -> (Option<&T>, FutureHandle<'a, T>) {
let state = cx.use_hook(|_| {
new_fut: impl FnOnce() -> F,
) -> &'a UseFuture<T> {
let state = cx.use_hook(move |_| {
//
let fut = f();
let slot = Rc::new(Cell::new(None));
let updater = cx.schedule_update();
let _slot = slot.clone();
let new_fut = async move {
let res = fut.await;
_slot.set(Some(res));
updater();
};
let task = cx.push_future(new_fut);
UseFutureInner {
needs_regen: true,
slot,
UseFuture {
update: cx.schedule_update(),
needs_regen: Cell::new(true),
slot: Rc::new(Cell::new(None)),
value: None,
task: Some(task),
task: None,
}
});
@@ -32,23 +21,55 @@ pub fn use_future<'a, T: 'static, F: Future<Output = T> + 'static>(
state.task = None;
}
(
state.value.as_ref(),
FutureHandle {
cx,
value: Cell::new(None),
},
)
if state.needs_regen.get() {
// We don't need regen anymore
state.needs_regen.set(false);
// Create the new future
let fut = new_fut();
// Clone in our cells
let slot = state.slot.clone();
let updater = state.update.clone();
state.task = Some(cx.push_future(async move {
let res = fut.await;
slot.set(Some(res));
updater();
}));
}
state
}
struct UseFutureInner<T> {
needs_regen: bool,
pub struct UseFuture<T> {
update: Rc<dyn Fn()>,
needs_regen: Cell<bool>,
value: Option<T>,
slot: Rc<Cell<Option<T>>>,
task: Option<TaskId>,
}
pub struct FutureHandle<'a, T> {
cx: &'a ScopeState,
value: Cell<Option<T>>,
impl<T> UseFuture<T> {
pub fn restart(&self) {
self.needs_regen.set(true);
(self.update)();
}
// clears the value in the future slot without starting the future over
pub fn clear(&self) -> Option<T> {
(self.update)();
self.slot.replace(None)
}
// Manually set the value in the future slot without starting the future over
pub fn set(&self, new_value: T) {
self.slot.set(Some(new_value));
self.needs_regen.set(true);
(self.update)();
}
pub fn value(&self) -> Option<&T> {
self.value.as_ref()
}
}
+1 -1
View File
@@ -42,7 +42,7 @@ pub fn Link<'a, R: Routable>(cx: Scope<'a, LinkProps<'a, R>>) -> Element {
href: "#",
class: format_args!("{}", cx.props.class.unwrap_or("")),
onclick: move |_| service.push_route(cx.props.to.clone()),
{&cx.props.children}
&cx.props.children
}
})
}
+1 -1
View File
@@ -194,7 +194,7 @@ impl<'a> TextRenderer<'a, '_> {
// when the page is loaded, the `querySelectorAll` will be used to collect all the nodes, and then add
// them interpreter's stack
if let (true, Some(id)) = (self.cfg.pre_render, node.try_mounted_id()) {
write!(f, " dio_el=\"{}\"", id)?;
write!(f, " dioxus-id=\"{}\"", id)?;
for _listener in el.listeners {
// todo: write the listeners
+2 -2
View File
@@ -55,13 +55,13 @@ impl WebsysDom {
// re-hydrate the page - only supports one virtualdom per page
if cfg.hydrate {
// Load all the elements into the arena
let node_list: NodeList = document.query_selector_all("dio_el").unwrap();
let node_list: NodeList = document.query_selector_all("dioxus-id").unwrap();
let len = node_list.length() as usize;
for x in 0..len {
let node: Node = node_list.get(x as u32).unwrap();
let el: &Element = node.dyn_ref::<Element>().unwrap();
let id: String = el.get_attribute("dio_el").unwrap();
let id: String = el.get_attribute("dioxus-id").unwrap();
let id = id.parse::<usize>().unwrap();
nodes[id] = Some(node);
}