Commit 425a0225 authored by Yuri Mikhin's avatar Yuri Mikhin Committed by Yuri Mikhin

Add clickable to app card.

parent b151c7e2
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="m11.003 6.276-5.267 5.267a.667.667 0 0 1-.943-.943l5.266-5.267H5.67A.667.667 0 1 1 5.67 4h6.667v6.667a.667.667 0 0 1-1.333 0V6.276Z" fill="currentColor"/>
</svg>
import { Box, Heading, Image, Text, useColorModeValue } from '@chakra-ui/react'; import { Box, Heading, Icon, Image, Link, LinkBox, LinkOverlay, Text, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import type { MouseEvent } from 'react';
import React, { useCallback } from 'react';
import type { AppItemPreview } from 'types/client/apps'; import type { AppItemPreview } from 'types/client/apps';
const AppCard = ({ title, logo, shortDescription, categories }: AppItemPreview) => { import northEastIcon from 'icons/arrows/north-east.svg';
interface Props extends AppItemPreview {
onInfoClick: (id: string) => void;
}
const AppCard = ({ id, title, logo, shortDescription, categories, onInfoClick }: Props) => {
const categoriesLabel = categories.map(c => c.name).join(', '); const categoriesLabel = categories.map(c => c.name).join(', ');
const handleInfoClick = useCallback((event: MouseEvent) => {
event.preventDefault();
onInfoClick(id);
}, [ onInfoClick, id ]);
return ( return (
<Box <LinkBox
borderRadius={{ base: 'none', sm: 'md' }} borderRadius="md"
height="100%" height="100%"
padding={{ base: '16px', sm: '20px' }} padding={{ base: 3, sm: '20px' }}
boxShadow={ `0 0 0 1px ${ useColorModeValue('var(--chakra-colors-gray-200)', 'var(--chakra-colors-gray-600)') }` } boxShadow={ `0 0 0 1px ${ useColorModeValue('var(--chakra-colors-gray-200)', 'var(--chakra-colors-gray-600)') }` }
> >
<Box overflow="hidden" height="100%"> <Box
display={{ base: 'grid', sm: 'block' }}
gridTemplateColumns={{ base: '64px 1fr', sm: '1fr' }}
gridTemplateRows={{ base: '20px 20px auto', sm: 'none' }}
gridRowGap={{ base: 2, sm: 'none' }}
gridColumnGap={{ base: 4, sm: 'none' }}
height="100%"
>
<Box <Box
gridRow={{ base: '1 / 4', sm: 'auto' }}
marginBottom={ 4 } marginBottom={ 4 }
w={{ base: '64px', sm: '96px' }} w={{ base: '64px', sm: '96px' }}
h={{ base: '64px', sm: '96px' }} h={{ base: '64px', sm: '96px' }}
...@@ -26,12 +46,20 @@ const AppCard = ({ title, logo, shortDescription, categories }: AppItemPreview) ...@@ -26,12 +46,20 @@ const AppCard = ({ title, logo, shortDescription, categories }: AppItemPreview)
</Box> </Box>
<Heading <Heading
gridColumn={{ base: 2, sm: 'auto' }}
as="h3" as="h3"
marginBottom={ 2 } marginBottom={ 2 }
fontSize={{ base: 'sm', sm: 'lg' }} fontSize={{ base: 'sm', sm: 'lg' }}
fontWeight="semibold" fontWeight="semibold"
> >
{ title } <LinkOverlay
href="#"
_hover={{
textDecoration: 'underline',
}}
>
{ title }
</LinkOverlay>
</Heading> </Heading>
<Text <Text
...@@ -49,9 +77,36 @@ const AppCard = ({ title, logo, shortDescription, categories }: AppItemPreview) ...@@ -49,9 +77,36 @@ const AppCard = ({ title, logo, shortDescription, categories }: AppItemPreview)
> >
{ shortDescription } { shortDescription }
</Text> </Text>
<Box
position="absolute"
right={{ base: 3, sm: '20px' }}
bottom={{ base: 3, sm: '20px' }}
paddingTop={ 1 }
paddingLeft={ 8 }
bgGradient={ `linear(to-r, transparent, ${ useColorModeValue('white', 'black') } 20%)` }
>
<Link
fontSize={{ base: 'xs', sm: 'sm' }}
display="flex"
alignItems="center"
paddingRight={{ sm: 2 }}
maxW="100%"
overflow="hidden"
href="#"
onClick={ handleInfoClick }
>
More
<Icon
as={ northEastIcon }
marginLeft={ 1 }
/>
</Link>
</Box>
</Box> </Box>
</Box> </LinkBox>
); );
}; };
export default AppCard; export default React.memo(AppCard);
...@@ -9,9 +9,10 @@ import EmptySearchResult from 'ui/apps/EmptySearchResult'; ...@@ -9,9 +9,10 @@ import EmptySearchResult from 'ui/apps/EmptySearchResult';
type Props = { type Props = {
apps: Array<AppItemPreview>; apps: Array<AppItemPreview>;
onAppClick: (id: string) => void;
} }
const AppList = ({ apps }: Props) => { const AppList = ({ apps, onAppClick }: Props) => {
return ( return (
<> <>
<VisuallyHidden> <VisuallyHidden>
...@@ -21,18 +22,18 @@ const AppList = ({ apps }: Props) => { ...@@ -21,18 +22,18 @@ const AppList = ({ apps }: Props) => {
{ apps.length > 0 ? ( { apps.length > 0 ? (
<Grid <Grid
templateColumns={{ templateColumns={{
base: 'repeat(auto-fill, minmax(160px, 1fr))', sm: 'repeat(auto-fill, minmax(170px, 1fr))',
sm: 'repeat(auto-fill, minmax(200px, 1fr))',
lg: 'repeat(auto-fill, minmax(260px, 1fr))', lg: 'repeat(auto-fill, minmax(260px, 1fr))',
}} }}
autoRows="1fr" autoRows="1fr"
gap={{ base: '1px', sm: '24px' }} gap={{ base: '16px', sm: '24px' }}
> >
{ apps.map((app) => ( { apps.map((app) => (
<GridItem <GridItem
key={ app.id } key={ app.id }
> >
<AppCard <AppCard
onInfoClick={ onAppClick }
id={ app.id } id={ app.id }
title={ app.title } title={ app.title }
logo={ app.logo } logo={ app.logo }
...@@ -49,4 +50,4 @@ const AppList = ({ apps }: Props) => { ...@@ -49,4 +50,4 @@ const AppList = ({ apps }: Props) => {
); );
}; };
export default AppList; export default React.memo(AppList);
...@@ -13,7 +13,11 @@ const defaultDisplayedApps = [ ...TEMPORARY_DEMO_APPS ] ...@@ -13,7 +13,11 @@ const defaultDisplayedApps = [ ...TEMPORARY_DEMO_APPS ]
const Apps = () => { const Apps = () => {
const [ displayedApps, setDisplayedApps ] = useState<Array<AppItemOverview>>(defaultDisplayedApps); const [ displayedApps, setDisplayedApps ] = useState<Array<AppItemOverview>>(defaultDisplayedApps);
const [ displayedAppId, setDisplayedAppId ] = useState<string | null>('component'); const [ displayedAppId, setDisplayedAppId ] = useState<string | null>(null);
const showAppInfo = useCallback((id: string) => {
setDisplayedAppId(id);
}, []);
const filterApps = (q: string) => { const filterApps = (q: string) => {
const apps = displayedApps const apps = displayedApps
...@@ -30,7 +34,7 @@ const Apps = () => { ...@@ -30,7 +34,7 @@ const Apps = () => {
return ( return (
<> <>
<FilterInput onChange={ debounceFilterApps } marginBottom={{ base: '4', lg: '6' }} placeholder="Find app"/> <FilterInput onChange={ debounceFilterApps } marginBottom={{ base: '4', lg: '6' }} placeholder="Find app"/>
<AppList apps={ displayedApps }/> <AppList apps={ displayedApps } onAppClick={ showAppInfo }/>
<AppModal <AppModal
id={ displayedAppId } id={ displayedAppId }
onClose={ clearDisplayedAppId } onClose={ clearDisplayedAppId }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment