refactor(details): migrate game details, thumbnails and menus to v3
- GameDetails/context menus: chakra context-menu dep replaced with MenuRoot shims, hover lift kept, FixedSelect play-status control, Link/Text/Separator prop renames - Features/Summary/SystemRequirements: Jodit + modal flows moved onto Dialog shims, v3 Button/Tag/Link tokens, carousel slide kept as-is - Preserves legacy dark card/menu surfaces via gray.950 -> v2 gray.700 mapping in the theme
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import agent from '../api/agent'
|
||||
import { useParams } from 'react-router'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -12,10 +12,9 @@ import {
|
||||
Spacer,
|
||||
Stack,
|
||||
Text,
|
||||
useColorModeValue,
|
||||
useDisclosure,
|
||||
useMediaQuery,
|
||||
} from '@chakra-ui/react'
|
||||
import {useColorModeValue} from './ui/color-mode'
|
||||
import {useDisclosure, useMediaQuery} from '@chakra-ui/react'
|
||||
import ImageSlider from './detailsComponents/ImageSlider'
|
||||
import Summary from './detailsComponents/Summary'
|
||||
import Features from './detailsComponents/Features'
|
||||
@@ -26,7 +25,7 @@ import { loadingState } from '../stateManagement/loadingState'
|
||||
import { ImmutableObject, useHookstate } from '@hookstate/core'
|
||||
import LoadingModal from './LoadingModal'
|
||||
import SteamAndDeckLogo from './helperComponents/SteamAndDeckLogo'
|
||||
import { ExternalLinkIcon } from '@chakra-ui/icons'
|
||||
import { LuExternalLink } from 'react-icons/lu'
|
||||
import { Data } from '../models/game'
|
||||
import SummaryModal from './detailsComponents/SummaryModal'
|
||||
import SystemRequirementsModal from './detailsComponents/SystemRequirementsModal'
|
||||
@@ -38,14 +37,14 @@ const GameDetails = () => {
|
||||
const loaded = loadedState.get()
|
||||
const { id } = useParams<{ id: string }>()
|
||||
const bg = useColorModeValue('white', 'gray.700')
|
||||
const { isOpen: isSummaryOpen, onOpen: onSummaryOpen, onClose: onSummaryClose } = useDisclosure()
|
||||
const { isOpen: isSystemOpen, onOpen: onSystemOpen, onClose: onSystemClose } = useDisclosure()
|
||||
const [isSmallerThan768] = useMediaQuery('(max-width: 768px)')
|
||||
const { open: isSummaryOpen, onOpen: onSummaryOpen, onClose: onSummaryClose } = useDisclosure()
|
||||
const { open: isSystemOpen, onOpen: onSystemOpen, onClose: onSystemClose } = useDisclosure()
|
||||
const [isSmallerThan768] = useMediaQuery(['(max-width: 768px)'])
|
||||
|
||||
useEffect(() => {
|
||||
const getGame = async () => {
|
||||
loadedState.set(false)
|
||||
return await agent.Games.details(id)
|
||||
return await agent.Games.details(id!)
|
||||
}
|
||||
getGame().then((result) => {
|
||||
gameState.set(result)
|
||||
@@ -69,7 +68,7 @@ const GameDetails = () => {
|
||||
<SystemRequirementsModal isOpen={isSystemOpen} onClose={onSystemClose} game={game} />
|
||||
|
||||
: ''}
|
||||
<Container maxW="container.xl" mt="5">
|
||||
<Container maxW="1280px" mt="5">
|
||||
<Flex direction={{ base: 'column', md: 'row' }}>
|
||||
<Box p={2} alignSelf={{
|
||||
base: 'center',
|
||||
@@ -78,25 +77,27 @@ const GameDetails = () => {
|
||||
<Heading as="h1">{game.title}</Heading>
|
||||
</Box>
|
||||
<Spacer />
|
||||
<Stack spacing={[1, 5]} direction={'row'} alignSelf={{
|
||||
<Stack gap={[1, 5]} direction={'row'} alignSelf={{
|
||||
base: 'center',
|
||||
md: 'end'
|
||||
}} pb="3">
|
||||
{game.accessedBy[0].store.includes('Steam') && game.steamId.length > 0 &&
|
||||
(<ChakraLink href={`steam://run/${game.steamId}`}>
|
||||
<Button variant={'outline'} colorScheme="blue">
|
||||
<Button variant={'outline'} colorPalette="blue">
|
||||
<Flex>
|
||||
<SteamAndDeckLogo size={'1.5em'} />
|
||||
<Text mt={'1'} ml={'2'}>
|
||||
Open with Steam <ExternalLinkIcon pb={'1'} />
|
||||
Open with Steam <LuExternalLink style={{display: 'inline'}} />
|
||||
</Text>
|
||||
</Flex>
|
||||
</Button>
|
||||
</ChakraLink>)}
|
||||
<Button as={Link} to={`/games/${game._id}/edit`} colorScheme="blue">
|
||||
<Button asChild colorPalette="blue">
|
||||
<Link to={`/games/${game._id}/edit`}>
|
||||
<Text mt={'1'}>
|
||||
Edit
|
||||
</Text>
|
||||
</Link>
|
||||
</Button>
|
||||
</Stack>
|
||||
</Flex>
|
||||
@@ -122,7 +123,7 @@ const GameDetails = () => {
|
||||
<Box bg={bg} p="5" mt="3" rounded="md">
|
||||
{isSmallerThan768 ?
|
||||
<Flex width="100%">
|
||||
<Button colorScheme='blue' size='lg' width='100%' onMouseDown={onSummaryOpen}>
|
||||
<Button colorPalette='blue' size='lg' width='100%' onMouseDown={onSummaryOpen}>
|
||||
About This Game
|
||||
</Button>
|
||||
<Spacer />
|
||||
@@ -138,7 +139,7 @@ const GameDetails = () => {
|
||||
<Box bg={bg} mt="3" p="5" rounded="md">
|
||||
{isSmallerThan768 ?
|
||||
<Flex width="100%">
|
||||
<Button colorScheme='blue' size='lg' width='100%' onMouseDown={onSystemOpen}>
|
||||
<Button colorPalette='blue' size='lg' width='100%' onMouseDown={onSystemOpen}>
|
||||
System Requirements
|
||||
</Button>
|
||||
<Spacer />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Data } from '../../models/game'
|
||||
import { Link as ChakraLink, Flex, Heading, Image, LinkBox, LinkOverlay, Spacer, Text } from '@chakra-ui/react'
|
||||
import { Link as ChakraLink, Flex, Heading, Image, Spacer, Text, Box } from '@chakra-ui/react'
|
||||
import GameRating from "../detailsComponents/GameRating";
|
||||
import SteamAndDeckLogo from "../helperComponents/SteamAndDeckLogo";
|
||||
|
||||
@@ -16,20 +16,21 @@ export default function GameThumbnail({ onToggle, game, playState }: Props) {
|
||||
const gameLink = game.accessedBy[0].store.includes('Steam') && game.steamId.length > 0 ? game.steamId : game._id
|
||||
return (
|
||||
<>
|
||||
<LinkBox
|
||||
as={Link}
|
||||
<Box
|
||||
asChild
|
||||
>
|
||||
<Link
|
||||
to={`/games/${gameLink}`}
|
||||
onMouseOver={onToggle}
|
||||
onMouseOut={onToggle}
|
||||
>
|
||||
<LinkOverlay>
|
||||
<Image borderTopRadius="md" src={game.frontImage} alt={game.title} />
|
||||
</LinkOverlay>
|
||||
<Heading m={2} size="md" my="2">
|
||||
{game.steamId !== '' ? `${game.steamId}: ${game.title}` : `${game.title}`}
|
||||
</Heading>
|
||||
<Text ml={2}>Play Status: {playState}</Text>
|
||||
</LinkBox>
|
||||
</Link>
|
||||
</Box>
|
||||
<Flex m={2}>
|
||||
<GameRating game={game} size={'1em'} />
|
||||
<Spacer />
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Data } from "../../models/game";
|
||||
import { ContextMenu } from 'chakra-ui-contextmenu';
|
||||
import { MenuItem, MenuList } from '@chakra-ui/menu';
|
||||
import { Menu, Portal } from '@chakra-ui/react';
|
||||
import GameThumbnail from "./GameThumbnail";
|
||||
import { Box, MenuGroup, useDisclosure } from "@chakra-ui/react";
|
||||
import { Box, useDisclosure } from "@chakra-ui/react";
|
||||
import GameThumbnailSlide from "./GameThumbnailSlide";
|
||||
import { playStatusValues } from "../../componentUtils/SelectValues";
|
||||
import agent from "../../api/agent";
|
||||
@@ -14,7 +13,7 @@ interface Props {
|
||||
}
|
||||
|
||||
const GameThumbnailContextMenu = ({ game }: Props) => {
|
||||
const { isOpen, onToggle } = useDisclosure()
|
||||
const { open: isOpen, onToggle } = useDisclosure()
|
||||
const [playState, setPlayState] = useState(game.accessedBy[0].playStatus)
|
||||
const gameLink = game.steamId.length > 1 ? game.steamId : game._id
|
||||
|
||||
@@ -34,20 +33,10 @@ const GameThumbnailContextMenu = ({ game }: Props) => {
|
||||
let mql = window.matchMedia('(max-width: 768px)');
|
||||
|
||||
return (
|
||||
<ContextMenu<HTMLDivElement> key={game._id} renderMenu={() => (
|
||||
<MenuList>
|
||||
<MenuItem><Link to={`/games/${gameLink}`} target="_blank" rel="noopener noreferrer">Open in New Tab</Link></MenuItem>
|
||||
<MenuGroup title={'Change PlayStatus'}>
|
||||
{playStatusValues.map(value => <MenuItem
|
||||
onClick={() => rightClick(value.label, value.value)}
|
||||
>{value.label}</MenuItem>)}
|
||||
</MenuGroup>
|
||||
</MenuList>
|
||||
)}>
|
||||
{ref => <>
|
||||
<Menu.Root key={game._id}>
|
||||
<Menu.ContextTrigger asChild>
|
||||
<Box
|
||||
ref={ref}
|
||||
border={'1px'}
|
||||
borderWidth={'1px'} borderStyle={'solid'}
|
||||
borderColor={'gray.500'}
|
||||
maxW={'sm'}
|
||||
rounded={'md'}
|
||||
@@ -58,10 +47,28 @@ const GameThumbnailContextMenu = ({ game }: Props) => {
|
||||
>
|
||||
<GameThumbnail onToggle={onToggle} game={game} playState={playState} />
|
||||
</Box>
|
||||
</Menu.ContextTrigger>
|
||||
<Portal>
|
||||
<Menu.Positioner>
|
||||
<Menu.Content>
|
||||
<Menu.Item value="open-new-tab" asChild>
|
||||
<Link to={`/games/${gameLink}`} target="_blank" rel="noopener noreferrer">Open in New Tab</Link>
|
||||
</Menu.Item>
|
||||
<Menu.ItemGroup>
|
||||
<Menu.ItemGroupLabel>Change PlayStatus</Menu.ItemGroupLabel>
|
||||
{playStatusValues.map((value, idx) => (
|
||||
<Menu.Item
|
||||
key={idx}
|
||||
value={value.value}
|
||||
onSelect={() => rightClick(value.label, value.value)}
|
||||
>{value.label}</Menu.Item>
|
||||
))}
|
||||
</Menu.ItemGroup>
|
||||
</Menu.Content>
|
||||
</Menu.Positioner>
|
||||
</Portal>
|
||||
{(!mql.matches) && <GameThumbnailSlide isOpen={isOpen} game={game} />}
|
||||
</>
|
||||
}
|
||||
</ContextMenu>
|
||||
</Menu.Root>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import {Box, Container, Heading, HStack, Slide} from "@chakra-ui/react";
|
||||
import {Box, Container, Heading, HStack, Presence} from "@chakra-ui/react";
|
||||
import {Data} from "../../models/game";
|
||||
import ImageSlider from "../detailsComponents/ImageSlider";
|
||||
|
||||
@@ -10,17 +10,25 @@ interface Props {
|
||||
|
||||
const GameThumbnailSlide = ({isOpen, game}: Props) => {
|
||||
return (
|
||||
<Slide direction="bottom" in={isOpen} unmountOnExit={true} style={{zIndex: 10}}>
|
||||
<Presence
|
||||
present={isOpen}
|
||||
position="fixed"
|
||||
bottom="0"
|
||||
insetX="0"
|
||||
animationName={{ _open: "slide-from-bottom-full", _closed: "slide-to-bottom-full" }}
|
||||
animationDuration="moderate"
|
||||
style={{zIndex: 10}}
|
||||
>
|
||||
<Box
|
||||
p="40px"
|
||||
color="white"
|
||||
mt="4"
|
||||
bgGradient={'linear(to-br, #314755, #26a0da)'}
|
||||
bgImage={'linear-gradient(to bottom right, #314755, #26a0da)'}
|
||||
borderTopRadius="md"
|
||||
shadow="md"
|
||||
>
|
||||
<Container maxW="container.xl">
|
||||
<HStack spacing='2rem'>
|
||||
<Container maxW="1280px">
|
||||
<HStack gap='2rem'>
|
||||
<ImageSlider game={game} width={'250px'}/>
|
||||
<Box>
|
||||
<Heading>{game.title}</Heading>
|
||||
@@ -29,7 +37,7 @@ const GameThumbnailSlide = ({isOpen, game}: Props) => {
|
||||
</HStack>
|
||||
</Container>
|
||||
</Box>
|
||||
</Slide>
|
||||
</Presence>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState as reactUseState } from 'react'
|
||||
import { Badge, Box, Divider, Flex, Heading, Link, Text } from '@chakra-ui/react'
|
||||
import { Badge, Box, Separator, Flex, Heading, Link, Text } from '@chakra-ui/react'
|
||||
import { Data } from '../../models/game'
|
||||
import { gameDashboardState } from '../../stateManagement/gameState'
|
||||
import { ImmutableObject, useHookstate } from '@hookstate/core'
|
||||
@@ -36,48 +36,40 @@ export default function Features({ game }: Props) {
|
||||
return history('/games')
|
||||
}
|
||||
|
||||
const badge = (label: string) => (
|
||||
<Box>
|
||||
<Badge colorPalette="blue" variant="outline" rounded="md" pl="2" pr="2">
|
||||
<Text pt="1" fontSize="sm">
|
||||
{label}
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
)
|
||||
|
||||
return (
|
||||
<Box mb="3">
|
||||
<Heading as="h3" size="lg">Features and Information</Heading>
|
||||
<Flex direction="column" m="2">
|
||||
<Box>
|
||||
<Badge colorScheme="blue" variant="outline" rounded="md" pl="2" pr="2">
|
||||
<Text pt="1" fontSize="sm">
|
||||
Rating:
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
{badge('Rating:')}
|
||||
<Box mt="1.5" ml="5" mr="2">
|
||||
<GameRating game={game} size={'1.5em'} />
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider orientation="horizontal" />
|
||||
<Separator borderColor="gray.200" orientation="horizontal" />
|
||||
{game.accessedBy[0].store.includes('Steam') && game.steamId.length > 0 &&
|
||||
(<>
|
||||
<Flex direction="column" m="2">
|
||||
<Box>
|
||||
<Badge colorScheme="blue" variant="outline" rounded="md" pl="2" pr="2">
|
||||
<Text pt="1" fontSize="sm">
|
||||
Steam ID:
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
{badge('Steam ID:')}
|
||||
<Box mt="1.5" ml="5" mr="2">
|
||||
<Link pt="1" href={`steam://run/${game.steamId}`}>{game.steamId}</Link>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider orientation="horizontal" />
|
||||
<Separator borderColor="gray.200" orientation="horizontal" />
|
||||
</>)}
|
||||
{game.series.length > 1 &&
|
||||
(<>
|
||||
<Flex direction="column" m="2">
|
||||
<Box>
|
||||
<Badge colorScheme="blue" variant="outline" rounded="md" pl="2" pr="2">
|
||||
<Text pt="1" fontSize="sm">
|
||||
Series:
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
{badge('Series:')}
|
||||
<Box mt="1.5" ml="5" mr="2">
|
||||
<Link onMouseDown={() => {
|
||||
gamesState.filters.series.set(game.series)
|
||||
@@ -85,16 +77,10 @@ export default function Features({ game }: Props) {
|
||||
}} pt="1">{game.series}</Link>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider orientation="horizontal" />
|
||||
<Separator borderColor="gray.200" orientation="horizontal" />
|
||||
</>)}
|
||||
<Flex direction="column" m="2">
|
||||
<Box>
|
||||
<Badge colorScheme="blue" variant="outline" rounded="md" pl="2" pr="2">
|
||||
<Text pt="1" fontSize="sm">
|
||||
Play Status:
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
{badge('Play Status:')}
|
||||
<Box mt="1.5" ml="5" mr="2">
|
||||
<Box display={'flex'}>
|
||||
{editMode ?
|
||||
@@ -120,15 +106,9 @@ export default function Features({ game }: Props) {
|
||||
</Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider orientation="horizontal" />
|
||||
<Separator borderColor="gray.200" orientation="horizontal" />
|
||||
<Flex direction="column" m="2">
|
||||
<Box>
|
||||
<Badge colorScheme="blue" variant="outline" rounded="md" pl="2" pr="2">
|
||||
<Text pt="1" fontSize="sm">
|
||||
Genre:
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
{badge('Genre:')}
|
||||
<Box mt={'2'} ml={'4'}>
|
||||
{game.genre.map((genre, index) => [
|
||||
index > 0 && ", ",
|
||||
@@ -141,15 +121,9 @@ export default function Features({ game }: Props) {
|
||||
])}
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider orientation="horizontal" />
|
||||
<Separator borderColor="gray.200" orientation="horizontal" />
|
||||
<Flex direction="column" m="2">
|
||||
<Box>
|
||||
<Badge colorScheme="blue" variant="outline" rounded="md" pl="2" pr="2">
|
||||
<Text pt="1" fontSize="sm">
|
||||
Operating Systems:
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
{badge('Operating Systems:')}
|
||||
<Box mt="1.5" ml="5" mr="2">
|
||||
<Text pt="1">
|
||||
{Object.keys(game.os).filter(os => {
|
||||
@@ -175,15 +149,9 @@ export default function Features({ game }: Props) {
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider orientation="horizontal" />
|
||||
<Separator borderColor="gray.200" orientation="horizontal" />
|
||||
<Flex direction="column" m="2">
|
||||
<Box>
|
||||
<Badge colorScheme="blue" variant="outline" rounded="md" pl="2" pr="2">
|
||||
<Text pt="1" fontSize="sm">
|
||||
Store:
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
{badge('Store:')}
|
||||
<Box mt="1.5" ml="5" mr="2">
|
||||
{game.accessedBy[0].store.map((store, index) => [
|
||||
index > 0 && ", ",
|
||||
@@ -196,15 +164,9 @@ export default function Features({ game }: Props) {
|
||||
])}
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider orientation="horizontal" />
|
||||
<Separator borderColor="gray.200" orientation="horizontal" />
|
||||
<Flex direction="column" m="2">
|
||||
<Box>
|
||||
<Badge colorScheme="blue" variant="outline" rounded="md" pl="2" pr="2">
|
||||
<Text pt="1" fontSize="sm">
|
||||
Developer:
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
{badge('Developer:')}
|
||||
<Box mt="1.5" ml="5" mr="2">
|
||||
{game.developer.map((developer, index) => [
|
||||
index > 0 && ", ",
|
||||
@@ -217,15 +179,9 @@ export default function Features({ game }: Props) {
|
||||
])}
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider orientation="horizontal" />
|
||||
<Separator borderColor="gray.200" orientation="horizontal" />
|
||||
<Flex direction="column" m="2">
|
||||
<Box>
|
||||
<Badge colorScheme="blue" variant="outline" rounded="md" pl="2" pr="2">
|
||||
<Text pt="1" fontSize="sm">
|
||||
Publisher:
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
{badge('Publisher:')}
|
||||
<Box mt="1.5" ml="5" mr="2">
|
||||
{game.publisher.map((publisher, index) => [
|
||||
index > 0 && ", ",
|
||||
@@ -238,15 +194,9 @@ export default function Features({ game }: Props) {
|
||||
])}
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider orientation="horizontal" />
|
||||
<Separator borderColor="gray.200" orientation="horizontal" />
|
||||
<Flex direction="column" m="2">
|
||||
<Box>
|
||||
<Badge colorScheme="blue" variant="outline" rounded="md" pl="2" pr="2">
|
||||
<Text pt="1" fontSize="sm">
|
||||
Controller Support:
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
{badge('Controller Support:')}
|
||||
<Box mt="1.5" ml="5" mr="2">
|
||||
<Link onMouseDown={() => {
|
||||
gamesState.filters.controller.set(game.controller)
|
||||
@@ -254,28 +204,16 @@ export default function Features({ game }: Props) {
|
||||
}} pt="1">{game.controller}</Link>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider orientation="horizontal" />
|
||||
<Separator borderColor="gray.200" orientation="horizontal" />
|
||||
<Flex direction="column" m="2">
|
||||
<Box>
|
||||
<Badge colorScheme="blue" variant="outline" rounded="md" pl="2" pr="2">
|
||||
<Text pt="1" fontSize="sm">
|
||||
Release Date:
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
{badge('Release Date:')}
|
||||
<Box mt="1.5" ml="5" mr="2">
|
||||
<Text pt="1">{game.releaseDate}</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider orientation="horizontal" />
|
||||
<Separator borderColor="gray.200" orientation="horizontal" />
|
||||
<Flex direction="column" m="2">
|
||||
<Box>
|
||||
<Badge colorScheme="blue" variant="outline" rounded="md" pl="2" pr="2">
|
||||
<Text pt="1" fontSize="sm">
|
||||
Soundtrack:
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
{badge('Soundtrack:')}
|
||||
<Box mt="1.5" ml="5" mr="2">
|
||||
<Link onMouseDown={() => {
|
||||
gamesState.filters.soundtrack.set(game.accessedBy[0].soundtrack)
|
||||
@@ -283,15 +221,9 @@ export default function Features({ game }: Props) {
|
||||
}} pt="1">{game.accessedBy[0].soundtrack}</Link>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider orientation="horizontal" />
|
||||
<Separator borderColor="gray.200" orientation="horizontal" />
|
||||
<Flex direction="column" m="2">
|
||||
<Box>
|
||||
<Badge colorScheme="blue" variant="outline" rounded="md" pl="2" pr="2">
|
||||
<Text pt="1" fontSize="sm">
|
||||
Does it work with Intel?:
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
{badge('Does it work with Intel?:')}
|
||||
<Box mt="1.5" ml="5" mr="2">
|
||||
<Link onMouseDown={() => {
|
||||
gamesState.filters.intel.set(game.intel)
|
||||
@@ -299,15 +231,9 @@ export default function Features({ game }: Props) {
|
||||
}} pt="1">{game.intel}</Link>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider orientation="horizontal" />
|
||||
<Separator borderColor="gray.200" orientation="horizontal" />
|
||||
<Flex direction="column" m="2">
|
||||
<Box>
|
||||
<Badge colorScheme="blue" variant="outline" rounded="md" pl="2" pr="2">
|
||||
<Text pt="1" fontSize="sm">
|
||||
Does it work with WINE?:
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
{badge('Does it work with WINE?:')}
|
||||
<Box mt="1.5" ml="5" mr="2">
|
||||
<Link onMouseDown={() => {
|
||||
gamesState.filters.wine.set(game.wine)
|
||||
@@ -315,7 +241,7 @@ export default function Features({ game }: Props) {
|
||||
}} pt="1">{game.wine}</Link>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider orientation="horizontal" />
|
||||
<Separator borderColor="gray.200" orientation="horizontal" />
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@ import React from 'react';
|
||||
import { Data } from '../../models/game'
|
||||
import agent from "../../api/agent";
|
||||
import {playStatusValues} from "../../componentUtils/SelectValues";
|
||||
import {Select} from "chakra-react-select";
|
||||
import {Select} from "../FixedSelect";
|
||||
import {ImmutableObject} from "@hookstate/core";
|
||||
|
||||
|
||||
interface Props {
|
||||
game: Data
|
||||
game: Data | ImmutableObject<Data>
|
||||
playState: string
|
||||
setPlayState: any
|
||||
}
|
||||
@@ -33,14 +34,14 @@ const GamePlayStatus = ({game, playState, setPlayState}: Props) => {
|
||||
value: playState,
|
||||
label: playState,
|
||||
}}
|
||||
onChange={(e) => {
|
||||
onChange={(e: any) => {
|
||||
if(e === null) return
|
||||
handleClick(e.value, e.label)
|
||||
}}
|
||||
size={'sm'}
|
||||
options={playStatusValues}
|
||||
chakraStyles={{
|
||||
container: (provided) => ({
|
||||
container: (provided: any) => ({
|
||||
...provided,
|
||||
width: "150px"
|
||||
})
|
||||
|
||||
@@ -5,10 +5,11 @@ import agent from "../../api/agent";
|
||||
import {Flex, Link} from "@chakra-ui/react";
|
||||
import {IoGameController, IoGameControllerOutline} from "react-icons/io5";
|
||||
import {BiReset} from "react-icons/bi";
|
||||
import {ImmutableObject} from "@hookstate/core";
|
||||
|
||||
|
||||
interface Props {
|
||||
game: Data
|
||||
game: Data | ImmutableObject<Data>
|
||||
size: string
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react'
|
||||
import { Data } from '../../models/game'
|
||||
import { Interweave } from 'interweave'
|
||||
import { Divider, Box, Heading } from '@chakra-ui/react'
|
||||
import { Separator, Box, Heading } from '@chakra-ui/react'
|
||||
import { ImmutableObject } from '@hookstate/core'
|
||||
|
||||
interface Props {
|
||||
@@ -15,7 +15,7 @@ export default function Summary({ game }: Props) {
|
||||
{reviews.length >= 1 && (
|
||||
<>
|
||||
<Heading as="h1">Reviews</Heading>
|
||||
<Divider m="3" />
|
||||
<Separator borderColor="gray.200" m="3" />
|
||||
<Interweave
|
||||
content={reviews}
|
||||
allowAttributes
|
||||
@@ -24,7 +24,7 @@ export default function Summary({ game }: Props) {
|
||||
</>
|
||||
)}
|
||||
<Heading mt={reviews.length >= 1 ? '10' : ''} as="h1">About This Game</Heading>
|
||||
<Divider m="3" />
|
||||
<Separator borderColor="gray.200" m="3" />
|
||||
<Interweave
|
||||
content={summary}
|
||||
allowAttributes
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react'
|
||||
import { Button, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay } from '@chakra-ui/react'
|
||||
import { Button, Dialog } from '@chakra-ui/react'
|
||||
import {DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogRoot} from '../ui/dialog'
|
||||
import Summary from './Summary'
|
||||
import { ImmutableObject } from '@hookstate/core'
|
||||
import { Data } from '../../models/game'
|
||||
@@ -14,20 +15,19 @@ interface Props {
|
||||
const SummaryModal = ({ isOpen, onClose, game }: Props) => {
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose}>
|
||||
<ModalOverlay />
|
||||
<ModalContent maxW={'90%'}>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<DialogRoot open={isOpen} onOpenChange={(e) => { if (!e.open) onClose() }}>
|
||||
<DialogContent maxW={'90%'}>
|
||||
<DialogCloseTrigger />
|
||||
<DialogBody>
|
||||
<Summary game={game} />
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button colorScheme='blue' onMouseDown={onClose}>
|
||||
</DialogBody>
|
||||
<DialogFooter>
|
||||
<Button colorPalette='blue' onMouseDown={onClose}>
|
||||
Close
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</DialogRoot>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { TabList, Tab, TabPanel, TabPanels, Tabs, Heading, Box } from '@chakra-ui/react'
|
||||
import { Tabs, Heading, Box } from '@chakra-ui/react'
|
||||
import { Data } from '../../models/game'
|
||||
import { Interweave } from 'interweave'
|
||||
import { ImmutableObject } from '@hookstate/core'
|
||||
@@ -20,51 +20,51 @@ export default function SystemRequirements({ game }: Props) {
|
||||
return (
|
||||
<Box>
|
||||
<Heading as='h3' size='lg'>System Requirements</Heading>
|
||||
<Tabs isLazy mt='3'>
|
||||
<TabList>
|
||||
<Tab>Windows</Tab>
|
||||
<Tab isDisabled={macMin}>Mac</Tab>
|
||||
<Tab isDisabled={linMin}>Linux</Tab>
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
<TabPanel>
|
||||
<Tabs isLazy>
|
||||
<TabList>
|
||||
<Tab>Minimum</Tab>
|
||||
<Tab isDisabled={winRec}>Recommended</Tab>
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
<TabPanel>{<Interweave content={windows.minimum} />}</TabPanel>
|
||||
<TabPanel>{<Interweave content={windows.recommended} />}</TabPanel>
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<Tabs isLazy>
|
||||
<TabList>
|
||||
<Tab isDisabled={macMin}>Minimum</Tab>
|
||||
<Tab isDisabled={macRec}>Recommended</Tab>
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
<TabPanel>{<Interweave content={mac.minimum} />}</TabPanel>
|
||||
<TabPanel>{<Interweave content={mac.recommended} />}</TabPanel>
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<Tabs isLazy>
|
||||
<TabList>
|
||||
<Tab isDisabled={linMin}>Minimum</Tab>
|
||||
<Tab isDisabled={linRec}>Recommended</Tab>
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
<TabPanel>{<Interweave content={linux.minimum} />}</TabPanel>
|
||||
<TabPanel>{<Interweave content={linux.recommended} />}</TabPanel>
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
</TabPanel>
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
<Tabs.Root lazyMount mt='3' defaultValue="windows">
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="windows">Windows</Tabs.Trigger>
|
||||
<Tabs.Trigger value="mac" disabled={macMin}>Mac</Tabs.Trigger>
|
||||
<Tabs.Trigger value="linux" disabled={linMin}>Linux</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
<Tabs.ContentGroup>
|
||||
<Tabs.Content value="windows">
|
||||
<Tabs.Root lazyMount defaultValue="win-min">
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="win-min">Minimum</Tabs.Trigger>
|
||||
<Tabs.Trigger value="win-rec" disabled={winRec}>Recommended</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
<Tabs.ContentGroup>
|
||||
<Tabs.Content value="win-min">{<Interweave content={windows.minimum} />}</Tabs.Content>
|
||||
<Tabs.Content value="win-rec">{<Interweave content={windows.recommended} />}</Tabs.Content>
|
||||
</Tabs.ContentGroup>
|
||||
</Tabs.Root>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="mac">
|
||||
<Tabs.Root lazyMount defaultValue="mac-min">
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="mac-min" disabled={macMin}>Minimum</Tabs.Trigger>
|
||||
<Tabs.Trigger value="mac-rec" disabled={macRec}>Recommended</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
<Tabs.ContentGroup>
|
||||
<Tabs.Content value="mac-min">{<Interweave content={mac.minimum} />}</Tabs.Content>
|
||||
<Tabs.Content value="mac-rec">{<Interweave content={mac.recommended} />}</Tabs.Content>
|
||||
</Tabs.ContentGroup>
|
||||
</Tabs.Root>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="linux">
|
||||
<Tabs.Root lazyMount defaultValue="lin-min">
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="lin-min" disabled={linMin}>Minimum</Tabs.Trigger>
|
||||
<Tabs.Trigger value="lin-rec" disabled={linRec}>Recommended</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
<Tabs.ContentGroup>
|
||||
<Tabs.Content value="lin-min">{<Interweave content={linux.minimum} />}</Tabs.Content>
|
||||
<Tabs.Content value="lin-rec">{<Interweave content={linux.recommended} />}</Tabs.Content>
|
||||
</Tabs.ContentGroup>
|
||||
</Tabs.Root>
|
||||
</Tabs.Content>
|
||||
</Tabs.ContentGroup>
|
||||
</Tabs.Root>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react'
|
||||
import { Button, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay } from '@chakra-ui/react'
|
||||
import { Button } from '@chakra-ui/react'
|
||||
import {DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogRoot} from '../ui/dialog'
|
||||
import { ImmutableObject } from '@hookstate/core'
|
||||
import { Data } from '../../models/game'
|
||||
import SystemRequirements from './SystemRequirementsMenu'
|
||||
@@ -14,20 +15,19 @@ interface Props {
|
||||
const SummaryModal = ({ isOpen, onClose, game }: Props) => {
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose}>
|
||||
<ModalOverlay />
|
||||
<ModalContent maxW={'90%'}>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<DialogRoot open={isOpen} onOpenChange={(e) => { if (!e.open) onClose() }}>
|
||||
<DialogContent maxW={'90%'}>
|
||||
<DialogCloseTrigger />
|
||||
<DialogBody>
|
||||
<SystemRequirements game={game} />
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button colorScheme='blue' onMouseDown={onClose}>
|
||||
</DialogBody>
|
||||
<DialogFooter>
|
||||
<Button colorPalette='blue' onMouseDown={onClose}>
|
||||
Close
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</DialogRoot>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user