Color picker? lmao

This commit is contained in:
Aode (lion) 2021-12-29 11:24:13 -06:00
commit c68671ea3d
7 changed files with 1838 additions and 0 deletions

2
.cargo/config Normal file
View file

@ -0,0 +1,2 @@
[build]
rustflags = ["--cfg", "tokio_unstable"]

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

1583
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

22
Cargo.toml Normal file
View 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
View 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
View 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
View 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)
}
}