@@ -4,7 +4,7 @@ import useAppsStore from "../store/appStoreStore";
44import { AppListing , PackageState , ManifestResponse , HomepageApp } from "../types/Apps" ;
55import { compareVersions } from "../utils/compareVersions" ;
66import { 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" ;
88import { BsDownload } from "react-icons/bs" ;
99import { Modal } from "../components/Modal" ;
1010import 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