generated from ElnuDev/rust-project
Compare commits
No commits in common. "09d93fac79c71b295784679f2f150783fcfcee8e" and "d488b99765fd103816f5849364caab43c9d6d11e" have entirely different histories.
09d93fac79
...
d488b99765
7 changed files with 46 additions and 141 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,2 @@
|
||||||
/target
|
/target
|
||||||
.direnv
|
.direnv
|
||||||
dist
|
|
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -393,8 +393,6 @@ dependencies = [
|
||||||
"strum",
|
"strum",
|
||||||
"strum_macros",
|
"strum_macros",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
|
||||||
"web-sys",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
34
dist/index.html
vendored
Normal file
34
dist/index.html
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<!DOCTYPE html><html lang="en"><head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>dyesub-tool</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>(function () {
|
||||||
|
var protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||||
|
var url = protocol + '//' + window.location.host + '/_trunk/ws';
|
||||||
|
var poll_interval = 5000;
|
||||||
|
var reload_upon_connect = () => {
|
||||||
|
window.setTimeout(
|
||||||
|
() => {
|
||||||
|
// when we successfully reconnect, we'll force a
|
||||||
|
// reload (since we presumably lost connection to
|
||||||
|
// trunk due to it being killed, so it will have
|
||||||
|
// rebuilt on restart)
|
||||||
|
var ws = new WebSocket(url);
|
||||||
|
ws.onopen = () => window.location.reload();
|
||||||
|
ws.onclose = reload_upon_connect;
|
||||||
|
},
|
||||||
|
poll_interval);
|
||||||
|
};
|
||||||
|
|
||||||
|
var ws = new WebSocket(url);
|
||||||
|
ws.onmessage = (ev) => {
|
||||||
|
const msg = JSON.parse(ev.data);
|
||||||
|
if (msg.reload) {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ws.onclose = reload_upon_connect;
|
||||||
|
})()
|
||||||
|
</script></body></html>
|
3
dyesub-tool/.gitignore
vendored
Normal file
3
dyesub-tool/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
layout.json
|
||||||
|
output.svg
|
||||||
|
dist
|
|
@ -14,5 +14,3 @@ serde_json = "1.0.105"
|
||||||
strum = "0.25.0"
|
strum = "0.25.0"
|
||||||
strum_macros = "0.25.2"
|
strum_macros = "0.25.2"
|
||||||
wasm-bindgen = "0.2.87"
|
wasm-bindgen = "0.2.87"
|
||||||
wasm-bindgen-futures = "0.4.37"
|
|
||||||
web-sys = { version = "0.3.64", features = ["FileList", "Blob"] }
|
|
||||||
|
|
|
@ -1,145 +1,18 @@
|
||||||
#![feature(async_closure)]
|
|
||||||
|
|
||||||
mod render;
|
mod render;
|
||||||
pub mod svg;
|
pub mod svg;
|
||||||
|
|
||||||
use leptos::{*, ev::SubmitEvent, html::Input};
|
use leptos::*;
|
||||||
use wasm_bindgen::{JsCast, JsValue};
|
use wasm_bindgen::JsCast;
|
||||||
use web_sys::File;
|
|
||||||
use strum_macros::IntoStaticStr;
|
|
||||||
use derive_more::From;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct ResultMessageData {
|
|
||||||
title: String,
|
|
||||||
message: View,
|
|
||||||
colorway: Colorway,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Clone, Copy, IntoStaticStr)]
|
|
||||||
enum Colorway {
|
|
||||||
#[default]
|
|
||||||
#[strum(serialize = "plain")]
|
|
||||||
Plain,
|
|
||||||
#[strum(serialize = "info")]
|
|
||||||
Info,
|
|
||||||
#[strum(serialize = "ok")]
|
|
||||||
Ok,
|
|
||||||
#[strum(serialize = "warn")]
|
|
||||||
Warn,
|
|
||||||
#[strum(serialize = "bad")]
|
|
||||||
Bad,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[component]
|
|
||||||
fn ResultMessage(cx: Scope, message: ReadSignal<Option<ResultMessageData>>) -> impl IntoView {
|
|
||||||
view! { cx,
|
|
||||||
<Show when=move || message().is_some() fallback=move |_| {}>
|
|
||||||
<div class=move || {
|
|
||||||
let colorway_str: &str = message().unwrap().colorway.into();
|
|
||||||
colorway_str.to_owned() + " box"
|
|
||||||
}>
|
|
||||||
<h3>{move || message().unwrap().title}</h3>
|
|
||||||
<p>{move || message().unwrap().message}</p>
|
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(From, IntoStaticStr)]
|
|
||||||
enum ReadKleError {
|
|
||||||
#[strum(serialize = "No file chosen")]
|
|
||||||
NoFile,
|
|
||||||
#[strum(serialize = "Failed to open file")]
|
|
||||||
TextAwait(JsValue),
|
|
||||||
#[strum(serialize = "Failed to parse file to string")]
|
|
||||||
ParseToString,
|
|
||||||
#[strum(serialize = "Failed to parse KLE JSON")]
|
|
||||||
Serde(serde_json::Error)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToString for ReadKleError {
|
|
||||||
fn to_string(&self) -> String {
|
|
||||||
if let Self::TextAwait(error) = self {
|
|
||||||
if let Some(error) = error.as_string() {
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
} else if let Self::Serde(error) = self {
|
|
||||||
return error.to_string();
|
|
||||||
}
|
|
||||||
"".to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn read_kle_from_file(file: &ReadSignal<Option<File>>) -> Result<kle_serial::Keyboard, ReadKleError> {
|
|
||||||
let file = match file() {
|
|
||||||
Some(file) => file,
|
|
||||||
None => return Err(ReadKleError::NoFile),
|
|
||||||
};
|
|
||||||
let file_contents = match wasm_bindgen_futures::JsFuture::from(file.text()).await?.as_string() {
|
|
||||||
Some(contents) => contents,
|
|
||||||
None => return Err(ReadKleError::ParseToString),
|
|
||||||
};
|
|
||||||
let keyboard = serde_json::from_str(&file_contents)?;
|
|
||||||
Ok(keyboard)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[component]
|
|
||||||
fn KeyboardFromFile(cx: Scope, set_keyboard: WriteSignal<Option<kle_serial::Keyboard>>) -> impl IntoView {
|
|
||||||
let file_input = create_node_ref::<Input>(cx);
|
|
||||||
let (file, set_file) = create_signal(cx, Option::<File>::None);
|
|
||||||
let (result_message, set_result_message) = create_signal(cx, Option::<ResultMessageData>::None);
|
|
||||||
let on_submit = move |e: SubmitEvent| {
|
|
||||||
e.prevent_default();
|
|
||||||
spawn_local(async move {
|
|
||||||
match read_kle_from_file(&file).await {
|
|
||||||
Ok(keyboard) => {
|
|
||||||
set_result_message(Some(ResultMessageData {
|
|
||||||
title: "Success".to_owned(),
|
|
||||||
message: view! { cx,
|
|
||||||
"Loaded KLE layout "<b>{&keyboard.metadata.name}</b>" successfully!"
|
|
||||||
}.into_view(cx),
|
|
||||||
colorway: Colorway::Ok,
|
|
||||||
}));
|
|
||||||
set_keyboard(Some(keyboard));
|
|
||||||
},
|
|
||||||
Err(err) => set_result_message(Some(ResultMessageData {
|
|
||||||
message: view! { cx,
|
|
||||||
{
|
|
||||||
err.to_string()
|
|
||||||
}
|
|
||||||
}.into_view(cx),
|
|
||||||
title: <ReadKleError as Into<&str>>::into(err).to_string(),
|
|
||||||
colorway: Colorway::Bad,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
view! { cx,
|
|
||||||
<h3>"Load KLE JSON from file"</h3>
|
|
||||||
<ResultMessage message=result_message />
|
|
||||||
<form class="f-row align-items:center" on:submit=on_submit>
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
accept="application/json"
|
|
||||||
node_ref=file_input
|
|
||||||
on:change=move |_| {
|
|
||||||
set_file(file_input().unwrap().files().map(|files| files.get(0)).flatten());
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Show when=move || file().is_some() fallback=move |_| {}>
|
|
||||||
<input type="submit" value="Load" />
|
|
||||||
</Show>
|
|
||||||
</form>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn App(cx: Scope) -> impl IntoView {
|
fn App(cx: Scope) -> impl IntoView {
|
||||||
let (keyboard, set_keyboard) = create_signal(cx, None);
|
let (count, set_count) = create_signal(cx, 0);
|
||||||
|
|
||||||
view! { cx,
|
view! { cx,
|
||||||
<KeyboardFromFile set_keyboard />
|
<button on:click=move |_| set_count(count.get() + 1)>
|
||||||
|
"Click me: "
|
||||||
|
{move || count.get()}
|
||||||
|
</button>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ Updating `cargoHash`:
|
||||||
version = "0.1.0";
|
version = "0.1.0";
|
||||||
buildAndTestSubdir = "dyesub-tool";
|
buildAndTestSubdir = "dyesub-tool";
|
||||||
buildInputs = with pkgs; [ trunk ];
|
buildInputs = with pkgs; [ trunk ];
|
||||||
cargoHash = "sha256-UcFVv4lqmZW4Nwjps2u2cNU323hk8ezifeGU9dEZ7Ao=";
|
cargoHash = "sha256-Bxc2koMKq8cGFiJtA0qL1geWQls1k2PgtByg7LZwdlc=";
|
||||||
meta = meta // {
|
meta = meta // {
|
||||||
description = "A tool for generating dye sublimation transfer sheet SVGs for Japanese thumb shift 拇指シフト keycaps.";
|
description = "A tool for generating dye sublimation transfer sheet SVGs for Japanese thumb shift 拇指シフト keycaps.";
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue