Skip to content

Commit

Permalink
Add way to hide minutes or plays on / artist list
Browse files Browse the repository at this point in the history
  • Loading branch information
fsktom committed Oct 20, 2024
1 parent 3b2734b commit cabd0e8
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 50 deletions.
39 changes: 18 additions & 21 deletions endsong_web/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

62 changes: 46 additions & 16 deletions endsong_web/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,34 +170,61 @@ impl<'de> Deserialize<'de> for Sorting {
}
}
}

/// Whether to show minutes, plays or both
#[derive(Debug)]
enum Show {
/// Show plays
Plays,
/// Show minutes
Minutes,
/// Show minutes and plays
Both,
}
impl std::fmt::Display for Show {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Plays => write!(f, "plays"),
Self::Minutes => write!(f, "minutes"),
Self::Both => write!(f, "both"),
}
}
}
impl<'de> Deserialize<'de> for Show {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;

match s.as_str() {
"minutes" => Ok(Self::Minutes),
"plays" => Ok(Self::Plays),
_ => Ok(Self::Both),
}
}
}

/// Form used in [`top_artists`]
#[derive(Deserialize)]
pub struct TopArtistsForm {
/// Number of artists to display
top: Option<usize>,
/// Way to sort the artits
sort: Sorting,
/// Whether to display minutes, plays or both
show: Show,
}
/// [`Template`] for [`top_artists`]
///
/// ```rinja
/// {% for (artist, info) in artists %}
/// <li class="ml-7">
/// <a href="{{ info.link }}"
/// >{{ artist }} | {{ info.plays }} play{{ info.plays|pluralize }} | {{
/// info.duration.num_minutes() }} minute{{
/// info.duration.num_minutes()|pluralize }}</a
/// >
/// </li>
/// {% endfor %}
/// ```
#[derive(Template)]
#[template(in_doc = true, ext = "html", print = "none")]
#[template(path = "top_artists.html", print = "none")]
struct TopArtistsTempate {
/// List of [`Artist`]s with their info
artists: Vec<(Artist, ArtistInfo)>,
/// Whether to display minutes, plays or both of the artists
show: Show,
}
/// POST `/top_artists[?top=usize][&sort=String]`
/// POST `/top_artists[?top=usize][&sort=String][&show=Show]`
#[expect(
clippy::missing_panics_doc,
reason = "unwraps which should never panic"
Expand All @@ -209,7 +236,8 @@ pub async fn top_artists(
debug!(
top = form.top,
sort = form.sort.to_string(),
"POST /top_artists[?top=usize][&sort=Sorting]"
show = form.show.to_string(),
"POST /top_artists[?top=usize][&sort=Sorting][&show=Show]"
);

let top = form.top.unwrap_or(10000);
Expand Down Expand Up @@ -243,7 +271,9 @@ pub async fn top_artists(
.collect(),
};

TopArtistsTempate { artists }
let show = form.show;

TopArtistsTempate { artists, show }
}

