context menu implementation testing

This commit is contained in:
2026-04-10 13:54:56 -04:00
parent ec0c6a3487
commit 4325280020
7 changed files with 101 additions and 142 deletions
@@ -1,64 +1,63 @@
use super::props::*;
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_primitives::context_menu::{
self, ContextMenuContentProps, ContextMenuItemProps, ContextMenuProps, ContextMenuTriggerProps, const CONTEXT_MENU_CSS: Asset = asset!("./style.scss");
};
#[component] #[component]
pub fn ContextMenu(props: ContextMenuProps) -> Element { pub fn ContextMenu(props: ContextMenuProps) -> Element
rsx! { {
document::Link { rel: "stylesheet", href: asset!("./style.css") } rsx! {
context_menu::ContextMenu { document::Link { rel: "stylesheet", href: CONTEXT_MENU_CSS }
disabled: props.disabled, {props.children}
open: props.open, }
default_open: props.default_open,
on_open_change: props.on_open_change,
roving_loop: props.roving_loop,
attributes: props.attributes,
{props.children}
}
}
} }
#[component] #[component]
pub fn ContextMenuTrigger(props: ContextMenuTriggerProps) -> Element { pub fn ContextMenuTrigger(props: ContextMenuTriggerProps) -> Element
rsx! { {
context_menu::ContextMenuTrigger { rsx! {
padding: "20px", div{
background: "var(--primary-color)", class: "contextMenuTrigger",
border: "1px dashed var(--primary-color-6)", oncontextmenu: move|e|{
border_radius: ".5rem",
cursor: "context-menu", },
user_select: "none", {props.children}
text_align: "center", }
attributes: props.attributes, }
{props.children}
}
}
} }
#[component] #[component]
pub fn ContextMenuContent(props: ContextMenuContentProps) -> Element { pub fn ContextMenuContent(props: ContextMenuContentProps) -> Element
rsx! { {
context_menu::ContextMenuContent { rsx! {
class: "context-menu-content", div{
id: props.id, class: "contextMenuContent",
attributes: props.attributes, {props.children}
{props.children} }
} }
}
} }
#[component] #[component]
pub fn ContextMenuItem(props: ContextMenuItemProps) -> Element { pub fn ContextMenuItem(props: ContextMenuItemProps) -> Element
rsx! { {
context_menu::ContextMenuItem { rsx! {
class: "context-menu-item", div {
disabled: props.disabled, class: "contextMenuItem",
value: props.value, onclick: move |_|{
index: props.index, props.on_select.call(props.value.clone());
on_select: props.on_select, },
attributes: props.attributes, div {
{props.children} class: "content",
} {props.children}
} }
}
}
}
#[component]
pub fn ContextMenuNestedContent(props: ContextMenuNestedProps) -> Element
{
rsx! {
{props.children}
}
} }
@@ -1,2 +1,3 @@
mod component; mod component;
mod props;
pub use component::*; pub use component::*;
@@ -0,0 +1,33 @@
use dioxus::prelude::*;
#[derive(Props, Clone, PartialEq)]
pub struct ContextMenuProps
{
pub children: Element,
}
#[derive(Props, Clone, PartialEq)]
pub struct ContextMenuItemProps
{
pub value: String,
pub on_select: EventHandler<String>,
pub children: Element,
}
#[derive(Props, Clone, PartialEq)]
pub struct ContextMenuTriggerProps
{
pub children: Element,
}
#[derive(Props, Clone, PartialEq)]
pub struct ContextMenuContentProps
{
pub children: Element,
}
#[derive(Props, Clone, PartialEq)]
pub struct ContextMenuNestedProps
{
pub children: Element,
}
@@ -1,71 +0,0 @@
.context-menu-content {
z-index: 1000;
min-width: 220px;
padding: 0.25rem;
border-radius: 0.5rem;
background: var(--dark, var(--primary-color-5))
var(--light, var(--primary-color));
box-shadow: inset 0 0 0 1px var(--dark, var(--primary-color-7))
var(--light, var(--primary-color-6));
opacity: 0;
pointer-events: none;
will-change: transform, opacity;
}
.context-menu-content[data-state="closed"] {
animation: context-menu-animate-out 150ms ease-in forwards;
}
@keyframes context-menu-animate-out {
0% {
opacity: 1;
transform: scale(1) translateY(0);
}
100% {
opacity: 0;
transform: scale(0.95) translateY(-2px);
}
}
.context-menu-content[data-state="open"] {
animation: context-menu-animate-in 150ms ease-out forwards;
}
@keyframes context-menu-animate-in {
0% {
opacity: 0;
transform: scale(0.95) translateY(-2px);
}
100% {
opacity: 1;
transform: scale(1) translateY(0);
}
}
.context-menu-item {
display: flex;
align-items: center;
padding: 8px 12px;
border-radius: calc(0.5rem - 0.25rem);
color: var(--secondary-color-4);
cursor: pointer;
font-size: 14px;
outline: none;
transition: background-color 100ms ease-out;
user-select: none;
}
.context-menu-item[data-disabled="true"] {
color: var(--secondary-color-5);
cursor: not-allowed;
}
.context-menu-item:hover:not([data-disabled="true"]),
.context-menu-item:focus-visible {
background: var(--light, var(--primary-color-4))
var(--dark, var(--primary-color-7));
color: var(--light, var(--secondary-color-1))
var(--dark, var(--secondary-color-4));
}
+13 -16
View File
@@ -1,7 +1,5 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_primitives::context_menu::{ use dioxus_primitives::context_menu::{ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger};
ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger,
};
use tonic::{Response, Status}; use tonic::{Response, Status};
use web_sys::window; use web_sys::window;
@@ -13,13 +11,15 @@ use crate::{
}, },
}; };
pub struct MediaClassChangeEvent { pub struct MediaClassChangeEvent
{
pub index: usize, pub index: usize,
pub class: String, 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 index: usize,
pub on_class_changed: Option<EventHandler<MediaClassChangeEvent>>, pub on_class_changed: Option<EventHandler<MediaClassChangeEvent>>,
@@ -27,14 +27,16 @@ pub struct MediaItemProps {
} }
#[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",
_ => "", _ => "",
@@ -42,13 +44,6 @@ pub fn MediaItem(props: MediaItemProps) -> Element {
let url = item.media_url; let url = item.media_url;
let download = format!("{HOST}{url}"); let download = format!("{HOST}{url}");
// class_signal.set(match class
// {
// 1 => "blur",
// 2 => "secret",
// _ => "",
// });
return rsx! { return rsx! {
ContextMenu{ ContextMenu{
ContextMenuTrigger{ ContextMenuTrigger{
@@ -181,7 +176,8 @@ 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 { },
@@ -196,7 +192,8 @@ 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 -2
View File
@@ -1,5 +1,5 @@
pub mod basic; pub mod basic;
// mod context_menu; mod context_menu;
mod icons; mod icons;
mod media_grid; mod media_grid;
mod media_item; mod media_item;
@@ -9,7 +9,7 @@ mod notif;
mod pagination; mod pagination;
mod passkey; mod passkey;
mod search; mod search;
// pub use context_menu::*; pub use context_menu::*;
pub use media_grid::*; pub use media_grid::*;
pub use media_item::*; pub use media_item::*;
pub use metrics_token::*; pub use metrics_token::*;