Skip to content

Commit 7217b9c

Browse files
authored
Merge pull request #14021 from ethereum/shadcn-toc
Shadcn migration - toc
2 parents 0cccfda + c8e0df0 commit 7217b9c

File tree

9 files changed

+133
-184
lines changed

9 files changed

+133
-184
lines changed

src/components/TableOfContents/ItemsList.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import { ChakraProps, List, ListItem } from "@chakra-ui/react"
2-
31
import type { ToCItem } from "@/lib/types"
42

53
import ToCLink from "@/components/TableOfContents/TableOfContentsLink"
64

7-
export type ItemsListProps = ChakraProps & {
5+
export type ItemsListProps = {
86
items: Array<ToCItem>
97
depth: number
108
maxDepth: number
@@ -25,19 +23,19 @@ const ItemsList = ({
2523
{items.map((item, index) => {
2624
const { title, items } = item
2725
return (
28-
<ListItem key={index} m={0} {...rest}>
26+
<li key={index} className="mb-2 last:mb-0" {...rest}>
2927
<ToCLink depth={depth} item={item} activeHash={activeHash} />
3028
{items && (
31-
<List key={title} fontSize="sm" ps="2" m="0" mt="2" spacing="2">
29+
<ul key={title} className="m-0 mt-2 list-none gap-2 ps-2 text-sm">
3230
<ItemsList
3331
items={items}
3432
depth={depth + 1}
3533
maxDepth={maxDepth}
3634
activeHash={activeHash}
3735
/>
38-
</List>
36+
</ul>
3937
)}
40-
</ListItem>
38+
</li>
4139
)
4240
})}
4341
</>
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { Fragment } from "react"
2+
3+
import type { ToCItem } from "@/lib/types"
4+
5+
import { cn } from "@/lib/utils/cn"
6+
7+
import { DropdownMenuItem } from "../ui/dropdown-menu"
8+
import { BaseLink } from "../ui/Link"
9+
10+
export type ItemsListProps = {
11+
items: Array<ToCItem>
12+
depth: number
13+
maxDepth: number
14+
activeHash?: string
15+
className?: string
16+
}
17+
18+
const ItemsListMobile = ({
19+
items,
20+
depth,
21+
maxDepth,
22+
activeHash,
23+
...rest
24+
}: ItemsListProps) => {
25+
if (depth > maxDepth) return null
26+
27+
return (
28+
<>
29+
{items.map((item, index) => {
30+
const { items, title, url } = item
31+
return (
32+
<Fragment key={title}>
33+
<DropdownMenuItem key={index} {...rest} asChild>
34+
<BaseLink
35+
className="text-body no-underline focus-visible:outline-0"
36+
href={url}
37+
>
38+
{title}
39+
</BaseLink>
40+
</DropdownMenuItem>
41+
{items && (
42+
<ItemsListMobile
43+
className={cn("ps-4", depth > 1 && "ps-8")}
44+
items={items}
45+
depth={depth + 1}
46+
maxDepth={maxDepth}
47+
activeHash={activeHash}
48+
/>
49+
)}
50+
</Fragment>
51+
)
52+
})}
53+
</>
54+
)
55+
}
56+
57+
ItemsListMobile.displayName = "TocItemsListMobile"
58+
59+
export default ItemsListMobile

src/components/TableOfContents/TableOfContentsLink.tsx

Lines changed: 16 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { cssVar, SystemStyleObject } from "@chakra-ui/react"
2-
31
import type { ToCItem } from "@/lib/types"
42

5-
import { BaseLink } from "@/components/Link"
3+
import { cn } from "@/lib/utils/cn"
4+
5+
import { BaseLink } from "../ui/Link"
66

77
export type TableOfContentsLinkProps = {
88
depth: number
@@ -16,57 +16,24 @@ const Link = ({
1616
activeHash,
1717
}: TableOfContentsLinkProps) => {
1818
const isActive = activeHash === url
19-
const isNested = depth === 2
20-
21-
const classList: Array<string> = []
22-
isActive && classList.push("active")
23-
isNested && classList.push("nested")
24-
const classes = classList.join(" ")
25-
26-
const $dotBg = cssVar("dot-bg")
27-
28-
const hoverOrActiveStyle: SystemStyleObject = {
29-
color: $dotBg.reference,
30-
_after: {
31-
content: `""`,
32-
backgroundColor: "background.base",
33-
border: "1px",
34-
borderColor: $dotBg.reference,
35-
borderRadius: "50%",
36-
boxSize: 2,
37-
position: "absolute",
38-
// 16px is the initial list padding
39-
// 8px is the padding for each nested list
40-
// 4px is half of the width of the dot
41-
// 1px for the border
42-
"inset-inline-start": `calc(-16px - 8px * ${depth} - 4px - 1px)`,
43-
top: "50%",
44-
mt: -1,
45-
},
46-
}
4719

4820
return (
4921
<BaseLink
5022
href={url}
51-
className={classes}
52-
textDecoration="none"
53-
display="inline-block"
54-
position="relative"
55-
color="body.medium"
56-
width={{ base: "100%", lg: "auto" }}
57-
_hover={{
58-
...hoverOrActiveStyle,
59-
}}
60-
p="2"
61-
ps="0"
62-
sx={{
63-
[$dotBg.variable]: "var(--eth-colors-primary-hover)",
64-
"&.active": {
65-
[$dotBg.variable]: "var(--eth-colors-primary-visited)",
66-
...hoverOrActiveStyle,
67-
},
68-
}}
23+
className={cn(
24+
"group relative inline-block w-full p-2 ps-0 text-body-medium no-underline lg:w-auto",
25+
isActive && "visited"
26+
)}
6927
>
28+
<div
29+
className={cn(
30+
"absolute top-1/2 -mt-1 hidden h-2 w-2 rounded-full border border-primary-hover bg-background group-hover:inline-block",
31+
isActive && "inline-block"
32+
)}
33+
style={{
34+
insetInlineStart: `calc(-16px - 8px * ${depth} - 4px - 1px)`,
35+
}}
36+
/>
7037
{title}
7138
</BaseLink>
7239
)

src/components/TableOfContents/TableOfContentsMobile.tsx

Lines changed: 32 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
11
import React from "react"
22
import { useTranslation } from "next-i18next"
33
import { MdExpandMore } from "react-icons/md"
4-
import {
5-
Box,
6-
chakra,
7-
Fade,
8-
Flex,
9-
Icon,
10-
List,
11-
useDisclosure,
12-
useToken,
13-
} from "@chakra-ui/react"
144

155
import type { ToCItem } from "@/lib/types"
166

17-
import { outerListProps } from "@/lib/utils/toc"
7+
import { Button } from "../ui/buttons/Button"
8+
import {
9+
DropdownMenu,
10+
DropdownMenuContent,
11+
DropdownMenuTrigger,
12+
} from "../ui/dropdown-menu"
1813

19-
import ItemsList from "./ItemsList"
14+
import ItemsListMobile from "./ItemsListMobile"
2015

2116
export type TableOfContentsMobileProps = {
2217
items?: Array<ToCItem>
@@ -25,58 +20,39 @@ export type TableOfContentsMobileProps = {
2520

2621
const Mobile = ({ items, maxDepth }: TableOfContentsMobileProps) => {
2722
const { t } = useTranslation("common")
28-
// TODO: Replace with direct token implementation after UI migration is completed
29-
const lgBp = useToken("breakpoints", "lg")
3023

31-
const { getButtonProps, getDisclosureProps, isOpen } = useDisclosure({
32-
defaultIsOpen: false,
33-
})
3424
if (!items) {
3525
return null
3626
}
3727

3828
return (
39-
<Box
40-
hideFrom={lgBp}
41-
as="aside"
42-
background="background.base"
43-
border="1px"
44-
borderColor="border"
45-
borderRadius="4px"
46-
py={2}
47-
px={4}
48-
>
49-
<Flex
50-
color="text200"
51-
cursor="pointer"
52-
alignItems="center"
53-
justify="space-between"
54-
{...getButtonProps()}
29+
<DropdownMenu>
30+
<DropdownMenuTrigger asChild>
31+
<Button
32+
isSecondary
33+
variant="outline"
34+
className="flex w-full justify-between lg:hidden"
35+
>
36+
<span className="flex-1 text-center">{t("on-this-page")}</span>
37+
<MdExpandMore />
38+
</Button>
39+
</DropdownMenuTrigger>
40+
<DropdownMenuContent
41+
align="start"
42+
sideOffset={8}
43+
className="w-[var(--radix-dropdown-menu-trigger-width)]"
44+
// prevents focus from moving to the trigger after closing
45+
onCloseAutoFocus={(e) => {
46+
e.preventDefault()
47+
}}
5548
>
56-
<chakra.span flex={1} fontWeight={500}>
57-
{t("on-this-page")}
58-
</chakra.span>
59-
<Icon
60-
as={MdExpandMore}
61-
transform={isOpen ? "rotate(0)" : "rotate(-90deg)"}
62-
boxSize={6}
63-
transition="transform .4s"
49+
<ItemsListMobile
50+
items={items}
51+
depth={0}
52+
maxDepth={maxDepth ? maxDepth : 1}
6453
/>
65-
</Flex>
66-
<Fade
67-
in={isOpen}
68-
{...getDisclosureProps()}
69-
transition={{ enter: { duration: 0.6 } }}
70-
>
71-
<List {...outerListProps}>
72-
<ItemsList
73-
items={items}
74-
depth={0}
75-
maxDepth={maxDepth ? maxDepth : 1}
76-
/>
77-
</List>
78-
</Fade>
79-
</Box>
54+
</DropdownMenuContent>
55+
</DropdownMenu>
8056
)
8157
}
8258

src/components/TableOfContents/index.tsx

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,24 @@
11
import { useTranslation } from "next-i18next"
22
import { FaGithub } from "react-icons/fa"
3-
import {
4-
Box,
5-
BoxProps,
6-
calc,
7-
Flex,
8-
Icon,
9-
List,
10-
useToken,
11-
} from "@chakra-ui/react"
123

134
import type { ToCItem } from "@/lib/types"
145

15-
import { ButtonLink } from "@/components/Buttons"
166
import ItemsList from "@/components/TableOfContents/ItemsList"
177
import Mobile from "@/components/TableOfContents/TableOfContentsMobile"
188

19-
import { outerListProps } from "@/lib/utils/toc"
9+
import { cn } from "@/lib/utils/cn"
10+
11+
import { ButtonLink } from "../ui/buttons/Button"
2012

2113
import { useActiveHash } from "@/hooks/useActiveHash"
2214

23-
export type TableOfContentsProps = BoxProps & {
15+
export type TableOfContentsProps = {
2416
items: Array<ToCItem>
2517
maxDepth?: number
2618
editPath?: string
2719
hideEditButton?: boolean
2820
isMobile?: boolean
21+
className?: string
2922
}
3023

3124
const TableOfContents = ({
@@ -34,11 +27,10 @@ const TableOfContents = ({
3427
editPath,
3528
hideEditButton = false,
3629
isMobile = false,
30+
className,
3731
...rest
3832
}: TableOfContentsProps) => {
3933
const { t } = useTranslation("common")
40-
// TODO: Replace with direct token implementation after UI migration is completed
41-
const lgBp = useToken("breakpoints", "lg")
4234

4335
const titleIds: Array<string> = []
4436

@@ -65,43 +57,29 @@ const TableOfContents = ({
6557
}
6658

6759
return (
68-
<Flex
69-
direction="column"
70-
align="start"
71-
gap={4}
72-
hideBelow={lgBp}
73-
as="aside"
74-
position="sticky"
75-
top="19" // Account for navbar
76-
p={4}
77-
pe={0}
78-
maxW="25%"
79-
minW={48}
80-
height={calc.subtract("100vh", "80px")}
81-
overflowY="auto"
60+
<aside
61+
className={cn(
62+
"sticky top-19 hidden h-[calc(100vh-80px)] min-w-48 max-w-[25%] flex-col items-start gap-4 overflow-y-auto p-4 pe-0 lg:flex",
63+
className
64+
)}
8265
{...rest}
8366
>
8467
{!hideEditButton && editPath && (
85-
<ButtonLink
86-
leftIcon={<Icon as={FaGithub} />}
87-
href={editPath}
88-
variant="outline"
89-
>
68+
<ButtonLink href={editPath} variant="outline">
69+
<FaGithub />
9070
{t("edit-page")}
9171
</ButtonLink>
9272
)}
93-
<Box textTransform="uppercase" color="body.medium">
94-
{t("on-this-page")}
95-
</Box>
96-
<List m={0} spacing="2" {...outerListProps}>
73+
<div className="uppercase text-body-medium">{t("on-this-page")}</div>
74+
<ul className="m-0 mb-2 mt-2 list-none gap-2 border-s border-s-body-medium ps-4 pt-0 text-sm">
9775
<ItemsList
9876
items={items}
9977
depth={0}
10078
maxDepth={maxDepth ? maxDepth : 1}
10179
activeHash={activeHash}
10280
/>
103-
</List>
104-
</Flex>
81+
</ul>
82+
</aside>
10583
)
10684
}
10785

0 commit comments

Comments
 (0)