codify "platform" into resolution logic, server-fn/fullstack overhaul (#4596)
overhaul dioxus fullstack using a new implementation of server_fn This PR is a complete rewrite of dioxus fullstack designed to improve compatibility with axum and to fix a number of compilation errors based on feature flag unification plumbing through macros.
This commit is contained in:
1 parent
8421c3aef0
commit
f2b1c6d97f
424 files changed
+17284
-6624
No files matched your search
@@ -0,0 +1,41 @@
|
||||
use anyhow::Result;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
thread_local! {
|
||||
static DB: std::sync::LazyLock<rusqlite::Connection> = std::sync::LazyLock::new(|| {
|
||||
let conn = rusqlite::Connection::open("hotdogdb/hotdog.db").expect("Failed to open database");
|
||||
|
||||
conn.execute_batch(
|
||||
"CREATE TABLE IF NOT EXISTS dogs (
|
||||
id INTEGER PRIMARY KEY,
|
||||
url TEXT NOT NULL
|
||||
);",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
conn
|
||||
});
|
||||
}
|
||||
|
||||
#[get("/api/dogs")]
|
||||
pub async fn list_dogs() -> Result<Vec<(usize, String)>> {
|
||||
DB.with(|db| {
|
||||
Ok(db
|
||||
.prepare("SELECT id, url FROM dogs ORDER BY id DESC LIMIT 10")?
|
||||
.query_map([], |row| Ok((row.get(0)?, row.get(1)?)))?
|
||||
.collect::<Result<Vec<(usize, String)>, rusqlite::Error>>()?)
|
||||
})
|
||||
}
|
||||
|
||||
#[delete("/api/dogs/{id}")]
|
||||
pub async fn remove_dog(id: usize) -> Result<()> {
|
||||
DB.with(|db| db.execute("DELETE FROM dogs WHERE id = ?1", [id]))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[post("/api/dogs")]
|
||||
pub async fn save_dog(image: String) -> Result<()> {
|
||||
DB.with(|db| db.execute("INSERT INTO dogs (url) VALUES (?1)", [&image]))?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
use dioxus::prelude::*;
|
||||
|
||||
use crate::{
|
||||
backend::{list_dogs, remove_dog, save_dog},
|
||||
Route,
|
||||
};
|
||||
|
||||
#[component]
|
||||
pub fn Favorites() -> Element {
|
||||
let mut favorites = use_loader(list_dogs)?;
|
||||
|
||||
rsx! {
|
||||
div { id: "favorites",
|
||||
for (id , url) in favorites.cloned() {
|
||||
div { class: "favorite-dog", key: "{id}",
|
||||
img { src: "{url}" }
|
||||
button {
|
||||
onclick: move |_| async move {
|
||||
_ = remove_dog(id).await;
|
||||
favorites.restart();
|
||||
},
|
||||
"❌"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn NavBar() -> Element {
|
||||
rsx! {
|
||||
div { id: "title",
|
||||
span {}
|
||||
Link { to: Route::DogView, h1 { "🌭 HotDog! " } }
|
||||
Link { to: Route::Favorites, id: "heart", "♥️" }
|
||||
}
|
||||
Outlet::<Route> {}
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn DogView() -> Element {
|
||||
let mut img_src = use_loader(|| async move {
|
||||
anyhow::Ok(
|
||||
reqwest::get("https://dog.ceo/api/breeds/image/random")
|
||||
.await?
|
||||
.json::<serde_json::Value>()
|
||||
.await?["message"]
|
||||
.to_string(),
|
||||
)
|
||||
})?;
|
||||
|
||||
rsx! {
|
||||
div { id: "dogview",
|
||||
img { id: "dogimg", src: "{img_src}" }
|
||||
}
|
||||
div { id: "buttons",
|
||||
button {
|
||||
id: "skip",
|
||||
onclick: move |_| img_src.restart(),
|
||||
"skip"
|
||||
}
|
||||
button {
|
||||
id: "save",
|
||||
onclick: move |_| async move { _ = save_dog(img_src()).await },
|
||||
"save!"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
mod backend;
|
||||
mod frontend;
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use frontend::*;
|
||||
|
||||
#[derive(Routable, PartialEq, Clone)]
|
||||
enum Route {
|
||||
#[layout(NavBar)]
|
||||
#[route("/")]
|
||||
DogView,
|
||||
|
||||
#[route("/favorites")]
|
||||
Favorites,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[cfg(not(feature = "server"))]
|
||||
dioxus::fullstack::set_server_url("https://hot-dog.fly.dev");
|
||||
|
||||
dioxus::launch(app);
|
||||
}
|
||||
|
||||
fn app() -> Element {
|
||||
rsx! {
|
||||
Stylesheet { href: asset!("/assets/main.css") }
|
||||
Router::<Route> {}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user