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