show packages list filter and sorting buttons (#269)

* #267 #262 show packages list filter and sorting buttons

* #262 toggle installed vs all packages filter

* #267 show more packages

---------

Co-authored-by: neil <neil@neils-MacBook-Pro.local>
This commit is contained in:
Neil 2023-03-07 13:18:21 +08:00 committed by GitHub
parent 3c17dd97f9
commit 78a6887374
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 100 additions and 41 deletions

View file

@ -9,42 +9,83 @@
import { installPackage } from '@native';
import { trackInstall, trackInstallFailed } from '$libs/analytics';
import SortingButtons from '$components/search-packages/sorting-buttons.svelte';
export let title = 'Packages';
export let category = ''; // filter
let installedOnly = false;
let sortBy = 'popularity';
let sortDirection: 'asc' | 'desc' = 'desc';
let limit = 9;
let packages: GUIPackage[] = [];
packagesStore.subscribe((ps) => {
packages = category ?
ps.filter((p) => (p.categories || []).includes(category)) :
ps;
});
const setPackages = (pkgs: GUIPackage[]) => {
const sortedPackages = pkgs.sort((a, b) => {
if (sortBy === 'popularity') {
const aPop = +a.dl_count + a.installs;
const bPop = +b.dl_count + b.installs;
return sortDirection === 'asc' ? aPop - bPop : bPop - aPop;
} else {
// most recent
const aDate = new Date(a.last_modified);
const bDate = new Date(b.last_modified);
return sortDirection === 'asc' ? +aDate - +bDate : +bDate - +aDate;
}
});
packages = sortedPackages.filter((p) => installedOnly ? [PackageStates.INSTALLED, PackageStates.NEEDS_UPDATE].includes(p.state!) : true);
};
packagesStore.subscribe(setPackages);
const onSort = (opt: string, dir: 'asc' | 'desc') => {
sortBy = opt;
sortDirection = dir;
setPackages(packages);
};
const toggleInstalledFilter = (installed: boolean) => {
installedOnly = installed;
setPackages($packagesStore);
}
</script>
<header class="border-gray text-primary flex items-center justify-between border bg-black p-4">
<span>{title}</span>
<header class="flex items-center justify-between my-4">
<h1 class="text-primary text-4xl font-bold">{title}</h1>
<div class="flex">
<section class="border border-gray mr-2 rounded-sm h-10 text-gray font-thin flex">
<button on:click={() => toggleInstalledFilter(false)} class={`px-2 ${installedOnly ? "":"active"}`}>All packages</button>
<button on:click={() => toggleInstalledFilter(true)} class={`px-2 ${installedOnly ? "active":""}`}>installed only</button>
</section>
<section class="border-gray h-10 w-48 border rounded-sm">
<SortingButtons {onSort} />
</section>
</div>
</header>
<ul class="grid grid-cols-3 bg-black">
{#if packages.length > 0}
{#each packages as pkg}
<div class={pkg.state === PackageStates.INSTALLING ? 'animate-pulse' : ''}>
<Package
{pkg}
onClick={async () => {
try {
pkg.state = PackageStates.INSTALLING;
await installPackage(pkg);
trackInstall(pkg.full_name);
pkg.state = PackageStates.INSTALLED;
} catch (error) {
let message = 'Unknown Error'
if (error instanceof Error) message = error.message
trackInstallFailed(pkg.full_name, message || "unknown");
}
}}
/>
</div>
{#each packages as pkg, index}
{#if index < limit}
<div class={pkg.state === PackageStates.INSTALLING ? 'animate-pulse' : ''}>
<Package
{pkg}
onClick={async () => {
try {
pkg.state = PackageStates.INSTALLING;
await installPackage(pkg);
trackInstall(pkg.full_name);
pkg.state = PackageStates.INSTALLED;
} catch (error) {
let message = 'Unknown Error'
if (error instanceof Error) message = error.message
trackInstallFailed(pkg.full_name, message || "unknown");
}
}}
/>
</div>
{/if}
{/each}
{:else}
{#each Array(9) as _}
@ -54,3 +95,24 @@
{/each}
{/if}
</ul>
{#if limit < packages.length }
<footer class="w-full flex border border-gray h-16">
<button class="flex-grow h-16" on:click={() => limit += 9 }>show more</button>
</footer>
{/if}
<style>
button {
height: 100%;
text-decoration: none;
min-width: 120px;
transition: 0.1s linear;
}
button:hover, button.active {
color: white;
background-color: #8000ff;
box-shadow: inset 0vw 0vw 0vw 0.223vw #1a1a1a !important;
box-sizing: border-box;
}
</style>

View file

@ -26,14 +26,14 @@
};
</script>
<section class="sorting-container font-machina bg-black text-white">
<section class="sorting-container font-machina bg-black text-gray">
<div class="dropdown">
<div class="dropdown-title">{$t("sorting.label")}</div>
<ul class="dropdown-content column flex">
{#each sortOptions as option}
<li class="flex items-center">
<button
class={`sort-btn uppercase ${sortBy === option ? 'active' : ''}`}
class={`sort-btn ${sortBy === option ? 'active' : ''}`}
on:click={() => setSortBy(option)}
>
{optionLabels[option]}
@ -67,13 +67,11 @@
.sorting-container {
display: inline-block;
text-align: center;
text-decoration: none;
text-transform: uppercase;
max-width: 240px;
width: 100%;
height: 100%;
min-height: 34px;
min-height: 30px;
transition: 0.1s linear;
}
@ -100,9 +98,9 @@
.dropdown-content li {
position: relative;
padding: 0px 10px;
height: 40px;
height: 32px;
width: 100%;
line-height: 40px;
line-height: 36px;
}
.dropdown-content li .sort-btn {
@ -131,8 +129,8 @@
}
.dropdown-title {
height: 50px;
line-height: 50px;
height: 40px;
line-height: 40px;
padding-left: 10px;
}
</style>

View file

@ -62,9 +62,9 @@
},
"view-all": "view all",
"sorting": {
"label": "sort order",
"popularity": "popularity",
"most-recent": "most recent"
"label": "Filters",
"popularity": "Most popular",
"most-recent": "Most recent"
}
}
}

View file

@ -9,9 +9,8 @@
</script>
<div>
<PageHeader coverUrl="/images/headers/header_bg_1.png">{$t("home.discover-title")}</PageHeader>
<section class="mt-8 mb-8">
<Packages title={$t("package.foundation-essentials-title")} category="foundation_essentials" />
<Packages title={$t("home.discover-title")}/>
</section>
<PageHeader coverUrl="/images/headers/header_bg_1.png">{$t("home.tutorials-title")}</PageHeader>
<section class="mt-8 mb-8">