import { useState } from 'react'
import { Link } from 'react-router-dom'
import { useRepoTree } from '../../api/queries/repos'
import { Skeleton } from '../../ui/Skeleton'
import { cn } from '../../lib/utils'
interface TreeBrowserProps {
owner: string
repo: string
ref: string
path?: string
}
export function TreeBrowser({ owner, repo, ref, path = '' }: TreeBrowserProps) {
const { data: entries, isLoading, isError } = useRepoTree(owner, repo, ref, path)
if (isLoading) return
if (isError) return
Failed to load file tree.
if (!entries?.length) return Empty repository.
const dirs = entries.filter(e => e.type === 'tree').sort((a, b) => a.name.localeCompare(b.name))
const files = entries.filter(e => e.type === 'blob').sort((a, b) => a.name.localeCompare(b.name))
return (
{/* Breadcrumb */}
{path && (
{repo}
{path.split('/').map((seg, i, arr) => {
const partial = arr.slice(0, i + 1).join('/')
return (
/
{i < arr.length - 1
? {seg}
: {seg}
}
)
})}
)}
{/* Entries */}
{[...dirs, ...files].map((entry, i) => {
const entryPath = path ? `${path}/${entry.name}` : entry.name
const isDir = entry.type === 'tree'
const href = isDir
? `/repos/${owner}/${repo}?path=${entryPath}`
: `/repos/${owner}/${repo}/blob?ref=${ref}&path=${entryPath}`
return (
-
{isDir ? (
) : (
)}
{entry.name}
)
})}
)
}
function TreeSkeleton() {
return (
{Array.from({ length: 6 }).map((_, i) => (
))}
)
}
// Collapsible row used in inline tree navigation
export function TreeRow({
name,
type,
href,
}: {
name: string
type: 'blob' | 'tree'
href: string
}) {
const [open, setOpen] = useState(false)
return (
{type === 'tree' && (
)}
{name}
)
}