Home Tab + Tauri backend

This commit is contained in:
2025-12-28 09:01:26 +01:00
commit 896841e1c0
85 changed files with 1533 additions and 0 deletions

10
src/pages/chat.rs Normal file
View File

@@ -0,0 +1,10 @@
use yew::prelude::*;
#[function_component(Chat)]
pub fn chat() -> Html {
html! {
<div>
<h1>{"Chat Page"}</h1>
</div>
}
}

116
src/pages/home.rs Normal file
View File

@@ -0,0 +1,116 @@
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::spawn_local;
use web_sys::{window, MouseEvent, ScrollBehavior, ScrollToOptions};
use yew::prelude::*;
// Tauri 'invoke' Funktion deklarieren
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"])]
async fn invoke(cmd: &str, args: JsValue) -> JsValue;
}
// Wir definieren Post lokal, damit Yew weiß, wie die JSON-Daten vom Backend aussehen
// In src/pages/home.rs
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct Post {
pub content: String,
pub author: String,
pub created_at: u64,
}
#[function_component(Home)]
pub fn home() -> Html {
let posts = use_state(|| None::<Vec<Post>>);
let error = use_state(|| false);
let load_posts = {
let posts = posts.clone();
let error = error.clone();
Callback::from(move |_e: MouseEvent| {
let posts = posts.clone();
let error = error.clone();
// UI zurücksetzen & Scrollen
posts.set(None);
error.set(false);
if let Some(win) = window() {
let options = ScrollToOptions::new();
options.set_top(0.0);
options.set_behavior(ScrollBehavior::Smooth);
let _ = win.scroll_to_with_scroll_to_options(&options);
}
spawn_local(async move {
// Daten vom Rust-Backend anfordern
let res = invoke("fetch_nostr_posts", JsValue::NULL).await;
// JSON-Resultat in Vec<Post> umwandeln
if let Ok(new_posts) = serde_wasm_bindgen::from_value::<Vec<Post>>(res) {
posts.set(Some(new_posts));
} else {
error.set(true);
}
});
})
};
// Initiales Laden beim Start
{
let load_posts = load_posts.clone();
use_effect_with((), move |_| {
load_posts.emit(MouseEvent::new("click").unwrap());
|| ()
});
}
html! {
<div class="feed-container">
<div class="feed-header">
<h1 class="feed-title">{"✨ Entdecken"}</h1>
<button class="reload-btn" onclick={load_posts.clone()}>
{"🔄"}
</button>
</div>
{
if *error {
html! { <p class="status-msg">{"Fehler beim Laden der Posts."}</p> }
} else if let Some(ref posts_list) = *posts {
html! {
<div class="posts-list">
{ for posts_list.iter().map(|p| html! { <PostCard post={p.clone()} /> }) }
<div class="footer-action">
<button class="reload-btn-large" onclick={load_posts}>
{"Nach oben & Neu laden"}
</button>
</div>
</div>
}
} else {
html! { <p class="status-msg">{"Verbinde mit Nostr über Tauri..."}</p> }
}
}
</div>
}
}
#[derive(Properties, PartialEq)]
pub struct PostProps {
pub post: Post,
}
#[function_component(PostCard)]
pub fn post_card(props: &PostProps) -> Html {
let post = &props.post;
html! {
<div class="post-card">
<div class="post-header">
<span class="post-author">{ format!("{:.8}...", post.author) }</span>
<span class="post-date">{ post.created_at }</span>
</div>
<div class="post-content">{ &post.content }</div>
</div>
}
}

3
src/pages/mod.rs Normal file
View File

@@ -0,0 +1,3 @@
pub mod chat;
pub mod home;
pub mod news;

10
src/pages/news.rs Normal file
View File

@@ -0,0 +1,10 @@
use yew::prelude::*;
#[function_component(News)]
pub fn news() -> Html {
html! {
<div>
<h1>{"News Page"}</h1>
</div>
}
}