From cdadedcb2e0239eb4b8a68aabc01f00b3f55a18e Mon Sep 17 00:00:00 2001 From: Alvin Unreal Date: Sun, 24 May 2026 02:22:48 +0200 Subject: [PATCH] Show pet details in modal on pets page --- apps/desktop/src/renderer/src/main.tsx | 204 +++++++++++++---------- apps/desktop/src/renderer/src/styles.css | 5 +- 2 files changed, 118 insertions(+), 91 deletions(-) diff --git a/apps/desktop/src/renderer/src/main.tsx b/apps/desktop/src/renderer/src/main.tsx index cfb8dd7f..2f1767f1 100644 --- a/apps/desktop/src/renderer/src/main.tsx +++ b/apps/desktop/src/renderer/src/main.tsx @@ -1825,7 +1825,8 @@ function App() { setState(nextState); setCatalog(nextCatalog); setCodex(nextCodex); setCatalogPage(nextCatalog.page ?? 0); setCatalogPages({ [nextCatalog.page ?? 0]: nextCatalog.pets }); - setSelectedId((current) => current || nextState.preferences.defaultPetId || nextState.pets.installed[0]?.id || nextCatalog.pets[0]?.id || ""); + const visiblePetIds = new Set([...nextState.pets.installed.map((pet) => pet.id), ...nextCatalog.pets.map((pet) => pet.id), ...nextCodex.pets.map((pet) => pet.id)]); + setSelectedId((current) => current && visiblePetIds.has(current) ? current : ""); } useEffect(() => { if (currentRoute !== "pets") return; @@ -1897,7 +1898,7 @@ function App() { }); }, [state, catalogPages, catalogSearch, codex, filter, query]); - const selected = pets.find((p) => p.id === selectedId) ?? pets[0]; + const selected = selectedId ? pets.find((p) => p.id === selectedId) ?? null : null; const defaultId = state?.preferences.defaultPetId; useEffect(() => { @@ -2047,7 +2048,12 @@ function App() { const hasDistinctPreview = pet.preview && pet.preview !== pet.spritesheet; const useSpritesheetFrame = !isBuiltIn && !hasDistinctPreview && !!pet.spritesheet; return ( - + -
- {/* Main Action (Install, Import, Set Default) */} - {!selected.installed && selected.sourceKind === "catalog" && ( - - )} - {!selected.installed && selected.sourceKind === "codex" && ( - - )} - {selected.installed && selected.id !== defaultId && !selected.broken && ( - +

{selected.description || selected.id}

+
+ {safePetImage(selected.spritesheet) ? ( + + ) : ( + + )} +
+
+ {selected.broken && Broken} + {selected.installed && !selected.broken && Ready} + {selected.builtIn && Originals} + {selected.original && !selected.builtIn && Original} + {selected.featured && !selected.original && Featured} + {selected.category === "western" && !selected.original && !selected.featured && Western} + {selected.category === "asian" && !selected.original && !selected.featured && Asian} +
+ {statusText &&

{statusText}

} + + {safePetImage(selected.spritesheet) && ( + <> +

Preview Animations

+
+ {[ + { label: "Thinking", state: "thinking" as const }, + { label: "Happy", state: "happy" as const }, + { label: "Wave", state: "wave" as const }, + ].map((previewState) => ( +
+ + {previewState.label} +
+ ))} +
+ )} - {/* Secondary Actions (Remove, Refresh) */} -
- {selected.installed && !selected.builtIn && !selected.protected && ( +
+ {/* Main Action (Install, Import, Set Default) */} + {!selected.installed && selected.sourceKind === "catalog" && ( )} - + {!selected.installed && selected.sourceKind === "codex" && ( + + )} + {selected.installed && selected.id !== defaultId && !selected.broken && ( + + )} + +
+ {selected.installed && !selected.builtIn && !selected.protected && ( + + )} + +
-
:

No pets available.

} - + +
+ ) : null} )} diff --git a/apps/desktop/src/renderer/src/styles.css b/apps/desktop/src/renderer/src/styles.css index 1cc0b13d..9afd977e 100644 --- a/apps/desktop/src/renderer/src/styles.css +++ b/apps/desktop/src/renderer/src/styles.css @@ -18,7 +18,7 @@ .hero-logo-container { @apply flex shrink-0 items-center justify-end; } .hero-brand-logo { @apply h-28 w-auto max-w-[480px] object-contain select-none; filter: drop-shadow(0 6px 12px rgba(61, 99, 160, 0.10)); } .eyebrow { @apply mb-1.5 font-monoDisplay text-xs font-black uppercase tracking-[.18em] text-brand; } - .layout { @apply grid min-h-0 flex-1 grid-cols-[1.25fr_.75fr] gap-5 max-[900px]:grid-cols-1; } + .layout { @apply grid min-h-0 flex-1 grid-cols-1 gap-5; } .glass { @apply rounded-[28px] border border-[rgba(126,161,210,.48)] p-5 shadow-glass backdrop-blur-xl; background: rgba(255, 255, 255, 0.76); box-shadow: inset 0 1px 0 rgba(255,255,255,.96), 0 24px 60px rgba(61,99,160,.15); } .gallery { @apply flex min-h-0 flex-col overflow-hidden; } .toolbar { @apply flex items-center gap-3; } .search { @apply min-w-0 flex-1 rounded-2xl border border-blue-300/80 bg-white/80 px-4 py-3 text-navy outline-none shadow-inner transition-shadow duration-150 focus:border-brand focus:bg-white focus:ring-4 focus:ring-brand/15; } @@ -37,7 +37,7 @@ .filter.active .filter-icon-wrapper { @apply opacity-100; } .filter-icon { @apply h-3.5 w-3.5 stroke-[2.5]; } .pager { @apply mt-3 flex items-center justify-between gap-2.5 rounded-xl border border-blue-200/40 bg-blue-50/20 p-1.5 text-xs font-bold text-slatecopy; } - .pets-grid { @apply grid min-h-0 flex-1 grid-cols-2 gap-3 overflow-y-auto p-1.5 pr-2.5 pb-3 max-[680px]:grid-cols-1; overscroll-behavior: contain; scrollbar-color: rgba(96, 165, 250, 0.42) transparent; } + .pets-grid { @apply grid min-h-0 flex-1 grid-cols-1 gap-3 overflow-y-auto p-1.5 pr-2.5 pb-3; overscroll-behavior: contain; scrollbar-color: rgba(96, 165, 250, 0.42) transparent; } .pet-card { @apply flex flex-row items-center gap-3.5 rounded-2xl border border-slate-200 bg-white/80 p-3 text-left shadow-sm transition-[transform,border-color,background-color,box-shadow] hover:-translate-y-0.5 hover:border-brand hover:bg-white active:scale-[0.96] min-h-[92px] w-full cursor-pointer; } .pet-card.selected { @apply border-brand bg-blue-50/90 ring-4 ring-blue-200/50 shadow-md; } .thumb { @apply grid h-14 w-14 shrink-0 place-items-center overflow-hidden rounded-2xl bg-gradient-to-br from-white to-blue-100 border border-blue-100/50; } @@ -168,6 +168,7 @@ .plugin-config-overlay { @apply fixed inset-0 z-30 flex items-center justify-center p-6; animation: plugin-fade-in 0.2s ease-out; } .plugin-config-backdrop { @apply absolute inset-0 cursor-default border-0 bg-navy/[0.12] p-0 backdrop-blur-[4px]; } .plugin-inspector { @apply relative z-10 flex max-h-[calc(100vh-4rem)] w-[min(760px,calc(100vw-3rem))] flex-col gap-4 overflow-y-auto pr-3 shadow-[0_32px_80px_rgba(16,33,73,0.25)]; overscroll-behavior: contain; scrollbar-gutter: stable; animation: plugin-pop-in 0.25s cubic-bezier(0.16, 1, 0.3, 1); } + .pet-detail-inspector { @apply w-[min(900px,calc(100vw-3rem))]; } @keyframes plugin-fade-in { from { opacity: 0; } to { opacity: 1; } } @keyframes plugin-pop-in { from { opacity: 0; transform: scale(0.96) translateY(10px); } to { opacity: 1; transform: scale(1) translateY(0); } } .plugin-inspector-head { @apply flex items-center gap-4; }