Skip to content

Commit 0c8f831

Browse files
authored
Merge pull request #13411 from ethereum/shadcn-footer-link
Shadcn migration - footer, skiplink, list & link components
2 parents 1329550 + 2c3bec2 commit 0c8f831

File tree

10 files changed

+317
-132
lines changed

10 files changed

+317
-132
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"@radix-ui/react-navigation-menu": "^1.2.0",
3939
"@radix-ui/react-popover": "^1.1.1",
4040
"@radix-ui/react-slot": "^1.1.0",
41+
"@radix-ui/react-visually-hidden": "^1.1.0",
4142
"@socialgouv/matomo-next": "^1.8.0",
4243
"chart.js": "^4.4.2",
4344
"chartjs-plugin-datalabels": "^2.2.0",

src/components/Footer.tsx

Lines changed: 41 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,18 @@
11
import { useTranslation } from "next-i18next"
22
import { FaDiscord, FaGithub, FaTwitter } from "react-icons/fa"
33
import { IoChevronUpSharp } from "react-icons/io5"
4-
import {
5-
Box,
6-
Flex,
7-
Heading,
8-
Icon,
9-
List,
10-
ListItem,
11-
SimpleGrid,
12-
Text,
13-
} from "@chakra-ui/react"
144

155
import type { FooterLink, FooterLinkSection } from "@/lib/types"
166

17-
import { BaseLink } from "@/components/Link"
187
import Translation from "@/components/Translation"
198

9+
import { cn } from "@/lib/utils/cn"
2010
import { scrollIntoView } from "@/lib/utils/scrollIntoView"
2111

22-
import { Button } from "./Buttons"
12+
import { BaseLink } from "../../tailwind/Link"
13+
import { Button } from "../../tailwind/ui/buttons/Button"
14+
15+
import { List, ListItem } from "./ui/list"
2316

