From 380f010a7e0c62b274febd2a32735586ec8c3867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20F=C3=B6rtsch?= Date: Thu, 5 Feb 2026 08:51:44 +0100 Subject: [PATCH] add sort button --- src/pages/Library/LibraryPage.css | 20 +++++--- src/pages/Library/LibraryPage.tsx | 82 ++++++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 8 deletions(-) diff --git a/src/pages/Library/LibraryPage.css b/src/pages/Library/LibraryPage.css index 1959c37..56114d1 100644 --- a/src/pages/Library/LibraryPage.css +++ b/src/pages/Library/LibraryPage.css @@ -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; diff --git a/src/pages/Library/LibraryPage.tsx b/src/pages/Library/LibraryPage.tsx index da00e0c..d65cea2 100644 --- a/src/pages/Library/LibraryPage.tsx +++ b/src/pages/Library/LibraryPage.tsx @@ -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([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(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 ( Bibliothek + setShowSortSheet(true)} + color="primary" + > + + + + + setSearchText(e.detail.value || "")} + className="library-searchbar" + /> - + 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" }, + ]} + /> + Bibliothek @@ -174,9 +246,15 @@ export default function LibraryPage() {

{error}

+ ) : filteredAndSortedGames.length === 0 ? ( +
+

+ {searchText ? "Keine Spiele gefunden" : "Keine Spiele vorhanden"} +

+
) : ( - {games.map((game) => ( + {filteredAndSortedGames.map((game) => (