Skip to content

Commit 4e65a69

Browse files
committed
app-store: improve screenshots
1 parent 021a716 commit 4e65a69

File tree

1 file changed

+59
-13
lines changed

1 file changed

+59
-13
lines changed

hyperdrive/packages/app-store/ui/src/pages/AppPage.tsx

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import useAppsStore from "../store/appStoreStore";
44
import { AppListing, PackageState, ManifestResponse, HomepageApp } from "../types/Apps";
55
import { compareVersions } from "../utils/compareVersions";
66
import { MirrorSelector, ManifestDisplay } from '../components';
7-
import { FaChevronDown, FaChevronRight, FaCheck, FaCircleNotch, FaPlay } from "react-icons/fa6";
7+
import { FaChevronDown, FaChevronRight, FaCheck, FaCircleNotch, FaPlay, FaXmark } from "react-icons/fa6";
88
import { BsDownload } from "react-icons/bs";
99
import { Modal } from "../components/Modal";
1010
import classNames from "classnames";
@@ -84,6 +84,8 @@ export default function AppPage() {
8484
const [hasProcessedIntent, setHasProcessedIntent] = useState(false);
8585
const [awaitPresenceInHomepageApps, setAwaitPresenceInHomepageApps] = useState(false);
8686
const [launchUrl, setLaunchUrl] = useState<string | null>(null);
87+
const [showScreenshots, setShowScreenshots] = useState(true);
88+
const [activeScreenshot, setActiveScreenshot] = useState<string | null>(null);
8789

8890
useEffect(() => {
8991
const backTickCounter = (e: KeyboardEvent) => {
@@ -111,6 +113,15 @@ export default function AppPage() {
111113
.sort((a, b) => compareVersions(b.version, a.version));
112114
}, [app]);
113115

116+
const screenshots = useMemo(() => {
117+
if (isDevMode) {
118+
return MOCK_APP.metadata?.properties?.screenshots ?? [];
119+
}
120+
return app?.metadata?.properties?.screenshots ?? [];
121+
}, [app, isDevMode]);
122+
123+
const hasScreenshots = screenshots.length > 0;
124+
114125
const isDownloaded = useMemo(() => {
115126
if (!app || !selectedVersion) return false;
116127
const versionData = sortedVersions.find(v => v.version === selectedVersion);
@@ -664,18 +675,53 @@ export default function AppPage() {
664675

665676
{appButtons({ className: "flex-col items-stretch md:hidden" })}
666677

667-
{(app.metadata?.properties?.screenshots || isDevMode) && (
668-
<div className="flex flex-col gap-2">
669-
<h3 className="prose">Screenshots</h3>
670-
<div className="flex flex-wrap gap-2 overflow-y-auto min-h-0 max-h-lg">
671-
{(isDevMode ? MOCK_APP.metadata!.properties.screenshots! : app!.metadata!.properties!.screenshots!).map((screenshot, index) => (
672-
<img
673-
src={screenshot}
674-
alt={`Screenshot ${index + 1}`}
675-
className="rounded-lg w-full h-full object-contain aspect-video max-w-md max-h-md"
676-
loading="lazy"
677-
/>
678-
))}
678+
{(hasScreenshots || isDevMode) && (
679+
<div className="flex flex-col gap-4">
680+
<button
681+
onClick={() => setShowScreenshots(!showScreenshots)}
682+
className="flex items-center gap-2 text-lg font-medium text-gray-900 dark:text-white hover:text-iris dark:hover:text-neon transition-colors"
683+
>
684+
{showScreenshots ? <FaChevronDown /> : <FaChevronRight />} Screenshots
685+
</button>
686+
{showScreenshots && (
687+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
688+
{screenshots.map((screenshot, index) => (
689+
<img
690+
key={index}
691+
src={screenshot}
692+
alt={`Screenshot ${index + 1}`}
693+
className="rounded-lg w-full h-auto object-cover aspect-video max-h-64 hover:scale-105 transition-transform cursor-pointer"
694+
loading="lazy"
695+
onClick={() => setActiveScreenshot(screenshot)}
696+
/>
697+
))}
698+
</div>
699+
)}
700+
</div>
701+
)}
702+
703+
{activeScreenshot && (
704+
<div
705+
className="fixed inset-0 z-50 flex items-center justify-center bg-black/80 p-4"
706+
onClick={() => setActiveScreenshot(null)}
707+
>
708+
<div
709+
className="relative max-w-5xl max-h-[90vh] flex items-center justify-center"
710+
onClick={event => event.stopPropagation()}
711+
>
712+
<button
713+
type="button"
714+
className="absolute top-2 right-2 bg-black/60 text-white rounded-full p-2 hover:bg-black/80 transition-colors"
715+
onClick={() => setActiveScreenshot(null)}
716+
aria-label="Close screenshot preview"
717+
>
718+
<FaXmark size={18} />
719+
</button>
720+
<img
721+
src={activeScreenshot}
722+
alt="Selected app screenshot"
723+
className="max-h-[85vh] w-auto max-w-full rounded-lg shadow-2xl"
724+
/>
679725
</div>
680726
</div>
681727
)}

0 commit comments

Comments
 (0)