feat: use gallery images for package card banners
This commit is contained in:
parent
cd122e877e
commit
13e52ab3ec
6 changed files with 44 additions and 6 deletions
|
|
@ -102,6 +102,10 @@ impl Component for PackageCard {
|
|||
let provider = self.item.provider;
|
||||
let package_type = self.package_type.clone();
|
||||
let icon_url = self.item.icon_url.clone();
|
||||
let banner = match self.item.banner_url.clone() {
|
||||
Some(url) => PackageBanner::new(Some(url), BANNER_H).sharp(),
|
||||
None => PackageBanner::new(icon_url.clone(), BANNER_H),
|
||||
};
|
||||
let cluster_id = self.cluster_id;
|
||||
|
||||
let a11y_id = use_a11y();
|
||||
|
|
@ -134,7 +138,7 @@ impl Component for PackageCard {
|
|||
.height(Size::px(BANNER_H))
|
||||
.overflow(Overflow::Clip)
|
||||
// No installed badge, the control at the foot of the card already states it
|
||||
.child(PackageBanner::new(icon_url.clone(), BANNER_H).backdrop_only()),
|
||||
.child(banner.backdrop_only()),
|
||||
)
|
||||
.child(
|
||||
rect()
|
||||
|
|
|
|||
|
|
@ -289,6 +289,7 @@ pub(crate) struct PackageBanner {
|
|||
icon_url: Option<String>,
|
||||
height: f32,
|
||||
backdrop_only: bool,
|
||||
sharp: bool,
|
||||
key: DiffKey,
|
||||
}
|
||||
|
||||
|
|
@ -298,6 +299,7 @@ impl PackageBanner {
|
|||
icon_url,
|
||||
height,
|
||||
backdrop_only: false,
|
||||
sharp: false,
|
||||
key: DiffKey::None,
|
||||
}
|
||||
}
|
||||
|
|
@ -307,6 +309,11 @@ impl PackageBanner {
|
|||
self.backdrop_only = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn sharp(mut self) -> Self {
|
||||
self.sharp = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyExt for PackageBanner {
|
||||
|
|
@ -319,7 +326,7 @@ impl Component for PackageBanner {
|
|||
fn render(&self) -> impl IntoElement {
|
||||
let h = self.height;
|
||||
let icon = h * 0.62;
|
||||
let query = use_cached_image(self.icon_url.clone(), 512);
|
||||
let query = use_cached_image(self.icon_url.clone(), if self.sharp { 384 } else { 256 });
|
||||
let loaded = loaded_image(self.icon_url.as_deref(), &query);
|
||||
|
||||
let banner = rect()
|
||||
|
|
@ -350,7 +357,7 @@ impl Component for PackageBanner {
|
|||
)
|
||||
.layer(Layer::Relative(1)),
|
||||
)
|
||||
.child(
|
||||
.maybe_child((!self.sharp).then(|| {
|
||||
rect()
|
||||
.position(Position::new_absolute().top(0.).left(0.))
|
||||
.width(Size::fill())
|
||||
|
|
@ -358,8 +365,9 @@ impl Component for PackageBanner {
|
|||
.backdrop_blur(12.)
|
||||
.background(BANNER_BG.with_a(120))
|
||||
.overflow(Overflow::Clip)
|
||||
.layer(Layer::Relative(3)),
|
||||
)
|
||||
.layer(Layer::Relative(3))
|
||||
.into_element()
|
||||
}))
|
||||
.maybe_child((!backdrop_only).then(|| {
|
||||
rect()
|
||||
.width(Size::px(icon))
|
||||
|
|
|
|||
|
|
@ -488,6 +488,8 @@ struct CfMod {
|
|||
struct CfScreenshot {
|
||||
url: String,
|
||||
#[serde(default)]
|
||||
thumbnail_url: Option<String>,
|
||||
#[serde(default)]
|
||||
title: Option<String>,
|
||||
}
|
||||
|
||||
|
|
@ -629,6 +631,12 @@ impl From<CfMod> for ProjectSummary {
|
|||
.logo
|
||||
.and_then(|l| l.thumbnail_url.or(l.url))
|
||||
.filter(|s| !s.is_empty()),
|
||||
banner_url: m
|
||||
.screenshots
|
||||
.into_iter()
|
||||
.next()
|
||||
.map(|s| s.thumbnail_url.filter(|t| !t.is_empty()).unwrap_or(s.url))
|
||||
.filter(|s| !s.is_empty()),
|
||||
downloads: m.download_count,
|
||||
created: m.date_created,
|
||||
updated: m.date_modified,
|
||||
|
|
@ -668,6 +676,7 @@ impl CfMod {
|
|||
.map(|s| GalleryImage {
|
||||
url: s.url,
|
||||
title: s.title.filter(|t| !t.is_empty()),
|
||||
featured: false,
|
||||
})
|
||||
.collect(),
|
||||
license: None,
|
||||
|
|
|
|||
|
|
@ -130,6 +130,10 @@ impl PackageProvider for ModrinthProvider {
|
|||
game_versions: Vec<String>,
|
||||
downloads: u64,
|
||||
icon_url: Option<String>,
|
||||
#[serde(default)]
|
||||
featured_gallery: Option<String>,
|
||||
#[serde(default)]
|
||||
gallery: Vec<String>,
|
||||
date_created: DateTime<Utc>,
|
||||
date_modified: DateTime<Utc>,
|
||||
}
|
||||
|
|
@ -152,6 +156,10 @@ impl PackageProvider for ModrinthProvider {
|
|||
summary: h.description,
|
||||
author: h.author,
|
||||
icon_url: h.icon_url,
|
||||
banner_url: h
|
||||
.featured_gallery
|
||||
.or_else(|| h.gallery.into_iter().next())
|
||||
.filter(|url| !url.is_empty()),
|
||||
downloads: h.downloads,
|
||||
created: h.date_created,
|
||||
updated: h.date_modified,
|
||||
|
|
@ -534,6 +542,8 @@ struct ModrinthGalleryItem {
|
|||
raw_url: Option<String>,
|
||||
#[serde(default)]
|
||||
title: Option<String>,
|
||||
#[serde(default)]
|
||||
featured: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
|
@ -627,6 +637,7 @@ impl ModrinthProject {
|
|||
.map(|g| GalleryImage {
|
||||
url: g.raw_url.filter(|url| !url.is_empty()).unwrap_or(g.url),
|
||||
title: g.title.filter(|t| !t.is_empty()),
|
||||
featured: g.featured,
|
||||
})
|
||||
.collect(),
|
||||
license,
|
||||
|
|
|
|||
|
|
@ -70,6 +70,8 @@ pub struct ProjectSummary {
|
|||
pub summary: String,
|
||||
pub author: String,
|
||||
pub icon_url: Option<String>,
|
||||
#[serde(default)]
|
||||
pub banner_url: Option<String>,
|
||||
pub downloads: u64,
|
||||
pub created: DateTime<Utc>,
|
||||
pub updated: DateTime<Utc>,
|
||||
|
|
@ -103,6 +105,8 @@ pub struct ProjectMember {
|
|||
pub struct GalleryImage {
|
||||
pub url: String,
|
||||
pub title: Option<String>,
|
||||
#[serde(default)]
|
||||
pub featured: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
|
|
|||
|
|
@ -376,7 +376,9 @@ async fn apply_project_cover(
|
|||
fn cover_url(project: &ProjectDetail) -> Option<String> {
|
||||
project
|
||||
.gallery
|
||||
.first()
|
||||
.iter()
|
||||
.find(|image| image.featured)
|
||||
.or_else(|| project.gallery.first())
|
||||
.map(|image| image.url.clone())
|
||||
.or_else(|| project.icon_url.clone())
|
||||
.filter(|url| !url.is_empty())
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue