Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DS implementation - Table of Contents #13156

Merged
merged 13 commits into from
Aug 6, 2024
10 changes: 1 addition & 9 deletions src/components/TableOfContents/ItemsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,7 @@ const ItemsList = ({
<ListItem key={index} m={0} {...rest}>
<ToCLink depth={depth} item={item} activeHash={activeHash} />
{items && (
<List
key={title}
fontSize="sm"
lineHeight={1.6}
fontWeight={400}
ps={4}
pe={1}
m={0}
>
<List key={title} fontSize="sm" ps="2" m="0" mt="2" spacing="2">
<ItemsList
items={items}
depth={depth + 1}
Expand Down
95 changes: 95 additions & 0 deletions src/components/TableOfContents/TableOfContents.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import * as React from "react"
import { Stack } from "@chakra-ui/react"
import { Meta, StoryObj } from "@storybook/react"

import { ToCItem, TocNodeType } from "@/lib/types"

import TableOfContents from "./"

const tocItems: ToCItem[] = [
{
title: "The early Web",
url: "#early-internet",
items: [
{ title: "Web 1.0: Read-Only (1990-2004)", url: "#web1" },
{ title: "Web 2.0: Read-Write (2004-now)", url: "#web2" },
],
},
{
title: "Web 3.0: Read-Write-Own",
url: "#web3",
items: [
{
title: "What is Web3?",
url: "#what-is-web3",
items: [{ title: "Core ideas of Web3", url: "#core-ideas" }],
},
{
title: "Why is Web3 important?",
url: "#why-is-web3-important",
items: [
{ title: "Ownership", url: "#ownership" },
{
title: "Censorship resistance",
url: "#censorship-resistance",
},
{
title: "Decentralized autonomous organizations (DAOs)",
url: "#daos",
},
],
},
{ title: "Identity", url: "#identity" },
{
title: "Native payments",
url: "#native-payments",
items: [
{ title: "Cryptocurrency", url: "#cryptocurrency" },
{ title: "Micropayments", url: "#micropayments" },
{ title: "Tokenization", url: "#tokenization" },
],
},
],
},
{
title: "Web3 limitations",
url: "#web3-limitations",
items: [
{ title: "Accessibility", url: "#accessibility" },
{ title: "User experience", url: "#user-experience" },
{ title: "Education", url: "#education" },
{
title: "Centralized infrastructure",
url: "#centralized-infrastructure",
},
],
},
{
title: "A decentralized future",
url: "#decentralized-future",
},
{ title: "How can I get involved", url: "#get-involved" },
{ title: "Further reading", url: "#further-reading" },
]

const meta = {
title: "Molecules / Navigation / TableOfContents",
parameters: {
layout: "fullscreen",
},
decorators: [
(Story) => (
<Stack minH="100vh" position="relative">
<Story />
</Stack>
),
],
} satisfies Meta<typeof TableOfContents>

export default meta

type Story = StoryObj<typeof meta>

export const Default: Story = {
render: () => <TableOfContents slug="#web3" items={tocItems} maxDepth={2} />,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9:11:34 AM: Failed to compile.
9:11:34 AM: 
9:11:34 AM: ./src/components/TableOfContents/TableOfContents.stories.tsx:94:34
9:11:34 AM: Type error: Type '{ slug: string; items: ToCItem[]; maxDepth: number; }' is not assignable to type 'IntrinsicAttributes & BoxProps & { items: ToCItem[]; maxDepth?: number | undefined; editPath?: string | undefined; hideEditButton?: boolean | undefined; isMobile?: boolean | undefined; }'.
9:11:34 AM:   Property 'slug' does not exist on type 'IntrinsicAttributes & BoxProps & { items: ToCItem[]; maxDepth?: number | undefined; editPath?: string | undefined; hideEditButton?: boolean | undefined; isMobile?: boolean | undefined; }'.
9:11:34 AM:   92 |
9:11:34 AM:   93 | export const Default: Story = {
9:11:34 AM: > 94 |   render: () => <TableOfContents slug="#web3" items={tocItems} maxDepth={2} />,
9:11:34 AM:      |                                  ^
9:11:34 AM:   95 | }
9:11:34 AM:   96 |
9:11:34 AM: error Command failed with exit code 1. (https://ntl.fyi/exit-code-1)

cc: @pettinarip Getting an error here... slug is not a prop on TableOfContents, do we need this here?

// src/components/TableOfContents/index.tsx
export type TableOfContentsProps = BoxProps & {
  items: Array<ToCItem>
  maxDepth?: number
  editPath?: string
  hideEditButton?: boolean
  isMobile?: boolean
}

}
41 changes: 13 additions & 28 deletions src/components/TableOfContents/TableOfContentsLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import type { ToCItem } from "@/lib/types"

import { BaseLink } from "@/components/Link"

import { useRtlFlip } from "@/hooks/useRtlFlip"

export type TableOfContentsLinkProps = {
depth: number
item: ToCItem
Expand All @@ -17,7 +15,6 @@ const Link = ({
item: { title, url },
activeHash,
}: TableOfContentsLinkProps) => {
const { flipForRtl } = useRtlFlip()
const isActive = activeHash === url
const isNested = depth === 2

Expand All @@ -29,16 +26,20 @@ const Link = ({
const $dotBg = cssVar("dot-bg")

const hoverOrActiveStyle: SystemStyleObject = {
color: "primary.base",
color: $dotBg.reference,
_after: {
content: `""`,
background: $dotBg.reference,
backgroundColor: "background.base",
border: "1px",
borderColor: "primary.base",
borderColor: $dotBg.reference,
borderRadius: "50%",
boxSize: 2,
position: "absolute",
insetInlineStart: "-1.29rem",
// 16px is the initial list padding
// 8px is the padding for each nested list
// 4px is half of the width of the dot
// 1px for the border
"inset-inline-start": `calc(-16px - 8px * ${depth} - 4px - 1px)`,
top: "50%",
mt: -1,
},
Expand All @@ -51,35 +52,19 @@ const Link = ({
textDecoration="none"
display="inline-block"
position="relative"
color="textTableOfContents"
fontWeight="normal"
mb="0.5rem !important"
color="body.medium"
width={{ base: "100%", lg: "auto" }}
_hover={{
...hoverOrActiveStyle,
}}
p="2"
ps="0"
sx={{
[$dotBg.variable]: "colors.background",
[$dotBg.variable]: "var(--eth-colors-primary-hover)",
"&.active": {
[$dotBg.variable]: "colors.primary",
[$dotBg.variable]: "var(--eth-colors-primary-visited)",
...hoverOrActiveStyle,
},
"&.nested": {
_before: {
content: `"⌞"`,
opacity: 0.5,
display: "inline-flex",
position: "absolute",
insetInlineStart: -3.5,
top: -1,
transform: flipForRtl,
},
"&.active, &:hover": {
_after: {
insetInlineStart: "-2.29rem",
},
},
},
}}
>
{title}
Expand Down
53 changes: 25 additions & 28 deletions src/components/TableOfContents/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import {
Box,
BoxProps,
calc,
Flex,
Icon,
List,
ListItem,
useToken,
} from "@chakra-ui/react"

Expand Down Expand Up @@ -65,7 +65,10 @@ const TableOfContents = ({
}

return (
<Box
<Flex
direction="column"
align="start"
gap={4}
hideBelow={lgBp}
as="aside"
position="sticky"
Expand All @@ -78,33 +81,27 @@ const TableOfContents = ({
overflowY="auto"
{...rest}
>
<List {...outerListProps}>
{!hideEditButton && editPath && (
<ListItem mb={2}>
<ButtonLink
leftIcon={<Icon as={FaGithub} />}
href={editPath}
variant="outline"
>
{t("edit-page")}
</ButtonLink>
</ListItem>
)}
<ListItem>
<Box mb={2} textTransform="uppercase">
{t("on-this-page")}
</Box>
<List m={0}>
<ItemsList
items={items}
depth={0}
maxDepth={maxDepth ? maxDepth : 1}
activeHash={activeHash}
/>
</List>
</ListItem>
{!hideEditButton && editPath && (
<ButtonLink
leftIcon={<Icon as={FaGithub} />}
href={editPath}
variant="outline"
>
{t("edit-page")}
</ButtonLink>
)}
<Box textTransform="uppercase" color="body.medium">
{t("on-this-page")}
</Box>
<List m={0} spacing="2" {...outerListProps}>
<ItemsList
items={items}
depth={0}
maxDepth={maxDepth ? maxDepth : 1}
activeHash={activeHash}
/>
</List>
</Box>
</Flex>
)
}

Expand Down
6 changes: 2 additions & 4 deletions src/lib/utils/toc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,14 @@ export const parseHeadingId = (heading: string): string => {
*/
export const outerListProps: ListProps = {
borderStart: "1px solid",
borderStartColor: "dropdownBorder",
borderStartColor: "body.medium",
borderTop: 0,
fontSize: "sm",
lineHeight: 1.6,
fontWeight: 400,
spacing: "2",
m: 0,
mt: 2,
mb: 2,
ps: 4,
pe: 1,
pt: 0,
sx: {
// TODO: Flip to object syntax with `lg` token after completion of Chakra migration
Expand Down
Loading