Skip to content

Commit afe6f81

Browse files
authored
feat: filter markdown docs by framework and package manager (#717)
1 parent 01f9d70 commit afe6f81

File tree

8 files changed

+444
-128
lines changed

8 files changed

+444
-128
lines changed

src/components/CopyPageDropdown.tsx

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ import {
1010
DropdownContent,
1111
DropdownItem,
1212
} from './Dropdown'
13+
import {
14+
getPackageManager,
15+
PACKAGE_MANAGERS,
16+
} from '~/utils/markdown/installCommand'
1317

1418
// Markdown icon component matching the screenshot
1519
function MarkdownIcon({ className }: { className?: string }) {
@@ -92,23 +96,40 @@ type CopyPageDropdownProps = {
9296
branch?: string
9397
/** File path in the repo (e.g., 'src/blog/my-post.md'). Required if repo is provided. */
9498
filePath?: string
99+
/** Current framework for filtering markdown content (appended as ?framework= query param) */
100+
currentFramework?: string
95101
}
96102

97103
export function CopyPageDropdown({
98104
repo,
99105
branch,
100106
filePath,
107+
currentFramework,
101108
}: CopyPageDropdownProps = {}) {
102109
const [open, setOpen] = React.useState(false)
103110
const [copied, setCopied] = React.useState(false)
104111
const { notify } = useToast()
105112

106113
// Determine if we should fetch from GitHub or use the page URL
107-
const useGitHub = repo && branch && filePath
114+
const useGitHub = repo === 'tanstack/tanstack.com'
108115
const gitHubUrl = useGitHub
109116
? `https://raw.githubusercontent.com/${repo}/${branch}/${filePath}`
110117
: null
111-
const pageMarkdownUrl = `${typeof window !== 'undefined' ? window.location.origin : ''}${typeof window !== 'undefined' ? window.location.pathname.replace(/\/$/, '') : ''}.md`
118+
const pageMarkdownUrl = (() => {
119+
const base = `${typeof window !== 'undefined' ? window.location.origin : ''}${typeof window !== 'undefined' ? window.location.pathname.replace(/\/$/, '') : ''}.md`
120+
const params = new URLSearchParams()
121+
if (currentFramework) {
122+
params.set('framework', currentFramework)
123+
}
124+
// Read package manager from localStorage (same key as PackageManagerTabs)
125+
if (typeof localStorage !== 'undefined') {
126+
const pm = localStorage.getItem('packageManager')
127+
const validPm = getPackageManager(pm)
128+
params.set('pm', validPm)
129+
}
130+
const queryString = params.toString()
131+
return queryString ? `${base}?${queryString}` : base
132+
})()
112133

113134
const handleCopyPage = async () => {
114135
const urlToFetch = gitHubUrl || pageMarkdownUrl

src/components/Doc.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ export function Doc({
164164
libraryId={libraryId}
165165
libraryVersion={libraryVersion}
166166
pagePath={pagePath}
167+
currentFramework={currentFramework}
167168
titleBarActions={
168169
setIsFullWidth ? (
169170
<button

src/components/markdown/MarkdownContent.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ type MarkdownContentProps = {
2626
libraryId?: string
2727
libraryVersion?: string
2828
pagePath?: string
29+
/** Current framework for filtering markdown content */
30+
currentFramework?: string
2931
}
3032

3133
export function MarkdownContent({
@@ -41,6 +43,7 @@ export function MarkdownContent({
4143
libraryId,
4244
libraryVersion,
4345
pagePath,
46+
currentFramework,
4447
}: MarkdownContentProps) {
4548
const renderMarkdownContent = () => {
4649
const markdownElement = htmlMarkup ? (
@@ -70,7 +73,12 @@ export function MarkdownContent({
7073
<div className="flex flex-wrap items-center justify-between gap-2">
7174
<DocTitle>{title}</DocTitle>
7275
<div className="flex items-center gap-2 shrink-0">
73-
<CopyPageDropdown repo={repo} branch={branch} filePath={filePath} />
76+
<CopyPageDropdown
77+
repo={repo}
78+
branch={branch}
79+
filePath={filePath}
80+
currentFramework={currentFramework}
81+
/>
7482
{titleBarActions}
7583
</div>
7684
</div>

src/components/markdown/PackageManagerTabs.tsx

Lines changed: 6 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,12 @@ import { create } from 'zustand'
55
import { Tabs, type TabDefinition } from './Tabs'
66
import { CodeBlock } from './CodeBlock'
77
import type { Framework } from '~/libraries/types'
8-
9-
type PackageManager = 'bun' | 'npm' | 'pnpm' | 'yarn'
10-
type InstallMode =
11-
| 'install'
12-
| 'dev-install'
13-
| 'local-install'
14-
| 'create'
15-
| 'custom'
8+
import {
9+
getInstallCommand,
10+
PACKAGE_MANAGERS,
11+
type PackageManager,
12+
type InstallMode,
13+
} from '~/utils/markdown/installCommand'
1614

1715
// Use zustand for cross-component synchronization
1816
// This ensures all PackageManagerTabs instances on the page stay in sync
@@ -36,119 +34,6 @@ type PackageManagerTabsProps = {
3634
frameworks: Framework[]
3735
}
3836

39-
const PACKAGE_MANAGERS: PackageManager[] = ['npm', 'pnpm', 'yarn', 'bun']
40-
41-
function getInstallCommand(
42-
packageManager: PackageManager,
43-
packageGroups: string[][],
44-
mode: InstallMode,
45-
): string[] {
46-
const commands: string[] = []
47-
48-
if (mode === 'custom') {
49-
for (const packages of packageGroups) {
50-
const pkgStr = packages.join(' ')
51-
switch (packageManager) {
52-
case 'npm':
53-
commands.push(`npm ${pkgStr}`)
54-
break
55-
case 'pnpm':
56-
commands.push(`pnpm ${pkgStr}`)
57-
break
58-
case 'yarn':
59-
commands.push(`yarn ${pkgStr}`)
60-
break
61-
case 'bun':
62-
commands.push(`bun ${pkgStr}`)
63-
break
64-
}
65-
}
66-
}
67-
68-
if (mode === 'create') {
69-
for (const packages of packageGroups) {
70-
const pkgStr = packages.join(' ')
71-
switch (packageManager) {
72-
case 'npm':
73-
commands.push(`npm create ${pkgStr}`)
74-
break
75-
case 'pnpm':
76-
commands.push(`pnpm create ${pkgStr}`)
77-
break
78-
case 'yarn':
79-
commands.push(`yarn create ${pkgStr}`)
80-
break
81-
case 'bun':
82-
commands.push(`bun create ${pkgStr}`)
83-
break
84-
}
85-
}
86-
}
87-
88-
if (mode === 'local-install') {
89-
// Each group becomes one command line
90-
for (const packages of packageGroups) {
91-
const pkgStr = packages.join(' ')
92-
switch (packageManager) {
93-
case 'npm':
94-
commands.push(`npx ${pkgStr}`)
95-
break
96-
case 'pnpm':
97-
commands.push(`pnpx ${pkgStr}`)
98-
break
99-
case 'yarn':
100-
commands.push(`yarn dlx ${pkgStr}`)
101-
break
102-
case 'bun':
103-
commands.push(`bunx ${pkgStr}`)
104-
break
105-
}
106-
}
107-
return commands
108-
}
109-
110-
if (mode === 'dev-install') {
111-
for (const packages of packageGroups) {
112-
const pkgStr = packages.join(' ')
113-
switch (packageManager) {
114-
case 'npm':
115-
commands.push(`npm i -D ${pkgStr}`)
116-
break
117-
case 'pnpm':
118-
commands.push(`pnpm add -D ${pkgStr}`)
119-
break
120-
case 'yarn':
121-
commands.push(`yarn add -D ${pkgStr}`)
122-
break
123-
case 'bun':
124-
commands.push(`bun add -d ${pkgStr}`)
125-
break
126-
}
127-
}
128-
return commands
129-
}
130-
131-
// install mode
132-
for (const packages of packageGroups) {
133-
const pkgStr = packages.join(' ')
134-
switch (packageManager) {
135-
case 'npm':
136-
commands.push(`npm i ${pkgStr}`)
137-
break
138-
case 'pnpm':
139-
commands.push(`pnpm add ${pkgStr}`)
140-
break
141-
case 'yarn':
142-
commands.push(`yarn add ${pkgStr}`)
143-
break
144-
case 'bun':
145-
commands.push(`bun add ${pkgStr}`)
146-
break
147-
}
148-
}
149-
return commands
150-
}
151-
15237
export function PackageManagerTabs({
15338
packagesByFramework,
15439
mode,

src/routes/$libraryId/$version.docs.framework.$framework.{$}[.]md.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { findLibrary, getBranch } from '~/libraries'
22
import { loadDocs } from '~/utils/docs'
33
import { notFound, createFileRoute } from '@tanstack/react-router'
4+
import { filterFrameworkContent } from '~/utils/markdown/filterFrameworkContent'
5+
import { getPackageManager } from '~/utils/markdown/installCommand'
46

57
export const Route = createFileRoute(
68
'/$libraryId/$version/docs/framework/$framework/{$}.md',
@@ -19,7 +21,9 @@ export const Route = createFileRoute(
1921
_splat: string
2022
}
2123
}) => {
22-
const _url = new URL(request.url)
24+
const url = new URL(request.url)
25+
const pm = getPackageManager(url.searchParams.get('pm'))
26+
const keepMarkers = url.searchParams.get('keep_markers') === 'true'
2327

2428
const { libraryId, version, framework, _splat: docsPath } = params
2529
const library = findLibrary(libraryId)
@@ -36,7 +40,14 @@ export const Route = createFileRoute(
3640
docsPath: `${root}/framework/${framework}/${docsPath}`,
3741
})
3842

39-
const markdownContent = `# ${doc.title}\n${doc.content}`
43+
// Filter framework-specific content using framework from URL path
44+
const filteredContent = filterFrameworkContent(doc.content, {
45+
framework,
46+
packageManager: pm,
47+
keepMarkers,
48+
})
49+
50+
const markdownContent = `# ${doc.title}\n${filteredContent}`
4051
const filename = (docsPath || 'file').split('/').join('-')
4152

4253
return new Response(markdownContent, {

src/routes/$libraryId/$version.docs.{$}[.]md.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { createFileRoute } from '@tanstack/react-router'
22
import { getBranch, getLibrary, type LibraryId } from '~/libraries'
33
import { loadDocs } from '~/utils/docs'
4+
import { filterFrameworkContent } from '~/utils/markdown/filterFrameworkContent'
5+
import { getPackageManager } from '~/utils/markdown/installCommand'
46

57
export const Route = createFileRoute('/$libraryId/$version/docs/{$}.md')({
68
server: {
@@ -12,7 +14,10 @@ export const Route = createFileRoute('/$libraryId/$version/docs/{$}.md')({
1214
request: Request
1315
params: { libraryId: string; version: string; _splat: string }
1416
}) => {
15-
const _url = new URL(request.url)
17+
const url = new URL(request.url)
18+
const framework = url.searchParams.get('framework')
19+
const pm = getPackageManager(url.searchParams.get('pm'))
20+
const keepMarkers = url.searchParams.get('keep_markers') === 'true'
1621

1722
const { libraryId, version, _splat: docsPath } = params
1823
const library = getLibrary(libraryId as LibraryId)
@@ -24,7 +29,16 @@ export const Route = createFileRoute('/$libraryId/$version/docs/{$}.md')({
2429
docsPath: `${root}/${docsPath}`,
2530
})
2631

27-
const markdownContent = `# ${doc.title}\n${doc.content}`
32+
// Filter framework-specific content only if framework is explicitly specified
33+
const filteredContent = framework
34+
? filterFrameworkContent(doc.content, {
35+
framework,
36+
packageManager: pm,
37+
keepMarkers,
38+
})
39+
: doc.content
40+
41+
const markdownContent = `# ${doc.title}\n${filteredContent}`
2842
const filename = (docsPath || 'file').split('/').join('-')
2943

3044
return new Response(markdownContent, {

0 commit comments

Comments
 (0)