xref: /expo/docs/ui/components/Home/Cells.tsx (revision c615fa2e)
1import { css } from '@emotion/react';
2import {
3  ArrowRightIcon,
4  ArrowUpRightIcon,
5  borderRadius,
6  breakpoints,
7  iconSize,
8  palette,
9  shadows,
10  spacing,
11  theme,
12  typography,
13} from '@expo/styleguide';
14import { PropsWithChildren } from 'react';
15import { Col, ColProps } from 'react-grid-system';
16
17import { A, P } from '~/ui/components/Text';
18
19const CustomCol = ({ children, sm, md, lg, xl, xxl }: PropsWithChildren<ColProps>) => (
20  <>
21    <Col css={cellWrapperStyle} sm={sm} md={md} lg={lg} xl={xl} xxl={xxl}>
22      {children}
23    </Col>
24    <div css={mobileCellWrapperStyle}>{children}</div>
25  </>
26);
27
28export const GridCell = ({
29  children,
30  sm,
31  md,
32  lg,
33  xl,
34  xxl,
35  className,
36}: PropsWithChildren<ColProps>) => (
37  <CustomCol css={cellWrapperStyle} sm={sm} md={md} lg={lg} xl={xl} xxl={xxl}>
38    <div css={cellStyle} className={className}>
39      {children}
40    </div>
41  </CustomCol>
42);
43
44type APIGridCellProps = ColProps & {
45  icon?: string | JSX.Element;
46  title?: string;
47  link?: string;
48};
49
50export const APIGridCell = ({
51  icon,
52  title,
53  link,
54  className,
55  sm = 6,
56  md = 6,
57  lg = 6,
58  xl = 3,
59}: APIGridCellProps) => (
60  <CustomCol css={cellWrapperStyle} md={md} sm={sm} lg={lg} xl={xl}>
61    <A href={link} css={[cellStyle, cellAPIStyle, cellHoverStyle]} className={className} isStyled>
62      <div css={cellIconWrapperStyle}>{icon}</div>
63      <div css={cellTitleWrapperStyle}>
64        {title}
65        <ArrowRightIcon color={theme.icon.secondary} />
66      </div>
67    </A>
68  </CustomCol>
69);
70
71type CommunityGridCellProps = APIGridCellProps & {
72  description?: string;
73  iconBackground?: string;
74};
75
76export const CommunityGridCell = ({
77  icon,
78  iconBackground = palette.light.gray11,
79  title,
80  link,
81  description,
82  className,
83  md = 6,
84}: CommunityGridCellProps) => (
85  <CustomCol css={cellWrapperStyle} md={md}>
86    <A
87      href={link}
88      css={[cellStyle, cellCommunityStyle, cellCommunityHoverStyle]}
89      className={className}
90      isStyled>
91      <div css={[cellCommunityIconWrapperStyle, css({ backgroundColor: iconBackground })]}>
92        {icon}
93      </div>
94      <div css={cellCommunityContentStyle}>
95        <span css={cellCommunityTitleStyle}>{title}</span>
96        <P css={cellCommunityDescriptionStyle}>{description}</P>
97      </div>
98      <ArrowUpRightIcon color={theme.icon.secondary} css={cellCommunityLinkIconStyle} />
99    </A>
100  </CustomCol>
101);
102
103const cellWrapperStyle = css`
104  padding-left: 0 !important;
105  padding-right: 0 !important;
106
107  @media screen and (max-width: ${breakpoints.medium}px) {
108    display: none;
109  }
110`;
111
112const mobileCellWrapperStyle = css({
113  width: '100%',
114
115  [`@media screen and (min-width: ${breakpoints.medium}px)`]: {
116    display: 'none',
117  },
118});
119
120const cellHoverStyle = css`
121  & {
122    transition: box-shadow 200ms;
123
124    svg {
125      transition: transform 200ms;
126    }
127  }
128
129  &:hover {
130    box-shadow: ${shadows.sm};
131
132    svg {
133      transform: scale(1.05);
134    }
135
136    svg[role='img'] {
137      transform: none;
138    }
139  }
140`;
141
142const cellStyle = css({
143  margin: spacing[4],
144  padding: spacing[8],
145  minHeight: 200,
146  overflow: 'hidden',
147  position: 'relative',
148  borderWidth: 1,
149  borderStyle: 'solid',
150  borderColor: theme.border.default,
151  borderRadius: borderRadius.lg,
152
153  h2: {
154    marginTop: 0,
155    marginBottom: 0,
156  },
157
158  h3: {
159    marginTop: 0,
160  },
161});
162
163const cellAPIStyle = css({
164  display: 'block',
165  backgroundColor: theme.background.subtle,
166  padding: 0,
167  overflow: 'hidden',
168  textDecoration: 'none',
169});
170
171const cellIconWrapperStyle = css({
172  display: 'flex',
173  minHeight: 136,
174  justifyContent: 'space-around',
175  alignItems: 'center',
176});
177
178const cellTitleWrapperStyle = css({
179  ...typography.fontSizes[15],
180  display: 'flex',
181  justifyContent: 'space-between',
182  backgroundColor: theme.background.default,
183  padding: spacing[4],
184  textDecoration: 'none',
185  fontWeight: 500,
186  lineHeight: '30px',
187  color: theme.text.default,
188  alignItems: 'center',
189});
190
191const cellCommunityStyle = css({
192  display: 'flex',
193  minHeight: `calc(100% - (2 * ${spacing[3]}px}))`,
194  padding: spacing[4],
195  margin: `${spacing[3]}px ${spacing[4]}px`,
196  flexDirection: 'row',
197  textDecoration: 'none',
198});
199
200const cellCommunityIconWrapperStyle = css({
201  height: 48,
202  width: 48,
203  minWidth: 48,
204  display: 'flex',
205  justifyContent: 'center',
206  alignItems: 'center',
207  borderRadius: borderRadius.lg,
208  marginRight: spacing[3],
209});
210
211const cellCommunityContentStyle = css({
212  flexGrow: 1,
213});
214
215const cellCommunityTitleStyle = css({
216  ...typography.fontSizes[16],
217  fontWeight: 500,
218  color: theme.text.default,
219  textDecoration: 'none',
220  marginBottom: spacing[2],
221});
222
223const cellCommunityDescriptionStyle = css({
224  ...typography.fontSizes[14],
225  color: theme.text.secondary,
226});
227
228const cellCommunityLinkIconStyle = css({
229  marginLeft: spacing[1.5],
230  alignSelf: 'center',
231  minWidth: iconSize.md,
232});
233
234const cellCommunityHoverStyle = css`
235  & {
236    transition: box-shadow 200ms;
237
238    svg {
239      transition: transform 200ms;
240    }
241  }
242
243  &:hover {
244    box-shadow: ${shadows.sm};
245
246    svg {
247      transform: scale(1.075);
248    }
249  }
250`;
251