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 React from 'react';
import { Box, Heading, Icon, Image, Link, LinkBox, LinkOverlay, Text, useColorModeValue } from '@chakra-ui/react';
import type { MouseEvent } from 'react';
import React, { useCallback } from 'react';
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 handleInfoClick = useCallback((event: MouseEvent) => {
event.preventDefault();
onInfoClick(id);
}, [ onInfoClick, id ]);
return (
<Box
borderRadius={{ base: 'none', sm: 'md' }}
<LinkBox
borderRadius="md"
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)') }` }
>
<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
gridRow={{ base: '1 / 4', sm: 'auto' }}
marginBottom={ 4 }
w={{ base: '64px', sm: '96px' }}
h={{ base: '64px', sm: '96px' }}
......@@ -26,12 +46,20 @@ const AppCard = ({ title, logo, shortDescription, categories }: AppItemPreview)
</Box>
<Heading
gridColumn={{ base: 2, sm: 'auto' }}
as="h3"
marginBottom={ 2 }
fontSize={{ base: 'sm', sm: 'lg' }}
fontWeight="semibold"
>
{ title }
<LinkOverlay
href="#"
_hover={{
textDecoration: 'underline',
}}
>
{ title }
</LinkOverlay>
</Heading>
<Text
......@@ -49,9 +77,36 @@ const AppCard = ({ title, logo, shortDescription, categories }: AppItemPreview)
>
{ shortDescription }
</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>
</LinkBox>
);
};
export default AppCard;
export default React.memo(AppCard);
......@@ -9,9 +9,10 @@ import EmptySearchResult from 'ui/apps/EmptySearchResult';
type Props = {
apps: Array<AppItemPreview>;
onAppClick: (id: string) => void;
}
const AppList = ({ apps }: Props) => {
const AppList = ({ apps, onAppClick }: Props) => {
return (
<>
<VisuallyHidden>
......@@ -21,18 +22,18 @@ const AppList = ({ apps }: Props) => {
{ apps.length > 0 ? (
<Grid
templateColumns={{
base: 'repeat(auto-fill, minmax(160px, 1fr))',
sm: 'repeat(auto-fill, minmax(200px, 1fr))',
sm: 'repeat(auto-fill, minmax(170px, 1fr))',
lg: 'repeat(auto-fill, minmax(260px, 1fr))',
}}
autoRows="1fr"
gap={{ base: '1px', sm: '24px' }}
gap={{ base: '16px', sm: '24px' }}
>
{ apps.map((app) => (
<GridItem
key={ app.id }
>
<AppCard
onInfoClick={ onAppClick }
id={ app.id }
title={ app.title }
logo={ app.logo }
......@@ -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 ]
const Apps = () => {
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 apps = displayedApps
......@@ -30,7 +34,7 @@ const Apps = () => {
return (
<>
<FilterInput onChange={ debounceFilterApps } marginBottom={{ base: '4', lg: '6' }} placeholder="Find app"/>
<AppList apps={ displayedApps }/>
<AppList apps={ displayedApps } onAppClick={ showAppInfo }/>
<AppModal
id={ displayedAppId }
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