feat: client side read files

This commit is contained in:
Asger Juul Brunshøj 2025-01-17 00:12:13 +01:00
parent 4daec21e2d
commit a3f1cc1b77
7 changed files with 125 additions and 72 deletions

90
Cargo.lock generated
View File

@ -67,11 +67,12 @@ dependencies = [
[[package]] [[package]]
name = "anstyle-wincon" name = "anstyle-wincon"
version = "3.0.6" version = "3.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"once_cell",
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
@ -119,6 +120,7 @@ dependencies = [
"tracing-subscriber", "tracing-subscriber",
"type-toppings", "type-toppings",
"wasm-bindgen", "wasm-bindgen",
"web-sys",
] ]
[[package]] [[package]]
@ -264,9 +266,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.7.0" version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -1060,9 +1062,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]] [[package]]
name = "leptos" name = "leptos"
version = "0.7.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8a90c679094979aa12927e8e925fe8eead1420d69420b2d8c6540863937ca75" checksum = "21c31c9d022c77702c53e02830d08b28320aca9c0899a19c443096c114623fa5"
dependencies = [ dependencies = [
"any_spawner", "any_spawner",
"base64 0.22.1", "base64 0.22.1",
@ -1099,9 +1101,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_axum" name = "leptos_axum"
version = "0.7.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae4386e955d6ba7c3c8d09583e99044050f6fb9a48b8d4096af948fdb3345434" checksum = "43b613d5784037baee42a11d21bc263adfc1a55e416556a3d5bfe39c7b87fadf"
dependencies = [ dependencies = [
"any_spawner", "any_spawner",
"axum", "axum",
@ -1123,9 +1125,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_config" name = "leptos_config"
version = "0.7.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c712e1ed3283d1acb842cef4cbcce7b2987a347cc1bf7141195e01f92bb8590d" checksum = "5d874993c7664d757677d056c8f46b5cb5365fe622005e1bf26050f4996e7e52"
dependencies = [ dependencies = [
"config", "config",
"regex", "regex",
@ -1136,9 +1138,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_dom" name = "leptos_dom"
version = "0.7.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99803be421344a2184fd5796e1a7645c2090738b2ab5d1a856084816853ec322" checksum = "a462aaeec85bc4ecfb26bf324437b92690bf3add1e30eb29b3acc08b20e8b4cb"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"or_poisoned", "or_poisoned",
@ -1152,9 +1154,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_hot_reload" name = "leptos_hot_reload"
version = "0.7.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92413c6d93a22d8c4e75b2e7da3867af173e8d9ca49ce170b631e7c2766eef48" checksum = "07eb295ad2f3b2af190da62af339b84fd01ce3c71702f09eb69a57310fcf0c6d"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"camino", "camino",
@ -1170,9 +1172,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_integration_utils" name = "leptos_integration_utils"
version = "0.7.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fbf6dc5358d766932c6e58b30df53cfde916a9f4d20d4bb0cfc1bbf7f85a1" checksum = "a8652fcd7a1744f85403b95c5520143f3b962d640c8450b8514f9530fb5c4b76"
dependencies = [ dependencies = [
"futures", "futures",
"hydration_context", "hydration_context",
@ -1185,9 +1187,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_macro" name = "leptos_macro"
version = "0.7.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20bcb2afa03e0614c64eec4a95ec2986fd3c59358daa0f50006e081bc1bd1067" checksum = "90291b25ee576bc9c299d3371cc8f09bf60ea939a8de61fa8b744650aff76e24"
dependencies = [ dependencies = [
"attribute-derive", "attribute-derive",
"cfg-if", "cfg-if",
@ -1208,9 +1210,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_meta" name = "leptos_meta"
version = "0.7.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a54d4b942a474e38b606ff0bfe8712f093300bd053adb9dd7a028a14ca3fbfac" checksum = "7250991b2077ef5869e999c74cf4990926a3c3919b50c9937e101c1c874102db"
dependencies = [ dependencies = [
"futures", "futures",
"indexmap", "indexmap",
@ -1224,9 +1226,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_router" name = "leptos_router"
version = "0.7.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ff7d8c058b4bd7512fa58224b684d5da10d5f056171b8e27d516e0d36e1a5d" checksum = "9a193dbd62b9617a5d7d199ea70c570da01a1bbe798e617373b6351845be6778"
dependencies = [ dependencies = [
"any_spawner", "any_spawner",
"either_of", "either_of",
@ -1249,9 +1251,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_router_macro" name = "leptos_router_macro"
version = "0.7.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15a48035e8d796233a5b43322aeab9387f946f914dacdf17a1981c3910879b19" checksum = "34bc3f80ad810b22058f12d278bb0bf929779cc0bc1289a06980d896f62743f0"
dependencies = [ dependencies = [
"proc-macro-error2", "proc-macro-error2",
"proc-macro2", "proc-macro2",
@ -1260,9 +1262,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_server" name = "leptos_server"
version = "0.7.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fb23bd110ac04c7276aae3d8ba523f94cf06989d00b4e76eaee89451b06b494" checksum = "18caffe32c245ddb35697edd898ccb3393efce67672a707a14eebd0db2e8249a"
dependencies = [ dependencies = [
"any_spawner", "any_spawner",
"base64 0.22.1", "base64 0.22.1",
@ -1309,9 +1311,9 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.22" version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
[[package]] [[package]]
name = "manyhow" name = "manyhow"
@ -1381,9 +1383,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.8.2" version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924"
dependencies = [ dependencies = [
"adler2", "adler2",
] ]
@ -1590,9 +1592,9 @@ dependencies = [
[[package]] [[package]]
name = "prettyplease" name = "prettyplease"
version = "0.2.28" version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "924b9a625d6df5b74b0b3cfbb5669b3f62ddf3d46a677ce12b1945471b4ae5c3" checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"syn", "syn",
@ -1739,9 +1741,9 @@ dependencies = [
[[package]] [[package]]
name = "reactive_graph" name = "reactive_graph"
version = "0.1.3" version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bee22d7574c73fbfd47d828ee14dc67ca65606ade81de2f8d1691741072a93b" checksum = "9fbf210c04505e128fb7f64acecc23c71f82f56c7d481b190e1010b7bada2cb9"
dependencies = [ dependencies = [
"any_spawner", "any_spawner",
"async-lock", "async-lock",
@ -1991,9 +1993,9 @@ dependencies = [
[[package]] [[package]]
name = "server_fn" name = "server_fn"
version = "0.7.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0b9f0d2eecb2bf4f909661acc731009e3657574dec93a0ec9f114e250f74bc4" checksum = "f5dd7fcccd3ef2081da086c1f8595b506627abbbbc9f64be0141d2251219570e"
dependencies = [ dependencies = [
"axum", "axum",
"bytes", "bytes",
@ -2027,9 +2029,9 @@ dependencies = [
[[package]] [[package]]
name = "server_fn_macro" name = "server_fn_macro"
version = "0.7.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee7723bef57b4353cd9939e280d3b5b2ebe45b4a4630c9e9e97a6fa4b84e8b1c" checksum = "e0bbac4f01a714b0490247ac625bdb7055548210556c39e8f56a2dbbe3abc70b"
dependencies = [ dependencies = [
"const_format", "const_format",
"convert_case", "convert_case",
@ -2041,9 +2043,9 @@ dependencies = [
[[package]] [[package]]
name = "server_fn_macro_default" name = "server_fn_macro_default"
version = "0.7.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87663ec10f17fbe8f6c53adc2d038df3304bfd17aaaab22f777810a9e6e05fff" checksum = "f07dfd1744a5f5612f00f69fe035b0bfafdf12bb46d76e785673078a9e56b170"
dependencies = [ dependencies = [
"server_fn_macro", "server_fn_macro",
"syn", "syn",
@ -2152,9 +2154,9 @@ dependencies = [
[[package]] [[package]]
name = "tachys" name = "tachys"
version = "0.1.3" version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "761f12c13d74f1b723e3c53ff70fe291d15fe51cc4b6586aafea974f0b647043" checksum = "d777e4426a597296b020edcb5c3d8f25a3ccd8adfd22eb5154ac81da946aef9f"
dependencies = [ dependencies = [
"any_spawner", "any_spawner",
"const_str_slice_concat", "const_str_slice_concat",
@ -2567,9 +2569,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.11.1" version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b913a3b5fe84142e269d63cc62b64319ccaf89b748fc31fe025177f767a756c4" checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4"
dependencies = [ dependencies = [
"getrandom", "getrandom",
] ]

View File

@ -33,6 +33,7 @@ tracing-subscriber = { version = "0.3.18", features = [
], optional = true } ], optional = true }
ron = { version = "0.8" } ron = { version = "0.8" }
rand = { version = "0.8", optional = true } rand = { version = "0.8", optional = true }
web-sys = { version = "0.3.76", features = ["File", "FileList"] }
[dev-dependencies.serde_json] [dev-dependencies.serde_json]
version = "1" version = "1"

View File

@ -17,7 +17,7 @@ pub fn shell(options: LeptosOptions) -> impl IntoView {
<HydrationScripts options /> <HydrationScripts options />
<MetaTags /> <MetaTags />
</head> </head>
<body class="bg-slate-950"> <body class="bg-slate-950 text-white">
<App /> <App />
</body> </body>
</html> </html>
@ -50,7 +50,7 @@ pub fn App() -> impl leptos::IntoView {
<main> <main>
<Routes fallback=|| "Not found"> <Routes fallback=|| "Not found">
<Route path=path!("/wall") view=Wall /> <Route path=path!("/wall") view=Wall />
<Route path=path!("/wall/edit") view=EditWall/> <Route path=path!("/wall/edit") view=EditWall />
</Routes> </Routes>
</main> </main>
</Router> </Router>

View File

@ -2,5 +2,5 @@ use leptos::prelude::*;
#[component] #[component]
pub fn Header() -> impl leptos::IntoView { pub fn Header() -> impl leptos::IntoView {
leptos::view! { <div>"header"</div> } leptos::view! { <div class="border-b py-2 mb-4">"Ascend"</div> }
} }

View File

@ -1,10 +1,14 @@
use crate::components::header::Header; use crate::components::header::Header;
use crate::models::HoldPosition; use crate::models::HoldPosition;
use crate::models::HoldRole;
use crate::models::Wall; use crate::models::Wall;
use leptos::ev::Event;
use leptos::html::Input;
use leptos::prelude::*; use leptos::prelude::*;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use wasm_bindgen::JsCast;
use wasm_bindgen::prelude::*;
use web_sys::FileList;
#[component] #[component]
pub fn EditWall() -> impl leptos::IntoView { pub fn EditWall() -> impl leptos::IntoView {
@ -15,12 +19,12 @@ pub fn EditWall() -> impl leptos::IntoView {
leptos::view! { leptos::view! {
<div class="min-w-screen min-h-screen bg-slate-900"> <div class="min-w-screen min-h-screen bg-slate-900">
<div class="container mx-auto"> <div class="container mx-auto">
<Header /> <Header />
<Await future=load let:data> <Await future=load let:data>
<Ready data=data.to_owned() /> <Ready data=data.to_owned() />
</Await> </Await>
</div> </div>
</div> </div>
} }
} }
@ -35,22 +39,68 @@ fn Ready(data: InitialData) -> impl leptos::IntoView {
} }
} }
let mut cells = vec![]; let mut holds = vec![];
for &_hold_position in &hold_positions { for &hold_position in &hold_positions {
let cell = view! { <Hold /> }; holds.push(view! { <Hold hold_position /> });
cells.push(cell);
} }
let grid_classes = format!("grid grid-rows-{} grid-cols-{} gap-4", data.wall.rows, data.wall.cols); let grid_classes = format!("grid grid-rows-{} grid-cols-{} gap-4", data.wall.rows, data.wall.cols);
view! { view! { <div class=move || { grid_classes.clone() }>{holds}</div> }
<div class=move || { grid_classes.clone() }>{cells}</div>
}
} }
#[component] #[component]
fn Hold() -> impl leptos::IntoView { fn Hold(hold_position: HoldPosition) -> impl leptos::IntoView {
view! { <div class="bg-indigo-100 aspect-square rounded"></div> } let file_input_ref = NodeRef::<Input>::new();
let open_camera = move |_| {
if let Some(input) = file_input_ref.get() {
input.click(); // Trigger the file input click programmatically
}
};
// Callback to handle file selection
let on_file_input = move |event: Event| {
let files: FileList = event.target().unwrap().unchecked_ref::<web_sys::HtmlInputElement>().files().unwrap();
leptos::logging::log!("{:?}", &files);
let file = files.item(0).unwrap();
leptos::logging::log!("{:?}", &file);
let file_reader = web_sys::FileReader::new().unwrap();
file_reader.read_as_array_buffer(&file).unwrap();
leptos::logging::log!("foo");
let onload = Closure::wrap(Box::new(move |event: Event| {
leptos::logging::log!("onload");
let file_reader: web_sys::FileReader = event.target().unwrap().dyn_into().unwrap();
let file = file_reader.result().unwrap();
let file = web_sys::js_sys::Uint8Array::new(&file);
let mut file_buffer = vec![0; file.length() as usize];
file.copy_to(&mut file_buffer);
leptos::logging::log!("bytes: {:?}", &file_buffer.len());
}) as Box<dyn FnMut(_)>);
file_reader.set_onload(Some(onload.as_ref().unchecked_ref()));
onload.forget();
};
view! {
<button on:click=open_camera>
<div class="bg-indigo-100 aspect-square rounded"></div>
</button>
<input
node_ref=file_input_ref
type="file"
accept="image/*"
capture="user"
style="display: none;"
on:input=on_file_input
/>
}
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]

View File

@ -17,12 +17,12 @@ pub fn Wall() -> impl leptos::IntoView {
leptos::view! { leptos::view! {
<div class="min-w-screen min-h-screen bg-slate-900"> <div class="min-w-screen min-h-screen bg-slate-900">
<div class="container mx-auto"> <div class="container mx-auto">
<Header /> <Header />
<Await future=load let:data> <Await future=load let:data>
<Ready data=data.to_owned() /> <Ready data=data.to_owned() />
</Await> </Await>
</div> </div>
</div> </div>
} }
} }
@ -45,7 +45,7 @@ fn Ready(data: InitialData) -> impl leptos::IntoView {
let mut cells = vec![]; let mut cells = vec![];
for &hold_position in &hold_positions { for &hold_position in &hold_positions {
let role = move || current_problem.get().map(|problem| problem.holds.get(&hold_position).copied()).flatten(); let role = move || current_problem.get().and_then(|problem| problem.holds.get(&hold_position).copied());
let role = Signal::derive(role); let role = Signal::derive(role);
let cell = view! { <Hold role /> }; let cell = view! { <Hold role /> };
@ -72,7 +72,7 @@ fn Hold(#[prop(into)] role: Signal<Option<HoldRole>>) -> impl leptos::IntoView {
}; };
let mut s = "bg-indigo-100 aspect-square rounded".to_string(); let mut s = "bg-indigo-100 aspect-square rounded".to_string();
if let Some(c) = role_classes { if let Some(c) = role_classes {
s.push_str(" "); s.push(' ');
s.push_str(c); s.push_str(c);
} }
s s

View File

@ -83,7 +83,7 @@ pub mod mini_moonboard {
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
#[cfg_attr(rustfmt, rustfmt_skip)] #[rustfmt::skip]
pub enum MoveDescription { pub enum MoveDescription {
A12, B12, C12, D12, E12, F12, G12, H12, I12, J12, K12, A12, B12, C12, D12, E12, F12, G12, H12, I12, J12, K12,
A11, B11, C11, D11, E11, F11, G11, H11, I11, J11, K11, A11, B11, C11, D11, E11, F11, G11, H11, I11, J11, K11,