add sort button
This commit is contained in:
@@ -4,12 +4,20 @@
|
||||
--padding-end: 16px;
|
||||
}
|
||||
|
||||
.hero {
|
||||
background: #ffffff;
|
||||
border-radius: 20px;
|
||||
padding: 1.1rem 1.2rem;
|
||||
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.08);
|
||||
display: flex;
|
||||
.library-searchbar {
|
||||
--background: transparent;
|
||||
--border-radius: 0;
|
||||
--padding-top: 8px;
|
||||
--padding-start: 8px;
|
||||
--padding-end: 8px;
|
||||
--padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.action-sheet-button.sort-action-active {
|
||||
color: #007aff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
gap: 1.5rem;
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
import {
|
||||
IonBadge,
|
||||
IonActionSheet,
|
||||
IonButton,
|
||||
IonContent,
|
||||
IonHeader,
|
||||
IonIcon,
|
||||
IonItem,
|
||||
IonLabel,
|
||||
IonList,
|
||||
IonNote,
|
||||
IonPage,
|
||||
IonSearchbar,
|
||||
IonSpinner,
|
||||
IonTitle,
|
||||
IonToolbar,
|
||||
} from "@ionic/react";
|
||||
import { swapVerticalOutline } from "ionicons/icons";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
|
||||
import "./LibraryPage.css";
|
||||
@@ -69,6 +74,11 @@ export default function LibraryPage() {
|
||||
const [games, setGames] = useState<SteamGame[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [searchText, setSearchText] = useState("");
|
||||
const [sortBy, setSortBy] = useState<"title" | "playtime" | "lastPlayed">(
|
||||
"title",
|
||||
);
|
||||
const [showSortSheet, setShowSortSheet] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let active = true;
|
||||
@@ -131,14 +141,76 @@ export default function LibraryPage() {
|
||||
);
|
||||
}, [games]);
|
||||
|
||||
const filteredAndSortedGames = useMemo(() => {
|
||||
// Filtere nach Suchtext
|
||||
let filtered = games.filter((game) =>
|
||||
game.title.toLowerCase().includes(searchText.toLowerCase()),
|
||||
);
|
||||
|
||||
// Sortiere
|
||||
filtered.sort((a, b) => {
|
||||
if (sortBy === "title") {
|
||||
return a.title.localeCompare(b.title, "de");
|
||||
} else if (sortBy === "playtime") {
|
||||
return (b.playtimeHours ?? 0) - (a.playtimeHours ?? 0);
|
||||
} else {
|
||||
// lastPlayed
|
||||
const aDate = a.lastPlayed ? new Date(a.lastPlayed).getTime() : 0;
|
||||
const bDate = b.lastPlayed ? new Date(b.lastPlayed).getTime() : 0;
|
||||
return bDate - aDate;
|
||||
}
|
||||
});
|
||||
|
||||
return filtered;
|
||||
}, [games, searchText, sortBy]);
|
||||
|
||||
return (
|
||||
<IonPage>
|
||||
<IonHeader translucent>
|
||||
<IonToolbar>
|
||||
<IonTitle>Bibliothek</IonTitle>
|
||||
<IonButton
|
||||
slot="end"
|
||||
fill="clear"
|
||||
onClick={() => setShowSortSheet(true)}
|
||||
color="primary"
|
||||
>
|
||||
<IonIcon slot="icon-only" icon={swapVerticalOutline} />
|
||||
</IonButton>
|
||||
</IonToolbar>
|
||||
<IonToolbar>
|
||||
<IonSearchbar
|
||||
placeholder="Spiele suchen..."
|
||||
value={searchText}
|
||||
onIonInput={(e) => setSearchText(e.detail.value || "")}
|
||||
className="library-searchbar"
|
||||
/>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<IonContent fullscreen className="library-content">
|
||||
<IonActionSheet
|
||||
isOpen={showSortSheet}
|
||||
onDidDismiss={() => setShowSortSheet(false)}
|
||||
header="Sortieren nach"
|
||||
buttons={[
|
||||
{
|
||||
text: "Titel",
|
||||
cssClass: sortBy === "title" ? "sort-action-active" : "",
|
||||
handler: () => setSortBy("title"),
|
||||
},
|
||||
{
|
||||
text: "Spielzeit",
|
||||
cssClass: sortBy === "playtime" ? "sort-action-active" : "",
|
||||
handler: () => setSortBy("playtime"),
|
||||
},
|
||||
{
|
||||
text: "Zuletzt gespielt",
|
||||
cssClass: sortBy === "lastPlayed" ? "sort-action-active" : "",
|
||||
handler: () => setSortBy("lastPlayed"),
|
||||
},
|
||||
{ text: "Abbrechen", role: "cancel" },
|
||||
]}
|
||||
/>
|
||||
<IonContent fullscreen className="library-content" id="library-content">
|
||||
<IonHeader collapse="condense">
|
||||
<IonToolbar>
|
||||
<IonTitle size="large">Bibliothek</IonTitle>
|
||||
@@ -174,9 +246,15 @@ export default function LibraryPage() {
|
||||
<div className="state error">
|
||||
<p>{error}</p>
|
||||
</div>
|
||||
) : filteredAndSortedGames.length === 0 ? (
|
||||
<div className="state">
|
||||
<p>
|
||||
{searchText ? "Keine Spiele gefunden" : "Keine Spiele vorhanden"}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<IonList inset className="game-list">
|
||||
{games.map((game) => (
|
||||
{filteredAndSortedGames.map((game) => (
|
||||
<IonItem
|
||||
key={game.id}
|
||||
lines="full"
|
||||
|
||||
Reference in New Issue
Block a user