diff --git a/src/components/MdComponents.tsx b/src/components/MdComponents.tsx
deleted file mode 100644
index 9affa173a57..00000000000
--- a/src/components/MdComponents.tsx
+++ /dev/null
@@ -1,253 +0,0 @@
-import { ComponentProps } from "react"
-import {
- Badge,
- Box,
- type BoxProps,
- chakra,
- Divider as ChakraDivider,
- Flex,
- type FlexProps,
- type HeadingProps,
- ListItem,
- OrderedList,
- Text,
- UnorderedList,
- useToken,
-} from "@chakra-ui/react"
-
-import type { ChildOnlyProp } from "@/lib/types"
-
-import ButtonDropdown, {
- type ButtonDropdownProps,
-} from "@/components/ButtonDropdown"
-import { ButtonLink } from "@/components/Buttons"
-import Contributors from "@/components/Contributors"
-import MarkdownImage from "@/components/MarkdownImage"
-import OldHeading from "@/components/OldHeading"
-import { mdxTableComponents } from "@/components/Table"
-import TooltipLink from "@/components/TooltipLink"
-import YouTube from "@/components/YouTube"
-
-import ContributorsQuizBanner from "./Banners/ContributorsQuizBanner"
-import GlossaryTooltip from "./Glossary/GlossaryTooltip"
-import { StandaloneQuizWidget } from "./Quiz/QuizWidget"
-import Card from "./Card"
-import DocLink from "./DocLink"
-import Emoji from "./Emoji"
-import ExpandableCard from "./ExpandableCard"
-import FeaturedText from "./FeaturedText"
-import IdAnchor from "./IdAnchor"
-import InfoBanner from "./InfoBanner"
-import IssuesList from "./IssuesList"
-import LocaleDateTime from "./LocaleDateTime"
-import MainArticle from "./MainArticle"
-
-/**
- * Base HTML elements
- */
-const headingPropsForAnchor = (id?: string): HeadingProps => {
- if (!id) return {}
- return {
- scrollMarginTop: 28,
- id,
- "data-group": true,
- position: "relative",
- } as HeadingProps
-}
-
-export const commonHeadingProps = (id?: string): HeadingProps => ({
- fontWeight: 700,
- lineHeight: 1.4,
- ...headingPropsForAnchor(id),
-})
-
-export const Heading1 = ({ children, ...rest }: HeadingProps) => (
-
- {children}
-
-)
-
-export const Heading2 = ({ id, children, ...rest }: HeadingProps) => (
-
-
- {children}
-
-)
-
-export const Heading3 = ({ id, children, ...rest }: HeadingProps) => (
-
-
- {children}
-
-)
-
-export const Heading4 = ({ id, children, ...rest }: HeadingProps) => (
-
-
- {children}
-
-)
-
-export const Pre = (props: ChildOnlyProp) => (
-
-)
-
-export const Paragraph = (props: ChildOnlyProp) => (
-
-)
-
-export const HR = () => (
-
-)
-
-// All base html element components
-export const htmlElements = {
- a: TooltipLink,
- div: Box,
- h1: Heading1,
- h2: Heading2,
- h3: Heading3,
- h4: Heading4,
- hr: HR,
- img: MarkdownImage,
- li: ListItem,
- ol: OrderedList,
- p: Paragraph,
- pre: Pre,
- time: LocaleDateTime,
- ul: UnorderedList,
- ...mdxTableComponents,
-}
-
-/**
- * Custom React components
- */
-export const Page = (props: FlexProps) => (
-
-)
-
-export const Title = (props: ChildOnlyProp) =>
-
-export const ContentContainer = (props: Pick) => {
- const lgBp = useToken("breakpoints", "lg")
-
- return (
-
- )
-}
-
-export const MobileButton = (props: ChildOnlyProp) => {
- const borderColor = useToken("colors", "border")
- return (
-
- )
-}
-
-export const StyledButtonDropdown = ({
- list,
- ...rest
-}: FlexProps & Pick) => (
-
-
-
-)
-
-export const MobileButtonDropdown = (
- props: ComponentProps
-) =>
-
-export const Divider = () =>
-
-// All custom React components
-export const reactComponents = {
- Badge,
- ButtonLink,
- Card,
- ContentContainer,
- Contributors,
- ContributorsQuizBanner,
- Divider,
- DocLink,
- Emoji,
- ExpandableCard,
- FeaturedText,
- GlossaryTooltip,
- InfoBanner,
- MobileButton,
- MobileButtonDropdown,
- Page,
- QuizWidget: StandaloneQuizWidget,
- StyledButtonDropdown,
- IssuesList,
- Title,
- YouTube,
-}
-
-/**
- * All base markdown components as default export
- */
-const MdComponents = {
- ...htmlElements,
- ...reactComponents,
-}
-
-export default MdComponents
diff --git a/src/components/MdComponents/MdComponents.stories.tsx b/src/components/MdComponents/MdComponents.stories.tsx
new file mode 100644
index 00000000000..9d101a7334d
--- /dev/null
+++ b/src/components/MdComponents/MdComponents.stories.tsx
@@ -0,0 +1,129 @@
+import pickBy from "lodash/pickBy"
+import type { Meta, StoryObj } from "@storybook/react/*"
+
+import type { List as ButtonDropdownList } from "@/components/ButtonDropdown"
+
+import { viewportModes } from "../../../.storybook/modes"
+
+import MdComponentSet from "."
+
+const meta = {
+ title: "Molecules / Display Content / MdComponents",
+ parameters: {
+ layout: "none",
+ chromatic: {
+ modes: pickBy(viewportModes, (args) =>
+ ["md", "lg"].includes(args.viewport)
+ ),
+ },
+ },
+} satisfies Meta
+
+export default meta
+
+const {
+ ContentContainer,
+ h1: Heading1,
+ h2: Heading2,
+ h3: Heading3,
+ h4: Heading4,
+ Title,
+ p: Paragraph,
+ FeaturedText,
+ Divider,
+ hr: HR,
+ pre: Pre,
+ Page,
+ MobileButton,
+ MobileButtonDropdown,
+} = MdComponentSet
+
+const Para = () => (
+
+ Ether (also known by its ticker symbol, ETH) is the native currency
+ transacted on Ethereum. ETH is needed to pay for usage of the Ethereum
+ network (in the form of transaction fees). ETH is also used to secure the
+ network with staking. When people talk about the price of Ethereum,
+ they're referring to ETH the asset.
+
+)
+
+export const MdComponents: StoryObj = {
+ render: () => (
+
+
+
+
+
+
+ Heading1
+
+ Heading2
+
+ Heading3
+
+ Heading4
+
+ Title
+
+
+ Lots of coding here
+
+ Feature Text
+
+
+
+ ),
+}
+
+const roadmapDropdownLinks: ButtonDropdownList = {
+ text: "nav-roadmap-options",
+ ariaLabel: "nav-roadmap-options-alt",
+ items: [
+ {
+ text: "nav-roadmap-home",
+ href: "/roadmap/",
+ matomo: {
+ eventCategory: `Roadmap dropdown`,
+ eventAction: `Clicked`,
+ eventName: "clicked roadmap home",
+ },
+ },
+ {
+ text: "nav-roadmap-security",
+ href: "/roadmap/security",
+ matomo: {
+ eventCategory: `Roadmap security dropdown`,
+ eventAction: `Clicked`,
+ eventName: "clicked roadmap security",
+ },
+ },
+ {
+ text: "nav-roadmap-scaling",
+ href: "/roadmap/scaling",
+ matomo: {
+ eventCategory: `Roadmap scaling dropdown`,
+ eventAction: `Clicked`,
+ eventName: "clicked roadmap scaling home",
+ },
+ },
+ {
+ text: "nav-roadmap-user-experience",
+ href: "/roadmap/user-experience/",
+ matomo: {
+ eventCategory: `Roadmap user experience dropdown`,
+ eventAction: `Clicked`,
+ eventName: "clicked roadmap user experience home",
+ },
+ },
+ {
+ text: "nav-roadmap-future-proofing",
+ href: "/roadmap/future-proofing",
+ matomo: {
+ eventCategory: `Roadmap future-proofing dropdown`,
+ eventAction: `Clicked`,
+ eventName: "clicked roadmap future-proofing home",
+ },
+ },
+ ],
+}
diff --git a/src/components/MdComponents/index.tsx b/src/components/MdComponents/index.tsx
new file mode 100644
index 00000000000..a58550e47c5
--- /dev/null
+++ b/src/components/MdComponents/index.tsx
@@ -0,0 +1,220 @@
+import { ComponentProps, type HTMLAttributes } from "react"
+import { Badge, Box, type BoxProps } from "@chakra-ui/react"
+
+import type { ChildOnlyProp } from "@/lib/types"
+
+import ButtonDropdown, {
+ type ButtonDropdownProps,
+} from "@/components/ButtonDropdown"
+import Contributors from "@/components/Contributors"
+import MarkdownImage from "@/components/MarkdownImage"
+import { mdxTableComponents } from "@/components/Table"
+import TooltipLink from "@/components/TooltipLink"
+import YouTube from "@/components/YouTube"
+
+import { cn } from "@/lib/utils/cn"
+
+import ContributorsQuizBanner from "../Banners/ContributorsQuizBanner"
+import Card from "../Card"
+import DocLink from "../DocLink"
+import Emoji from "../Emoji"
+import ExpandableCard from "../ExpandableCard"
+import FeaturedText from "../FeaturedText"
+import GlossaryTooltip from "../Glossary/GlossaryTooltip"
+import IdAnchor from "../IdAnchor"
+import InfoBanner from "../InfoBanner"
+import IssuesList from "../IssuesList"
+import LocaleDateTime from "../LocaleDateTime"
+import MainArticle from "../MainArticle"
+import { StandaloneQuizWidget } from "../Quiz/QuizWidget"
+import { ButtonLink } from "../ui/buttons/Button"
+import { Flex } from "../ui/flex"
+import { ListItem, OrderedList, UnorderedList } from "../ui/list"
+
+export const commonHeadingAttributes = (className: string, id?: string) => ({
+ id,
+ className: cn(
+ "font-bold leading-xs my-8",
+ id && "scroll-mt-28 relative",
+ className
+ ),
+ "data-group": !!id || undefined,
+})
+
+type HeadingProps = HTMLAttributes
+
+export const Heading1 = ({ children, className, ...rest }: HeadingProps) => (
+
+ {children}
+
+)
+
+export const Heading2 = ({
+ id,
+ children,
+ className,
+ ...rest
+}: HeadingProps) => (
+
+
+ {children}
+
+)
+
+export const Heading3 = ({
+ id,
+ children,
+ className,
+ ...rest
+}: HeadingProps) => (
+
+
+ {children}
+
+)
+
+export const Heading4 = ({
+ id,
+ children,
+ className,
+ ...rest
+}: HeadingProps) => (
+
+
+ {children}
+
+)
+
+export const Pre = (props: ChildOnlyProp) => (
+
+)
+
+export const Paragraph = (props: ChildOnlyProp) => (
+
+)
+
+export const HR = () => (
+
+)
+
+// All base html element components
+export const htmlElements = {
+ a: TooltipLink,
+ div: Box,
+ h1: Heading1,
+ h2: Heading2,
+ h3: Heading3,
+ h4: Heading4,
+ hr: HR,
+ img: MarkdownImage,
+ li: ListItem,
+ ol: OrderedList,
+ p: Paragraph,
+ pre: Pre,
+ time: LocaleDateTime,
+ ul: UnorderedList,
+ ...mdxTableComponents,
+}
+
+/**
+ * Custom React components
+ */
+export const Page = ({
+ className,
+ ...props
+}: HTMLAttributes) => (
+
+)
+
+export const Title = (props: ChildOnlyProp) => (
+
+)
+
+export const ContentContainer = (props: Pick) => {
+ return (
+
+ )
+}
+
+export const MobileButton = (props: ChildOnlyProp) => {
+ return (
+
+ )
+}
+
+export const StyledButtonDropdown = ({
+ list,
+ className,
+ ...rest
+}: HTMLAttributes & Pick) => (
+
+
+
+)
+
+export const MobileButtonDropdown = ({
+ className,
+ ...props
+}: ComponentProps) => (
+
+)
+
+export const Divider = () => (
+
+)
+
+// All custom React components
+export const reactComponents = {
+ Badge,
+ ButtonLink,
+ Card,
+ ContentContainer,
+ Contributors,
+ ContributorsQuizBanner,
+ Divider,
+ DocLink,
+ Emoji,
+ ExpandableCard,
+ FeaturedText,
+ GlossaryTooltip,
+ InfoBanner,
+ MobileButton,
+ MobileButtonDropdown,
+ Page,
+ QuizWidget: StandaloneQuizWidget,
+ StyledButtonDropdown,
+ IssuesList,
+ Title,
+ YouTube,
+}
+
+/**
+ * All base markdown components as default export
+ */
+const MdComponents = {
+ ...htmlElements,
+ ...reactComponents,
+}
+
+export default MdComponents
diff --git a/src/layouts/Docs.tsx b/src/layouts/Docs.tsx
index 7d6fc32ddf7..925b60310c8 100644
--- a/src/layouts/Docs.tsx
+++ b/src/layouts/Docs.tsx
@@ -1,4 +1,5 @@
import { useRouter } from "next/router"
+import type { HTMLAttributes } from "react"
import {
Badge,
Box,
@@ -6,7 +7,6 @@ import {
Divider as ChakraDivider,
Flex,
type FlexProps,
- type HeadingProps,
type ListProps,
OrderedList as ChakraOrderedList,
UnorderedList as ChakraUnorderedList,
@@ -45,6 +45,7 @@ import TableOfContents from "@/components/TableOfContents"
import Translation from "@/components/Translation"
import YouTube from "@/components/YouTube"
+import { cn } from "@/lib/utils/cn"
import { getEditPath } from "@/lib/utils/editPath"
const Page = (props: ChildOnlyProp & Pick) => (
@@ -80,47 +81,33 @@ const ContentContainer = (props: ContentContainerProps) => (
/>
)
-const baseHeadingStyle: HeadingProps = {
- fontFamily: "mono",
- textTransform: "uppercase",
- fontWeight: "bold",
- scrollMarginTop: 40,
-}
+const baseHeadingClasses = "font-mono uppercase font-bold scroll-mt-40"
-const H1 = (props: HeadingProps) => (
+const H1 = (props: HTMLAttributes) => (
)
-const H2 = (props: HeadingProps) => (
+const H2 = (props: HTMLAttributes) => (
)
-const baseSubHeadingStyles: HeadingProps = {
- lineHeight: 1.4,
- fontWeight: "semibold",
-}
+const baseSubHeadingClasses = "leading-xs font-semibold"
-const H3 = (props: HeadingProps) => (
-
+const H3 = (props: HTMLAttributes) => (
+
)
-const H4 = (props: HeadingProps) => (
-
+const H4 = (props: HTMLAttributes) => (
+
)
const UnorderedList = (props: ListProps) => (
diff --git a/src/layouts/Staking.tsx b/src/layouts/Staking.tsx
index aabe7c501c2..9236ac5e740 100644
--- a/src/layouts/Staking.tsx
+++ b/src/layouts/Staking.tsx
@@ -1,11 +1,11 @@
import { useTranslation } from "next-i18next"
+import type { HTMLAttributes } from "react"
import {
Box,
type BoxProps,
chakra,
Flex,
Grid,
- type HeadingProps,
SimpleGrid,
Text,
UnorderedList,
@@ -43,16 +43,12 @@ import WithdrawalsTabComparison from "@/components/Staking/WithdrawalsTabCompari
import TableOfContents from "@/components/TableOfContents"
import UpgradeStatus from "@/components/UpgradeStatus"
-const Heading1 = (props: HeadingProps) => (
-
+const Heading1 = (props: HTMLAttributes) => (
+
)
-const Heading4 = (props: HeadingProps) => (
-
+const Heading4 = (props: HTMLAttributes) => (
+
)
const Paragraph = (props: ChildOnlyProp) => (
diff --git a/src/layouts/Static.tsx b/src/layouts/Static.tsx
index 0f0fa18b64b..3b39613413e 100644
--- a/src/layouts/Static.tsx
+++ b/src/layouts/Static.tsx
@@ -1,5 +1,5 @@
import { useRouter } from "next/router"
-import { type HeadingProps } from "@chakra-ui/react"
+import type { HTMLAttributes } from "react"
import type { ChildOnlyProp, Lang } from "@/lib/types"
import type { MdPageContent, StaticFrontmatter } from "@/lib/interfaces"
@@ -38,17 +38,17 @@ import { isLangRightToLeft } from "@/lib/utils/translations"
import GuideHeroImage from "@/public/images/heroes/guides-hub-hero.jpg"
-const Heading1 = (props: HeadingProps) => (
-
+const Heading1 = (props: HTMLAttributes) => (
+
)
-const Heading2 = (props: HeadingProps) => (
-
+const Heading2 = (props: HTMLAttributes) => (
+
)
-const Heading3 = (props: HeadingProps) => (
-
+const Heading3 = (props: HTMLAttributes) => (
+
)
-const Heading4 = (props: HeadingProps) => (
-
+const Heading4 = (props: HTMLAttributes) => (
+
)
// Static layout components
diff --git a/src/layouts/Tutorial.tsx b/src/layouts/Tutorial.tsx
index 4c5a54a0a95..aa599d44653 100644
--- a/src/layouts/Tutorial.tsx
+++ b/src/layouts/Tutorial.tsx
@@ -1,11 +1,11 @@
import { useRouter } from "next/router"
+import type { HTMLAttributes } from "react"
import {
Badge,
Box,
type BoxProps,
Divider,
Flex,
- type HeadingProps,
Kbd,
Text,
type TextProps,
@@ -65,40 +65,30 @@ const ContentContainer = (props: ContentContainerProps) => {
)
}
-const Heading1 = (props: HeadingProps) => (
+const Heading1 = (props: HTMLAttributes) => (
)
-const Heading2 = (props: HeadingProps) => (
+const Heading2 = (props: HTMLAttributes) => (
)
-const Heading3 = (props: HeadingProps) => (
+const Heading3 = (props: HTMLAttributes) => (
)
-const Heading4 = (props: HeadingProps) => (
+const Heading4 = (props: HTMLAttributes) => (
)
diff --git a/src/layouts/Upgrade.tsx b/src/layouts/Upgrade.tsx
index 8978dc5f8e3..c227863f5e3 100644
--- a/src/layouts/Upgrade.tsx
+++ b/src/layouts/Upgrade.tsx
@@ -1,8 +1,8 @@
import { useTranslation } from "next-i18next"
+import type { HTMLAttributes } from "react"
import {
Box,
type BoxProps,
- type FlexProps,
List,
ListItem,
Text,
@@ -29,7 +29,9 @@ import UpgradeStatus from "@/components/UpgradeStatus"
import { getSummaryPoints } from "@/lib/utils/getSummaryPoints"
-const Page = (props: FlexProps) =>
+const Page = (props: HTMLAttributes) => (
+
+)
type ContainerProps = Pick