summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/components/buy.rs38
-rw-r--r--src/components/input_placeholder.rs77
-rw-r--r--src/components/mod.rs2
-rw-r--r--src/components/product_overview.rs5
-rw-r--r--src/lib.rs8
5 files changed, 128 insertions, 2 deletions
diff --git a/src/components/buy.rs b/src/components/buy.rs
new file mode 100644
index 0000000..86e9952
--- /dev/null
+++ b/src/components/buy.rs
@@ -0,0 +1,38 @@
+use leptos::{
+    IntoView, component,
+    html::Input,
+    prelude::{ClassAttribute, ElementChild, Get, NodeRef, OnAttribute, Set, signal},
+    view,
+    web_sys::SubmitEvent,
+};
+
+use crate::components::{input_placeholder::InputPlaceholder, site_header::SiteHeader};
+
+#[component]
+pub fn Buy() -> impl IntoView {
+    let (product_barcode, set_product_barcode) = signal(String::new());
+
+    let input_element: NodeRef<Input> = NodeRef::new();
+
+    let on_submit = move |ev: SubmitEvent| {
+        // stop the page from reloading!
+        ev.prevent_default();
+
+        let value = input_element
+            .get()
+            // event handlers can only fire after the view
+            // is mounted to the DOM, so the `NodeRef` will be `Some`
+            .expect("<input> to exist")
+            .value();
+        set_product_barcode.set(value);
+    };
+
+    view! {
+        <SiteHeader logo=icondata_io::IoPricetag back_location="/" name="Buy" />
+        <form class="flex flex-col contents-start m-2 g-2" on:submit=on_submit>
+            <InputPlaceholder input_type="number" label="Product Barcode" node_ref=input_element />
+            <input type="submit" value="Submit" />
+        </form>
+        <p>"Name is: " {product_barcode}</p>
+    }
+}
diff --git a/src/components/input_placeholder.rs b/src/components/input_placeholder.rs
new file mode 100644
index 0000000..92f9926
--- /dev/null
+++ b/src/components/input_placeholder.rs
@@ -0,0 +1,77 @@
+use leptos::{
+    IntoView, component,
+    html::Input,
+    prelude::{ClassAttribute, ElementChild, GlobalAttributes, NodeRef, NodeRefAttribute},
+    view,
+};
+use uuid::Uuid;
+
+#[component]
+pub fn InputPlaceholder(
+    input_type: &'static str,
+    label: &'static str,
+    node_ref: NodeRef<Input>,
+    #[prop(default = None)] initial_value: Option<String>,
+) -> impl IntoView {
+    let id = Uuid::new_v4();
+
+    view! {
+        <div class="relative h-14">
+            <input
+                id=id.to_string()
+                type=input_type
+                class="\
+                absolute \
+                bottom-0 \
+                bg-gray-200 \
+                border-8 \
+                border-b-2 \
+                border-b-trasparent \
+                border-gray-200 \
+                focus:outline-none \
+                h-10 \
+                peer \
+                placeholder-transparent \
+                rounded-t-lg \
+                text-gray-900 \
+                w-full \
+                "
+                placeholder="sentinel value"
+                node_ref=node_ref
+                value=initial_value
+            />
+
+            // TODO: Reference `var(--tw-border-2)` instead of the `2 px` <2025-10-01>
+            <div class="
+            absolute \
+            bottom-0 \
+            h-[2px] \
+            w-full \
+            bg-gray-300 \
+            peer-focus:bg-indigo-600 \
+            " />
+
+            <label
+                for=id.to_string()
+                class="\
+                bottom-10 \
+                absolute \
+                left-0 \
+                text-gray-700 \
+                text-sm \
+                transition-all \
+                peer-focus:bottom-10 \
+                peer-focus:left-0 \
+                peer-focus:text-gray-700 \
+                peer-focus:text-sm \
+                peer-placeholder-shown:text-base \
+                peer-placeholder-shown:text-gray-400 \
+                peer-placeholder-shown:bottom-2 \
+                peer-placeholder-shown:left-2 \
+                "
+            >
+                {label}
+            </label>
+        </div>
+    }
+}
diff --git a/src/components/mod.rs b/src/components/mod.rs
index 7174ad8..55e4397 100644
--- a/src/components/mod.rs
+++ b/src/components/mod.rs
@@ -2,8 +2,10 @@
 pub mod async_fetch;
 pub mod container;
 pub mod icon_p;
+pub mod input_placeholder;
 
 // Specific
+pub mod buy;
 pub mod inventory;
 pub mod product_overview;
 pub mod recipies;
diff --git a/src/components/product_overview.rs b/src/components/product_overview.rs
index ae2eaf2..d86c04d 100644
--- a/src/components/product_overview.rs
+++ b/src/components/product_overview.rs
@@ -11,7 +11,10 @@ pub fn ProductOverview() -> impl IntoView {
         <Container
             header="Inventory"
             buttons=vec![
-                (view! { <IconP icon=icondata_io::IoClipboardOutline text="Inventory" /> }, "inventory"),
+                (
+                    view! { <IconP icon=icondata_io::IoClipboardOutline text="Inventory" /> },
+                    "inventory",
+                ),
                 (view! { <IconP icon=icondata_io::IoPricetags text="Consume" /> }, "consume"),
                 (view! { <IconP icon=icondata_io::IoStorefront text="Buy" /> }, "buy"),
             ]
diff --git a/src/lib.rs b/src/lib.rs
index a488d95..3813ebb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -31,7 +31,7 @@ use reactive_stores::Store;
 use rocie_client::apis::configuration::Configuration;
 
 use crate::{
-    components::inventory::Inventory,
+    components::{buy::Buy, inventory::Inventory},
     pages::{home::Home, not_found::NotFound},
 };
 
@@ -78,6 +78,12 @@ pub fn App() -> impl IntoView {
                         view! { <Inventory /> }
                     }
                 />
+                <Route
+                    path=path!("/buy")
+                    view=move || {
+                        view! { <Buy /> }
+                    }
+                />
             </Routes>
         </Router>
     }