Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion src/components/TopRepos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { RepoHealthScore } from "@/types/repo-health";
import RepoHealthPanel from "@/components/RepoHealthPanel";
import RepoActivityDrawer from "@/components/RepoActivityDrawer";
import { Search, Bookmark } from "lucide-react";
import { getCodebaseSizeFromLanguages, type CodebaseSize } from "@/lib/codebase-size";

interface RepoItemProps {
repo: Repo;
Expand Down Expand Up @@ -53,6 +54,22 @@ const RepoItem = memo(({
: "bg-[var(--destructive)]/15 text-[var(--destructive)] border border-[var(--destructive)]/25";

const visibleLanguages = repo.languages ? getVisibleLanguages(repo.languages) : [];
const codebaseSize = getCodebaseSizeFromLanguages(repo.languages);

const sizeConfig: Record<CodebaseSize, { classes: string; ariaLabel: string }> = {
Small: {
classes: "bg-emerald-500/10 text-emerald-400 border-emerald-500/20",
ariaLabel: "Small codebase, under 50KB total code",
},
Medium: {
classes: "bg-amber-500/10 text-amber-400 border-amber-500/20",
ariaLabel: "Medium codebase, between 50KB and 500KB total code",
},
Large: {
classes: "bg-blue-500/10 text-blue-400 border-blue-500/20",
ariaLabel: "Large codebase, over 500KB total code",
},
};

return (
<li>
Expand Down Expand Up @@ -154,7 +171,7 @@ const RepoItem = memo(({
/>
</div>
<div className="mt-2 min-h-6">
{visibleLanguages.length > 0 && (
{(visibleLanguages.length > 0 || codebaseSize) && (
<div className="flex flex-wrap gap-1.5 text-[11px] text-[var(--muted-foreground)]">
{visibleLanguages.map((language) => (
<span
Expand All @@ -170,6 +187,15 @@ const RepoItem = memo(({
<span>{language.percentage}%</span>
</span>
))}
{codebaseSize && (
<span
className={`inline-flex items-center gap-1 rounded-full border px-2 py-0.5 font-medium ${sizeConfig[codebaseSize].classes}`}
aria-label={sizeConfig[codebaseSize].ariaLabel}
title={sizeConfig[codebaseSize].ariaLabel}
>
{codebaseSize} Codebase
</span>
)}
</div>
)}
</div>
Expand Down
42 changes: 42 additions & 0 deletions src/lib/codebase-size.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Pure utility that classifies a repository's codebase size based on total
* language bytes returned by the GitHub REST API (`/repos/:owner/:repo/languages`).
*
* Thresholds (per issue #2601):
* < 50 KB (51,200 bytes) → "Small"
* 50–500 KB (512,000 bytes) → "Medium"
* > 500 KB → "Large"
*/

export type CodebaseSize = "Small" | "Medium" | "Large";

const SMALL_THRESHOLD = 51_200; // 50 KB
const LARGE_THRESHOLD = 512_000; // 500 KB

/**
* Classifies a codebase by its total byte count.
*/
export function getCodebaseSize(totalBytes: number): CodebaseSize {
if (totalBytes < SMALL_THRESHOLD) return "Small";
if (totalBytes <= LARGE_THRESHOLD) return "Medium";
return "Large";
}

interface LanguageEntry {
bytes: number;
}

/**
* Convenience wrapper: sums `bytes` from a languages array and returns the
* codebase size classification. Returns `null` when there is no language data.
*/
export function getCodebaseSizeFromLanguages(
languages: LanguageEntry[] | undefined
): CodebaseSize | null {
if (!languages || languages.length === 0) return null;

const totalBytes = languages.reduce((sum, lang) => sum + lang.bytes, 0);
if (totalBytes <= 0) return null;

return getCodebaseSize(totalBytes);
}
Loading