rewrite components such that data always flows downwards
This commit is contained in:
@@ -9,18 +9,22 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Props)]
|
#[derive(PartialEq, Clone, Props)]
|
||||||
pub struct MediaGridProps
|
pub struct MediaGridProps {
|
||||||
{
|
|
||||||
pub query: Signal<String>,
|
pub query: Signal<String>,
|
||||||
pub max_page: Signal<i32>,
|
pub max_page: Signal<i32>,
|
||||||
pub total_items: Signal<i32>,
|
pub total_items: Signal<i32>,
|
||||||
pub page: Signal<i32>,
|
pub page: Signal<i32>,
|
||||||
pub page_size: Signal<i32>,
|
pub page_size: Signal<i32>,
|
||||||
|
pub on_page_loaded: Option<EventHandler<PaginationInfo>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PaginationInfo {
|
||||||
|
pub total_pages: i32,
|
||||||
|
pub total_items: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn MediaGrid(mut props: MediaGridProps) -> Element
|
pub fn MediaGrid(props: MediaGridProps) -> Element {
|
||||||
{
|
|
||||||
let mut error_display = use_signal(|| {
|
let mut error_display = use_signal(|| {
|
||||||
rsx! {}
|
rsx! {}
|
||||||
});
|
});
|
||||||
@@ -34,32 +38,29 @@ pub fn MediaGrid(mut props: MediaGridProps) -> Element
|
|||||||
query: Some(props.query.cloned()),
|
query: Some(props.query.cloned()),
|
||||||
};
|
};
|
||||||
let result = client.list_media(request).await;
|
let result = client.list_media(request).await;
|
||||||
if let Ok(items) = result
|
if let Ok(items) = result {
|
||||||
{
|
|
||||||
let res = items.into_inner();
|
let res = items.into_inner();
|
||||||
|
|
||||||
return Ok(res);
|
return Ok(res);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
let err = result.err().unwrap();
|
let err = result.err().unwrap();
|
||||||
let message = err.message();
|
let message = err.message();
|
||||||
return Err(format!("Failed to load results: {message}"));
|
return Err(format!("Failed to load results: {message}"));
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
use_effect(move || match media_result()
|
use_effect(move || match media_result() {
|
||||||
{
|
Some(value) => match value {
|
||||||
Some(value) => match value
|
Ok(result) => {
|
||||||
{
|
if let Some(pagination) = result.pagination {
|
||||||
Ok(result) =>
|
|
||||||
{
|
|
||||||
if let Some(pagination) = result.pagination
|
|
||||||
{
|
|
||||||
let total_pages = pagination.total_pages;
|
let total_pages = pagination.total_pages;
|
||||||
let total_items = pagination.total_items;
|
let total_items = pagination.total_items;
|
||||||
props.max_page.set(total_pages.max(1));
|
if let Some(handler) = props.on_page_loaded {
|
||||||
props.total_items.set(total_items.max(1));
|
handler.call(PaginationInfo {
|
||||||
|
total_pages,
|
||||||
|
total_items,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
items.set(Some(result.items));
|
items.set(Some(result.items));
|
||||||
error_display.set(rsx! {});
|
error_display.set(rsx! {});
|
||||||
@@ -70,8 +71,7 @@ pub fn MediaGrid(mut props: MediaGridProps) -> Element
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
_ =>
|
_ => {}
|
||||||
{}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
@@ -87,8 +87,7 @@ pub fn MediaGrid(mut props: MediaGridProps) -> Element
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn PlaceholderGrid(count: usize) -> Element
|
fn PlaceholderGrid(count: usize) -> Element {
|
||||||
{
|
|
||||||
rsx! {
|
rsx! {
|
||||||
div{
|
div{
|
||||||
class: "mediaGrid",
|
class: "mediaGrid",
|
||||||
@@ -100,12 +99,12 @@ fn PlaceholderGrid(count: usize) -> Element
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn MediaList(items: Vec<MediaModel>) -> Element
|
fn MediaList(items: Vec<MediaModel>) -> Element {
|
||||||
{
|
|
||||||
rsx! {
|
rsx! {
|
||||||
{items.iter().map(|itm| rsx!{
|
{items.iter().enumerate().map(|(index, itm)| rsx!{
|
||||||
MediaItem {
|
MediaItem {
|
||||||
item: itm.clone()
|
item: itm.clone(),
|
||||||
|
index
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_primitives::context_menu::{ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger};
|
use dioxus_primitives::context_menu::{
|
||||||
|
ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger,
|
||||||
|
};
|
||||||
use tonic::{Response, Status};
|
use tonic::{Response, Status};
|
||||||
use web_sys::window;
|
use web_sys::window;
|
||||||
|
|
||||||
@@ -11,23 +13,28 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub struct MediaClassChangeEvent {
|
||||||
|
pub index: usize,
|
||||||
|
pub class: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Props)]
|
#[derive(PartialEq, Clone, Props)]
|
||||||
pub struct MediaItemProps
|
pub struct MediaItemProps {
|
||||||
{
|
|
||||||
pub item: MediaModel,
|
pub item: MediaModel,
|
||||||
|
pub index: usize,
|
||||||
|
pub on_class_changed: Option<EventHandler<MediaClassChangeEvent>>,
|
||||||
|
pub on_deleted: Option<EventHandler<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn MediaItem(props: MediaItemProps) -> Element
|
pub fn MediaItem(props: MediaItemProps) -> Element {
|
||||||
{
|
|
||||||
let item = props.item;
|
let item = props.item;
|
||||||
let mtype = item.media_type().as_str_name();
|
let mtype = item.media_type().as_str_name();
|
||||||
let filename = item.file_name;
|
let filename = item.file_name;
|
||||||
let id = item.id.unwrap().value;
|
let id = item.id.unwrap().value;
|
||||||
let thumb = item.thumb_url;
|
let thumb = item.thumb_url;
|
||||||
let class = item.class;
|
let class = item.class;
|
||||||
let mut class_signal = use_signal(|| match class
|
let mut class_signal = use_signal(|| match class {
|
||||||
{
|
|
||||||
1 => "blur",
|
1 => "blur",
|
||||||
2 => "secret",
|
2 => "secret",
|
||||||
_ => "",
|
_ => "",
|
||||||
@@ -174,8 +181,7 @@ pub fn MediaItem(props: MediaItemProps) -> Element
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn MediaItemPlaceHolder() -> Element
|
pub fn MediaItemPlaceHolder() -> Element {
|
||||||
{
|
|
||||||
return rsx! {
|
return rsx! {
|
||||||
div { class: "mediaItem placeholder",
|
div { class: "mediaItem placeholder",
|
||||||
img { },
|
img { },
|
||||||
@@ -190,8 +196,7 @@ pub fn MediaItemPlaceHolder() -> Element
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_class(id: String, class: i32) -> Result<Response<()>, Status>
|
async fn set_class(id: String, class: i32) -> Result<Response<()>, Status> {
|
||||||
{
|
|
||||||
let mut client = get_rpc_client();
|
let mut client = get_rpc_client();
|
||||||
return client
|
return client
|
||||||
.set_media_class(SetMediaClassRequest {
|
.set_media_class(SetMediaClassRequest {
|
||||||
|
|||||||
@@ -2,8 +2,12 @@ use dioxus::prelude::*;
|
|||||||
use web_sys::window;
|
use web_sys::window;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Pagination(page: Signal<i32>, max_page: Signal<i32>, item_count: Signal<i32>) -> Element
|
pub fn Pagination(
|
||||||
{
|
page: Signal<i32>,
|
||||||
|
max_page: Signal<i32>,
|
||||||
|
item_count: Signal<i32>,
|
||||||
|
on_page_change: EventHandler<i32>,
|
||||||
|
) -> Element {
|
||||||
let cur_page_val = page.cloned();
|
let cur_page_val = page.cloned();
|
||||||
let max_page_val = max_page.cloned();
|
let max_page_val = max_page.cloned();
|
||||||
let item_count_val = item_count.cloned();
|
let item_count_val = item_count.cloned();
|
||||||
@@ -12,16 +16,16 @@ pub fn Pagination(page: Signal<i32>, max_page: Signal<i32>, item_count: Signal<i
|
|||||||
class: "pagination",
|
class: "pagination",
|
||||||
a {
|
a {
|
||||||
onclick: move|_| {
|
onclick: move|_| {
|
||||||
page.set(1);
|
on_page_change.call(1);
|
||||||
on_page_change();
|
scroll_document();
|
||||||
},
|
},
|
||||||
"First"
|
"First"
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
onclick: move|_| {
|
onclick: move|_| {
|
||||||
let p = (cur_page_val - 1).max(1);
|
let p = (cur_page_val - 1).max(1);
|
||||||
page.set(p);
|
on_page_change.call(p);
|
||||||
on_page_change();
|
scroll_document();
|
||||||
},
|
},
|
||||||
"Prev"
|
"Prev"
|
||||||
}
|
}
|
||||||
@@ -29,15 +33,15 @@ pub fn Pagination(page: Signal<i32>, max_page: Signal<i32>, item_count: Signal<i
|
|||||||
a {
|
a {
|
||||||
onclick: move|_| {
|
onclick: move|_| {
|
||||||
let p = (cur_page_val + 1).min(max_page_val);
|
let p = (cur_page_val + 1).min(max_page_val);
|
||||||
page.set(p);
|
on_page_change.call(p);
|
||||||
on_page_change();
|
scroll_document();
|
||||||
},
|
},
|
||||||
"Next"
|
"Next"
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
onclick: move|_| {
|
onclick: move|_| {
|
||||||
page.set(max_page_val);
|
on_page_change.call(max_page_val);
|
||||||
on_page_change();
|
scroll_document();
|
||||||
},
|
},
|
||||||
"Last"
|
"Last"
|
||||||
}
|
}
|
||||||
@@ -45,8 +49,7 @@ pub fn Pagination(page: Signal<i32>, max_page: Signal<i32>, item_count: Signal<i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_page_change()
|
fn scroll_document() {
|
||||||
{
|
|
||||||
let window = window().expect("Failed to get window");
|
let window = window().expect("Failed to get window");
|
||||||
let document = window.document().expect("Failed to get document");
|
let document = window.document().expect("Failed to get document");
|
||||||
document
|
document
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Search(query: Signal<String>, page: Signal<i32>) -> Element {
|
pub fn Search(query: String, oninput: Option<EventHandler<String>>) -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
div { class: "searchBar",
|
div { class: "searchBar",
|
||||||
input {
|
input {
|
||||||
r#type: "search",
|
r#type: "search",
|
||||||
placeholder: "Search Files",
|
placeholder: "Search Files",
|
||||||
value: query,
|
value: query,
|
||||||
oninput: move |event| {query.set(event.value()); page.set(1);},
|
oninput: move |event| {
|
||||||
|
if let Some(handler) = oninput {
|
||||||
|
handler.call(event.value());
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::components::{MediaGrid, Pagination, Search};
|
use crate::components::{MediaGrid, Pagination, PaginationInfo, Search};
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
// #[component]
|
// #[component]
|
||||||
@@ -19,19 +19,34 @@ use dioxus::prelude::*;
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Home(page: Option<i32>, q: Option<String>) -> Element
|
pub fn Home(page: Option<i32>, q: Option<String>) -> Element {
|
||||||
{
|
let mut query = use_signal(|| q.unwrap_or("".to_string()));
|
||||||
let query = use_signal(|| q.unwrap_or("".to_string()));
|
let mut page = use_signal(|| page.unwrap_or(1));
|
||||||
let page = use_signal(|| page.unwrap_or(1));
|
|
||||||
let page_size = use_signal::<i32>(|| 100);
|
let page_size = use_signal::<i32>(|| 100);
|
||||||
let max_page = use_signal(|| 1 as i32);
|
let mut max_page = use_signal(|| 1 as i32);
|
||||||
let item_count = use_signal(|| 0 as i32);
|
let mut item_count = use_signal(|| 0 as i32);
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
class: "stickyTop",
|
class: "stickyTop",
|
||||||
Search { query, page },
|
Search {
|
||||||
Pagination { page, max_page, item_count },
|
query: query(),
|
||||||
|
oninput: move |q| {
|
||||||
|
query.set(q);
|
||||||
|
page.set(1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Pagination {
|
||||||
|
page, max_page, item_count,
|
||||||
|
on_page_change: move |p|{
|
||||||
|
page.set(p);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
MediaGrid { query: query, page: page, max_page, total_items: item_count, page_size,
|
||||||
|
on_page_loaded: move |p: PaginationInfo| {
|
||||||
|
max_page.set(p.total_pages);
|
||||||
|
item_count.set(p.total_items);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
MediaGrid { query: query, page: page, max_page, total_items: item_count, page_size }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
use crate::HOST;
|
use crate::HOST;
|
||||||
use crate::components::radio_group::{RadioGroup, RadioItem};
|
|
||||||
use crate::rpc::aoba::SetMediaClassRequest;
|
|
||||||
use crate::rpc::{
|
use crate::rpc::{
|
||||||
aoba::{Id, MediaModel},
|
aoba::{Id, MediaModel},
|
||||||
get_rpc_client,
|
get_rpc_client,
|
||||||
@@ -8,26 +6,20 @@ use crate::rpc::{
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Media(id: String) -> Element
|
pub fn Media(id: String) -> Element {
|
||||||
{
|
|
||||||
let media_result = use_resource(use_reactive!(|(id)| async move {
|
let media_result = use_resource(use_reactive!(|(id)| async move {
|
||||||
let mut client = get_rpc_client();
|
let mut client = get_rpc_client();
|
||||||
let result = client.get_media(Id { value: id.clone() }).await;
|
let result = client.get_media(Id { value: id.clone() }).await;
|
||||||
if let Ok(item) = result
|
if let Ok(item) = result {
|
||||||
{
|
|
||||||
let res = item.into_inner();
|
let res = item.into_inner();
|
||||||
return res.value;
|
return res.value;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return match media_result.cloned().unwrap_or(None)
|
return match media_result.cloned().unwrap_or(None) {
|
||||||
{
|
Some(media) => {
|
||||||
Some(media) =>
|
|
||||||
{
|
|
||||||
return rsx! {MediaPage{media: media}};
|
return rsx! {MediaPage{media: media}};
|
||||||
}
|
}
|
||||||
None => rsx! {"Not Found"},
|
None => rsx! {"Not Found"},
|
||||||
@@ -35,12 +27,10 @@ pub fn Media(id: String) -> Element
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn MediaPage(media: MediaModel) -> Element
|
fn MediaPage(media: MediaModel) -> Element {
|
||||||
{
|
|
||||||
let url = media.thumb_url;
|
let url = media.thumb_url;
|
||||||
let id = media.id.expect("Media has no id").value.clone();
|
let id = media.id.expect("Media has no id").value.clone();
|
||||||
let cur_class = use_signal(|| match media.class
|
let cur_class = use_signal(|| match media.class {
|
||||||
{
|
|
||||||
0 => "Standard",
|
0 => "Standard",
|
||||||
1 => "NSFW",
|
1 => "NSFW",
|
||||||
2 => "Secret",
|
2 => "Secret",
|
||||||
|
|||||||
Reference in New Issue
Block a user