feat: featured gallery
This commit is contained in:
parent
6634e0648e
commit
2d02f64239
6 changed files with 66 additions and 24 deletions
|
|
@ -13,7 +13,7 @@ function includes<T, TArray extends T>(list: { includes: (arg0: TArray) => boole
|
|||
|
||||
export function PackageGrid({ items, provider }: { items: Array<SearchResult>; provider: Provider }) {
|
||||
return (
|
||||
<div className="grid grid-cols-2 xl:grid-cols-3 gap-2">
|
||||
<div className="grid grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-2">
|
||||
{items.map(item => (
|
||||
<PackageItem key={item.project_id} {...item} provider={provider} />
|
||||
))}
|
||||
|
|
@ -45,11 +45,11 @@ export function PackageItem({ provider, ...item }: SearchResult & { provider: Pr
|
|||
<img alt={`Icon for ${item.title}`} className="absolute z-0 max-w-none w-7/6 opacity-50 blur-xl" src={item.icon_url} />
|
||||
<img
|
||||
alt={`Icon for ${item.title}`}
|
||||
className="relative z-1 aspect-ratio-square rounded-md image-render-auto w-2/5"
|
||||
className="relative z-1 aspect-ratio-square rounded-lg image-render-auto h-5/6"
|
||||
src={item.icon_url}
|
||||
/>
|
||||
</Show>
|
||||
<Tooltip text={loaders.map(upperFirst).join(', ')}>
|
||||
<Tooltip className="bg-component-bg-disabled" text={loaders.map(upperFirst).join(', ')}>
|
||||
<Focusable>
|
||||
<div className="flex flex-col rounded-full bg-component-bg/70 border-component-border/70 border p-1 absolute top-0 right-0 m-2">
|
||||
{loaders.toSpliced(loaders.length > 3 ? 2 : 3).map(loader => <LoaderIcon className="w-5 m-1" key={loader} loader={loader} />)}
|
||||
|
|
|
|||
|
|
@ -27,19 +27,20 @@ function RouteComponent() {
|
|||
|
||||
function Featured() {
|
||||
// const context = useBrowserContext();
|
||||
const [provider, slug] = useMemo<[Provider, string]>(() => ['Modrinth', 'sodium'], []);
|
||||
const [provider, slug] = useMemo<[Provider, string]>(() => ['Modrinth', 'iris'], []);
|
||||
const featuredPackage = usePackageData(provider, slug, {}, 'getFeatured');
|
||||
const navigate = useNavigate();
|
||||
|
||||
const featuredImageIndex = useMemo(() => featuredPackage.data?.gallery.findIndex(image => image.featured), [featuredPackage.data]);
|
||||
const [selectedImage, setSelectedImage] = useState(featuredImageIndex ?? 0);
|
||||
return (
|
||||
<Show when={featuredPackage.isSuccess}>
|
||||
<div className="flex flex-col gap-y-1">
|
||||
<h5 className="ml-2">Featured</h5>
|
||||
<div className="w-full flex flex-row overflow-hidden rounded-lg bg-page-elevated">
|
||||
<h5 className="ml-2 uppercase opacity-60">Featured</h5>
|
||||
<div className="w-full flex flex-col lg:flex-row overflow-hidden rounded-lg bg-page-elevated">
|
||||
<div className="w-full p-1">
|
||||
<img alt="thumbnail" className="aspect-ratio-video h-full rounded-md object-cover object-center" src={featuredPackage.data?.icon_url ?? ''} />
|
||||
<img alt="thumbnail" className="aspect-video h-full w-full rounded-md object-cover object-center" src={featuredPackage.data?.gallery[selectedImage].url} />
|
||||
</div>
|
||||
<div className="max-w-84 min-w-52 flex flex-col gap-y-1 p-4">
|
||||
<div className="max-w-64 min-w-52 flex flex-col gap-y-1 p-4">
|
||||
<h2>{featuredPackage.data?.name}</h2>
|
||||
|
||||
<Show when={false}>
|
||||
|
|
@ -49,7 +50,20 @@ function Featured() {
|
|||
</div>
|
||||
</Show>
|
||||
|
||||
<p className="mt-1 flex-1 leading-normal">{featuredPackage.data?.short_desc}</p>
|
||||
<p className="my-1 flex-1 leading-normal">{featuredPackage.data?.short_desc}</p>
|
||||
|
||||
<div className="grid grid-cols-3 gap-2 h-full">
|
||||
{featuredPackage.data?.gallery.map(
|
||||
(image, index) => (
|
||||
<img
|
||||
className="aspect-video object-center object-cover rounded-md"
|
||||
key={image.url}
|
||||
onClick={() => setSelectedImage(index)}
|
||||
src={image.url}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row justify-end">
|
||||
<Button color="ghost" onClick={() => navigate({ to: '/app/browser/package/$provider/$slug', params: { provider, slug } })}>
|
||||
|
|
@ -77,7 +91,7 @@ function Lists() {
|
|||
function List({ provider }: { provider: Provider }) {
|
||||
const search = useBrowserSearch(provider, {
|
||||
filters: null,
|
||||
limit: 18 as unknown as bigint,
|
||||
limit: 24 as unknown as bigint,
|
||||
offset: null,
|
||||
query: null,
|
||||
sort: null,
|
||||
|
|
@ -85,7 +99,7 @@ function List({ provider }: { provider: Provider }) {
|
|||
const [expanded, setExpanded] = useState(false);
|
||||
return (
|
||||
<div>
|
||||
<h5 className="uppercase p-3 opacity-60">{provider}</h5>
|
||||
<h5 className="uppercase m-2 opacity-60">{provider}</h5>
|
||||
<div className={`relative overflow-hidden ${expanded ? '' : 'h-128'}`}>
|
||||
{search.isSuccess
|
||||
? <PackageGrid items={search.data.items} provider={provider} />
|
||||
|
|
|
|||
|
|
@ -30,14 +30,14 @@ function RouteComponent() {
|
|||
export function BrowserLayout(props: any) {
|
||||
return (
|
||||
<div className="relative h-full flex flex-1 flex-col items-center gap-2">
|
||||
<div className="h-full w-full max-w-screen-xl flex flex-1 flex-col items-center gap-y-2">
|
||||
<div className="h-full w-full max-w-screen-2xl flex flex-1 flex-col items-center gap-y-2">
|
||||
<div className="grid grid-cols-[220px_auto_220px] w-full gap-x-6">
|
||||
<div />
|
||||
<BrowserToolbar />
|
||||
<div />
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-[220px_auto_220px] w-full max-w-screen-xl gap-x-6 pb-8">
|
||||
<div className="grid grid-cols-[220px_auto_220px] w-full gap-x-6 pb-8">
|
||||
<BrowserCategories />
|
||||
|
||||
<div className="h-full flex flex-col gap-y-4">
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ pub struct ManagedPackage {
|
|||
pub links: PackageLinks,
|
||||
pub status: PackageStatus,
|
||||
pub downloads: usize,
|
||||
pub gallery: Vec<PackageGallery>
|
||||
}
|
||||
|
||||
#[onelauncher_macro::specta]
|
||||
|
|
@ -205,6 +206,16 @@ pub struct PackageDonationUrl {
|
|||
pub url: String,
|
||||
}
|
||||
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct PackageGallery {
|
||||
pub url: String,
|
||||
pub thumbnail_url: String,
|
||||
pub title: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub featured: Option<bool>
|
||||
}
|
||||
|
||||
/// https://api.modrinth.com/v2/tag/donation_platform
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use super::ProviderExt;
|
||||
use crate::api::packages::data::{
|
||||
ManagedPackage, ManagedUser, ManagedVersion, ManagedVersionDependency, ManagedVersionFile, PackageAuthor, PackageDependencyType, PackageDonationUrl, PackageLicense, PackageLinks, PackageReleaseType, PackageSide, PackageStatus, SearchQuery, SearchResult, DEFAULT_LIMIT
|
||||
ManagedPackage, ManagedUser, ManagedVersion, ManagedVersionDependency, ManagedVersionFile, PackageAuthor, PackageDependencyType, PackageDonationUrl, PackageGallery, PackageLicense, PackageLinks, PackageReleaseType, PackageSide, PackageStatus, SearchQuery, SearchResult, DEFAULT_LIMIT
|
||||
};
|
||||
use crate::error::LauncherResult;
|
||||
use crate::utils::http;
|
||||
|
|
@ -363,7 +363,7 @@ struct ModrinthPackage {
|
|||
#[serde(default)]
|
||||
pub license: Option<PackageLicense>,
|
||||
// #[serde(default)]
|
||||
// pub gallery: Vec<Gallery>,
|
||||
pub gallery: Vec<ModrinthGallery>,
|
||||
#[serde(default)]
|
||||
pub status: PackageStatus,
|
||||
}
|
||||
|
|
@ -405,6 +405,7 @@ impl From<ModrinthPackage> for ManagedPackage {
|
|||
},
|
||||
status: value.status,
|
||||
downloads: value.downloads,
|
||||
gallery: value.gallery.into_iter().map(Into::into).collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -532,6 +533,29 @@ impl From<ModrinthUser> for ManagedUser {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ModrinthGallery {
|
||||
#[serde(rename = "raw_url")]
|
||||
pub url: String,
|
||||
#[serde(rename = "url")]
|
||||
pub thumbnail_url: String,
|
||||
pub title: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub featured: Option<bool>
|
||||
}
|
||||
|
||||
impl From<ModrinthGallery> for PackageGallery {
|
||||
fn from(value: ModrinthGallery) -> Self {
|
||||
Self {
|
||||
url: value.url,
|
||||
thumbnail_url: value.thumbnail_url,
|
||||
title: value.title,
|
||||
description: value.description,
|
||||
featured: value.featured
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
enum FacetOperation {
|
||||
NotEq,
|
||||
|
|
|
|||
|
|
@ -110,13 +110,6 @@ body {
|
|||
display: none;
|
||||
}
|
||||
|
||||
h1 { @apply text-[2rem] font-semibold; line-height: 1.5 !important; }
|
||||
h2 { @apply text-[1.5rem] font-semibold; line-height: 1.25 !important; }
|
||||
h3 { @apply text-[1.25rem] font-medium; }
|
||||
h4 { @apply text-[1rem] font-medium; }
|
||||
h5 { @apply text-[0.875rem] text-fg-secondary font-bold uppercase; }
|
||||
h6 { @apply text-[0.75rem] text-fg-secondary font-medium uppercase; }
|
||||
|
||||
code {
|
||||
@apply rounded-md p-2 text-left;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue