Skip to content

Commit ff22098

Browse files
committed
fix: combine packages
1 parent affe289 commit ff22098

File tree

1 file changed

+81
-80
lines changed

1 file changed

+81
-80
lines changed

src/routes/stats/npm/index.tsx

Lines changed: 81 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import {
1111
MdPushPin,
1212
MdMoreVert,
1313
MdSearch,
14-
MdArrowDownward,
15-
MdArrowUpward,
1614
} from 'react-icons/md'
1715
import { keepPreviousData, queryOptions, useQuery } from '@tanstack/react-query'
1816
import * as Plot from '@observablehq/plot'
@@ -726,10 +724,17 @@ function NpmStatsChart({
726724
)
727725
}
728726

729-
function PackageSearch() {
727+
function PackageSearch({
728+
onSelect,
729+
placeholder = 'Search for a package...',
730+
autoFocus = false,
731+
}: {
732+
onSelect: (packageName: string) => void
733+
placeholder?: string
734+
autoFocus?: boolean
735+
}) {
730736
const [inputValue, setInputValue] = React.useState('')
731737
const [open, setOpen] = React.useState(false)
732-
const navigate = Route.useNavigate()
733738
const containerRef = React.useRef<HTMLDivElement>(null)
734739

735740
const [debouncedInputValue] = useDebouncedValue(inputValue, {
@@ -791,19 +796,7 @@ function PackageSearch() {
791796
const selectedItem = searchQuery.data?.find((item) => item.name === value)
792797
if (!selectedItem) return
793798

794-
navigate({
795-
to: '.',
796-
search: (prev) => ({
797-
...prev,
798-
packageGroups: [
799-
...prev.packageGroups,
800-
{
801-
packages: [{ name: selectedItem.name }],
802-
},
803-
],
804-
}),
805-
resetScroll: false,
806-
})
799+
onSelect(selectedItem.name)
807800
setInputValue('')
808801
setOpen(false)
809802
}
@@ -815,11 +808,12 @@ function PackageSearch() {
815808
<div className="flex items-center gap-1">
816809
<MdSearch className="text-lg" />
817810
<Command.Input
818-
placeholder="Search for a package..."
811+
placeholder={placeholder}
819812
className="w-full bg-gray-500/10 rounded-md px-2 py-1 min-w-[200px] text-sm"
820813
value={inputValue}
821814
onValueChange={handleInputChange}
822815
onFocus={() => setOpen(true)}
816+
autoFocus={autoFocus}
823817
/>
824818
</div>
825819
{searchQuery.isLoading && (
@@ -925,10 +919,6 @@ function RouteComponent() {
925919
const [combiningPackage, setCombiningPackage] = React.useState<string | null>(
926920
null
927921
)
928-
const [combineSearchResults, setCombineSearchResults] = React.useState<
929-
NpmPackage[]
930-
>([])
931-
const [isCombining, setIsCombining] = React.useState(false)
932922
const navigate = Route.useNavigate()
933923
const [colorPickerPackage, setColorPickerPackage] = React.useState<
934924
string | null
@@ -1066,7 +1056,6 @@ function RouteComponent() {
10661056
}
10671057

10681058
setCombiningPackage(null)
1069-
setCombineSearchResults([])
10701059
}
10711060

10721061
const handleRemoveFromGroup = (mainPackage: string, subPackage: string) => {
@@ -1145,27 +1134,6 @@ function RouteComponent() {
11451134

11461135
const handleCombinePackage = (packageName: string) => {
11471136
setCombiningPackage(packageName)
1148-
setCombineSearchResults([])
1149-
}
1150-
1151-
const handleCombineSearch = async (query: string) => {
1152-
if (!query || query.length < 2) {
1153-
setCombineSearchResults([])
1154-
return
1155-
}
1156-
1157-
setIsCombining(true)
1158-
try {
1159-
const response = await fetch(
1160-
`https://api.npms.io/v2/search?q=${encodeURIComponent(query)}&size=10`
1161-
)
1162-
const data = await response.json()
1163-
setCombineSearchResults(data.results.map((r: any) => r.package))
1164-
} catch (error) {
1165-
console.error('Error searching packages:', error)
1166-
} finally {
1167-
setIsCombining(false)
1168-
}
11691137
}
11701138

11711139
const handleColorClick = (packageName: string, event: React.MouseEvent) => {
@@ -1249,6 +1217,69 @@ function RouteComponent() {
12491217
})
12501218
}
12511219

1220+
const handleAddPackage = (packageName: string) => {
1221+
navigate({
1222+
to: '.',
1223+
search: (prev) => ({
1224+
...prev,
1225+
packageGroups: [
1226+
...prev.packageGroups,
1227+
{
1228+
packages: [{ name: packageName }],
1229+
},
1230+
],
1231+
}),
1232+
resetScroll: false,
1233+
})
1234+
}
1235+
1236+
const handleAddToGroup = (packageName: string) => {
1237+
if (!combiningPackage) return
1238+
1239+
// Find the package group that contains the combining package
1240+
const packageGroup = packageGroups.find((pkg) =>
1241+
pkg.packages.some((p) => p.name === combiningPackage)
1242+
)
1243+
1244+
if (packageGroup) {
1245+
// Update existing package group
1246+
const newPackages = packageGroups.map((pkg) =>
1247+
pkg === packageGroup
1248+
? {
1249+
...pkg,
1250+
packages: [...pkg.packages, { name: packageName }],
1251+
}
1252+
: pkg
1253+
)
1254+
1255+
navigate({
1256+
to: '.',
1257+
search: (prev) => ({
1258+
...prev,
1259+
packageGroups: newPackages,
1260+
}),
1261+
resetScroll: false,
1262+
})
1263+
} else {
1264+
// Create new package group
1265+
navigate({
1266+
to: '.',
1267+
search: (prev) => ({
1268+
...prev,
1269+
packageGroups: [
1270+
...packageGroups,
1271+
{
1272+
packages: [{ name: combiningPackage }, { name: packageName }],
1273+
},
1274+
],
1275+
}),
1276+
resetScroll: false,
1277+
})
1278+
}
1279+
1280+
setCombiningPackage(null)
1281+
}
1282+
12521283
return (
12531284
<div className="min-h-dvh p-2 sm:p-4 space-y-2 sm:space-y-4">
12541285
<div className="bg-white dark:bg-black/50 rounded-lg p-2 sm:p-4 flex items-center gap-2 text-lg sm:text-xl shadow-xl">
@@ -1271,7 +1302,7 @@ function RouteComponent() {
12711302
<div className="flex gap-4">
12721303
<div className="flex-1 bg-white dark:bg-black/50 rounded-lg space-y-4 p-4 shadow-xl max-w-full">
12731304
<div className="flex gap-2 flex-wrap">
1274-
<PackageSearch />
1305+
<PackageSearch onSelect={handleAddPackage} />
12751306
<DropdownMenu>
12761307
<Tooltip content="Select time range">
12771308
<DropdownMenuTrigger asChild>
@@ -1770,41 +1801,11 @@ function RouteComponent() {
17701801
<MdClose className="w-4 h-4 sm:w-5 sm:h-5" />
17711802
</button>
17721803
</div>
1773-
<div className="relative">
1774-
<input
1775-
type="text"
1776-
placeholder="Search for packages..."
1777-
className="w-full bg-gray-500/10 rounded-md px-2 sm:px-3 py-1.5 sm:py-2 text-sm sm:text-base"
1778-
onChange={(e) => handleCombineSearch(e.target.value)}
1779-
autoFocus
1780-
/>
1781-
{isCombining && (
1782-
<div className="absolute right-2 top-0 bottom-0 flex items-center justify-center">
1783-
<FaSpinner className="w-3 h-3 sm:w-4 sm:h-4 animate-spin" />
1784-
</div>
1785-
)}
1786-
</div>
1787-
<div className="mt-2 sm:mt-4 max-h-40 sm:max-h-60 overflow-auto">
1788-
{combineSearchResults.map((pkg) => (
1789-
<button
1790-
key={pkg.name}
1791-
onClick={() => handleCombineSelect(pkg)}
1792-
className="w-full text-left px-2 sm:px-3 py-1.5 sm:py-2 hover:bg-gray-500/20 rounded-md"
1793-
>
1794-
<div className="font-medium text-sm sm:text-base">
1795-
{pkg.name}
1796-
</div>
1797-
<div className="text-xs sm:text-sm text-gray-500 dark:text-gray-400">
1798-
{pkg.description}
1799-
</div>
1800-
</button>
1801-
))}
1802-
{combineSearchResults.length === 0 && (
1803-
<div className="px-2 sm:px-3 py-1.5 sm:py-2 text-sm text-gray-500">
1804-
No matching packages found
1805-
</div>
1806-
)}
1807-
</div>
1804+
<PackageSearch
1805+
onSelect={handleAddToGroup}
1806+
placeholder="Search for packages to add..."
1807+
autoFocus={true}
1808+
/>
18081809
</div>
18091810
</div>
18101811
)}

0 commit comments

Comments
 (0)