Skip to content

Commit cd0c957

Browse files
authored
Merge pull request #8679 from TylerAPfledderer/refactor/staking-products-card-grid-chakra
Refactor: Migrate `StakingProductsCardGrid` to Chakra
2 parents 3d32135 + 30e9f74 commit cd0c957

File tree

1 file changed

+148
-169
lines changed

1 file changed

+148
-169
lines changed

src/components/Staking/StakingProductsCardGrid.tsx

Lines changed: 148 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
11
import React, {
22
ComponentType,
3+
ReactNode,
34
SVGProps,
4-
useContext,
55
useEffect,
66
useState,
77
} from "react"
8-
import styled from "@emotion/styled"
9-
import { useTheme } from "@emotion/react"
108
import { shuffle } from "lodash"
9+
import {
10+
Box,
11+
BoxProps,
12+
Center,
13+
Flex,
14+
Heading,
15+
HStack,
16+
Icon,
17+
List,
18+
ListIcon,
19+
ListItem,
20+
SimpleGrid,
21+
useColorModeValue,
22+
} from "@chakra-ui/react"
1123
// Data imports
1224
import stakingProducts from "../../data/staking-products.json"
1325
// Component imports
@@ -38,135 +50,17 @@ import Wagyu from "../../assets/staking/wagyu-glyph.svg"
3850
import { EventOptions } from "../../utils/matomo"
3951
// When adding a product svg, be sure to add to mapping below as well.
4052

41-
const CardGrid = styled.div`
42-
display: grid;
43-
grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
44-
gap: 2rem;
45-
margin: 3rem 0;
46-
`
47-
48-
const Card = styled.div`
49-
display: flex;
50-
flex-direction: column;
51-
background: ${({ theme }) => theme.colors.offBackground};
52-
border-radius: 0.25rem;
53-
&:hover {
54-
transition: 0.1s;
55-
transform: scale(1.01);
56-
}
57-
`
58-
59-
const PaddedDiv = styled.div`
60-
padding: 1.5rem 2rem;
61-
`
62-
63-
const Spacer = styled.div`
64-
flex: 1;
65-
`
66-
67-
const Banner = styled(PaddedDiv)`
68-
display: flex;
69-
align-items: center;
70-
gap: 1.5rem;
71-
background: ${({ color }) => color}
72-
linear-gradient(0deg, rgba(0, 0, 0, 30%), rgba(0, 0, 0, 0));
73-
border-radius: 0.25rem;
74-
max-height: 6rem;
75-
h2 {
76-
margin: 0;
77-
color: white;
78-
font-size: 1.5rem;
79-
}
80-
svg {
81-
height: 2rem;
82-
}
83-
`
84-
85-
const MinEthBar = styled.div`
86-
display: flex;
87-
justify-content: center;
88-
align-items: center;
89-
font-weight: 700;
90-
font-size: 1rem;
91-
color: ${({ theme }) => theme.colors.textTableOfContents};
92-
text-transform: uppercase;
93-
padding-top: 1.5rem;
94-
`
95-
96-
const Pills = styled(PaddedDiv)`
97-
display: flex;
98-
flex-wrap: wrap;
99-
gap: 0.25rem;
100-
/* padding-top: 1rem; */
101-
`
102-
103-
const Pill = styled.div<{ type: string }>`
104-
text-align: center;
105-
padding: 0.25rem 0.75rem;
106-
color: ${({ theme, type }) =>
107-
type ? "rgba(0, 0, 0, 0.6)" : theme.colors.text200};
108-
background: ${({ theme, type }) => {
109-
if (!type) return "transparent"
110-
switch (type.toLowerCase()) {
111-
case "ui":
112-
return theme.colors.stakingPillUI
113-
case "platform":
114-
return theme.colors.stakingPillPlatform
115-
default:
116-
return theme.colors.tagGray
117-
}
118-
}};
119-
font-size: ${({ theme }) => theme.fontSizes.xs};
120-
border: 1px solid ${({ theme }) => theme.colors.lightBorder};
121-
border-radius: 0.25rem;
122-
`
123-
124-
const Content = styled(PaddedDiv)`
125-
padding-top: 0;
126-
padding-bottom: 0;
127-
128-
ul {
129-
list-style: none;
130-
margin-left: 0;
131-
padding-left: 0;
132-
}
133-
`
134-
135-
const Item = styled.li`
136-
display: flex;
137-
align-items: center;
138-
text-indent: 1em;
139-
text-transform: uppercase;
140-
font-weight: 400;
141-
font-size: 0.75rem;
142-
line-height: 0.875rem;
143-
letter-spacing: 0.04em;
144-
145-
p {
146-
margin: 1rem auto 1rem 0;
147-
}
148-
`
149-
150-
const Cta = styled(PaddedDiv)`
151-
a {
152-
width: 100%;
153-
}
154-
`
53+
const PADDED_DIV_STYLE: BoxProps = {
54+
px: 8,
55+
py: 6,
56+
}
15557

