@@ -7,6 +7,20 @@ use crate::db::AppSettings;
77use crate :: offline_audio:: { is_song_downloaded, prefetch_song_audio} ;
88use dioxus:: prelude:: * ;
99
10+ fn anchored_menu_style (
11+ anchor_x : f64 ,
12+ anchor_y : f64 ,
13+ menu_width : f64 ,
14+ menu_max_height : f64 ,
15+ ) -> String {
16+ let preferred_top = ( anchor_y + 8.0 ) . max ( 8.0 ) ;
17+ let preferred_left = ( anchor_x - menu_width) . max ( 4.0 ) ;
18+ format ! (
19+ "top: clamp(8px, {:.1}px, calc(100vh - {:.1}px - 8px)); left: clamp(4px, {:.1}px, calc(100vw - {:.1}px - 4px)); max-height: min({:.1}px, calc(100vh - 16px)); overflow-y: auto;" ,
20+ preferred_top, menu_max_height, preferred_left, menu_width, menu_max_height
21+ )
22+ }
23+
1024/// Song row tailored for album detail pages: adds per-song favorite toggle.
1125#[ component]
1226pub fn AlbumSongRow ( song : Song , index : usize , onclick : EventHandler < MouseEvent > ) -> Element {
@@ -20,6 +34,8 @@ pub fn AlbumSongRow(song: Song, index: usize, onclick: EventHandler<MouseEvent>)
2034 let is_favorited = use_signal ( || song. starred . is_some ( ) ) ;
2135 let download_busy = use_signal ( || false ) ;
2236 let mut show_mobile_actions = use_signal ( || false ) ;
37+ let mut menu_x = use_signal ( || 0f64 ) ;
38+ let mut menu_y = use_signal ( || 0f64 ) ;
2339 let initially_downloaded = is_song_downloaded ( & song) ;
2440 let downloaded = use_signal ( move || initially_downloaded) ;
2541 let is_current = now_playing ( )
@@ -357,6 +373,9 @@ pub fn AlbumSongRow(song: Song, index: usize, onclick: EventHandler<MouseEvent>)
357373 aria_label: "Song actions" ,
358374 onclick: move |evt: MouseEvent | {
359375 evt. stop_propagation( ) ;
376+ let coords = evt. client_coordinates( ) ;
377+ menu_x. set( coords. x) ;
378+ menu_y. set( coords. y) ;
360379 show_mobile_actions. set( !show_mobile_actions( ) ) ;
361380 } ,
362381 Icon {
@@ -366,14 +385,15 @@ pub fn AlbumSongRow(song: Song, index: usize, onclick: EventHandler<MouseEvent>)
366385 }
367386 if show_mobile_actions( ) {
368387 div {
369- class: "fixed inset-0 z-20 " ,
388+ class: "fixed inset-0 z-[9998] " ,
370389 onclick: move |evt: MouseEvent | {
371390 evt. stop_propagation( ) ;
372391 show_mobile_actions. set( false ) ;
373392 } ,
374393 }
375394 div {
376- class: "absolute right-0 top-10 z-30 w-44 rounded-xl border border-zinc-700 bg-zinc-900/95 shadow-2xl p-1.5 space-y-1" ,
395+ class: "fixed z-[9999] w-44 rounded-xl border border-zinc-700 bg-zinc-900/95 shadow-2xl p-1.5 space-y-1" ,
396+ style: anchored_menu_style( menu_x( ) , menu_y( ) , 176.0 , 360.0 ) ,
377397 onclick: move |evt: MouseEvent | evt. stop_propagation( ) ,
378398 button {
379399 class: "w-full flex items-center gap-2 px-2.5 py-2 rounded-lg text-sm text-zinc-200 hover:bg-zinc-800/80 transition-colors" ,
0 commit comments