From d1f8263bf9f22753ad53e1b0105172a3bd0faf5f Mon Sep 17 00:00:00 2001
From: xXJSONDeruloXx <danielhimebauch@gmail.com>
Date: Sun, 6 Sep 2026 23:12:28 -0400
Subject: feat: organize game profiles and focus enabled settings

---
 src/components/GameConfigurationSelector.tsx | 107 +++++++++++++++++++++------
 1 file changed, 84 insertions(+), 23 deletions(-)

(limited to 'src/components/GameConfigurationSelector.tsx')

diff --git a/src/components/GameConfigurationSelector.tsx b/src/components/GameConfigurationSelector.tsx
index fcdd0aa..982fcef 100644
--- a/src/components/GameConfigurationSelector.tsx
+++ b/src/components/GameConfigurationSelector.tsx
@@ -1,4 +1,6 @@
 import { ButtonItem, Field, PanelSectionRow } from "@decky/ui";
+import { useEffect, useState } from "react";
+import { RiArrowDownSFill, RiArrowUpSFill } from "react-icons/ri";
 import { GameTarget } from "../hooks/useGameConfiguration";
 
 interface Props {
@@ -8,42 +10,101 @@ interface Props {
   onResetAll: () => Promise<void>;
 }
 
-const profileDescription = (target: GameTarget, running: boolean, active: boolean) => [
-  running ? "Now playing" : "",
-  target.nonSteam ? "Non-Steam" : "Steam",
-  target.configured
-    ? active ? "Profile active" : "Profile saved · applies next launch"
-    : "Not configured · changes apply next launch",
-].filter(Boolean).join(" · ");
+const CONFIGURED_COLLAPSED_KEY = "lsfg-configured-games-collapsed";
+const AVAILABLE_COLLAPSED_KEY = "lsfg-available-games-collapsed";
 
-export function GameConfigurationSelector({ targets, runningGame, onSelect, onResetAll }: Props) {
-  const games = [...targets].sort((a, b) => {
-    if (a.appid === runningGame?.appid) return -1;
-    if (b.appid === runningGame?.appid) return 1;
-    return a.name.localeCompare(b.name);
+function usePersistentCollapsed(key: string) {
+  const [collapsed, setCollapsed] = useState(() => {
+    try {
+      return localStorage.getItem(key) === "true";
+    } catch {
+      return false;
+    }
   });
 
+  useEffect(() => {
+    try {
+      localStorage.setItem(key, String(collapsed));
+    } catch {
+      // Persisting the view preference is optional.
+    }
+  }, [collapsed, key]);
+
+  return [collapsed, () => setCollapsed((value) => !value)] as const;
+}
+
+function GameGroup({
+  title,
+  games,
+  collapsed,
+  onToggle,
+  onSelect,
+}: {
+  title: string;
+  games: GameTarget[];
+  collapsed: boolean;
+  onToggle: () => void;
+  onSelect: (appid: string) => void;
+}) {
+  if (games.length === 0) return null;
+
   return (
     <>
-      {games.length === 0 && (
-        <PanelSectionRow>
-          <Field label="No installed games" description="Steam has not reported any eligible games" />
-        </PanelSectionRow>
-      )}
-      {games.map((game) => (
+      <PanelSectionRow>
+        <ButtonItem
+          layout="below"
+          bottomSeparator={collapsed ? "standard" : "none"}
+          onClick={onToggle}
+        >
+          {collapsed ? <RiArrowDownSFill /> : <RiArrowUpSFill />} {title} ({games.length})
+        </ButtonItem>
+      </PanelSectionRow>
+      {!collapsed && games.map((game) => (
         <PanelSectionRow key={game.appid}>
           <Field
             label={game.name}
-            description={profileDescription(
-              game,
-              game.appid === runningGame?.appid,
-              game.appid === runningGame?.appid ? runningGame.configured : game.configured,
-            )}
+            description={game.nonSteam ? "Non-Steam" : "Steam"}
             onActivate={() => onSelect(game.appid)}
             highlightOnFocus
           />
         </PanelSectionRow>
       ))}
+    </>
+  );
+}
+
+export function GameConfigurationSelector({ targets, runningGame, onSelect, onResetAll }: Props) {
+  const sortGames = (games: GameTarget[]) => [...games].sort((a, b) => {
+    if (a.appid === runningGame?.appid) return -1;
+    if (b.appid === runningGame?.appid) return 1;
+    return a.name.localeCompare(b.name);
+  });
+  const configuredGames = sortGames(targets.filter((game) => game.configured));
+  const availableGames = sortGames(targets.filter((game) => !game.configured));
+  const [configuredCollapsed, toggleConfigured] = usePersistentCollapsed(CONFIGURED_COLLAPSED_KEY);
+  const [availableCollapsed, toggleAvailable] = usePersistentCollapsed(AVAILABLE_COLLAPSED_KEY);
+
+  return (
+    <>
+      {targets.length === 0 && (
+        <PanelSectionRow>
+          <Field label="No installed games" description="Steam has not reported any eligible games" />
+        </PanelSectionRow>
+      )}
+      <GameGroup
+        title="Configured"
+        games={configuredGames}
+        collapsed={configuredCollapsed}
+        onToggle={toggleConfigured}
+        onSelect={onSelect}
+      />
+      <GameGroup
+        title="Available games"
+        games={availableGames}
+        collapsed={availableCollapsed}
+        onToggle={toggleAvailable}
+        onSelect={onSelect}
+      />
       <PanelSectionRow>
         <ButtonItem
           layout="below"
-- 
cgit v1.2.3

