chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
import { Avatar } from '#/components/atoms/avatar.jsx';
import { Count } from '#/components/atoms/count.jsx';
import { describeAuthor, initial } from '#/lib/authors.js';
import { identicon } from '#/lib/avatars.js';
import { useHistory } from '#/lib/source.js';
/** How many faces show before the rest are counted. */
const FACES = 14;
/**
* Everyone the history credits, as a row of faces beside the files, the way
* a forge lists a repository's contributors. Each face carries its name and
* its count in the title. An author the account has claimed wears their
* profile; anyone else keeps the initial of the name the commit carries.
*
* The count is read from the same history walk the gauges read, so it costs
* no read of its own.
* @param {{repo: string, refName: string, space?: string}} props
*/
export function Contributors({ repo, refName, space }) {
const { data: history } = useHistory(repo, refName, space);
const authors = history?.authors ?? [];
if (authors.length === 0) return null;
const shown = authors.slice(0, FACES);
return (
<div className="border-border border-t pt-4">
<h2 className="flex items-center gap-2 font-semibold text-[14px] text-foreground">
Contributors
<Count value={authors.length} />
</h2>
<ul className="mt-3 flex flex-wrap gap-2">
{shown.map(({ ident, commits }) => {
const person = describeAuthor(ident);
return (
<li
key={ident}
title={`${person.name} · ${commits} ${commits === 1 ? 'commit' : 'commits'}`}
>
<Avatar
src={
person.avatar ||
(person.did ? identicon(person.did) : undefined)
}
fallback={
<span className="text-[11px] text-faint">
{initial(person.name)}
</span>
}
className="size-8"
/>
</li>
);
})}
</ul>
{authors.length > shown.length && (
<p className="mt-2 text-[12.5px] text-faint">
+ {authors.length - shown.length} more
</p>
)}
</div>
);
}