AbdulElahGwaith's picture
Upload folder using huggingface_hub
b91e262 verified
'use client'
import type React from 'react'
import { CircleHelp } from 'lucide-react'
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from './ui/tooltip'
import { ImportChain } from '@/components/import-chain'
import { Skeleton } from '@/components/ui/skeleton'
import { AnalyzeData, ModulesData } from '@/lib/analyze-data'
import { SpecialModule } from '@/lib/types'
import { getSpecialModuleType } from '@/lib/utils'
import { Badge } from './ui/badge'
interface SidebarProps {
sidebarWidth: number
analyzeData: AnalyzeData | null
modulesData: ModulesData | null
selectedSourceIndex: number | null
moduleDepthMap: Map<number, number>
environmentFilter: 'client' | 'server'
filterSource?: (sourceIndex: number) => boolean
isLoading?: boolean
}
function formatBytes(bytes: number): string {
if (bytes === 0) return '0 B'
if (bytes < 1024) return `${bytes} B`
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`
if (bytes < 1024 * 1024 * 1024)
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`
}
export function Sidebar({
sidebarWidth,
analyzeData,
modulesData,
selectedSourceIndex,
moduleDepthMap,
environmentFilter,
filterSource,
isLoading = false,
}: SidebarProps) {
filterSource = filterSource ?? (() => true)
if (isLoading || !analyzeData) {
return (
<div
className="flex-none bg-muted border-l border-border overflow-y-auto"
style={{ width: `${sidebarWidth}%` }}
>
<div className="flex-1 p-3 space-y-4 overflow-y-auto">
<Skeleton className="h-4 w-3/4" />
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-5/6" />
<div className="mt-4 space-y-2">
<Skeleton className="h-3 w-full" />
<Skeleton className="h-3 w-full" />
<Skeleton className="h-3 w-4/5" />
</div>
</div>
</div>
)
}
return (
<div
className="flex-none bg-muted border-l border-border overflow-y-auto"
style={{ width: `${sidebarWidth}%` }}
>
{selectedSourceIndex != null ? (
<SelectionDetails
analyzeData={analyzeData}
modulesData={modulesData}
selectedSourceIndex={selectedSourceIndex}
filterSource={filterSource}
moduleDepthMap={moduleDepthMap}
environmentFilter={environmentFilter}
/>
) : null}
</div>
)
}
function SelectionDetails({
analyzeData,
modulesData,
selectedSourceIndex,
filterSource,
moduleDepthMap,
environmentFilter,
}: {
analyzeData: AnalyzeData
modulesData: ModulesData | null
selectedSourceIndex: number
moduleDepthMap: Map<number, number>
environmentFilter: 'client' | 'server'
filterSource: (sourceIndex: number) => boolean
}) {
const specialModuleType = getSpecialModuleType(
analyzeData,
selectedSourceIndex
)
const selectedSource =
selectedSourceIndex != null
? analyzeData.source(selectedSourceIndex)
: undefined
const hasChildModules =
selectedSourceIndex != null &&
analyzeData.sourceChildren(selectedSourceIndex).length > 0
const childModuleCount =
hasChildModules && selectedSourceIndex != null
? analyzeData.getRecursiveModuleCount(selectedSourceIndex, filterSource)
: null
const { size, compressedSize } = analyzeData.getRecursiveSizes(
selectedSourceIndex,
filterSource
)
const chunks =
selectedSourceIndex != null
? analyzeData.sourceChunks(selectedSourceIndex)
: []
return (
<div className="flex-1 p-3 space-y-8 overflow-y-auto">
<div className="space-y-2">
<h2 className="text-s font-semibold mb-1 text-foreground truncate">
{selectedSource?.path || 'All Route Modules'}
</h2>
{selectedSourceIndex != null &&
analyzeData.source(selectedSourceIndex) ? (
<div className="text-xs">
<div>
<span>{formatBytes(compressedSize)}</span>
<span className="text-muted-foreground ml-1">
compressed (estimated)
</span>
<InlineHelpTooltip>
Estimated compressed size. Modules are compressed in isolation
which may differ from their size in the final chunk.
</InlineHelpTooltip>
</div>
<div>
<span>{formatBytes(size)}</span>{' '}
<span className="text-muted-foreground">uncompressed</span>
<InlineHelpTooltip>
Uncompressed modules may still be minified, tree-shaken, and
dead-code eliminated. They just don't account for general
compression like gzip.
</InlineHelpTooltip>
</div>
{hasChildModules && childModuleCount != null ? (
<div>
<span>{childModuleCount} </span>
<span className="text-muted-foreground">
{childModuleCount === 1 ? 'module' : 'modules'}
</span>
</div>
) : null}
</div>
) : null}
</div>
{selectedSourceIndex != null &&
analyzeData.source(selectedSourceIndex) &&
(specialModuleType === SpecialModule.POLYFILL_MODULE ||
specialModuleType === SpecialModule.POLYFILL_NOMODULE) && (
<dl className="flex items-center gap-2">
<dt className="inline-flex items-center">
<Badge variant="polyfill">Polyfill</Badge>
</dt>
<dd className="text-xs text-muted-foreground">
Next.js built-in polyfills
</dd>
</dl>
)}
{selectedSourceIndex != null &&
analyzeData.source(selectedSourceIndex) &&
!hasChildModules && (
<>
{modulesData && (
<ImportChain
startFileId={selectedSourceIndex}
analyzeData={analyzeData}
modulesData={modulesData}
depthMap={moduleDepthMap}
environmentFilter={environmentFilter}
/>
)}
{chunks.length > 0 ? (
<div className="mt-2">
<p className="text-xs font-semibold text-foreground">
Output Chunks
</p>
<ul className="text-xs text-muted-foreground font-mono mt-1 space-y-1">
{chunks.map((chunk) => (
<li key={chunk} className="break-all">
{chunk}
</li>
))}
</ul>
</div>
) : null}
</>
)}
</div>
)
}
function InlineHelpTooltip({ children }: { children: React.ReactNode }) {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<CircleHelp
size={14}
className="inline-block ml-1 text-muted-foreground"
aria-hidden="true"
/>
</TooltipTrigger>
<TooltipContent className="max-w-xs" side="top" align="center">
{children}
</TooltipContent>
</Tooltip>
</TooltipProvider>
)
}