~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
63 lines · 2.2 KB Raw History
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>
  );
}