Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 41aa78b672 |
@@ -195,3 +195,24 @@ form {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pagination {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5;
|
||||||
|
padding: 2px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
transition: all 0.25s ease-out;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
padding: 5px 10px;
|
||||||
|
background-color: $featureColor;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $focusColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ use crate::{
|
|||||||
#[derive(PartialEq, Clone, Props)]
|
#[derive(PartialEq, Clone, Props)]
|
||||||
pub struct MediaGridProps {
|
pub struct MediaGridProps {
|
||||||
pub query: Option<String>,
|
pub query: Option<String>,
|
||||||
|
pub max_page: Signal<i32>,
|
||||||
|
pub total_items: Signal<i32>,
|
||||||
#[props(default = Some(1))]
|
#[props(default = Some(1))]
|
||||||
pub page: Option<i32>,
|
pub page: Option<i32>,
|
||||||
#[props(default = Some(100))]
|
#[props(default = Some(100))]
|
||||||
@@ -33,12 +35,13 @@ impl Into<PageFilter> for MediaGridProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn MediaGrid(props: MediaGridProps) -> Element {
|
pub fn MediaGrid(mut props: MediaGridProps) -> Element {
|
||||||
let media_result = use_resource(use_reactive!(|(props)| async move {
|
let media_result = use_resource(use_reactive!(|(props)| async move {
|
||||||
let mut client = get_rpc_client();
|
let mut client = get_rpc_client();
|
||||||
let result = client.list_media(props.into_request()).await;
|
let result = client.list_media(props.into_request()).await;
|
||||||
if let Ok(items) = result {
|
if let Ok(items) = result {
|
||||||
return Ok(items.into_inner());
|
let res = items.into_inner();
|
||||||
|
return Ok(res);
|
||||||
} else {
|
} else {
|
||||||
let err = result.err().unwrap();
|
let err = result.err().unwrap();
|
||||||
let message = err.message();
|
let message = err.message();
|
||||||
@@ -48,7 +51,13 @@ pub fn MediaGrid(props: MediaGridProps) -> Element {
|
|||||||
|
|
||||||
match media_result.cloned() {
|
match media_result.cloned() {
|
||||||
Some(value) => match value {
|
Some(value) => match value {
|
||||||
Ok(result) => rsx! {
|
Ok(result) => {
|
||||||
|
let pagination = result.pagination.unwrap();
|
||||||
|
let total_pages = pagination.total_pages;
|
||||||
|
let total_items = pagination.total_items;
|
||||||
|
props.max_page.set(total_pages.max(1));
|
||||||
|
props.total_items.set(total_items.max(1));
|
||||||
|
return rsx! {
|
||||||
div {
|
div {
|
||||||
class: "mediaGrid",
|
class: "mediaGrid",
|
||||||
// oncontextmenu: oncontext,
|
// oncontextmenu: oncontext,
|
||||||
@@ -58,7 +67,8 @@ pub fn MediaGrid(props: MediaGridProps) -> Element {
|
|||||||
}
|
}
|
||||||
})},
|
})},
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
|
}
|
||||||
Err(msg) => rsx! {
|
Err(msg) => rsx! {
|
||||||
div {
|
div {
|
||||||
class: "mediaGrid",
|
class: "mediaGrid",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ mod media_item;
|
|||||||
mod metrics_token;
|
mod metrics_token;
|
||||||
mod navbar;
|
mod navbar;
|
||||||
mod notif;
|
mod notif;
|
||||||
|
mod pagination;
|
||||||
mod search;
|
mod search;
|
||||||
pub use context_menu::*;
|
pub use context_menu::*;
|
||||||
pub use media_grid::*;
|
pub use media_grid::*;
|
||||||
@@ -12,5 +13,6 @@ pub use media_item::*;
|
|||||||
pub use metrics_token::*;
|
pub use metrics_token::*;
|
||||||
pub use navbar::*;
|
pub use navbar::*;
|
||||||
pub use notif::*;
|
pub use notif::*;
|
||||||
|
pub use pagination::*;
|
||||||
pub use search::*;
|
pub use search::*;
|
||||||
mod icons;
|
mod icons;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ pub fn Navbar() -> Element {
|
|||||||
pub fn MainNaviagation() -> Element {
|
pub fn MainNaviagation() -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
div { class: "mainNav",
|
div { class: "mainNav",
|
||||||
Link { class: "navItem", to: Route::Home {}, "Home" }
|
Link { class: "navItem", to: Route::Home { }, "Home" }
|
||||||
Link { class: "navItem", to: Route::Settings {}, "Settings" }
|
Link { class: "navItem", to: Route::Settings {}, "Settings" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
30
AobaClient/src/components/pagination.rs
Normal file
30
AobaClient/src/components/pagination.rs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Pagination(page: Signal<i32>, max_page: Signal<i32>, item_count: Signal<i32>) -> Element {
|
||||||
|
let cur_page_val = page.cloned();
|
||||||
|
let max_page_val = max_page.cloned();
|
||||||
|
let item_count_val = item_count.cloned();
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
class: "pagination",
|
||||||
|
a {
|
||||||
|
onclick: move|_| page.set(1),
|
||||||
|
"First"
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
onclick: move|_| page.set((cur_page_val - 1).max(1)),
|
||||||
|
"Prev"
|
||||||
|
}
|
||||||
|
div { "Page {cur_page_val} of {max_page_val} ({item_count_val} Media Items)" }
|
||||||
|
a {
|
||||||
|
onclick: move|_| page.set((cur_page_val + 1).min(max_page_val)),
|
||||||
|
"Next"
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
onclick: move|_| page.set(max_page_val),
|
||||||
|
"Last"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Search(query: Signal<String>) -> Element {
|
pub fn Search(query: Signal<String>, page: Signal<i32>) -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
div { class: "searchBar stickyTop",
|
div { class: "searchBar stickyTop",
|
||||||
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()),
|
oninput: move |event| {query.set(event.value()); page.set(1);},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
layouts::MainLayout,
|
layouts::MainLayout,
|
||||||
views::{Home, Settings},
|
views::{Home, Media, Settings},
|
||||||
};
|
};
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
@@ -8,8 +8,11 @@ use dioxus::prelude::*;
|
|||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
pub enum Route {
|
pub enum Route {
|
||||||
#[layout(MainLayout)]
|
#[layout(MainLayout)]
|
||||||
|
|
||||||
#[route("/")]
|
#[route("/")]
|
||||||
Home {},
|
Home { },
|
||||||
|
#[route("/media/:id")]
|
||||||
|
Media { id: String },
|
||||||
#[route("/settings")]
|
#[route("/settings")]
|
||||||
Settings {},
|
Settings {},
|
||||||
// #[end_layout]
|
// #[end_layout]
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
use crate::components::{MediaGrid, Search};
|
use crate::components::{MediaGrid, Pagination, Search};
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Home() -> Element {
|
pub fn Home() -> Element {
|
||||||
let query = use_signal(|| "".to_string());
|
let query = use_signal(|| "".to_string());
|
||||||
|
let page = use_signal(|| 1 as i32);
|
||||||
|
let max_page = use_signal(|| 1 as i32);
|
||||||
|
let item_count = use_signal(|| 0 as i32);
|
||||||
rsx! {
|
rsx! {
|
||||||
Search { query }
|
Search { query, page },
|
||||||
MediaGrid { query: query.cloned() }
|
Pagination { page, max_page, item_count },
|
||||||
|
MediaGrid { query: query.cloned(), page: page.cloned(), max_page, total_items: item_count }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
AobaClient/src/views/media.rs
Normal file
8
AobaClient/src/views/media.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Media(id: String) -> Element {
|
||||||
|
rsx! {
|
||||||
|
{id}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
mod home;
|
mod home;
|
||||||
mod login;
|
mod login;
|
||||||
|
mod media;
|
||||||
pub use home::*;
|
pub use home::*;
|
||||||
pub use login::*;
|
pub use login::*;
|
||||||
|
pub use media::*;
|
||||||
|
|
||||||
mod settings;
|
mod settings;
|
||||||
pub use settings::Settings;
|
pub use settings::Settings;
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace AobaCore.Models;
|
namespace AobaCore.Models;
|
||||||
public class PagedResult<T>(List<T> items, int page, int pageSize, long totalItems)
|
public class PagedResult<T>(List<T> items, int page, int pageSize, int totalItems)
|
||||||
{
|
{
|
||||||
public List<T> Items { get; set; } = items;
|
public List<T> Items { get; set; } = items;
|
||||||
public int Page { get; set; } = page;
|
public int Page { get; set; } = page;
|
||||||
public int PageSize { get; set; } = pageSize;
|
public int PageSize { get; set; } = pageSize;
|
||||||
public long TotalItems { get; set; } = totalItems;
|
public int TotalItems { get; set; } = totalItems;
|
||||||
public long TotalPages { get; set; } = totalItems / pageSize;
|
public int TotalPages { get; set; } = (totalItems / pageSize) + 1;
|
||||||
public string? Query { get; set; }
|
public string? Query { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class AobaService(IMongoDatabase db)
|
|||||||
var total = await find.CountDocumentsAsync();
|
var total = await find.CountDocumentsAsync();
|
||||||
page -= 1;
|
page -= 1;
|
||||||
var items = await find.Sort(sort).Skip(page * pageSize).Limit(pageSize).ToListAsync();
|
var items = await find.Sort(sort).Skip(page * pageSize).Limit(pageSize).ToListAsync();
|
||||||
return new PagedResult<Media>(items, page, pageSize, total);
|
return new PagedResult<Media>(items, page, pageSize, (int)total);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<Media>> FindMediaWithExtAsync(string ext, CancellationToken cancellationToken = default)
|
public async Task<List<Media>> FindMediaWithExtAsync(string ext, CancellationToken cancellationToken = default)
|
||||||
|
|||||||
@@ -54,8 +54,8 @@ message ListResponse {
|
|||||||
message Pagination {
|
message Pagination {
|
||||||
int32 page = 1;
|
int32 page = 1;
|
||||||
int32 pageSize = 2;
|
int32 pageSize = 2;
|
||||||
int64 totalPages = 3;
|
int32 totalPages = 3;
|
||||||
int64 totalItems = 4;
|
int32 totalItems = 4;
|
||||||
optional string query = 5;
|
optional string query = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user