Skip to content

Commit ad5b7f9

Browse files
rsbhclaude
andauthored
feat: MDX component styling and UI improvements (#16)
* fix: add shiki syntax highlighting color support for code blocks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add styled MDX components for details, paragraph, and inline code Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: revert unused text directives to plain text to prevent URL mangling Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: improve content spacing and use unist-util-visit for directive plugin Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add mermaid diagram support Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: sticky sidebar, folder ordering, navbar API link, and callout fix Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: match navbar button heights for search and API links Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: preserve sidebar scroll position across navigations Move Layout to layout.tsx and render only Page in page.tsx. Sidebar scroll preserved via module-level variable targeting Apsara Sidebar.Main scrollable element. Remove duplicate border-right and overflow-y from sidebar CSS. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: default index page order to 0 for sidebar sorting Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR review comments - Guard against undefined node.name in remark-unused-directives - Use asChild on Button for API links (avoid nested interactive elements) - Remove .content code font-family: inherit (preserves monospace) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: prevent hydration error when block elements are inside paragraphs Render div instead of p when children contain block elements like summary, details, etc. to avoid invalid HTML nesting. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: use useId hook for mermaid render ID Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: disable scroll-to-top on sidebar link navigation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove unused ref from mermaid component Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent eeeecc3 commit ad5b7f9

23 files changed

Lines changed: 580 additions & 44 deletions

bun.lock

Lines changed: 252 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/chronicle/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,15 @@
3535
"fumadocs-core": "^16.4.9",
3636
"fumadocs-mdx": "^14.2.6",
3737
"lodash": "^4.17.23",
38+
"mermaid": "^11.13.0",
3839
"next": "16.1.6",
3940
"react": "^19.0.0",
4041
"react-device-detect": "^2.2.3",
4142
"react-dom": "^19.0.0",
4243
"remark-attr": "^0.11.1",
4344
"remark-directive": "^4.0.0",
4445
"slugify": "^1.6.6",
46+
"unist-util-visit": "^5.1.0",
4547
"yaml": "^2.8.2",
4648
"zod": "^4.3.6"
4749
}

packages/chronicle/source.config.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { defineDocs, defineConfig } from 'fumadocs-mdx/config'
22
import remarkDirective from 'remark-directive'
3-
import { remarkDirectiveAdmonition } from 'fumadocs-core/mdx-plugins'
3+
import { remarkDirectiveAdmonition, remarkMdxMermaid } from 'fumadocs-core/mdx-plugins'
4+
import remarkUnusedDirectives from './src/lib/remark-unused-directives'
45

56
const contentDir = process.env.CHRONICLE_CONTENT_DIR || './content'
67

@@ -35,6 +36,8 @@ export default defineConfig({
3536
},
3637
},
3738
],
39+
remarkUnusedDirectives,
40+
remarkMdxMermaid,
3841
],
3942
},
4043
})
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { loadConfig } from '@/lib/config'
2+
import { buildPageTree } from '@/lib/source'
3+
import { getTheme } from '@/themes/registry'
4+
5+
export default function DocsLayout({ children }: { children: React.ReactNode }) {
6+
const config = loadConfig()
7+
const tree = buildPageTree()
8+
const { Layout, className } = getTheme(config.theme?.name)
9+
10+
return (
11+
<Layout config={config} tree={tree} classNames={{ layout: className }}>
12+
{children}
13+
</Layout>
14+
)
15+
}

packages/chronicle/src/app/[[...slug]]/page.tsx

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,29 +26,27 @@ export default async function DocsPage({ params }: PageProps) {
2626
notFound()
2727
}
2828

29-
const { Layout, Page, className } = getTheme(config.theme?.name)
29+
const { Page } = getTheme(config.theme?.name)
3030

3131
const data = page.data as PageData
3232
const MDXBody = data.body
3333

3434
const tree = buildPageTree()
3535

