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