Loading Web/src/components/media/ContentViewer.tsx +11 −4 Original line number Diff line number Diff line Loading @@ -3,8 +3,8 @@ import { t } from 'i18next'; import ReactPlayer, { ReactPlayerProps } from 'react-player'; import { GameMedia } from '../../client'; import { defaultStreamUrl } from '../../utils/getStreamUrl'; import { Video } from './Player/Video'; import { PivoImage } from './PivoImage'; import { Video } from './Player/Video'; interface IContentViewerProps { media: GameMedia; Loading @@ -28,7 +28,8 @@ export function ContentViewer({ media, autoplay, videoProps, onPrevious, onNext subtitles={subtitleSources} minW="100%" maxW="100%" h="60vmin" minH="100%" maxH="100%" autoplay={autoplay} onPrevious={onPrevious} onNext={onNext} Loading @@ -41,7 +42,7 @@ export function ContentViewer({ media, autoplay, videoProps, onPrevious, onNext alt={''} style={{ width: '100%', height: '60vmin', height: '100%', objectFit: 'contain', objectPosition: 'center center', }} Loading Loading @@ -85,13 +86,19 @@ export function ContentPreview({ media, autoplay, ...props }: IContentViewerProp <PivoImage id={media.attachmentId} sizes="25vw" style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center center', }} imageProps={{ style: { width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center center', } }, }} /> ); Loading Web/src/components/pages/Events.tsx +1 −1 Original line number Diff line number Diff line Loading @@ -57,7 +57,7 @@ export function Events() { </Text> . {t('events.part2')} -{' '} <Text as="span" textStyle="link"> <Link to="/ecosystem">{t('menuButtons.community')}</Link> <Link to="/community">{t('menuButtons.community')}</Link> </Text> . </Text> Loading Web/src/components/pages/GamesGallery.tsx +154 −141 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import { AccordionIcon, AccordionItem, AccordionPanel, AspectRatio, Box, Breadcrumb, BreadcrumbItem, Loading @@ -13,6 +14,8 @@ import { CardBody, Center, Flex, Grid, GridItem, HStack, Heading, Highlight, Loading Loading @@ -45,6 +48,7 @@ import { } from 'react-icons/ri'; import { Link as RouterLink, useSearchParams } from 'react-router-dom'; import { getApiV1Games, getApiV1Tags } from '../../client'; import { GALLERY_PAGE_SIZE, MEDIA_ASPECT } from '../../constants'; import { getPrefered } from '../../utils/preferedLanguage'; import { sequence } from '../../utils/sequence'; import { PivoImage } from '../media/PivoImage'; Loading @@ -54,8 +58,6 @@ import { Loading } from '../utils/Loading'; import { OutletOrChildren } from '../utils/OutletOrChildren'; import { PageTitle } from '../utils/PageTitle'; const PAGE_SIZE = 16; export function GamesGallery() { const [loaded, setLoaded] = useState<boolean>(false); const [selectedSort, _setSelectedSort] = useState<string>('recent'); Loading Loading @@ -380,7 +382,7 @@ export function GamesGallery() { <AwaitAPI request={getApiV1Games({ query: { pageSize: PAGE_SIZE, pageSize: GALLERY_PAGE_SIZE, pageIndex: page, sort: sortBy[selectedSort].value, lang: i18next.language, Loading @@ -392,7 +394,7 @@ export function GamesGallery() { > {(gameItems, isLoading, headers) => { const total = parseInt(headers['x-total-count']) /* WIP item */ + 1; const pages = Math.ceil(total / PAGE_SIZE); const pages = Math.ceil(total / GALLERY_PAGE_SIZE); return ( <Box position="relative"> Loading @@ -408,10 +410,21 @@ export function GamesGallery() { <Loading large center /> </Center> )} <Flex paddingTop={5} gap={5} wrap="wrap" opacity={isLoading ? 0.2 : 1}> <Grid paddingTop={5} columnGap={6} rowGap={8} opacity={isLoading ? 0.2 : 1} templateColumns={{ base: '1fr', md: 'repeat(2, minmax(0, 1fr))', lg: 'repeat(3, minmax(0, 1fr))', xl: 'repeat(4, minmax(0, 1fr))', }} > {gameItems.map((game) => ( <GridItem key={game.id}> <Link key={game.id} as={RouterLink} to={ game.id + Loading @@ -421,14 +434,15 @@ export function GamesGallery() { } > <Card maxW="xs" variant="unstyled" backgroundColor="transparent" flexGrow={1} flexShrink={0} > <CardBody> <Center w={{ base: 60, md: 80 }} h={{ base: 36, md: 56 }} <AspectRatio ratio={MEDIA_ASPECT} w="100%" borderRadius="md" sx={{ boxShadow: useColorModeValue( Loading Loading @@ -458,16 +472,16 @@ export function GamesGallery() { }} /> ) : ( <> <Center> <RiGameFill size={40} /> <RiCircleFill size={10} /> <span style={{ width: 5 }} /> <RiCircleFill size={10} /> <span style={{ width: 5 }} /> <RiCircleFill size={10} /> </> )} </Center> )} </AspectRatio> <Stack mt="4" spacing="1"> <Heading size="md"> Loading Loading @@ -517,7 +531,8 @@ export function GamesGallery() { mr={2} mb={2} _hover={{ backgroundColor: isSelected backgroundColor: isSelected ? undefined : useColorModeValue( 'gray.200', Loading @@ -525,7 +540,9 @@ export function GamesGallery() { ), }} onClick={(event) => { toggleTag(tagDetails.id); toggleTag( tagDetails.id, ); event.preventDefault(); event.stopPropagation(); }} Loading @@ -542,17 +559,13 @@ export function GamesGallery() { </CardBody> </Card> </Link> </GridItem> ))} {page === pages - 1 && ( <Card maxW="xs" variant="unstyled" backgroundColor="transparent"> <CardBody> <Center w={{ base: 60, md: 80 }} h="100%" overflow="hidden" opacity={0.2} > <Center h="100%" overflow="hidden" opacity={0.2}> <VStack textAlign="center" px={4}> <Icon as={RiGamepadFill} boxSize={20} /> <Text fontWeight="bold">{t('games.wip1')}</Text> Loading Loading @@ -583,7 +596,7 @@ export function GamesGallery() { </CardBody> </Card> )} </Flex> </Grid> <HStack mt={8} mb={6}> <IconButton isDisabled={page === 0} Loading Web/src/components/pages/Release.tsx +63 −50 Original line number Diff line number Diff line Loading @@ -36,7 +36,7 @@ import Avatar from 'boring-avatars'; import { CZ, GB, SK } from 'country-flag-icons/react/3x2'; import { t } from 'i18next'; import moment from 'moment'; import { useState } from 'react'; import { useMemo, useState } from 'react'; import { FaItchIo } from 'react-icons/fa'; import { RiArrowDropDownLine, Loading @@ -48,15 +48,16 @@ import { } from 'react-icons/ri'; import { useParams } from 'react-router-dom'; import { GameMedia, getApiV1GamesById, getApiV1ReleasesById } from '../../client'; import { MEDIA_ASPECT } from '../../constants'; import { capitalize } from '../../utils/capitalize'; import { defaultStreamUrl } from '../../utils/getStreamUrl'; import { getPrefered } from '../../utils/preferedLanguage'; import { ContentPreview, ContentViewer } from '../media/ContentViewer'; import { PivoImage } from '../media/PivoImage'; import { AwaitAPI } from '../utils/AwaitAPI'; import { ChakraMarkdown } from '../utils/ChakraMarkdown'; import { Error } from '../utils/Error'; import { PageTitle } from '../utils/PageTitle'; import { PivoImage } from '../media/PivoImage'; const iconMap = { 'steampowered.com': <RiSteamFill size={20} />, Loading Loading @@ -109,22 +110,30 @@ export function Release() { } }; return ( <AwaitAPI request={getApiV1ReleasesById({ const releaseGetter = useMemo( () => getApiV1ReleasesById({ path: { id: releaseId, }, })} > {(release) => ( <AwaitAPI request={getApiV1GamesById({ }), [releaseId], ); const gameGetter = useMemo( () => getApiV1GamesById({ path: { id: gameId, }, })} > }), [gameId], ); return ( <AwaitAPI request={releaseGetter}> {(release) => ( <AwaitAPI request={gameGetter}> {(game) => { // Correct way to access the second media item, if it exists const primaryMediaId = release.media?.filter((media) => media.mediaType.startsWith('image'))[0] Loading @@ -143,17 +152,17 @@ export function Release() { id={primaryMediaId} sizes="100vw" imageProps={{ alt: "heading-game", w: "100%", alt: 'heading-game', w: '100%', h: { base: 36, sm: 36, md: 56, lg: 72 }, objectFit: "cover", objectFit: 'cover', objectPosition: 'center center', sx: { boxShadow: useColorModeValue( '2px 2px 10px rgba(128, 128, 128, 0.7)', '2px 2px 10px rgba(44, 48, 68, 0.7)', ), } }, }} /> <Box Loading Loading @@ -428,24 +437,29 @@ export function Release() { <Grid marginBottom={5} templateRows={{ base: 'auto', md: `repeat(${Math.max( 2, 1 + Math.ceil((release.media.length - 1) / 4), )}, 1fr)`, templateColumns={{ base: '1', md: 'repeat(2, minmax(0, 1fr))', lg: 'repeat(3, minmax(0, 1fr))', xl: 'repeat(4, minmax(0, 1fr))', }} templateColumns={{ base: '1', md: 'repeat(4, 1fr)' }} gap={5} gap={0} > {release.media?.map((media, index) => { const isHighlighted = index === 0; return ( <GridItem aspectRatio={MEDIA_ASPECT} key={media.attachmentId} rowSpan={isHighlighted ? 2 : 1} colSpan={isHighlighted ? 2 : 1} rowSpan={{ base: 1, md: isHighlighted ? 2 : 1 }} colSpan={{ base: 1, md: isHighlighted ? 2 : 1 }} pr={4} pb={4} > <Box w="100%" h="100%" borderRadius="md" overflow={'hidden'} sx={{ Loading @@ -456,7 +470,11 @@ export function Release() { }} cursor={'pointer'} > <ContentPreview media={media} onClick={() => openModal(media)} /> <ContentPreview media={media} onClick={() => openModal(media)} /> </Box> </GridItem> ); })} Loading Loading @@ -654,19 +672,14 @@ export function Release() { )} </VStack> <Modal isOpen={isModalOpen} onClose={closeModal} size={'3xl'} isCentered> <Modal isOpen={isModalOpen} onClose={closeModal} size={'full'} isCentered> <ModalOverlay /> <ModalContent m={0} borderRadius="none"> <ModalCloseButton size="lg" _hover={{ color: 'black' }} zIndex="1" position="absolute" top="4" right="4" /> <ModalBody p={0}> <ModalContent m={0} borderRadius="none" bg="none"> <ModalCloseButton size="lg" zIndex="1" position="absolute" top="4" right="4" /> <ModalBody p={0} overflow="hidden" position="relative"> <Box position="absolute" inset={{ base: 0, md: 10 }}> {selectedMedia && <ContentViewer media={selectedMedia} />} </Box> </ModalBody> </ModalContent> </Modal> Loading Web/src/constants.ts 0 → 100644 +3 −0 Original line number Diff line number Diff line export const GALLERY_PAGE_SIZE = 12; // Divisible by 1, 2, 3, 4 export const MEDIA_ASPECT = 16 / 9; Loading
Web/src/components/media/ContentViewer.tsx +11 −4 Original line number Diff line number Diff line Loading @@ -3,8 +3,8 @@ import { t } from 'i18next'; import ReactPlayer, { ReactPlayerProps } from 'react-player'; import { GameMedia } from '../../client'; import { defaultStreamUrl } from '../../utils/getStreamUrl'; import { Video } from './Player/Video'; import { PivoImage } from './PivoImage'; import { Video } from './Player/Video'; interface IContentViewerProps { media: GameMedia; Loading @@ -28,7 +28,8 @@ export function ContentViewer({ media, autoplay, videoProps, onPrevious, onNext subtitles={subtitleSources} minW="100%" maxW="100%" h="60vmin" minH="100%" maxH="100%" autoplay={autoplay} onPrevious={onPrevious} onNext={onNext} Loading @@ -41,7 +42,7 @@ export function ContentViewer({ media, autoplay, videoProps, onPrevious, onNext alt={''} style={{ width: '100%', height: '60vmin', height: '100%', objectFit: 'contain', objectPosition: 'center center', }} Loading Loading @@ -85,13 +86,19 @@ export function ContentPreview({ media, autoplay, ...props }: IContentViewerProp <PivoImage id={media.attachmentId} sizes="25vw" style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center center', }} imageProps={{ style: { width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center center', } }, }} /> ); Loading
Web/src/components/pages/Events.tsx +1 −1 Original line number Diff line number Diff line Loading @@ -57,7 +57,7 @@ export function Events() { </Text> . {t('events.part2')} -{' '} <Text as="span" textStyle="link"> <Link to="/ecosystem">{t('menuButtons.community')}</Link> <Link to="/community">{t('menuButtons.community')}</Link> </Text> . </Text> Loading
Web/src/components/pages/GamesGallery.tsx +154 −141 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import { AccordionIcon, AccordionItem, AccordionPanel, AspectRatio, Box, Breadcrumb, BreadcrumbItem, Loading @@ -13,6 +14,8 @@ import { CardBody, Center, Flex, Grid, GridItem, HStack, Heading, Highlight, Loading Loading @@ -45,6 +48,7 @@ import { } from 'react-icons/ri'; import { Link as RouterLink, useSearchParams } from 'react-router-dom'; import { getApiV1Games, getApiV1Tags } from '../../client'; import { GALLERY_PAGE_SIZE, MEDIA_ASPECT } from '../../constants'; import { getPrefered } from '../../utils/preferedLanguage'; import { sequence } from '../../utils/sequence'; import { PivoImage } from '../media/PivoImage'; Loading @@ -54,8 +58,6 @@ import { Loading } from '../utils/Loading'; import { OutletOrChildren } from '../utils/OutletOrChildren'; import { PageTitle } from '../utils/PageTitle'; const PAGE_SIZE = 16; export function GamesGallery() { const [loaded, setLoaded] = useState<boolean>(false); const [selectedSort, _setSelectedSort] = useState<string>('recent'); Loading Loading @@ -380,7 +382,7 @@ export function GamesGallery() { <AwaitAPI request={getApiV1Games({ query: { pageSize: PAGE_SIZE, pageSize: GALLERY_PAGE_SIZE, pageIndex: page, sort: sortBy[selectedSort].value, lang: i18next.language, Loading @@ -392,7 +394,7 @@ export function GamesGallery() { > {(gameItems, isLoading, headers) => { const total = parseInt(headers['x-total-count']) /* WIP item */ + 1; const pages = Math.ceil(total / PAGE_SIZE); const pages = Math.ceil(total / GALLERY_PAGE_SIZE); return ( <Box position="relative"> Loading @@ -408,10 +410,21 @@ export function GamesGallery() { <Loading large center /> </Center> )} <Flex paddingTop={5} gap={5} wrap="wrap" opacity={isLoading ? 0.2 : 1}> <Grid paddingTop={5} columnGap={6} rowGap={8} opacity={isLoading ? 0.2 : 1} templateColumns={{ base: '1fr', md: 'repeat(2, minmax(0, 1fr))', lg: 'repeat(3, minmax(0, 1fr))', xl: 'repeat(4, minmax(0, 1fr))', }} > {gameItems.map((game) => ( <GridItem key={game.id}> <Link key={game.id} as={RouterLink} to={ game.id + Loading @@ -421,14 +434,15 @@ export function GamesGallery() { } > <Card maxW="xs" variant="unstyled" backgroundColor="transparent" flexGrow={1} flexShrink={0} > <CardBody> <Center w={{ base: 60, md: 80 }} h={{ base: 36, md: 56 }} <AspectRatio ratio={MEDIA_ASPECT} w="100%" borderRadius="md" sx={{ boxShadow: useColorModeValue( Loading Loading @@ -458,16 +472,16 @@ export function GamesGallery() { }} /> ) : ( <> <Center> <RiGameFill size={40} /> <RiCircleFill size={10} /> <span style={{ width: 5 }} /> <RiCircleFill size={10} /> <span style={{ width: 5 }} /> <RiCircleFill size={10} /> </> )} </Center> )} </AspectRatio> <Stack mt="4" spacing="1"> <Heading size="md"> Loading Loading @@ -517,7 +531,8 @@ export function GamesGallery() { mr={2} mb={2} _hover={{ backgroundColor: isSelected backgroundColor: isSelected ? undefined : useColorModeValue( 'gray.200', Loading @@ -525,7 +540,9 @@ export function GamesGallery() { ), }} onClick={(event) => { toggleTag(tagDetails.id); toggleTag( tagDetails.id, ); event.preventDefault(); event.stopPropagation(); }} Loading @@ -542,17 +559,13 @@ export function GamesGallery() { </CardBody> </Card> </Link> </GridItem> ))} {page === pages - 1 && ( <Card maxW="xs" variant="unstyled" backgroundColor="transparent"> <CardBody> <Center w={{ base: 60, md: 80 }} h="100%" overflow="hidden" opacity={0.2} > <Center h="100%" overflow="hidden" opacity={0.2}> <VStack textAlign="center" px={4}> <Icon as={RiGamepadFill} boxSize={20} /> <Text fontWeight="bold">{t('games.wip1')}</Text> Loading Loading @@ -583,7 +596,7 @@ export function GamesGallery() { </CardBody> </Card> )} </Flex> </Grid> <HStack mt={8} mb={6}> <IconButton isDisabled={page === 0} Loading
Web/src/components/pages/Release.tsx +63 −50 Original line number Diff line number Diff line Loading @@ -36,7 +36,7 @@ import Avatar from 'boring-avatars'; import { CZ, GB, SK } from 'country-flag-icons/react/3x2'; import { t } from 'i18next'; import moment from 'moment'; import { useState } from 'react'; import { useMemo, useState } from 'react'; import { FaItchIo } from 'react-icons/fa'; import { RiArrowDropDownLine, Loading @@ -48,15 +48,16 @@ import { } from 'react-icons/ri'; import { useParams } from 'react-router-dom'; import { GameMedia, getApiV1GamesById, getApiV1ReleasesById } from '../../client'; import { MEDIA_ASPECT } from '../../constants'; import { capitalize } from '../../utils/capitalize'; import { defaultStreamUrl } from '../../utils/getStreamUrl'; import { getPrefered } from '../../utils/preferedLanguage'; import { ContentPreview, ContentViewer } from '../media/ContentViewer'; import { PivoImage } from '../media/PivoImage'; import { AwaitAPI } from '../utils/AwaitAPI'; import { ChakraMarkdown } from '../utils/ChakraMarkdown'; import { Error } from '../utils/Error'; import { PageTitle } from '../utils/PageTitle'; import { PivoImage } from '../media/PivoImage'; const iconMap = { 'steampowered.com': <RiSteamFill size={20} />, Loading Loading @@ -109,22 +110,30 @@ export function Release() { } }; return ( <AwaitAPI request={getApiV1ReleasesById({ const releaseGetter = useMemo( () => getApiV1ReleasesById({ path: { id: releaseId, }, })} > {(release) => ( <AwaitAPI request={getApiV1GamesById({ }), [releaseId], ); const gameGetter = useMemo( () => getApiV1GamesById({ path: { id: gameId, }, })} > }), [gameId], ); return ( <AwaitAPI request={releaseGetter}> {(release) => ( <AwaitAPI request={gameGetter}> {(game) => { // Correct way to access the second media item, if it exists const primaryMediaId = release.media?.filter((media) => media.mediaType.startsWith('image'))[0] Loading @@ -143,17 +152,17 @@ export function Release() { id={primaryMediaId} sizes="100vw" imageProps={{ alt: "heading-game", w: "100%", alt: 'heading-game', w: '100%', h: { base: 36, sm: 36, md: 56, lg: 72 }, objectFit: "cover", objectFit: 'cover', objectPosition: 'center center', sx: { boxShadow: useColorModeValue( '2px 2px 10px rgba(128, 128, 128, 0.7)', '2px 2px 10px rgba(44, 48, 68, 0.7)', ), } }, }} /> <Box Loading Loading @@ -428,24 +437,29 @@ export function Release() { <Grid marginBottom={5} templateRows={{ base: 'auto', md: `repeat(${Math.max( 2, 1 + Math.ceil((release.media.length - 1) / 4), )}, 1fr)`, templateColumns={{ base: '1', md: 'repeat(2, minmax(0, 1fr))', lg: 'repeat(3, minmax(0, 1fr))', xl: 'repeat(4, minmax(0, 1fr))', }} templateColumns={{ base: '1', md: 'repeat(4, 1fr)' }} gap={5} gap={0} > {release.media?.map((media, index) => { const isHighlighted = index === 0; return ( <GridItem aspectRatio={MEDIA_ASPECT} key={media.attachmentId} rowSpan={isHighlighted ? 2 : 1} colSpan={isHighlighted ? 2 : 1} rowSpan={{ base: 1, md: isHighlighted ? 2 : 1 }} colSpan={{ base: 1, md: isHighlighted ? 2 : 1 }} pr={4} pb={4} > <Box w="100%" h="100%" borderRadius="md" overflow={'hidden'} sx={{ Loading @@ -456,7 +470,11 @@ export function Release() { }} cursor={'pointer'} > <ContentPreview media={media} onClick={() => openModal(media)} /> <ContentPreview media={media} onClick={() => openModal(media)} /> </Box> </GridItem> ); })} Loading Loading @@ -654,19 +672,14 @@ export function Release() { )} </VStack> <Modal isOpen={isModalOpen} onClose={closeModal} size={'3xl'} isCentered> <Modal isOpen={isModalOpen} onClose={closeModal} size={'full'} isCentered> <ModalOverlay /> <ModalContent m={0} borderRadius="none"> <ModalCloseButton size="lg" _hover={{ color: 'black' }} zIndex="1" position="absolute" top="4" right="4" /> <ModalBody p={0}> <ModalContent m={0} borderRadius="none" bg="none"> <ModalCloseButton size="lg" zIndex="1" position="absolute" top="4" right="4" /> <ModalBody p={0} overflow="hidden" position="relative"> <Box position="absolute" inset={{ base: 0, md: 10 }}> {selectedMedia && <ContentViewer media={selectedMedia} />} </Box> </ModalBody> </ModalContent> </Modal> Loading
Web/src/constants.ts 0 → 100644 +3 −0 Original line number Diff line number Diff line export const GALLERY_PAGE_SIZE = 12; // Divisible by 1, 2, 3, 4 export const MEDIA_ASPECT = 16 / 9;