/// Helper trait for encoding aspect names to make them work in URLs
Expand Down
3 changes: 1 addition & 2 deletions endsong_web/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ async fn main() {
.route("/styles.css", get(r#static::styles))
.route("/htmx.js", get(r#static::htmx))
.route("/plotly.js", get(r#static::plotly))
.route("/artists", get(artists::base))
.route("/artists", post(artists::elements))
.route("/artists", get(artists::base).post(artists::elements))
.route("/artist/:artist_name", get(artist::base))
.route("/artist/:artist_name/albums", post(artist::albums))
.route("/artist/:artist_name/songs", post(artist::songs))
Expand Down
59 changes: 48 additions & 11 deletions endsong_web/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,47 @@
>
<h2 class="self-center text-xl font-semibold">Artists</h2>
<form class="flex items-center justify-center gap-4">
<label for="sorting">Sort by:</label>
<label>Show:</label>
<div class="flex gap-1">
<input
type="radio"
name="show"
value="plays"
id="show-plays"
hx-target="#artists"
hx-trigger="click"
hx-include="input[name='sort']:checked, input[name='top']:checked"
hx-post="/top_artists"
/><label for="show-plays">Plays</label>
</div>
<div class="flex gap-1">
<input
type="radio"
name="show"
value="minutes"
id="show-minutes"
hx-target="#artists"
hx-trigger="click"
hx-include="input[name='sort']:checked, input[name='top']:checked"
hx-post="/top_artists"
/><label for="show-minutes">Minutes</label>
</div>
<div class="flex gap-1">
<input
type="radio"
name="show"
value="both"
id="show-both"
hx-target="#artists"
hx-trigger="click"
hx-include="input[name='sort']:checked, input[name='top']:checked"
hx-post="/top_artists"
checked
/><label for="show-both">Both</label>
</div>
</form>
<form class="flex items-center justify-center gap-4">
<label>Sort by:</label>
<div class="flex gap-1">
<input
type="radio"
Expand All @@ -25,7 +65,7 @@ <h2 class="self-center text-xl font-semibold">Artists</h2>
checked
hx-target="#artists"
hx-trigger="click"
hx-include="next input[name='top']:checked"
hx-include="input[name='top']:checked, input[name='show']:checked"
hx-post="/top_artists"
/><label for="sorting-plays">Plays</label>
</div>
Expand All @@ -37,7 +77,7 @@ <h2 class="self-center text-xl font-semibold">Artists</h2>
id="sorting-minutes"
hx-target="#artists"
hx-trigger="click"
hx-include="next input[name='top']:checked"
hx-include="input[name='top']:checked, input[name='show']:checked"
hx-post="/top_artists"
/><label for="sorting-minutes">Minutes</label>
</div>
Expand All @@ -52,7 +92,7 @@ <h2 class="self-center text-xl font-semibold">Artists</h2>
checked
hx-target="#artists"
hx-trigger="click, load"
hx-include="previous input[name='sort']:checked"
hx-include="input[name='sort']:checked, input[name='show']:checked"
hx-post="/top_artists"
/><label for="top-artists-10">Top 10</label>
</div>
Expand All @@ -64,7 +104,7 @@ <h2 class="self-center text-xl font-semibold">Artists</h2>
id="top-artists-25"
hx-target="#artists"
hx-trigger="click"
hx-include="previous input[name='sort']:checked"
hx-include="input[name='sort']:checked, input[name='show']:checked"
hx-post="/top_artists"
/><label for="top-artists-25">Top 25</label>
</div>
Expand All @@ -76,7 +116,7 @@ <h2 class="self-center text-xl font-semibold">Artists</h2>
id="top-artists-50"
hx-target="#artists"
hx-trigger="click"
hx-include="previous input[name='sort']:checked"
hx-include="input[name='sort']:checked, input[name='show']:checked"
hx-post="/top_artists"
/><label for="top-artists-50">Top 50</label>
</div>
Expand All @@ -88,15 +128,12 @@ <h2 class="self-center text-xl font-semibold">Artists</h2>
id="top-artists-all"
hx-target="#artists"
hx-trigger="click"
hx-include="previous input[name='sort']:checked"
hx-include="input[name='sort']:checked, input[name='show']:checked"
hx-post="/top_artists"
/><label for="top-artists-all">All</label>
</div>
</form>
<ol class="list-decimal" id="artists">
<!-- so that tailwind saves ml-7 class used in .rs .... -->
<li class="ml-7"></li>
</ol>
<ol class="list-decimal" id="artists"></ol>
</article>
</section>
{% endblock %}
20 changes: 20 additions & 0 deletions endsong_web/templates/top_artists.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{% for (artist, info) in artists %}
<li class="ml-7">
{% match show %} {% when Show::Both %}
<a href="{{ info.link }}"
>{{ artist }} | {{ info.plays }} play{{ info.plays|pluralize }} |
{{info.duration.num_minutes() }} minute{{
info.duration.num_minutes()|pluralize }}</a
>
{% when Show::Plays %}
<a href="{{ info.link }}"
>{{ artist }} | {{ info.plays }} play{{ info.plays|pluralize }}</a
>
{% when Show::Minutes %}
<a href="{{ info.link }}"
>{{ artist }} | {{info.duration.num_minutes() }} minute{{
info.duration.num_minutes()|pluralize }}</a
>
{% endmatch %}
</li>
{% endfor %}

0 comments on commit cabd0e8

Please sign in to comment.