Skip to content

Commit b81fa54

Browse files
authored
add package contributors section based on the repository data (#2302)
1 parent 3a6a8f6 commit b81fa54

File tree

5 files changed

+129
-7
lines changed

5 files changed

+129
-7
lines changed

components/Package/EntityCounter.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Label } from '~/common/styleguide';
55
import tw from '~/util/tailwind';
66

77
type Props = {
8-
count: number;
8+
count: number | string;
99
style?: StyleProp<Style>;
1010
};
1111

components/Package/PackageAuthor.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ type Props = {
1313
};
1414

1515
const authorContainerStyle = tw`flex flex-row items-center gap-3 bg-transparent`;
16-
const labelStyle = tw`leading-[18px]`;
16+
const labelStyle = tw`text-[13px] leading-[18px]`;
1717
const sublabelStyle = tw`text-[11px] font-light text-palette-gray4 dark:text-secondary`;
1818

1919
export default function PackageAuthor({ author, compact }: Props) {
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import { useMemo } from 'react';
2+
import ContentLoader from 'react-content-loader';
3+
import { View } from 'react-native';
4+
import useSWR from 'swr';
5+
6+
import { A, H6Section, Label, useLayout } from '~/common/styleguide';
7+
import EntityCounter from '~/components/Package/EntityCounter';
8+
import UserAvatar from '~/components/Package/UserAvatar';
9+
import Tooltip from '~/components/Tooltip';
10+
import { type GitHubUser } from '~/types';
11+
import { TimeRange } from '~/util/datetime';
12+
import { pluralize } from '~/util/strings';
13+
import tw from '~/util/tailwind';
14+
15+
type Props = {
16+
fullName: string;
17+
};
18+
19+
const LIMIT = 38;
20+
21+
export default function RepositoryContributors({ fullName }: Props) {
22+
const { isSmallScreen } = useLayout();
23+
const { data, isLoading } = useSWR(
24+
`https://api.github.com/repos/${fullName}/contributors?per_page=${LIMIT}`,
25+
(url: string) => fetch(url).then(res => res.json()),
26+
{
27+
dedupingInterval: TimeRange.HOUR * 1000,
28+
revalidateOnFocus: false,
29+
}
30+
);
31+
32+
const contributors: GitHubUser[] = useMemo(
33+
() =>
34+
data?.sort((a: GitHubUser, b: GitHubUser) => (a.contributions < b.contributions ? 1 : -1)),
35+
[data]
36+
);
37+
38+
if (isLoading) {
39+
return (
40+
<>
41+
<H6Section style={tw`mt-3 flex gap-1.5`}>Contributors</H6Section>
42+
<ContentLoader
43+
speed={2}
44+
width="100%"
45+
height={36}
46+
backgroundColor={tw.prefixMatch('dark') ? '#2a2e36' : '#f3f3f3'}
47+
foregroundColor={tw.prefixMatch('dark') ? '#383c42' : '#ecebeb'}>
48+
<circle cx="18" cy="18" r="18" />
49+
<circle cx="62" cy="18" r="18" />
50+
<circle cx="106" cy="18" r="18" />
51+
<circle cx="150" cy="18" r="18" />
52+
<circle cx="194" cy="18" r="18" />
53+
</ContentLoader>
54+
</>
55+
);
56+
}
57+
58+
const hasMore = contributors?.length >= LIMIT;
59+
60+
return (
61+
<>
62+
<H6Section style={tw`mt-3 flex gap-1.5`}>
63+
Contributors
64+
<EntityCounter count={hasMore ? `${LIMIT}+` : contributors.length} />
65+
{!isSmallScreen && hasMore && (
66+
<A href={`https://github.com/${fullName}/contributors`} style={tw`ml-auto`}>
67+
<Label style={tw`font-light`}>See all contributors</Label>
68+
</A>
69+
)}
70+
</H6Section>
71+
<View style={tw`flex-row flex-wrap items-start gap-2`}>
72+
{contributors.map(contributor => (
73+
<View style={tw`flex flex-row items-center gap-3 bg-transparent`} key={contributor.login}>
74+
<Tooltip
75+
sideOffset={2}
76+
delayDuration={100}
77+
trigger={
78+
<View>
79+
<A href={contributor.html_url} style={tw`contents`}>
80+
<UserAvatar src={contributor.avatar_url} alt={`${contributor.login} avatar`} />
81+
</A>
82+
</View>
83+
}>
84+
<View>
85+
<Label style={tw`text-[13px] leading-[18px]`}>{contributor.login}</Label>
86+
<span style={tw`text-[11px] font-light text-palette-gray4 dark:text-secondary`}>
87+
{contributor.contributions} {pluralize('contribution', contributor.contributions)}
88+
</span>
89+
</View>
90+
</Tooltip>
91+
</View>
92+
))}
93+
</View>
94+
</>
95+
);
96+
}

scenes/PackageOverviewScene.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import MorePackagesBox from '~/components/Package/MorePackagesBox';
1919
import NotFound from '~/components/Package/NotFound';
2020
import PackageAuthor from '~/components/Package/PackageAuthor';
2121
import PackageHeader from '~/components/Package/PackageHeader';
22+
import RepositoryContributors from '~/components/Package/RepositoryContributors';
2223
import TopicsSection from '~/components/Package/TopicsSection';
2324
import PageMeta from '~/components/PageMeta';
2425
import { type NpmRegistryVersionData, type NpmUser, type PeerDependencyData } from '~/types';
@@ -80,9 +81,10 @@ export default function PackageOverviewScene({
8081
</UL>
8182
</>
8283
)}
84+
{!isSmallScreen && <MorePackagesBox library={library} />}
8385
{!isSmallScreen && !!author && (
8486
<>
85-
<H6Section style={tw`mt-4`}>Author</H6Section>
87+
<H6Section style={tw`mt-3`}>Author</H6Section>
8688
<View style={tw`items-start`}>
8789
<PackageAuthor author={author} />
8890
</View>
@@ -91,7 +93,7 @@ export default function PackageOverviewScene({
9193
{!isSmallScreen && maintainers && (
9294
<>
9395
<H6Section style={tw`mt-3 flex gap-1.5`}>
94-
Contributors
96+
Maintainers
9597
<EntityCounter count={maintainers.length} />
9698
</H6Section>
9799
<View style={tw`flex-row flex-wrap items-start gap-2`}>
@@ -103,7 +105,7 @@ export default function PackageOverviewScene({
103105
</View>
104106
</>
105107
)}
106-
{!isSmallScreen && <MorePackagesBox library={library} />}
108+
{!isSmallScreen && <RepositoryContributors fullName={library.github.fullName} />}
107109
</View>
108110
<View style={tw`flex-0.35 gap-4`} id="metadataContainer">
109111
<View>
@@ -187,6 +189,7 @@ export default function PackageOverviewScene({
187189
/>
188190
<DependenciesSection title="Development dependencies" data={devDependencies} />
189191
<DependenciesSection title="Engines" data={engines} />
192+
{isSmallScreen && <MorePackagesBox library={library} />}
190193
{isSmallScreen && !!author && (
191194
<>
192195
<H6Section>Author</H6Section>
@@ -198,7 +201,7 @@ export default function PackageOverviewScene({
198201
{isSmallScreen && maintainers && (
199202
<>
200203
<H6Section style={tw`flex gap-1.5`}>
201-
Contributors
204+
Maintainer
202205
<EntityCounter count={maintainers.length} />
203206
</H6Section>
204207
<View style={tw`flex-row flex-wrap items-start gap-2`}>
@@ -210,7 +213,7 @@ export default function PackageOverviewScene({
210213
</View>
211214
</>
212215
)}
213-
{isSmallScreen && <MorePackagesBox library={library} />}
216+
{isSmallScreen && <RepositoryContributors fullName={library.github.fullName} />}
214217
</View>
215218
</View>
216219
</ContentContainer>

types/index.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,3 +331,26 @@ export type NightlyProgramData = {
331331
maintainersUsernames: string[];
332332
notes: string;
333333
};
334+
335+
export type GitHubUser = {
336+
avatar_url: string;
337+
contributions: number;
338+
events_url: string;
339+
followers_url: string;
340+
following_url: string;
341+
gists_url: string;
342+
gravatar_id: string;
343+
html_url: string;
344+
id: number;
345+
login: string;
346+
node_id: string;
347+
organizations_url: string;
348+
received_events_url: string;
349+
repos_url: string;
350+
site_admin: boolean;
351+
starred_url: string;
352+
subscriptions_url: string;
353+
type: string;
354+
url: string;
355+
user_view_type: string;
356+
};

0 commit comments

Comments
 (0)