diff --git a/packages/ui/src/components/Markdown/Markdown.stories.tsx b/packages/ui/src/components/Markdown/Markdown.stories.tsx index 2e54f32..2fe567d 100644 --- a/packages/ui/src/components/Markdown/Markdown.stories.tsx +++ b/packages/ui/src/components/Markdown/Markdown.stories.tsx @@ -1,265 +1,163 @@ -import { Markdown } from './Markdown'; - import type { Meta, StoryObj } from '@storybook/react'; +import React from 'react'; + +import { Markdown, MARKDOWN_COMPONENTS } from './Markdown'; -/** - * Metadata for the Markdown component stories. - */ const meta: Meta = { - title: 'components/Markdown', + title: 'Components/Markdown', component: Markdown, - tags: ['autodocs'], + parameters: { + layout: 'padded', + }, }; export default meta; - -/** - * Type definition for Markdown component stories. - */ type Story = StoryObj; /** - * Default story showcasing various HTML elements to verify typography. - */ -export const Default: Story = { - args: { - children: ( - <> -

- This is a Markdown component that uses Tailwind CSS Typography (prose) to - render content with consistent styling. -

-

- It is designed to be used with rendered HTML from markdown processors, but works with any - HTML content that needs standard document styling. -

- - ), - }, -}; - -/** - * Showcasing all heading levels. - */ -export const Typography: Story = { - args: { - children: ( - <> -

Heading Level 1

-

Paragraph text following an H1.

-

Heading Level 2

-

Paragraph text following an H2.

-

Heading Level 3

-

Paragraph text following an H3.

-

Heading Level 4

-

Paragraph text following an H4.

-
Heading Level 5
-

Paragraph text following an H5.

-
Heading Level 6
-

Paragraph text following an H6.

- - ), - }, -}; - -/** - * Showcasing ordered and unordered lists. - */ -export const Lists: Story = { - args: { - children: ( - <> -

Unordered List

- - -

Ordered List

-
    -
  1. Step one
  2. -
  3. - Step two -
      -
    1. Sub-step 2.1
    2. -
    3. Sub-step 2.2
    4. -
    -
  4. -
  5. Step three
  6. -
- - ), - }, -}; - -/** - * Showcasing blockquotes. - */ -export const Quotes: Story = { - args: { - children: ( - <> -

Before the quote.

-
- "Design is not just what it looks like and feels like. Design is how it works." -
— Steve Jobs
-
-

After the quote.

- - ), - }, -}; - -/** - * Showcasing code and pre blocks. - */ -export const Code: Story = { - args: { - children: ( - <> -

- You can use inline code for small snippets. -

-
-          {`function hello() {
-  console.log("Hello, world!");
-}`}
-        
- - ), - }, -}; - -/** - * Showcasing tables. - */ -export const Tables: Story = { - args: { - children: ( - - - - - - - - - - - - - - - - - - - - - - - - - -
FeatureDescriptionStatus
TypographyGaramond and Lato fonts✅ Done
Dark ModeAutomatic inversion✅ Done
ResponsiveFluid layouts✅ Done
- ), - }, -}; - -/** - * The "Kitchen Sink" containing everything. + * A "Kitchen Sink" demonstration of all Markdown components working together + * as they would in a real article. */ export const KitchenSink: Story = { - args: { - children: ( - <> -

The Art of Markdown Rendering

-

- A lead paragraph that stands out and sets the tone for the rest of the document. -

-

- Markdown is a lightweight markup language with plain-text-formatting syntax. Its design - allows it to be converted to many output formats, but the name originally referred to the - tool for converting it to HTML. -

+ render: () => ( +
+ + The Art of Markdown Integration + + This article demonstrates how our design system translates standard Markdown tags into + beautiful, accessible UI primitives. From typography to complex data tables. + -

Key Features

-
    -
  • - Easy to read - The source text looks like the final output. -
  • -
  • - Easy to write - Minimal syntax overhead. -
  • -
  • - Versatile - Supports many elements like italics,{' '} - strikethrough, and code. -
  • -
+ -

Example Code Block

-
-          {`import { Markdown } from '@ermnvldmr/ui';
+        Typography & Vertical Rhythm
+        
+          Our typography system is built on a strict vertical rhythm. Headers use the{' '}
+          Header component, while paragraphs
+          leverage the Paragraph component with
+          pre-configured gutters.
+        
 
-export const MyPage = () => (
-  
-    

Welcome

-

This is styled automatically.

-
-);`}
-
+ + "Design is not just what it looks like and feels like. Design is how it works." +
+ — Steve Jobs +
-
- "Simplicity is the ultimate sophistication." -
— Leonardo da Vinci -
+ Nesting and Lists + + Lists are handled by our List system, + supporting both ordered and unordered variants: + -
+ + Standardization across all articles + + Support for nested structures: + + Nested unordered item + Another nested item + + + Consistent spacing and markers + -

Data Representation

- - - - - - - - - - - - - - - - - - - - - - - - - -
LanguageDifficultyUsage
TypeScriptModerateFrontend/Backend
RustHighSystems
PythonLowData Science
+ Code & Technical Content + + Technical articles often require code blocks. We use{' '} + CodeBlock for multi-line snippets: + -

Media Elements

-

Images should be rounded and have a nice shadow.

- Coding + + {`export const MarkdownP = memo(function MarkdownP(props: ParagraphProps) { + return ; +});`} + + + + Data Representation + + Tables are notoriously difficult to style in Markdown. Our components ensure they stay + within the container and maintain readable density. + + + + + + Component + Tag + Status + + + + + MarkdownP + + p + + Verified + + + MarkdownTable + + table + + Verified + + + + + Visual Assets + +
+
+ ), +}; -

Conclusion: We've built a robust system for rendering content.

- - ), - }, +/** + * Specifically showcases the header hierarchy from H1 to H6. + */ +export const HeaderHierarchy: Story = { + render: () => ( +
+ Header Level 1 + Header Level 2 + Header Level 3 + Header Level 4 + Header Level 5 + Header Level 6 +
+ ), +}; + +/** + * Demonstrates various list types and their spacing. + */ +export const ListStyles: Story = { + render: () => ( +
+
+ Unordered List + + First item + Second item + Third item + +
+
+ Ordered List + + Step one: Preparation + Step two: Implementation + Step three: Verification + +
+
+ ), }; diff --git a/packages/ui/src/components/Markdown/Markdown.test.tsx b/packages/ui/src/components/Markdown/Markdown.test.tsx new file mode 100644 index 0000000..2f08066 --- /dev/null +++ b/packages/ui/src/components/Markdown/Markdown.test.tsx @@ -0,0 +1,46 @@ +import { render, screen } from '@testing-library/react'; +import React from 'react'; + +import { Markdown, MARKDOWN_COMPONENTS } from './Markdown'; + +describe('Markdown Components', () => { + it('renders various markdown components correctly', () => { + render( + + Heading 1 + This is a paragraph. + Link + + Item 1 + + + + + Header + + + + + Cell + + + + + ); + + expect(screen.getByText('Heading 1')).toBeInTheDocument(); + expect(screen.getByText('This is a paragraph.')).toBeInTheDocument(); + expect(screen.getByRole('link')).toHaveAttribute('href', 'https://example.com'); + expect(screen.getByRole('list')).toBeInTheDocument(); + expect(screen.getByRole('table')).toBeInTheDocument(); + expect(screen.getByRole('cell')).toHaveTextContent('Cell'); + }); + + it('MARKDOWN_COMPONENTS map contains all necessary tags', () => { + expect(MARKDOWN_COMPONENTS.p).toBeDefined(); + expect(MARKDOWN_COMPONENTS.h1).toBeDefined(); + expect(MARKDOWN_COMPONENTS.table).toBeDefined(); + expect(MARKDOWN_COMPONENTS.pre).toBeDefined(); + expect(MARKDOWN_COMPONENTS.code).toBeDefined(); + }); +}); diff --git a/packages/ui/src/components/Markdown/Markdown.tsx b/packages/ui/src/components/Markdown/Markdown.tsx index 868a03e..624e5d7 100644 --- a/packages/ui/src/components/Markdown/Markdown.tsx +++ b/packages/ui/src/components/Markdown/Markdown.tsx @@ -1,9 +1,29 @@ import { cn } from '@ermnvldmr/stl'; -import React from 'react'; +import React, { memo } from 'react'; + +import { MarkdownA } from './MarkdownA/MarkdownA'; +import { MarkdownBlockquote } from './MarkdownBlockquote/MarkdownBlockquote'; +import { MarkdownCode } from './MarkdownCode/MarkdownCode'; +import { MarkdownH1 } from './MarkdownH1/MarkdownH1'; +import { MarkdownH2 } from './MarkdownH2/MarkdownH2'; +import { MarkdownH3 } from './MarkdownH3/MarkdownH3'; +import { MarkdownH4 } from './MarkdownH4/MarkdownH4'; +import { MarkdownH5 } from './MarkdownH5/MarkdownH5'; +import { MarkdownH6 } from './MarkdownH6/MarkdownH6'; +import { MarkdownHR } from './MarkdownHR/MarkdownHR'; +import { MarkdownImg } from './MarkdownImg/MarkdownImg'; +import { MarkdownLI } from './MarkdownLI/MarkdownLI'; +import { MarkdownOL } from './MarkdownOL/MarkdownOL'; +import { MarkdownP } from './MarkdownP/MarkdownP'; +import { MarkdownPre } from './MarkdownPre/MarkdownPre'; +import { MarkdownTable } from './MarkdownTable/MarkdownTable'; +import { MarkdownTBody } from './MarkdownTBody/MarkdownTBody'; +import { MarkdownTD } from './MarkdownTD/MarkdownTD'; +import { MarkdownTH } from './MarkdownTH/MarkdownTH'; +import { MarkdownTHead } from './MarkdownTHead/MarkdownTHead'; +import { MarkdownTR } from './MarkdownTR/MarkdownTR'; +import { MarkdownUL } from './MarkdownUL/MarkdownUL'; -/** - * Props for the Markdown component. - */ /** * Props for the Markdown component. */ @@ -14,22 +34,75 @@ export interface MarkdownProps { className?: string; } +/** + * A map of HTML tags to Markdown components for use with MDX or Astro Content. + */ +export const MARKDOWN_COMPONENTS = { + p: MarkdownP, + a: MarkdownA, + h1: MarkdownH1, + h2: MarkdownH2, + h3: MarkdownH3, + h4: MarkdownH4, + h5: MarkdownH5, + h6: MarkdownH6, + blockquote: MarkdownBlockquote, + ul: MarkdownUL, + ol: MarkdownOL, + li: MarkdownLI, + table: MarkdownTable, + thead: MarkdownTHead, + tbody: MarkdownTBody, + tr: MarkdownTR, + th: MarkdownTH, + td: MarkdownTD, + code: MarkdownCode, + pre: MarkdownPre, + hr: MarkdownHR, + img: MarkdownImg, +} as const; + +const MarkdownComponent = memo(function Markdown({ children, className }: MarkdownProps) { + return
{children}
; +}); + /** * Markdown component provides a styled container for rendered markdown content. - * It uses the Tailwind CSS Typography plugin (prose) with custom project styles. * - * @param props - The component props. - * @param props.children - * @param props.className - * @returns A React element. + * It also exports all necessary sub-components for mapping HTML tags to design system components. + * * @example * ```tsx * - *

Title

- *

Content goes here.

+ * Title + * Content goes here. *
+ * + * // Or with Astro: + * * ``` */ -export const Markdown: React.FC = ({ children, className }) => { - return
{children}
; -}; +export const Markdown = Object.assign(MarkdownComponent, { + P: MarkdownP, + A: MarkdownA, + H1: MarkdownH1, + H2: MarkdownH2, + H3: MarkdownH3, + H4: MarkdownH4, + H5: MarkdownH5, + H6: MarkdownH6, + Blockquote: MarkdownBlockquote, + UL: MarkdownUL, + OL: MarkdownOL, + LI: MarkdownLI, + Table: MarkdownTable, + THead: MarkdownTHead, + TBody: MarkdownTBody, + TR: MarkdownTR, + TH: MarkdownTH, + TD: MarkdownTD, + Code: MarkdownCode, + Pre: MarkdownPre, + HR: MarkdownHR, + Img: MarkdownImg, +}); \ No newline at end of file diff --git a/packages/ui/src/components/Markdown/MarkdownA/MarkdownA.tsx b/packages/ui/src/components/Markdown/MarkdownA/MarkdownA.tsx new file mode 100644 index 0000000..b599705 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownA/MarkdownA.tsx @@ -0,0 +1,12 @@ +import React, { memo } from 'react'; + +import { Link } from '../../Link/Link'; + +import type { LinkProps } from '../../Link/Link'; + +/** + * A Markdown link component that wraps the design system Link. + */ +export const MarkdownA = memo(function MarkdownA(props: LinkProps) { + return ; +}); \ No newline at end of file diff --git a/packages/ui/src/components/Markdown/MarkdownBlockquote/MarkdownBlockquote.tsx b/packages/ui/src/components/Markdown/MarkdownBlockquote/MarkdownBlockquote.tsx new file mode 100644 index 0000000..6e213c1 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownBlockquote/MarkdownBlockquote.tsx @@ -0,0 +1,14 @@ +import React, { memo } from 'react'; + +import { Blockquote } from '../../Blockquote/Blockquote'; + +import type { BlockquoteProps } from '../../Blockquote/Blockquote'; + +/** + * A Markdown blockquote component that wraps the design system Blockquote. + * + * Automatically applies gutterBottom and indentation. + */ +export const MarkdownBlockquote = memo(function MarkdownBlockquote(props: BlockquoteProps) { + return
; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownCode/MarkdownCode.tsx b/packages/ui/src/components/Markdown/MarkdownCode/MarkdownCode.tsx new file mode 100644 index 0000000..535ee79 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownCode/MarkdownCode.tsx @@ -0,0 +1,12 @@ +import React, { memo } from 'react'; + +import { Code } from '../../Code/Code'; + +import type { CodeProps } from '../../Code/Code'; + +/** + * A Markdown code component for inline snippets. + */ +export const MarkdownCode = memo(function MarkdownCode(props: CodeProps) { + return ; +}); \ No newline at end of file diff --git a/packages/ui/src/components/Markdown/MarkdownH1/MarkdownH1.tsx b/packages/ui/src/components/Markdown/MarkdownH1/MarkdownH1.tsx new file mode 100644 index 0000000..083ab98 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownH1/MarkdownH1.tsx @@ -0,0 +1,12 @@ +import React, { memo } from 'react'; + +import { Header } from '../../Header/Header'; + +import type { HeaderProps } from '../../Header/Header'; + +/** + * A Markdown H1 component that wraps the design system Header. + */ +export const MarkdownH1 = memo(function MarkdownH1(props: Omit) { + return
; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownH2/MarkdownH2.tsx b/packages/ui/src/components/Markdown/MarkdownH2/MarkdownH2.tsx new file mode 100644 index 0000000..3b954c9 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownH2/MarkdownH2.tsx @@ -0,0 +1,12 @@ +import React, { memo } from 'react'; + +import { Header } from '../../Header/Header'; + +import type { HeaderProps } from '../../Header/Header'; + +/** + * A Markdown H2 component that wraps the design system Header. + */ +export const MarkdownH2 = memo(function MarkdownH2(props: Omit) { + return
; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownH3/MarkdownH3.tsx b/packages/ui/src/components/Markdown/MarkdownH3/MarkdownH3.tsx new file mode 100644 index 0000000..68f7bb6 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownH3/MarkdownH3.tsx @@ -0,0 +1,12 @@ +import React, { memo } from 'react'; + +import { Header } from '../../Header/Header'; + +import type { HeaderProps } from '../../Header/Header'; + +/** + * A Markdown H3 component that wraps the design system Header. + */ +export const MarkdownH3 = memo(function MarkdownH3(props: Omit) { + return
; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownH4/MarkdownH4.tsx b/packages/ui/src/components/Markdown/MarkdownH4/MarkdownH4.tsx new file mode 100644 index 0000000..6147d3f --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownH4/MarkdownH4.tsx @@ -0,0 +1,12 @@ +import React, { memo } from 'react'; + +import { Header } from '../../Header/Header'; + +import type { HeaderProps } from '../../Header/Header'; + +/** + * A Markdown H4 component that wraps the design system Header. + */ +export const MarkdownH4 = memo(function MarkdownH4(props: Omit) { + return
; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownH5/MarkdownH5.tsx b/packages/ui/src/components/Markdown/MarkdownH5/MarkdownH5.tsx new file mode 100644 index 0000000..fcca02c --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownH5/MarkdownH5.tsx @@ -0,0 +1,12 @@ +import React, { memo } from 'react'; + +import { Header } from '../../Header/Header'; + +import type { HeaderProps } from '../../Header/Header'; + +/** + * A Markdown H5 component that wraps the design system Header. + */ +export const MarkdownH5 = memo(function MarkdownH5(props: Omit) { + return
; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownH6/MarkdownH6.tsx b/packages/ui/src/components/Markdown/MarkdownH6/MarkdownH6.tsx new file mode 100644 index 0000000..288b5f0 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownH6/MarkdownH6.tsx @@ -0,0 +1,12 @@ +import React, { memo } from 'react'; + +import { Header } from '../../Header/Header'; + +import type { HeaderProps } from '../../Header/Header'; + +/** + * A Markdown H6 component that wraps the design system Header. + */ +export const MarkdownH6 = memo(function MarkdownH6(props: Omit) { + return
; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownHR/MarkdownHR.tsx b/packages/ui/src/components/Markdown/MarkdownHR/MarkdownHR.tsx new file mode 100644 index 0000000..73bf2d7 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownHR/MarkdownHR.tsx @@ -0,0 +1,12 @@ +import React, { memo } from 'react'; + +import { Separator } from '../../Separator/Separator'; + +import type { SeparatorProps } from '../../Separator/Separator'; + +/** + * A Markdown horizontal rule component that wraps the design system Separator. + */ +export const MarkdownHR = memo(function MarkdownHR(props: SeparatorProps) { + return ; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownImg/MarkdownImg.tsx b/packages/ui/src/components/Markdown/MarkdownImg/MarkdownImg.tsx new file mode 100644 index 0000000..810ca40 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownImg/MarkdownImg.tsx @@ -0,0 +1,17 @@ +import React, { memo } from 'react'; + +import { Image } from '../../Image/Image'; + +import type { ImageProps } from '../../Image/Image'; + +/** + * A Markdown image component that wraps the design system Image. + * + * Note: Markdown usually only provides src and alt. Default constraints + * might be needed if they are not provided by the processor. + */ +export const MarkdownImg = memo(function MarkdownImg(props: ImageProps) { + // Default values for common Markdown images to prevent CLS + // if specific dimensions aren't provided. + return ; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownLI/MarkdownLI.tsx b/packages/ui/src/components/Markdown/MarkdownLI/MarkdownLI.tsx new file mode 100644 index 0000000..1be4ef3 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownLI/MarkdownLI.tsx @@ -0,0 +1,12 @@ +import React, { memo } from 'react'; + +import { List } from '../../List/List'; + +import type { ListItemProps } from '../../List/List'; + +/** + * A Markdown list item component. + */ +export const MarkdownLI = memo(function MarkdownLI(props: ListItemProps) { + return ; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownOL/MarkdownOL.tsx b/packages/ui/src/components/Markdown/MarkdownOL/MarkdownOL.tsx new file mode 100644 index 0000000..d8c7bcc --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownOL/MarkdownOL.tsx @@ -0,0 +1,12 @@ +import React, { memo } from 'react'; + +import { List } from '../../List/List'; + +import type { ListProps } from '../../List/List'; + +/** + * A Markdown ordered list component. + */ +export const MarkdownOL = memo(function MarkdownOL(props: ListProps) { + return ; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownP/MarkdownP.tsx b/packages/ui/src/components/Markdown/MarkdownP/MarkdownP.tsx new file mode 100644 index 0000000..0d9b1a7 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownP/MarkdownP.tsx @@ -0,0 +1,14 @@ +import React, { memo } from 'react'; + +import { Paragraph } from '../../Paragraph/Paragraph'; + +import type { ParagraphProps } from '../../Paragraph/Paragraph'; + +/** + * A Markdown paragraph component that wraps the design system Paragraph. + * + * Automatically applies gutterBottom for consistent vertical rhythm. + */ +export const MarkdownP = memo(function MarkdownP(props: ParagraphProps) { + return ; +}); \ No newline at end of file diff --git a/packages/ui/src/components/Markdown/MarkdownPre/MarkdownPre.tsx b/packages/ui/src/components/Markdown/MarkdownPre/MarkdownPre.tsx new file mode 100644 index 0000000..fe22516 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownPre/MarkdownPre.tsx @@ -0,0 +1,14 @@ +import React, { memo } from 'react'; + +import { CodeBlock } from '../../Code/CodeBlock/CodeBlock'; + +import type { CodeBlockProps } from '../../Code/CodeBlock/CodeBlock'; + +/** + * A Markdown pre component for code blocks. + * + * Wraps content in the design system CodeBlock. + */ +export const MarkdownPre = memo(function MarkdownPre(props: CodeBlockProps) { + return ; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownTBody/MarkdownTBody.tsx b/packages/ui/src/components/Markdown/MarkdownTBody/MarkdownTBody.tsx new file mode 100644 index 0000000..2708e18 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownTBody/MarkdownTBody.tsx @@ -0,0 +1,10 @@ +import React, { memo } from 'react'; + +import { Table } from '../../Table/Table'; + +/** + * A Markdown table body (tbody) component. + */ +export const MarkdownTBody = memo(function MarkdownTBody(props: React.HTMLAttributes) { + return ; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownTD/MarkdownTD.tsx b/packages/ui/src/components/Markdown/MarkdownTD/MarkdownTD.tsx new file mode 100644 index 0000000..8bd32b6 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownTD/MarkdownTD.tsx @@ -0,0 +1,18 @@ +import React, { memo } from 'react'; + +import { Table } from '../../Table/Table'; + +/** + * A Markdown table cell (td) component. + * + * Wraps content in Table.Content for consistent styling and alignment. + */ +export const MarkdownTD = memo(function MarkdownTD({ children, align, ...props }: React.TdHTMLAttributes) { + const effectiveAlign = (align === 'left' || align === 'center' || align === 'right') ? align : undefined; + + return ( + + {children} + + ); +}); diff --git a/packages/ui/src/components/Markdown/MarkdownTH/MarkdownTH.tsx b/packages/ui/src/components/Markdown/MarkdownTH/MarkdownTH.tsx new file mode 100644 index 0000000..b5f9e23 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownTH/MarkdownTH.tsx @@ -0,0 +1,12 @@ +import React, { memo } from 'react'; + +import { Table } from '../../Table/Table'; + +/** + * A Markdown table header cell (th) component. + */ +export const MarkdownTH = memo(function MarkdownTH({ align, ...props }: React.ThHTMLAttributes) { + const effectiveAlign = (align === 'left' || align === 'center' || align === 'right') ? align : undefined; + + return ; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownTHead/MarkdownTHead.tsx b/packages/ui/src/components/Markdown/MarkdownTHead/MarkdownTHead.tsx new file mode 100644 index 0000000..8d5bd7d --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownTHead/MarkdownTHead.tsx @@ -0,0 +1,10 @@ +import React, { memo } from 'react'; + +import { Table } from '../../Table/Table'; + +/** + * A Markdown table head (thead) component. + */ +export const MarkdownTHead = memo(function MarkdownTHead(props: React.HTMLAttributes) { + return ; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownTR/MarkdownTR.tsx b/packages/ui/src/components/Markdown/MarkdownTR/MarkdownTR.tsx new file mode 100644 index 0000000..3549b58 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownTR/MarkdownTR.tsx @@ -0,0 +1,10 @@ +import React, { memo } from 'react'; + +import { Table } from '../../Table/Table'; + +/** + * A Markdown table row (tr) component. + */ +export const MarkdownTR = memo(function MarkdownTR(props: React.HTMLAttributes) { + return ; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownTable/MarkdownTable.tsx b/packages/ui/src/components/Markdown/MarkdownTable/MarkdownTable.tsx new file mode 100644 index 0000000..3a1e234 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownTable/MarkdownTable.tsx @@ -0,0 +1,12 @@ +import React, { memo } from 'react'; + +import { Table } from '../../Table/Table'; + +import type { TableProps } from '../../Table/Table'; + +/** + * A Markdown table root component. + */ +export const MarkdownTable = memo(function MarkdownTable(props: TableProps) { + return ; +}); diff --git a/packages/ui/src/components/Markdown/MarkdownUL/MarkdownUL.tsx b/packages/ui/src/components/Markdown/MarkdownUL/MarkdownUL.tsx new file mode 100644 index 0000000..dea8fc5 --- /dev/null +++ b/packages/ui/src/components/Markdown/MarkdownUL/MarkdownUL.tsx @@ -0,0 +1,12 @@ +import React, { memo } from 'react'; + +import { List } from '../../List/List'; + +import type { ListProps } from '../../List/List'; + +/** + * A Markdown unordered list component. + */ +export const MarkdownUL = memo(function MarkdownUL(props: ListProps) { + return ; +}); diff --git a/services/www/src/pages/articles/[...slug].astro b/services/www/src/pages/articles/[...slug].astro index a801b63..6f8b530 100644 --- a/services/www/src/pages/articles/[...slug].astro +++ b/services/www/src/pages/articles/[...slug].astro @@ -1,4 +1,5 @@ --- +import { MARKDOWN_COMPONENTS } from '@ermnvldmr/ui'; import { getCollection, render } from 'astro:content'; import { ArticleLayout } from '#layouts/ArticleLayout/ArticleLayout'; @@ -30,6 +31,6 @@ const { title, description, createdDate, updatedDate, tags } = entry.data; updatedDate={updatedDate} tags={tags} > - +