156-
const Status: React.FC<{ status: FlagType }> = ({ status }) => {
157-
if (!status) return null
158-
const styles = { width: "24", height: "auto" }
159-
switch (status) {
160-
case "green-check":
161-
return <GreenCheck style={styles} />
162-
case "caution":
163-
return <Caution style={styles} />
164-
case "warning":
165-
case "false":
166-
return <Warning style={styles} />
167-
default:
168-
return <Unknown style={styles} />
169-
}
58+
enum FlagType {
59+
VALID = "green-check",
60+
CAUTION = "caution",
61+
WARNING = "warning",
62+
FALSE = "false",
63+
UNKNOWN = "unknown",
17064
}
17165

17266
const getSvgFromPath = (
@@ -192,12 +86,54 @@ const getSvgFromPath = (
19286
}
19387
return mapping[svgPath]
19488
}
195-
enum FlagType {
196-
VALID = "green-check",
197-
CAUTION = "caution",
198-
WARNING = "warning",
199-
FALSE = "false",
200-
UNKNOWN = "unknown",
89+
90+
const Status: React.FC<{ status: FlagType }> = ({ status }) => {
91+
if (!status) return null
92+
93+
const styles = { fontSize: "2xl", m: 0 }
94+
switch (status) {
95+
case "green-check":
96+
return <ListIcon as={GreenCheck} {...styles} />
97+
case "caution":
98+
return <ListIcon as={Caution} {...styles} />
99+
case "warning":
100+
case "false":
101+
return <ListIcon as={Warning} {...styles} />
102+
default:
103+
return <ListIcon as={Unknown} {...styles} />
104+
}
105+
}
106+
107+
const StakingPill: React.FC<{ type: string; children: ReactNode }> = ({
108+
type,
109+
children,
110+
}) => {
111+
const backgroundColor = () => {
112+
if (!type) return "transparent"
113+
switch (type.toLowerCase()) {
114+
case "ui":
115+
return "stakingPillUI"
116+
case "platform":
117+
return "stakingPillPlatform"
118+
default:
119+
return "tagGray"
120+
}
121+
}
122+
return (
123+
<Box
124+
background={backgroundColor()}
125+
border="1px"
126+
borderColor="lightBorder"
127+
borderRadius="base"
128+
color={type ? "rgba(0,0,0,0.6)" : "text200"}
129+
fontSize="xs"
130+
px={3}
131+
py={1}
132+
textAlign="center"
133+
>
134+
{children}
135+
</Box>
136+
)
201137
}
202138

203139
type Product = {
@@ -303,48 +239,89 @@ const StakingProductCard: React.FC<ICardProps> = ({
303239
].filter(({ status }) => !!status)
304240

305241
return (
306-
<Card>
307-
<Banner color={color}>
308-
{!!Svg && <Svg style={{ width: "32", height: "auto" }} />}
309-
<h2>{name}</h2>
310-
</Banner>
242+
<Flex
243+
direction="column"
244+
background="offBackground"
245+
borderRadius="base"
246+
_hover={{
247+
transition: "0.1s",
248+
transform: "scale(1.01)",
249+
}}
250+
>
251+
<HStack
252+
{...PADDED_DIV_STYLE}
253+
spacing={6}
254+
background={color}
255+
bgGradient="linear(0deg, rgba(0, 0, 0, 30%), rgba(0, 0, 0, 0))"
256+
borderRadius="base"
257+
maxH={24}
258+
>
259+
{!!Svg && <Icon as={Svg} fontSize="2rem" />}
260+
<Heading fontSize="2xl" color="white">
261+
{name}
262+
</Heading>
263+
</HStack>
311264
{typeof minEth !== "undefined" && (
312-
<MinEthBar>
313-
{minEth > 0 ? `From ${minEth} ETH` : "Any amount"}
314-
</MinEthBar>
265+
<Center
266+
fontWeight={700}
267+
fontSize="base"
268+
color="textTableOfContents"
269+
textTransform="uppercase"
270+
pt={6}
271+
>
272+
{minEth > 0 ? `From ${minEth} ETH` : "Any amount"}
273+
</Center>
315274
)}
316-
<Pills>
275+
<Flex
276+
{...PADDED_DIV_STYLE}
277+
flexWrap="wrap"
278+
gap={1}
279+
flex={1}
280+
alignItems="flex-start"
281+
>
317282
{platforms &&
318283
platforms.map((platform, idx) => (
319-
<Pill type="platform" key={idx}>
284+
<StakingPill type="platform" key={idx}>
320285
{platform}
321-
</Pill>
286+
</StakingPill>
322287
))}
323288
{ui &&
324289
ui.map((_ui, idx) => (
325-
<Pill type="ui" key={idx}>
290+
<StakingPill type="ui" key={idx}>
326291
{_ui}
327-
</Pill>
292+
</StakingPill>
328293
))}
329-
</Pills>
330-
<Spacer />
331-
<Content>
332-
<ul>
294+
</Flex>
295+
<Box {...PADDED_DIV_STYLE} py={0}>
296+
<List m={0} gap={3}>
333297
{data &&
334298
data.map(({ label, status }, idx) => (
335-
<Item key={idx}>
299+
<ListItem
300+
as={Flex}
301+
key={idx}
302+
textTransform="uppercase"
303+
fontSize="xs"
304+
lineHeight="0.875rem"
305+
letterSpacing="wider"
306+
my={4}
307+
ms="auto"
308+
me={0}
309+
py={2}
310+
gap="1em"
311+
alignItems="center"
312+
>
336313
<Status status={status} />
337-
<p>{label}</p>
338-
</Item>
314+
{label}
315+
</ListItem>
339316
))}
340-
</ul>
341-
</Content>
342-
<Cta>
343-
<ButtonLink to={url} customEventOptions={matomo}>
317+
</List>
318+
</Box>
319+
<Box {...PADDED_DIV_STYLE}>
320+
<ButtonLink to={url} customEventOptions={matomo} width="100%">
344321
<Translation id="page-staking-products-get-started" />
345322
</ButtonLink>
346-
</Cta>
347-
</Card>
323+
</Box>
324+
</Flex>
348325
)
349326
}
350327

@@ -353,11 +330,8 @@ export interface IProps {
353330
}
354331

355332
const StakingProductCardGrid: React.FC<IProps> = ({ category }) => {
356-
const theme = useTheme()
357333
const [rankedProducts, updateRankedProducts] = useState<Array<Product>>([])
358-
const isDarkTheme = theme.isDark
359-
360-
const [SAT, LUM] = isDarkTheme ? ["50%", "35%"] : ["75%", "60%"]
334+
const [SAT, LUM] = useColorModeValue(["75%", "60%"], ["50%", "35%"])
361335

362336
const scoreOpenSource = (product: Product): 1 | 0 => {
363337
return product.openSource === FlagType.VALID ? 1 : 0
@@ -564,11 +538,16 @@ const StakingProductCardGrid: React.FC<IProps> = ({ category }) => {
564538
if (!rankedProducts) return null
565539

566540
return (
567-
<CardGrid>
541+
<SimpleGrid
542+
templateColumns="repeat(auto-fill, minmax(min(100%, 280px), 1fr))"
543+
gap={8}
544+
my={12}
545+
mx={0}
546+
>
568547
{rankedProducts.map((product) => (
569548
<StakingProductCard key={product.name} product={product} />
570549
))}
571-
</CardGrid>
550+
</SimpleGrid>
572551
)
573552
}
574553

0 commit comments

Comments
 (0)