use leptos::*; use leptos_icons::*; use crate::songdata::SongData; use crate::models::{Album, Artist}; const LIKE_DISLIKE_BTN_SIZE: &str = "2em"; #[component] pub fn SongList(songs: MaybeSignal>) -> impl IntoView { view! { { songs.with(|songs| { let mut first_song = true; songs.iter().map(|song| { let playing = first_song.into(); first_song = false; let extra = Option::<()>::None; view! { } }).collect::>() }) }
} } #[component] pub fn SongListExtra(songs: MaybeSignal>) -> impl IntoView where T: Clone + IntoView + 'static { view! { { songs.with(|songs| { let mut first_song = true; songs.iter().map(|(song, extra)| { let playing = first_song.into(); first_song = false; view! { } }).collect::>() }) }
} } #[component] pub fn SongListItem(song: SongData, song_playing: MaybeSignal, extra: Option) -> impl IntoView where T: IntoView + 'static { let liked = create_rw_signal(song.like_dislike.map(|(liked, _)| liked).unwrap_or(false)); let disliked = create_rw_signal(song.like_dislike.map(|(_, disliked)| disliked).unwrap_or(false)); view! {

{song.title}

{format!("{}:{:02}", song.duration / 60, song.duration % 60)} {extra.map(|extra| view! { {extra} })} } } /// Display the song's image, with an overlay if the song is playing /// When the song list item is hovered, the overlay will show the play button #[component] fn SongImage(image_path: String, song_playing: MaybeSignal) -> impl IntoView { view! { {if song_playing.get() { view! { }.into_view() } else { view! { }.into_view() }} } } /// Displays a song's artists, with links to their artist pages #[component] fn SongArtists(artists: Vec) -> impl IntoView { let num_artists = artists.len() as isize; artists.iter().enumerate().map(|(i, artist)| { let i = i as isize; view! { { if let Some(id) = artist.id { view! { {artist.name.clone()} }.into_view() } else { view! { {artist.name.clone()} }.into_view() } } {if i < num_artists - 2 { ", " } else if i == num_artists - 2 { " & " } else { "" }} } }).collect::>() } /// Display a song's album, with a link to the album page #[component] fn SongAlbum(album: Option) -> impl IntoView { album.as_ref().map(|album| { view! { { if let Some(id) = album.id { view! { {album.title.clone()} }.into_view() } else { view! { {album.title.clone()} }.into_view() } } } }) } /// Display like and dislike buttons for a song, and indicate if the song is liked or disliked #[component] fn SongLikeDislike(liked: RwSignal, disliked: RwSignal) -> impl IntoView { let like_icon = Signal::derive(move || { if liked.get() { icondata::TbThumbUpFilled } else { icondata::TbThumbUp } }); let dislike_icon = Signal::derive(move || { if disliked.get() { icondata::TbThumbDownFilled } else { icondata::TbThumbDown } }); let like_class = MaybeProp::derive(move || { if liked.get() { Some(TextProp::from("controlbtn")) } else { Some(TextProp::from("controlbtn hide-until-hover")) } }); let dislike_class = MaybeProp::derive(move || { if disliked.get() { Some(TextProp::from("controlbtn hmirror")) } else { Some(TextProp::from("controlbtn hmirror hide-until-hover")) } }); let toggle_like = move |_| { liked.set(!liked.get_untracked()); disliked.set(disliked.get_untracked() && !liked.get_untracked()); }; let toggle_dislike = move |_| { disliked.set(!disliked.get_untracked()); liked.set(liked.get_untracked() && !disliked.get_untracked()); }; view! { } }