feat: client side read files

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

View File

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

View File

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

View File

@@ -2,5 +2,5 @@ use leptos::prelude::*;
#[component]
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::models::HoldPosition;
use crate::models::HoldRole;
use crate::models::Wall;
use leptos::ev::Event;
use leptos::html::Input;
use leptos::prelude::*;
use serde::Deserialize;
use serde::Serialize;
use wasm_bindgen::JsCast;
use wasm_bindgen::prelude::*;
use web_sys::FileList;
#[component]
pub fn EditWall() -> impl leptos::IntoView {
@@ -15,12 +19,12 @@ pub fn EditWall() -> impl leptos::IntoView {
leptos::view! {
<div class="min-w-screen min-h-screen bg-slate-900">
<div class="container mx-auto">
<Header />
<Await future=load let:data>
<Ready data=data.to_owned() />
</Await>
</div>
<div class="container mx-auto">
<Header />
<Await future=load let:data>
<Ready data=data.to_owned() />
</Await>
</div>
</div>
}
}
@@ -35,22 +39,68 @@ fn Ready(data: InitialData) -> impl leptos::IntoView {
}
}
let mut cells = vec![];
for &_hold_position in &hold_positions {
let cell = view! { <Hold /> };
cells.push(cell);
let mut holds = vec![];
for &hold_position in &hold_positions {
holds.push(view! { <Hold hold_position /> });
}
let grid_classes = format!("grid grid-rows-{} grid-cols-{} gap-4", data.wall.rows, data.wall.cols);
view! {
<div class=move || { grid_classes.clone() }>{cells}</div>
}
view! { <div class=move || { grid_classes.clone() }>{holds}</div> }
}
#[component]
fn Hold() -> impl leptos::IntoView {
view! { <div class="bg-indigo-100 aspect-square rounded"></div> }
fn Hold(hold_position: HoldPosition) -> impl leptos::IntoView {
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)]

View File

@@ -17,12 +17,12 @@ pub fn Wall() -> impl leptos::IntoView {
leptos::view! {
<div class="min-w-screen min-h-screen bg-slate-900">
<div class="container mx-auto">
<Header />
<Await future=load let:data>
<Ready data=data.to_owned() />
</Await>
</div>
<div class="container mx-auto">
<Header />
<Await future=load let:data>
<Ready data=data.to_owned() />
</Await>
</div>
</div>
}
}
@@ -45,7 +45,7 @@ fn Ready(data: InitialData) -> impl leptos::IntoView {
let mut cells = vec![];
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 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();
if let Some(c) = role_classes {
s.push_str(" ");
s.push(' ');
s.push_str(c);
}
s

View File

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