mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-10 06:34:20 +00:00
chore: move CLI into its own "studio" app
This commit is contained in:
parent
207784800d
commit
fd7933561f
37 changed files with 0 additions and 1481 deletions
|
@ -11,7 +11,6 @@ description = "Core functionality for Dioxus - a concurrent renderer-agnostic Vi
|
|||
dioxus-core = { path="./packages/core", version="0.1.0" }
|
||||
dioxus-core-macro = { path="./packages/core-macro", version="0.1.0" }
|
||||
dioxus-html-namespace = { path="./packages/html-namespace" }
|
||||
|
||||
dioxus-web = { path="./packages/web", optional=true }
|
||||
# dioxus-hooks = { path="./packages/hooks", version="0.0.0" }
|
||||
|
||||
|
@ -48,10 +47,7 @@ members = [
|
|||
"packages/html-namespace",
|
||||
"packages/web",
|
||||
"packages/webview",
|
||||
"packages/cli",
|
||||
# "packages/atoms",
|
||||
# "packages/ssr",
|
||||
# "packages/docsite",
|
||||
# "packages/router",
|
||||
# "packages/inputs",
|
||||
]
|
||||
|
|
2
packages/cli/.gitignore
vendored
2
packages/cli/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
/target
|
||||
Cargo.lock
|
3
packages/cli/.vscode/settings.json
vendored
3
packages/cli/.vscode/settings.json
vendored
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"rust-analyzer.inlayHints.enable": false
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
[package]
|
||||
name = "dioxus-cli"
|
||||
version = "0.1.0"
|
||||
authors = ["Jonathan Kelley <jkelleyrtp@gmail.com>"]
|
||||
edition = "2018"
|
||||
description = "CLI tool for developing, testing, and publishing Dioxus apps"
|
||||
"license" = "MIT/Apache-2.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.23"
|
||||
log = "0.4.13"
|
||||
fern = { version="0.6.0", features=["colored"] }
|
||||
wasm-bindgen-cli-support = "0.2.73"
|
||||
anyhow = "1.0.38"
|
||||
argh = "0.1.4"
|
||||
serde = "1.0.120"
|
||||
serde_json = "1.0.61"
|
||||
async-std = { version="1.9.0", features=["attributes"] }
|
||||
tide = "0.15.0"
|
||||
fs_extra = "1.2.0"
|
||||
|
||||
cargo_toml = "0.8.1"
|
||||
futures = "0.3.12"
|
||||
notify = "5.0.0-pre.4"
|
||||
rjdebounce = "0.2.1"
|
||||
tempfile = "3.2.0"
|
||||
|
||||
[[bin]]
|
||||
|
||||
path = "src/main.rs"
|
||||
name = "dioxus"
|
|
@ -1,48 +0,0 @@
|
|||
<div align="center">
|
||||
<h1>📦✨ dioxus-cli</h1>
|
||||
<p>
|
||||
<strong>Tooling to supercharge dioxus projects</strong>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
# About
|
||||
---
|
||||
dioxus-cli (inspired by wasm-pack and webpack) is a tool to help get dioxus projects off the ground. It handles all the build, development, bundling, and publishing to make web development just a simple two commands: `cargo init` and `dioxus-cli publish`.
|
||||
|
||||
Best thing:
|
||||
- No NPM.
|
||||
- No Webpack.
|
||||
- No `node_modules`.
|
||||
- No Babel
|
||||
- No parcel
|
||||
- No rollup
|
||||
- No ESLint
|
||||
|
||||
Just install Rust, dioxus-cli, and you're good to go.
|
||||
`cargo install --git github.com/jkelleyrtp/dioxus-cli`
|
||||
|
||||
Need a development server?
|
||||
`dioxus develop`
|
||||
|
||||
Need to run an example?
|
||||
`dioxus develop --example textbox`
|
||||
|
||||
Need to benchmark a component?
|
||||
`dioxus bench`
|
||||
|
||||
Need to test your code?
|
||||
`dioxus test`
|
||||
|
||||
Need to build your code into a bundle?
|
||||
`dioxus build --outdir public`
|
||||
|
||||
Need to publish your code to GitHub pages, Netlify, etc?
|
||||
`dioxus publish --ghpages myrepo.git`
|
||||
|
||||
# Use in your project
|
||||
---
|
||||
Sometimes you'll want to include static assets without bundling them into your .wasm content. dioxus-cli provides a few ways of doing this:
|
||||
|
||||
- Load in dynamic content using `dioxus::asset("./static/images/blah.svg")`
|
||||
- Live-reload HTML templates without rebuilding your .wasm with `dioxus::template("./templates/blah.html")`
|
||||
- Use a CSS library like tailwind in your dioxus configuration with
|
|
@ -1,146 +0,0 @@
|
|||
use crate::{
|
||||
cli::BuildOptions,
|
||||
config::{Config, ExecutableType},
|
||||
error::Result,
|
||||
};
|
||||
use log::{info, warn};
|
||||
use std::{io::Write, process::Command};
|
||||
use wasm_bindgen_cli_support::Bindgen;
|
||||
|
||||
pub struct BuildConfig {}
|
||||
impl Into<BuildConfig> for BuildOptions {
|
||||
fn into(self) -> BuildConfig {
|
||||
BuildConfig {}
|
||||
}
|
||||
}
|
||||
impl Default for BuildConfig {
|
||||
fn default() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(config: &Config, _build_config: &BuildConfig) -> Result<()> {
|
||||
/*
|
||||
[1] Build the project with cargo, generating a wasm32-unknown-unknown target (is there a more specific, better target to leverage?)
|
||||
[2] Generate the appropriate build folders
|
||||
[3] Wasm-bindgen the .wasm fiile, and move it into the {builddir}/modules/xxxx/xxxx_bg.wasm
|
||||
[4] Wasm-opt the .wasm file with whatever optimizations need to be done
|
||||
[5] Link up the html page to the wasm module
|
||||
*/
|
||||
|
||||
let Config {
|
||||
out_dir,
|
||||
crate_dir,
|
||||
target_dir,
|
||||
static_dir,
|
||||
executable,
|
||||
..
|
||||
} = config;
|
||||
|
||||
let t_start = std::time::Instant::now();
|
||||
|
||||
// [1] Build the .wasm module
|
||||
info!("Running build commands...");
|
||||
let mut cmd = Command::new("cargo");
|
||||
cmd.current_dir(&crate_dir)
|
||||
.arg("build")
|
||||
.arg("--target")
|
||||
.arg("wasm32-unknown-unknown")
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.stderr(std::process::Stdio::piped());
|
||||
|
||||
if config.release {
|
||||
cmd.arg("--release");
|
||||
}
|
||||
|
||||
match executable {
|
||||
ExecutableType::Binary(name) => cmd.arg("--bin").arg(name),
|
||||
ExecutableType::Lib(name) => cmd.arg("--lib").arg(name),
|
||||
ExecutableType::Example(name) => cmd.arg("--example").arg(name),
|
||||
};
|
||||
|
||||
let mut child = cmd.spawn()?;
|
||||
let _err_code = child.wait()?;
|
||||
|
||||
info!("Build complete!");
|
||||
|
||||
// [2] Establish the output directory structure
|
||||
let bindgen_outdir = out_dir.join("wasm");
|
||||
|
||||
// [3] Bindgen the final binary for use easy linking
|
||||
let mut bindgen_builder = Bindgen::new();
|
||||
|
||||
let release_type = match config.release {
|
||||
true => "release",
|
||||
false => "debug",
|
||||
};
|
||||
|
||||
let input_path = match executable {
|
||||
ExecutableType::Binary(name) | ExecutableType::Lib(name) => target_dir
|
||||
// .join("wasm32-unknown-unknown/release")
|
||||
.join(format!("wasm32-unknown-unknown/{}", release_type))
|
||||
.join(format!("{}.wasm", name)),
|
||||
|
||||
ExecutableType::Example(name) => target_dir
|
||||
// .join("wasm32-unknown-unknown/release/examples")
|
||||
.join(format!("wasm32-unknown-unknown/{}/examples", release_type))
|
||||
.join(format!("{}.wasm", name)),
|
||||
};
|
||||
|
||||
bindgen_builder
|
||||
.input_path(input_path)
|
||||
.web(true)?
|
||||
.debug(true)
|
||||
.demangle(true)
|
||||
.keep_debug(true)
|
||||
.remove_name_section(false)
|
||||
.remove_producers_section(false)
|
||||
.out_name("module")
|
||||
.generate(&bindgen_outdir)?;
|
||||
|
||||
// [4]
|
||||
// TODO: wasm-opt
|
||||
|
||||
// [5] Generate the html file with the module name
|
||||
// TODO: support names via options
|
||||
info!("Writing to '{:#?}' directory...", out_dir);
|
||||
let mut file = std::fs::File::create(out_dir.join("index.html"))?;
|
||||
file.write_all(gen_page("./wasm/module.js").as_str().as_bytes())?;
|
||||
|
||||
let copy_options = fs_extra::dir::CopyOptions::new();
|
||||
match fs_extra::dir::copy(static_dir, out_dir, ©_options) {
|
||||
Ok(_) => {}
|
||||
Err(_e) => {
|
||||
warn!("Error copying dir");
|
||||
}
|
||||
}
|
||||
|
||||
let t_end = std::time::Instant::now();
|
||||
log::info!("Done in {}ms! 🎉", (t_end - t_start).as_millis());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn gen_page(module: &str) -> String {
|
||||
format!(
|
||||
r#"
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
|
||||
<meta charset="UTF-8" />
|
||||
<link
|
||||
href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Note the usage of `type=module` here as this is an ES6 module -->
|
||||
<script type="module">
|
||||
import init from "{}";
|
||||
init("./wasm/module_bg.wasm");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
"#,
|
||||
module
|
||||
)
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
//! Utilities for working with cargo and rust files
|
||||
use crate::error::{Error, Result};
|
||||
use std::{env, fs, path::PathBuf, process::Command, str};
|
||||
|
||||
/// How many parent folders are searched for a `Cargo.toml`
|
||||
const MAX_ANCESTORS: u32 = 10;
|
||||
|
||||
/// Returns the root of the crate that the command is run from
|
||||
///
|
||||
/// If the command is run from the workspace root, this will return the top-level Cargo.toml
|
||||
pub fn crate_root() -> Result<PathBuf> {
|
||||
// From the current directory we work our way up, looking for `Cargo.toml`
|
||||
env::current_dir()
|
||||
.ok()
|
||||
.and_then(|mut wd| {
|
||||
for _ in 0..MAX_ANCESTORS {
|
||||
if contains_manifest(&wd) {
|
||||
return Some(wd);
|
||||
}
|
||||
if !wd.pop() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.ok_or_else(|| Error::CargoError("Failed to find the cargo directory".to_string()))
|
||||
}
|
||||
|
||||
/// Returns the root of a workspace
|
||||
/// TODO @Jon, find a different way that doesn't rely on the cargo metadata command (it's slow)
|
||||
pub fn workspace_root() -> Result<PathBuf> {
|
||||
let output = Command::new("cargo")
|
||||
.args(&["metadata"])
|
||||
.output()
|
||||
.map_err(|_| Error::CargoError("Manifset".to_string()))?;
|
||||
|
||||
if !output.status.success() {
|
||||
let mut msg = str::from_utf8(&output.stderr).unwrap().trim();
|
||||
if msg.starts_with("error: ") {
|
||||
msg = &msg[7..];
|
||||
}
|
||||
|
||||
return Err(Error::CargoError(msg.to_string()));
|
||||
}
|
||||
|
||||
let stdout = str::from_utf8(&output.stdout).unwrap();
|
||||
for line in stdout.lines() {
|
||||
let meta: serde_json::Value = serde_json::from_str(line)
|
||||
.map_err(|_| Error::CargoError("InvalidOutput".to_string()))?;
|
||||
|
||||
let root = meta["workspace_root"]
|
||||
.as_str()
|
||||
.ok_or_else(|| Error::CargoError("InvalidOutput".to_string()))?;
|
||||
return Ok(root.into());
|
||||
}
|
||||
|
||||
Err(Error::CargoError("InvalidOutput".to_string()))
|
||||
}
|
||||
|
||||
/// Checks if the directory contains `Cargo.toml`
|
||||
fn contains_manifest(path: &PathBuf) -> bool {
|
||||
fs::read_dir(path)
|
||||
.map(|entries| {
|
||||
entries
|
||||
.filter_map(Result::ok)
|
||||
.any(|ent| &ent.file_name() == "Cargo.toml")
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
use argh::FromArgs;
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
/// Top-level command.
|
||||
pub struct LaunchOptions {
|
||||
#[argh(subcommand)]
|
||||
pub command: LaunchCommand,
|
||||
}
|
||||
|
||||
/// The various kinds of commands that `wasm-pack` can execute.
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
#[argh(subcommand)]
|
||||
pub enum LaunchCommand {
|
||||
Develop(DevelopOptions),
|
||||
Build(BuildOptions),
|
||||
Test(TestOptions),
|
||||
Publish(PublishOptions),
|
||||
}
|
||||
|
||||
/// Publish your yew application to Github Pages, Netlify, or S3
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
#[argh(subcommand, name = "publish")]
|
||||
pub struct PublishOptions {}
|
||||
|
||||
/// 🔬 test your yew application!
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
#[argh(subcommand, name = "test")]
|
||||
pub struct TestOptions {
|
||||
/// an example in the crate
|
||||
#[argh(option)]
|
||||
pub example: Option<String>,
|
||||
}
|
||||
|
||||
/// 🏗️ Build your yew application
|
||||
#[derive(FromArgs, PartialEq, Debug, Clone)]
|
||||
#[argh(subcommand, name = "build")]
|
||||
pub struct BuildOptions {
|
||||
/// an optional direction which is "up" by default
|
||||
#[argh(option, short = 'o', default = "String::from(\"public\")")]
|
||||
pub outdir: String,
|
||||
|
||||
/// an example in the crate
|
||||
#[argh(option)]
|
||||
pub example: Option<String>,
|
||||
|
||||
/// develop in release mode
|
||||
#[argh(switch, short = 'r')]
|
||||
pub release: bool,
|
||||
}
|
||||
|
||||
/// 🛠 Start a development server
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
#[argh(subcommand, name = "develop")]
|
||||
pub struct DevelopOptions {
|
||||
/// an example in the crate
|
||||
#[argh(option)]
|
||||
pub example: Option<String>,
|
||||
|
||||
/// develop in release mode
|
||||
#[argh(switch, short = 'r')]
|
||||
pub release: bool,
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
use crate::{
|
||||
cli::{BuildOptions, DevelopOptions},
|
||||
error::Result,
|
||||
};
|
||||
use std::{io::Write, path::PathBuf, process::Command};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub out_dir: PathBuf,
|
||||
pub crate_dir: PathBuf,
|
||||
pub workspace_dir: PathBuf,
|
||||
pub target_dir: PathBuf,
|
||||
pub static_dir: PathBuf,
|
||||
pub manifest: cargo_toml::Manifest<cargo_toml::Value>,
|
||||
pub executable: ExecutableType,
|
||||
pub release: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ExecutableType {
|
||||
Binary(String),
|
||||
Lib(String),
|
||||
Example(String),
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new() -> Result<Self> {
|
||||
let crate_dir = crate::cargo::crate_root()?;
|
||||
let workspace_dir = crate::cargo::workspace_root()?;
|
||||
let target_dir = workspace_dir.join("target");
|
||||
let out_dir = crate_dir.join("public");
|
||||
let cargo_def = &crate_dir.join("Cargo.toml");
|
||||
let static_dir = crate_dir.join("static");
|
||||
|
||||
let manifest = cargo_toml::Manifest::from_path(&cargo_def).unwrap();
|
||||
|
||||
// We just assume they're using a 'main.rs'
|
||||
// Anyway, we've already parsed the manifest, so it should be easy to change the type
|
||||
let output_filename = (&manifest)
|
||||
.lib
|
||||
.as_ref()
|
||||
.and_then(|lib| lib.name.clone())
|
||||
.or_else(|| {
|
||||
(&manifest)
|
||||
.package
|
||||
.as_ref()
|
||||
.and_then(|pkg| Some(pkg.name.replace("-", "_")))
|
||||
.clone()
|
||||
})
|
||||
.expect("No lib found from cargo metadata");
|
||||
let executable = ExecutableType::Binary(output_filename);
|
||||
|
||||
let release = false;
|
||||
|
||||
Ok(Self {
|
||||
out_dir,
|
||||
crate_dir,
|
||||
workspace_dir,
|
||||
target_dir,
|
||||
static_dir,
|
||||
manifest,
|
||||
executable,
|
||||
release,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn as_example(&mut self, example_name: String) -> &mut Self {
|
||||
self.executable = ExecutableType::Example(example_name);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_release(&mut self, release: bool) -> &mut Self {
|
||||
self.release = release;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_build_options(&mut self, options: &BuildOptions) {
|
||||
if let Some(name) = &options.example {
|
||||
self.as_example(name.clone());
|
||||
}
|
||||
self.release = options.release;
|
||||
self.out_dir = options.outdir.clone().into();
|
||||
}
|
||||
|
||||
pub fn with_develop_options(&mut self, options: &DevelopOptions) {
|
||||
if let Some(name) = &options.example {
|
||||
self.as_example(name.clone());
|
||||
}
|
||||
self.release = options.release;
|
||||
self.out_dir = tempfile::Builder::new().tempdir().expect("").into_path();
|
||||
}
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
use crate::{builder::BuildConfig, cli::DevelopOptions, config::Config, error::Result};
|
||||
use async_std::prelude::FutureExt;
|
||||
|
||||
use async_std::future;
|
||||
use async_std::prelude::*;
|
||||
|
||||
use log::info;
|
||||
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct DevelopConfig {}
|
||||
impl Into<DevelopConfig> for DevelopOptions {
|
||||
fn into(self) -> DevelopConfig {
|
||||
DevelopConfig {}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn start(config: &Config, _options: &DevelopConfig) -> Result<()> {
|
||||
log::info!("Starting development server 🚀");
|
||||
|
||||
let Config { out_dir, .. } = config;
|
||||
|
||||
// Spawn the server onto a seperate task
|
||||
// This lets the task progress while we handle file updates
|
||||
let server = async_std::task::spawn(launch_server(out_dir.clone()));
|
||||
let watcher = async_std::task::spawn(watch_directory(config.clone()));
|
||||
|
||||
match server.race(watcher).await {
|
||||
Err(e) => log::warn!("Error running development server, {:?}", e),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn watch_directory(config: Config) -> Result<()> {
|
||||
// Create a channel to receive the events.
|
||||
let (watcher_tx, watcher_rx) = async_std::channel::bounded(100);
|
||||
|
||||
// Automatically select the best implementation for your platform.
|
||||
// You can also access each implementation directly e.g. INotifyWatcher.
|
||||
let mut watcher: RecommendedWatcher = Watcher::new_immediate(move |res| {
|
||||
async_std::task::block_on(watcher_tx.send(res));
|
||||
})
|
||||
.expect("failed to make watcher");
|
||||
|
||||
let src_dir = crate::cargo::crate_root()?;
|
||||
|
||||
// Add a path to be watched. All files and directories at that path and
|
||||
// below will be monitored for changes.
|
||||
watcher
|
||||
.watch(src_dir.join("src"), RecursiveMode::Recursive)
|
||||
.expect("Failed to watch dir");
|
||||
|
||||
watcher
|
||||
.watch(src_dir.join("examples"), RecursiveMode::Recursive)
|
||||
.expect("Failed to watch dir");
|
||||
|
||||
let build_config = BuildConfig::default();
|
||||
|
||||
'run: loop {
|
||||
crate::builder::build(&config, &build_config)?;
|
||||
|
||||
// Wait for the message with a debounce
|
||||
let _msg = watcher_rx
|
||||
.recv()
|
||||
.join(future::ready(1_usize).delay(Duration::from_millis(2000)))
|
||||
.await;
|
||||
|
||||
info!("File updated, rebuilding app");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn launch_server(outdir: PathBuf) -> Result<()> {
|
||||
let _crate_dir = crate::cargo::crate_root()?;
|
||||
let _workspace_dir = crate::cargo::workspace_root()?;
|
||||
|
||||
let mut app = tide::with_state(ServerState::new(outdir.to_owned()));
|
||||
let p = outdir.display().to_string();
|
||||
|
||||
app.at("/")
|
||||
.get(|req: tide::Request<ServerState>| async move {
|
||||
log::info!("Connected to development server");
|
||||
let state = req.state();
|
||||
Ok(tide::Body::from_file(state.serv_path.clone().join("index.html")).await?)
|
||||
})
|
||||
.serve_dir(p)?;
|
||||
|
||||
let port = "8080";
|
||||
let serve_addr = format!("0.0.0.0:{}", port);
|
||||
// let serve_addr = format!("127.0.0.1:{}", port);
|
||||
|
||||
info!("App available at http://{}", serve_addr);
|
||||
app.listen(serve_addr).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// https://github.com/http-rs/tide/blob/main/examples/state.rs
|
||||
/// Tide seems to prefer using state instead of injecting into the app closure
|
||||
/// The app closure needs to be static and
|
||||
#[derive(Clone)]
|
||||
struct ServerState {
|
||||
serv_path: PathBuf,
|
||||
}
|
||||
impl ServerState {
|
||||
fn new(serv_path: PathBuf) -> Self {
|
||||
Self { serv_path }
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
use thiserror::Error as ThisError;
|
||||
|
||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum Error {
|
||||
/// Used when errors need to propogate but are too unique to be typed
|
||||
#[error("{0}")]
|
||||
Unique(String),
|
||||
|
||||
#[error("I/O Error: {0}")]
|
||||
IO(#[from] std::io::Error),
|
||||
|
||||
#[error("Failed to write error")]
|
||||
FailedToWrite,
|
||||
|
||||
#[error("Failed to write error")]
|
||||
CargoError(String),
|
||||
|
||||
#[error(transparent)]
|
||||
Other(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
impl From<&str> for Error {
|
||||
fn from(s: &str) -> Self {
|
||||
Error::Unique(s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Error {
|
||||
fn from(s: String) -> Self {
|
||||
Error::Unique(s)
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
pub mod builder;
|
||||
pub mod cargo;
|
||||
pub mod cli;
|
||||
pub mod config;
|
||||
pub mod develop;
|
||||
pub mod error;
|
||||
pub mod logging;
|
||||
pub mod watch;
|
|
@ -1,49 +0,0 @@
|
|||
use fern::colors::{Color, ColoredLevelConfig};
|
||||
use log::debug;
|
||||
|
||||
pub fn set_up_logging() {
|
||||
// configure colors for the whole line
|
||||
let colors_line = ColoredLevelConfig::new()
|
||||
.error(Color::Red)
|
||||
.warn(Color::Yellow)
|
||||
// we actually don't need to specify the color for debug and info, they are white by default
|
||||
.info(Color::White)
|
||||
.debug(Color::White)
|
||||
// depending on the terminals color scheme, this is the same as the background color
|
||||
.trace(Color::BrightBlack);
|
||||
|
||||
// configure colors for the name of the level.
|
||||
// since almost all of them are the same as the color for the whole line, we
|
||||
// just clone `colors_line` and overwrite our changes
|
||||
let colors_level = colors_line.clone().info(Color::Green);
|
||||
// here we set up our fern Dispatch
|
||||
fern::Dispatch::new()
|
||||
.format(move |out, message, record| {
|
||||
out.finish(format_args!(
|
||||
"{color_line}[{level}{color_line}] {message}\x1B[0m",
|
||||
color_line = format_args!(
|
||||
"\x1B[{}m",
|
||||
colors_line.get_color(&record.level()).to_fg_str()
|
||||
),
|
||||
level = colors_level.color(record.level()),
|
||||
message = message,
|
||||
));
|
||||
})
|
||||
// set the default log level. to filter out verbose log messages from dependencies, set
|
||||
// this to Warn and overwrite the log level for your crate.
|
||||
.level(log::LevelFilter::Info)
|
||||
// .level(log::LevelFilter::Warn)
|
||||
// change log levels for individual modules. Note: This looks for the record's target
|
||||
// field which defaults to the module path but can be overwritten with the `target`
|
||||
// parameter:
|
||||
// `info!(target="special_target", "This log message is about special_target");`
|
||||
// .level_for("dioxus", log::LevelFilter::Debug)
|
||||
// .level_for("dioxus", log::LevelFilter::Info)
|
||||
// .level_for("pretty_colored", log::LevelFilter::Trace)
|
||||
// output to stdout
|
||||
.chain(std::io::stdout())
|
||||
.apply()
|
||||
.unwrap();
|
||||
|
||||
debug!("finished setting up logging! yay!");
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
use diopack::cli::{LaunchCommand, LaunchOptions};
|
||||
use dioxus_cli as diopack;
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() -> diopack::error::Result<()> {
|
||||
diopack::logging::set_up_logging();
|
||||
|
||||
let opts: LaunchOptions = argh::from_env();
|
||||
let mut config = diopack::config::Config::new()?;
|
||||
|
||||
match opts.command {
|
||||
LaunchCommand::Build(options) => {
|
||||
config.with_build_options(&options);
|
||||
diopack::builder::build(&config, &(options.into()))?;
|
||||
}
|
||||
|
||||
LaunchCommand::Develop(options) => {
|
||||
config.with_develop_options(&options);
|
||||
diopack::develop::start(&config, &(options.into())).await?;
|
||||
}
|
||||
|
||||
_ => {
|
||||
todo!("Command not currently implemented");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
pub struct Watcher {}
|
||||
|
||||
impl Watcher {
|
||||
// Spawns a new notify instance that alerts us of changes
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
/// Subsribe to the watcher
|
||||
pub fn subscribe() {}
|
||||
}
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
use crate::innerlude::Context;
|
||||
|
||||
use crate::innerlude::*;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
ops::{Deref, DerefMut},
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "dioxus-inputs"
|
||||
version = "0.0.0"
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
|
@ -1,28 +0,0 @@
|
|||
# Cross-platform controlled inputs
|
||||
|
||||
Dioxus does not include controlled inputs in Dioxus-Core. This would require core integration with HTML that is inherently not cross platform. Instead, this crate exists to provide a bunch of cross-platform input types that abstract over renderer quirks.
|
||||
|
||||
Included is:
|
||||
|
||||
- Button
|
||||
- Checkbox
|
||||
- Color
|
||||
- Date
|
||||
- Datetime-local
|
||||
- Email
|
||||
- File
|
||||
- Hidden
|
||||
- Image
|
||||
- Month
|
||||
- Number
|
||||
- Password
|
||||
- Radio
|
||||
- Range
|
||||
- Reset
|
||||
- Search
|
||||
- Submit
|
||||
- Tel
|
||||
- Text
|
||||
- Time
|
||||
- Url
|
||||
- Week
|
|
@ -1,7 +0,0 @@
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
}
|
1
packages/liveview/.gitignore
vendored
1
packages/liveview/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
.vscode/
|
|
@ -1,39 +0,0 @@
|
|||
[package]
|
||||
name = "dioxus-livehost"
|
||||
version = "0.0.0"
|
||||
authors = ["Jonathan Kelley <jkelleyrtp@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
dioxus-core = { path = "../core", version = "0.1.2" }
|
||||
dioxus-web = { path = "../web" }
|
||||
|
||||
|
||||
serde = { version = "1", features = ['derive'] }
|
||||
tide = "0.16.0"
|
||||
tide-websockets = "0.3.0"
|
||||
async-std = { version = "1.8.0", features = ["attributes"] }
|
||||
log = "0.4"
|
||||
fern = { version = "0.6.0", features = ["colored"] }
|
||||
async-channel = "1.5.1"
|
||||
futures-lite = "1.11.2"
|
||||
anyhow = "1.0.35"
|
||||
|
||||
|
||||
js-sys = { version = "0.3", optional = true }
|
||||
wasm-bindgen = { version = "0.2.71", optional = true }
|
||||
lazy_static = { version = "1.4.0", optional = true }
|
||||
wasm-bindgen-futures = { version = "0.4.20", optional = true }
|
||||
|
||||
|
||||
serde_millis = "0.1"
|
||||
serde_json = "1"
|
||||
strum = { version = "0.20", features = ["derive"] }
|
||||
|
||||
|
||||
[features]
|
||||
default = ["client", "server"]
|
||||
server = []
|
||||
client = []
|
|
@ -1,13 +0,0 @@
|
|||
# Livehost
|
||||
|
||||
Stream events from a server to a client.
|
||||
|
||||
This crate provides drivers for Actix, Warp, and Tide to run coupled frontend and backend.
|
||||
|
||||
This comes in the form of two approaches:
|
||||
|
||||
- tight coupling: frontend and backend are locked together
|
||||
- loose coupling: hooks subscribe a component to a server using the suspense mechanism
|
||||
|
||||
Tight coupling is basically an implmentation of loose coupling where **all** events move through the backend connection. This coupling option has higher latency but is very simple to deploy. We use this approach for dioxus-webview where latency is minimal (hosted locally) and we want builds to be simple - no need to manually bundle a custom frontend because everything is server rendered.
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
pub fn main() {
|
||||
#[cfg(feature = "client")]
|
||||
wasm_bindgen_futures::spawn_local(async { client::app().await.unwrap() });
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
async_std::task::block_on(async { server::app().await.expect("") });
|
||||
}
|
||||
|
||||
/// ===============================
|
||||
/// Common code (shared types)
|
||||
/// ===============================
|
||||
#[derive(PartialEq, strum::EnumIter, strum::Display, strum::AsRefStr, strum::EnumString)]
|
||||
pub enum SelectedStream {
|
||||
Football,
|
||||
Hockey,
|
||||
Socker,
|
||||
}
|
||||
|
||||
/// Client-specific code
|
||||
#[cfg(feature = "client")]
|
||||
mod client {
|
||||
use super::*;
|
||||
use dioxus_core::prelude::*;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
pub async fn app() -> anyhow::Result<()> {
|
||||
Ok(dioxus_web::WebsysRenderer::start(APP).await)
|
||||
}
|
||||
|
||||
static APP: FC<()> = |cx| {
|
||||
todo!()
|
||||
// let (selected_stream, set_stream) = use_state(cx, || SelectedStream::Football);
|
||||
|
||||
// let opts = SelectedStream::iter().map(|name| rsx! { option { "{name}", value: "{name}" } });
|
||||
|
||||
// cx.render(rsx! {
|
||||
// div {
|
||||
// h1 { "Tide basic CRUD app" }
|
||||
// h2 { "Chosen stream: {selected_stream}" }
|
||||
// select {
|
||||
// value: {selected_stream.as_ref()}
|
||||
// "{selected_stream}"
|
||||
// {opts}
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
};
|
||||
}
|
||||
|
||||
/// Server-specific code
|
||||
#[cfg(feature = "server")]
|
||||
mod server {
|
||||
use async_std::sync::RwLock;
|
||||
pub use log::info;
|
||||
use std::sync::Arc;
|
||||
use tide::Request;
|
||||
use tide_websockets::{Message, WebSocket, WebSocketConnection};
|
||||
|
||||
use crate::SelectedStream;
|
||||
|
||||
// type ServerRequest = Request<Arc<RwLock<()>>>;
|
||||
type ServerRequest = Request<()>;
|
||||
// type ServerRequest = Request<Arc<RwLock<ServerState>>>;
|
||||
|
||||
static CLIENT_PATH: &'static str = "";
|
||||
|
||||
pub async fn app() -> anyhow::Result<()> {
|
||||
let mut app = tide::new();
|
||||
|
||||
app.at("")
|
||||
.serve_dir(format!("{}/pkg", CLIENT_PATH))
|
||||
.expect("Cannot serve directory");
|
||||
|
||||
app.at("/updates").get(WebSocket::new(socket_handler));
|
||||
|
||||
let addr = "0.0.0.0:9001";
|
||||
log::info!("Congrats! Server is up and running at http://{}", addr);
|
||||
app.listen(addr).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn socket_handler(
|
||||
request: ServerRequest,
|
||||
stream: WebSocketConnection,
|
||||
) -> tide::Result<()> {
|
||||
// clone the receiver channel
|
||||
// subscribe to any updates
|
||||
// let receiver = request.state().read().await.receiver.clone();
|
||||
// while let Ok(evt) = receiver.recv().await {
|
||||
// let response_msg = serde_json::to_string(&evt)?;
|
||||
// stream.send_string(response_msg).await?;
|
||||
// }
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
#[derive(PartialEq, Props)]
|
||||
struct SreamListProps {
|
||||
selected_stream: SelectedStream,
|
||||
}
|
||||
|
||||
static STREAM_LIST: FC<SreamListProps> = |cx| {
|
||||
//
|
||||
let g = match cx.selected_stream {
|
||||
SelectedStream::Football => cx.render(rsx! {
|
||||
li {
|
||||
"watch football!"
|
||||
}
|
||||
}),
|
||||
SelectedStream::Hockey => cx.render(rsx! {
|
||||
li {
|
||||
"watch football!"
|
||||
}
|
||||
}),
|
||||
SelectedStream::Socker => cx.render(rsx! {
|
||||
li {
|
||||
"watch football!"
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
|
@ -1,182 +0,0 @@
|
|||
pub fn main() {
|
||||
#[cfg(feature = "client")]
|
||||
wasm_bindgen_futures::spawn_local(async { client::app().await.unwrap() });
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
async_std::task::block_on(async { server::app().await.expect("") });
|
||||
}
|
||||
|
||||
/// ===============================
|
||||
/// Common code (shared types)
|
||||
/// ===============================
|
||||
#[derive(PartialEq, strum::EnumIter, strum::Display, strum::AsRefStr, strum::EnumString)]
|
||||
pub enum SelectedStream {
|
||||
Football,
|
||||
Hockey,
|
||||
Socker,
|
||||
}
|
||||
|
||||
/// Client-specific code
|
||||
#[cfg(feature = "client")]
|
||||
mod client {
|
||||
use super::*;
|
||||
use dioxus_core::prelude::*;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
pub async fn app() -> anyhow::Result<()> {
|
||||
Ok(dioxus_web::WebsysRenderer::start(APP).await)
|
||||
}
|
||||
|
||||
static APP: FC<()> = |cx| {
|
||||
todo!()
|
||||
// let (selected_stream, set_stream) = use_state(cx, || SelectedStream::Football);
|
||||
|
||||
// let opts = SelectedStream::iter().map(|name| rsx! { option { "{name}", value: "{name}" } });
|
||||
|
||||
// cx.render(rsx! {
|
||||
// div {
|
||||
// h1 { "Tide basic CRUD app" }
|
||||
// h2 { "Chosen stream: {selected_stream}" }
|
||||
// select {
|
||||
// value: {selected_stream.as_ref()}
|
||||
// "{selected_stream}"
|
||||
// {opts}
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
};
|
||||
}
|
||||
|
||||
/// Server-specific code
|
||||
#[cfg(feature = "server")]
|
||||
mod server {
|
||||
use async_std::sync::RwLock;
|
||||
pub use log::info;
|
||||
use std::sync::Arc;
|
||||
use tide::Request;
|
||||
use tide_websockets::{Message, WebSocket, WebSocketConnection};
|
||||
|
||||
use crate::SelectedStream;
|
||||
|
||||
// type ServerRequest = Request<Arc<RwLock<()>>>;
|
||||
type ServerRequest = Request<()>;
|
||||
// type ServerRequest = Request<Arc<RwLock<ServerState>>>;
|
||||
|
||||
static CLIENT_PATH: &'static str = "";
|
||||
|
||||
pub async fn app() -> anyhow::Result<()> {
|
||||
let mut app = tide::new();
|
||||
|
||||
app.at("")
|
||||
.serve_dir(format!("{}/pkg", CLIENT_PATH))
|
||||
.expect("Cannot serve directory");
|
||||
|
||||
app.at("/updates").get(WebSocket::new(socket_handler));
|
||||
|
||||
let addr = "0.0.0.0:9001";
|
||||
log::info!("Congrats! Server is up and running at http://{}", addr);
|
||||
app.listen(addr).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn socket_handler(
|
||||
request: ServerRequest,
|
||||
stream: WebSocketConnection,
|
||||
) -> tide::Result<()> {
|
||||
// clone the receiver channel
|
||||
// subscribe to any updates
|
||||
// let receiver = request.state().read().await.receiver.clone();
|
||||
// while let Ok(evt) = receiver.recv().await {
|
||||
// let response_msg = serde_json::to_string(&evt)?;
|
||||
// stream.send_string(response_msg).await?;
|
||||
// }
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
#[derive(PartialEq, Props)]
|
||||
struct SreamListProps {
|
||||
selected_stream: SelectedStream,
|
||||
}
|
||||
|
||||
static STREAM_LIST: FC<SreamListProps> = |cx| {
|
||||
//
|
||||
match cx.selected_stream {
|
||||
SelectedStream::Football => cx.render(rsx! {
|
||||
li {
|
||||
"watch football!"
|
||||
}
|
||||
}),
|
||||
|
||||
_ => unimplemented!()
|
||||
// .render(cx),
|
||||
// SelectedStream::Hockey => rsx! {
|
||||
// li {
|
||||
// "watch football!"
|
||||
// }
|
||||
// }
|
||||
// .render(cx),
|
||||
// SelectedStream::Socker => rsx! {
|
||||
// li {
|
||||
// "watch football!"
|
||||
// }
|
||||
// }
|
||||
// .render(cx),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mod ergorsx {
|
||||
|
||||
// struct Ncx {}
|
||||
|
||||
// struct VVNode {}
|
||||
// struct DTree {
|
||||
// // struct DTree<F: Fn(&Ncx) -> VVNode> {
|
||||
// caller: F,
|
||||
// }
|
||||
// impl<F: Fn(&Ncx) -> VVNode> DTree<F> {
|
||||
// fn new(f: F) -> Self {
|
||||
// Self { caller: f }
|
||||
// }
|
||||
// }
|
||||
|
||||
// trait Renderable {
|
||||
// fn render(self, nodecx: &Ncx) -> VVNode;
|
||||
// }
|
||||
|
||||
// impl<F: Fn(&Ncx) -> VVNode> Renderable for DTree<F> {
|
||||
// fn render(self, nodecx: &Ncx) -> VVNode {
|
||||
// (self.caller)(nodecx)
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn test() {
|
||||
// let t = 123;
|
||||
// let r = match t {
|
||||
// 123 => DTree::new(|f| VVNode {}).render(cx),
|
||||
// 456 => DTree::new(|f| VVNode {}).render(cx),
|
||||
// 789 => DTree::new(|f| VVNode {}).render(cx),
|
||||
// _ => unreachable!(),
|
||||
// };
|
||||
// }
|
||||
|
||||
// fn example() {
|
||||
// rsx! {
|
||||
// div {
|
||||
|
||||
// }
|
||||
// }.render(cx)
|
||||
// }
|
||||
|
||||
// fn example() {
|
||||
// cx.render(rsx!{
|
||||
// div {
|
||||
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
}
|
|
@ -1,294 +0,0 @@
|
|||
<!-- a js-only interpreter for the dioxus patch stream :) -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
|
||||
<meta charset="UTF-8" />
|
||||
<link
|
||||
href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<div></div>
|
||||
</body>
|
||||
<script>
|
||||
class Interpreter {
|
||||
constructor(root) {
|
||||
this.stack = [root];
|
||||
}
|
||||
|
||||
top() {
|
||||
return this.stack[this.stack.length - 1];
|
||||
}
|
||||
|
||||
pop() {
|
||||
return this.stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
class OPTABLE {
|
||||
// 0
|
||||
SetText(edit, interp) {
|
||||
interp.top(interp.stack).textContent = edit.text;
|
||||
}
|
||||
// 1
|
||||
RemoveSelfAndNextSiblings(edit) {
|
||||
const node = interp.pop();
|
||||
let sibling = node.nextSibling;
|
||||
while (sibling) {
|
||||
const temp = sibling.nextSibling;
|
||||
sibling.remove();
|
||||
sibling = temp;
|
||||
}
|
||||
node.remove();
|
||||
}
|
||||
|
||||
// 2
|
||||
ReplaceWith(edit, interp) {
|
||||
const newNode = interp.pop();
|
||||
const oldNode = interp.pop();
|
||||
oldNode.replaceWith(newNode);
|
||||
interp.stack.push(newNode);
|
||||
}
|
||||
|
||||
// 3
|
||||
SetAttribute(edit, interp) {
|
||||
const name = edit.name;
|
||||
const value = edit.value;
|
||||
const node = interp.top(interp.stack);
|
||||
node.setAttribute(name, value);
|
||||
|
||||
// Some attributes are "volatile" and don't work through `setAttribute`.
|
||||
if ((name === "value", interp)) {
|
||||
node.value = value;
|
||||
}
|
||||
if ((name === "checked", interp)) {
|
||||
node.checked = true;
|
||||
}
|
||||
if ((name === "selected", interp)) {
|
||||
node.selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 4
|
||||
RemoveAttribute(edit, interp) {
|
||||
const name = edit.name;
|
||||
const node = interp.top(interp.stack);
|
||||
node.removeAttribute(name);
|
||||
|
||||
// Some attributes are "volatile" and don't work through `removeAttribute`.
|
||||
if ((name === "value", interp)) {
|
||||
node.value = null;
|
||||
}
|
||||
if ((name === "checked", interp)) {
|
||||
node.checked = false;
|
||||
}
|
||||
if ((name === "selected", interp)) {
|
||||
node.selected = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 5
|
||||
PushReverseChild(edit, interp) {
|
||||
const n = edit.n;
|
||||
const parent = interp.top(interp.stack);
|
||||
const children = parent.childNodes;
|
||||
const child = children[children.length - n - 1];
|
||||
interp.stack.push(child);
|
||||
}
|
||||
|
||||
// 6
|
||||
PopPushChild(edit, interp) {
|
||||
const n = edit.n;
|
||||
interp.pop();
|
||||
const parent = interp.top(interp.stack);
|
||||
const children = parent.childNodes;
|
||||
const child = children[n];
|
||||
interp.stack.push(child);
|
||||
}
|
||||
|
||||
// 7
|
||||
Pop(edit, interp) {
|
||||
interp.pop();
|
||||
}
|
||||
|
||||
// 8
|
||||
AppendChild(edit, interp) {
|
||||
console.log(interp.stack);
|
||||
const child = interp.pop();
|
||||
console.log(interp.stack);
|
||||
interp.top().appendChild(child);
|
||||
}
|
||||
|
||||
// 9
|
||||
CreateTextNode(edit, interp) {
|
||||
// interp.stack.push(document.createTextNode("asd"));
|
||||
console.log(interp.stack);
|
||||
|
||||
interp.stack.push(document.createTextNode(edit.text));
|
||||
console.log(interp.stack);
|
||||
}
|
||||
|
||||
// 10
|
||||
CreateElement(edit, interp) {
|
||||
const tagName = edit.tag_name;
|
||||
interp.stack.push(document.createElement(tagName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 11
|
||||
NewEventListener(edit, interp) {
|
||||
// todo!
|
||||
const eventId = mem32[i++];
|
||||
const eventType = interp.getCachedString(eventId);
|
||||
const a = mem32[i++];
|
||||
const b = mem32[i++];
|
||||
const el = interp.top(interp.stack);
|
||||
el.addEventListener(eventType, interp.eventHandler);
|
||||
el[`dodrio-a-${eventType}`] = a;
|
||||
el[`dodrio-b-${eventType}`] = b;
|
||||
}
|
||||
|
||||
// 12
|
||||
UpdateEventListener(edit, interp) {
|
||||
// todo!
|
||||
const eventId = mem32[i++];
|
||||
const eventType = interp.getCachedString(eventId);
|
||||
const el = interp.top(interp.stack);
|
||||
el[`dodrio-a-${eventType}`] = mem32[i++];
|
||||
el[`dodrio-b-${eventType}`] = mem32[i++];
|
||||
}
|
||||
|
||||
// 13
|
||||
RemoveEventListener(edit, interp) {
|
||||
// todo!
|
||||
const eventId = mem32[i++];
|
||||
const eventType = interp.getCachedString(eventId);
|
||||
const el = interp.top(interp.stack);
|
||||
el.removeEventListener(eventType, interp.eventHandler);
|
||||
}
|
||||
|
||||
// 14
|
||||
AddCachedString(edit, interp) {
|
||||
// todo!
|
||||
const pointer = mem32[i++];
|
||||
const length = mem32[i++];
|
||||
const id = mem32[i++];
|
||||
const str = string(mem8, pointer, length);
|
||||
interp.addCachedString(str, id);
|
||||
}
|
||||
|
||||
// 15
|
||||
DropCachedString(edit, interp) {
|
||||
// todo!
|
||||
const id = mem32[i++];
|
||||
interp.dropCachedString(id);
|
||||
}
|
||||
|
||||
// 16
|
||||
CreateElementNs(edit, interp) {
|
||||
// const tagNameId = mem32[i++];
|
||||
// const tagName = interp.getCachedString(tagNameId);
|
||||
// const nsId = mem32[i++];
|
||||
// const ns = interp.getCachedString(nsId);
|
||||
interp.stack.push(document.createElementNS(edit.ns, edit.tag_name));
|
||||
}
|
||||
|
||||
// 17
|
||||
SaveChildrenToTemporaries(edit, interp) {
|
||||
// let temp = mem32[i++];
|
||||
// const start = mem32[i++];
|
||||
// const end = mem32[i++];
|
||||
let temp = edit.temp;
|
||||
const start = edit.start;
|
||||
const end = edit.end;
|
||||
const parent = interp.top(interp.stack);
|
||||
const children = parent.childNodes;
|
||||
for (let i = start; i < end; i++, interp) {
|
||||
interp.temporaries[temp++] = children[i];
|
||||
}
|
||||
}
|
||||
|
||||
// 18
|
||||
PushChild(edit, interp) {
|
||||
const parent = interp.top(interp.stack);
|
||||
// const n = mem32[i++];
|
||||
const n = edit.n;
|
||||
const child = parent.childNodes[n];
|
||||
interp.stack.push(child);
|
||||
}
|
||||
|
||||
// 19
|
||||
PushTemporary(edit, interp) {
|
||||
// const temp = mem32[i++];
|
||||
const temp = edit.temp;
|
||||
interp.stack.push(interp.temporaries[temp]);
|
||||
}
|
||||
|
||||
// 20
|
||||
InsertBefore(edit, interp) {
|
||||
const before = interp.pop();
|
||||
const after = interp.pop();
|
||||
after.parentNode.insertBefore(before, after);
|
||||
interp.stack.push(before);
|
||||
}
|
||||
|
||||
// 21
|
||||
PopPushReverseChild(edit, interp) {
|
||||
// const n = mem32[i++];
|
||||
const n = edit.n;
|
||||
interp.pop();
|
||||
const parent = interp.top(interp.stack);
|
||||
const children = parent.childNodes;
|
||||
const child = children[children.length - n - 1];
|
||||
interp.stack.push(child);
|
||||
}
|
||||
|
||||
// 22
|
||||
RemoveChild(edit, interp) {
|
||||
// const n = mem32[i++];
|
||||
const n = edit.n;
|
||||
const parent = interp.top(interp.stack);
|
||||
const child = parent.childNodes[n];
|
||||
child.remove();
|
||||
}
|
||||
|
||||
// 23
|
||||
SetClass(edit, interp) {
|
||||
// const classId = mem32[i++];
|
||||
const className = edit.class_name;
|
||||
interp.top(interp.stack).className = className;
|
||||
}
|
||||
|
||||
// 24
|
||||
SaveTemplate(edit, interp) {
|
||||
const id = mem32[i++];
|
||||
const template = interp.top(interp.stack);
|
||||
interp.saveTemplate(id, template.cloneNode(true));
|
||||
}
|
||||
|
||||
// 25
|
||||
PushTemplate(edit, interp) {
|
||||
const id = mem32[i++];
|
||||
const template = interp.getTemplate(id);
|
||||
interp.stack.push(template.cloneNode(true));
|
||||
}
|
||||
}
|
||||
|
||||
const op_table = new OPTABLE();
|
||||
const interpreter = new Interpreter(window.document.body);
|
||||
|
||||
function EditListReceived(rawEditList) {
|
||||
let editList = JSON.parse(rawEditList);
|
||||
console.warn("hnelllo");
|
||||
editList.forEach(function (edit, index) {
|
||||
console.log(edit);
|
||||
op_table[edit.type](edit, interpreter);
|
||||
});
|
||||
}
|
||||
|
||||
external.invoke("initiate");
|
||||
</script>
|
||||
</html>
|
|
@ -1 +0,0 @@
|
|||
//! Request handler for actix
|
|
@ -1 +0,0 @@
|
|||
//! Request handler for rocket
|
|
@ -1 +0,0 @@
|
|||
//! Request handler for tide
|
|
@ -1 +0,0 @@
|
|||
//! Request handler for warp
|
|
@ -1,10 +0,0 @@
|
|||
mod handlers {
|
||||
|
||||
pub mod h_actix;
|
||||
|
||||
pub mod h_rocket;
|
||||
|
||||
pub mod h_tide;
|
||||
|
||||
pub mod h_warp;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
[package]
|
||||
name = "dioxus-router"
|
||||
version = "0.0.0"
|
||||
authors = ["Jonathan Kelley <jkelleyrtp@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
|
@ -1,40 +0,0 @@
|
|||
# Router hook for Dioxus apps
|
||||
|
||||
Dioxus-router provides a use_router hook that returns a different value depending on the route.
|
||||
The router is generic over any value, however it makes sense to return a different set of VNodes
|
||||
and feed them into the App's return VNodes.
|
||||
|
||||
Using the router should feel similar to tide's routing framework where an "address" book is assembled at the head of the app.
|
||||
|
||||
Here's an example of how to use the router hook:
|
||||
|
||||
```rust
|
||||
static App: FC<()> = |cx| {
|
||||
|
||||
// Route returns the associated VNodes
|
||||
// This hook re-fires when the route changes
|
||||
let route = use_router(cx, |router| {
|
||||
router.at("/").get(|path| {
|
||||
rsx!{ <LandingPage /> }
|
||||
});
|
||||
router.at("/shoes/:id").get(|path| {
|
||||
let id: Uuid = path.parse().unwrap();
|
||||
rsx!{ <ShoesPage id=id /> }
|
||||
});
|
||||
router.at("/pants/:id").get(|path| {
|
||||
let id: Uuid = path.parse().unwrap();
|
||||
rsx!{ <PantsPage id=id /> }
|
||||
});
|
||||
});
|
||||
|
||||
cx.render(rsx!{
|
||||
div {
|
||||
Navbar {}
|
||||
{route}
|
||||
Footer {}
|
||||
}
|
||||
})
|
||||
};
|
||||
```
|
||||
|
||||
Currently, the router is only supported in a web environment, but we plan to add 1st-party support via the context API when new renderers are available.
|
|
@ -1,7 +0,0 @@
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
}
|
|
@ -218,10 +218,3 @@ pub mod testing {
|
|||
}
|
||||
#[cfg(feature = "atoms")]
|
||||
pub mod atoms {}
|
||||
|
||||
// #[cfg(feature = "desktop")]
|
||||
pub mod webview {
|
||||
//! A webview based renderer for building desktop applications with Dioxus
|
||||
use dioxus_core::prelude::{Properties, FC};
|
||||
pub fn launch<P: Properties>(f: FC<P>) {}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue