Skip to content

Commit

Permalink
Merge pull request #124 from chomosuke/yujian/homeView-Style
Browse files Browse the repository at this point in the history
Yujian/home view style
  • Loading branch information
oldbugo committed Oct 2, 2021
2 parents e647d64 + e9ce4a5 commit 0aae100
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 32 deletions.
78 changes: 68 additions & 10 deletions web/src/components/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,56 @@
import React, { useRef } from 'react';
import PropTypes from 'prop-types';
import {
IImageProps, Image, ImageFit, Label, Stack, mergeStyleSets,
IImageProps, Image, ImageFit, Label, Stack, keyframes, mergeStyleSets,
} from '@fluentui/react';
import { ICard } from '../controllers/Card';
import { useHome } from '../HomeContext';
import { cancelLoading } from './cardDetails/CardImageField';
import { useApp } from '../AppContext';
import { Theme, useTheme } from '../theme';

export interface ICardProps {
card: ICard;
selected: boolean;
}

const getClassNames = () => {
const getClassNames = (selected: boolean, theme: Theme) => {
const height = '300px';
const width = '300px';

const focusDecorator = keyframes({
from: {
boxShadow: '2px 4px 4px hsl(0deg 0% 0% / 0.25)',
},
to: {
boxShadow: '8px 16px 16px hsl(0deg 0% 0% / 0.25)',
},
});

const overflowCutOff = {
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
};

const fontStandard = {
...theme.fontFamily.roboto,
...theme.fontSize.small,
color: theme.palette.sootyBee,
};

return mergeStyleSets({
root: {
height,
width,
background: theme.palette.justWhite,
...theme.shape.default,
'&:hover': {
borderRadius: '8px',
animationName: focusDecorator,
animationDuration: '0.2s',
animationFillMode: 'forwards',
},
},
cardContent: {
height,
Expand All @@ -31,25 +62,48 @@ const getClassNames = () => {
cursor: 'pointer',
height,
width,
borderRadius: '8px',
top: '-100%',
left: '0',
position: 'relative',
zIndex: '1',
...(selected
? {
background: 'rgb(255, 255, 255, 0.05)',
boxShadow: '8px 16px 16px hsl(0deg 0% 0% / 0.25)',
}
: {}),
},
imageContainer: {
height: '200px',
width,
},
labelContainer: {
margin: '16px',
},
mainLabel: {
...fontStandard,
fontSize: '18px',
...theme.fontWeight.bold,
...overflowCutOff,
},
subLabel: {
...fontStandard,
...theme.fontWeight.medium,
...overflowCutOff,
},
});
};

const imageStyles: IImageProps['styles'] = {
root: {
height: 200,
height: '200px',
width: '300px',
borderRadius: '8px 8px 0 0',
},
};

export const Card: React.VoidFunctionComponent<ICardProps> = ({ card }) => {
export const Card: React.VoidFunctionComponent<ICardProps> = ({ card, selected }) => {
const {
name,
phone,
Expand All @@ -58,10 +112,11 @@ export const Card: React.VoidFunctionComponent<ICardProps> = ({ card }) => {
} = card;
const { showCardDetail } = useApp();
const { lockCard } = useHome();
const theme = useTheme();

const {
root, cardContent, target, imageContainer,
} = getClassNames();
root, cardContent, target, imageContainer, mainLabel, subLabel, labelContainer,
} = getClassNames(selected, theme);

const ref = useRef<HTMLDivElement>(null);

Expand All @@ -80,14 +135,16 @@ export const Card: React.VoidFunctionComponent<ICardProps> = ({ card }) => {
{image != null && (
<Image
src={image}
imageFit={ImageFit.contain}
imageFit={ImageFit.cover}
styles={imageStyles}
/>
)}
</div>
<Label>{name}</Label>
<Label>{phone}</Label>
<Label>{jobTitle}</Label>
<div className={labelContainer}>
<Label className={mainLabel}>{name}</Label>
<Label className={subLabel}>{phone}</Label>
<Label className={subLabel}>{jobTitle}</Label>
</div>
</Stack>
<div
className={target}
Expand All @@ -99,4 +156,5 @@ export const Card: React.VoidFunctionComponent<ICardProps> = ({ card }) => {

Card.propTypes = {
card: (PropTypes.object as React.Requireable<ICard>).isRequired,
selected: PropTypes.bool.isRequired,
};
26 changes: 21 additions & 5 deletions web/src/components/TagButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { DefaultButton, IButtonProps, mergeStyleSets } from '@fluentui/react';
import PropTypes, { Requireable } from 'prop-types';
import React from 'react';
import { ITag } from '../controllers/Tag';
import { useTheme } from '../theme';

type OnClickHandler = IButtonProps['onClick'];

Expand All @@ -12,19 +13,34 @@ export interface ITagButtonProps {

const getClassNames = () => mergeStyleSets({
tagContainer: {
height: '100%',
outerWidth: '60px',
},
});

export const TagButton: React.VoidFunctionComponent<ITagButtonProps> = ({ tag, onClick }) => {
const theme = useTheme();
const tagStyles = {
root: {
backgroundColor: tag.color,
border: 'none',
padding: '0 48px',
borderStyle: 'solid',
borderWidth: '2px',
borderColor: tag.color,
whiteSpace: 'nowrap',
padding: '0 32px',
margin: '0 12px',
outerHeight: '48px',
height: '32px',
borderRadius: '4px',
...theme.fontFamily.roboto,
...theme.fontSize.small,
color: theme.palette.justWhite,
},
rootHovered: {
background: tag.color,
color: theme.palette.justWhite,
opacity: '0.8',
},
rootPressed: {
background: theme.palette.quartz,
color: tag.color,
},
};

Expand Down
109 changes: 92 additions & 17 deletions web/src/views/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@ import PropTypes from 'prop-types';
import React, {
RefObject, createRef, useEffect, useRef, useState,
} from 'react';
import { Stack, mergeStyleSets } from '@fluentui/react';
import { mergeStyleSets } from '@fluentui/react';
import { useApp } from '../AppContext';
import { HomeProvider } from '../HomeContext';
import { Card } from '../components/Card';
import { ICard } from '../controllers/Card';
import { CardDetails } from '../components/cardDetails/CardDetails';
import { useViewportSize } from '../ViewportSize';
import { TagButton } from '../components/TagButton';
import { Theme, useTheme } from '../theme';

export interface IHomeProps {
detail?: ICard;
}

const getClassNames = (expand: boolean, detail: boolean) => {
const getClassNames = (expand: boolean, detail: boolean, theme: Theme) => {
let templateColumnVar;
if (detail) {
templateColumnVar = expand ? '1fr 1fr' : '2fr 1fr';
Expand All @@ -25,31 +26,74 @@ const getClassNames = (expand: boolean, detail: boolean) => {

return mergeStyleSets({
root: {
height: '100%',
display: 'grid',
gridTemplateAreas: '"a b"',
gridTemplateColumns: templateColumnVar,
height: '100%',
background: theme.palette.quartz,
},
cardSection: {
cardGridContainer: {
gridArea: 'a',
width: 'content-width',
paddingLeft: '12vw',
paddingRight: (detail ? '4vw' : '12vw'),
paddingBottom: '200px',

overflow: 'auto',
},
cardSection: {
display: 'grid',
justifyContent: 'center',
gridTemplateColumns: 'repeat(auto-fill, 300px)',
gridGap: '72px 72px',
},
detailSection: {
gridArea: 'b',
height: '100%',
overflow: 'auto',
},
tagSection: {
display: 'flex',
margin: '48px 0 72px 0',
},
scrollButtonContainer: {
display: 'flex',
justifyContent: 'left',
alignItems: 'center',
cursor: 'pointer',
border: 'none',
height: '48px',
width: '60px',
background:
'linear-gradient(90deg, '
+ 'rgba(248,248,248,1) 50%, '
+ 'rgba(248,248,248,0.4) 80%, '
+ 'rgba(248,248,248,0) 100%)',
position: 'abosolute',
zIndex: '10',
},
scrollButton: {
height: '32px',
width: '32px',
color: theme.palette.darkDenim,
},
spacers: {
minWidth: '72px',
},
tagList: {
// flex: '1',
display: 'flex',
flexDirection: 'row',
width: '100%',
overflowX: 'scroll',

scrollBehavior: 'smooth',
margin: '24px 0',
margin: '8px -60px',
zIndex: '1',

// hide scrollbars across different browsers
scrollbarWidth: 'none',
'::-webkit-scrollbar': {
display: 'none',
},
},
});
};
Expand Down Expand Up @@ -195,14 +239,25 @@ export const Home: React.VoidFunctionComponent<IHomeProps> = ({ detail }) => {
* autoScroll end
*/

const {
root, cardSection, detailSection, tagList, tagSection,
} = getClassNames(expand, Boolean(detail));
const { user, searchQuery, tagQuery } = useApp();
if (user == null) throw new Error();

const { cards, tags } = user;
const context = useApp();
const theme = useTheme();

const {
root,
cardGridContainer,
cardSection,
detailSection,
tagList,
tagSection,
scrollButtonContainer,
scrollButton,
spacers,
} = getClassNames(expand, Boolean(detail), theme);
const rotate180 = { transform: 'rotate(180deg)' };

function filterCard(card: ICard): boolean {
const searchTokens = searchQuery.split(/\W/).filter((x) => x.length > 0);
Expand Down Expand Up @@ -240,10 +295,17 @@ export const Home: React.VoidFunctionComponent<IHomeProps> = ({ detail }) => {
}}
>
<div className={root}>
<div className={cardSection} ref={cardSectionRef} onScroll={onCardScroll}>
<div className={cardGridContainer} ref={cardSectionRef} onScroll={onCardScroll}>
<div className={tagSection}>
<button type='button' onClick={() => scroll(-200)}> scroll left </button>
<button
type='button'
className={scrollButtonContainer}
onClick={() => scroll(-(viewPortSize.width / 3))}
>
<theme.icon.caretLeft className={scrollButton} />
</button>
<div className={tagList} ref={tagScrollRef}>
<div className={spacers} />
{tags.map((tag) => (
<TagButton
key={tag.id}
Expand All @@ -255,13 +317,26 @@ export const Home: React.VoidFunctionComponent<IHomeProps> = ({ detail }) => {
}}
/>
))}
<div className={spacers} />
</div>
<button type='button' onClick={() => scroll(200)}> scroll right </button>
<button
type='button'
className={scrollButtonContainer}
onClick={() => scroll(viewPortSize.width / 3)}
style={rotate180}
>
<theme.icon.caretLeft className={scrollButton} />
</button>
</div>
<div className={cardSection}>
{cards.filter(filterCard).map((card) => (
<Card
key={card.id}
selected={card.id === detail?.id}
card={card}
/>
))}
</div>

<Stack horizontal wrap>
{cards.filter(filterCard).map((card) => <Card key={card.id} card={card} />)}
</Stack>
</div>
{detail != null
&& (
Expand Down

0 comments on commit 0aae100

Please sign in to comment.