Skip to content

Commit ba8aff0

Browse files
committed
feat: update PackageManagerTabs to support multiple packages per framework
1 parent 2896481 commit ba8aff0

File tree

2 files changed

+67
-33
lines changed

2 files changed

+67
-33
lines changed

src/components/PackageManagerTabs.tsx

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import * as React from 'react'
2-
import { useCurrentFramework } from './FrameworkSelect'
2+
import {
3+
useLocalCurrentFramework,
4+
} from './FrameworkSelect'
5+
import { useCurrentUserQuery } from '~/hooks/useCurrentUser'
6+
import { useParams } from '@tanstack/react-router'
37
import { useLocalStorage } from '~/utils/useLocalStorage'
48
import { Tabs, type TabDefinition } from './Tabs'
59
import { CodeBlock } from './CodeBlock'
@@ -10,7 +14,7 @@ type InstallMode = 'install' | 'dev-install'
1014

1115
type PackageManagerTabsProps = {
1216
id: string
13-
packagesByFramework: Record<string, string>
17+
packagesByFramework: Record<string, string[]>
1418
mode: InstallMode
1519
frameworks: Framework[]
1620
}
@@ -19,51 +23,74 @@ const PACKAGE_MANAGERS: PackageManager[] = ['npm', 'pnpm', 'yarn', 'bun']
1923

2024
function getInstallCommand(
2125
packageManager: PackageManager,
22-
packages: string,
26+
packages: string[],
2327
mode: InstallMode,
24-
): string {
28+
): string[] {
29+
const commands: string[] = []
30+
2531
if (mode === 'dev-install') {
32+
for (const pkg of packages) {
33+
switch (packageManager) {
34+
case 'npm':
35+
commands.push(`npm i -D ${pkg}`)
36+
break
37+
case 'pnpm':
38+
commands.push(`pnpm add -D ${pkg}`)
39+
break
40+
case 'yarn':
41+
commands.push(`yarn add -D ${pkg}`)
42+
break
43+
case 'bun':
44+
commands.push(`bun add -d ${pkg}`)
45+
break
46+
}
47+
}
48+
return commands
49+
}
50+
51+
// install mode
52+
for (const pkg of packages) {
2653
switch (packageManager) {
2754
case 'npm':
28-
return `npm i -D ${packages}`
55+
commands.push(`npm i ${pkg}`)
56+
break
2957
case 'pnpm':
30-
return `pnpm add -D ${packages}`
58+
commands.push(`pnpm add ${pkg}`)
59+
break
3160
case 'yarn':
32-
return `yarn add -D ${packages}`
61+
commands.push(`yarn add ${pkg}`)
62+
break
3363
case 'bun':
34-
return `bun add -d ${packages}`
64+
commands.push(`bun add ${pkg}`)
65+
break
3566
}
3667
}
37-
38-
// install mode
39-
switch (packageManager) {
40-
case 'npm':
41-
return `npm i ${packages}`
42-
case 'pnpm':
43-
return `pnpm add ${packages}`
44-
case 'yarn':
45-
return `yarn add ${packages}`
46-
case 'bun':
47-
return `bun add ${packages}`
48-
}
68+
return commands
4969
}
5070

5171
export function PackageManagerTabs({
5272
id,
5373
packagesByFramework,
5474
mode,
55-
frameworks,
5675
}: PackageManagerTabsProps) {
57-
const { framework: currentFramework } = useCurrentFramework(frameworks)
5876
const [storedPackageManager, setStoredPackageManager] =
5977
useLocalStorage<PackageManager>('packageManager', PACKAGE_MANAGERS[0])
6078

61-
// Normalize framework key to lowercase for lookup
62-
const normalizedFramework = currentFramework.toLowerCase()
79+
const { framework: paramsFramework } = useParams({ strict: false })
80+
const localCurrentFramework = useLocalCurrentFramework()
81+
const userQuery = useCurrentUserQuery()
82+
const userFramework = userQuery.data?.lastUsedFramework
83+
84+
const actualFramework = (paramsFramework ||
85+
userFramework ||
86+
localCurrentFramework.currentFramework ||
87+
'react') as Framework
88+
89+
const normalizedFramework = actualFramework.toLowerCase()
6390
const packages = packagesByFramework[normalizedFramework]
6491

6592
// Hide component if current framework not in package list
66-
if (!packages) {
93+
if (!packages || packages.length === 0) {
6794
return null
6895
}
6996

@@ -81,10 +108,11 @@ export function PackageManagerTabs({
81108

82109
// Generate children (command blocks) for each package manager
83110
const children = PACKAGE_MANAGERS.map((pm) => {
84-
const command = getInstallCommand(pm, packages, mode)
111+
const commands = getInstallCommand(pm, packages, mode)
112+
const commandText = commands.join('\n')
85113
return (
86114
<CodeBlock key={pm}>
87-
<code className="language-bash">{command}</code>
115+
<code className="language-bash">{commandText}</code>
88116
</CodeBlock>
89117
)
90118
})

src/utils/markdown/plugins/transformTabsComponent.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type TabExtraction = {
2222
}
2323

2424
type PackageManagerExtraction = {
25-
packagesByFramework: Record<string, string>
25+
packagesByFramework: Record<string, string[]>
2626
mode: InstallMode
2727
}
2828

@@ -53,17 +53,18 @@ function normalizeFrameworkKey(key: string): string {
5353
*/
5454
function parseFrameworkLine(text: string): {
5555
framework: string
56-
packages: string
56+
packages: string[]
5757
} | null {
5858
const colonIndex = text.indexOf(':')
5959
if (colonIndex === -1) {
6060
return null
6161
}
6262

6363
const framework = normalizeFrameworkKey(text.slice(0, colonIndex))
64-
const packages = text.slice(colonIndex + 1).trim()
64+
const packagesStr = text.slice(colonIndex + 1).trim()
65+
const packages = packagesStr.split(/\s+/).filter(Boolean)
6566

66-
if (!framework || !packages) {
67+
if (!framework || packages.length === 0) {
6768
return null
6869
}
6970

@@ -75,7 +76,7 @@ function extractPackageManagerData(
7576
mode: InstallMode,
7677
): PackageManagerExtraction | null {
7778
const children = node.children ?? []
78-
const packagesByFramework: Record<string, string> = {}
79+
const packagesByFramework: Record<string, string[]> = {}
7980

8081
// Recursively extract text from all children (including nested in <p> tags)
8182
function extractText(nodes: any[]): string {
@@ -99,7 +100,12 @@ function extractPackageManagerData(
99100

100101
const parsed = parseFrameworkLine(trimmed)
101102
if (parsed) {
102-
packagesByFramework[parsed.framework] = parsed.packages
103+
// Support multiple entries for same framework by concatenating packages
104+
if (packagesByFramework[parsed.framework]) {
105+
packagesByFramework[parsed.framework].push(...parsed.packages)
106+
} else {
107+
packagesByFramework[parsed.framework] = parsed.packages
108+
}
103109
}
104110
}
105111

0 commit comments

Comments
 (0)