3636
return (
37-
<Layout config={config} tree={tree} classNames={{ layout: className }}>
38-
<Page
39-
page={{
40-
slug: slug ?? [],
41-
frontmatter: {
42-
title: data.title,
43-
description: data.description,
44-
},
45-
content: <MDXBody components={mdxComponents} />,
46-
toc: data.toc ?? [],
47-
}}
48-
config={config}
49-
tree={tree}
50-
/>
51-
</Layout>
37+
<Page
38+
page={{
39+
slug: slug ?? [],
40+
frontmatter: {
41+
title: data.title,
42+
description: data.description,
43+
},
44+
content: <MDXBody components={mdxComponents} />,
45+
toc: data.toc ?? [],
46+
}}
47+
config={config}
48+
tree={tree}
49+
/>
5250
)
5351
}
5452

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
.callout {
22
margin: var(--rs-space-5) 0;
33
}
4+
5+
.callout p:last-child {
6+
margin-bottom: 0;
7+
}

packages/chronicle/src/components/mdx/code.module.css

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
border-radius: var(--rs-radius-2);
33
overflow: hidden;
44
margin: var(--rs-space-5) 0;
5-
border: 1px solid var(--rs-color-border-base);
5+
border: 1px solid var(--rs-color-border-base-primary);
66
}
77

88
.codeHeader {
99
padding: var(--rs-space-3) var(--rs-space-4);
1010
background: var(--rs-color-background-base-secondary);
11-
border-bottom: 1px solid var(--rs-color-border-base);
11+
border-bottom: 1px solid var(--rs-color-border-base-primary);
1212
font-size: var(--rs-font-size-mini);
1313
color: var(--rs-color-text-base-secondary);
1414
}
@@ -25,3 +25,18 @@
2525
font-size: var(--rs-font-size-small);
2626
line-height: 1.6;
2727
}
28+
29+
.pre code span {
30+
color: var(--shiki-light);
31+
}
32+
33+
:global([data-theme=dark]) .pre code span {
34+
color: var(--shiki-dark);
35+
}
36+
37+
.inlineCode {
38+
background: var(--rs-color-background-neutral-secondary);
39+
padding: var(--rs-space-1) var(--rs-space-2);
40+
border-radius: var(--rs-radius-1);
41+
font-size: inherit;
42+
}

packages/chronicle/src/components/mdx/code.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ type PreProps = ComponentProps<'pre'> & {
88
title?: string
99
}
1010

11+
export function MdxCode({ children, className, ...props }: ComponentProps<'code'>) {
12+
if (className || (typeof children === 'object')) {
13+
return <code className={className} {...props}>{children}</code>
14+
}
15+
return <code className={styles.inlineCode} {...props}>{children}</code>
16+
}
17+
1118
export function MdxPre({ children, title, className, ...props }: PreProps) {
1219
return (
1320
<div className={styles.codeBlock}>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
.details {
2+
border: 1px solid var(--rs-color-border-base-primary);
3+
border-radius: var(--rs-radius-2);
4+
margin: var(--rs-space-5) 0;
5+
}
6+
7+
.summary {
8+
padding: var(--rs-space-4) var(--rs-space-5);
9+
cursor: pointer;
10+
font-weight: 500;
11+
font-size: var(--rs-font-size-small);
12+
color: var(--rs-color-text-base-primary);
13+
background: var(--rs-color-background-base-secondary);
14+
list-style: none;
15+
display: flex;
16+
align-items: center;
17+
gap: var(--rs-space-3);
18+
}
19+
20+
.summary::-webkit-details-marker {
21+
display: none;
22+
}
23+
24+
.summary::before {
25+
content: '▶';
26+
font-size: 10px;
27+
transition: transform 0.2s ease;
28+
color: var(--rs-color-text-base-secondary);
29+
}
30+
31+
.details[open] > .summary::before {
32+
transform: rotate(90deg);
33+
}
34+
35+
.content {
36+
padding: var(--rs-space-4) var(--rs-space-5);
37+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { ComponentProps } from 'react'
2+
import styles from './details.module.css'
3+
4+
export function MdxDetails({ children, className, ...props }: ComponentProps<'details'>) {
5+
return (
6+
<details className={`${styles.details} ${className ?? ''}`} {...props}>
7+
{children}
8+
</details>
9+
)
10+
}
11+
12+
export function MdxSummary({ children, className, ...props }: ComponentProps<'summary'>) {
13+
return (
14+
<summary className={`${styles.summary} ${className ?? ''}`} {...props}>
15+
{children}
16+
</summary>
17+
)
18+
}

0 commit comments

Comments
 (0)