fix: icons

This commit is contained in:
valknarness
2025-10-26 22:53:16 +01:00
parent 8fc4aa8dab
commit 51b42fe625
32 changed files with 947 additions and 477 deletions

View File

@@ -3,7 +3,7 @@
import * as React from 'react'
import { useRouter } from 'next/navigation'
import {
CommandDialog,
Command,
CommandEmpty,
CommandGroup,
CommandInput,
@@ -11,6 +11,7 @@ import {
CommandList,
CommandSeparator,
} from '@/components/ui/command'
import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog'
import { Search, Star, BookOpen, Home, FileText, Code } from 'lucide-react'
interface CommandMenuProps {
@@ -18,20 +19,34 @@ interface CommandMenuProps {
setOpen: (open: boolean) => void
}
interface SearchResult {
repository_id: number
repository_name: string
repository_url: string
description: string | null
stars: number | null
language: string | null
topics: string | null
awesome_list_name: string | null
awesome_list_category: string | null
snippet: string | null
}
interface SearchResponse {
results: SearchResult[]
total: number
page: number
pageSize: number
totalPages: number
}
export function CommandMenu({ open, setOpen }: CommandMenuProps) {
const router = useRouter()
const [search, setSearch] = React.useState('')
const [results, setResults] = React.useState([])
const [results, setResults] = React.useState<SearchResult[]>([])
const [loading, setLoading] = React.useState(false)
// declare the async data fetching function
const fetchData = React.useCallback(async () => {
const response = await fetch(`/api/search?q=${encodeURIComponent(search)}`)
const data = await response.json()
setResults(data.results);
}, [])
React.useEffect(() => {
const down = (e: KeyboardEvent) => {
if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
@@ -45,13 +60,53 @@ const fetchData = React.useCallback(async () => {
}, [open, setOpen])
React.useEffect(() => {
if (!search) {
// Clear results if search is empty
if (!search || search.trim() === '') {
setResults([])
setLoading(false)
return
}
setLoading(true)
fetchData()
console.log(results)
setLoading(false)
// Debounce search
const timer = setTimeout(async () => {
setLoading(true)
try {
// Match the search page API call with same parameters
const params = new URLSearchParams({
q: search,
page: '1',
sortBy: 'relevance',
limit: '10' // Limit to 10 results for command menu
})
const response = await fetch(`/api/search?${params}`)
if (!response.ok) {
console.error('Search API error:', response.status, response.statusText)
setResults([])
return
}
const data: SearchResponse = await response.json()
// Check if response has error or invalid data
if (!data.results) {
console.error('Invalid search response:', data)
setResults([])
return
}
console.log('Search results:', data.results.length, 'results for:', search)
setResults(data.results)
} catch (error) {
console.error('Search error:', error)
setResults([])
} finally {
setLoading(false)
}
}, 300)
return () => clearTimeout(timer)
}, [search])
const runCommand = React.useCallback((command: () => void) => {
@@ -94,13 +149,19 @@ const fetchData = React.useCallback(async () => {
}
return (
<CommandDialog open={open} onOpenChange={setOpen}>
<CommandInput
placeholder="Search awesome lists, repos, and more..."
value={search}
onValueChange={setSearch}
/>
<CommandList>
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent className="overflow-hidden p-0" aria-describedby={undefined}>
<DialogTitle className="sr-only">Search</DialogTitle>
<Command
shouldFilter={false}
className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5"
>
<CommandInput
placeholder="Search awesome lists, repos, and more..."
value={search}
onValueChange={setSearch}
/>
<CommandList>
<CommandEmpty>
{loading ? (
<div className="flex items-center justify-center py-6">
@@ -133,17 +194,17 @@ const fetchData = React.useCallback(async () => {
{results.length > 0 && (
<CommandGroup heading="Search Results">
{results.map((result: any) => (
{results.map((result) => (
<CommandItem
key={result.repository_id}
value={result.repository_name}
onSelect={() => runCommand(() => router.push(result.url))}
onSelect={() => runCommand(() => router.push(`/repository/${result.repository_id}`))}
>
{getIcon(result.type)}
<Code className="mr-2 h-4 w-4" />
<div className="flex flex-1 flex-col gap-1">
<div className="flex items-center gap-2">
<span className="font-medium">{result.title}</span>
{result.stars && (
<span className="font-medium">{result.repository_name}</span>
{result.stars !== null && (
<span className="flex items-center gap-1 text-xs text-muted-foreground">
<Star className="h-3 w-3 fill-current" />
{result.stars.toLocaleString()}
@@ -155,17 +216,26 @@ const fetchData = React.useCallback(async () => {
{result.description}
</span>
)}
{result.category && (
<span className="text-xs text-primary">
{result.category}
</span>
)}
<div className="flex items-center gap-2">
{result.language && (
<span className="text-xs text-muted-foreground">
{result.language}
</span>
)}
{result.awesome_list_category && (
<span className="text-xs text-primary">
{result.awesome_list_category}
</span>
)}
</div>
</div>
</CommandItem>
))}
</CommandGroup>
)}
</CommandList>
</CommandDialog>
</CommandList>
</Command>
</DialogContent>
</Dialog>
)
}