Color picker? lmao
This commit is contained in:
commit
c68671ea3d
2
.cargo/config
Normal file
2
.cargo/config
Normal file
|
@ -0,0 +1,2 @@
|
|||
[build]
|
||||
rustflags = ["--cfg", "tokio_unstable"]
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
1583
Cargo.lock
generated
Normal file
1583
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
22
Cargo.toml
Normal file
22
Cargo.toml
Normal file
|
@ -0,0 +1,22 @@
|
|||
[package]
|
||||
name = "axum-playground"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
axum = "0.4"
|
||||
axum-liveview = { version = "0.1", git = "https://github.com/davidpdrsn/axum-liveview", branch = "main"}
|
||||
base64 = "0.13"
|
||||
bincode = { version = "2.0.0-alpha.2", features = ["derive"] }
|
||||
console-subscriber = "0.1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
tokio = { version = "1", features = ["full", "tracing"] }
|
||||
tower = "0.4"
|
||||
tower-http = { version = "0.2", features = ["trace"] }
|
||||
tower-service = "0.3"
|
||||
tracing = "0.1"
|
||||
tracing-error = "0.2"
|
||||
tracing-log = "0.1"
|
||||
tracing-subscriber = "0.3"
|
36
src/init_tracing.rs
Normal file
36
src/init_tracing.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use console_subscriber::ConsoleLayer;
|
||||
use tracing::subscriber::set_global_default;
|
||||
use tracing_error::ErrorLayer;
|
||||
use tracing_log::LogTracer;
|
||||
use tracing_subscriber::filter::Targets;
|
||||
use tracing_subscriber::fmt::format::FmtSpan;
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
use tracing_subscriber::Layer;
|
||||
use tracing_subscriber::Registry;
|
||||
|
||||
pub(crate) fn init_tracing() -> Result<(), Box<dyn std::error::Error>> {
|
||||
LogTracer::init()?;
|
||||
|
||||
let targets = std::env::var("RUST_LOG")
|
||||
.unwrap_or_else(|_| "info".into())
|
||||
.parse::<Targets>()?;
|
||||
|
||||
let format_layer = tracing_subscriber::fmt::layer()
|
||||
.with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
|
||||
.with_filter(targets);
|
||||
|
||||
let console_layer = ConsoleLayer::builder()
|
||||
.with_default_env()
|
||||
.event_buffer_capacity(1024 * 1024)
|
||||
.server_addr(([0, 0, 0, 0], 6669))
|
||||
.spawn();
|
||||
|
||||
let subscriber = Registry::default()
|
||||
.with(format_layer)
|
||||
.with(console_layer)
|
||||
.with(ErrorLayer::default());
|
||||
|
||||
set_global_default(subscriber)?;
|
||||
|
||||
Ok(())
|
||||
}
|
138
src/main.rs
Normal file
138
src/main.rs
Normal file
|
@ -0,0 +1,138 @@
|
|||
use axum::response::IntoResponse;
|
||||
use axum::Router;
|
||||
use axum_liveview::associated_data::FormEventValue;
|
||||
use axum_liveview::html;
|
||||
use axum_liveview::pubsub::InProcess;
|
||||
use axum_liveview::EmbedLiveView;
|
||||
use axum_liveview::Html;
|
||||
use axum_liveview::LiveView;
|
||||
use tower::limit::ConcurrencyLimitLayer;
|
||||
use tower::ServiceBuilder;
|
||||
use tower_http::trace::DefaultMakeSpan;
|
||||
use tower_http::trace::TraceLayer;
|
||||
use tracing::Level;
|
||||
|
||||
mod init_tracing;
|
||||
// mod tea;
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize, PartialEq)]
|
||||
enum Msg {
|
||||
Red,
|
||||
Green,
|
||||
Blue,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct State {
|
||||
red: u8,
|
||||
green: u8,
|
||||
blue: u8,
|
||||
}
|
||||
|
||||
fn color_input<M>(title: &str, msg: M) -> Html<M> {
|
||||
html! {
|
||||
<label style="display: flex; justify-content: space-between; padding: 8px; width: 100%;">
|
||||
<span style="font-weight: 500;">{ title }</span>
|
||||
<input type="number" min="0" max="255" axm-input={ msg }/>
|
||||
</label>
|
||||
}
|
||||
}
|
||||
|
||||
#[axum::async_trait]
|
||||
impl LiveView for State {
|
||||
type Message = Msg;
|
||||
|
||||
async fn update(self, msg: Self::Message, data: axum_liveview::AssociatedData) -> Self {
|
||||
let value = if let Some(FormEventValue::String(ref string)) = data.as_form() {
|
||||
if let Ok(value) = string.parse() {
|
||||
value
|
||||
} else {
|
||||
return self;
|
||||
}
|
||||
} else {
|
||||
return self;
|
||||
};
|
||||
|
||||
match msg {
|
||||
Msg::Red => Self { red: value, ..self },
|
||||
Msg::Green => Self {
|
||||
green: value,
|
||||
..self
|
||||
},
|
||||
Msg::Blue => Self {
|
||||
blue: value,
|
||||
..self
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&self) -> Html<Self::Message> {
|
||||
html! {
|
||||
<div style="margin: 0 auto; width: 350px; padding: 16px; background-color: #f5f5f5; border: 1px solid #e5e5e5; border-radius: 4px;">
|
||||
{ color_input("Red", Msg::Red) }
|
||||
{ color_input("Green", Msg::Green) }
|
||||
{ color_input("Blue", Msg::Blue) }
|
||||
<div style={
|
||||
format!(
|
||||
"height: 300px; width: 300px; margin: 15px auto 0; border-radius: 4px; background-color: rgb({}, {}, {})",
|
||||
self.red, self.green, self.blue
|
||||
)
|
||||
}></div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn root(live: EmbedLiveView) -> impl IntoResponse {
|
||||
html! {
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>"Hewwo Mr Obama"</title>
|
||||
{ axum_liveview::assets() }
|
||||
</head>
|
||||
<body style="margin: 0; background-color: #222;">
|
||||
<div style="display: flex; align-items: center; justify-content: space-around; min-height: 100vh;">
|
||||
{live.embed(State::default())}
|
||||
</div>
|
||||
<script>
|
||||
r#"
|
||||
const liveView = new LiveView({ host: 'localhost', port: 3000 });
|
||||
liveView.connect();
|
||||
"#
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
}
|
||||
|
||||
fn construct_router() -> Router {
|
||||
let pubsub = InProcess::new();
|
||||
|
||||
let global_middlewares = ServiceBuilder::new()
|
||||
.layer(axum_liveview::layer(pubsub))
|
||||
.layer(TraceLayer::new_for_http().make_span_with(DefaultMakeSpan::new().level(Level::INFO)))
|
||||
.layer(ConcurrencyLimitLayer::new(64));
|
||||
|
||||
Router::new()
|
||||
.route("/", axum::routing::get(root))
|
||||
.merge(axum_liveview::routes())
|
||||
.layer(global_middlewares)
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
async fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
axum::Server::bind(&([0, 0, 0, 0], 3000).into())
|
||||
.serve(construct_router().into_make_service())
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
init_tracing::init_tracing()?;
|
||||
|
||||
run().await
|
||||
}
|
56
src/tea.rs
Normal file
56
src/tea.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
use std::marker::PhantomData;
|
||||
use std::time::Duration;
|
||||
|
||||
use axum_liveview::Html;
|
||||
use bincode::config::Configuration;
|
||||
use bincode::{Decode, Encode};
|
||||
|
||||
enum CmdInner<Msg> {
|
||||
None,
|
||||
Timer(Duration, Msg),
|
||||
Batch(Vec<Cmd<Msg>>),
|
||||
}
|
||||
|
||||
pub(crate) struct Cmd<Msg>(CmdInner<Msg>);
|
||||
|
||||
pub(crate) struct Tea<Msg, Mdl, View, Update> {
|
||||
view: View,
|
||||
update: Update,
|
||||
model: Mdl,
|
||||
_msg: PhantomData<Msg>,
|
||||
}
|
||||
|
||||
fn encode<Msg>(msg: Msg) -> String
|
||||
where
|
||||
Msg: Encode,
|
||||
{
|
||||
base64::encode(
|
||||
bincode::encode_to_vec(msg, Configuration::standard())
|
||||
.expect("Message type can be encoded"),
|
||||
)
|
||||
}
|
||||
|
||||
fn decode<Msg>(s: &str) -> Result<Msg, Box<dyn std::error::Error>>
|
||||
where
|
||||
Msg: Decode,
|
||||
{
|
||||
let bytes = base64::decode(s)?;
|
||||
let (msg, _) = bincode::decode_from_slice(&bytes, Configuration::standard())?;
|
||||
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
impl<Msg, Mdl, View, Update> Tea<Msg, Mdl, View, Update>
|
||||
where
|
||||
View: Fn(&Mdl) -> Html,
|
||||
Update: Fn(Mdl, Msg) -> (Mdl, Cmd<Msg>),
|
||||
Msg: Decode + Encode,
|
||||
{
|
||||
fn update(mut self, msg: String) -> Self {
|
||||
self
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
(self.view)(&self.model)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue