WIP ContextMenu Renderer
This commit is contained in:
@@ -161,6 +161,7 @@ form {
|
|||||||
.contextMenu {
|
.contextMenu {
|
||||||
backdrop-filter: blur(10px) brightness(0.5) grayscale(1);
|
backdrop-filter: blur(10px) brightness(0.5) grayscale(1);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
.itemList {
|
.itemList {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -2,15 +2,58 @@ use core::str;
|
|||||||
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Props)]
|
pub mod props {
|
||||||
pub struct ContextMenuProps {
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone, Props)]
|
||||||
|
pub struct ContextMenu {
|
||||||
pub top: f64,
|
pub top: f64,
|
||||||
pub left: f64,
|
pub left: f64,
|
||||||
pub items: Option<Vec<Element>>,
|
pub items: Option<Vec<ContextMenuItem>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone, Props, Default)]
|
||||||
|
pub struct ContextMenuItem {
|
||||||
|
pub name: String,
|
||||||
|
pub sub_items: Option<Vec<ContextMenuItem>>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default)]
|
||||||
|
pub struct ContextMenuRenderer {
|
||||||
|
pub menu: Signal<Option<props::ContextMenu>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContextMenuRenderer {
|
||||||
|
pub fn close(&mut self) {
|
||||||
|
self.menu.set(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self) -> Element {
|
||||||
|
if let Some(menu) = self.menu.cloned() {
|
||||||
|
rsx! {
|
||||||
|
ContextMenu{
|
||||||
|
items: menu.items,
|
||||||
|
left: menu.left,
|
||||||
|
top: menu.top
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rsx! {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn ContextMenu(props: ContextMenuProps) -> Element {
|
pub fn ContextMenuRoot() -> Element {
|
||||||
|
let renderer = use_context::<ContextMenuRenderer>();
|
||||||
|
rsx! {
|
||||||
|
{renderer.render()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn ContextMenu(props: props::ContextMenu) -> Element {
|
||||||
let menu_items = if let Some(items) = props.items {
|
let menu_items = if let Some(items) = props.items {
|
||||||
rsx! {
|
rsx! {
|
||||||
ItemList { items }
|
ItemList { items }
|
||||||
@@ -29,23 +72,22 @@ pub fn ContextMenu(props: ContextMenuProps) -> Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn ItemList(items: Vec<Element>) -> Element {
|
fn ItemList(items: Vec<props::ContextMenuItem>) -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
div{
|
div{
|
||||||
class: "itemList",
|
class: "itemList",
|
||||||
{items.iter().map(|e| rsx!{{e}}) }
|
{items.iter().map(|e| rsx!{
|
||||||
|
ContextMenuItem{
|
||||||
|
name: e.name.clone(),
|
||||||
|
sub_items: e.sub_items.clone()
|
||||||
|
}
|
||||||
|
})}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Props)]
|
|
||||||
pub struct ContextMenuItemProps {
|
|
||||||
pub name: String,
|
|
||||||
pub sub_items: Option<Vec<Element>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn ContextMenuItem(props: ContextMenuItemProps) -> Element {
|
fn ContextMenuItem(props: props::ContextMenuItem) -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
div{
|
div{
|
||||||
class: "contextItem",
|
class: "contextItem",
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ use dioxus::prelude::*;
|
|||||||
use tonic::IntoRequest;
|
use tonic::IntoRequest;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
components::{ContextMenu, ContextMenuItem, MediaItem},
|
components::{
|
||||||
|
ContextMenuRenderer, MediaItem,
|
||||||
|
props::{ContextMenu, ContextMenuItem},
|
||||||
|
},
|
||||||
rpc::{aoba::PageFilter, get_rpc_client},
|
rpc::{aoba::PageFilter, get_rpc_client},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -46,36 +49,32 @@ pub fn MediaGrid(props: MediaGridProps) -> Element {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let mut context_menu: Signal<Element> = use_signal(|| rsx! {});
|
let mut ct_renderer = use_context::<ContextMenuRenderer>();
|
||||||
|
|
||||||
let oncontext = move |event: Event<MouseData>| {
|
let oncontext = move |event: Event<MouseData>| {
|
||||||
event.prevent_default();
|
event.prevent_default();
|
||||||
let data = event.data();
|
let data = event.data();
|
||||||
let pos = data.coordinates().client();
|
let pos = data.coordinates().client();
|
||||||
let left = pos.x;
|
let left = pos.x;
|
||||||
let top = pos.y;
|
let top = pos.y;
|
||||||
context_menu.set(rsx! {
|
ct_renderer.menu.set(Some(ContextMenu {
|
||||||
ContextMenu{
|
|
||||||
left: left,
|
left: left,
|
||||||
top: top,
|
top: top,
|
||||||
items: vec![
|
items: Some(vec![
|
||||||
rsx!{
|
ContextMenuItem {
|
||||||
ContextMenuItem{
|
name: "Details".to_string(),
|
||||||
name: "Details"
|
..Default::default()
|
||||||
}
|
|
||||||
},
|
},
|
||||||
rsx!{
|
ContextMenuItem {
|
||||||
ContextMenuItem{
|
name: "Download".to_string(),
|
||||||
name: "Download"
|
..Default::default()
|
||||||
}
|
|
||||||
},
|
},
|
||||||
rsx!{
|
ContextMenuItem {
|
||||||
ContextMenuItem{
|
name: "Delete".to_string(),
|
||||||
name: "Delete"
|
..Default::default()
|
||||||
}
|
|
||||||
},
|
},
|
||||||
]
|
]),
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match media_result.cloned() {
|
match media_result.cloned() {
|
||||||
@@ -83,14 +82,10 @@ pub fn MediaGrid(props: MediaGridProps) -> Element {
|
|||||||
Ok(result) => rsx! {
|
Ok(result) => rsx! {
|
||||||
div {
|
div {
|
||||||
class: "mediaGrid",
|
class: "mediaGrid",
|
||||||
onclick: move |_e| {
|
|
||||||
context_menu.set(rsx!{});
|
|
||||||
},
|
|
||||||
{result.items.iter().map(|itm| rsx!{
|
{result.items.iter().map(|itm| rsx!{
|
||||||
MediaItem { item: Some(itm.clone()), oncontextmenu: oncontext }
|
MediaItem { item: Some(itm.clone()), oncontextmenu: oncontext }
|
||||||
})},
|
})},
|
||||||
}
|
}
|
||||||
{context_menu.cloned()}
|
|
||||||
},
|
},
|
||||||
Err(msg) => rsx! {
|
Err(msg) => rsx! {
|
||||||
div {
|
div {
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
use crate::{Route, components::Navbar, contexts::AuthContext, views::Login};
|
use crate::{
|
||||||
|
Route,
|
||||||
|
components::{ContextMenuRoot, Navbar},
|
||||||
|
contexts::AuthContext,
|
||||||
|
views::Login,
|
||||||
|
};
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn MainLayout() -> Element {
|
pub fn MainLayout() -> Element {
|
||||||
@@ -13,6 +18,7 @@ pub fn MainLayout() -> Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return rsx! {
|
return rsx! {
|
||||||
|
ContextMenuRoot { }
|
||||||
Navbar {}
|
Navbar {}
|
||||||
div { id: "content", Outlet::<Route> {} }
|
div { id: "content", Outlet::<Route> {} }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ use contexts::AuthContext;
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use route::Route;
|
use route::Route;
|
||||||
|
|
||||||
|
use crate::components::ContextMenuRenderer;
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
pub const HOST: &'static str = "http://localhost:8081";
|
pub const HOST: &'static str = "http://localhost:8081";
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
@@ -31,6 +33,7 @@ fn main() {
|
|||||||
#[component]
|
#[component]
|
||||||
fn App() -> Element {
|
fn App() -> Element {
|
||||||
let _auth_state = use_context_provider(|| AuthContext::new());
|
let _auth_state = use_context_provider(|| AuthContext::new());
|
||||||
|
let _renderer = use_context_provider(|| ContextMenuRenderer::default());
|
||||||
rsx! {
|
rsx! {
|
||||||
document::Link { rel: "icon", href: FAVICON }
|
document::Link { rel: "icon", href: FAVICON }
|
||||||
document::Link { rel: "preconnect", href: "https://fonts.googleapis.com" }
|
document::Link { rel: "preconnect", href: "https://fonts.googleapis.com" }
|
||||||
@@ -41,6 +44,7 @@ fn App() -> Element {
|
|||||||
rel: "stylesheet",
|
rel: "stylesheet",
|
||||||
href: "https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap",
|
href: "https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap",
|
||||||
}
|
}
|
||||||
Router::<Route> {}
|
|
||||||
|
Router::<Route> { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user