2417
const socialLinks = [
2518
{
@@ -306,132 +299,76 @@ const Footer = ({ lastDeployLocaleTimestamp }: FooterProps) => {
306299
},
307300
]
308301

309-
const hoverStyles = {
310-
textDecor: "none",
311-
color: "primary.base",
312-
_after: {
313-
color: "primary.base",
314-
},
315-
"& svg": {
316-
fill: "primary.base",
317-
},
318-
}
319-
320-
const linkProps = {
321-
isPartiallyActive: false,
322-
textDecor: "none",
323-
color: "body.medium",
324-
fontWeight: "normal",
325-
_hover: hoverStyles,
326-
sx: {
327-
"& svg": {
328-
fill: "body.medium",
329-
},
330-
},
331-
}
302+
const footerLinkClassName =
303+
"text-body-medium no-underline hover:text-primary hover:after:text-primary"
332304

333305
return (
334-
<Box as="footer" py="4" px="8">
335-
<Flex
336-
justify={{ base: "center", md: "space-between" }}
337-
alignItems="center"
338-
flexWrap="wrap"
339-
gap={8}
340-
pt={4}
341-
pb={4}
342-
borderTop={"1px solid"}
343-
borderColor={"body.light"}
344-
>
345-
<Text fontSize={"sm"} fontStyle={"italic"} color={"body.medium"}>
306+
<footer className="px-8 py-4">
307+
<div className="flex flex-wrap items-center justify-center gap-8 border-t border-body-light py-4 md:justify-between">
308+
<p className="text-sm italic text-body-medium">
346309
<Translation id="website-last-updated" />: {lastDeployLocaleTimestamp}
347-
</Text>
310+
</p>
348311

349312
<Button
350-
leftIcon={<IoChevronUpSharp />}
351313
variant="outline"
352314
isSecondary
353315
onClick={() => scrollIntoView("__next")}
354316
>
355-
{t("go-to-top")}
317+
<IoChevronUpSharp /> Go to top
356318
</Button>
357-
</Flex>
319+
</div>
358320

359-
<SimpleGrid
360-
gap={4}
361-
justifyContent="space-between"
362-
templateColumns={{
363-
base: "auto",
364-
sm: "repeat(2, auto)",
365-
md: "repeat(3, auto)",
366-
xl: "repeat(6, auto)",
367-
}}
368-
>
321+
<div className="grid auto-cols-auto justify-between gap-4 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-5">
369322
{linkSections.map((section: FooterLinkSection, idx) => (
370-
<Box key={idx}>
371-
<Heading as="h3" fontSize="sm" lineHeight="base" my="1.14em">
323+
<div key={idx}>
324+
<h3 className="my-5 text-sm font-bold">
372325
<Translation id={section.title} />
373-
</Heading>
374-
<List fontSize="sm" lineHeight="base" fontWeight="normal" m="0">
326+
</h3>
327+
<List className="m-0 mb-4 list-none text-sm">
375328
{section.links.map((link, linkIdx) => (
376-
<ListItem key={linkIdx} mb={4}>
377-
<BaseLink href={link.href} {...linkProps}>
329+
<ListItem key={linkIdx} className="mb-4">
330+
<BaseLink
331+
href={link.href}
332+
className={footerLinkClassName}
333+
isPartiallyActive={false}
334+
>
378335
{link.text}
379336
</BaseLink>
380337
</ListItem>
381338
))}
382339
</List>
383-
</Box>
340+
</div>
384341
))}
385-
</SimpleGrid>
386-
<Flex
387-
p={6}
388-
flexDir="column"
389-
alignItems="center"
390-
justifyContent="center"
391-
fontSize="sm"
392-
bg="background.highlight"
393-
>
394-
<Box display="flex" gap={4}>
395-
{socialLinks.map(({ href, ariaLabel, icon }) => (
342+
</div>
343+
<div className="flex flex-col items-center justify-center bg-background-highlight p-6 text-sm">
344+
<div className="flex gap-4">
345+
{socialLinks.map(({ href, ariaLabel, icon: Icon }) => (
396346
<BaseLink
397347
key={href}
398348
href={href}
399349
hideArrow
400-
color="body.base"
401350
aria-label={ariaLabel}
402-
_focus={{ color: "primary.base" }}
351+
className="text-body hover:text-primary"
403352
>
404-
<Icon
405-
as={icon}
406-
_hover={{
407-
transition:
408-
"color 0.2s ease-in-out, transform 0.2s ease-in-out",
409-
}}
410-
fontSize="4xl"
411-
/>
353+
<Icon className="h-9 w-9 hover:transform hover:transition-colors" />
412354
</BaseLink>
413355
))}
414-
</Box>
415-
<List
416-
display="flex"
417-
flexDir={{ base: "column", sm: "row" }}
418-
flexWrap="wrap"
419-
justifyContent={{ base: "center", sm: "space-between", md: "center" }}
420-
fontWeight="normal"
421-
fontSize="sm"
422-
p={5}
423-
m={0}
424-
>
356+
</div>
357+
<List className="m-0 flex list-none flex-col flex-wrap justify-center p-5 text-sm font-normal sm:flex-row sm:justify-between md:justify-center">
425358
{dipperLinks.map(({ href, text }) => (
426-
<ListItem key={text} textAlign="center" px="2">
427-
<BaseLink href={href} w={["100%", null]} {...linkProps}>
359+
<ListItem key={text} className="px-2 text-center">
360+
<BaseLink
361+
href={href}
362+
className={cn("w-full sm:w-auto", footerLinkClassName)}
363+
isPartiallyActive={false}
364+
>
428365
{text}
429366
</BaseLink>
430367
</ListItem>
431368
))}
432369
</List>
433-
</Flex>
434-
</Box>
370+
</div>
371+
</footer>
435372
)
436373
}
437374

src/components/SkipLink.tsx

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,19 @@
11
import { useTranslation } from "next-i18next"
2-
import { Box } from "@chakra-ui/react"
3-
4-
import { BaseLink } from "@/components/Link"
52

63
import { MAIN_CONTENT_ID } from "@/lib/constants"
74

5+
import { BaseLink } from "../../tailwind/Link"
6+
87
export const SkipLink = () => {
98
const { t } = useTranslation()
109
return (
11-
<Box bg="primary.base">
10+
<div className="bg-primary">
1211
<BaseLink
1312
href={"#" + MAIN_CONTENT_ID}
14-
lineHeight="taller"
15-
position="absolute"
16-
top="-12"
17-
ms="2"
18-
color="background.base"
19-
textDecorationLine="none"
20-
_hover={{ textDecoration: "none" }}
21-
_focus={{ position: "static" }}
13+
className="absolute -top-12 ms-2 leading-8 text-background no-underline hover:no-underline focus:static"
2214
>
2315
{t("skip-to-main-content")}
2416
</BaseLink>
25-
</Box>
17+
</div>
2618
)
2719
}

src/components/ThemeProvider.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ const ThemeProvider = ({ children }: Pick<ThemeProviderProps, "children">) => {
3333
disableTransitionOnChange
3434
storageKey={COLOR_MODE_STORAGE_KEY}
3535
>
36-
<ChakraBaseProvider theme={theme} colorModeManager={colorModeManager}>
36+
<ChakraBaseProvider
37+
theme={theme}
38+
colorModeManager={colorModeManager}
39+
resetCSS={false}
40+
>
3741
{/* TODO: Can these CSS Vars be moved to `global.css`? */}
3842
<style jsx global>
3943
{`

src/components/ui/list.tsx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { BaseHTMLAttributes, ElementRef, forwardRef } from "react"
2+
import { Slot } from "@radix-ui/react-slot"
3+
4+
import { cn } from "@/lib/utils/cn"
5+
6+
export type ListProps = BaseHTMLAttributes<HTMLUListElement> & {
7+
asChild?: boolean
8+
}
9+
10+
const List = forwardRef<ElementRef<"ul">, ListProps>(
11+
({ className, asChild, ...props }, ref) => {
12+
const Comp = asChild ? Slot : "ul"
13+
return (
14+
<Comp
15+
ref={ref}
16+
className={cn("mb-6 ms-6 list-disc", className)}
17+
{...props}
18+
/>
19+
)
20+
}
21+
)
22+
23+
List.displayName = "List"
24+
25+
// Alias
26+
const UnorderedList = List
27+
28+
const OrderedList = forwardRef<ElementRef<"ol">, ListProps>(
29+
({ className, children, ...props }, ref) => (
30+
<List className={cn("list-decimal", className)} asChild>
31+
<ol ref={ref} {...props}>
32+
{children}
33+
</ol>
34+
</List>
35+
)
36+
)
37+
38+
OrderedList.displayName = "OrderedList"
39+
40+
const ListItem = forwardRef<
41+
ElementRef<"li">,
42+
BaseHTMLAttributes<HTMLLIElement>
43+
>(({ className, ...props }, ref) => (
44+
<li
45+
ref={ref}
46+
className={cn("mb-3 last:mb-0 [&_ol]:mt-3 [&_ul]:mt-3", className)}
47+
{...props}
48+
/>
49+
))
50+
51+
ListItem.displayName = "ListItem"
52+
53+
export { List, ListItem, OrderedList, UnorderedList }

src/layouts/BaseLayout.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// import { join } from "path"
22

33
import dynamic from "next/dynamic"
4-
// import { useRouter } from "next/router"
5-
import { Container } from "@chakra-ui/react"
64

75
import type { Root } from "@/lib/types"
86

@@ -54,7 +52,7 @@ export const BaseLayout = ({
5452
* layout on initial load.
5553
*/}
5654
<SkipLink />
57-
<Container maxW="container.2xl" marginInline="auto">
55+
<div className="max-w-screen-2xl mx-auto">
5856
<Nav />
5957

6058
{/* TODO: FIX TRANSLATION BANNER LOGIC FOR https://github.com/ethereum/ethereum-org-website/issues/11305 */}
@@ -72,7 +70,7 @@ export const BaseLayout = ({
7270
{children}
7371

7472
<Footer lastDeployLocaleTimestamp={lastDeployLocaleTimestamp} />
75-
</Container>
73+
</div>
7674
{/**
7775
* The Feedback Widget is positioned below the container to ensure it is not affecting the
7876
* layout on initial load.

src/styles/global.css

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@
178178
}
179179

180180
a {
181-
@apply text-primary underline;
181+
@apply text-primary underline underline-offset-3 hover:text-primary-hover focus-visible:rounded-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-hover;
182182
}
183183

184184
h1,
@@ -214,7 +214,14 @@
214214
@apply text-sm lg:text-md;
215215
}
216216

217-
/* TODO: to be replaced with list component styles */
217+
pre,
218+
code,
219+
kbd,
220+
samp {
221+
@apply font-monospace text-base leading-base;
222+
}
223+
224+
/* TODO: remove these global styles when the list component migration is complete */
218225
ul,
219226
ol {
220227
margin: 0px 0px 1.45rem 1.45rem;
@@ -243,11 +250,4 @@
243250
margin-bottom: calc(1.45rem / 2);
244251
}
245252
}
246-
247-
pre,
248-
code,
249-
kbd,
250-
samp {
251-
@apply font-monospace text-base leading-base;
252-
}
253253
}

tailwind.config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ const config = {
1010
prefix: "",
1111
theme: {
1212
extend: {
13+
screens: {
14+
sm: "480px",
15+
md: "768px",
16+
lg: "992px",
17+
xl: "1280px",
18+
"2xl": "1536px",
19+
},
1320
fontFamily: {
1421
heading: "var(--font-inter)",
1522
body: "var(--font-inter)",
@@ -122,6 +129,9 @@ const config = {
122129
"accordion-down": "accordion-down 0.2s ease-out",
123130
"accordion-up": "accordion-up 0.2s ease-out",
124131
},
132+
textUnderlineOffset: {
133+
3: "3px",
134+
},
125135
},
126136
},
127137
plugins: [require("tailwindcss-animate")],

0 commit comments

Comments
 (0)