xref: /expo/docs/ui/components/Home/Cells.tsx (revision dfd15ebd)
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}>
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.gray['800'],
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      <div css={[cellCommunityIconWrapperStyle, css({ backgroundColor: iconBackground })]}>
91        {icon}
92      </div>
93      <div css={cellCommunityContentStyle}>
94        <span css={cellCommunityTitleStyle}>{title}</span>
95        <P css={cellCommunityDescriptionStyle}>{description}</P>
96      </div>
97      <ArrowUpRightIcon color={theme.icon.secondary} css={cellCommunityLinkIconStyle} />
98    </a>
99  </CustomCol>
100);
101
102const cellWrapperStyle = css`
103  padding-left: 0 !important;
104  padding-right: 0 !important;
105
106  @media screen and (max-width: ${breakpoints.medium}px) {
107    display: none;
108  }
109`;
110
111const mobileCellWrapperStyle = css({
112  width: '100%',
113
114  [`@media screen and (min-width: ${breakpoints.medium}px)`]: {
115    display: 'none',
116  },
117});
118
119const cellHoverStyle = css`
120  & {
121    transition: box-shadow 200ms;
122
123    svg {
124      transition: transform 200ms;
125    }
126  }
127
128  &:hover {
129    box-shadow: ${shadows.tiny};
130
131    svg {
132      transform: scale(1.05);
133    }
134
135    svg[role='img'] {
136      transform: none;
137    }
138  }
139`;
140
141const cellStyle = css({
142  margin: spacing[4],
143  padding: spacing[8],
144  minHeight: 200,
145  overflow: 'hidden',
146  position: 'relative',
147  borderWidth: 1,
148  borderStyle: 'solid',
149  borderColor: theme.border.default,
150  borderRadius: borderRadius.large,
151});
152
153const cellAPIStyle = css({
154  display: 'block',
155  backgroundColor: theme.background.secondary,
156  padding: 0,
157  overflow: 'hidden',
158  textDecoration: 'none',
159});
160
161const cellIconWrapperStyle = css({
162  display: 'flex',
163  minHeight: 136,
164  justifyContent: 'space-around',
165  alignItems: 'center',
166});
167
168const cellTitleWrapperStyle = css({
169  ...typography.fontSizes[15],
170  display: 'flex',
171  justifyContent: 'space-between',
172  backgroundColor: theme.background.default,
173  padding: spacing[4],
174  textDecoration: 'none',
175  fontFamily: typography.fontStacks.medium,
176  lineHeight: '30px',
177  color: theme.text.default,
178  alignItems: 'center',
179});
180
181const cellCommunityStyle = css({
182  display: 'flex',
183  minHeight: `calc(100% - (2 * ${spacing[3]}px}))`,
184  padding: spacing[4],
185  margin: `${spacing[3]}px ${spacing[4]}px`,
186  flexDirection: 'row',
187  textDecoration: 'none',
188});
189
190const cellCommunityIconWrapperStyle = css({
191  height: 48,
192  width: 48,
193  minWidth: 48,
194  display: 'flex',
195  justifyContent: 'center',
196  alignItems: 'center',
197  borderRadius: borderRadius.large,
198  marginRight: spacing[3],
199});
200
201const cellCommunityContentStyle = css({
202  flexGrow: 1,
203});
204
205const cellCommunityTitleStyle = css({
206  ...typography.fontSizes[16],
207  fontFamily: typography.fontStacks.medium,
208  color: theme.text.default,
209  textDecoration: 'none',
210  marginBottom: spacing[2],
211});
212
213const cellCommunityDescriptionStyle = css({
214  ...typography.fontSizes[14],
215  color: theme.text.secondary,
216});
217
218const cellCommunityLinkIconStyle = css({
219  marginLeft: spacing[1.5],
220  alignSelf: 'center',
221  minWidth: iconSize.regular,
222});
223
224const cellCommunityHoverStyle = css`
225  & {
226    transition: box-shadow 200ms;
227
228    svg {
229      transition: transform 200ms;
230    }
231  }
232
233  &:hover {
234    box-shadow: ${shadows.tiny};
235
236    svg {
237      transform: scale(1.075);
238    }
239  }
240`;
241