+
+
+
-
{sortedContributors.length > 0 ? (
- {sortedContributors.map((contributor) => (
+ {sortedContributors.map((contributor, index) => (
))}
@@ -611,6 +625,10 @@ function calculateGithubContributionTotals(
return contributors.reduce(
(totals, contributor) => ({
changedFiles: totals.changedFiles + contributor.changedFiles,
+ highestContributionScore: Math.max(
+ totals.highestContributionScore,
+ contributor.contributionScore,
+ ),
contributionScore:
totals.contributionScore + contributor.contributionScore,
linkedIssueCount: totals.linkedIssueCount + contributor.linkedIssueCount,
@@ -618,6 +636,7 @@ function calculateGithubContributionTotals(
}),
{
changedFiles: 0,
+ highestContributionScore: 0,
contributionScore: 0,
linkedIssueCount: 0,
mergedPrCount: 0,
@@ -625,19 +644,157 @@ function calculateGithubContributionTotals(
);
}
+function calculateContributionSharePercent({
+ contributionScore,
+ maxContributionScore,
+}: {
+ contributionScore: number;
+ maxContributionScore: number;
+}) {
+ if (maxContributionScore <= 0 || contributionScore <= 0) {
+ return 0;
+ }
+
+ return Math.round((contributionScore / maxContributionScore) * 100);
+}
+
+function getContributionShareClass(sharePercent: number) {
+ if (sharePercent >= 92) {
+ return "w-full";
+ }
+
+ if (sharePercent >= 78) {
+ return "w-5/6";
+ }
+
+ if (sharePercent >= 62) {
+ return "w-2/3";
+ }
+
+ if (sharePercent >= 46) {
+ return "w-1/2";
+ }
+
+ if (sharePercent >= 30) {
+ return "w-1/3";
+ }
+
+ if (sharePercent > 0) {
+ return "w-1/5";
+ }
+
+ return "w-0";
+}
+
+function getRepositoryScoreFillClass(contributionScore: number) {
+ if (contributionScore >= 100) {
+ return "w-full";
+ }
+
+ if (contributionScore >= 80) {
+ return "w-5/6";
+ }
+
+ if (contributionScore >= 60) {
+ return "w-2/3";
+ }
+
+ if (contributionScore >= 35) {
+ return "w-1/2";
+ }
+
+ if (contributionScore > 0) {
+ return "w-1/3";
+ }
+
+ return "w-0";
+}
+
+function RealGithubContributionOverview({
+ topContributor,
+ totals,
+}: {
+ topContributor: GithubRepositoryContributor | null;
+ totals: ReturnType
;
+}) {
+ const scoreFillClass = getRepositoryScoreFillClass(totals.contributionScore);
+
+ return (
+
+
+
+
+
+ 기여도 점수
+
+
+
+ {contributionNumberFormatter.format(totals.contributionScore)}
+
+
+ PR {contributionNumberFormatter.format(totals.mergedPrCount)} ·
+ 이슈 {contributionNumberFormatter.format(totals.linkedIssueCount)}
+
+
+
+
+
+
+
+ {topContributor ? (
+
+
+
+ @{topContributor.githubUsername}
+
+
+ 선두 ·{" "}
+ {contributionNumberFormatter.format(
+ topContributor.contributionScore,
+ )}
+ 점
+
+
+ ) : (
+
+ 동기화 후 팀원별 PR 기여도가 여기에 표시돼요.
+
+ )}
+
+
+
+ );
+}
+
function RealGithubContributionStat({
+ icon: Icon,
label,
value,
}: {
+ icon: LucideIcon;
label: string;
value: number;
}) {
return (
-
-
- {label}
-
-
+
+
+
{contributionNumberFormatter.format(value)}
@@ -646,39 +803,131 @@ function RealGithubContributionStat({
function RealGithubContributorRow({
contributor,
+ maxContributionScore,
+ rank,
}: {
contributor: GithubRepositoryContributor;
+ maxContributionScore: number;
+ rank: number;
}) {
+ const sharePercent = calculateContributionSharePercent({
+ contributionScore: contributor.contributionScore,
+ maxContributionScore,
+ });
+ const shareClass = getContributionShareClass(sharePercent);
+
return (
-
-
-
- @{contributor.githubUsername}
-
-
- PR {contributionNumberFormatter.format(contributor.mergedPrCount)} ·
- 이슈{" "}
- {contributionNumberFormatter.format(contributor.linkedIssueCount)}
-
-
-
-
- +{contributionNumberFormatter.format(contributor.additions)}
-
-
- -{contributionNumberFormatter.format(contributor.deletions)}
-
-
- {contributionNumberFormatter.format(contributor.changedFiles)} files
-
-
- {contributionNumberFormatter.format(contributor.contributionScore)}
-
+
+
+
+ {rank === 1 ? : rank}
+
+
+
+
+
+ @{contributor.githubUsername}
+
+
+ PR{" "}
+ {contributionNumberFormatter.format(contributor.mergedPrCount)}{" "}
+ · 이슈{" "}
+ {contributionNumberFormatter.format(
+ contributor.linkedIssueCount,
+ )}
+
+
+
+ {contributionNumberFormatter.format(
+ contributor.contributionScore,
+ )}
+ 점
+
+
+
+
+
+
+
+
+
+
+
+
);
}
+function RealGithubContributorMetric({
+ label,
+ tone = "neutral",
+ value,
+}: {
+ label: string;
+ tone?: "negative" | "neutral" | "positive";
+ value: string;
+}) {
+ const toneClass = {
+ negative: "text-destructive",
+ neutral: "text-brand-ink",
+ positive: "text-chart-3",
+ }[tone];
+
+ return (
+
+
{label}
+
+ {value}
+
+
+ );
+}
+
function RealGithubRepositoryOption({
disabled,
onToggle,